Skip to content

Commit e6a8a2d

Browse files
committed
W25 Step A: HirBasicBlock + HirCFG canonical struct-pointer typedef
Per W25 spec docs/w25-hbb-canonicalization.md (theologian, gatekeeper APPROVED, supervisor signoff [chat L2068]). Atomic single-commit Step A per spec §3: replaces the dual-typedef HirBasicBlock + HirCFG with forward struct decls in hir_c_api.h + struct-pointer signatures across the API surface and §1a callers. ARCHITECTURAL FIX (Alex Option B "clear the debt now. Then we stop building new code on top of debt"): Pre-W25: hir_c_api.h declared 'typedef void* HirBasicBlock' + 'typedef void* HirCFG'. hir_basic_block_c.h declared the same names as struct typedefs. A single TU could not include both headers (typedef collision). 24 TUs worked around this with local extern decls — a 24-site signature-drift timebomb (push 51 root-cause class). Post-W25 Step A: hir_c_api.h replaces the void* typedefs with forward struct decls. API signatures use struct-pointer (struct HirCFG *, struct HirBasicBlock *). hir_basic_block_c.h's full struct definitions remain canonical. Both headers now coexist in any TU without conflict — but local extern decls in 24 §1b TUs still need deletion (Step B) before drift surface fully closes. CHANGES (10 files, +100/-82): Python/jit/hir/hir_c_api.h: - typedef void* HirBasicBlock + HirCFG REMOVED - struct HirBasicBlock + struct HirCFG forward decls ADDED - ~10 API signatures updated to struct-pointer form: hir_func_cfg, hir_cfg_get_rpo, hir_cfg_blocks_first/next, hir_block_empty/id/first/next/terminator/append/pop_front/ in_edges_count/fixup_phis, hir_instr_successor, hir_branch_target, hir_block_back, hir_remove_trampoline_blocks Python/jit/hir/hir_c_api.cpp: - as_cfg/as_block: signatures updated, static_cast → reinterpret_cast (struct-pointer to BasicBlock*/CFG* requires reinterpret) - NEW to_cfg/to_block helpers for return-direction conversion - All API impl signatures updated to match header - Legacy void*-arg wrappers (hir_cfg_blocks_first_ptr etc) use explicit static_cast to canonical struct-pointer (iter 1 fix per testkeeper [chat L2086] catch — C++ does not implicit-convert void* to struct pointer types) Python/jit/hir/clean_cfg.c (§1a per spec): - HirBasicBlock value → struct HirBasicBlock * - sizeof(HirBasicBlock) → sizeof(struct HirBasicBlock *) (array-of- pointers sizing — 8B → 8B, semantic preserved per spec line 134) Python/jit/hir/dead_code_elimination.c (§1a per spec) Python/jit/hir/dynamic_comparison_elimination.c (§1a per spec) Python/jit/hir/func_type_checks_c.c (§1a per spec) Python/jit/hir/guard_removal.c (§1a per spec) Python/jit/hir/copy_propagation.c (EXTRA §1a-class, spec §1a missed) Python/jit/hir/hir_stats_c.c (EXTRA §1a-class, spec §1a missed) Python/jit/hir/phi_elimination.c (EXTRA §1a-class, spec §1a missed) EXTRA TU rationale: spec §1a listed 5 TUs; my grep for callers of hir_cfg_*/hir_block_first/etc found 8 §1a-class TUs total. Per spec §4 'authoritative from grep', I included the 3 extras (testkeeper [chat L2090] confirmed — same discipline as their §4 inventory expansion 17 vs 24). Spec amendment to follow. UNCHANGED in Step A: 24 §1b TUs (assignment_c.c, dominator_c.c, refcount_env_c.c, builder_emit_c.c, etc.) keep their local extern decls. Their void* extern is ABI-compatible with my new canonical struct-pointer signature at link time. Step B will delete the local externs and add #include "hir_c_api.h". testkeeper x86_64 compile-only PASS verified pre-commit at binary timestamp 1776884355 (chat L2090). Iter 1 needed explicit-cast fix in 2 legacy wrappers; iter 2 clean. Falsification §5.1 (dual-include compile test) deferred to next small commit per spec §5 — requires CMakeLists.txt update for build inclusion. Step B and §5 falsification follow this commit per spec §9. Authorization chain: - W25 spec publication: chat L2017 (theologian) - gatekeeper APPROVED implementation: chat L2065 - supervisor metadata signoff + GREEN LIGHT: chat L2068 - Alex Option B directive: chat L2046 - testkeeper x86_64 compile PASS iter 2: chat L2090
1 parent b808cda commit e6a8a2d

