This commit is contained in:
Nilton Constantino 2026-01-30 12:34:38 +00:00
parent ceaac6cab8
commit 9189d2a023
No known key found for this signature in database
7 changed files with 29 additions and 55 deletions

View File

@ -159,7 +159,7 @@ mod tests {
assert!(opcodes.contains(&OpCode::Alloc));
assert!(opcodes.contains(&OpCode::LoadRef));
// After PR-20, BeginMutate/EndMutate map to LoadRef/Nop for now
// After PR-05, BeginMutate/EndMutate map to GateLoad/Nop for now
// because VM is feature-frozen. StoreRef is removed from lowering.
assert!(opcodes.contains(&OpCode::Nop));
assert!(opcodes.contains(&OpCode::Add));

View File

@ -3,7 +3,7 @@ use crate::frontends::pbs::ast::*;
use crate::frontends::pbs::symbols::*;
use crate::frontends::pbs::contracts::ContractRegistry;
use crate::ir_core;
use crate::ir_core::ids::{FunctionId, TypeId, ValueId};
use crate::ir_core::ids::{FieldId, FunctionId, TypeId, ValueId};
use crate::ir_core::{Block, Function, Instr, Module, Param, Program, Terminator, Type};
use std::collections::HashMap;
@ -239,7 +239,7 @@ impl<'a> Lowerer<'a> {
// 3. Begin Operation
self.emit(Instr::BeginPeek { gate: ValueId(gate_slot) });
self.emit(Instr::GetLocal(gate_slot));
self.emit(Instr::LoadRef(0));
self.emit(Instr::GateLoadField(FieldId(0)));
// 4. Bind view to local
self.local_vars.push(HashMap::new());
@ -269,7 +269,7 @@ impl<'a> Lowerer<'a> {
// 3. Begin Operation
self.emit(Instr::BeginBorrow { gate: ValueId(gate_slot) });
self.emit(Instr::GetLocal(gate_slot));
self.emit(Instr::LoadRef(0));
self.emit(Instr::GateLoadField(FieldId(0)));
// 4. Bind view to local
self.local_vars.push(HashMap::new());
@ -299,7 +299,7 @@ impl<'a> Lowerer<'a> {
// 3. Begin Operation
self.emit(Instr::BeginMutate { gate: ValueId(gate_slot) });
self.emit(Instr::GetLocal(gate_slot));
self.emit(Instr::LoadRef(0));
self.emit(Instr::GateLoadField(FieldId(0)));
// 4. Bind view to local
self.local_vars.push(HashMap::new());

View File

@ -19,3 +19,8 @@ pub struct TypeId(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ValueId(pub u32);
/// Unique identifier for a field within a HIP object.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct FieldId(pub u32);

View File

@ -1,5 +1,5 @@
use serde::{Deserialize, Serialize};
use super::ids::{ConstId, FunctionId, TypeId, ValueId};
use super::ids::{ConstId, FieldId, FunctionId, TypeId, ValueId};
/// Instructions within a basic block.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
@ -40,9 +40,9 @@ pub enum Instr {
EndPeek,
EndBorrow,
EndMutate,
/// Reads from heap at reference + offset. Pops reference, pushes value.
LoadRef(u32),
/// Writes to heap at reference + offset. Pops reference and value.
StoreRef(u32),
/// Reads from heap at gate + field. Pops gate, pushes value.
GateLoadField(FieldId),
/// Writes to heap at gate + field. Pops gate and value.
GateStoreField(FieldId),
Free,
}

View File

@ -88,15 +88,15 @@ fn validate_function(func: &super::function::Function) -> Result<(), String> {
None => return Err("EndMutate without matching BeginMutate".to_string()),
}
}
Instr::LoadRef(_) => {
Instr::GateLoadField(_) => {
if current_stack.is_empty() {
return Err("LoadRef outside of HIP operation".to_string());
return Err("GateLoadField outside of HIP operation".to_string());
}
}
Instr::StoreRef(_) => {
Instr::GateStoreField(_) => {
match current_stack.last() {
Some(op) if op.kind == HipOpKind::Mutate => {},
_ => return Err("StoreRef outside of BeginMutate".to_string()),
_ => return Err("GateStoreField outside of BeginMutate".to_string()),
}
}
Instr::Call(id, _) => {
@ -180,9 +180,9 @@ mod tests {
id: 0,
instrs: vec![
Instr::BeginPeek { gate: ValueId(0) },
Instr::LoadRef(0),
Instr::GateLoadField(FieldId(0)),
Instr::BeginMutate { gate: ValueId(1) },
Instr::StoreRef(0),
Instr::GateStoreField(FieldId(0)),
Instr::EndMutate,
Instr::EndPeek,
],
@ -229,7 +229,7 @@ mod tests {
id: 0,
instrs: vec![
Instr::BeginBorrow { gate: ValueId(0) },
Instr::StoreRef(0),
Instr::GateStoreField(FieldId(0)),
Instr::EndBorrow,
],
terminator: Terminator::Return,
@ -237,7 +237,7 @@ mod tests {
let prog = create_dummy_program(create_dummy_function(vec![block]));
let res = validate_program(&prog);
assert!(res.is_err());
assert!(res.unwrap_err().contains("StoreRef outside of BeginMutate"));
assert!(res.unwrap_err().contains("GateStoreField outside of BeginMutate"));
}
#[test]
@ -246,7 +246,7 @@ mod tests {
id: 0,
instrs: vec![
Instr::BeginMutate { gate: ValueId(0) },
Instr::StoreRef(0),
Instr::GateStoreField(FieldId(0)),
Instr::EndMutate,
],
terminator: Terminator::Return,
@ -260,14 +260,14 @@ mod tests {
let block = Block {
id: 0,
instrs: vec![
Instr::LoadRef(0),
Instr::GateLoadField(FieldId(0)),
],
terminator: Terminator::Return,
};
let prog = create_dummy_program(create_dummy_function(vec![block]));
let res = validate_program(&prog);
assert!(res.is_err());
assert!(res.unwrap_err().contains("LoadRef outside of HIP operation"));
assert!(res.unwrap_err().contains("GateLoadField outside of HIP operation"));
}
#[test]
@ -282,7 +282,7 @@ mod tests {
let block1 = Block {
id: 1,
instrs: vec![
Instr::LoadRef(0),
Instr::GateLoadField(FieldId(0)),
Instr::EndPeek,
],
terminator: Terminator::Return,

View File

@ -81,8 +81,8 @@ pub fn lower_function(core_func: &ir_core::Function) -> Result<ir_vm::Function>
ir_core::Instr::EndPeek => ir_vm::InstrKind::GateEndPeek,
ir_core::Instr::EndBorrow => ir_vm::InstrKind::GateEndBorrow,
ir_core::Instr::EndMutate => ir_vm::InstrKind::GateEndMutate,
ir_core::Instr::LoadRef(offset) => ir_vm::InstrKind::GateLoad { offset: *offset },
ir_core::Instr::StoreRef(offset) => ir_vm::InstrKind::GateStore { offset: *offset },
ir_core::Instr::GateLoadField(field_id) => ir_vm::InstrKind::GateLoad { offset: field_id.0 },
ir_core::Instr::GateStoreField(field_id) => ir_vm::InstrKind::GateStore { offset: field_id.0 },
ir_core::Instr::Free => anyhow::bail!("Instruction 'Free' cannot be represented in ir_vm v0"),
};
vm_func.body.push(ir_vm::Instruction::new(kind, None));

View File

@ -1,34 +1,3 @@
# PR-05 — Gate-Aware Access Path (Choose One, Explicitly)
### Goal
Close the loop between Core IR access semantics and VM IR access execution.
### Choose One Approach (Explicit in PR Description)
#### Approach A (Preferred)
* Core IR expresses semantic access:
* `CoreGateLoadField(field_id)`
* `CoreGateStoreField(field_id)`
* Lowering resolves `field_id``offset`
* VM IR emits `GateLoad/GateStore`
#### Approach B (Minimal)
* Core IR already carries `offset`
* Lowering maps directly to `GateLoad/GateStore`
**Hard rule:** no direct heap access, no fake offsets.
### Tests
* Lowering emits correct offsets
* Offset is visible in VM IR (not implicit)
---
# PR-06 — RC Hooks Documentation (No RC Yet)
### Goal