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) 0x66, 0x00, 0x00, 0x00, // ROM Size: 102 // 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 0x51, 0x00, // Ret ]; assert_eq!(bytecode, expected_bytecode, "Bytecode does not match golden ISA/ABI v0"); }