selfhost/runtime: Stage 0-1 runner + MIR JSON loader (summary) with trace; compiler: scopebox/loopform prepass wiring (flags, child args); libs: add P1 standard boxes (console/string/array/map) as thin wrappers; runner: pass --box-pref via env; ops_calls dispatcher skeleton; docs: selfhost executor roadmap + scopebox/loopform notes; smokes: selfhost runner + identity prepasses; CURRENT_TASK: update plan and box lib schedule

This commit is contained in:
Selfhosting Dev
2025-09-22 21:52:39 +09:00
parent b00dc4ec37
commit da78fc174b
72 changed files with 3163 additions and 2557 deletions

View File

@ -5,6 +5,9 @@
*/
use super::{Effect, EffectMask, ValueId};
use crate::mir::types::{
BarrierOp, BinaryOp, CompareOp, ConstValue, MirType, TypeOpKind, UnaryOp, WeakRefOp,
};
// use crate::value::NyashValue; // Commented out to avoid circular dependency
use std::fmt;
@ -291,76 +294,7 @@ pub enum MirInstruction {
},
}
/// Constant values in MIR
#[derive(Debug, Clone, PartialEq)]
pub enum ConstValue {
Integer(i64),
Float(f64),
Bool(bool),
String(String),
Null,
Void,
}
/// Binary operations
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
// Arithmetic
Add,
Sub,
Mul,
Div,
Mod,
// Bitwise
BitAnd,
BitOr,
BitXor,
Shl,
Shr,
// Logical
And,
Or,
}
/// Unary operations
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
// Arithmetic
Neg,
// Logical
Not,
// Bitwise
BitNot,
}
/// Comparison operations
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompareOp {
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
/// MIR type system
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MirType {
Integer,
Float,
Bool,
String,
Box(String), // Box type with name
Array(Box<MirType>),
Future(Box<MirType>), // Future containing a type
Void,
Unknown,
}
// types moved to crate::mir::types
impl MirInstruction {
/// Get the effect mask for this instruction
@ -587,26 +521,7 @@ impl MirInstruction {
}
}
/// Kind of unified type operation (PoC)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TypeOpKind {
Check,
Cast,
}
/// Kind of unified weak reference operation (PoC)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WeakRefOp {
New,
Load,
}
/// Kind of unified barrier operation (PoC)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BarrierOp {
Read,
Write,
}
// enums TypeOpKind/WeakRefOp/BarrierOp moved to crate::mir::types
impl ConstValue {
/*
@ -767,18 +682,7 @@ impl fmt::Display for MirInstruction {
}
}
impl fmt::Display for ConstValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ConstValue::Integer(n) => write!(f, "{}", n),
ConstValue::Float(fl) => write!(f, "{}", fl),
ConstValue::Bool(b) => write!(f, "{}", b),
ConstValue::String(s) => write!(f, "\"{}\"", s),
ConstValue::Null => write!(f, "null"),
ConstValue::Void => write!(f, "void"),
}
}
}
// Display for ConstValue moved to crate::mir::types
#[cfg(test)]

View File

@ -6,9 +6,10 @@
//! in `MirInstruction`.
use super::{BasicBlockId, ConstValue, Effect, EffectMask, ValueId};
use crate::mir::instruction::{
BarrierOp as MirBarrierOp, BinaryOp as MirBinOp, MirInstruction, MirType,
TypeOpKind as MirTypeOpKind, WeakRefOp as MirWeakRefOp,
use crate::mir::instruction::MirInstruction;
use crate::mir::types::{
BarrierOp as MirBarrierOp, BinaryOp as MirBinOp, MirType, TypeOpKind as MirTypeOpKind,
WeakRefOp as MirWeakRefOp,
};
// Local macro utilities for generating InstructionMeta boilerplate.
@ -114,6 +115,13 @@ pub fn effects_via_meta(i: &MirInstruction) -> Option<EffectMask> {
if let Some(k) = JumpInst::from_mir(i) { return Some(k.effects()); }
if let Some(k) = PrintInst::from_mir(i) { return Some(k.effects()); }
if let Some(k) = DebugInst::from_mir(i) { return Some(k.effects()); }
if let Some(k) = TypeCheckInst::from_mir(i) { return Some(k.effects()); }
if let Some(k) = CopyInst::from_mir(i) { return Some(k.effects()); }
if let Some(k) = NopInst::from_mir(i) { return Some(k.effects()); }
if let Some(k) = ThrowInst::from_mir(i) { return Some(k.effects()); }
if let Some(k) = CatchInst::from_mir(i) { return Some(k.effects()); }
if let Some(k) = SafepointInst::from_mir(i) { return Some(k.effects()); }
if let Some(k) = FunctionNewInst::from_mir(i) { return Some(k.effects()); }
None
}
@ -136,6 +144,13 @@ pub fn dst_via_meta(i: &MirInstruction) -> Option<ValueId> {
if let Some(_k) = PrintInst::from_mir(i) { return None; }
if let Some(_k) = DebugInst::from_mir(i) { return None; }
if let Some(k) = CallLikeInst::from_mir(i) { return k.dst(); }
if let Some(k) = TypeCheckInst::from_mir(i) { return k.dst(); }
if let Some(k) = CopyInst::from_mir(i) { return k.dst(); }
if let Some(_k) = NopInst::from_mir(i) { return None; }
if let Some(_k) = ThrowInst::from_mir(i) { return None; }
if let Some(k) = CatchInst::from_mir(i) { return k.dst(); }
if let Some(_k) = SafepointInst::from_mir(i) { return None; }
if let Some(k) = FunctionNewInst::from_mir(i) { return k.dst(); }
None
}
@ -158,6 +173,13 @@ pub fn used_via_meta(i: &MirInstruction) -> Option<Vec<ValueId>> {
if let Some(k) = PrintInst::from_mir(i) { return Some(k.used()); }
if let Some(k) = DebugInst::from_mir(i) { return Some(k.used()); }
if let Some(k) = CallLikeInst::from_mir(i) { return Some(k.used()); }
if let Some(k) = TypeCheckInst::from_mir(i) { return Some(k.used()); }
if let Some(k) = CopyInst::from_mir(i) { return Some(k.used()); }
if let Some(k) = NopInst::from_mir(i) { return Some(k.used()); }
if let Some(k) = ThrowInst::from_mir(i) { return Some(k.used()); }
if let Some(k) = CatchInst::from_mir(i) { return Some(k.used()); }
if let Some(k) = SafepointInst::from_mir(i) { return Some(k.used()); }
if let Some(k) = FunctionNewInst::from_mir(i) { return Some(k.used()); }
None
}
@ -369,6 +391,17 @@ inst_meta! {
}
}
// ---- FunctionNew ---- (macro-generated)
inst_meta! {
pub struct FunctionNewInst { dst: ValueId, captures: Vec<(String, ValueId)>, me: Option<ValueId> }
=> {
from_mir = |i| match i { MirInstruction::FunctionNew { dst, captures, me, .. } => Some(FunctionNewInst { dst: *dst, captures: captures.clone(), me: *me }), _ => None };
effects = |_: &Self| EffectMask::PURE.add(Effect::Alloc);
dst = |s: &Self| Some(s.dst);
used = |s: &Self| { let mut v: Vec<ValueId> = s.captures.iter().map(|(_, id)| *id).collect(); if let Some(m) = s.me { v.push(m); } v };
}
}
// ---- Store ---- (macro-generated)
inst_meta! {
pub struct StoreInst { value: ValueId, ptr: ValueId }
@ -446,6 +479,72 @@ inst_meta! {
}
}
// ---- TypeCheck ---- (macro-generated)
inst_meta! {
pub struct TypeCheckInst { dst: ValueId, value: ValueId }
=> {
from_mir = |i| match i { MirInstruction::TypeCheck { dst, value, .. } => Some(TypeCheckInst { dst: *dst, value: *value }), _ => None };
effects = |_: &Self| EffectMask::PURE;
dst = |s: &Self| Some(s.dst);
used = |s: &Self| vec![s.value];
}
}
// ---- Copy ---- (macro-generated)
inst_meta! {
pub struct CopyInst { dst: ValueId, src: ValueId }
=> {
from_mir = |i| match i { MirInstruction::Copy { dst, src } => Some(CopyInst { dst: *dst, src: *src }), _ => None };
effects = |_: &Self| EffectMask::PURE;
dst = |s: &Self| Some(s.dst);
used = |s: &Self| vec![s.src];
}
}
// ---- Nop ---- (macro-generated)
inst_meta! {
pub struct NopInst { }
=> {
from_mir = |i| match i { MirInstruction::Nop => Some(NopInst {}), _ => None };
effects = |_: &Self| EffectMask::PURE;
dst = |_: &Self| None;
used = |_: &Self| Vec::new();
}
}
// ---- Throw ---- (macro-generated)
inst_meta! {
pub struct ThrowInst { exception: ValueId, effects_mask: EffectMask }
=> {
from_mir = |i| match i { MirInstruction::Throw { exception, effects } => Some(ThrowInst { exception: *exception, effects_mask: *effects }), _ => None };
effects = |s: &Self| s.effects_mask;
dst = |_: &Self| None;
used = |s: &Self| vec![s.exception];
}
}
// ---- Catch ---- (macro-generated)
inst_meta! {
pub struct CatchInst { exception_value: ValueId }
=> {
from_mir = |i| match i { MirInstruction::Catch { exception_value, .. } => Some(CatchInst { exception_value: *exception_value }), _ => None };
effects = |_: &Self| EffectMask::CONTROL;
dst = |s: &Self| Some(s.exception_value);
used = |_: &Self| Vec::new();
}
}
// ---- Safepoint ---- (macro-generated)
inst_meta! {
pub struct SafepointInst { }
=> {
from_mir = |i| match i { MirInstruction::Safepoint => Some(SafepointInst {}), _ => None };
effects = |_: &Self| EffectMask::PURE;
dst = |_: &Self| None;
used = |_: &Self| Vec::new();
}
}
// ---- Call-like (dst/used only; effects fallback in MirInstruction) ----
#[derive(Debug, Clone)]
pub enum CallLikeInst {

View File

@ -75,7 +75,7 @@ pub fn build_simple_loop<L: LoopBuilderApi>(
let void_id = lb.new_value();
lb.emit(MirInstruction::Const {
dst: void_id,
value: super::instruction::ConstValue::Void,
value: crate::mir::ConstValue::Void,
})?;
Ok(void_id)
}

View File

@ -42,47 +42,14 @@ pub struct LoopBuilder<'a> {
no_phi_mode: bool,
}
// Local copy: detect a variable name assigned within an AST fragment
fn extract_assigned_var_local(ast: &ASTNode) -> Option<String> {
match ast {
ASTNode::Assignment { target, .. } => {
if let ASTNode::Variable { name, .. } = target.as_ref() {
Some(name.clone())
} else {
None
}
}
ASTNode::Program { statements, .. } => statements
.last()
.and_then(|st| extract_assigned_var_local(st)),
ASTNode::If {
then_body,
else_body,
..
} => {
let then_prog = ASTNode::Program {
statements: then_body.clone(),
span: crate::ast::Span::unknown(),
};
let tvar = extract_assigned_var_local(&then_prog);
let evar = else_body.as_ref().and_then(|eb| {
let ep = ASTNode::Program {
statements: eb.clone(),
span: crate::ast::Span::unknown(),
};
extract_assigned_var_local(&ep)
});
match (tvar, evar) {
(Some(tv), Some(ev)) if tv == ev => Some(tv),
_ => None,
}
}
_ => None,
}
}
// (removed) extract_assigned_var_local was a local helper used during
// diagnostics and is no longer referenced. Keep the file lean and avoid
// dead_code warnings.
impl<'a> LoopBuilder<'a> {
// --- Small helpers for continue/break commonization ---
// =============================================================
// Control Helpers — break/continue/jumps/unreachable handling
// =============================================================
/// Emit a jump to `target` from the current block and record predecessor metadata.
fn jump_with_pred(&mut self, target: BasicBlockId) -> Result<(), String> {
@ -124,6 +91,9 @@ impl<'a> LoopBuilder<'a> {
self.switch_to_unreachable_block_with_void()
}
// =============================================================
// Lifecycle — create builder, main loop construction
// =============================================================
/// 新しいループビルダーを作成
pub fn new(parent: &'a mut super::builder::MirBuilder) -> Self {
let no_phi_mode = parent.is_no_phi_mode();
@ -272,6 +242,9 @@ impl<'a> LoopBuilder<'a> {
Ok(void_dst)
}
// =============================================================
// PHI Helpers — prepare/finalize PHIs and block sealing
// =============================================================
/// ループ変数の準備(事前検出または遅延生成)
fn prepare_loop_variables(
&mut self,
@ -400,6 +373,7 @@ impl<'a> LoopBuilder<'a> {
.emit_instruction(MirInstruction::Const { dst, value })
}
/// ブロック先頭に PHI 命令を挿入(不変条件: PHI は常にブロック先頭)
fn emit_phi_at_block_start(
&mut self,
block_id: BasicBlockId,
@ -454,6 +428,9 @@ impl<'a> LoopBuilder<'a> {
}
}
// =============================================================
// Variable Map Utilities — snapshots and rebinding
// =============================================================
fn get_current_variable_map(&self) -> HashMap<String, ValueId> {
self.parent_builder.variable_map.clone()
}
@ -509,192 +486,157 @@ impl<'a> LoopBuilder<'a> {
void_id
}))
}
ASTNode::If {
condition,
then_body,
else_body,
..
} => {
// Lower a simple if inside loop, ensuring continue/break inside branches are handled
let cond_val = self.parent_builder.build_expression(*condition.clone())?;
let then_bb = self.new_block();
let else_bb = self.new_block();
let merge_bb = self.new_block();
self.emit_branch(cond_val, then_bb, else_bb)?;
// Capture pre-if variable map (used for phi normalization)
let pre_if_var_map = self.get_current_variable_map();
let pre_then_var_value = pre_if_var_map.clone();
// then
self.set_current_block(then_bb)?;
for s in then_body.iter().cloned() {
let _ = self.build_statement(s)?;
// Stop if block terminated
let cur_id = self.current_block()?;
let terminated = {
if let Some(ref fun_ro) = self.parent_builder.current_function {
if let Some(bb) = fun_ro.get_block(cur_id) {
bb.is_terminated()
} else {
false
}
} else {
false
}
};
if terminated {
break;
}
}
let then_var_map_end = self.get_current_variable_map();
// Only jump to merge if not already terminated (e.g., continue/break)
let then_reaches_merge = {
let cur_id = self.current_block()?;
let need_jump = {
if let Some(ref fun_ro) = self.parent_builder.current_function {
if let Some(bb) = fun_ro.get_block(cur_id) {
!bb.is_terminated()
} else {
false
}
} else {
false
}
};
if need_jump {
self.emit_jump(merge_bb)?;
true
} else {
false
}
};
// else
self.set_current_block(else_bb)?;
let mut else_var_map_end_opt: Option<
std::collections::HashMap<String, super::ValueId>,
> = None;
if let Some(es) = else_body.clone() {
for s in es.into_iter() {
let _ = self.build_statement(s)?;
let cur_id = self.current_block()?;
let terminated = {
if let Some(ref fun_ro) = self.parent_builder.current_function {
if let Some(bb) = fun_ro.get_block(cur_id) {
bb.is_terminated()
} else {
false
}
} else {
false
}
};
if terminated {
break;
}
}
else_var_map_end_opt = Some(self.get_current_variable_map());
}
let else_reaches_merge = {
let cur_id = self.current_block()?;
let need_jump = {
if let Some(ref fun_ro) = self.parent_builder.current_function {
if let Some(bb) = fun_ro.get_block(cur_id) {
!bb.is_terminated()
} else {
false
}
} else {
false
}
};
if need_jump {
self.emit_jump(merge_bb)?;
true
} else {
false
}
};
// Continue at merge
self.set_current_block(merge_bb)?;
// If branches assign variables, emit PHIs per variable and bind them.
// Previous logic handled only a single variable; here we generalize to all assigned vars.
fn collect_assigned_vars(ast: &ASTNode, out: &mut std::collections::HashSet<String>) {
match ast {
ASTNode::Assignment { target, .. } => {
if let ASTNode::Variable { name, .. } = target.as_ref() {
out.insert(name.clone());
}
}
ASTNode::Program { statements, .. } => {
for s in statements { collect_assigned_vars(s, out); }
}
ASTNode::If { then_body, else_body, .. } => {
let tp = ASTNode::Program { statements: then_body.clone(), span: crate::ast::Span::unknown() };
collect_assigned_vars(&tp, out);
if let Some(eb) = else_body {
let ep = ASTNode::Program { statements: eb.clone(), span: crate::ast::Span::unknown() };
collect_assigned_vars(&ep, out);
}
}
_ => {}
}
}
let mut vars: std::collections::HashSet<String> = std::collections::HashSet::new();
let then_prog = ASTNode::Program { statements: then_body.clone(), span: crate::ast::Span::unknown() };
collect_assigned_vars(&then_prog, &mut vars);
if let Some(es) = &else_body {
let else_prog = ASTNode::Program { statements: es.clone(), span: crate::ast::Span::unknown() };
collect_assigned_vars(&else_prog, &mut vars);
}
// Reset to pre-if map before rebinding to ensure a clean environment
self.parent_builder.variable_map = pre_if_var_map.clone();
for var_name in vars.into_iter() {
// then-side value: from then end map if assigned there; otherwise pre-if value
let then_val = then_var_map_end.get(&var_name).copied().or_else(|| pre_then_var_value.get(&var_name).copied());
// else-side value: prefer else end map when else assigns; otherwise pre-if value
let else_val = else_var_map_end_opt
.as_ref()
.and_then(|m| m.get(&var_name).copied())
.or_else(|| pre_then_var_value.get(&var_name).copied());
if let (Some(tv), Some(ev)) = (then_val, else_val) {
// Build incoming list only for predecessors that actually reach merge
let mut incomings: Vec<(BasicBlockId, ValueId)> = Vec::new();
if then_reaches_merge { incomings.push((then_bb, tv)); }
if else_reaches_merge { incomings.push((else_bb, ev)); }
match incomings.len() {
0 => { /* neither branch reaches merge: nothing to bind */ }
1 => {
// Single predecessor reaching merge: no PHI needed
let (_pred, v) = incomings[0];
self.parent_builder.variable_map.insert(var_name, v);
}
_ => {
let phi_id = self.new_value();
if self.no_phi_mode {
for (pred, v) in incomings.iter().copied() {
self.parent_builder.insert_edge_copy(pred, phi_id, v)?;
}
} else {
self.emit_phi_at_block_start(merge_bb, phi_id, incomings)?;
}
self.parent_builder.variable_map.insert(var_name, phi_id);
}
}
}
}
let void_id = self.new_value();
self.emit_const(void_id, ConstValue::Void)?;
Ok(void_id)
}
ASTNode::If { condition, then_body, else_body, .. } =>
self.lower_if_in_loop(*condition, then_body, else_body),
ASTNode::Break { .. } => self.do_break(),
ASTNode::Continue { .. } => self.do_continue(),
other => self.parent_builder.build_expression(other),
}
}
/// Lower an if-statement inside a loop, preserving continue/break semantics and emitting PHIs per assigned variable.
fn lower_if_in_loop(
&mut self,
condition: ASTNode,
then_body: Vec<ASTNode>,
else_body: Option<Vec<ASTNode>>,
) -> Result<ValueId, String> {
// Evaluate condition and create blocks
let cond_val = self.parent_builder.build_expression(condition)?;
let then_bb = self.new_block();
let else_bb = self.new_block();
let merge_bb = self.new_block();
self.emit_branch(cond_val, then_bb, else_bb)?;
// Capture pre-if variable map (used for phi normalization)
let pre_if_var_map = self.get_current_variable_map();
let pre_then_var_value = pre_if_var_map.clone();
// then branch
self.set_current_block(then_bb)?;
for s in then_body.iter().cloned() {
let _ = self.build_statement(s)?;
// Stop if block terminated
let cur_id = self.current_block()?;
let terminated = {
if let Some(ref fun_ro) = self.parent_builder.current_function {
if let Some(bb) = fun_ro.get_block(cur_id) { bb.is_terminated() } else { false }
} else { false }
};
if terminated { break; }
}
let then_var_map_end = self.get_current_variable_map();
// Only jump to merge if not already terminated (e.g., continue/break)
// Capture the actual predecessor block that reaches merge (entry block may not be the exit).
let then_pred_to_merge: Option<BasicBlockId> = {
let cur_id = self.current_block()?;
let need_jump = {
if let Some(ref fun_ro) = self.parent_builder.current_function {
if let Some(bb) = fun_ro.get_block(cur_id) { !bb.is_terminated() } else { false }
} else { false }
};
if need_jump {
// Emit the edge now; record the real predecessor (cur_id), not the entry then_bb.
self.emit_jump(merge_bb)?;
Some(cur_id)
} else {
// Terminated path (e.g., continue/break) — no incoming to merge.
None
}
};
// else branch
self.set_current_block(else_bb)?;
let mut else_var_map_end_opt: Option<HashMap<String, ValueId>> = None;
if let Some(es) = else_body.clone() {
for s in es.into_iter() {
let _ = self.build_statement(s)?;
let cur_id = self.current_block()?;
let terminated = {
if let Some(ref fun_ro) = self.parent_builder.current_function {
if let Some(bb) = fun_ro.get_block(cur_id) { bb.is_terminated() } else { false }
} else { false }
};
if terminated { break; }
}
else_var_map_end_opt = Some(self.get_current_variable_map());
}
let else_pred_to_merge: Option<BasicBlockId> = {
let cur_id = self.current_block()?;
let need_jump = {
if let Some(ref fun_ro) = self.parent_builder.current_function {
if let Some(bb) = fun_ro.get_block(cur_id) { !bb.is_terminated() } else { false }
} else { false }
};
if need_jump {
self.emit_jump(merge_bb)?;
Some(cur_id)
} else {
None
}
};
// Continue at merge
self.set_current_block(merge_bb)?;
// collect assigned variables in both branches
fn collect_assigned_vars(ast: &ASTNode, out: &mut std::collections::HashSet<String>) {
match ast {
ASTNode::Assignment { target, .. } => {
if let ASTNode::Variable { name, .. } = target.as_ref() { out.insert(name.clone()); }
}
ASTNode::Program { statements, .. } => { for s in statements { collect_assigned_vars(s, out); } }
ASTNode::If { then_body, else_body, .. } => {
let tp = ASTNode::Program { statements: then_body.clone(), span: crate::ast::Span::unknown() };
collect_assigned_vars(&tp, out);
if let Some(eb) = else_body {
let ep = ASTNode::Program { statements: eb.clone(), span: crate::ast::Span::unknown() };
collect_assigned_vars(&ep, out);
}
}
_ => {}
}
}
let mut vars: std::collections::HashSet<String> = std::collections::HashSet::new();
let then_prog = ASTNode::Program { statements: then_body.clone(), span: crate::ast::Span::unknown() };
collect_assigned_vars(&then_prog, &mut vars);
if let Some(es) = &else_body {
let else_prog = ASTNode::Program { statements: es.clone(), span: crate::ast::Span::unknown() };
collect_assigned_vars(&else_prog, &mut vars);
}
// Reset to pre-if map before rebinding to ensure a clean environment
self.parent_builder.variable_map = pre_if_var_map.clone();
for var_name in vars.into_iter() {
let then_val = then_var_map_end.get(&var_name).copied().or_else(|| pre_then_var_value.get(&var_name).copied());
let else_val = else_var_map_end_opt.as_ref().and_then(|m| m.get(&var_name).copied()).or_else(|| pre_then_var_value.get(&var_name).copied());
if let (Some(tv), Some(ev)) = (then_val, else_val) {
let mut incomings: Vec<(BasicBlockId, ValueId)> = Vec::new();
if let Some(pred) = then_pred_to_merge { incomings.push((pred, tv)); }
if let Some(pred) = else_pred_to_merge { incomings.push((pred, ev)); }
match incomings.len() {
0 => {}
1 => {
let (_pred, v) = incomings[0];
self.parent_builder.variable_map.insert(var_name, v);
}
_ => {
let phi_id = self.new_value();
if self.no_phi_mode {
for (pred, v) in incomings.iter().copied() {
self.parent_builder.insert_edge_copy(pred, phi_id, v)?;
}
} else {
self.emit_phi_at_block_start(merge_bb, phi_id, incomings)?;
}
self.parent_builder.variable_map.insert(var_name, phi_id);
}
}
}
}
let void_id = self.new_value();
self.emit_const(void_id, ConstValue::Void)?;
Ok(void_id)
}
}

