Normalize passes keep spans and clean warnings
This commit is contained in:
@ -148,9 +148,9 @@ impl MirInterpreter {
|
||||
) -> Option<crate::ast::Span> {
|
||||
let idx = inst_index?;
|
||||
if idx < block.instructions.len() {
|
||||
block.instruction_span(idx)
|
||||
block.instruction_with_span(idx).map(|sp| sp.span)
|
||||
} else if idx == block.instructions.len() {
|
||||
block.terminator_span()
|
||||
block.terminator_spanned().map(|sp| sp.span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -334,9 +334,10 @@ impl MirInterpreter {
|
||||
|
||||
fn execute_block_instructions(&mut self, block: &BasicBlock) -> Result<(), VMError> {
|
||||
let phi_count = block.phi_instructions().count();
|
||||
for (idx, inst) in block.non_phi_instructions().enumerate() {
|
||||
for (idx, sp) in block.iter_spanned_enumerated().skip(phi_count) {
|
||||
let inst = sp.inst;
|
||||
self.last_block = Some(block.id);
|
||||
self.last_inst_index = Some(phi_count + idx);
|
||||
self.last_inst_index = Some(idx);
|
||||
self.last_inst = Some(inst.clone());
|
||||
if Self::trace_enabled() {
|
||||
eprintln!("[vm-trace] inst bb={:?} {:?}", block.id, inst);
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* SSA-form basic blocks with phi functions and terminator instructions
|
||||
*/
|
||||
|
||||
use super::{EffectMask, MirInstruction, SpannedInstruction, ValueId};
|
||||
use super::{EffectMask, MirInstruction, SpannedInstRef, SpannedInstruction, ValueId};
|
||||
use crate::ast::Span;
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
@ -239,11 +239,64 @@ impl BasicBlock {
|
||||
self.instruction_spans.get(idx).copied()
|
||||
}
|
||||
|
||||
/// Get instruction with span by index.
|
||||
pub fn instruction_with_span(&self, idx: usize) -> Option<SpannedInstRef<'_>> {
|
||||
self.instructions
|
||||
.get(idx)
|
||||
.zip(self.instruction_spans.get(idx))
|
||||
.map(|(inst, span)| SpannedInstRef {
|
||||
inst,
|
||||
span: *span,
|
||||
})
|
||||
}
|
||||
|
||||
/// Get span for terminator instruction
|
||||
pub fn terminator_span(&self) -> Option<Span> {
|
||||
self.terminator_span
|
||||
}
|
||||
|
||||
/// Get terminator together with its span.
|
||||
pub fn terminator_spanned(&self) -> Option<SpannedInstRef<'_>> {
|
||||
self.terminator.as_ref().map(|inst| SpannedInstRef {
|
||||
inst,
|
||||
span: self.terminator_span.unwrap_or_else(Span::unknown),
|
||||
})
|
||||
}
|
||||
|
||||
/// Iterate instructions with their spans.
|
||||
pub fn iter_spanned(&self) -> impl Iterator<Item = SpannedInstRef<'_>> {
|
||||
self.instructions
|
||||
.iter()
|
||||
.zip(self.instruction_spans.iter())
|
||||
.map(|(inst, span)| SpannedInstRef {
|
||||
inst,
|
||||
span: *span,
|
||||
})
|
||||
}
|
||||
|
||||
/// Iterate instructions with index and span.
|
||||
pub fn iter_spanned_enumerated(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (usize, SpannedInstRef<'_>)> {
|
||||
self.iter_spanned()
|
||||
.enumerate()
|
||||
.map(|(idx, sp)| (idx, sp))
|
||||
}
|
||||
|
||||
/// Iterate all instructions (including terminator) with spans.
|
||||
pub fn all_spanned_instructions(&self) -> impl Iterator<Item = SpannedInstRef<'_>> {
|
||||
self.iter_spanned()
|
||||
.chain(self.terminator_spanned().into_iter())
|
||||
}
|
||||
|
||||
/// Iterate all instructions (including terminator) with index and span.
|
||||
/// Non-phi + phi + terminator share the same indexing as `all_instructions()`.
|
||||
pub fn all_spanned_instructions_enumerated(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (usize, SpannedInstRef<'_>)> {
|
||||
self.all_spanned_instructions().enumerate()
|
||||
}
|
||||
|
||||
/// Insert instruction at the beginning (after phi instructions)
|
||||
pub fn insert_instruction_after_phis(&mut self, instruction: MirInstruction) {
|
||||
let phi_count = self.phi_instructions().count();
|
||||
|
||||
@ -119,7 +119,13 @@ impl super::MirBuilder {
|
||||
self.start_new_block(merge_block)?;
|
||||
// フェーズM: PHI はブロック先頭に配置(cf_common 統一)
|
||||
if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) {
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, result_val, phi_inputs);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
func,
|
||||
cur_bb,
|
||||
result_val,
|
||||
phi_inputs,
|
||||
self.current_span,
|
||||
);
|
||||
} else {
|
||||
self.emit_instruction(super::MirInstruction::Phi {
|
||||
dst: result_val,
|
||||
|
||||
@ -83,8 +83,12 @@ impl MirBuilder {
|
||||
if let (Some(func), Some(cur_bb)) =
|
||||
(self.current_function.as_mut(), self.current_block)
|
||||
{
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(
|
||||
func, cur_bb, merged, inputs,
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
func,
|
||||
cur_bb,
|
||||
merged,
|
||||
inputs,
|
||||
self.current_span,
|
||||
);
|
||||
} else {
|
||||
self.emit_instruction(MirInstruction::Phi {
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
//! Box-First理論: PHI insertion の境界を明確にし、差し替え可能な箱として提供
|
||||
|
||||
use super::{BasicBlockId, MirBuilder, ValueId};
|
||||
use crate::mir::MirInstruction;
|
||||
use std::collections::BTreeMap; // Phase 25.1: 決定性確保
|
||||
|
||||
/// PHI Merge Helper - 統一PHI挿入ロジック(Conservative戦略)
|
||||
|
||||
@ -213,6 +213,8 @@ impl super::MirBuilder {
|
||||
/// - While/ForRange は将来 Loop lowering へ委譲する拡張ポイントとして扱い、
|
||||
/// 現状は他の専用ビルダ/既存パスと同様に build_expression に委譲する。
|
||||
pub(super) fn build_statement(&mut self, node: ASTNode) -> Result<ValueId, String> {
|
||||
// Align current_span to this statement node before lowering expressions under it.
|
||||
self.current_span = node.span();
|
||||
match node {
|
||||
// 将来ここに While / ForRange / Match / Using など statement 専用分岐を追加する。
|
||||
other => self.build_expression(other),
|
||||
|
||||
@ -54,7 +54,6 @@ pub fn lower_min_loop_to_joinir(module: &crate::mir::MirModule) -> Option<JoinMo
|
||||
let mut main_func = JoinFunction::new(main_id, "main".to_string(), vec![]);
|
||||
|
||||
let i_init = ValueId(1000); // 固定 ValueId
|
||||
let const_0 = ValueId(1001);
|
||||
let const_1 = ValueId(1002);
|
||||
let const_2 = ValueId(1003);
|
||||
|
||||
|
||||
@ -49,7 +49,6 @@ use crate::mir::join_ir::lowering::value_id_ranges::stage1_using_resolver as vid
|
||||
use crate::mir::join_ir::JoinModule;
|
||||
use crate::mir::loop_form::LoopForm;
|
||||
use crate::mir::query::{MirQuery, MirQueryBox};
|
||||
use crate::mir::ValueId;
|
||||
|
||||
/// Phase 27.12: Stage1UsingResolverBox.resolve_for_source の JoinIR lowering(public dispatcher)
|
||||
///
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::mir::{BasicBlockId, ValueId};
|
||||
use crate::mir::ValueId;
|
||||
|
||||
// Phase 27.9: Lowering submodule
|
||||
pub mod lowering;
|
||||
|
||||
@ -31,7 +31,6 @@ use crate::mir::{
|
||||
BasicBlockId, BinaryOp, CompareOp as MirCompareOp, ConstValue as MirConstValue, EffectMask,
|
||||
FunctionSignature, MirFunction, MirInstruction, MirModule, MirType, ValueId,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Phase 27-shortterm S-4 エラー型
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@ -134,17 +134,14 @@ impl LoopBuilderApi for super::builder::MirBuilder {
|
||||
inputs: Vec<(BasicBlockId, ValueId)>,
|
||||
) -> Result<(), String> {
|
||||
if let Some(ref mut f) = self.current_function {
|
||||
if let Some(bb) = f.get_block_mut(block) {
|
||||
let inst = MirInstruction::Phi { dst, inputs };
|
||||
// Update effect mask and insert at the very start
|
||||
bb.effects = bb.effects | inst.effects();
|
||||
bb.instructions.insert(0, inst);
|
||||
bb.instruction_spans
|
||||
.insert(0, self.current_span);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
f,
|
||||
block,
|
||||
dst,
|
||||
inputs,
|
||||
self.current_span,
|
||||
);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("Block {} not found", block.as_u32()))
|
||||
}
|
||||
} else {
|
||||
Err("No current function".into())
|
||||
}
|
||||
|
||||
@ -23,7 +23,6 @@
|
||||
use super::{BasicBlockId, ConstValue, MirInstruction, ValueId};
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::control_form::{is_control_form_trace_on, ControlForm, IfShape, LoopShape};
|
||||
use crate::mir::phi_core::loop_snapshot_merge::LoopSnapshotMergeBox;
|
||||
use crate::mir::phi_core::loopform_builder::{LoopFormBuilder, LoopFormOps};
|
||||
use crate::mir::phi_core::phi_input_collector::PhiInputCollector;
|
||||
use std::collections::{BTreeMap, BTreeSet}; // Phase 25.1: 決定性確保
|
||||
@ -1049,7 +1048,7 @@ impl<'a> LoopBuilder<'a> {
|
||||
}
|
||||
let then_var_map_end = self.get_current_variable_map();
|
||||
// フェーズS修正:最強モード指摘の「実到達predecessor捕捉」を統一
|
||||
let then_pred_to_merge =
|
||||
let _then_pred_to_merge =
|
||||
capture_actual_predecessor_and_jump(self.parent_builder, merge_bb)?;
|
||||
// Pop then-branch debug region
|
||||
self.parent_builder.debug_pop_region();
|
||||
@ -1093,7 +1092,7 @@ impl<'a> LoopBuilder<'a> {
|
||||
else_var_map_end_opt = Some(self.get_current_variable_map());
|
||||
}
|
||||
// フェーズS修正:else branchでも統一実到達predecessor捕捉
|
||||
let else_pred_to_merge =
|
||||
let _else_pred_to_merge =
|
||||
capture_actual_predecessor_and_jump(self.parent_builder, merge_bb)?;
|
||||
// Pop else-branch debug region
|
||||
self.parent_builder.debug_pop_region();
|
||||
@ -1315,7 +1314,10 @@ impl crate::mir::phi_core::loop_phi::LoopPhiOps for LoopBuilder<'_> {
|
||||
preheader_id
|
||||
);
|
||||
}
|
||||
block.add_instruction(MirInstruction::Copy { dst, src });
|
||||
block.add_instruction_with_span(
|
||||
MirInstruction::Copy { dst, src },
|
||||
self.parent_builder.current_span,
|
||||
);
|
||||
Ok(())
|
||||
} else {
|
||||
if dbg {
|
||||
|
||||
@ -56,7 +56,7 @@ pub use instruction::MirInstruction;
|
||||
pub use join_ir_runner::{run_joinir_function, JoinRuntimeError, JoinValue};
|
||||
pub use optimizer::MirOptimizer;
|
||||
pub use printer::MirPrinter;
|
||||
pub use spanned_instruction::SpannedInstruction;
|
||||
pub use spanned_instruction::{SpannedInstRef, SpannedInstruction};
|
||||
pub use query::{MirQuery, MirQueryBox};
|
||||
pub use slot_registry::{BoxTypeId, MethodSlot};
|
||||
pub use types::{
|
||||
@ -229,8 +229,8 @@ mod tests {
|
||||
// Ensure TypeOp exists in the resulting MIR
|
||||
let has_typeop = result.module.functions.values().any(|f| {
|
||||
f.blocks.values().any(|b| {
|
||||
b.all_instructions()
|
||||
.any(|i| matches!(i, MirInstruction::TypeOp { .. }))
|
||||
b.all_spanned_instructions()
|
||||
.any(|sp| matches!(sp.inst, MirInstruction::TypeOp { .. }))
|
||||
})
|
||||
});
|
||||
assert!(
|
||||
@ -264,8 +264,8 @@ mod tests {
|
||||
// Ensure TypeOp exists in the resulting MIR
|
||||
let has_typeop = result.module.functions.values().any(|f| {
|
||||
f.blocks.values().any(|b| {
|
||||
b.all_instructions()
|
||||
.any(|i| matches!(i, MirInstruction::TypeOp { .. }))
|
||||
b.all_spanned_instructions()
|
||||
.any(|sp| matches!(sp.inst, MirInstruction::TypeOp { .. }))
|
||||
})
|
||||
});
|
||||
assert!(
|
||||
|
||||
@ -508,8 +508,8 @@ mod tests {
|
||||
let f = module.get_function("main").unwrap();
|
||||
let block = f.get_block(bb0).unwrap();
|
||||
let has_typeop = block
|
||||
.all_instructions()
|
||||
.any(|i| matches!(i, MirInstruction::TypeOp { .. }));
|
||||
.all_spanned_instructions()
|
||||
.any(|sp| matches!(sp.inst, MirInstruction::TypeOp { .. }));
|
||||
assert!(
|
||||
has_typeop,
|
||||
"TypeOp should not be dropped by DCE when used by console.log (ExternCall)"
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
use crate::ast::Span;
|
||||
use crate::mir::optimizer::MirOptimizer;
|
||||
use crate::mir::optimizer_stats::OptimizationStats;
|
||||
use crate::mir::{BarrierOp, MirModule, SpannedInstruction, TypeOpKind, ValueId, WeakRefOp};
|
||||
use crate::mir::{
|
||||
BarrierOp, EffectMask, MirModule, SpannedInstruction, TypeOpKind, ValueId, WeakRefOp,
|
||||
};
|
||||
use crate::ast::Span;
|
||||
|
||||
fn idemp_enabled() -> bool {
|
||||
std::env::var("NYASH_MIR_DEV_IDEMP").ok().as_deref() == Some("1")
|
||||
@ -36,26 +38,46 @@ pub fn force_plugin_invoke(_opt: &mut MirOptimizer, module: &mut MirModule) -> O
|
||||
None => continue,
|
||||
};
|
||||
for (_bb, block) in &mut function.blocks {
|
||||
for inst in &mut block.instructions {
|
||||
if let I::BoxCall {
|
||||
let old_spanned = block.drain_spanned_instructions();
|
||||
let mut new_spanned = Vec::with_capacity(old_spanned.len());
|
||||
for SpannedInstruction { inst, span } in old_spanned {
|
||||
let rewritten = match inst {
|
||||
I::BoxCall {
|
||||
dst,
|
||||
box_val,
|
||||
method,
|
||||
args,
|
||||
effects,
|
||||
..
|
||||
} = inst.clone()
|
||||
{
|
||||
*inst = I::PluginInvoke {
|
||||
} => {
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::PluginInvoke {
|
||||
dst,
|
||||
box_val,
|
||||
method,
|
||||
args,
|
||||
effects,
|
||||
}
|
||||
}
|
||||
other => other,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
new_spanned.push(SpannedInstruction {
|
||||
inst: rewritten,
|
||||
span,
|
||||
});
|
||||
}
|
||||
|
||||
let (insts, spans): (Vec<_>, Vec<_>) = new_spanned
|
||||
.into_iter()
|
||||
.map(|sp| (sp.inst, sp.span))
|
||||
.unzip();
|
||||
block.instructions = insts;
|
||||
block.instruction_spans = spans;
|
||||
block.effects = block
|
||||
.instructions
|
||||
.iter()
|
||||
.chain(block.terminator.iter())
|
||||
.fold(EffectMask::PURE, |mask, inst| mask | inst.effects());
|
||||
}
|
||||
if idemp_enabled() {
|
||||
let key = idemp_key(pass_name, &fname);
|
||||
@ -85,11 +107,13 @@ pub fn normalize_python_helper_calls(
|
||||
None => continue,
|
||||
};
|
||||
for (_bb, block) in &mut function.blocks {
|
||||
for inst in &mut block.instructions {
|
||||
let old_spanned = block.drain_spanned_instructions();
|
||||
let mut new_spanned = Vec::with_capacity(old_spanned.len());
|
||||
for SpannedInstruction { mut inst, span } in old_spanned {
|
||||
if let I::PluginInvoke {
|
||||
box_val,
|
||||
method,
|
||||
args,
|
||||
ref mut box_val,
|
||||
ref method,
|
||||
ref mut args,
|
||||
..
|
||||
} = inst
|
||||
{
|
||||
@ -105,7 +129,20 @@ pub fn normalize_python_helper_calls(
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
}
|
||||
new_spanned.push(SpannedInstruction { inst, span });
|
||||
}
|
||||
|
||||
let (insts, spans): (Vec<_>, Vec<_>) = new_spanned
|
||||
.into_iter()
|
||||
.map(|sp| (sp.inst, sp.span))
|
||||
.unzip();
|
||||
block.instructions = insts;
|
||||
block.instruction_spans = spans;
|
||||
block.effects = block
|
||||
.instructions
|
||||
.iter()
|
||||
.chain(block.terminator.iter())
|
||||
.fold(EffectMask::PURE, |mask, inst| mask | inst.effects());
|
||||
}
|
||||
if idemp_enabled() {
|
||||
let key = idemp_key(pass_name, &fname);
|
||||
@ -143,90 +180,79 @@ pub fn normalize_legacy_instructions(
|
||||
None => continue,
|
||||
};
|
||||
for (_bb, block) in &mut function.blocks {
|
||||
for inst in &mut block.instructions {
|
||||
match inst {
|
||||
let old_spanned = block.drain_spanned_instructions();
|
||||
let mut new_spanned = Vec::with_capacity(old_spanned.len());
|
||||
for SpannedInstruction { inst, span } in old_spanned {
|
||||
let rewritten = match inst {
|
||||
I::WeakNew { dst, box_val } => {
|
||||
let d = *dst;
|
||||
let v = *box_val;
|
||||
*inst = I::WeakRef {
|
||||
dst: d,
|
||||
op: WeakRefOp::New,
|
||||
value: v,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::WeakRef {
|
||||
dst,
|
||||
op: WeakRefOp::New,
|
||||
value: box_val,
|
||||
}
|
||||
}
|
||||
I::WeakLoad { dst, weak_ref } => {
|
||||
let d = *dst;
|
||||
let v = *weak_ref;
|
||||
*inst = I::WeakRef {
|
||||
dst: d,
|
||||
op: WeakRefOp::Load,
|
||||
value: v,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::WeakRef {
|
||||
dst,
|
||||
op: WeakRefOp::Load,
|
||||
value: weak_ref,
|
||||
}
|
||||
}
|
||||
I::BarrierRead { ptr } => {
|
||||
let p = *ptr;
|
||||
*inst = I::Barrier {
|
||||
op: BarrierOp::Read,
|
||||
ptr: p,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::Barrier {
|
||||
op: BarrierOp::Read,
|
||||
ptr,
|
||||
}
|
||||
}
|
||||
I::BarrierWrite { ptr } => {
|
||||
let p = *ptr;
|
||||
*inst = I::Barrier {
|
||||
op: BarrierOp::Write,
|
||||
ptr: p,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::Barrier {
|
||||
op: BarrierOp::Write,
|
||||
ptr,
|
||||
}
|
||||
}
|
||||
I::Print { value, .. } => {
|
||||
let v = *value;
|
||||
*inst = I::ExternCall {
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::ExternCall {
|
||||
dst: None,
|
||||
iface_name: "env.console".to_string(),
|
||||
method_name: "log".to_string(),
|
||||
args: vec![v],
|
||||
args: vec![value],
|
||||
effects: crate::mir::EffectMask::PURE.add(crate::mir::Effect::Io),
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
}
|
||||
I::ArrayGet { dst, array, index } if array_to_boxcall => {
|
||||
let d = *dst;
|
||||
let a = *array;
|
||||
let i = *index;
|
||||
stats.intrinsic_optimizations += 1;
|
||||
let mid =
|
||||
crate::mir::slot_registry::resolve_slot_by_type_name("ArrayBox", "get");
|
||||
*inst = I::BoxCall {
|
||||
dst: Some(d),
|
||||
box_val: a,
|
||||
I::BoxCall {
|
||||
dst: Some(dst),
|
||||
box_val: array,
|
||||
method: "get".to_string(),
|
||||
method_id: mid,
|
||||
args: vec![i],
|
||||
args: vec![index],
|
||||
effects: crate::mir::EffectMask::READ,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
}
|
||||
I::ArraySet {
|
||||
array,
|
||||
index,
|
||||
value,
|
||||
} if array_to_boxcall => {
|
||||
let a = *array;
|
||||
let i = *index;
|
||||
let v = *value;
|
||||
stats.intrinsic_optimizations += 1;
|
||||
let mid =
|
||||
crate::mir::slot_registry::resolve_slot_by_type_name("ArrayBox", "set");
|
||||
*inst = I::BoxCall {
|
||||
I::BoxCall {
|
||||
dst: None,
|
||||
box_val: a,
|
||||
box_val: array,
|
||||
method: "set".to_string(),
|
||||
method_id: mid,
|
||||
args: vec![i, v],
|
||||
args: vec![index, value],
|
||||
effects: crate::mir::EffectMask::WRITE,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
}
|
||||
I::PluginInvoke {
|
||||
dst,
|
||||
@ -235,176 +261,163 @@ pub fn normalize_legacy_instructions(
|
||||
args,
|
||||
effects,
|
||||
} => {
|
||||
let d = *dst;
|
||||
let recv = *box_val;
|
||||
let m = method.clone();
|
||||
let as_ = args.clone();
|
||||
let eff = *effects;
|
||||
*inst = I::BoxCall {
|
||||
dst: d,
|
||||
box_val: recv,
|
||||
method: m,
|
||||
method_id: None,
|
||||
args: as_,
|
||||
effects: eff,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::BoxCall {
|
||||
dst,
|
||||
box_val,
|
||||
method,
|
||||
method_id: None,
|
||||
args,
|
||||
effects,
|
||||
}
|
||||
I::Debug { .. } if !rw_dbg => {
|
||||
*inst = I::Nop;
|
||||
}
|
||||
I::Safepoint if !rw_sp => {
|
||||
*inst = I::Nop;
|
||||
}
|
||||
I::FutureNew { dst, value } if rw_future => {
|
||||
let d = *dst;
|
||||
let v = *value;
|
||||
*inst = I::ExternCall {
|
||||
dst: Some(d),
|
||||
I::Debug { .. } if !rw_dbg => I::Nop,
|
||||
I::Safepoint if !rw_sp => I::Nop,
|
||||
I::FutureNew { dst, value } if rw_future => I::ExternCall {
|
||||
dst: Some(dst),
|
||||
iface_name: "env.future".to_string(),
|
||||
method_name: "new".to_string(),
|
||||
args: vec![v],
|
||||
args: vec![value],
|
||||
effects: crate::mir::EffectMask::PURE.add(crate::mir::Effect::Io),
|
||||
};
|
||||
}
|
||||
I::FutureSet { future, value } if rw_future => {
|
||||
let f = *future;
|
||||
let v = *value;
|
||||
*inst = I::ExternCall {
|
||||
},
|
||||
I::FutureSet { future, value } if rw_future => I::ExternCall {
|
||||
dst: None,
|
||||
iface_name: "env.future".to_string(),
|
||||
method_name: "set".to_string(),
|
||||
args: vec![f, v],
|
||||
args: vec![future, value],
|
||||
effects: crate::mir::EffectMask::PURE.add(crate::mir::Effect::Io),
|
||||
};
|
||||
}
|
||||
I::Await { dst, future } if rw_future => {
|
||||
let d = *dst;
|
||||
let f = *future;
|
||||
*inst = I::ExternCall {
|
||||
dst: Some(d),
|
||||
},
|
||||
I::Await { dst, future } if rw_future => I::ExternCall {
|
||||
dst: Some(dst),
|
||||
iface_name: "env.future".to_string(),
|
||||
method_name: "await".to_string(),
|
||||
args: vec![f],
|
||||
args: vec![future],
|
||||
effects: crate::mir::EffectMask::PURE.add(crate::mir::Effect::Io),
|
||||
},
|
||||
other => other,
|
||||
};
|
||||
new_spanned.push(SpannedInstruction {
|
||||
inst: rewritten,
|
||||
span,
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
// terminator rewrite (subset migrated as needed)
|
||||
if let Some(term) = &mut block.terminator {
|
||||
match term {
|
||||
|
||||
let terminator = block.terminator.take();
|
||||
let terminator_span = block.terminator_span.take();
|
||||
if let Some(term) = terminator {
|
||||
let span = terminator_span.unwrap_or_else(Span::unknown);
|
||||
let rewritten = match term {
|
||||
I::TypeCheck {
|
||||
dst,
|
||||
value,
|
||||
expected_type,
|
||||
} => {
|
||||
let ty = crate::mir::MirType::Box(expected_type.clone());
|
||||
*term = I::TypeOp {
|
||||
dst: *dst,
|
||||
op: TypeOpKind::Check,
|
||||
value: *value,
|
||||
ty,
|
||||
};
|
||||
let ty = crate::mir::MirType::Box(expected_type);
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::TypeOp {
|
||||
dst,
|
||||
op: TypeOpKind::Check,
|
||||
value,
|
||||
ty,
|
||||
}
|
||||
}
|
||||
I::Cast {
|
||||
dst,
|
||||
value,
|
||||
target_type,
|
||||
} => {
|
||||
let ty = target_type.clone();
|
||||
*term = I::TypeOp {
|
||||
dst: *dst,
|
||||
op: TypeOpKind::Cast,
|
||||
value: *value,
|
||||
ty,
|
||||
};
|
||||
let ty = target_type;
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::TypeOp {
|
||||
dst,
|
||||
op: TypeOpKind::Cast,
|
||||
value,
|
||||
ty,
|
||||
}
|
||||
}
|
||||
I::WeakNew { dst, box_val } => {
|
||||
let d = *dst;
|
||||
let v = *box_val;
|
||||
*term = I::WeakRef {
|
||||
dst: d,
|
||||
op: WeakRefOp::New,
|
||||
value: v,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::WeakRef {
|
||||
dst,
|
||||
op: WeakRefOp::New,
|
||||
value: box_val,
|
||||
}
|
||||
}
|
||||
I::WeakLoad { dst, weak_ref } => {
|
||||
let d = *dst;
|
||||
let v = *weak_ref;
|
||||
*term = I::WeakRef {
|
||||
dst: d,
|
||||
op: WeakRefOp::Load,
|
||||
value: v,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::WeakRef {
|
||||
dst,
|
||||
op: WeakRefOp::Load,
|
||||
value: weak_ref,
|
||||
}
|
||||
}
|
||||
I::BarrierRead { ptr } => {
|
||||
let p = *ptr;
|
||||
*term = I::Barrier {
|
||||
op: BarrierOp::Read,
|
||||
ptr: p,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::Barrier {
|
||||
op: BarrierOp::Read,
|
||||
ptr,
|
||||
}
|
||||
}
|
||||
I::BarrierWrite { ptr } => {
|
||||
let p = *ptr;
|
||||
*term = I::Barrier {
|
||||
op: BarrierOp::Write,
|
||||
ptr: p,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::Barrier {
|
||||
op: BarrierOp::Write,
|
||||
ptr,
|
||||
}
|
||||
}
|
||||
I::Print { value, .. } => {
|
||||
let v = *value;
|
||||
*term = I::ExternCall {
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::ExternCall {
|
||||
dst: None,
|
||||
iface_name: "env.console".to_string(),
|
||||
method_name: "log".to_string(),
|
||||
args: vec![v],
|
||||
args: vec![value],
|
||||
effects: crate::mir::EffectMask::PURE,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
}
|
||||
I::ArrayGet { dst, array, index } if array_to_boxcall => {
|
||||
let d = *dst;
|
||||
let a = *array;
|
||||
let i = *index;
|
||||
*term = I::BoxCall {
|
||||
dst: Some(d),
|
||||
box_val: a,
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::BoxCall {
|
||||
dst: Some(dst),
|
||||
box_val: array,
|
||||
method: "get".to_string(),
|
||||
method_id: None,
|
||||
args: vec![i],
|
||||
args: vec![index],
|
||||
effects: crate::mir::EffectMask::READ,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
}
|
||||
I::ArraySet {
|
||||
array,
|
||||
index,
|
||||
value,
|
||||
} if array_to_boxcall => {
|
||||
let a = *array;
|
||||
let i = *index;
|
||||
let v = *value;
|
||||
*term = I::BoxCall {
|
||||
stats.intrinsic_optimizations += 1;
|
||||
I::BoxCall {
|
||||
dst: None,
|
||||
box_val: a,
|
||||
box_val: array,
|
||||
method: "set".to_string(),
|
||||
method_id: None,
|
||||
args: vec![i, v],
|
||||
args: vec![index, value],
|
||||
effects: crate::mir::EffectMask::WRITE,
|
||||
}
|
||||
}
|
||||
other => other,
|
||||
};
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
block.terminator = Some(rewritten);
|
||||
block.terminator_span = Some(span);
|
||||
}
|
||||
|
||||
let (insts, spans): (Vec<_>, Vec<_>) = new_spanned
|
||||
.into_iter()
|
||||
.map(|sp| (sp.inst, sp.span))
|
||||
.unzip();
|
||||
block.instructions = insts;
|
||||
block.instruction_spans = spans;
|
||||
block.effects = block
|
||||
.instructions
|
||||
.iter()
|
||||
.chain(block.terminator.iter())
|
||||
.fold(EffectMask::PURE, |mask, inst| mask | inst.effects());
|
||||
}
|
||||
if idemp_enabled() {
|
||||
let key = idemp_key(pass_name, &fname);
|
||||
@ -555,6 +568,12 @@ pub fn normalize_ref_field_access(
|
||||
block.terminator_span = Some(term_span);
|
||||
}
|
||||
}
|
||||
|
||||
block.effects = block
|
||||
.instructions
|
||||
.iter()
|
||||
.chain(block.terminator.iter())
|
||||
.fold(EffectMask::PURE, |mask, inst| mask | inst.effects());
|
||||
}
|
||||
if idemp_enabled() {
|
||||
let key = idemp_key(pass_name, &fname);
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
use crate::ast::Span;
|
||||
use crate::mir::optimizer::MirOptimizer;
|
||||
use crate::mir::optimizer_stats::OptimizationStats;
|
||||
use crate::mir::{BinaryOp, CompareOp, EffectMask, MirInstruction as I, MirModule, ValueId};
|
||||
use crate::mir::{
|
||||
BinaryOp, CompareOp, EffectMask, MirInstruction as I, MirModule, SpannedInstruction, ValueId,
|
||||
};
|
||||
|
||||
/// Core-13 "pure" normalization: rewrite a few non-13 ops to allowed forms.
|
||||
/// - Load(dst, ptr) => ExternCall(Some dst, env.local.get, [ptr])
|
||||
@ -16,33 +18,34 @@ pub fn normalize_pure_core13(_opt: &mut MirOptimizer, module: &mut MirModule) ->
|
||||
let mut stats = OptimizationStats::new();
|
||||
for (_fname, function) in &mut module.functions {
|
||||
for (_bb, block) in &mut function.blocks {
|
||||
let mut out: Vec<I> = Vec::with_capacity(block.instructions.len() + 8);
|
||||
let mut out_spans: Vec<Span> = Vec::with_capacity(block.instructions.len() + 8);
|
||||
let old = std::mem::take(&mut block.instructions);
|
||||
let mut old_spans_iter = std::mem::take(&mut block.instruction_spans).into_iter();
|
||||
for inst in old.into_iter() {
|
||||
let span = old_spans_iter.next().unwrap_or_else(Span::unknown);
|
||||
let old = block.drain_spanned_instructions();
|
||||
let mut out: Vec<SpannedInstruction> = Vec::with_capacity(old.len() + 8);
|
||||
for SpannedInstruction { inst, span } in old.into_iter() {
|
||||
match inst {
|
||||
I::Load { dst, ptr } => {
|
||||
out.push(I::ExternCall {
|
||||
out.push(SpannedInstruction {
|
||||
inst: I::ExternCall {
|
||||
dst: Some(dst),
|
||||
iface_name: "env.local".to_string(),
|
||||
method_name: "get".to_string(),
|
||||
args: vec![ptr],
|
||||
effects: EffectMask::READ,
|
||||
},
|
||||
span,
|
||||
});
|
||||
out_spans.push(span);
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
I::Store { value, ptr } => {
|
||||
out.push(I::ExternCall {
|
||||
out.push(SpannedInstruction {
|
||||
inst: I::ExternCall {
|
||||
dst: None,
|
||||
iface_name: "env.local".to_string(),
|
||||
method_name: "set".to_string(),
|
||||
args: vec![ptr, value],
|
||||
effects: EffectMask::WRITE,
|
||||
},
|
||||
span,
|
||||
});
|
||||
out_spans.push(span);
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
I::NewBox {
|
||||
@ -53,22 +56,26 @@ 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 {
|
||||
out.push(SpannedInstruction {
|
||||
inst: I::Const {
|
||||
dst: ty_id,
|
||||
value: crate::mir::ConstValue::String(box_type),
|
||||
},
|
||||
span,
|
||||
});
|
||||
out_spans.push(span);
|
||||
let mut call_args = Vec::with_capacity(1 + args.len());
|
||||
call_args.push(ty_id);
|
||||
call_args.append(&mut args);
|
||||
out.push(I::ExternCall {
|
||||
out.push(SpannedInstruction {
|
||||
inst: I::ExternCall {
|
||||
dst: Some(dst),
|
||||
iface_name: "env.box".to_string(),
|
||||
method_name: "new".to_string(),
|
||||
args: call_args,
|
||||
effects: EffectMask::PURE, // constructor is logically alloc; conservatively PURE here
|
||||
},
|
||||
span,
|
||||
});
|
||||
out_spans.push(span);
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
I::UnaryOp { dst, op, operand } => {
|
||||
@ -76,62 +83,71 @@ 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 {
|
||||
out.push(SpannedInstruction {
|
||||
inst: I::Const {
|
||||
dst: zero,
|
||||
value: crate::mir::ConstValue::Integer(0),
|
||||
},
|
||||
span,
|
||||
});
|
||||
out_spans.push(span);
|
||||
out.push(I::BinOp {
|
||||
out.push(SpannedInstruction {
|
||||
inst: I::BinOp {
|
||||
dst,
|
||||
op: BinaryOp::Sub,
|
||||
lhs: zero,
|
||||
rhs: operand,
|
||||
},
|
||||
span,
|
||||
});
|
||||
out_spans.push(span);
|
||||
}
|
||||
crate::mir::UnaryOp::Not => {
|
||||
let f = ValueId::new(function.next_value_id);
|
||||
function.next_value_id += 1;
|
||||
out.push(I::Const {
|
||||
out.push(SpannedInstruction {
|
||||
inst: I::Const {
|
||||
dst: f,
|
||||
value: crate::mir::ConstValue::Bool(false),
|
||||
},
|
||||
span,
|
||||
});
|
||||
out_spans.push(span);
|
||||
out.push(I::Compare {
|
||||
out.push(SpannedInstruction {
|
||||
inst: I::Compare {
|
||||
dst,
|
||||
op: CompareOp::Eq,
|
||||
lhs: operand,
|
||||
rhs: f,
|
||||
},
|
||||
span,
|
||||
});
|
||||
out_spans.push(span);
|
||||
}
|
||||
crate::mir::UnaryOp::BitNot => {
|
||||
let all1 = ValueId::new(function.next_value_id);
|
||||
function.next_value_id += 1;
|
||||
out.push(I::Const {
|
||||
out.push(SpannedInstruction {
|
||||
inst: I::Const {
|
||||
dst: all1,
|
||||
value: crate::mir::ConstValue::Integer(-1),
|
||||
},
|
||||
span,
|
||||
});
|
||||
out_spans.push(span);
|
||||
out.push(I::BinOp {
|
||||
out.push(SpannedInstruction {
|
||||
inst: I::BinOp {
|
||||
dst,
|
||||
op: BinaryOp::BitXor,
|
||||
lhs: operand,
|
||||
rhs: all1,
|
||||
},
|
||||
span,
|
||||
});
|
||||
out_spans.push(span);
|
||||
}
|
||||
}
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
other => {
|
||||
out.push(other);
|
||||
out_spans.push(span);
|
||||
other => out.push(SpannedInstruction { inst: other, span }),
|
||||
}
|
||||
}
|
||||
}
|
||||
block.instructions = out;
|
||||
block.instruction_spans = out_spans;
|
||||
block.instructions = out.iter().map(|s| s.inst.clone()).collect();
|
||||
block.instruction_spans = out.iter().map(|s| s.span).collect();
|
||||
|
||||
if let Some(term) = block.terminator.take() {
|
||||
let term_span = block.terminator_span.take().unwrap_or_else(Span::unknown);
|
||||
|
||||
@ -41,8 +41,8 @@ fn analyze_function(func: &MirFunction) -> EscapeInfo {
|
||||
let mut info = EscapeInfo::default();
|
||||
// Collect local boxes: results of NewBox in this function
|
||||
for block in func.blocks.values() {
|
||||
for ins in block.instructions.iter() {
|
||||
if let MirInstruction::NewBox { dst, .. } = ins {
|
||||
for sp in block.iter_spanned() {
|
||||
if let MirInstruction::NewBox { dst, .. } = sp.inst {
|
||||
info.local_boxes.insert(*dst);
|
||||
}
|
||||
}
|
||||
@ -54,8 +54,8 @@ fn analyze_function(func: &MirFunction) -> EscapeInfo {
|
||||
}
|
||||
// Conservative escape marking
|
||||
for block in func.blocks.values() {
|
||||
for ins in block.all_instructions() {
|
||||
match ins {
|
||||
for sp in block.all_spanned_instructions() {
|
||||
match sp.inst {
|
||||
MirInstruction::Return { value: Some(v) } => {
|
||||
if info.local_boxes.contains(v) {
|
||||
info.escaping.insert(*v);
|
||||
|
||||
@ -158,8 +158,8 @@ impl MirPrinter {
|
||||
let mut barrier_read = 0usize;
|
||||
let mut barrier_write = 0usize;
|
||||
for block in function.blocks.values() {
|
||||
for inst in &block.instructions {
|
||||
match inst {
|
||||
for sp in block.iter_spanned() {
|
||||
match sp.inst {
|
||||
MirInstruction::Throw { .. } => {
|
||||
if dlog::on("NYASH_DEBUG_MIR_PRINTER") {
|
||||
eprintln!("[PRINTER] found throw in {}", function.signature.name);
|
||||
@ -191,8 +191,8 @@ impl MirPrinter {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if let Some(term) = &block.terminator {
|
||||
match term {
|
||||
if let Some(sp) = block.terminator_spanned() {
|
||||
match sp.inst {
|
||||
MirInstruction::Throw { .. } => {
|
||||
if dlog::on("NYASH_DEBUG_MIR_PRINTER") {
|
||||
eprintln!(
|
||||
@ -306,17 +306,16 @@ impl MirPrinter {
|
||||
writeln!(output).unwrap();
|
||||
|
||||
// Instructions
|
||||
let mut line_num = 0;
|
||||
for instruction in block.all_instructions() {
|
||||
for sp in block.all_spanned_instructions() {
|
||||
if self.show_line_numbers {
|
||||
write!(output, " {:3}: ", line_num).unwrap();
|
||||
write!(output, " {:3}: ", sp.span.line).unwrap();
|
||||
} else {
|
||||
write!(output, " ").unwrap();
|
||||
}
|
||||
|
||||
let mut line = self.format_instruction(instruction, types);
|
||||
let mut line = self.format_instruction(sp.inst, types);
|
||||
if self.show_effects_inline {
|
||||
let eff = instruction.effects();
|
||||
let eff = sp.inst.effects();
|
||||
let cat = if eff.is_pure() {
|
||||
"pure"
|
||||
} else if eff.is_read_only() {
|
||||
@ -327,7 +326,6 @@ impl MirPrinter {
|
||||
line.push_str(&format!(" ; eff: {}", cat));
|
||||
}
|
||||
writeln!(output, "{}", line).unwrap();
|
||||
line_num += 1;
|
||||
}
|
||||
|
||||
// Block effects (if verbose and not pure)
|
||||
|
||||
@ -109,7 +109,6 @@ impl<'m> MirQuery for MirQueryBox<'m> {
|
||||
FutureSet { future, value } => vec![*future, *value],
|
||||
Await { future, .. } => vec![*future],
|
||||
Safepoint => Vec::new(),
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::ast::Span;
|
||||
use super::MirInstruction;
|
||||
use crate::ast::Span;
|
||||
|
||||
/// MIR instruction bundled with its source span.
|
||||
#[derive(Debug, Clone)]
|
||||
@ -7,3 +7,10 @@ pub struct SpannedInstruction {
|
||||
pub inst: MirInstruction,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// Reference view of a MIR instruction bundled with its span.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SpannedInstRef<'a> {
|
||||
pub inst: &'a MirInstruction,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
use crate::mir::{BasicBlockId, CompareOp, MirFunction, MirInstruction, ValueId};
|
||||
use crate::mir::{
|
||||
BasicBlockId, CompareOp, MirFunction, MirInstruction, SpannedInstruction, ValueId,
|
||||
};
|
||||
use crate::ast::Span;
|
||||
|
||||
/// Emit a MIR Compare instruction into the current block (function-level SSOT helper)
|
||||
pub fn emit_compare_func(
|
||||
@ -49,16 +52,28 @@ pub fn set_jump(f: &mut MirFunction, cur_bb: BasicBlockId, target: BasicBlockId)
|
||||
|
||||
/// Insert a PHI instruction at block head (after existing PHIs) with normalized inputs order.
|
||||
pub fn insert_phi_at_head(
|
||||
f: &mut MirFunction,
|
||||
bb_id: BasicBlockId,
|
||||
dst: ValueId,
|
||||
inputs: Vec<(BasicBlockId, ValueId)>,
|
||||
) {
|
||||
insert_phi_at_head_spanned(f, bb_id, dst, inputs, Span::unknown());
|
||||
}
|
||||
|
||||
/// Insert a PHI instruction at block head (after existing PHIs) with normalized inputs order.
|
||||
/// Allows passing a span to retain source mapping when available.
|
||||
pub fn insert_phi_at_head_spanned(
|
||||
f: &mut MirFunction,
|
||||
bb_id: BasicBlockId,
|
||||
dst: ValueId,
|
||||
mut inputs: Vec<(BasicBlockId, ValueId)>,
|
||||
span: Span,
|
||||
) {
|
||||
inputs.sort_by_key(|(bb, _)| bb.0);
|
||||
if let Some(bb) = f.get_block_mut(bb_id) {
|
||||
bb.insert_spanned_after_phis(crate::mir::SpannedInstruction {
|
||||
bb.insert_spanned_after_phis(SpannedInstruction {
|
||||
inst: MirInstruction::Phi { dst, inputs },
|
||||
span: crate::ast::Span::unknown(),
|
||||
span,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +72,13 @@ impl MirBuilder {
|
||||
// 統一された挿入ロジック(既存パターンと完全互換)
|
||||
if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) {
|
||||
// CFG経由の正規化挿入(predecessor順序の正規化を含む)
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, phi_val, inputs);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
func,
|
||||
cur_bb,
|
||||
phi_val,
|
||||
inputs,
|
||||
self.current_span,
|
||||
);
|
||||
} else {
|
||||
// フォールバック: 直接emit(主にテストや特殊ケース用)
|
||||
self.emit_instruction(MirInstruction::Phi {
|
||||
@ -131,7 +137,13 @@ impl MirBuilder {
|
||||
// 統一された挿入ロジック(既存パターンと完全互換)
|
||||
if let (Some(func), Some(cur_bb)) = (self.current_function.as_mut(), self.current_block) {
|
||||
// CFG経由の正規化挿入(predecessor順序の正規化を含む)
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(func, cur_bb, dst, inputs);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
func,
|
||||
cur_bb,
|
||||
dst,
|
||||
inputs,
|
||||
self.current_span,
|
||||
);
|
||||
} else {
|
||||
// フォールバック: 直接emit(主にテストや特殊ケース用)
|
||||
self.emit_instruction(MirInstruction::Phi { dst, inputs })?;
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
// - ValueIdの意味的分類(Parameter, Local, Constant等)を導入
|
||||
// - GUARDバグのような「ValueId(0)の曖昧性」から生じるバグを根絶
|
||||
|
||||
use crate::mir::ConstValue;
|
||||
use crate::mir::ValueId;
|
||||
|
||||
/// ValueIdの意味的分類(型安全性強化)
|
||||
|
||||
@ -93,9 +93,10 @@ impl MirVerifier {
|
||||
instruction_index
|
||||
);
|
||||
if let Some(bb) = function.blocks.get(block) {
|
||||
let inst_opt = bb.all_instructions().nth(*instruction_index);
|
||||
if let Some(inst) = inst_opt {
|
||||
eprintln!("[mir-ssa-debug-inst] inst={:?}", inst);
|
||||
let inst_opt =
|
||||
bb.all_spanned_instructions_enumerated().nth(*instruction_index);
|
||||
if let Some((_idx, sp)) = inst_opt {
|
||||
eprintln!("[mir-ssa-debug-inst] inst={:?}", sp.inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -291,8 +292,8 @@ impl MirVerifier {
|
||||
|
||||
// Collect values used in merge block
|
||||
let mut used_values = std::collections::HashSet::new();
|
||||
for inst in merge_bb.all_instructions() {
|
||||
for v in inst.used_values() {
|
||||
for sp in merge_bb.all_spanned_instructions() {
|
||||
for v in sp.inst.used_values() {
|
||||
used_values.insert(v);
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,15 +9,15 @@ pub fn check_weakref_and_barrier(function: &MirFunction) -> Result<(), Vec<Verif
|
||||
let mut def_map: std::collections::HashMap<ValueId, (BasicBlockId, usize, &MirInstruction)> =
|
||||
std::collections::HashMap::new();
|
||||
for (bid, block) in &function.blocks {
|
||||
for (idx, inst) in block.all_instructions().enumerate() {
|
||||
if let Some(dst) = inst.dst_value() {
|
||||
def_map.insert(dst, (*bid, idx, inst));
|
||||
for (idx, sp) in block.all_spanned_instructions_enumerated() {
|
||||
if let Some(dst) = sp.inst.dst_value() {
|
||||
def_map.insert(dst, (*bid, idx, sp.inst));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (bid, block) in &function.blocks {
|
||||
for (idx, inst) in block.all_instructions().enumerate() {
|
||||
match inst {
|
||||
for (idx, sp) in block.all_spanned_instructions_enumerated() {
|
||||
match sp.inst {
|
||||
MirInstruction::WeakRef {
|
||||
op: crate::mir::WeakRefOp::Load,
|
||||
value,
|
||||
@ -103,11 +103,10 @@ pub fn check_barrier_context(function: &MirFunction) -> Result<(), Vec<Verificat
|
||||
|
||||
let mut errors = Vec::new();
|
||||
for (bid, block) in &function.blocks {
|
||||
let mut insts: Vec<(usize, &MirInstruction)> =
|
||||
block.instructions.iter().enumerate().collect();
|
||||
if let Some(term) = &block.terminator {
|
||||
insts.push((usize::MAX, term));
|
||||
}
|
||||
let insts: Vec<(usize, &MirInstruction)> = block
|
||||
.all_spanned_instructions_enumerated()
|
||||
.map(|(i, sp)| (i, sp.inst))
|
||||
.collect();
|
||||
for (idx, inst) in &insts {
|
||||
let is_barrier = matches!(
|
||||
inst,
|
||||
|
||||
@ -42,8 +42,8 @@ pub fn check_merge_uses(function: &MirFunction) -> Result<(), Vec<VerificationEr
|
||||
let mut phi_dsts_in_block: HashMap<BasicBlockId, HashSet<ValueId>> = HashMap::new();
|
||||
for (bid, block) in &function.blocks {
|
||||
let set = phi_dsts_in_block.entry(*bid).or_default();
|
||||
for inst in block.all_instructions() {
|
||||
if let crate::mir::MirInstruction::Phi { dst, .. } = inst {
|
||||
for sp in block.all_spanned_instructions() {
|
||||
if let crate::mir::MirInstruction::Phi { dst, .. } = sp.inst {
|
||||
set.insert(*dst);
|
||||
}
|
||||
}
|
||||
@ -57,11 +57,11 @@ pub fn check_merge_uses(function: &MirFunction) -> Result<(), Vec<VerificationEr
|
||||
}
|
||||
let phi_dsts = phi_dsts_in_block.get(bid);
|
||||
let doms_of_block = dominators.get(bid).unwrap();
|
||||
for inst in block.all_instructions() {
|
||||
if let crate::mir::MirInstruction::Phi { .. } = inst {
|
||||
for sp in block.all_spanned_instructions() {
|
||||
if let crate::mir::MirInstruction::Phi { .. } = sp.inst {
|
||||
continue;
|
||||
}
|
||||
for used in inst.used_values() {
|
||||
for used in sp.inst.used_values() {
|
||||
if let Some(&db) = def_block.get(&used) {
|
||||
if !doms_of_block.contains(&db) {
|
||||
let is_phi_dst = phi_dsts.map(|s| s.contains(&used)).unwrap_or(false);
|
||||
|
||||
@ -11,11 +11,11 @@ pub fn check_dominance(function: &MirFunction) -> Result<(), Vec<VerificationErr
|
||||
let def_block = utils::compute_def_blocks(function);
|
||||
let dominators = utils::compute_dominators(function);
|
||||
for (use_block_id, block) in &function.blocks {
|
||||
for instruction in block.all_instructions() {
|
||||
if let crate::mir::MirInstruction::Phi { .. } = instruction {
|
||||
for sp in block.all_spanned_instructions() {
|
||||
if let crate::mir::MirInstruction::Phi { .. } = sp.inst {
|
||||
continue;
|
||||
}
|
||||
for used_value in instruction.used_values() {
|
||||
for used_value in sp.inst.used_values() {
|
||||
if let Some(&def_bb) = def_block.get(&used_value) {
|
||||
if def_bb != *use_block_id {
|
||||
let doms = dominators.get(use_block_id).unwrap();
|
||||
|
||||
@ -9,8 +9,8 @@ pub fn check_no_legacy_ops(function: &MirFunction) -> Result<(), Vec<Verificatio
|
||||
}
|
||||
let mut errors = Vec::new();
|
||||
for (bid, block) in &function.blocks {
|
||||
for (idx, inst) in block.all_instructions().enumerate() {
|
||||
let legacy_name = match inst {
|
||||
for (idx, sp) in block.all_spanned_instructions_enumerated() {
|
||||
let legacy_name = match sp.inst {
|
||||
MirInstruction::TypeCheck { .. } => Some("TypeCheck"), // -> TypeOp(Check)
|
||||
MirInstruction::Cast { .. } => Some("Cast"), // -> TypeOp(Cast)
|
||||
MirInstruction::WeakNew { .. } => Some("WeakNew"), // -> WeakRef(New)
|
||||
|
||||
@ -14,8 +14,8 @@ pub fn check_ssa_form(function: &MirFunction) -> Result<(), Vec<VerificationErro
|
||||
}
|
||||
|
||||
for (block_id, block) in &function.blocks {
|
||||
for (inst_idx, instruction) in block.all_instructions().enumerate() {
|
||||
if let Some(dst) = instruction.dst_value() {
|
||||
for (inst_idx, sp) in block.all_spanned_instructions_enumerated() {
|
||||
if let Some(dst) = sp.inst.dst_value() {
|
||||
if let Some((first_block, _)) = definitions.insert(dst, (*block_id, inst_idx)) {
|
||||
errors.push(VerificationError::MultipleDefinition {
|
||||
value: dst,
|
||||
@ -28,12 +28,12 @@ pub fn check_ssa_form(function: &MirFunction) -> Result<(), Vec<VerificationErro
|
||||
}
|
||||
|
||||
for (block_id, block) in &function.blocks {
|
||||
for (inst_idx, instruction) in block.all_instructions().enumerate() {
|
||||
for used_value in instruction.used_values() {
|
||||
for (inst_idx, sp) in block.all_spanned_instructions_enumerated() {
|
||||
for used_value in sp.inst.used_values() {
|
||||
if !definitions.contains_key(&used_value) {
|
||||
eprintln!(
|
||||
"[ssa-undef-debug] fn={} bb={:?} inst_idx={} used={:?} inst={:?}",
|
||||
function.signature.name, block_id, inst_idx, used_value, instruction
|
||||
function.signature.name, block_id, inst_idx, used_value, sp.inst
|
||||
);
|
||||
errors.push(VerificationError::UndefinedValue {
|
||||
value: used_value,
|
||||
|
||||
@ -17,8 +17,8 @@ pub fn compute_def_blocks(function: &MirFunction) -> HashMap<ValueId, BasicBlock
|
||||
def_block.insert(*pid, function.entry_block);
|
||||
}
|
||||
for (bid, block) in &function.blocks {
|
||||
for inst in block.all_instructions() {
|
||||
if let Some(dst) = inst.dst_value() {
|
||||
for sp in block.all_spanned_instructions() {
|
||||
if let Some(dst) = sp.inst.dst_value() {
|
||||
def_block.insert(dst, *bid);
|
||||
}
|
||||
}
|
||||
@ -79,8 +79,8 @@ pub fn compute_reachable_blocks(function: &MirFunction) -> HashSet<BasicBlockId>
|
||||
worklist.push(*successor);
|
||||
}
|
||||
}
|
||||
for instruction in &block.instructions {
|
||||
if let crate::mir::MirInstruction::Catch { handler_bb, .. } = instruction {
|
||||
for sp in block.iter_spanned() {
|
||||
if let crate::mir::MirInstruction::Catch { handler_bb, .. } = sp.inst {
|
||||
if !reachable.contains(handler_bb) {
|
||||
worklist.push(*handler_bb);
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ use super::merge::new_block;
|
||||
use super::ternary;
|
||||
use super::BridgeEnv;
|
||||
use crate::mir::{BasicBlockId, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId};
|
||||
use crate::ast::Span;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use super::super::ast::ExprV0;
|
||||
@ -290,7 +291,13 @@ pub(super) fn lower_expr_with_scope<S: VarScope>(
|
||||
} else {
|
||||
inputs.push((fall_bb, rval));
|
||||
}
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(f, merge_bb, out, inputs);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
f,
|
||||
merge_bb,
|
||||
out,
|
||||
inputs,
|
||||
Span::unknown(),
|
||||
);
|
||||
Ok((out, merge_bb))
|
||||
}
|
||||
ExprV0::Call { name, args } => {
|
||||
|
||||
@ -23,10 +23,10 @@
|
||||
use super::super::ast::ExprV0;
|
||||
use super::super::ast::StmtV0;
|
||||
use super::{lower_stmt_list_with_vars, new_block, BridgeEnv, LoopContext};
|
||||
use crate::mir::phi_core::loop_snapshot_merge::LoopSnapshotMergeBox;
|
||||
use crate::mir::phi_core::loopform_builder::{LoopFormBuilder, LoopFormOps};
|
||||
use crate::mir::phi_core::phi_input_collector::PhiInputCollector;
|
||||
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
||||
use crate::ast::Span;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// LoopForm v2 用の JSON bridge 実装。
|
||||
@ -143,7 +143,13 @@ impl LoopFormOps for LoopFormJsonOps<'_> {
|
||||
dst: ValueId,
|
||||
inputs: Vec<(BasicBlockId, ValueId)>,
|
||||
) -> Result<(), String> {
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(self.f, self.current_block, dst, inputs);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
self.f,
|
||||
self.current_block,
|
||||
dst,
|
||||
inputs,
|
||||
Span::unknown(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -363,11 +369,12 @@ pub(super) fn lower_loop_stmt(
|
||||
// 異なる値を持つ場合は PHI ノードを continue_merge_bb に生成
|
||||
let final_inputs = collector.finalize();
|
||||
let phi_id = ops.f.next_value_id();
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
ops.f,
|
||||
continue_merge_bb,
|
||||
phi_id,
|
||||
final_inputs,
|
||||
Span::unknown(),
|
||||
);
|
||||
phi_id
|
||||
};
|
||||
|
||||
@ -5,6 +5,7 @@ use super::expr::{lower_expr_with_scope, VarScope};
|
||||
use super::merge::new_block;
|
||||
use super::BridgeEnv;
|
||||
use crate::mir::{BasicBlockId, CompareOp, ConstValue, MirFunction, MirInstruction, ValueId};
|
||||
use crate::ast::Span;
|
||||
|
||||
pub(super) fn lower_match_expr_with_scope<S: VarScope>(
|
||||
env: &BridgeEnv,
|
||||
@ -85,6 +86,12 @@ pub(super) fn lower_match_expr_with_scope<S: VarScope>(
|
||||
let out = f.next_value_id();
|
||||
// フェーズM.2: PHI統一処理(no_phi分岐削除)
|
||||
let inputs = phi_inputs;
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(f, merge_bb, out, inputs);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
f,
|
||||
merge_bb,
|
||||
out,
|
||||
inputs,
|
||||
Span::unknown(),
|
||||
);
|
||||
Ok((out, merge_bb))
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use crate::mir::{BasicBlock, BasicBlockId, MirFunction, MirInstruction, ValueId};
|
||||
use crate::ast::Span;
|
||||
|
||||
fn next_block_id(f: &MirFunction) -> BasicBlockId {
|
||||
let mut mx = 0u32;
|
||||
@ -41,11 +42,12 @@ pub(super) fn merge_values(
|
||||
bb.add_instruction_before_terminator(MirInstruction::Copy { dst, src: val_b });
|
||||
}
|
||||
} else {
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
f,
|
||||
merge_bb,
|
||||
dst,
|
||||
vec![(pred_a, val_a), (pred_b, val_b)],
|
||||
Span::unknown(),
|
||||
);
|
||||
}
|
||||
dst
|
||||
|
||||
@ -7,6 +7,7 @@ use super::super::ast::ExprV0;
|
||||
use super::merge::new_block;
|
||||
use super::BridgeEnv;
|
||||
use crate::mir::{BasicBlockId, MirFunction, ValueId};
|
||||
use crate::ast::Span;
|
||||
|
||||
use super::expr::{lower_expr_with_scope, VarScope};
|
||||
|
||||
@ -40,6 +41,12 @@ pub(super) fn lower_ternary_expr_with_scope<S: VarScope>(
|
||||
let out = f.next_value_id();
|
||||
// フェーズM.2: PHI統一処理(no_phi分岐削除)
|
||||
let inputs = vec![(tend, tval), (eend, eval)];
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(f, merge_bb, out, inputs);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
f,
|
||||
merge_bb,
|
||||
out,
|
||||
inputs,
|
||||
Span::unknown(),
|
||||
);
|
||||
Ok((out, merge_bb))
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use super::super::ast::{CatchV0, StmtV0};
|
||||
use super::{lower_stmt_list_with_vars, new_block, BridgeEnv, LoopContext};
|
||||
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
||||
use crate::ast::Span;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub(super) fn lower_try_stmt(
|
||||
@ -102,8 +103,12 @@ pub(super) fn lower_try_stmt(
|
||||
if let Some(_bb) = f.get_block_mut(catch_bb) {
|
||||
let mut inputs = incoming_exc.clone();
|
||||
inputs.sort_by_key(|(bbid, _)| bbid.0);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(
|
||||
f, catch_bb, phi_dst, inputs,
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
f,
|
||||
catch_bb,
|
||||
phi_dst,
|
||||
inputs,
|
||||
Span::unknown(),
|
||||
);
|
||||
}
|
||||
catch_vars.insert(param.clone(), phi_dst);
|
||||
@ -170,7 +175,13 @@ pub(super) fn lower_try_stmt(
|
||||
}
|
||||
if let Some(_bb) = f.get_block_mut(finally_block) {
|
||||
for (dst, inputs) in phi_entries {
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(f, finally_block, dst, inputs);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
f,
|
||||
finally_block,
|
||||
dst,
|
||||
inputs,
|
||||
Span::unknown(),
|
||||
);
|
||||
}
|
||||
}
|
||||
let mut finally_vars = merged_vars.clone();
|
||||
@ -226,7 +237,13 @@ pub(super) fn lower_try_stmt(
|
||||
}
|
||||
if let Some(_bb) = f.get_block_mut(exit_bb) {
|
||||
for (dst, inputs) in phi_entries {
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(f, exit_bb, dst, inputs);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
f,
|
||||
exit_bb,
|
||||
dst,
|
||||
inputs,
|
||||
Span::unknown(),
|
||||
);
|
||||
}
|
||||
}
|
||||
*vars = merged_vars;
|
||||
@ -326,7 +343,13 @@ pub(super) fn lower_try_stmt(
|
||||
// フェーズM.2: PHI統一処理(no_phi分岐削除)
|
||||
if let Some(_bb) = f.get_block_mut(finally_block) {
|
||||
for (dst, inputs) in phi_entries {
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(f, finally_block, dst, inputs);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
f,
|
||||
finally_block,
|
||||
dst,
|
||||
inputs,
|
||||
Span::unknown(),
|
||||
);
|
||||
}
|
||||
}
|
||||
let mut finally_vars = merged_vars.clone();
|
||||
@ -377,7 +400,13 @@ pub(super) fn lower_try_stmt(
|
||||
// フェーズM.2: PHI統一処理(no_phi分岐削除)
|
||||
if let Some(_bb) = f.get_block_mut(exit_bb) {
|
||||
for (dst, inputs) in phi_entries {
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head(f, exit_bb, dst, inputs);
|
||||
crate::mir::ssot::cf_common::insert_phi_at_head_spanned(
|
||||
f,
|
||||
exit_bb,
|
||||
dst,
|
||||
inputs,
|
||||
Span::unknown(),
|
||||
);
|
||||
}
|
||||
}
|
||||
*vars = merged_vars;
|
||||
|
||||
@ -101,14 +101,12 @@ fn print_source_snippet(filename: &str, src: &str, line: usize, col: Option<usiz
|
||||
if line <= lines.len() {
|
||||
let text = lines[line - 1];
|
||||
let mut underline = String::new();
|
||||
let mut idx = 0usize;
|
||||
for (i, ch) in text.chars().enumerate() {
|
||||
if i + 1 >= col {
|
||||
break;
|
||||
}
|
||||
// Preserve tabs visually; spaces elsewhere
|
||||
underline.push(if ch == '\t' { '\t' } else { ' ' });
|
||||
idx = i;
|
||||
}
|
||||
let pad = " "; // align under " LNNNNN |"
|
||||
eprintln!(" {}{}^", pad, underline);
|
||||
|
||||
@ -178,6 +178,7 @@ impl<'a> PreludeManagerBox<'a> {
|
||||
});
|
||||
current_line += main_lines;
|
||||
}
|
||||
let _ = current_line;
|
||||
|
||||
if trace {
|
||||
crate::runner::trace::log(format!(
|
||||
|
||||
@ -999,6 +999,7 @@ pub fn merge_prelude_text(
|
||||
});
|
||||
current_line += main_lines;
|
||||
}
|
||||
let _ = current_line;
|
||||
|
||||
if trace {
|
||||
crate::runner::trace::log(format!(
|
||||
|
||||
@ -21,7 +21,7 @@ mod modules;
|
||||
|
||||
use super::NyashRunner;
|
||||
use crate::cli::CliGroups;
|
||||
use std::{path::Path, process};
|
||||
use std::path::Path;
|
||||
|
||||
impl NyashRunner {
|
||||
/// If enabled, run the Stage-1 CLI stub as a child process and return its exit code.
|
||||
|
||||
Reference in New Issue
Block a user