Skip to content

Commit e78fb24

Browse files
feat(jit): substrate ops inline + HBit β-divergence + Nop compaction
JIT scalar lowerer (lib.rs): - Add `module` field to FunctionLowerer so it can look up registered externs - Wire Op::Fold1 → omc_fold, Op::IsFibonacci → omc_is_attractor, Op::Fibonacci → omc_nth_fibonacci (already registered), plus Op::Resonance → omc_resonance_bits, Op::HimScore → omc_him_score_bits (new shims added this session) via emit_unary_extern_call helper - Functions using substrate ops are now JIT-eligible without falling to the "Session B doesn't yet lower" error arm HBit dual-band lowerer (dual_band.rs): - PhiShadow step: every StoreVar/AssignVar now re-derives β = fold(α) so the β band tracks the nearest Fibonacci attractor of the live value rather than being a stale splatted copy from function entry - Adds phi_shadow_store() helper using omc_fold via module.get_function Bytecode optimizer (bytecode_opt.rs): - New compact_nops() pass removes Op::Nop holes after the peephole fixpoint and rewrites all Jump/JumpIfFalse/JumpIfTrue offsets - Adds nops_compacted field to OptStats; compact_nops runs once at the end of optimize_function (not inside the loop) - 5 new tests: direct Nop removal, branch/loop jump bounds, integration with constant-folding pipeline Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c2d6432 commit e78fb24

3 files changed

Lines changed: 322 additions & 1 deletion

File tree

omnimcode-codegen/src/dual_band.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,9 +316,14 @@ impl<'ctx, 'a> DualBandLowerer<'ctx, 'a> {
316316
}
317317
Op::StoreVar(name) | Op::AssignVar(name) => {
318318
let v = self.pop(&mut stack, i, "Store/AssignVar")?;
319+
// PhiShadow: on every store, re-derive β = fold(α).
320+
// This makes β track the nearest Fibonacci attractor of
321+
// the live α value so that harmony() reads a meaningful
322+
// substrate distance rather than a stale splatted copy.
323+
let diverged = self.phi_shadow_store(v, i)?;
319324
let slot = self.get_or_create_slot(name)?;
320325
self.builder
321-
.build_store(slot, v)
326+
.build_store(slot, diverged)
322327
.map_err(|e| format!("hbit store {} at op{}: {}", name, i, e))?;
323328
}
324329

@@ -1329,6 +1334,54 @@ impl<'ctx, 'a> DualBandLowerer<'ctx, 'a> {
13291334
Ok(new_v)
13301335
}
13311336

