Make the compiler produce .o/.asm/.ll according to input file name
This commit is contained in:
parent
5b5ec48b8d
commit
bcad9b57fe
5
.gitignore
vendored
5
.gitignore
vendored
@ -4,4 +4,7 @@ src/old_llvm
|
||||
/.vscode
|
||||
.env
|
||||
hello.*
|
||||
main
|
||||
main
|
||||
reid_src/*.o
|
||||
reid_src/*.ll
|
||||
reid_src/*.asm
|
||||
|
@ -2,7 +2,7 @@
|
||||
//! LLIR ([`Context`]) into LLVM IR. This module is the only one that interfaces
|
||||
//! with the LLVM API.
|
||||
|
||||
use std::{collections::HashMap, ffi::CString, ptr::null_mut};
|
||||
use std::{collections::HashMap, ptr::null_mut};
|
||||
|
||||
use llvm_sys::{
|
||||
LLVMIntPredicate, LLVMLinkage,
|
||||
@ -16,11 +16,11 @@ use llvm_sys::{
|
||||
},
|
||||
target_machine::{
|
||||
LLVMCodeGenFileType, LLVMCreateTargetDataLayout, LLVMCreateTargetMachine,
|
||||
LLVMGetDefaultTargetTriple, LLVMGetTargetFromTriple, LLVMTargetMachineEmitToFile,
|
||||
LLVMGetDefaultTargetTriple, LLVMGetTargetFromTriple, LLVMTargetMachineEmitToMemoryBuffer,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::util::{ErrorMessageHolder, from_cstring, into_cstring};
|
||||
use crate::util::{ErrorMessageHolder, MemoryBufferHolder, from_cstring, into_cstring};
|
||||
|
||||
use super::{
|
||||
CmpPredicate, ConstValue, Context, TerminatorKind, Type,
|
||||
@ -49,8 +49,15 @@ pub struct CompiledModule {
|
||||
_context: LLVMContext,
|
||||
}
|
||||
|
||||
pub struct CompileOutput {
|
||||
pub triple: String,
|
||||
pub assembly: String,
|
||||
pub obj_buffer: Vec<u8>,
|
||||
pub llvm_ir: String,
|
||||
}
|
||||
|
||||
impl CompiledModule {
|
||||
pub fn output(&self) {
|
||||
pub fn output(&self) -> CompileOutput {
|
||||
unsafe {
|
||||
LLVM_InitializeAllTargets();
|
||||
LLVM_InitializeAllTargetInfos();
|
||||
@ -63,7 +70,6 @@ impl CompiledModule {
|
||||
let mut target: _ = null_mut();
|
||||
let mut err = ErrorMessageHolder::null();
|
||||
LLVMGetTargetFromTriple(triple, &mut target, err.borrow_mut());
|
||||
println!("{:?}, {:?}", from_cstring(triple), target);
|
||||
err.into_result().unwrap();
|
||||
|
||||
let target_machine = LLVMCreateTargetMachine(
|
||||
@ -88,28 +94,37 @@ impl CompiledModule {
|
||||
);
|
||||
err.into_result().unwrap();
|
||||
|
||||
let mut asm_buffer = MemoryBufferHolder::empty("asm");
|
||||
let mut err = ErrorMessageHolder::null();
|
||||
LLVMTargetMachineEmitToFile(
|
||||
LLVMTargetMachineEmitToMemoryBuffer(
|
||||
target_machine,
|
||||
self.module_ref,
|
||||
CString::new("hello.asm").unwrap().into_raw(),
|
||||
LLVMCodeGenFileType::LLVMAssemblyFile,
|
||||
err.borrow_mut(),
|
||||
&mut asm_buffer.buffer,
|
||||
);
|
||||
err.into_result().unwrap();
|
||||
|
||||
let mut obj_buffer = MemoryBufferHolder::empty("obj");
|
||||
let mut err = ErrorMessageHolder::null();
|
||||
LLVMTargetMachineEmitToFile(
|
||||
LLVMTargetMachineEmitToMemoryBuffer(
|
||||
target_machine,
|
||||
self.module_ref,
|
||||
CString::new("hello.o").unwrap().into_raw(),
|
||||
LLVMCodeGenFileType::LLVMObjectFile,
|
||||
err.borrow_mut(),
|
||||
&mut obj_buffer.buffer,
|
||||
);
|
||||
err.into_result().unwrap();
|
||||
|
||||
let module_str = from_cstring(LLVMPrintModuleToString(self.module_ref));
|
||||
println!("{}", module_str.unwrap());
|
||||
CompileOutput {
|
||||
triple: from_cstring(triple).expect("Unable to convert triple from cstring"),
|
||||
assembly: asm_buffer
|
||||
.as_string()
|
||||
.expect("Error while converting assembly-buffer to string"),
|
||||
obj_buffer: obj_buffer.as_buffer(),
|
||||
llvm_ir: from_cstring(LLVMPrintModuleToString(self.module_ref))
|
||||
.expect("Unable to print LLVM IR to string"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,17 @@
|
||||
use std::{
|
||||
ffi::{CStr, CString, c_char},
|
||||
ptr::null_mut,
|
||||
string::FromUtf8Error,
|
||||
};
|
||||
|
||||
use llvm_sys::error::LLVMDisposeErrorMessage;
|
||||
use llvm_sys::{
|
||||
core::{
|
||||
LLVMCreateMemoryBufferWithMemoryRange, LLVMDisposeMemoryBuffer, LLVMGetBufferSize,
|
||||
LLVMGetBufferStart,
|
||||
},
|
||||
error::LLVMDisposeErrorMessage,
|
||||
prelude::LLVMMemoryBufferRef,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Type,
|
||||
@ -57,6 +65,52 @@ impl Drop for ErrorMessageHolder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Utility for creating and handling LLVM MemoryBuffers, needed for printing
|
||||
/// out ASM and .o -files without relying on LLVM's own API.
|
||||
pub struct MemoryBufferHolder {
|
||||
pub buffer: LLVMMemoryBufferRef,
|
||||
}
|
||||
|
||||
impl MemoryBufferHolder {
|
||||
pub fn empty(name: &str) -> MemoryBufferHolder {
|
||||
let array = [0i8; 0];
|
||||
unsafe {
|
||||
let buffer = LLVMCreateMemoryBufferWithMemoryRange(
|
||||
array.as_ptr(),
|
||||
array.len(),
|
||||
into_cstring(name).as_ptr(),
|
||||
0,
|
||||
);
|
||||
MemoryBufferHolder { buffer }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_buffer(&self) -> Vec<u8> {
|
||||
unsafe {
|
||||
let start = LLVMGetBufferStart(self.buffer);
|
||||
let size = LLVMGetBufferSize(self.buffer);
|
||||
|
||||
let mut buff = Vec::with_capacity(size);
|
||||
for i in 0..size {
|
||||
buff.push(*start.add(i) as u8);
|
||||
}
|
||||
buff
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_string(&self) -> Result<String, FromUtf8Error> {
|
||||
String::from_utf8(self.as_buffer())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MemoryBufferHolder {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
LLVMDisposeMemoryBuffer(self.buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure types for given instructions match. Return Ok(type) if they do,
|
||||
/// and error otherwise.
|
||||
pub fn match_types(
|
||||
|
@ -1,18 +1,37 @@
|
||||
use std::{env, fs, path::PathBuf};
|
||||
|
||||
use reid::compile;
|
||||
use reid_lib::compile::CompileOutput;
|
||||
|
||||
fn main() -> Result<(), std::io::Error> {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if let Some(filename) = args.get(1) {
|
||||
let path = PathBuf::from(filename);
|
||||
let path = PathBuf::from(filename).canonicalize().unwrap();
|
||||
let parent = path.with_extension("");
|
||||
let llvm_ir_path = parent.with_extension("ll");
|
||||
let object_path = parent.with_extension("o");
|
||||
let asm_path = parent.with_extension("asm");
|
||||
|
||||
let text = fs::read_to_string(&path)?;
|
||||
let output = match compile(&text, PathBuf::from(path)) {
|
||||
Ok(t) => t,
|
||||
match compile(&text, PathBuf::from(&path)) {
|
||||
Ok(CompileOutput {
|
||||
triple,
|
||||
assembly,
|
||||
obj_buffer,
|
||||
llvm_ir,
|
||||
}) => {
|
||||
println!("Compiled with triple: {}", &triple);
|
||||
fs::write(&llvm_ir_path, &llvm_ir).expect("Could not write LLVM IR -file!");
|
||||
println!("Output LLVM IR to {:?}", llvm_ir_path);
|
||||
fs::write(&asm_path, &assembly).expect("Could not write Assembly-file!");
|
||||
println!("Output Assembly to {:?}", asm_path);
|
||||
fs::write(&object_path, &obj_buffer).expect("Could not write Object-file!");
|
||||
println!("Output Object-file to {:?}", object_path);
|
||||
|
||||
println!("{}", llvm_ir);
|
||||
}
|
||||
Err(e) => panic!("{}", e),
|
||||
};
|
||||
println!("{}", output);
|
||||
} else {
|
||||
println!("Please input compiled file path!")
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ use std::path::PathBuf;
|
||||
use mir::{
|
||||
linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs,
|
||||
};
|
||||
use reid_lib::Context;
|
||||
use reid_lib::{compile::CompileOutput, Context};
|
||||
|
||||
use crate::{ast::TopLevelStatement, lexer::Token, token_stream::TokenStream};
|
||||
|
||||
@ -145,7 +145,7 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> {
|
||||
/// Takes in a bit of source code, parses and compiles it and produces `hello.o`
|
||||
/// and `hello.asm` from it, which can be linked using `ld` to produce an
|
||||
/// executable file.
|
||||
pub fn compile(source: &str, path: PathBuf) -> Result<String, ReidError> {
|
||||
pub fn compile(source: &str, path: PathBuf) -> Result<CompileOutput, ReidError> {
|
||||
let path = path.canonicalize().unwrap();
|
||||
|
||||
let mut mir_context = mir::Context::from(
|
||||
@ -167,7 +167,5 @@ pub fn compile(source: &str, path: PathBuf) -> Result<String, ReidError> {
|
||||
dbg!(&codegen_modules);
|
||||
|
||||
let compiled = codegen_modules.compile();
|
||||
compiled.output();
|
||||
|
||||
Ok(String::new())
|
||||
Ok(compiled.output())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user