2025-08-18 09:14:39 +00:00
|
|
|
/*!
|
|
|
|
|
* LLVM Compiler Implementation - Compile MIR to LLVM IR and native code
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
use crate::mir::function::MirModule;
|
2025-08-18 19:29:24 +09:00
|
|
|
use crate::mir::instruction::{MirInstruction, ConstValue, BinaryOp, UnaryOp, CompareOp};
|
|
|
|
|
use crate::mir::ValueId;
|
|
|
|
|
use crate::box_trait::{NyashBox, IntegerBox, FloatBox, StringBox, BoolBox, NullBox};
|
2025-08-18 09:14:39 +00:00
|
|
|
use super::context::CodegenContext;
|
2025-08-18 19:29:24 +09:00
|
|
|
use std::collections::HashMap;
|
2025-08-18 09:14:39 +00:00
|
|
|
|
2025-08-18 19:29:24 +09:00
|
|
|
/// Mock LLVM Compiler with MIR interpreter for demonstration
|
|
|
|
|
/// This simulates LLVM behavior by interpreting MIR instructions
|
2025-08-18 09:14:39 +00:00
|
|
|
pub struct LLVMCompiler {
|
2025-08-18 19:29:24 +09:00
|
|
|
/// Values stored during mock execution
|
|
|
|
|
values: HashMap<ValueId, Box<dyn NyashBox>>,
|
2025-08-18 09:14:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LLVMCompiler {
|
|
|
|
|
pub fn new() -> Result<Self, String> {
|
2025-08-18 09:25:57 +00:00
|
|
|
Ok(Self {
|
2025-08-18 19:29:24 +09:00
|
|
|
values: HashMap::new(),
|
2025-08-18 09:25:57 +00:00
|
|
|
})
|
2025-08-18 09:14:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn compile_module(
|
|
|
|
|
&self,
|
|
|
|
|
mir_module: &MirModule,
|
|
|
|
|
output_path: &str,
|
|
|
|
|
) -> Result<(), String> {
|
2025-08-18 09:25:57 +00:00
|
|
|
// Mock implementation - in a real scenario this would:
|
|
|
|
|
// 1. Create LLVM context and module
|
|
|
|
|
// 2. Convert MIR instructions to LLVM IR
|
|
|
|
|
// 3. Generate object file
|
|
|
|
|
|
|
|
|
|
println!("🔧 Mock LLVM Compilation:");
|
|
|
|
|
println!(" Module: {}", mir_module.name);
|
|
|
|
|
println!(" Functions: {}", mir_module.functions.len());
|
|
|
|
|
println!(" Output: {}", output_path);
|
|
|
|
|
|
|
|
|
|
// Find main function
|
|
|
|
|
let main_func = mir_module.functions.get("Main.main")
|
|
|
|
|
.ok_or("Main.main function not found")?;
|
2025-08-18 09:14:39 +00:00
|
|
|
|
2025-08-18 09:25:57 +00:00
|
|
|
println!(" Main function found with {} blocks", main_func.blocks.len());
|
|
|
|
|
|
|
|
|
|
// Simulate object file generation
|
|
|
|
|
std::fs::write(output_path, b"Mock object file")?;
|
|
|
|
|
println!(" ✅ Mock object file created");
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn compile_and_execute(
|
2025-08-18 19:29:24 +09:00
|
|
|
&mut self,
|
2025-08-18 09:25:57 +00:00
|
|
|
mir_module: &MirModule,
|
|
|
|
|
temp_path: &str,
|
|
|
|
|
) -> Result<Box<dyn NyashBox>, String> {
|
2025-08-18 19:29:24 +09:00
|
|
|
// Mock implementation - interprets MIR instructions to simulate execution
|
2025-08-18 09:25:57 +00:00
|
|
|
|
2025-08-18 19:29:24 +09:00
|
|
|
println!("🚀 Mock LLVM Compile & Execute (MIR Interpreter Mode):");
|
2025-08-18 09:25:57 +00:00
|
|
|
|
|
|
|
|
// 1. Mock object file generation
|
|
|
|
|
let obj_path = format!("{}.o", temp_path);
|
|
|
|
|
self.compile_module(mir_module, &obj_path)?;
|
|
|
|
|
|
2025-08-18 19:29:24 +09:00
|
|
|
// 2. Find and execute main function
|
|
|
|
|
let main_func = mir_module.functions.get("Main.main")
|
|
|
|
|
.ok_or("Main.main function not found")?;
|
|
|
|
|
|
|
|
|
|
println!(" ⚡ Interpreting MIR instructions...");
|
2025-08-18 09:25:57 +00:00
|
|
|
|
2025-08-18 19:29:24 +09:00
|
|
|
// 3. Execute MIR instructions
|
|
|
|
|
let result = self.interpret_function(main_func)?;
|
2025-08-18 09:25:57 +00:00
|
|
|
|
2025-08-18 19:29:24 +09:00
|
|
|
// 4. Cleanup mock files
|
|
|
|
|
let _ = std::fs::remove_file(&obj_path);
|
|
|
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Interpret a MIR function by executing its instructions
|
|
|
|
|
fn interpret_function(
|
|
|
|
|
&mut self,
|
|
|
|
|
func: &crate::mir::function::MirFunction,
|
|
|
|
|
) -> Result<Box<dyn NyashBox>, String> {
|
|
|
|
|
// Clear value storage
|
|
|
|
|
self.values.clear();
|
|
|
|
|
|
|
|
|
|
// For now, just execute the entry block
|
|
|
|
|
if let Some(entry_block) = func.blocks.get(&0) {
|
|
|
|
|
for inst in &entry_block.instructions {
|
|
|
|
|
match inst {
|
|
|
|
|
MirInstruction::Const { dst, value } => {
|
|
|
|
|
let nyash_value = match value {
|
|
|
|
|
ConstValue::Integer(i) => Box::new(IntegerBox::new(*i)) as Box<dyn NyashBox>,
|
|
|
|
|
ConstValue::Float(f) => Box::new(FloatBox::new(*f)) as Box<dyn NyashBox>,
|
|
|
|
|
ConstValue::String(s) => Box::new(StringBox::new(s.clone())) as Box<dyn NyashBox>,
|
|
|
|
|
ConstValue::Bool(b) => Box::new(BoolBox::new(*b)) as Box<dyn NyashBox>,
|
|
|
|
|
ConstValue::Null => Box::new(NullBox::new()) as Box<dyn NyashBox>,
|
|
|
|
|
};
|
|
|
|
|
self.values.insert(*dst, nyash_value);
|
|
|
|
|
println!(" 📝 %{} = const {:?}", dst.0, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MirInstruction::BinOp { dst, op, lhs, rhs } => {
|
|
|
|
|
// Get operands
|
|
|
|
|
let left = self.values.get(lhs)
|
|
|
|
|
.ok_or_else(|| format!("Value %{} not found", lhs.0))?;
|
|
|
|
|
let right = self.values.get(rhs)
|
|
|
|
|
.ok_or_else(|| format!("Value %{} not found", rhs.0))?;
|
|
|
|
|
|
|
|
|
|
// Simple integer arithmetic for now
|
|
|
|
|
if let (Some(l), Some(r)) = (left.as_any().downcast_ref::<IntegerBox>(),
|
|
|
|
|
right.as_any().downcast_ref::<IntegerBox>()) {
|
|
|
|
|
let result = match op {
|
|
|
|
|
BinaryOp::Add => l.value() + r.value(),
|
|
|
|
|
BinaryOp::Sub => l.value() - r.value(),
|
|
|
|
|
BinaryOp::Mul => l.value() * r.value(),
|
|
|
|
|
BinaryOp::Div => {
|
|
|
|
|
if r.value() == 0 {
|
|
|
|
|
return Err("Division by zero".to_string());
|
|
|
|
|
}
|
|
|
|
|
l.value() / r.value()
|
|
|
|
|
}
|
|
|
|
|
BinaryOp::Mod => l.value() % r.value(),
|
|
|
|
|
};
|
|
|
|
|
self.values.insert(*dst, Box::new(IntegerBox::new(result)));
|
|
|
|
|
println!(" 📊 %{} = %{} {:?} %{} = {}", dst.0, lhs.0, op, rhs.0, result);
|
|
|
|
|
} else {
|
|
|
|
|
return Err("Binary operation on non-integer values not supported in mock".to_string());
|
2025-08-18 09:14:39 +00:00
|
|
|
}
|
2025-08-18 19:29:24 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MirInstruction::Return { value } => {
|
|
|
|
|
if let Some(val_id) = value {
|
|
|
|
|
let result = self.values.get(val_id)
|
|
|
|
|
.ok_or_else(|| format!("Return value %{} not found", val_id.0))?
|
|
|
|
|
.clone_box();
|
|
|
|
|
println!(" ✅ Returning value from %{}", val_id.0);
|
|
|
|
|
return Ok(result);
|
|
|
|
|
} else {
|
|
|
|
|
println!(" ✅ Void return");
|
2025-08-18 09:25:57 +00:00
|
|
|
return Ok(Box::new(IntegerBox::new(0)));
|
2025-08-18 09:14:39 +00:00
|
|
|
}
|
2025-08-18 19:29:24 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ => {
|
|
|
|
|
// Other instructions not yet implemented
|
|
|
|
|
println!(" ⚠️ Skipping instruction: {:?}", inst);
|
2025-08-18 09:14:39 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-18 09:25:57 +00:00
|
|
|
|
2025-08-18 19:29:24 +09:00
|
|
|
// Default return
|
2025-08-18 09:25:57 +00:00
|
|
|
Ok(Box::new(IntegerBox::new(0)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The real implementation would look like this with proper LLVM libraries:
|
|
|
|
|
/*
|
|
|
|
|
#[cfg(feature = "llvm")]
|
|
|
|
|
use inkwell::context::Context;
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "llvm")]
|
|
|
|
|
pub struct LLVMCompiler {
|
|
|
|
|
context: Context,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "llvm")]
|
|
|
|
|
impl LLVMCompiler {
|
|
|
|
|
pub fn new() -> Result<Self, String> {
|
|
|
|
|
Ok(Self {
|
|
|
|
|
context: Context::create(),
|
|
|
|
|
})
|
2025-08-18 09:14:39 +00:00
|
|
|
}
|
|
|
|
|
|
2025-08-18 09:25:57 +00:00
|
|
|
pub fn compile_module(
|
2025-08-18 09:14:39 +00:00
|
|
|
&self,
|
|
|
|
|
mir_module: &MirModule,
|
2025-08-18 09:25:57 +00:00
|
|
|
output_path: &str,
|
|
|
|
|
) -> Result<(), String> {
|
|
|
|
|
let codegen = CodegenContext::new(&self.context, "nyash_module")?;
|
|
|
|
|
|
|
|
|
|
// 1. main関数を探す
|
|
|
|
|
let main_func = mir_module.functions.get("Main.main")
|
|
|
|
|
.ok_or("Main.main function not found")?;
|
|
|
|
|
|
|
|
|
|
// 2. LLVM関数を作成
|
|
|
|
|
let i32_type = codegen.context.i32_type();
|
|
|
|
|
let fn_type = i32_type.fn_type(&[], false);
|
|
|
|
|
let llvm_func = codegen.module.add_function("main", fn_type, None);
|
|
|
|
|
|
|
|
|
|
// 3. エントリブロックを作成
|
|
|
|
|
let entry = codegen.context.append_basic_block(llvm_func, "entry");
|
|
|
|
|
codegen.builder.position_at_end(entry);
|
|
|
|
|
|
|
|
|
|
// 4. MIR命令を処理
|
|
|
|
|
for (_block_id, block) in &main_func.blocks {
|
|
|
|
|
for inst in &block.instructions {
|
|
|
|
|
match inst {
|
|
|
|
|
MirInstruction::Return { value: Some(_value_id) } => {
|
|
|
|
|
let ret_val = i32_type.const_int(42, false);
|
|
|
|
|
codegen.builder.build_return(Some(&ret_val)).unwrap();
|
|
|
|
|
}
|
|
|
|
|
MirInstruction::Return { value: None } => {
|
|
|
|
|
let ret_val = i32_type.const_int(0, false);
|
|
|
|
|
codegen.builder.build_return(Some(&ret_val)).unwrap();
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
// 他の命令は今回スキップ
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-18 09:14:39 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-08-18 09:25:57 +00:00
|
|
|
|
|
|
|
|
// 5. 検証
|
|
|
|
|
if !llvm_func.verify(true) {
|
|
|
|
|
return Err("Function verification failed".to_string());
|
2025-08-18 09:14:39 +00:00
|
|
|
}
|
2025-08-18 09:25:57 +00:00
|
|
|
|
|
|
|
|
// 6. オブジェクトファイル生成
|
|
|
|
|
codegen.target_machine
|
|
|
|
|
.write_to_file(&codegen.module,
|
|
|
|
|
inkwell::targets::FileType::Object,
|
|
|
|
|
output_path.as_ref())
|
|
|
|
|
.map_err(|e| format!("Failed to write object file: {}", e))?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
2025-08-18 09:14:39 +00:00
|
|
|
}
|
2025-08-18 09:25:57 +00:00
|
|
|
|
|
|
|
|
// ... rest of implementation
|
2025-08-18 09:14:39 +00:00
|
|
|
}
|
2025-08-18 09:25:57 +00:00
|
|
|
*/
|
2025-08-18 09:14:39 +00:00
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_compiler_creation() {
|
2025-08-18 09:25:57 +00:00
|
|
|
let compiler = LLVMCompiler::new();
|
|
|
|
|
assert!(compiler.is_ok());
|
2025-08-18 09:14:39 +00:00
|
|
|
}
|
|
|
|
|
}
|