Skip to content

Commit 72bb8e9

Browse files
committed
Tier 8 SECOND-PILOT Phase A: block_map_.blocks → PhxBlockMap (custom hash)
Migrates the BCOffset→BasicBlock* lookup from std::unordered_map to a purpose-built open-addressed hash (Knuth multiplicative, linear probing, load factor 0.7) living in PhxHirBuilderState.block_map_phx. Custom hash chosen per spec §2.1 strict path because the D2 block-count measurement (2026-04-24) showed re._parser:Tokenizer.__next at 294 blocks and Tokenizer.get at 147 — PhxArray linear-scan would be O(n²) on these real stdlib hot paths. Net bridge delta: -1 (per Tier 8 spec §5 python#11 net-subtract). - DELETED hir_builder_state_block_map_blocks_lookup_cpp (Phase 3 Batch 4) - DELETED hir_builder_get_block_at_off (Tier 2 emit-conversion bridge) - ADDED phx_hir_builder_state(builder) — canonical state-from-builder accessor; future Phase B/C/D pilots reuse the pattern. block_map_.bc_blocks (heavy BytecodeInstructionBlock value-type) stays C++-side this phase; only the BCOffset→BasicBlock* lookup migrated. HIRBuilder::getBlockAtOff body now delegates to phx_block_map_lookup; the C++ method shell is deferred to a later phase. 12 C-side caller sites in builder_emit_c.c rewired to phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder) ->block_map_phx, off). NULL-value invariant verified pre-commit: the sole insert site (createBlocks) takes the value from CFG::AllocateBlock() = `new BasicBlock(id)` which never returns NULL. Falsifiers bundled: - test_phx_block_map.c: 8 unit tests (init/insert/resize-trigger at cap=16/N=300/synthesized collisions/overwrite/miss/clear). - gate_phoenix.sh: block_map_resize_chain (10-arm if/return, ~25 block_starts) added to wiring-gate force_compile fixtures so PhxBlockMap_resize fires deterministically (testkeeper 10:29:06Z gap flag — prior wiring fixtures were all <12 BBs). - w45_bridge_drift_falsifier.sh: lookup_cpp fixture retargeted to phx_hir_builder_state. - w45_section_3_5_derivation_drift.sh: Fixture 4 retargeted to phx_hir_builder_state return-type mutation (PhxHirBuilderState* → int breaks the 12 caller derefs). Auth chain: theologian patch-shape APPROVE 10:28:51Z + 10:33:54Z (β2) + 10:41:07Z (revisions); supervisor authorization 10:25:19Z + 10:29:05Z + 10:29:22Z; librarian §5 python#11 net-subtract precedent 10:30:04Z; testkeeper pre-commit BUILD PASS + 8/8 unit PASS 10:46:46Z.
1 parent 2a35849 commit 72bb8e9

11 files changed

Lines changed: 447 additions & 71 deletions

Python/jit/hir/builder.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,12 @@ HIRBuilder::BlockMap HIRBuilder::createBlocks(
11641164
Function& irfunc,
11651165
const BytecodeInstructionBlock& bc_block) {
11661166
BlockMap block_map;
1167+
/* Tier 8 SECOND-PILOT Phase A: blocks lookup table now lives in
1168+
* state_.block_map_phx. Clear before populating so successive
1169+
* createBlocks calls (e.g. inlined callees via inlineHIR) start with
1170+
* an empty hash, matching the prior re-assignment-of-empty-map
1171+
* semantics of the deleted std::unordered_map field. */
1172+
phx_block_map_clear(&state_.block_map_phx);
11671173

11681174
// Mark the beginning of each basic block in the bytecode
11691175
std::set<BCIndex> block_starts = {BCIndex{0}};
@@ -1223,7 +1229,11 @@ HIRBuilder::BlockMap HIRBuilder::createBlocks(
12231229
end_idx = BCIndex{bc_block.size()};
12241230
}
12251231
auto block = irfunc.cfg.AllocateBlock();
1226-
block_map.blocks[start_idx] = block;
1232+
/* Tier 8 SECOND-PILOT Phase A: blocks lookup migrated from
1233+
* std::unordered_map<BCOffset,BasicBlock*> to PhxBlockMap (custom
1234+
* open-addressed hash) in PhxHirBuilderState.block_map_phx. */
1235+
phx_block_map_insert(
1236+
&state_.block_map_phx, BCOffset{start_idx}.value(), block);
12271237
block_map.bc_blocks.emplace(
12281238
std::piecewise_construct,
12291239
std::forward_as_tuple(block),
@@ -1473,19 +1483,14 @@ void HIRBuilder::emitCallExceptionHandler(
14731483
}
14741484

14751485
BasicBlock* HIRBuilder::getBlockAtOff(BCOffset off) {
1476-
auto it = block_map_.blocks.find(off);
1477-
JIT_DCHECK(it != block_map_.blocks.end(), "No block for offset {}", off);
1478-
return it->second;
1486+
/* Tier 8 SECOND-PILOT Phase A: lookup migrated to PhxBlockMap. */
1487+
void *blk = phx_block_map_lookup(&state_.block_map_phx, off.value());
1488+
JIT_DCHECK(blk != nullptr, "No block for offset {}", off);
1489+
return static_cast<BasicBlock*>(blk);
14791490
}
14801491

1481-
extern "C" void *hir_builder_state_block_map_blocks_lookup_cpp(
1482-
void *builder,
1483-
int off) {
1484-
HIRBuilder *self = static_cast<HIRBuilder*>(builder);
1485-
auto it = self->block_map_.blocks.find(BCOffset{off});
1486-
JIT_DCHECK(
1487-
it != self->block_map_.blocks.end(), "No block for offset {}", off);
1488-
return static_cast<void*>(it->second);
1492+
extern "C" PhxHirBuilderState *phx_hir_builder_state(void *builder) {
1493+
return &static_cast<HIRBuilder*>(builder)->state_;
14891494
}
14901495

14911496
std::unique_ptr<Function> buildHIR(const Preloader& preloader) {

Python/jit/hir/builder.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#include <unordered_set>
1717

1818
extern "C" {
19-
void *hir_builder_get_block_at_off(void *builder, int byte_offset);
2019
void *hir_builder_preloader_annotations(void *builder);
2120
int hir_builder_preloader_num_args(void *builder);
2221
HirType hir_builder_preloader_return_type(void *builder);
@@ -173,7 +172,6 @@ struct InlineResult {
173172
};
174173

175174
class HIRBuilder {
176-
friend void* ::hir_builder_get_block_at_off(void*, int);
177175
friend void ::hir_builder_insert_run_periodic_activities_c(
178176
void*, void*, void*, void*, void*);
179177
friend void* ::hir_builder_get_kwnames(void*);
@@ -212,11 +210,15 @@ class HIRBuilder {
212210
// (push/size/entry) DELETED. findExceptionHandler + parseExceptionTable
213211
// C++ shims rewired internally to PhxExceptionTable; Phase B will
214212
// delete those shims.
215-
// Phase 3 Batch 4 (theologian 00:06:05Z): Class B-kept disposition
216-
// closure for block_map_ — lookup bridge accesses
217-
// block_map_.blocks (std::unordered_map) via friend.
218-
friend void *::hir_builder_state_block_map_blocks_lookup_cpp(
219-
void*, int);
213+
// Tier 8 SECOND-PILOT Phase A (theologian 10:25:08Z + supervisor
214+
// 10:25:19Z + 10:29:05Z): block_map_.blocks migrated from
215+
// std::unordered_map<BCOffset,BasicBlock*> to PhxBlockMap (custom
216+
// open-addressed hash) in PhxHirBuilderState.block_map_phx. The
217+
// _cpp lookup bridge + the public hir_builder_get_block_at_off
218+
// C-API DELETED; C-side callers use phx_hir_builder_state +
219+
// phx_block_map_lookup directly. block_map_.bc_blocks (heavy
220+
// BytecodeInstructionBlock value) STAYS on the C++ side this phase.
221+
friend PhxHirBuilderState *::phx_hir_builder_state(void*);
220222
public:
221223
const Preloader& preloader() const { return preloader_; }
222224
explicit HIRBuilder(const Preloader& preloader)
@@ -575,8 +577,11 @@ class HIRBuilder {
575577
const InvokeTarget& target,
576578
TranslationContext& tc,
577579
long nargs);
580+
/* Tier 8 SECOND-PILOT Phase A: BlockMap.blocks migrated to
581+
* PhxBlockMap in PhxHirBuilderState.block_map_phx (custom hash);
582+
* BlockMap retained holding only bc_blocks (heavy
583+
* BytecodeInstructionBlock value-type, deferred to later phase). */
578584
struct BlockMap {
579-
std::unordered_map<BCOffset, BasicBlock*> blocks;
580585
std::unordered_map<BasicBlock*, BytecodeInstructionBlock> bc_blocks;
581586
};
582587
BlockMap createBlocks(

Python/jit/hir/builder_emit_c.c

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "cinderx/Jit/hir/hir_c_api.h"
1010
#include "cinderx/Jit/hir/hir_instr_c.h"
1111
#include "cinderx/Jit/hir/hir_basic_block_c.h"
12+
#include "cinderx/Jit/hir/builder_state_c.h" /* PhxBlockMap + state accessor */
1213
#include "cinderx/Jit/hir/phx_frame_state.h"
1314
#include "cinderx/Jit/hir/hir_type_c.h"
1415
#include "cinderx/Jit/hir/annotation_index_c.h" /* HirAnnotationIndex (emitTypeAnnotationGuards) */
@@ -537,7 +538,6 @@ void hir_builder_emit_store_slice_c(PhxTranslationContext *tc, void *func) {
537538
}
538539

539540
/* emitAsyncForHeaderYieldFrom — yield from async for header */
540-
extern void *hir_builder_get_block_at_off(void *builder, int byte_offset);
541541

542542
void hir_builder_emit_async_for_header_yield_from_c(
543543
PhxTranslationContext *tc, void *func, void *builder,
@@ -552,10 +552,10 @@ void hir_builder_emit_async_for_header_yield_from_c(
552552
phx_ptr_arr_pop(&tc->frame.stack);
553553
phx_ptr_arr_push(&tc->frame.stack, out);
554554

555-
void *yf_cont_block = hir_builder_get_block_at_off(builder, next_instr_offset);
555+
void *yf_cont_block = phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder)->block_map_phx, next_instr_offset);
556556
PhxExecBlock *top = (PhxExecBlock *)tc->frame.block_stack_data;
557557
int handler_off = top[tc->frame.block_stack_count - 1].handler_off;
558-
void *yf_done_block = hir_builder_get_block_at_off(builder, handler_off);
558+
void *yf_done_block = phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder)->block_map_phx, handler_off);
559559
phx_tc_emit(tc, hir_c_create_cond_branch_iter_not_done_cpp(out, yf_cont_block, yf_done_block));
560560
}
561561

@@ -1621,7 +1621,6 @@ void hir_builder_emit_get_iter_c(
16211621
}
16221622

16231623
/* emitForIter — peek iterator, InvokeIterNext, CondBranchIterNotDone */
1624-
extern void *hir_builder_get_block_at_off(void *builder, int byte_offset);
16251624

16261625
void hir_builder_emit_for_iter_c(
16271626
PhxTranslationContext *tc,
@@ -1637,8 +1636,8 @@ void hir_builder_emit_for_iter_c(
16371636
void *next_val = hir_func_alloc_register(func);
16381637
phx_tc_emit(tc, hir_c_create_invoke_iter_next_reg(next_val, iterator, &tc->frame));
16391638
phx_ptr_arr_push(&tc->frame.stack, next_val);
1640-
void *footer = hir_builder_get_block_at_off(builder, jump_target);
1641-
void *body = hir_builder_get_block_at_off(builder, next_instr_offset);
1639+
void *footer = phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder)->block_map_phx, jump_target);
1640+
void *body = phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder)->block_map_phx, next_instr_offset);
16421641
phx_tc_emit(tc, hir_c_create_cond_branch_iter_not_done_cpp(next_val, body, footer));
16431642
}
16441643

@@ -1734,7 +1733,6 @@ void hir_builder_emit_fast_len_c(
17341733
}
17351734

17361735
/* ---- Tier 2 bridge externs (used by multiple emit methods) ---- */
1737-
extern void *hir_builder_get_block_at_off(void *builder, int byte_offset);
17381736

17391737
/* emitJumpIf — peek var, IsTruthy or direct, conditional branch */
17401738
void hir_builder_emit_jump_if_c(
@@ -1775,8 +1773,8 @@ void hir_builder_emit_jump_if_c(
17751773
false_off = next_instr_offset;
17761774
break;
17771775
}
1778-
void *true_block = hir_builder_get_block_at_off(builder, true_off);
1779-
void *false_block = hir_builder_get_block_at_off(builder, false_off);
1776+
void *true_block = phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder)->block_map_phx, true_off);
1777+
void *false_block = phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder)->block_map_phx, false_off);
17801778
if (check_truthy) {
17811779
void *tval = hir_func_alloc_register(func);
17821780
phx_tc_emit(tc, hir_c_create_is_truthy_reg(tval, var, &tc->frame));
@@ -1903,8 +1901,8 @@ void hir_builder_emit_pop_jump_if_c(
19031901
false_off = jump_target;
19041902
break;
19051903
}
1906-
void *true_block = hir_builder_get_block_at_off(builder, true_off);
1907-
void *false_block = hir_builder_get_block_at_off(builder, false_off);
1904+
void *true_block = phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder)->block_map_phx, true_off);
1905+
void *false_block = phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder)->block_map_phx, false_off);
19081906