View File

@ -14,6 +14,7 @@ pub mod function;
pub mod instruction;
pub mod instruction_kinds; // small kind-specific metadata (Const/BinOp)
pub mod instruction_introspection; // Introspection helpers for tests (instruction names)
pub mod types; // core MIR enums (ConstValue, Ops, MirType)
pub mod loop_api; // Minimal LoopBuilder facade (adapter-ready)
pub mod loop_builder; // SSA loop construction with phi nodes
pub mod optimizer;
@ -33,9 +34,9 @@ pub use basic_block::{BasicBlock, BasicBlockId, BasicBlockIdGenerator};
pub use builder::MirBuilder;
pub use effect::{Effect, EffectMask};
pub use function::{FunctionSignature, MirFunction, MirModule};
pub use instruction::{
BarrierOp, BinaryOp, CompareOp, ConstValue, MirInstruction, MirType, TypeOpKind, UnaryOp,
WeakRefOp,
pub use instruction::MirInstruction;
pub use types::{
BarrierOp, BinaryOp, CompareOp, ConstValue, MirType, TypeOpKind, UnaryOp, WeakRefOp,
};
pub use optimizer::MirOptimizer;
pub use printer::MirPrinter;

View File

@ -225,13 +225,12 @@ fn resolve_type_from_value(
def_map: &std::collections::HashMap<ValueId, (super::basic_block::BasicBlockId, usize)>,
id: ValueId,
) -> Option<MirType> {
use super::instruction::ConstValue;
if let Some((bb, idx)) = def_map.get(&id).copied() {
if let Some(block) = function.blocks.get(&bb) {
if idx < block.instructions.len() {
match &block.instructions[idx] {
MirInstruction::Const {
value: ConstValue::String(s),
value: crate::mir::ConstValue::String(s),
..
} => {
return Some(map_type_name(s));
@ -244,7 +243,7 @@ fn resolve_type_from_value(
if let Some(sblock) = function.blocks.get(&sbb) {
if sidx < sblock.instructions.len() {
if let MirInstruction::Const {
value: ConstValue::String(s),
value: crate::mir::ConstValue::String(s),
..
} = &sblock.instructions[sidx]
{
@ -313,7 +312,7 @@ fn diagnose_unlowered_type_ops(
if let Some(b) = function.blocks.get(&bb) {
if idx < b.instructions.len() {
if let MirInstruction::Const {
value: super::instruction::ConstValue::String(s),
value: crate::mir::ConstValue::String(s),
..
} = &b.instructions[idx]
{

View File

@ -41,7 +41,7 @@ pub fn diagnose_unlowered_type_ops(
if let Some(b) = function.blocks.get(&bb) {
if idx < b.instructions.len() {
if let MirInstruction::Const {
value: crate::mir::instruction::ConstValue::String(s),
value: crate::mir::ConstValue::String(s),
..
} = &b.instructions[idx]
{

View File

@ -239,7 +239,7 @@ pub fn normalize_legacy_instructions(
value,
expected_type,
} => {
let ty = crate::mir::instruction::MirType::Box(expected_type.clone());
let ty = crate::mir::MirType::Box(expected_type.clone());
*term = I::TypeOp {
dst: *dst,
op: TypeOpKind::Check,
@ -370,7 +370,7 @@ pub fn normalize_ref_field_access(
function.next_value_id += 1;
out.push(I::Const {
dst: new_id,
value: crate::mir::instruction::ConstValue::String(field),
value: crate::mir::ConstValue::String(field),
});
out.push(I::BoxCall {
dst: Some(dst),
@ -391,7 +391,7 @@ pub fn normalize_ref_field_access(
function.next_value_id += 1;
out.push(I::Const {
dst: new_id,
value: crate::mir::instruction::ConstValue::String(field),
value: crate::mir::ConstValue::String(field),
});
out.push(I::Barrier {
op: BarrierOp::Write,
@ -423,7 +423,7 @@ pub fn normalize_ref_field_access(
function.next_value_id += 1;
block.instructions.push(I::Const {
dst: new_id,
value: crate::mir::instruction::ConstValue::String(field),
value: crate::mir::ConstValue::String(field),
});
I::BoxCall {
dst: Some(dst),
@ -443,7 +443,7 @@ pub fn normalize_ref_field_access(
function.next_value_id += 1;
block.instructions.push(I::Const {
dst: new_id,
value: crate::mir::instruction::ConstValue::String(field),
value: crate::mir::ConstValue::String(field),
});
block.instructions.push(I::Barrier {
op: BarrierOp::Write,

View File

@ -11,7 +11,7 @@ use crate::mir::{BinaryOp, CompareOp, EffectMask, MirInstruction as I, MirModule
/// Not x => Compare(Eq, x, Const false)
/// BitNot x => BinOp(BitXor, x, Const(-1))
pub fn normalize_pure_core13(_opt: &mut MirOptimizer, module: &mut MirModule) -> OptimizationStats {
use crate::mir::instruction::ConstValue;
use crate::mir::types::ConstValue;
let mut stats = OptimizationStats::new();
for (_fname, function) in &mut module.functions {
for (_bb, block) in &mut function.blocks {
@ -43,7 +43,7 @@ pub fn normalize_pure_core13(_opt: &mut MirOptimizer, module: &mut MirModule) ->
// prepend type name as Const String
let ty_id = ValueId::new(function.next_value_id);
function.next_value_id += 1;
out.push(I::Const { dst: ty_id, value: ConstValue::String(box_type) });
out.push(I::Const { dst: ty_id, value: crate::mir::ConstValue::String(box_type) });
let mut call_args = Vec::with_capacity(1 + args.len());
call_args.push(ty_id);
call_args.append(&mut args);
@ -61,19 +61,19 @@ pub fn normalize_pure_core13(_opt: &mut MirOptimizer, module: &mut MirModule) ->
crate::mir::UnaryOp::Neg => {
let zero = ValueId::new(function.next_value_id);
function.next_value_id += 1;
out.push(I::Const { dst: zero, value: ConstValue::Integer(0) });
out.push(I::Const { dst: zero, value: crate::mir::ConstValue::Integer(0) });
out.push(I::BinOp { dst, op: BinaryOp::Sub, lhs: zero, rhs: operand });
}
crate::mir::UnaryOp::Not => {
let f = ValueId::new(function.next_value_id);
function.next_value_id += 1;
out.push(I::Const { dst: f, value: ConstValue::Bool(false) });
out.push(I::Const { dst: f, value: crate::mir::ConstValue::Bool(false) });
out.push(I::Compare { dst, op: CompareOp::Eq, lhs: operand, rhs: f });
}
crate::mir::UnaryOp::BitNot => {
let all1 = ValueId::new(function.next_value_id);
function.next_value_id += 1;
out.push(I::Const { dst: all1, value: ConstValue::Integer(-1) });
out.push(I::Const { dst: all1, value: crate::mir::ConstValue::Integer(-1) });
out.push(I::BinOp { dst, op: BinaryOp::BitXor, lhs: operand, rhs: all1 });
}
}

View File

@ -338,10 +338,6 @@ impl MirPrinter {
output
}
fn format_dst(&self, dst: &ValueId, types: &HashMap<ValueId, MirType>) -> String {
printer_helpers::format_dst(dst, types)
}
/// Format a single instruction
fn format_instruction(
&self,

111
src/mir/types.rs Normal file
View File

@ -0,0 +1,111 @@
/*!
* MIR Core Types — split from instruction.rs for clarity (behavior-preserving)
*/
use std::fmt;
/// Constant values in MIR
#[derive(Debug, Clone, PartialEq)]
pub enum ConstValue {
Integer(i64),
Float(f64),
Bool(bool),
String(String),
Null,
Void,
}
impl fmt::Display for ConstValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ConstValue::Integer(n) => write!(f, "{}", n),
ConstValue::Float(fl) => write!(f, "{}", fl),
ConstValue::Bool(b) => write!(f, "{}", b),
ConstValue::String(s) => write!(f, "\"{}\"", s),
ConstValue::Null => write!(f, "null"),
ConstValue::Void => write!(f, "void"),
}
}
}
/// Binary operations
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
// Arithmetic
Add,
Sub,
Mul,
Div,
Mod,
// Bitwise
BitAnd,
BitOr,
BitXor,
Shl,
Shr,
// Logical
And,
Or,
}
/// Unary operations
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
// Arithmetic
Neg,
// Logical
Not,
// Bitwise
BitNot,
}
/// Comparison operations
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompareOp {
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
/// MIR type system
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MirType {
Integer,
Float,
Bool,
String,
Box(String), // Box type with name
Array(Box<MirType>),
Future(Box<MirType>), // Future containing a type
Void,
Unknown,
}
/// Kind of unified type operation (PoC)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TypeOpKind {
Check,
Cast,
}
/// Kind of unified weak reference operation (PoC)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WeakRefOp {
New,
Load,
}
/// Kind of unified barrier operation (PoC)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BarrierOp {
Read,
Write,
}

View File

@ -4,10 +4,9 @@
* Implements dominance checking, SSA verification, and semantic analysis
*/
use super::{BasicBlockId, MirFunction, MirModule, ValueId};
use super::{MirFunction, MirModule};
use crate::debug::log as dlog;
use crate::mir::verification_types::VerificationError;
use std::collections::HashMap;
mod cfg;
mod dom;
mod awaits;

View File

@ -69,7 +69,7 @@ pub fn check_weakref_and_barrier(function: &MirFunction) -> Result<(), Vec<Verif
| MirInstruction::BarrierWrite { ptr } => {
if let Some((_db, _di, def_inst)) = def_map.get(ptr) {
if let MirInstruction::Const {
value: crate::mir::instruction::ConstValue::Void,
value: crate::mir::ConstValue::Void,
..
} = def_inst
{