2026-01-30 17:28:04 +00:00

127 lines
6.4 KiB
Rust

use prometeu_compiler::ir_core::{self, Program, Block, Instr, Terminator, ConstantValue, ConstPool};
use prometeu_compiler::ir_core::ids::{FunctionId, ConstId as CoreConstId, TypeId as CoreTypeId, FieldId, ValueId};
use prometeu_compiler::ir_vm::InstrKind;
use prometeu_compiler::lowering::lower_program;
use prometeu_compiler::backend::emit_bytecode::emit_module;
use prometeu_compiler::common::files::FileManager;
use std::collections::HashMap;
#[test]
fn test_hip_conformance_core_to_vm_to_bytecode() {
// 1. Setup Core IR Program
let mut const_pool = ConstPool::new();
let _val_const = const_pool.insert(ConstantValue::Int(42));
let type_id = CoreTypeId(10);
let field_id = FieldId(1);
let mut field_offsets = HashMap::new();
field_offsets.insert(field_id, 0); // Field at offset 0
let mut field_types = HashMap::new();
field_types.insert(field_id, ir_core::Type::Int);
let program = Program {
const_pool,
modules: vec![ir_core::Module {
name: "conformance".to_string(),
functions: vec![ir_core::Function {
id: FunctionId(1),
name: "main".to_string(),
params: vec![],
return_type: ir_core::Type::Void,
local_types: HashMap::new(),
blocks: vec![Block {
id: 0,
instrs: vec![
// allocates a storage struct
Instr::Alloc { ty: type_id, slots: 2 },
Instr::SetLocal(0), // x = alloc
// mutates a field
Instr::BeginMutate { gate: ValueId(0) },
Instr::PushConst(CoreConstId(0)),
Instr::SetLocal(1), // v = 42
Instr::GateStoreField { gate: ValueId(0), field: field_id, value: ValueId(1) },
Instr::EndMutate,
// peeks value
Instr::BeginPeek { gate: ValueId(0) },
Instr::GateLoadField { gate: ValueId(0), field: field_id },
Instr::EndPeek,
Instr::Pop, // clean up the peeked value
],
terminator: Terminator::Return,
}],
}],
}],
field_offsets,
field_types,
};
// 2. Lower to VM IR
let vm_module = lower_program(&program).expect("Lowering failed");
let func = &vm_module.functions[0];
// Assert VM IR contains required instructions
let kinds: Vec<_> = func.body.iter().map(|i| &i.kind).collect();
assert!(kinds.iter().any(|k| matches!(k, InstrKind::Alloc { type_id: tid, slots: 2 } if tid.0 == 10)), "Missing correct Alloc");
assert!(kinds.contains(&&InstrKind::GateBeginMutate), "Missing GateBeginMutate");
assert!(kinds.contains(&&InstrKind::GateEndMutate), "Missing GateEndMutate");
assert!(kinds.iter().any(|k| matches!(k, InstrKind::GateStore { offset: 0 })), "Missing correct GateStore");
assert!(kinds.contains(&&InstrKind::GateBeginPeek), "Missing GateBeginPeek");
assert!(kinds.contains(&&InstrKind::GateEndPeek), "Missing GateEndPeek");
assert!(kinds.iter().any(|k| matches!(k, InstrKind::GateLoad { offset: 0 })), "Missing correct GateLoad");
// RC ops
assert!(kinds.contains(&&InstrKind::GateRetain), "Missing GateRetain");
assert!(kinds.contains(&&InstrKind::GateRelease), "Missing GateRelease");
// 3. Emit Bytecode
let file_manager = FileManager::new();
let emit_result = emit_module(&vm_module, &file_manager).expect("Emission failed");
let bytecode = emit_result.rom;
// 4. Assert exact bytes match frozen ISA/ABI
let expected_bytecode = vec![
0x50, 0x50, 0x42, 0x43, // Magic: "PPBC"
0x00, 0x00, // Version: 0
0x00, 0x00, // Flags: 0
0x02, 0x00, 0x00, 0x00, // CP Count: 2
0x00, // CP[0]: Null
0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // CP[1]: Int64(42)
0x6c, 0x00, 0x00, 0x00, // ROM Size: 108
// Instructions:
0x60, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // Alloc { tid: 10, slots: 2 }
0x43, 0x00, 0x00, 0x00, 0x00, 0x00, // SetLocal 0
0x42, 0x00, 0x00, 0x00, 0x00, 0x00, // GetLocal 0
0x69, 0x00, // GateRetain
0x67, 0x00, // GateBeginMutate
0x10, 0x00, 0x01, 0x00, 0x00, 0x00, // PushConst 1 (42)
0x43, 0x00, 0x01, 0x00, 0x00, 0x00, // SetLocal 1
0x42, 0x00, 0x00, 0x00, 0x00, 0x00, // GetLocal 0
0x69, 0x00, // GateRetain
0x42, 0x00, 0x01, 0x00, 0x00, 0x00, // GetLocal 1
0x62, 0x00, 0x00, 0x00, 0x00, 0x00, // GateStore 0
0x68, 0x00, // GateEndMutate
0x6a, 0x00, // GateRelease
0x42, 0x00, 0x00, 0x00, 0x00, 0x00, // GetLocal 0
0x69, 0x00, // GateRetain
0x63, 0x00, // GateBeginPeek
0x42, 0x00, 0x00, 0x00, 0x00, 0x00, // GetLocal 0
0x69, 0x00, // GateRetain
0x61, 0x00, 0x00, 0x00, 0x00, 0x00, // GateLoad 0
0x64, 0x00, // GateEndPeek
0x6a, 0x00, // GateRelease
0x11, 0x00, // Pop
0x42, 0x00, 0x00, 0x00, 0x00, 0x00, // GetLocal 0 (cleanup)
0x6a, 0x00, // GateRelease
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, // PushConst 0 (Null return)
0x51, 0x00, // Ret
];
assert_eq!(bytecode, expected_bytecode, "Bytecode does not match golden ISA/ABI v0");
}