pr 30
This commit is contained in:
parent
ceaac6cab8
commit
9189d2a023
@ -159,7 +159,7 @@ mod tests {
|
|||||||
|
|
||||||
assert!(opcodes.contains(&OpCode::Alloc));
|
assert!(opcodes.contains(&OpCode::Alloc));
|
||||||
assert!(opcodes.contains(&OpCode::LoadRef));
|
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.
|
// because VM is feature-frozen. StoreRef is removed from lowering.
|
||||||
assert!(opcodes.contains(&OpCode::Nop));
|
assert!(opcodes.contains(&OpCode::Nop));
|
||||||
assert!(opcodes.contains(&OpCode::Add));
|
assert!(opcodes.contains(&OpCode::Add));
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use crate::frontends::pbs::ast::*;
|
|||||||
use crate::frontends::pbs::symbols::*;
|
use crate::frontends::pbs::symbols::*;
|
||||||
use crate::frontends::pbs::contracts::ContractRegistry;
|
use crate::frontends::pbs::contracts::ContractRegistry;
|
||||||
use crate::ir_core;
|
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 crate::ir_core::{Block, Function, Instr, Module, Param, Program, Terminator, Type};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@ -239,7 +239,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
// 3. Begin Operation
|
// 3. Begin Operation
|
||||||
self.emit(Instr::BeginPeek { gate: ValueId(gate_slot) });
|
self.emit(Instr::BeginPeek { gate: ValueId(gate_slot) });
|
||||||
self.emit(Instr::GetLocal(gate_slot));
|
self.emit(Instr::GetLocal(gate_slot));
|
||||||
self.emit(Instr::LoadRef(0));
|
self.emit(Instr::GateLoadField(FieldId(0)));
|
||||||
|
|
||||||
// 4. Bind view to local
|
// 4. Bind view to local
|
||||||
self.local_vars.push(HashMap::new());
|
self.local_vars.push(HashMap::new());
|
||||||
@ -269,7 +269,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
// 3. Begin Operation
|
// 3. Begin Operation
|
||||||
self.emit(Instr::BeginBorrow { gate: ValueId(gate_slot) });
|
self.emit(Instr::BeginBorrow { gate: ValueId(gate_slot) });
|
||||||
self.emit(Instr::GetLocal(gate_slot));
|
self.emit(Instr::GetLocal(gate_slot));
|
||||||
self.emit(Instr::LoadRef(0));
|
self.emit(Instr::GateLoadField(FieldId(0)));
|
||||||
|
|
||||||
// 4. Bind view to local
|
// 4. Bind view to local
|
||||||
self.local_vars.push(HashMap::new());
|
self.local_vars.push(HashMap::new());
|
||||||
@ -299,7 +299,7 @@ impl<'a> Lowerer<'a> {
|
|||||||
// 3. Begin Operation
|
// 3. Begin Operation
|
||||||
self.emit(Instr::BeginMutate { gate: ValueId(gate_slot) });
|
self.emit(Instr::BeginMutate { gate: ValueId(gate_slot) });
|
||||||
self.emit(Instr::GetLocal(gate_slot));
|
self.emit(Instr::GetLocal(gate_slot));
|
||||||
self.emit(Instr::LoadRef(0));
|
self.emit(Instr::GateLoadField(FieldId(0)));
|
||||||
|
|
||||||
// 4. Bind view to local
|
// 4. Bind view to local
|
||||||
self.local_vars.push(HashMap::new());
|
self.local_vars.push(HashMap::new());
|
||||||
|
|||||||
@ -19,3 +19,8 @@ pub struct TypeId(pub u32);
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct ValueId(pub u32);
|
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);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use super::ids::{ConstId, FunctionId, TypeId, ValueId};
|
use super::ids::{ConstId, FieldId, FunctionId, TypeId, ValueId};
|
||||||
|
|
||||||
/// Instructions within a basic block.
|
/// Instructions within a basic block.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
@ -40,9 +40,9 @@ pub enum Instr {
|
|||||||
EndPeek,
|
EndPeek,
|
||||||
EndBorrow,
|
EndBorrow,
|
||||||
EndMutate,
|
EndMutate,
|
||||||
/// Reads from heap at reference + offset. Pops reference, pushes value.
|
/// Reads from heap at gate + field. Pops gate, pushes value.
|
||||||
LoadRef(u32),
|
GateLoadField(FieldId),
|
||||||
/// Writes to heap at reference + offset. Pops reference and value.
|
/// Writes to heap at gate + field. Pops gate and value.
|
||||||
StoreRef(u32),
|
GateStoreField(FieldId),
|
||||||
Free,
|
Free,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -88,15 +88,15 @@ fn validate_function(func: &super::function::Function) -> Result<(), String> {
|
|||||||
None => return Err("EndMutate without matching BeginMutate".to_string()),
|
None => return Err("EndMutate without matching BeginMutate".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instr::LoadRef(_) => {
|
Instr::GateLoadField(_) => {
|
||||||
if current_stack.is_empty() {
|
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() {
|
match current_stack.last() {
|
||||||
Some(op) if op.kind == HipOpKind::Mutate => {},
|
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, _) => {
|
Instr::Call(id, _) => {
|
||||||
@ -180,9 +180,9 @@ mod tests {
|
|||||||
id: 0,
|
id: 0,
|
||||||
instrs: vec![
|
instrs: vec![
|
||||||
Instr::BeginPeek { gate: ValueId(0) },
|
Instr::BeginPeek { gate: ValueId(0) },
|
||||||
Instr::LoadRef(0),
|
Instr::GateLoadField(FieldId(0)),
|
||||||
Instr::BeginMutate { gate: ValueId(1) },
|
Instr::BeginMutate { gate: ValueId(1) },
|
||||||
Instr::StoreRef(0),
|
Instr::GateStoreField(FieldId(0)),
|
||||||
Instr::EndMutate,
|
Instr::EndMutate,
|
||||||
Instr::EndPeek,
|
Instr::EndPeek,
|
||||||
],
|
],
|
||||||
@ -229,7 +229,7 @@ mod tests {
|
|||||||
id: 0,
|
id: 0,
|
||||||
instrs: vec![
|
instrs: vec![
|
||||||
Instr::BeginBorrow { gate: ValueId(0) },
|
Instr::BeginBorrow { gate: ValueId(0) },
|
||||||
Instr::StoreRef(0),
|
Instr::GateStoreField(FieldId(0)),
|
||||||
Instr::EndBorrow,
|
Instr::EndBorrow,
|
||||||
],
|
],
|
||||||
terminator: Terminator::Return,
|
terminator: Terminator::Return,
|
||||||
@ -237,7 +237,7 @@ mod tests {
|
|||||||
let prog = create_dummy_program(create_dummy_function(vec![block]));
|
let prog = create_dummy_program(create_dummy_function(vec![block]));
|
||||||
let res = validate_program(&prog);
|
let res = validate_program(&prog);
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
assert!(res.unwrap_err().contains("StoreRef outside of BeginMutate"));
|
assert!(res.unwrap_err().contains("GateStoreField outside of BeginMutate"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -246,7 +246,7 @@ mod tests {
|
|||||||
id: 0,
|
id: 0,
|
||||||
instrs: vec![
|
instrs: vec![
|
||||||
Instr::BeginMutate { gate: ValueId(0) },
|
Instr::BeginMutate { gate: ValueId(0) },
|
||||||
Instr::StoreRef(0),
|
Instr::GateStoreField(FieldId(0)),
|
||||||
Instr::EndMutate,
|
Instr::EndMutate,
|
||||||
],
|
],
|
||||||
terminator: Terminator::Return,
|
terminator: Terminator::Return,
|
||||||
@ -260,14 +260,14 @@ mod tests {
|
|||||||
let block = Block {
|
let block = Block {
|
||||||
id: 0,
|
id: 0,
|
||||||
instrs: vec![
|
instrs: vec![
|
||||||
Instr::LoadRef(0),
|
Instr::GateLoadField(FieldId(0)),
|
||||||
],
|
],
|
||||||
terminator: Terminator::Return,
|
terminator: Terminator::Return,
|
||||||
};
|
};
|
||||||
let prog = create_dummy_program(create_dummy_function(vec![block]));
|
let prog = create_dummy_program(create_dummy_function(vec![block]));
|
||||||
let res = validate_program(&prog);
|
let res = validate_program(&prog);
|
||||||
assert!(res.is_err());
|
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]
|
#[test]
|
||||||
@ -282,7 +282,7 @@ mod tests {
|
|||||||
let block1 = Block {
|
let block1 = Block {
|
||||||
id: 1,
|
id: 1,
|
||||||
instrs: vec![
|
instrs: vec![
|
||||||
Instr::LoadRef(0),
|
Instr::GateLoadField(FieldId(0)),
|
||||||
Instr::EndPeek,
|
Instr::EndPeek,
|
||||||
],
|
],
|
||||||
terminator: Terminator::Return,
|
terminator: Terminator::Return,
|
||||||
|
|||||||
@ -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::EndPeek => ir_vm::InstrKind::GateEndPeek,
|
||||||
ir_core::Instr::EndBorrow => ir_vm::InstrKind::GateEndBorrow,
|
ir_core::Instr::EndBorrow => ir_vm::InstrKind::GateEndBorrow,
|
||||||
ir_core::Instr::EndMutate => ir_vm::InstrKind::GateEndMutate,
|
ir_core::Instr::EndMutate => ir_vm::InstrKind::GateEndMutate,
|
||||||
ir_core::Instr::LoadRef(offset) => ir_vm::InstrKind::GateLoad { offset: *offset },
|
ir_core::Instr::GateLoadField(field_id) => ir_vm::InstrKind::GateLoad { offset: field_id.0 },
|
||||||
ir_core::Instr::StoreRef(offset) => ir_vm::InstrKind::GateStore { offset: *offset },
|
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"),
|
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));
|
vm_func.body.push(ir_vm::Instruction::new(kind, None));
|
||||||
|
|||||||
@ -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)
|
# PR-06 — RC Hooks Documentation (No RC Yet)
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user