merge: resolve conflicts (prefer cranelift-dev for Core-13 defaults; drop modules/using, add env.local/env.box shims)
This commit is contained in:
@ -157,6 +157,10 @@ impl MirBuilder {
|
||||
/// Emit a weak reference creation (Unified: WeakRef(New))
|
||||
#[allow(dead_code)]
|
||||
pub(super) fn emit_weak_new(&mut self, box_val: ValueId) -> Result<ValueId, String> {
|
||||
if crate::config::env::mir_core13_pure() {
|
||||
// Pure mode: avoid WeakRef emission; pass-through
|
||||
return Ok(box_val);
|
||||
}
|
||||
let dst = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::WeakRef { dst, op: super::WeakRefOp::New, value: box_val })?;
|
||||
Ok(dst)
|
||||
@ -165,6 +169,10 @@ impl MirBuilder {
|
||||
/// Emit a weak reference load (Unified: WeakRef(Load))
|
||||
#[allow(dead_code)]
|
||||
pub(super) fn emit_weak_load(&mut self, weak_ref: ValueId) -> Result<ValueId, String> {
|
||||
if crate::config::env::mir_core13_pure() {
|
||||
// Pure mode: avoid WeakRef emission; pass-through
|
||||
return Ok(weak_ref);
|
||||
}
|
||||
let dst = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::WeakRef { dst, op: super::WeakRefOp::Load, value: weak_ref })?;
|
||||
Ok(dst)
|
||||
@ -771,6 +779,27 @@ impl MirBuilder {
|
||||
/// Build new expression: new ClassName(arguments)
|
||||
pub(super) fn build_new_expression(&mut self, class: String, arguments: Vec<ASTNode>) -> Result<ValueId, String> {
|
||||
// Phase 9.78a: Unified Box creation using NewBox instruction
|
||||
// Core-13 pure mode: emit ExternCall(env.box.new) with type name const only
|
||||
if crate::config::env::mir_core13_pure() {
|
||||
// Emit Const String for type name
|
||||
let ty_id = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Const { dst: ty_id, value: ConstValue::String(class.clone()) })?;
|
||||
// Evaluate arguments (pass through to env.box.new shim)
|
||||
let mut arg_vals: Vec<ValueId> = Vec::with_capacity(arguments.len());
|
||||
for a in arguments { arg_vals.push(self.build_expression(a)?); }
|
||||
// Build arg list: [type, a1, a2, ...]
|
||||
let mut args: Vec<ValueId> = Vec::with_capacity(1 + arg_vals.len());
|
||||
args.push(ty_id);
|
||||
args.extend(arg_vals);
|
||||
// Call env.box.new
|
||||
let dst = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::ExternCall {
|
||||
dst: Some(dst), iface_name: "env.box".to_string(), method_name: "new".to_string(), args, effects: EffectMask::PURE,
|
||||
})?;
|
||||
// 型注釈(最小)
|
||||
self.value_types.insert(dst, super::MirType::Box(class.clone()));
|
||||
return Ok(dst);
|
||||
}
|
||||
|
||||
// Optimization: Primitive wrappers → emit Const directly when possible
|
||||
if class == "IntegerBox" && arguments.len() == 1 {
|
||||
|
||||
@ -73,10 +73,35 @@ impl super::MirBuilder {
|
||||
// Build a unary operation
|
||||
pub(super) fn build_unary_op(&mut self, operator: String, operand: ASTNode) -> Result<ValueId, String> {
|
||||
let operand_val = self.build_expression(operand)?;
|
||||
// Core-13 純化: UnaryOp を直接 展開(Neg/Not/BitNot)
|
||||
if crate::config::env::mir_core13_pure() {
|
||||
match operator.as_str() {
|
||||
"-" => {
|
||||
let zero = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Const { dst: zero, value: crate::mir::ConstValue::Integer(0) })?;
|
||||
let dst = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::BinOp { dst, op: crate::mir::BinaryOp::Sub, lhs: zero, rhs: operand_val })?;
|
||||
return Ok(dst);
|
||||
}
|
||||
"!" | "not" => {
|
||||
let f = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Const { dst: f, value: crate::mir::ConstValue::Bool(false) })?;
|
||||
let dst = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Compare { dst, op: crate::mir::CompareOp::Eq, lhs: operand_val, rhs: f })?;
|
||||
return Ok(dst);
|
||||
}
|
||||
"~" => {
|
||||
let all1 = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::Const { dst: all1, value: crate::mir::ConstValue::Integer(-1) })?;
|
||||
let dst = self.value_gen.next();
|
||||
self.emit_instruction(MirInstruction::BinOp { dst, op: crate::mir::BinaryOp::BitXor, lhs: operand_val, rhs: all1 })?;
|
||||
return Ok(dst);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let dst = self.value_gen.next();
|
||||
|
||||
let mir_op = self.convert_unary_operator(operator)?;
|
||||
|
||||
self.emit_instruction(MirInstruction::UnaryOp { dst, op: mir_op, operand: operand_val })?;
|
||||
Ok(dst)
|
||||
}
|
||||
|
||||
@ -126,6 +126,37 @@ impl MirCompiler {
|
||||
return Err(format!("Core-13 strict: final MIR contains {} legacy ops", legacy_count));
|
||||
}
|
||||
}
|
||||
|
||||
// Core-13 pure: allow only the 13 canonical ops; reject all others
|
||||
if crate::config::env::mir_core13_pure() {
|
||||
let mut bad = 0usize;
|
||||
let is_allowed = |i: &MirInstruction| -> bool {
|
||||
matches!(i,
|
||||
MirInstruction::Const { .. }
|
||||
| MirInstruction::BinOp { .. }
|
||||
| MirInstruction::Compare { .. }
|
||||
| MirInstruction::Jump { .. }
|
||||
| MirInstruction::Branch { .. }
|
||||
| MirInstruction::Return { .. }
|
||||
| MirInstruction::Phi { .. }
|
||||
| MirInstruction::Call { .. }
|
||||
| MirInstruction::BoxCall { .. }
|
||||
| MirInstruction::ExternCall { .. }
|
||||
| MirInstruction::TypeOp { .. }
|
||||
| MirInstruction::Safepoint
|
||||
| MirInstruction::Barrier { .. }
|
||||
)
|
||||
};
|
||||
for (_fname, function) in &module.functions {
|
||||
for (_bb, block) in &function.blocks {
|
||||
for inst in &block.instructions { if !is_allowed(inst) { bad += 1; } }
|
||||
if let Some(term) = &block.terminator { if !is_allowed(term) { bad += 1; } }
|
||||
}
|
||||
}
|
||||
if bad > 0 {
|
||||
return Err(format!("Core-13 pure strict: final MIR contains {} non-Core-13 ops", bad));
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the generated MIR
|
||||
let verification_result = self.verifier.verify_module(&module);
|
||||
@ -292,6 +323,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_lowering_await_expression() {
|
||||
if crate::config::env::mir_core13_pure() { eprintln!("[TEST] skip await under Core-13 pure mode"); return; }
|
||||
// Build AST: await 1 (semantic is nonsensical but should emit Await)
|
||||
let ast = ASTNode::AwaitExpression { expression: Box::new(ASTNode::Literal { value: LiteralValue::Integer(1), span: crate::ast::Span::unknown() }), span: crate::ast::Span::unknown() };
|
||||
let mut compiler = MirCompiler::new();
|
||||
@ -302,6 +334,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_await_has_checkpoints() {
|
||||
if crate::config::env::mir_core13_pure() { eprintln!("[TEST] skip await under Core-13 pure mode"); return; }
|
||||
use crate::ast::{LiteralValue, Span};
|
||||
// Build: await 1
|
||||
let ast = ASTNode::AwaitExpression { expression: Box::new(ASTNode::Literal { value: LiteralValue::Integer(1), span: Span::unknown() }), span: Span::unknown() };
|
||||
@ -317,6 +350,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_rewritten_await_still_checkpoints() {
|
||||
if crate::config::env::mir_core13_pure() { eprintln!("[TEST] skip await under Core-13 pure mode"); return; }
|
||||
use crate::ast::{LiteralValue, Span};
|
||||
// Enable rewrite so Await → ExternCall(env.future.await)
|
||||
std::env::set_var("NYASH_REWRITE_FUTURE", "1");
|
||||
@ -388,6 +422,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_try_catch_compilation() {
|
||||
// Core-13 pure モードでは Try/Catch 命令は許容集合外のためスキップ
|
||||
if crate::config::env::mir_core13_pure() {
|
||||
eprintln!("[TEST] skip try/catch under Core-13 pure mode");
|
||||
return;
|
||||
}
|
||||
let mut compiler = MirCompiler::new();
|
||||
|
||||
let try_catch_ast = ASTNode::TryCatch {
|
||||
|
||||
@ -85,7 +85,12 @@ impl MirOptimizer {
|
||||
// Lowererがより正確にBox種別を選べるようにする。
|
||||
let updates = crate::mir::passes::type_hints::propagate_param_type_hints(module);
|
||||
if updates > 0 { stats.intrinsic_optimizations += updates as usize; }
|
||||
|
||||
|
||||
// Pass 7 (optional): Core-13 pure normalization
|
||||
if crate::config::env::mir_core13_pure() {
|
||||
stats.merge(self.normalize_pure_core13(module));
|
||||
}
|
||||
|
||||
if self.debug {
|
||||
println!("✅ Optimization complete: {}", stats);
|
||||
}
|
||||
@ -115,6 +120,120 @@ impl MirOptimizer {
|
||||
|
||||
stats
|
||||
}
|
||||
|
||||
/// Core-13 "pure" normalization: rewrite a few non-13 ops to allowed forms.
|
||||
/// - Load(dst, ptr) => ExternCall(Some dst, env.local.get, [ptr])
|
||||
/// - Store(val, ptr) => ExternCall(None, env.local.set, [ptr, val])
|
||||
/// - NewBox(dst, T, args...) => ExternCall(Some dst, env.box.new, [Const String(T), args...])
|
||||
/// - UnaryOp:
|
||||
/// Neg x => BinOp(Sub, Const 0, x)
|
||||
/// Not x => Compare(Eq, x, Const false)
|
||||
/// BitNot x => BinOp(BitXor, x, Const(-1))
|
||||
fn normalize_pure_core13(&mut self, module: &mut MirModule) -> OptimizationStats {
|
||||
use super::instruction::ConstValue;
|
||||
use super::{MirInstruction as I, BinaryOp, CompareOp};
|
||||
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 old = std::mem::take(&mut block.instructions);
|
||||
for inst in old.into_iter() {
|
||||
match inst {
|
||||
I::Load { dst, ptr } => {
|
||||
out.push(I::ExternCall {
|
||||
dst: Some(dst), iface_name: "env.local".to_string(), method_name: "get".to_string(),
|
||||
args: vec![ptr], effects: super::EffectMask::READ,
|
||||
});
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
I::Store { value, ptr } => {
|
||||
out.push(I::ExternCall {
|
||||
dst: None, iface_name: "env.local".to_string(), method_name: "set".to_string(),
|
||||
args: vec![ptr, value], effects: super::EffectMask::WRITE,
|
||||
});
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
I::NewBox { dst, box_type, mut args } => {
|
||||
// prepend type name as Const String
|
||||
let ty_id = super::ValueId::new(function.next_value_id);
|
||||
function.next_value_id += 1;
|
||||
out.push(I::Const { dst: ty_id, value: ConstValue::String(box_type) });
|
||||
let mut call_args = Vec::with_capacity(1 + args.len());
|
||||
call_args.push(ty_id);
|
||||
call_args.append(&mut args);
|
||||
out.push(I::ExternCall {
|
||||
dst: Some(dst), iface_name: "env.box".to_string(), method_name: "new".to_string(),
|
||||
args: call_args, effects: super::EffectMask::PURE, // constructor is logically alloc; conservatively PURE here
|
||||
});
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
I::UnaryOp { dst, op, operand } => {
|
||||
match op {
|
||||
super::UnaryOp::Neg => {
|
||||
let zero = super::ValueId::new(function.next_value_id); function.next_value_id += 1;
|
||||
out.push(I::Const { dst: zero, value: ConstValue::Integer(0) });
|
||||
out.push(I::BinOp { dst, op: BinaryOp::Sub, lhs: zero, rhs: operand });
|
||||
}
|
||||
super::UnaryOp::Not => {
|
||||
let f = super::ValueId::new(function.next_value_id); function.next_value_id += 1;
|
||||
out.push(I::Const { dst: f, value: ConstValue::Bool(false) });
|
||||
out.push(I::Compare { dst, op: CompareOp::Eq, lhs: operand, rhs: f });
|
||||
}
|
||||
super::UnaryOp::BitNot => {
|
||||
let all1 = super::ValueId::new(function.next_value_id); function.next_value_id += 1;
|
||||
out.push(I::Const { dst: all1, value: ConstValue::Integer(-1) });
|
||||
out.push(I::BinOp { dst, op: BinaryOp::BitXor, lhs: operand, rhs: all1 });
|
||||
}
|
||||
}
|
||||
stats.intrinsic_optimizations += 1;
|
||||
}
|
||||
other => out.push(other),
|
||||
}
|
||||
}
|
||||
block.instructions = out;
|
||||
if let Some(term) = block.terminator.take() {
|
||||
block.terminator = Some(match term {
|
||||
I::Load { dst, ptr } => {
|
||||
I::ExternCall { dst: Some(dst), iface_name: "env.local".to_string(), method_name: "get".to_string(), args: vec![ptr], effects: super::EffectMask::READ }
|
||||
}
|
||||
I::Store { value, ptr } => {
|
||||
I::ExternCall { dst: None, iface_name: "env.local".to_string(), method_name: "set".to_string(), args: vec![ptr, value], effects: super::EffectMask::WRITE }
|
||||
}
|
||||
I::NewBox { dst, box_type, mut args } => {
|
||||
let ty_id = super::ValueId::new(function.next_value_id);
|
||||
function.next_value_id += 1;
|
||||
block.instructions.push(I::Const { dst: ty_id, value: ConstValue::String(box_type) });
|
||||
let mut call_args = Vec::with_capacity(1 + args.len());
|
||||
call_args.push(ty_id);
|
||||
call_args.append(&mut args);
|
||||
I::ExternCall { dst: Some(dst), iface_name: "env.box".to_string(), method_name: "new".to_string(), args: call_args, effects: super::EffectMask::PURE }
|
||||
}
|
||||
I::UnaryOp { dst, op, operand } => {
|
||||
match op {
|
||||
super::UnaryOp::Neg => {
|
||||
let zero = super::ValueId::new(function.next_value_id); function.next_value_id += 1;
|
||||
block.instructions.push(I::Const { dst: zero, value: ConstValue::Integer(0) });
|
||||
I::BinOp { dst, op: BinaryOp::Sub, lhs: zero, rhs: operand }
|
||||
}
|
||||
super::UnaryOp::Not => {
|
||||
let f = super::ValueId::new(function.next_value_id); function.next_value_id += 1;
|
||||
block.instructions.push(I::Const { dst: f, value: ConstValue::Bool(false) });
|
||||
I::Compare { dst, op: CompareOp::Eq, lhs: operand, rhs: f }
|
||||
}
|
||||
super::UnaryOp::BitNot => {
|
||||
let all1 = super::ValueId::new(function.next_value_id); function.next_value_id += 1;
|
||||
block.instructions.push(I::Const { dst: all1, value: ConstValue::Integer(-1) });
|
||||
I::BinOp { dst, op: BinaryOp::BitXor, lhs: operand, rhs: all1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
other => other,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
stats
|
||||
}
|
||||
|
||||
/// Eliminate dead code in a single function
|
||||
fn eliminate_dead_code_in_function(&mut self, function: &mut MirFunction) -> usize {
|
||||
|
||||
Reference in New Issue
Block a user