19091907
if (opcode == POP_JUMP_IF_FALSE || opcode == POP_JUMP_IF_TRUE) {
19101908
void *is_true = hir_func_alloc_register(func);
@@ -1931,8 +1929,8 @@ void hir_builder_emit_pop_jump_if_none_c(
19311929
int jump_target,
19321930
int next_instr_offset) {
19331931
void *var = phx_ptr_arr_pop(&tc->frame.stack);
1934-
void *true_block = hir_builder_get_block_at_off(builder, jump_target);
1935-
void *false_block = hir_builder_get_block_at_off(builder, next_instr_offset);
1932+
void *true_block = phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder)->block_map_phx, jump_target);
1933+
void *false_block = phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder)->block_map_phx, next_instr_offset);
19361934

19371935
void *none = hir_func_alloc_register(func);
19381936
HirType t_none = hir_type_from_object(Py_None);
@@ -4224,7 +4222,6 @@ void hir_builder_emit_before_with_c(
42244222
* emits Send + GetSecondOutput<TCInt64>, pushes value_in, then cond-branch
42254223
* on is_done to (jump_target_block, next_instr_block) — both resolved by
42264224
* C++ stub via getBlockAtOff. */
4227-
extern void *hir_builder_get_block_at_off(void *builder, int byte_offset);
42284225

42294226
void hir_builder_emit_send_c(
42304227
PhxTranslationContext *tc,
@@ -4244,8 +4241,8 @@ void hir_builder_emit_send_c(
42444241
is_done, t_cint64, value_in));
42454242
phx_ptr_arr_push(&tc->frame.stack, value_in);
42464243

4247-
void *done_block = hir_builder_get_block_at_off(builder, jump_target_off);
4248-
void *continue_block = hir_builder_get_block_at_off(builder, next_instr_off);
4244+
void *done_block = phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder)->block_map_phx, jump_target_off);
4245+
void *continue_block = phx_block_map_lookup_or_panic(&phx_hir_builder_state(builder)->block_map_phx, next_instr_off);
42494246
/* hir_c_create_cond_branch_cpp: uses Edge::set_to which manages the
42504247
* target BasicBlock's in_edges_ set. The pure-C hir_c_create_cond_branch
42514248
* bypasses Edge::set_to (writes edge.to directly), leaving target

Python/jit/hir/builder_state_c.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@
88
*/
99

1010
#include "cinderx/Jit/hir/builder_state_c.h"
11+
#include "cinderx/Common/jit_log_c.h"
1112
#include "Python.h"
1213

1314
#include <stdint.h>
1415

16+
void *phx_block_map_lookup_or_panic(const PhxBlockMap *m, int key) {
17+
void *blk = phx_block_map_lookup(m, key);
18+
JIT_CHECK_C(blk != NULL, "No block for offset %d", key);
19+
return blk;
20+
}
21+
1522
void hir_builder_state_init(
1623
PhxHirBuilderState *state,
1724
void *code,
@@ -22,10 +29,12 @@ void hir_builder_state_init(
2229
state->func = NULL;
2330
state->kwnames = NULL;
2431
phx_exception_table_init(&state->exception_table_phx);
32+
phx_block_map_init(&state->block_map_phx);
2533
}
2634

2735
void hir_builder_state_destroy(PhxHirBuilderState *state) {
2836
phx_exception_table_destroy(&state->exception_table_phx);
37+
phx_block_map_destroy(&state->block_map_phx);
2938
}
3039

3140
void hir_builder_state_parse_exception_table_c(

0 commit comments

Comments
 (0)