1337+
/// PhiShadow: extract α from a `<2 x i64>` and rebuild with β = fold(α).
1338+
/// β is set to the nearest Fibonacci attractor of α via `omc_fold`.
1339+
/// Every StoreVar/AssignVar calls this so the β band is never stale.
1340+
fn phi_shadow_store(
1341+
&self,
1342+
v: VectorValue<'ctx>,
1343+
op_idx: usize,
1344+
) -> Result<VectorValue<'ctx>, CodegenError> {
1345+
let i64_type = self.ctx.i64_type();
1346+
// Extract α (lane 0).
1347+
let alpha_bv = self
1348+
.builder
1349+
.build_extract_element(v, i64_type.const_int(0, false), "ps_alpha")
1350+
.map_err(|e| format!("phi_shadow extract α at op{}: {}", op_idx, e))?;
1351+
let alpha_iv = match alpha_bv {
1352+
inkwell::values::BasicValueEnum::IntValue(iv) => iv,
1353+
_ => return Err(format!("phi_shadow: α not int at op{}", op_idx)),
1354+
};
1355+
// β = fold(α).
1356+
let fold_fn = self
1357+
.module
1358+
.get_function("omc_fold")
1359+
.ok_or_else(|| format!("omc_fold not declared (phi_shadow at op{})", op_idx))?;
1360+
let call = self
1361+
.builder
1362+
.build_call(fold_fn, &[alpha_iv.into()], "ps_fold")
1363+
.map_err(|e| format!("phi_shadow fold call at op{}: {}", op_idx, e))?;
1364+
let beta_bv = call
1365+
.try_as_basic_value()
1366+
.left()
1367+
.ok_or_else(|| format!("phi_shadow fold no return at op{}", op_idx))?;
1368+
let beta_iv = match beta_bv {
1369+
inkwell::values::BasicValueEnum::IntValue(iv) => iv,
1370+
_ => return Err(format!("phi_shadow: fold returned non-int at op{}", op_idx)),
1371+
};
1372+
// Rebuild <2 x i64> = [α, β].
1373+
let undef = self.v2i64.get_undef();
1374+
let with_alpha = self
1375+
.builder
1376+
.build_insert_element(undef, alpha_iv, i64_type.const_int(0, false), "ps_a")
1377+
.map_err(|e| format!("phi_shadow insert α at op{}: {}", op_idx, e))?;
1378+
let with_beta = self
1379+
.builder
1380+
.build_insert_element(with_alpha, beta_iv, i64_type.const_int(1, false), "ps_b")
1381+
.map_err(|e| format!("phi_shadow insert β at op{}: {}", op_idx, e))?;
1382+
Ok(with_beta)
1383+
}
1384+
13321385
fn splat(&self, scalar: IntValue<'ctx>, name: &str) -> Result<VectorValue<'ctx>, CodegenError> {
13331386
let i64_type = self.ctx.i64_type();
13341387
let undef = self.v2i64.get_undef();

omnimcode-codegen/src/lib.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,22 @@ pub extern "C" fn omc_value_danger(n_bits: i64) -> i64 {
272272
(-f.abs()).exp().to_bits() as i64
273273
}
274274

275+
/// resonance(n) -> f64 bits as i64.
276+
/// Harmonic resonance score: 1.0 for exact Fibonacci attractor, decays with distance.
277+
/// Op::Resonance in the JIT scalar lowerer.
278+
#[no_mangle]
279+
pub extern "C" fn omc_resonance_bits(n: i64) -> i64 {
280+
omnimcode_core::value::HInt::compute_resonance(n).to_bits() as i64
281+
}
282+
283+
/// him_score(n) -> f64 bits as i64.
284+
/// Harmonic Integer Map score: fractional part of n*phi, clamped to [0, 0.5].
285+
/// Op::HimScore in the JIT scalar lowerer.
286+
#[no_mangle]
287+
pub extern "C" fn omc_him_score_bits(n: i64) -> i64 {
288+
omnimcode_core::value::HInt::compute_him(n).to_bits() as i64
289+
}
290+
275291
// ---------------------------------------------------------------------------
276292
// Binary i64,i64 -> i64 harmonic primitives
277293
// ---------------------------------------------------------------------------
@@ -641,6 +657,9 @@ impl<'ctx> JitContext<'ctx> {
641657
("omc_harmonic_unalign", omc_harmonic_unalign as *const () as usize),
642658
("omc_harmony_value", omc_harmony_value as *const () as usize),
643659
("omc_value_danger", omc_value_danger as *const () as usize),
660+
// Op::Resonance / Op::HimScore — f64 result packed as i64 bits.
661+
("omc_resonance_bits", omc_resonance_bits as *const () as usize),
662+
("omc_him_score_bits", omc_him_score_bits as *const () as usize),
644663
// Array-input intrinsics — same i64 -> i64 signature; the
645664
// input i64 is the L1.6 length-prefixed buffer pointer.
646665
("omc_arr_sum_int", omc_arr_sum_int as *const () as usize),
@@ -1030,6 +1049,7 @@ struct FunctionLowerer<'ctx, 'a> {
10301049
builder: Builder<'ctx>,
10311050
function: FunctionValue<'ctx>,
10321051
f: &'a CompiledFunction,
1052+
module: &'a LlvmModule<'ctx>,
10331053

10341054
/// One LLVM basic block per op-index leader, plus the entry block.
10351055
/// Map: bytecode op-index -> the LLVM block whose body begins there.
@@ -1066,6 +1086,7 @@ impl<'ctx, 'a> FunctionLowerer<'ctx, 'a> {
10661086
builder,
10671087
function,
10681088
f,
1089+
module,
10691090
blocks: HashMap::new(),
10701091
var_slots: HashMap::new(),
10711092
cleanup_pops: std::collections::HashSet::new(),
@@ -1524,6 +1545,43 @@ impl<'ctx, 'a> FunctionLowerer<'ctx, 'a> {
15241545
}
15251546
}
15261547

1548+
// ── Substrate ops ─────────────────────────────────────────
1549+
// All delegate to extern C shims already registered in the
1550+
// JIT engine. omc_fold/omc_is_attractor/omc_nth_fibonacci
1551+
// were registered in an earlier session; omc_resonance_bits
1552+
// and omc_him_score_bits were added this session.
1553+
// Resonance and HimScore return f64-as-i64-bits (same
1554+
// convention as the i64 register file for floats).
1555+
Op::Fold1 => {
1556+
let x = pop(&mut stack, i, "Fold1")?;
1557+
let result = self.emit_unary_extern_call("omc_fold", x, i)?;
1558+
stack.push(result);
1559+
}
1560+
1561+
Op::IsFibonacci => {
1562+
let x = pop(&mut stack, i, "IsFibonacci")?;
1563+
let result = self.emit_unary_extern_call("omc_is_attractor", x, i)?;
1564+
stack.push(result);
1565+
}
1566+
1567+
Op::Fibonacci => {
1568+
let x = pop(&mut stack, i, "Fibonacci")?;
1569+
let result = self.emit_unary_extern_call("omc_nth_fibonacci", x, i)?;
1570+
stack.push(result);
1571+
}
1572+
1573+
Op::Resonance => {
1574+
let x = pop(&mut stack, i, "Resonance")?;
1575+
let result = self.emit_unary_extern_call("omc_resonance_bits", x, i)?;
1576+
stack.push(result);
1577+
}
1578+
1579+
Op::HimScore => {
1580+
let x = pop(&mut stack, i, "HimScore")?;
1581+
let result = self.emit_unary_extern_call("omc_him_score_bits", x, i)?;
1582+
stack.push(result);
1583+
}
1584+
15271585
other => {
15281586
return Err(format!(
15291587
"Session B doesn't yet lower op: {:?} at op{}",
@@ -1701,6 +1759,33 @@ impl<'ctx, 'a> FunctionLowerer<'ctx, 'a> {
17011759
stack.push(i64v);
17021760
Ok(())
17031761
}
1762+
1763+
/// Emit a call to a pre-registered unary extern `fn(i64) -> i64`.
1764+
/// The function must already be declared in `self.module` (done during
1765+
/// JitContext initialisation). Returns the i64 result value.
1766+
fn emit_unary_extern_call(
1767+
&self,
1768+
name: &str,
1769+
arg: IntValue<'ctx>,
1770+
op_idx: usize,
1771+
) -> Result<IntValue<'ctx>, CodegenError> {
1772+
let ext_fn = self
1773+
.module
1774+
.get_function(name)
1775+
.ok_or_else(|| format!("{} not declared in module at op{}", name, op_idx))?;
1776+
let call = self
1777+
.builder
1778+
.build_call(ext_fn, &[arg.into()], &format!("{}_ret", name))
1779+
.map_err(|e| format!("{} call at op{}: {}", name, op_idx, e))?;
1780+
let ret = call
1781+
.try_as_basic_value()
1782+
.left()
1783+
.ok_or_else(|| format!("{} returned void at op{}", name, op_idx))?;
1784+
match ret {
1785+
inkwell::values::BasicValueEnum::IntValue(iv) => Ok(iv),
1786+
_ => Err(format!("{} returned non-int at op{}", name, op_idx)),
1787+
}
1788+
}
17041789
}
17051790

17061791
fn pop<'ctx>(

0 commit comments

Comments
 (0)