10 files changed

Lines changed: 100 additions & 82 deletions

Python/jit/hir/clean_cfg.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@
1717
* - the target has exactly 1 predecessor
1818
* - the target is not block itself (no self-loops)
1919
* Returns 1 if absorption happened, 0 otherwise. */
20-
static int absorb_dst_block(HirBasicBlock block) {
20+
static int absorb_dst_block(struct HirBasicBlock *block) {
2121
HirInstr term = hir_block_terminator(block);
2222
/* C struct predicate — direct opcode read, no C++ bridge */
2323
if (!hir_c_is_branch(term)) {
2424
return 0;
2525
}
2626

2727
/* C struct accessor — reads HirBranch.edge.to directly */
28-
HirBasicBlock target = hir_c_branch_target(term);
28+
struct HirBasicBlock *target = hir_c_branch_target(term);
2929
/* Assertion wrapper: C struct matches C++ bridge (wiring methodology) */
3030
assert(target == hir_branch_target(term));
3131
if (target == block) {
@@ -52,7 +52,7 @@ static int absorb_dst_block(HirBasicBlock block) {
5252
size_t num_edges = hir_c_num_edges(new_term);
5353
assert(num_edges == hir_instr_num_edges(new_term));
5454
for (size_t i = 0; i < num_edges; i++) {
55-
HirBasicBlock succ = hir_c_successor(new_term, i);
55+
struct HirBasicBlock *succ = hir_c_successor(new_term, i);
5656
assert(succ == hir_instr_successor(new_term, i));
5757
hir_block_fixup_phis(succ, target, block);
5858
}
@@ -63,29 +63,30 @@ static int absorb_dst_block(HirBasicBlock block) {
6363
}
6464

6565
void hir_clean_cfg_run(HirFunction func) {
66-
HirCFG cfg = hir_func_cfg(func);
66+
struct HirCFG *cfg = hir_func_cfg(func);
6767
int changed = 0;
6868

6969
do {
7070
hir_remove_unreachable_instructions(func);
7171
hir_phi_elimination_run(func);
7272

73-
/* Get RPO traversal */
73+
/* Get RPO traversal. Array-of-pointers sizing — sizeof(ptr) == 8B,
74+
* matches pre-W25 sizeof(void*). Semantic preserved. */
7475
size_t rpo_cap = 256;
75-
HirBasicBlock *rpo_blocks = (HirBasicBlock *)malloc(
76-
rpo_cap * sizeof(HirBasicBlock));
76+
struct HirBasicBlock **rpo_blocks = (struct HirBasicBlock **)malloc(
77+
rpo_cap * sizeof(struct HirBasicBlock *));
7778
if (!rpo_blocks) return;
7879
size_t num_blocks = hir_cfg_get_rpo(cfg, rpo_blocks, rpo_cap);
7980
if (num_blocks > rpo_cap) {
8081
rpo_cap = num_blocks;
81-
rpo_blocks = (HirBasicBlock *)realloc(
82-
rpo_blocks, rpo_cap * sizeof(HirBasicBlock));
82+
rpo_blocks = (struct HirBasicBlock **)realloc(
83+
rpo_blocks, rpo_cap * sizeof(struct HirBasicBlock *));
8384
if (!rpo_blocks) return;
8485
hir_cfg_get_rpo(cfg, rpo_blocks, rpo_cap);
8586
}
8687

8788
for (size_t i = 0; i < num_blocks; i++) {
88-
HirBasicBlock block = rpo_blocks[i];
89+
struct HirBasicBlock *block = rpo_blocks[i];
8990
if (hir_block_empty(block)) {
9091
continue;
9192
}

Python/jit/hir/copy_propagation.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@ static int chase_assign_cb(void **reg_slot, void *ctx) {
1919
}
2020

2121
void hir_copy_propagation_run(HirFunction func) {
22-
HirCFG cfg = hir_func_cfg(func);
22+
struct HirCFG *cfg = hir_func_cfg(func);
2323

24-
/* Get RPO traversal */
24+
/* Get RPO traversal. Array-of-pointers sizing — sizeof(ptr) preserved. */
2525
size_t rpo_cap = 256;
26-
HirBasicBlock *rpo_blocks = malloc(rpo_cap * sizeof(HirBasicBlock));
26+
struct HirBasicBlock **rpo_blocks = malloc(rpo_cap * sizeof(struct HirBasicBlock *));
2727
if (!rpo_blocks) return;
2828
size_t num_blocks = hir_cfg_get_rpo(cfg, rpo_blocks, rpo_cap);
2929
if (num_blocks > rpo_cap) {
3030
rpo_cap = num_blocks;
31-
rpo_blocks = realloc(rpo_blocks, rpo_cap * sizeof(HirBasicBlock));
31+
rpo_blocks = realloc(rpo_blocks, rpo_cap * sizeof(struct HirBasicBlock *));
3232
if (!rpo_blocks) return;
3333
hir_cfg_get_rpo(cfg, rpo_blocks, rpo_cap);
3434
}
@@ -43,7 +43,7 @@ void hir_copy_propagation_run(HirFunction func) {
4343
}
4444

4545
for (size_t i = 0; i < num_blocks; i++) {
46-
HirBasicBlock block = rpo_blocks[i];
46+
struct HirBasicBlock *block = rpo_blocks[i];
4747
HirInstr instr = hir_block_first(block);
4848

4949
while (instr != NULL) {

Python/jit/hir/dead_code_elimination.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,13 @@ static int dce_visit_cb(void **reg_slot, void *ctx) {
149149
/* ---- DCE pass ---- */
150150

151151
void hir_dead_code_elimination_run(HirFunction func) {
152-
HirCFG cfg = hir_func_cfg(func);
152+
struct HirCFG *cfg = hir_func_cfg(func);
153153

154154
/* Phase 1: seed worklist with useful instructions */
155155
Worklist worklist;
156156
wl_init(&worklist, 128);
157157

158-
HirBasicBlock block = hir_cfg_blocks_first(cfg);
158+
struct HirBasicBlock *block = hir_cfg_blocks_first(cfg);
159159
while (block != NULL) {
160160
HirInstr instr = hir_block_first(block);
161161
while (instr != NULL) {
@@ -183,7 +183,7 @@ void hir_dead_code_elimination_run(HirFunction func) {
183183
/* Phase 3: delete dead instructions */
184184
block = hir_cfg_blocks_first(cfg);
185185
while (block != NULL) {
186-
HirBasicBlock next_block = hir_cfg_blocks_next(cfg, block);
186+
struct HirBasicBlock *next_block = hir_cfg_blocks_next(cfg, block);
187187
HirInstr instr = hir_block_first(block);
188188
while (instr != NULL) {
189189
HirInstr next = hir_block_next(block, instr);

Python/jit/hir/dynamic_comparison_elimination.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
void hir_dynamic_comparison_elimination_run(HirFunction func) {
1616
HirLivenessState *liveness = hir_liveness_create(func);
1717

18-
HirCFG cfg = hir_func_cfg(func);
19-
HirBasicBlock block = hir_cfg_blocks_first(cfg);
18+
struct HirCFG *cfg = hir_func_cfg(func);
19+
struct HirBasicBlock *block = hir_cfg_blocks_first(cfg);
2020

2121
while (block != NULL) {
22-
HirBasicBlock next_block = hir_cfg_blocks_next(cfg, block);
22+
struct HirBasicBlock *next_block = hir_cfg_blocks_next(cfg, block);
2323

2424
/* Get last instruction in block */
2525
HirInstr instr = hir_block_back(block);

Python/jit/hir/func_type_checks_c.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@ static int operands_must_match(HirOperandType op_type) {
8282
}
8383

8484
int hir_func_type_checks(HirFunction func) {
85-
HirCFG cfg = hir_func_cfg(func);
85+
struct HirCFG *cfg = hir_func_cfg(func);
8686
const char *fullname = hir_func_fullname(func);
8787

88-
for (HirBasicBlock block = hir_cfg_blocks_first(cfg);
88+
for (struct HirBasicBlock *block = hir_cfg_blocks_first(cfg);
8989
block != NULL;
9090
block = hir_cfg_blocks_next(cfg, block)) {
9191
int block_id = hir_block_id(block);

Python/jit/hir/guard_removal.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ void hir_guard_type_removal_run(HirFunction func) {
185185
size_t removed_count = 0;
186186
size_t removed_cap = 0;
187187

188-
HirCFG cfg = hir_func_cfg(func);
189-
for (HirBasicBlock block = hir_cfg_blocks_first(cfg);
188+
struct HirCFG *cfg = hir_func_cfg(func);
189+
for (struct HirBasicBlock *block = hir_cfg_blocks_first(cfg);
190190
block != NULL;
191191
block = hir_cfg_blocks_next(cfg, block)) {
192192

Python/jit/hir/hir_c_api.cpp

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,23 @@ static inline Function* as_func(HirFunction f) {
133133
return static_cast<Function*>(f);
134134
}
135135

136-
static inline CFG* as_cfg(HirCFG c) {
137-
return static_cast<CFG*>(c);
136+
static inline CFG* as_cfg(struct HirCFG *c) {
137+
return reinterpret_cast<CFG*>(c);
138138
}
139139

140-
static inline BasicBlock* as_block(HirBasicBlock b) {
141-
return static_cast<BasicBlock*>(b);
140+
static inline BasicBlock* as_block(struct HirBasicBlock *b) {
141+
return reinterpret_cast<BasicBlock*>(b);
142+
}
143+
144+
/* Reverse direction: opaque pointer from C++ object. Used by API funcs
145+
* that return HBB/CFG pointers — the C++ pointer must be opaqued back to
146+
* the canonical struct-pointer form. reinterpret_cast preserves identity. */
147+
static inline struct HirBasicBlock *to_block(BasicBlock *b) {
148+
return reinterpret_cast<struct HirBasicBlock *>(b);
149+
}
150+
151+
static inline struct HirCFG *to_cfg(CFG *c) {
152+
return reinterpret_cast<struct HirCFG *>(c);
142153
}
143154

144155
static inline Instr* as_instr(HirInstr i) {
@@ -153,8 +164,8 @@ static inline Register* as_reg(HirRegister r) {
153164

154165
extern "C" {
155166

156-
HirCFG hir_func_cfg(HirFunction func) {
157-
return &as_func(func)->cfg;
167+
struct HirCFG *hir_func_cfg(HirFunction func) {
168+
return to_cfg(&as_func(func)->cfg);
158169
}
159170

160171
const char *hir_func_fullname(HirFunction func) {
@@ -226,51 +237,51 @@ void hir_preloader_ensure(void *py_func) {
226237
}
227238
}
228239

229-
size_t hir_cfg_get_rpo(HirCFG cfg, HirBasicBlock *out, size_t capacity) {
240+
size_t hir_cfg_get_rpo(struct HirCFG *cfg, struct HirBasicBlock **out, size_t capacity) {
230241
auto rpo = as_cfg(cfg)->GetRPOTraversal();
231242
size_t count = rpo.size() < capacity ? rpo.size() : capacity;
232243
for (size_t i = 0; i < count; i++) {
233-
out[i] = rpo[i];
244+
out[i] = to_block(rpo[i]);
234245
}
235246
return count;
236247
}
237248

238-
HirBasicBlock hir_cfg_blocks_first(HirCFG cfg) {
249+
struct HirBasicBlock *hir_cfg_blocks_first(struct HirCFG *cfg) {
239250
auto& blocks = as_cfg(cfg)->blocks;
240251
if (blocks.begin() == blocks.end()) {
241252
return nullptr;
242253
}
243-
return &*blocks.begin();
254+
return to_block(&*blocks.begin());
244255
}
245256

246-
HirBasicBlock hir_cfg_blocks_next(HirCFG cfg, HirBasicBlock block) {
257+
struct HirBasicBlock *hir_cfg_blocks_next(struct HirCFG *cfg, struct HirBasicBlock *block) {
247258
auto& blocks = as_cfg(cfg)->blocks;
248259
auto it = blocks.iterator_to(*as_block(block));
249260
++it;
250261
if (it == blocks.end()) {
251262
return nullptr;
252263
}
253-
return &*it;
264+
return to_block(&*it);
254265
}
255266

256267
/* ---- BasicBlock ---- */
257268

258-
int hir_block_id(HirBasicBlock block) {
269+
int hir_block_id(struct HirBasicBlock *block) {
259270
return as_block(block)->id;
260271
}
261272

262-
int hir_block_empty(HirBasicBlock block) {
273+
int hir_block_empty(struct HirBasicBlock *block) {
263274
return as_block(block)->empty() ? 1 : 0;
264275
}
265276

266-
HirInstr hir_block_first(HirBasicBlock block) {
277+
HirInstr hir_block_first(struct HirBasicBlock *block) {
267278
if (as_block(block)->empty()) {
268279
return nullptr;
269280
}
270281
return &as_block(block)->front();
271282
}
272283

273-
HirInstr hir_block_next(HirBasicBlock block, HirInstr instr) {
284+
HirInstr hir_block_next(struct HirBasicBlock *block, HirInstr instr) {
274285
auto it = as_block(block)->iterator_to(*as_instr(instr));
275286
++it;
276287
if (it == as_block(block)->end()) {
@@ -279,25 +290,25 @@ HirInstr hir_block_next(HirBasicBlock block, HirInstr instr) {
279290
return &*it;
280291
}
281292

282-
HirInstr hir_block_terminator(HirBasicBlock block) {
293+
HirInstr hir_block_terminator(struct HirBasicBlock *block) {
283294
return as_block(block)->GetTerminator();
284295
}
285296

286-
HirInstr hir_block_append(HirBasicBlock block, HirInstr instr) {
297+
HirInstr hir_block_append(struct HirBasicBlock *block, HirInstr instr) {
287298
return as_block(block)->Append(as_instr(instr));
288299
}
289300

290-
HirInstr hir_block_pop_front(HirBasicBlock block) {
301+
HirInstr hir_block_pop_front(struct HirBasicBlock *block) {
291302
return as_block(block)->pop_front();
292303
}
293304

294-
size_t hir_block_in_edges_count(HirBasicBlock block) {
305+
size_t hir_block_in_edges_count(struct HirBasicBlock *block) {
295306
return as_block(block)->in_edges().size();
296307
}
297308

298-
void hir_block_fixup_phis(HirBasicBlock block,
299-
HirBasicBlock old_pred,
300-
HirBasicBlock new_pred) {
309+
void hir_block_fixup_phis(struct HirBasicBlock *block,
310+
struct HirBasicBlock *old_pred,
311+
struct HirBasicBlock *new_pred) {
301312
as_block(block)->fixupPhis(as_block(old_pred), as_block(new_pred));
302313
}
303314

@@ -312,8 +323,8 @@ size_t hir_instr_num_edges(HirInstr instr) {
312323
return as_instr(instr)->numEdges();
313324
}
314325

315-
HirBasicBlock hir_instr_successor(HirInstr instr, size_t index) {
316-
return as_instr(instr)->successor(index);
326+
struct HirBasicBlock *hir_instr_successor(HirInstr instr, size_t index) {
327+
return to_block(as_instr(instr)->successor(index));
317328
}
318329

319330
/* ---- Instruction mutation ---- */
@@ -370,12 +381,12 @@ int hir_c_visit_deopt_extension(void *instr_ptr,
370381

371382
/* ---- Branch-specific ---- */
372383

373-
HirBasicBlock hir_branch_target(HirInstr branch) {
384+
struct HirBasicBlock *hir_branch_target(HirInstr branch) {
374385
auto* instr = as_instr(branch);
375386
if (!instr->IsBranch()) {
376387
return nullptr;
377388
}
378-
return static_cast<Branch*>(instr)->target();
389+
return to_block(static_cast<Branch*>(instr)->target());
379390
}
380391

381392
/* ---- Register accessors ---- */
@@ -608,7 +619,7 @@ int hir_memory_effects_may_store(HirInstr instr) {
608619
extern "C" int hir_remove_trampoline_blocks_c(void *cfg);
609620
extern "C" int hir_remove_unreachable_blocks_c(void *func);
610621

611-
int hir_remove_trampoline_blocks(HirCFG cfg) {
622+
int hir_remove_trampoline_blocks(struct HirCFG *cfg) {
612623
return hir_remove_trampoline_blocks_c(cfg);
613624
}
614625

@@ -656,7 +667,7 @@ void hir_instr_replace_with(HirInstr old_instr, HirInstr new_instr) {
656667
as_instr(old_instr)->ReplaceWith(*as_instr(new_instr));
657668
}
658669

659-
HirInstr hir_block_back(HirBasicBlock block) {
670+
HirInstr hir_block_back(struct HirBasicBlock *block) {
660671
auto* bb = as_block(block);
661672
if (bb->empty()) return nullptr;
662673
return &bb->back();
@@ -2467,11 +2478,12 @@ void hir_bb_destroy(void *block) {
24672478
}
24682479

24692480
void *hir_cfg_blocks_first_ptr(void *cfg) {
2470-
return hir_cfg_blocks_first(cfg);
2481+
return hir_cfg_blocks_first(static_cast<struct HirCFG *>(cfg));
24712482
}
24722483

24732484
void *hir_cfg_blocks_next_ptr(void *cfg, void *block) {
2474-
return hir_cfg_blocks_next(cfg, static_cast<BasicBlock*>(block));
2485+
return hir_cfg_blocks_next(static_cast<struct HirCFG *>(cfg),
2486+
static_cast<struct HirBasicBlock *>(block));
24752487
}
24762488

24772489
size_t hir_cfg_get_rpo_from(HirFunction func, void *start,

0 commit comments

Comments
 (0)