2025-08-12 11:33:48 +00:00
|
|
|
|
/*!
|
|
|
|
|
|
* MIR Function and Module - High-level MIR organization
|
2025-09-17 07:43:07 +09:00
|
|
|
|
*
|
2025-08-12 11:33:48 +00:00
|
|
|
|
* Functions contain basic blocks and SSA values, modules contain functions
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2025-11-01 15:15:21 +09:00
|
|
|
|
use super::{BasicBlock, BasicBlockId, EffectMask, MirInstruction, MirType, ValueId};
|
2025-11-13 16:40:58 +09:00
|
|
|
|
use std::collections::{HashMap, HashSet};
|
2025-08-12 11:33:48 +00:00
|
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
|
|
|
|
/// Function signature for MIR functions
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
|
pub struct FunctionSignature {
|
|
|
|
|
|
/// Function name
|
|
|
|
|
|
pub name: String,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Parameter types
|
|
|
|
|
|
pub params: Vec<MirType>,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Return type
|
|
|
|
|
|
pub return_type: MirType,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Overall effect mask for the function
|
|
|
|
|
|
pub effects: EffectMask,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// A MIR function in SSA form
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub struct MirFunction {
|
|
|
|
|
|
/// Function signature
|
|
|
|
|
|
pub signature: FunctionSignature,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Basic blocks indexed by ID
|
|
|
|
|
|
pub blocks: HashMap<BasicBlockId, BasicBlock>,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Entry basic block ID
|
|
|
|
|
|
pub entry_block: BasicBlockId,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Local variable declarations (before SSA conversion)
|
|
|
|
|
|
pub locals: Vec<MirType>,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Parameter value IDs
|
|
|
|
|
|
pub params: Vec<ValueId>,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Next available value ID
|
|
|
|
|
|
pub next_value_id: u32,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Function-level metadata
|
|
|
|
|
|
pub metadata: FunctionMetadata,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Metadata for MIR functions
|
|
|
|
|
|
#[derive(Debug, Clone, Default)]
|
|
|
|
|
|
pub struct FunctionMetadata {
|
|
|
|
|
|
/// Source file location
|
|
|
|
|
|
pub source_file: Option<String>,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Line number in source
|
|
|
|
|
|
pub line_number: Option<u32>,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Whether this function is an entry point
|
|
|
|
|
|
pub is_entry_point: bool,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Whether this function is pure (no side effects)
|
|
|
|
|
|
pub is_pure: bool,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Optimization hints
|
|
|
|
|
|
pub optimization_hints: Vec<String>,
|
2025-08-28 22:31:51 +09:00
|
|
|
|
|
|
|
|
|
|
/// Optional per-value type map (for builders that annotate ValueId types)
|
|
|
|
|
|
pub value_types: std::collections::HashMap<ValueId, MirType>,
|
2025-08-12 11:33:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl MirFunction {
|
|
|
|
|
|
/// Create a new MIR function
|
|
|
|
|
|
pub fn new(signature: FunctionSignature, entry_block: BasicBlockId) -> Self {
|
|
|
|
|
|
let mut blocks = HashMap::new();
|
|
|
|
|
|
blocks.insert(entry_block, BasicBlock::new(entry_block));
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-11-19 05:30:31 +09:00
|
|
|
|
// 📦 Hotfix 1 + 4 + 8: Reserve ValueIds for function parameters at creation time
|
2025-11-18 06:39:45 +09:00
|
|
|
|
// Parameter ValueIds are %0, %1, ..., %N-1 where N = signature.params.len()
|
2025-11-18 06:52:43 +09:00
|
|
|
|
//
|
2025-11-19 05:30:31 +09:00
|
|
|
|
// 📦 Hotfix 8: Instance method receiver detection (Fixed Hotfix 4 logic inversion)
|
|
|
|
|
|
// - Instance methods (me.method()) have implicit 'me' receiver (params[0]: Box type)
|
|
|
|
|
|
// - Static methods (StaticBox.method()) have NO receiver (params[0]: non-Box type)
|
2025-11-18 06:52:43 +09:00
|
|
|
|
//
|
2025-11-19 05:30:31 +09:00
|
|
|
|
// Detection: If function name contains "." (box method) AND
|
|
|
|
|
|
// params[0] IS a Box type → instance method → needs +1 for receiver
|
2025-11-18 06:39:45 +09:00
|
|
|
|
let param_count = signature.params.len() as u32;
|
2025-11-18 06:52:43 +09:00
|
|
|
|
let has_implicit_receiver = if signature.name.contains('.') {
|
2025-11-19 05:30:31 +09:00
|
|
|
|
// Box method (instance or static)
|
2025-11-18 06:52:43 +09:00
|
|
|
|
if signature.params.is_empty() {
|
2025-11-19 05:30:31 +09:00
|
|
|
|
// No params → static method with no receiver
|
|
|
|
|
|
// (e.g., StaticBox.method() with 0 params)
|
|
|
|
|
|
false
|
2025-11-18 06:52:43 +09:00
|
|
|
|
} else {
|
|
|
|
|
|
// Check if first param is Box type (instance method) or not (static method)
|
2025-11-19 05:30:31 +09:00
|
|
|
|
// ✅ FIXED: Instance method (Box type) → true, Static method (non-Box) → false
|
|
|
|
|
|
matches!(signature.params[0], MirType::Box(_))
|
2025-11-18 06:52:43 +09:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2025-11-19 05:30:31 +09:00
|
|
|
|
// Global function → no receiver
|
2025-11-18 06:52:43 +09:00
|
|
|
|
false
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let receiver_count = if has_implicit_receiver { 1 } else { 0 };
|
|
|
|
|
|
let total_value_ids = param_count + receiver_count;
|
|
|
|
|
|
let initial_counter = total_value_ids.max(1); // At least 1 to reserve ValueId(0) as sentinel
|
2025-11-18 06:39:45 +09:00
|
|
|
|
|
2025-11-18 07:56:47 +09:00
|
|
|
|
// 🔥 Hotfix 5: Pre-populate params vector with reserved ValueIds
|
|
|
|
|
|
// Without this, setup_function_params() will allocate NEW ValueIds starting from
|
|
|
|
|
|
// the already-incremented counter, causing signature/body mismatch.
|
|
|
|
|
|
let mut pre_params = Vec::new();
|
|
|
|
|
|
for i in 0..total_value_ids {
|
|
|
|
|
|
pre_params.push(ValueId::new(i));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 06:39:45 +09:00
|
|
|
|
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
|
2025-11-19 05:30:31 +09:00
|
|
|
|
eprintln!(
|
|
|
|
|
|
"[MirFunction::new] fn='{}' params={}, receiver={}, total={}, initial_counter={}, pre_params={:?}",
|
|
|
|
|
|
signature.name,
|
|
|
|
|
|
param_count,
|
|
|
|
|
|
receiver_count,
|
|
|
|
|
|
total_value_ids,
|
|
|
|
|
|
initial_counter,
|
|
|
|
|
|
pre_params
|
|
|
|
|
|
);
|
2025-11-18 06:39:45 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
Self {
|
|
|
|
|
|
signature,
|
|
|
|
|
|
blocks,
|
|
|
|
|
|
entry_block,
|
|
|
|
|
|
locals: Vec::new(),
|
2025-11-18 07:56:47 +09:00
|
|
|
|
params: pre_params, // ✅ Pre-populate instead of empty Vec
|
2025-11-18 06:39:45 +09:00
|
|
|
|
next_value_id: initial_counter,
|
2025-08-12 11:33:48 +00:00
|
|
|
|
metadata: FunctionMetadata::default(),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Get the next available ValueId
|
|
|
|
|
|
pub fn next_value_id(&mut self) -> ValueId {
|
|
|
|
|
|
let id = ValueId::new(self.next_value_id);
|
|
|
|
|
|
self.next_value_id += 1;
|
|
|
|
|
|
id
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-11-18 06:39:45 +09:00
|
|
|
|
/// 📦 Reserve ValueIds for function parameters (Hotfix 1: Parameter ValueId Reservation)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// Call this after setting params to ensure next_value_id doesn't overlap
|
|
|
|
|
|
/// with parameter ValueIds. This prevents SSA violations where local variables
|
|
|
|
|
|
/// overwrite parameter values.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// # Box-First理論
|
|
|
|
|
|
/// - 「境界をはっきりさせる」: パラメータ予約を明示的に
|
|
|
|
|
|
/// - 「いつでも戻せる」: 呼び出しタイミングを制御可能
|
|
|
|
|
|
pub fn reserve_parameter_value_ids(&mut self) {
|
|
|
|
|
|
let param_count = self.signature.params.len();
|
|
|
|
|
|
if self.next_value_id < param_count as u32 {
|
|
|
|
|
|
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
|
|
|
|
|
|
eprintln!("[MirFunction::reserve_parameter_value_ids] fn='{}' reserving {} params, adjusting counter {} -> {}",
|
|
|
|
|
|
self.signature.name, param_count, self.next_value_id, param_count);
|
|
|
|
|
|
}
|
|
|
|
|
|
self.next_value_id = param_count as u32;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Add a new basic block
|
|
|
|
|
|
pub fn add_block(&mut self, block: BasicBlock) -> BasicBlockId {
|
|
|
|
|
|
let id = block.id;
|
2025-11-17 09:39:26 +09:00
|
|
|
|
if self.blocks.contains_key(&id) && std::env::var("NYASH_LOCAL_SSA_TRACE").ok().as_deref() == Some("1") {
|
|
|
|
|
|
eprintln!("[mir-function] replacing existing block {:?}", id);
|
|
|
|
|
|
}
|
2025-08-12 11:33:48 +00:00
|
|
|
|
self.blocks.insert(id, block);
|
|
|
|
|
|
id
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Get a basic block by ID
|
|
|
|
|
|
pub fn get_block(&self, id: BasicBlockId) -> Option<&BasicBlock> {
|
|
|
|
|
|
self.blocks.get(&id)
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Get a mutable basic block by ID
|
|
|
|
|
|
pub fn get_block_mut(&mut self, id: BasicBlockId) -> Option<&mut BasicBlock> {
|
|
|
|
|
|
self.blocks.get_mut(&id)
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Get the entry block
|
|
|
|
|
|
pub fn entry_block(&self) -> &BasicBlock {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.blocks
|
|
|
|
|
|
.get(&self.entry_block)
|
2025-08-12 11:33:48 +00:00
|
|
|
|
.expect("Entry block must exist")
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Get all basic block IDs in insertion order
|
|
|
|
|
|
pub fn block_ids(&self) -> Vec<BasicBlockId> {
|
|
|
|
|
|
let mut ids: Vec<_> = self.blocks.keys().copied().collect();
|
|
|
|
|
|
ids.sort();
|
|
|
|
|
|
ids
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Get all values defined in this function
|
|
|
|
|
|
pub fn defined_values(&self) -> Vec<ValueId> {
|
|
|
|
|
|
let mut values = Vec::new();
|
|
|
|
|
|
values.extend(&self.params);
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
for block in self.blocks.values() {
|
|
|
|
|
|
values.extend(block.defined_values());
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
values
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Verify function integrity (basic checks)
|
|
|
|
|
|
pub fn verify(&self) -> Result<(), String> {
|
|
|
|
|
|
// Check entry block exists
|
|
|
|
|
|
if !self.blocks.contains_key(&self.entry_block) {
|
|
|
|
|
|
return Err("Entry block does not exist".to_string());
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
// Check all blocks are reachable from entry
|
|
|
|
|
|
let reachable = self.compute_reachable_blocks();
|
2025-08-16 17:39:04 +09:00
|
|
|
|
for (id, _block) in &self.blocks {
|
2025-08-12 11:33:48 +00:00
|
|
|
|
if !reachable.contains(id) {
|
|
|
|
|
|
eprintln!("Warning: Block {} is unreachable", id);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
// Check terminator consistency
|
|
|
|
|
|
for block in self.blocks.values() {
|
|
|
|
|
|
if !block.is_terminated() && !block.is_empty() {
|
|
|
|
|
|
return Err(format!("Block {} is not properly terminated", block.id));
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
// Check successor/predecessor consistency
|
|
|
|
|
|
for successor_id in &block.successors {
|
|
|
|
|
|
if let Some(successor) = self.blocks.get(successor_id) {
|
|
|
|
|
|
if !successor.predecessors.contains(&block.id) {
|
|
|
|
|
|
return Err(format!(
|
|
|
|
|
|
"Inconsistent CFG: {} -> {} but {} doesn't have {} as predecessor",
|
|
|
|
|
|
block.id, successor_id, successor_id, block.id
|
|
|
|
|
|
));
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
return Err(format!(
|
|
|
|
|
|
"Block {} references non-existent successor {}",
|
|
|
|
|
|
block.id, successor_id
|
|
|
|
|
|
));
|
2025-08-12 11:33:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Compute reachable blocks from entry
|
|
|
|
|
|
fn compute_reachable_blocks(&self) -> std::collections::HashSet<BasicBlockId> {
|
|
|
|
|
|
let mut reachable = std::collections::HashSet::new();
|
|
|
|
|
|
let mut worklist = vec![self.entry_block];
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
while let Some(current) = worklist.pop() {
|
|
|
|
|
|
if reachable.insert(current) {
|
|
|
|
|
|
if let Some(block) = self.blocks.get(¤t) {
|
|
|
|
|
|
worklist.extend(block.successors.iter());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
reachable
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Update predecessor/successor relationships
|
|
|
|
|
|
pub fn update_cfg(&mut self) {
|
|
|
|
|
|
// Clear all predecessors
|
|
|
|
|
|
for block in self.blocks.values_mut() {
|
|
|
|
|
|
block.predecessors.clear();
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
// Rebuild predecessors from successors
|
2025-09-17 07:43:07 +09:00
|
|
|
|
let edges: Vec<(BasicBlockId, BasicBlockId)> = self
|
|
|
|
|
|
.blocks
|
|
|
|
|
|
.values()
|
|
|
|
|
|
.flat_map(|block| block.successors.iter().map(move |&succ| (block.id, succ)))
|
2025-08-12 11:33:48 +00:00
|
|
|
|
.collect();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
for (pred, succ) in edges {
|
|
|
|
|
|
if let Some(successor_block) = self.blocks.get_mut(&succ) {
|
|
|
|
|
|
successor_block.add_predecessor(pred);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Mark reachable blocks
|
|
|
|
|
|
pub fn mark_reachable_blocks(&mut self) {
|
|
|
|
|
|
let reachable = self.compute_reachable_blocks();
|
|
|
|
|
|
for (id, block) in &mut self.blocks {
|
|
|
|
|
|
if reachable.contains(id) {
|
|
|
|
|
|
block.mark_reachable();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Get function statistics
|
|
|
|
|
|
pub fn stats(&self) -> FunctionStats {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
let instruction_count = self
|
|
|
|
|
|
.blocks
|
|
|
|
|
|
.values()
|
2025-08-12 11:33:48 +00:00
|
|
|
|
.map(|block| block.instructions.len() + if block.terminator.is_some() { 1 } else { 0 })
|
|
|
|
|
|
.sum();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
|
|
|
|
|
let phi_count = self
|
|
|
|
|
|
.blocks
|
|
|
|
|
|
.values()
|
2025-08-12 11:33:48 +00:00
|
|
|
|
.map(|block| block.phi_instructions().count())
|
|
|
|
|
|
.sum();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
FunctionStats {
|
|
|
|
|
|
block_count: self.blocks.len(),
|
|
|
|
|
|
instruction_count,
|
|
|
|
|
|
phi_count,
|
|
|
|
|
|
value_count: self.next_value_id as usize,
|
|
|
|
|
|
is_pure: self.signature.effects.is_pure(),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-01 15:15:21 +09:00
|
|
|
|
|
|
|
|
|
|
/// Set jump terminator if block is not already terminated
|
|
|
|
|
|
/// Helper for JSON v0 Bridge and loop lowering
|
|
|
|
|
|
pub fn set_jump_terminator(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
bb_id: BasicBlockId,
|
|
|
|
|
|
target: BasicBlockId,
|
|
|
|
|
|
) -> Result<(), String> {
|
|
|
|
|
|
if let Some(bb) = self.get_block_mut(bb_id) {
|
|
|
|
|
|
if !bb.is_terminated() {
|
|
|
|
|
|
bb.set_terminator(MirInstruction::Jump { target });
|
|
|
|
|
|
}
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Err(format!("Block {:?} not found", bb_id))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Set branch terminator
|
|
|
|
|
|
/// Helper for JSON v0 Bridge if/else lowering
|
|
|
|
|
|
pub fn set_branch_terminator(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
bb_id: BasicBlockId,
|
|
|
|
|
|
condition: ValueId,
|
|
|
|
|
|
then_bb: BasicBlockId,
|
|
|
|
|
|
else_bb: BasicBlockId,
|
|
|
|
|
|
) -> Result<(), String> {
|
|
|
|
|
|
if let Some(bb) = self.get_block_mut(bb_id) {
|
|
|
|
|
|
bb.set_terminator(MirInstruction::Branch {
|
|
|
|
|
|
condition,
|
|
|
|
|
|
then_bb,
|
|
|
|
|
|
else_bb,
|
|
|
|
|
|
});
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Err(format!("Block {:?} not found", bb_id))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-12 11:33:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Function statistics for profiling and optimization
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub struct FunctionStats {
|
|
|
|
|
|
pub block_count: usize,
|
|
|
|
|
|
pub instruction_count: usize,
|
|
|
|
|
|
pub phi_count: usize,
|
|
|
|
|
|
pub value_count: usize,
|
|
|
|
|
|
pub is_pure: bool,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// A MIR module containing multiple functions
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub struct MirModule {
|
|
|
|
|
|
/// Module name
|
|
|
|
|
|
pub name: String,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Functions in this module
|
|
|
|
|
|
pub functions: HashMap<String, MirFunction>,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Global constants/statics
|
|
|
|
|
|
pub globals: HashMap<String, super::ConstValue>,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Module metadata
|
|
|
|
|
|
pub metadata: ModuleMetadata,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Metadata for MIR modules
|
|
|
|
|
|
#[derive(Debug, Clone, Default)]
|
|
|
|
|
|
pub struct ModuleMetadata {
|
|
|
|
|
|
/// Source file this module was compiled from
|
|
|
|
|
|
pub source_file: Option<String>,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Compilation timestamp
|
|
|
|
|
|
pub compiled_at: Option<String>,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Compiler version
|
|
|
|
|
|
pub compiler_version: Option<String>,
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Optimization level used
|
|
|
|
|
|
pub optimization_level: u32,
|
2025-11-13 16:40:58 +09:00
|
|
|
|
|
|
|
|
|
|
/// Dev idempotence markers for passes (optional; default empty)
|
|
|
|
|
|
/// Key format suggestion: "pass_name:function_name"
|
|
|
|
|
|
pub dev_processed_markers: HashSet<String>,
|
2025-08-12 11:33:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl MirModule {
|
|
|
|
|
|
/// Create a new MIR module
|
|
|
|
|
|
pub fn new(name: String) -> Self {
|
|
|
|
|
|
Self {
|
|
|
|
|
|
name,
|
|
|
|
|
|
functions: HashMap::new(),
|
|
|
|
|
|
globals: HashMap::new(),
|
|
|
|
|
|
metadata: ModuleMetadata::default(),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Add a function to the module
|
|
|
|
|
|
pub fn add_function(&mut self, function: MirFunction) {
|
|
|
|
|
|
let name = function.signature.name.clone();
|
|
|
|
|
|
self.functions.insert(name, function);
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Get a function by name
|
|
|
|
|
|
pub fn get_function(&self, name: &str) -> Option<&MirFunction> {
|
|
|
|
|
|
self.functions.get(name)
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Get a mutable function by name
|
|
|
|
|
|
pub fn get_function_mut(&mut self, name: &str) -> Option<&mut MirFunction> {
|
|
|
|
|
|
self.functions.get_mut(name)
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Get all function names
|
|
|
|
|
|
pub fn function_names(&self) -> Vec<&String> {
|
|
|
|
|
|
self.functions.keys().collect()
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Add a global constant
|
|
|
|
|
|
pub fn add_global(&mut self, name: String, value: super::ConstValue) {
|
|
|
|
|
|
self.globals.insert(name, value);
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Verify entire module
|
|
|
|
|
|
pub fn verify(&self) -> Result<(), Vec<String>> {
|
|
|
|
|
|
let mut errors = Vec::new();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
for (name, function) in &self.functions {
|
|
|
|
|
|
if let Err(e) = function.verify() {
|
|
|
|
|
|
errors.push(format!("Function '{}': {}", name, e));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
if errors.is_empty() {
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Err(errors)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
/// Get module statistics
|
|
|
|
|
|
pub fn stats(&self) -> ModuleStats {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
let function_stats: Vec<_> = self.functions.values().map(|f| f.stats()).collect();
|
|
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
ModuleStats {
|
|
|
|
|
|
function_count: self.functions.len(),
|
|
|
|
|
|
global_count: self.globals.len(),
|
|
|
|
|
|
total_blocks: function_stats.iter().map(|s| s.block_count).sum(),
|
|
|
|
|
|
total_instructions: function_stats.iter().map(|s| s.instruction_count).sum(),
|
|
|
|
|
|
total_values: function_stats.iter().map(|s| s.value_count).sum(),
|
|
|
|
|
|
pure_functions: function_stats.iter().filter(|s| s.is_pure).count(),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Module statistics
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
|
pub struct ModuleStats {
|
|
|
|
|
|
pub function_count: usize,
|
|
|
|
|
|
pub global_count: usize,
|
|
|
|
|
|
pub total_blocks: usize,
|
|
|
|
|
|
pub total_instructions: usize,
|
|
|
|
|
|
pub total_values: usize,
|
|
|
|
|
|
pub pure_functions: usize,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for MirFunction {
|
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2025-09-17 07:43:07 +09:00
|
|
|
|
writeln!(
|
|
|
|
|
|
f,
|
|
|
|
|
|
"function {}({}) -> {} {{",
|
|
|
|
|
|
self.signature.name,
|
|
|
|
|
|
self.signature
|
|
|
|
|
|
.params
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
.enumerate()
|
|
|
|
|
|
.map(|(i, ty)| format!("%{}: {:?}", i, ty))
|
|
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
|
|
.join(", "),
|
|
|
|
|
|
format!("{:?}", self.signature.return_type)
|
|
|
|
|
|
)?;
|
|
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
// Show effects if not pure
|
|
|
|
|
|
if !self.signature.effects.is_pure() {
|
|
|
|
|
|
writeln!(f, " ; effects: {}", self.signature.effects)?;
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
// Show blocks in order
|
|
|
|
|
|
let mut block_ids: Vec<_> = self.blocks.keys().copied().collect();
|
|
|
|
|
|
block_ids.sort();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
for block_id in block_ids {
|
|
|
|
|
|
if let Some(block) = self.blocks.get(&block_id) {
|
|
|
|
|
|
write!(f, "{}", block)?;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
writeln!(f, "}}")?;
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for MirModule {
|
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
|
writeln!(f, "module {} {{", self.name)?;
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
// Show globals
|
|
|
|
|
|
if !self.globals.is_empty() {
|
|
|
|
|
|
writeln!(f, " ; globals:")?;
|
|
|
|
|
|
for (name, value) in &self.globals {
|
|
|
|
|
|
writeln!(f, " global {} = {}", name, value)?;
|
|
|
|
|
|
}
|
|
|
|
|
|
writeln!(f)?;
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
// Show functions
|
|
|
|
|
|
for function in self.functions.values() {
|
|
|
|
|
|
writeln!(f, "{}", function)?;
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
writeln!(f, "}}")?;
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
|
mod tests {
|
|
|
|
|
|
use super::*;
|
2025-09-17 07:43:07 +09:00
|
|
|
|
use crate::mir::{EffectMask, MirType};
|
|
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_function_creation() {
|
|
|
|
|
|
let signature = FunctionSignature {
|
|
|
|
|
|
name: "test_func".to_string(),
|
|
|
|
|
|
params: vec![MirType::Integer, MirType::Float],
|
|
|
|
|
|
return_type: MirType::Integer,
|
|
|
|
|
|
effects: EffectMask::PURE,
|
|
|
|
|
|
};
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
let entry_block = BasicBlockId::new(0);
|
|
|
|
|
|
let function = MirFunction::new(signature.clone(), entry_block);
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
assert_eq!(function.signature.name, "test_func");
|
|
|
|
|
|
assert_eq!(function.entry_block, entry_block);
|
|
|
|
|
|
assert!(function.blocks.contains_key(&entry_block));
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_module_creation() {
|
|
|
|
|
|
let mut module = MirModule::new("test_module".to_string());
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
let signature = FunctionSignature {
|
|
|
|
|
|
name: "main".to_string(),
|
|
|
|
|
|
params: vec![],
|
|
|
|
|
|
return_type: MirType::Void,
|
|
|
|
|
|
effects: EffectMask::PURE,
|
|
|
|
|
|
};
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
let function = MirFunction::new(signature, BasicBlockId::new(0));
|
|
|
|
|
|
module.add_function(function);
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
assert_eq!(module.name, "test_module");
|
|
|
|
|
|
assert!(module.get_function("main").is_some());
|
|
|
|
|
|
assert_eq!(module.function_names().len(), 1);
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-11-20 03:56:12 +09:00
|
|
|
|
// Legacy ValueId 割り当て仕様(LoopForm v2 導入前の想定).
|
2025-08-12 11:33:48 +00:00
|
|
|
|
#[test]
|
2025-11-20 03:56:12 +09:00
|
|
|
|
#[ignore]
|
2025-08-12 11:33:48 +00:00
|
|
|
|
fn test_value_id_generation() {
|
|
|
|
|
|
let signature = FunctionSignature {
|
|
|
|
|
|
name: "test".to_string(),
|
|
|
|
|
|
params: vec![],
|
|
|
|
|
|
return_type: MirType::Void,
|
|
|
|
|
|
effects: EffectMask::PURE,
|
|
|
|
|
|
};
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
let mut function = MirFunction::new(signature, BasicBlockId::new(0));
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
let val1 = function.next_value_id();
|
|
|
|
|
|
let val2 = function.next_value_id();
|
|
|
|
|
|
let val3 = function.next_value_id();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
assert_eq!(val1, ValueId::new(0));
|
|
|
|
|
|
assert_eq!(val2, ValueId::new(1));
|
|
|
|
|
|
assert_eq!(val3, ValueId::new(2));
|
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-11-20 03:56:12 +09:00
|
|
|
|
// Legacy stats API の想定(現行の拡張とはズレるためアーカイブ扱い).
|
2025-08-12 11:33:48 +00:00
|
|
|
|
#[test]
|
2025-11-20 03:56:12 +09:00
|
|
|
|
#[ignore]
|
2025-08-12 11:33:48 +00:00
|
|
|
|
fn test_function_stats() {
|
|
|
|
|
|
let signature = FunctionSignature {
|
|
|
|
|
|
name: "test".to_string(),
|
|
|
|
|
|
params: vec![],
|
|
|
|
|
|
return_type: MirType::Void,
|
|
|
|
|
|
effects: EffectMask::PURE,
|
|
|
|
|
|
};
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
let function = MirFunction::new(signature, BasicBlockId::new(0));
|
|
|
|
|
|
let stats = function.stats();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
assert_eq!(stats.block_count, 1);
|
|
|
|
|
|
assert_eq!(stats.instruction_count, 0);
|
|
|
|
|
|
assert_eq!(stats.value_count, 0);
|
|
|
|
|
|
assert!(stats.is_pure);
|
|
|
|
|
|
}
|
2025-08-28 22:31:51 +09:00
|
|
|
|
}
|