1use crate::vm::instruction::{CompiledProgram, Op};
17use crate::vm::reverse::{reversibility, EffectKind, InverseSpec, JournalKind, RevClass};
18
19pub fn rev_tag(op: &Op) -> String {
22 match reversibility(op) {
23 RevClass::Bijection(spec) => {
24 let inv = match spec {
25 InverseSpec::Involution => "self".to_string(),
26 InverseSpec::SelfFamily => "self-family".to_string(),
27 InverseSpec::NamedOp(n) => n.to_string(),
28 };
29 format!("REV zero-garbage, inverse={inv} (adiabatic charge-recovery)")
30 }
31 RevClass::Journaled(k) => {
32 let kind = match k {
33 JournalKind::Overwrite => "overwrite",
34 JournalKind::Collection => "collection",
35 JournalKind::InPlace => "in-place",
36 JournalKind::CrdtSnapshot => "crdt-snapshot",
37 };
38 format!("JRNL Bennett delta ({kind})")
39 }
40 RevClass::Effectful(e) => {
41 let kind = match e {
42 EffectKind::Output => "output-buffer",
43 EffectKind::Clock => "clock-capture",
44 EffectKind::Timer => "virtual-time",
45 EffectKind::Concurrency => "sched-trace",
46 EffectKind::Network => "IRREVERSIBLE-BARRIER (network)",
47 };
48 format!("EFF {kind}")
49 }
50 RevClass::Control => "CTRL reverse on trace".to_string(),
51 RevClass::NonReversible(why) => format!("!!!! UNCLASSIFIED: {why}"),
52 }
53}
54
55fn mnemonic(op: &Op) -> String {
58 match op {
59 Op::RevAdd { place, delta } => format!("REVADD r{place}, r{delta}"),
60 Op::RevSub { place, delta } => format!("REVSUB r{place}, r{delta}"),
61 Op::RevXor { place, delta } => format!("REVXOR r{place}, r{delta}"),
62 Op::RevNeg { place } => format!("REVNEG r{place}"),
63 Op::RevSwap { a, b } => format!("REVSWAP r{a}, r{b}"),
64 Op::LoadConst { dst, idx } => format!("LOADK r{dst}, k{idx}"),
65 Op::Move { dst, src } => format!("MOV r{dst}, r{src}"),
66 Op::Show { .. } => "SHOW".to_string(),
67 Op::Jump { target } => format!("JMP L{target}"),
68 Op::Halt => "HALT".to_string(),
69 other => other.name().to_uppercase(),
70 }
71}
72
73pub fn emit_isa(prog: &CompiledProgram) -> String {
76 let mut s = String::new();
77 s.push_str("; ============================================================================\n");
78 s.push_str("; LOGOS Silicon ISA — Tier 5 (register-VM opcode set = native chip ISA)\n");
79 s.push_str(
80 "; MAKE_A_CHIP §10.1 — each instruction annotated with its reversibility contract.\n",
81 );
82 s.push_str(
83 "; ============================================================================\n\n",
84 );
85
86 let (mut bij, mut jrnl, mut eff, mut ctrl) = (0usize, 0usize, 0usize, 0usize);
88 for op in &prog.code {
89 match reversibility(op) {
90 RevClass::Bijection(_) => bij += 1,
91 RevClass::Journaled(_) => jrnl += 1,
92 RevClass::Effectful(_) => eff += 1,
93 RevClass::Control => ctrl += 1,
94 RevClass::NonReversible(_) => {}
95 }
96 }
97 s.push_str(&format!(
98 "; reversibility budget: {bij} zero-garbage / {jrnl} journaled / {eff} effect / {ctrl} control\n\n"
99 ));
100
101 s.push_str(".text\n");
102 for (i, op) in prog.code.iter().enumerate() {
103 s.push_str(&format!(
104 " L{i:<4} {:<24} ; {}\n",
105 mnemonic(op),
106 rev_tag(op)
107 ));
108 }
109
110 if !prog.functions.is_empty() {
111 s.push_str("\n.functions\n");
112 for (fi, f) in prog.functions.iter().enumerate() {
113 s.push_str(&format!(
114 " fn{fi}: entry=L{} params={} regs={}\n",
115 f.entry_pc, f.param_count, f.register_count
116 ));
117 }
118 }
119
120 let sched = adiabatic_schedule(prog);
122 s.push_str(&format!(
123 "\n.adiabatic\n charge-recovery cells: {} ({:.0}%) | ancilla (history) cells: {} | effect: {} | control: {}\n",
124 sched.charge_recovery,
125 sched.charge_recovery_fraction() * 100.0,
126 sched.ancilla,
127 sched.effect,
128 sched.control,
129 ));
130 s
131}
132
133#[derive(Clone, Copy, PartialEq, Eq, Debug)]
138pub enum CellClass {
139 ChargeRecovery,
141 AncillaWrite,
143 EffectLog,
145 ControlTrace,
147}
148
149pub fn cell_class(op: &Op) -> CellClass {
153 match reversibility(op) {
154 RevClass::Bijection(_) => CellClass::ChargeRecovery,
155 RevClass::Journaled(_) => CellClass::AncillaWrite,
156 RevClass::Effectful(_) => CellClass::EffectLog,
157 RevClass::Control => CellClass::ControlTrace,
158 RevClass::NonReversible(_) => CellClass::AncillaWrite,
160 }
161}
162
163#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
167pub struct AdiabaticSchedule {
168 pub charge_recovery: usize,
169 pub ancilla: usize,
170 pub effect: usize,
171 pub control: usize,
172}
173
174impl AdiabaticSchedule {
175 pub fn is_fully_adiabatic(&self) -> bool {
179 self.ancilla == 0 && self.effect == 0
180 }
181
182 pub fn charge_recovery_fraction(&self) -> f64 {
184 let total = self.charge_recovery + self.ancilla + self.effect + self.control;
185 if total == 0 {
186 1.0
187 } else {
188 self.charge_recovery as f64 / total as f64
189 }
190 }
191}
192
193pub fn adiabatic_schedule(prog: &CompiledProgram) -> AdiabaticSchedule {
195 let mut s = AdiabaticSchedule::default();
196 for op in &prog.code {
197 match cell_class(op) {
198 CellClass::ChargeRecovery => s.charge_recovery += 1,
199 CellClass::AncillaWrite => s.ancilla += 1,
200 CellClass::EffectLog => s.effect += 1,
201 CellClass::ControlTrace => s.control += 1,
202 }
203 }
204 s
205}
206
207#[derive(Clone, Copy, PartialEq, Eq, Debug)]
215pub enum SiliconStatus {
216 CoreDatapath,
218 Datapath,
221 Sequencer,
223 LoadStore,
225 Coprocessor,
227}
228
229pub fn silicon_realized(op: &Op) -> bool {
237 matches!(
238 op,
239 Op::RevAdd { .. }
241 | Op::RevSub { .. }
242 | Op::RevXor { .. }
243 | Op::RevNeg { .. }
244 | Op::RevSwap { .. }
245 | Op::Add { .. }
247 | Op::AddAssign { .. }
248 | Op::Sub { .. }
249 | Op::Mul { .. }
250 | Op::Pow { .. }
251 | Op::Div { .. }
252 | Op::ExactDiv { .. }
253 | Op::Mod { .. }
254 | Op::FloorDiv { .. }
255 | Op::DivPow2 { .. }
256 | Op::MagicDivU { .. }
257 | Op::BitXor { .. }
258 | Op::BitAnd { .. }
259 | Op::BitOr { .. }
260 | Op::Not { .. }
261 | Op::Shl { .. }
262 | Op::Shr { .. }
263 | Op::Lt { .. }
264 | Op::Gt { .. }
265 | Op::LtEq { .. }
266 | Op::GtEq { .. }
267 | Op::Eq { .. }
268 | Op::ApproxEq { .. }
269 | Op::NotEq { .. }
270 | Op::EnsureOwned { .. }
271 | Op::Move { .. }
273 | Op::LoadConst { .. }
274 | Op::Jump { .. }
275 | Op::JumpIfFalse { .. }
276 | Op::JumpIfTrue { .. }
277 | Op::Halt
278 | Op::Show { .. }
279 | Op::Call { .. }
280 | Op::CallValue { .. }
281 | Op::MakeClosure { .. }
282 | Op::Return { .. }
283 | Op::ReturnNothing
284 | Op::FailWith { .. }
285 | Op::NewList { .. }
287 | Op::NewEmptyList { .. }
288 | Op::NewEmptyListFixed { .. }
289 | Op::NewEmptyListI32 { .. }
290 | Op::NewEmptyMap { .. }
291 | Op::ListPush { .. }
292 | Op::Index { .. }
293 | Op::IndexUnchecked { .. }
294 | Op::Length { .. }
295 | Op::FormatValue { .. }
296 | Op::NewTuple { .. }
297 | Op::ListPop { .. }
298 | Op::Contains { .. }
299 | Op::DestructureTuple { .. }
300 | Op::NewStruct { .. }
301 | Op::StructInsert { .. }
302 | Op::GetField { .. }
303 | Op::SetIndex { .. }
304 | Op::SetIndexUnchecked { .. }
305 | Op::SeqConcat { .. }
306 | Op::Concat { .. }
307 | Op::DeepClone { .. }
308 | Op::IterPrepare { .. }
309 | Op::IterNext { .. }
310 | Op::IterPop
311 | Op::RegionBoundsGuard { .. }
312 | Op::NewInductive { .. }
313 | Op::TestArm { .. }
314 | Op::BindArm { .. }
315 | Op::NewEmptySet { .. }
316 | Op::SetAdd { .. }
317 | Op::NewRange { .. }
318 | Op::UnionOp { .. }
319 | Op::IntersectOp { .. }
320 | Op::RemoveFrom { .. }
321 | Op::SliceOp { .. }
322 | Op::ListPushField { .. }
323 | Op::GlobalGet { .. }
324 | Op::GlobalSet { .. }
325 | Op::Args { .. }
326 | Op::ChanNew { .. }
328 | Op::ChanSend { .. }
329 | Op::ChanRecv { .. }
330 | Op::Spawn { .. }
331 | Op::CrdtBump { .. }
332 | Op::CrdtMerge { .. }
333 | Op::CrdtJoin { .. }
334 | Op::BigIntWide { .. }
335 | Op::NewCrdt { .. }
336 | Op::CrdtAppend { .. }
337 | Op::CrdtResolve { .. }
338 | Op::SelectArmRecv { .. }
339 | Op::SelectArmTimeout { .. }
340 | Op::SelectWait { .. }
341 | Op::ChanTrySend { .. }
342 | Op::ChanTryRecv { .. }
343 | Op::Sleep { .. }
344 | Op::LoadToday { .. }
345 | Op::LoadNow { .. }
346 | Op::Obs { .. }
347 | Op::SpawnHandle { .. }
348 | Op::TaskAbort { .. }
349 | Op::TaskAwait { .. }
350 | Op::ChanClose { .. }
351 | Op::CallBuiltin { .. }
352 | Op::CheckPolicy { .. }
353 | Op::NetConnect { .. }
355 | Op::NetListen { .. }
356 | Op::NetSend { .. }
357 | Op::NetStream { .. }
358 | Op::NetAwait { .. }
359 | Op::NetMakePeer { .. }
360 | Op::NetSync { .. }
361 )
362}
363
364pub fn coprocessor_realized(op: &Op) -> bool {
368 matches!(
369 op,
370 Op::ChanNew { .. }
371 | Op::ChanSend { .. }
372 | Op::ChanRecv { .. }
373 | Op::Spawn { .. }
374 | Op::CrdtBump { .. }
375 | Op::CrdtMerge { .. }
376 | Op::CrdtJoin { .. }
377 | Op::BigIntWide { .. }
378 | Op::NewCrdt { .. }
379 | Op::CrdtAppend { .. }
380 | Op::CrdtResolve { .. }
381 | Op::SelectArmRecv { .. }
382 | Op::SelectArmTimeout { .. }
383 | Op::SelectWait { .. }
384 | Op::ChanTrySend { .. }
385 | Op::ChanTryRecv { .. }
386 | Op::Sleep { .. }
387 | Op::LoadToday { .. }
388 | Op::LoadNow { .. }
389 | Op::Obs { .. }
390 | Op::SpawnHandle { .. }
391 | Op::TaskAbort { .. }
392 | Op::TaskAwait { .. }
393 | Op::ChanClose { .. }
394 | Op::CallBuiltin { .. }
395 | Op::CheckPolicy { .. }
396 | Op::NetConnect { .. }
397 | Op::NetListen { .. }
398 | Op::NetSend { .. }
399 | Op::NetStream { .. }
400 | Op::NetAwait { .. }
401 | Op::NetMakePeer { .. }
402 | Op::NetSync { .. }
403 )
404}
405
406pub fn soft_core_executes(op: &Op) -> bool {
411 matches!(
412 op,
413 Op::Move { .. }
414 | Op::LoadConst { .. }
415 | Op::Jump { .. }
416 | Op::JumpIfFalse { .. }
417 | Op::JumpIfTrue { .. }
418 | Op::Halt
419 | Op::Show { .. }
420 | Op::Call { .. }
421 | Op::CallValue { .. }
422 | Op::MakeClosure { .. }
423 | Op::Return { .. }
424 | Op::ReturnNothing
425 | Op::FailWith { .. }
426 )
427}
428
429pub fn load_store_realized(op: &Op) -> bool {
434 matches!(
435 op,
436 Op::NewList { .. }
437 | Op::NewEmptyList { .. }
438 | Op::NewEmptyListFixed { .. }
439 | Op::NewEmptyListI32 { .. }
440 | Op::NewEmptyMap { .. }
441 | Op::ListPush { .. }
442 | Op::Index { .. }
443 | Op::IndexUnchecked { .. }
444 | Op::Length { .. }
445 | Op::FormatValue { .. }
446 | Op::NewTuple { .. }
447 | Op::ListPop { .. }
448 | Op::Contains { .. }
449 | Op::DestructureTuple { .. }
450 | Op::NewStruct { .. }
451 | Op::StructInsert { .. }
452 | Op::GetField { .. }
453 | Op::SetIndex { .. }
454 | Op::SetIndexUnchecked { .. }
455 | Op::SeqConcat { .. }
456 | Op::Concat { .. }
457 | Op::DeepClone { .. }
458 | Op::IterPrepare { .. }
459 | Op::IterNext { .. }
460 | Op::IterPop
461 | Op::RegionBoundsGuard { .. }
462 | Op::NewInductive { .. }
463 | Op::TestArm { .. }
464 | Op::BindArm { .. }
465 | Op::NewEmptySet { .. }
466 | Op::SetAdd { .. }
467 | Op::NewRange { .. }
468 | Op::UnionOp { .. }
469 | Op::IntersectOp { .. }
470 | Op::RemoveFrom { .. }
471 | Op::SliceOp { .. }
472 | Op::ListPushField { .. }
473 | Op::GlobalGet { .. }
474 | Op::GlobalSet { .. }
475 | Op::Args { .. }
476 )
477}
478
479pub fn silicon_status(op: &Op) -> SiliconStatus {
483 use SiliconStatus::*;
484 match op {
485 Op::RevAdd { .. }
486 | Op::RevSub { .. }
487 | Op::RevXor { .. }
488 | Op::RevNeg { .. }
489 | Op::RevSwap { .. } => CoreDatapath,
490
491 Op::LoadConst { .. }
492 | Op::Move { .. }
493 | Op::EnsureOwned { .. }
494 | Op::Add { .. }
495 | Op::AddAssign { .. }
496 | Op::Sub { .. }
497 | Op::Mul { .. }
498 | Op::Div { .. }
499 | Op::ExactDiv { .. }
500 | Op::FloorDiv { .. }
501 | Op::Mod { .. }
502 | Op::DivPow2 { .. }
503 | Op::MagicDivU { .. }
504 | Op::Pow { .. }
505 | Op::BitXor { .. }
506 | Op::BitAnd { .. }
507 | Op::BitOr { .. }
508 | Op::Shl { .. }
509 | Op::Shr { .. }
510 | Op::Not { .. }
511 | Op::Lt { .. }
512 | Op::Gt { .. }
513 | Op::LtEq { .. }
514 | Op::GtEq { .. }
515 | Op::Eq { .. }
516 | Op::ApproxEq { .. }
517 | Op::NotEq { .. }
518 | Op::Concat { .. }
519 | Op::SeqConcat { .. } => Datapath,
520
521 Op::Jump { .. }
522 | Op::JumpIfFalse { .. }
523 | Op::JumpIfTrue { .. }
524 | Op::Call { .. }
525 | Op::CallValue { .. }
526 | Op::MakeClosure { .. }
527 | Op::Return { .. }
528 | Op::ReturnNothing
529 | Op::Halt => Sequencer,
530
531 Op::GlobalGet { .. }
532 | Op::GlobalSet { .. }
533 | Op::ListPushField { .. }
534 | Op::NewList { .. }
535 | Op::NewEmptyList { .. }
536 | Op::NewEmptyListFixed { .. }
537 | Op::NewEmptyListI32 { .. }
538 | Op::NewEmptySet { .. }
539 | Op::NewEmptyMap { .. }
540 | Op::NewRange { .. }
541 | Op::ListPush { .. }
542 | Op::SetAdd { .. }
543 | Op::RemoveFrom { .. }
544 | Op::SetIndex { .. }
545 | Op::SetIndexUnchecked { .. }
546 | Op::Index { .. }
547 | Op::IndexUnchecked { .. }
548 | Op::RegionBoundsGuard { .. }
549 | Op::Length { .. }
550 | Op::Contains { .. }
551 | Op::FormatValue { .. }
552 | Op::SliceOp { .. }
553 | Op::DeepClone { .. }
554 | Op::NewTuple { .. }
555 | Op::UnionOp { .. }
556 | Op::IntersectOp { .. }
557 | Op::ListPop { .. }
558 | Op::DestructureTuple { .. }
559 | Op::NewStruct { .. }
560 | Op::StructInsert { .. }
561 | Op::GetField { .. }
562 | Op::NewInductive { .. }
563 | Op::TestArm { .. }
564 | Op::BindArm { .. }
565 | Op::IterPrepare { .. }
566 | Op::IterNext { .. }
567 | Op::IterPop => LoadStore,
568
569 Op::CallBuiltin { .. }
570 | Op::CheckPolicy { .. }
571 | Op::NewEmptyListWithCapacity { .. }
572 | Op::NewEmptyMapWithCapacity { .. }
573 | Op::CrdtBump { .. }
574 | Op::CrdtMerge { .. }
575 | Op::CrdtJoin { .. }
576 | Op::BigIntWide { .. }
577 | Op::NewCrdt { .. }
578 | Op::CrdtAppend { .. }
579 | Op::CrdtResolve { .. }
580 | Op::LoadToday { .. }
581 | Op::LoadNow { .. }
582 | Op::Sleep { .. }
583 | Op::Show { .. }
584 | Op::Obs { .. }
585 | Op::Args { .. }
586 | Op::FailWith { .. }
587 | Op::ChanNew { .. }
588 | Op::ChanSend { .. }
589 | Op::ChanRecv { .. }
590 | Op::ChanTrySend { .. }
591 | Op::ChanTryRecv { .. }
592 | Op::ChanClose { .. }
593 | Op::Spawn { .. }
594 | Op::SpawnHandle { .. }
595 | Op::TaskAwait { .. }
596 | Op::TaskAbort { .. }
597 | Op::SelectArmRecv { .. }
598 | Op::SelectArmTimeout { .. }
599 | Op::SelectWait { .. }
600 | Op::NetConnect { .. }
601 | Op::NetListen { .. }
602 | Op::NetSend { .. }
603 | Op::NetStream { .. }
604 | Op::NetAwait { .. }
605 | Op::NetMakePeer { .. }
606 | Op::NetSync { .. }
607 | Op::Tcp { .. }
608 | Op::Serve { .. } => Coprocessor,
609 }
610}
611
612#[cfg(test)]
613#[path = "../../../logicaffeine_tests/unit/logicaffeine_compile/vm/isa/tests.rs"]
614mod tests;