Compare commits
2 Commits
5b5ec48b8d
...
29200bd4ef
Author | SHA1 | Date | |
---|---|---|---|
29200bd4ef | |||
bcad9b57fe |
4
.gitignore
vendored
4
.gitignore
vendored
@ -5,3 +5,7 @@ src/old_llvm
|
|||||||
.env
|
.env
|
||||||
hello.*
|
hello.*
|
||||||
main
|
main
|
||||||
|
reid_src/*.o
|
||||||
|
reid_src/*.ll
|
||||||
|
reid_src/*.asm
|
||||||
|
reid_src/*.out
|
||||||
|
17
Makefile
Normal file
17
Makefile
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
SRC=foo.reid
|
||||||
|
BIN=$(SRC:.reid=.out)
|
||||||
|
|
||||||
|
REID=cargo run --example cli
|
||||||
|
LD=ld
|
||||||
|
LDFLAGS=
|
||||||
|
|
||||||
|
all: $(BIN)
|
||||||
|
clean:
|
||||||
|
rm -f $(BIN) $(SRC:.reid=.o) $(SRC:.reid=.asm) $(SRC:.reid=.ll)
|
||||||
|
|
||||||
|
$(BIN): $(SRC:.reid=.o)
|
||||||
|
$(LD) -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/crt1.o -lc $(LDFLAGS) $< -o$@
|
||||||
|
|
||||||
|
.SUFFIXES: .o .reid
|
||||||
|
.reid.o:
|
||||||
|
$(REID) $<
|
16
libtest.sh
16
libtest.sh
@ -5,13 +5,17 @@
|
|||||||
#
|
#
|
||||||
# Do note this file is extremely simply for my own personal convenience
|
# Do note this file is extremely simply for my own personal convenience
|
||||||
|
|
||||||
export .env
|
# export .env
|
||||||
cargo run --release --example cli $1 && \
|
# cargo run --release --example cli $1 && \
|
||||||
# clang hello.o -o main && \
|
# # clang hello.o -o main && \
|
||||||
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
|
# ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
|
||||||
-o main /usr/lib/crt1.o hello.o -lc && \
|
# -o main /usr/lib/crt1.o hello.o -lc && \
|
||||||
./main ; echo "Return value: ""$?"
|
# ./main ; echo "Return value: ""$?"
|
||||||
|
|
||||||
|
$BINARY="$($1 | cut -d'.' -f1)"".out"
|
||||||
|
|
||||||
|
make clean SRC=$1 && make SRC=$1 && echo "" && \
|
||||||
|
$BINARY ; echo "Return value: ""$?"
|
||||||
|
|
||||||
## Command from: clang -v hello.o -o test
|
## Command from: clang -v hello.o -o test
|
||||||
## Original command:
|
## Original command:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//! LLIR ([`Context`]) into LLVM IR. This module is the only one that interfaces
|
//! LLIR ([`Context`]) into LLVM IR. This module is the only one that interfaces
|
||||||
//! with the LLVM API.
|
//! with the LLVM API.
|
||||||
|
|
||||||
use std::{collections::HashMap, ffi::CString, ptr::null_mut};
|
use std::{collections::HashMap, ptr::null_mut};
|
||||||
|
|
||||||
use llvm_sys::{
|
use llvm_sys::{
|
||||||
LLVMIntPredicate, LLVMLinkage,
|
LLVMIntPredicate, LLVMLinkage,
|
||||||
@ -16,11 +16,11 @@ use llvm_sys::{
|
|||||||
},
|
},
|
||||||
target_machine::{
|
target_machine::{
|
||||||
LLVMCodeGenFileType, LLVMCreateTargetDataLayout, LLVMCreateTargetMachine,
|
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::{
|
use super::{
|
||||||
CmpPredicate, ConstValue, Context, TerminatorKind, Type,
|
CmpPredicate, ConstValue, Context, TerminatorKind, Type,
|
||||||
@ -49,8 +49,15 @@ pub struct CompiledModule {
|
|||||||
_context: LLVMContext,
|
_context: LLVMContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CompileOutput {
|
||||||
|
pub triple: String,
|
||||||
|
pub assembly: String,
|
||||||
|
pub obj_buffer: Vec<u8>,
|
||||||
|
pub llvm_ir: String,
|
||||||
|
}
|
||||||
|
|
||||||
impl CompiledModule {
|
impl CompiledModule {
|
||||||
pub fn output(&self) {
|
pub fn output(&self) -> CompileOutput {
|
||||||
unsafe {
|
unsafe {
|
||||||
LLVM_InitializeAllTargets();
|
LLVM_InitializeAllTargets();
|
||||||
LLVM_InitializeAllTargetInfos();
|
LLVM_InitializeAllTargetInfos();
|
||||||
@ -63,7 +70,6 @@ impl CompiledModule {
|
|||||||
let mut target: _ = null_mut();
|
let mut target: _ = null_mut();
|
||||||
let mut err = ErrorMessageHolder::null();
|
let mut err = ErrorMessageHolder::null();
|
||||||
LLVMGetTargetFromTriple(triple, &mut target, err.borrow_mut());
|
LLVMGetTargetFromTriple(triple, &mut target, err.borrow_mut());
|
||||||
println!("{:?}, {:?}", from_cstring(triple), target);
|
|
||||||
err.into_result().unwrap();
|
err.into_result().unwrap();
|
||||||
|
|
||||||
let target_machine = LLVMCreateTargetMachine(
|
let target_machine = LLVMCreateTargetMachine(
|
||||||
@ -88,28 +94,37 @@ impl CompiledModule {
|
|||||||
);
|
);
|
||||||
err.into_result().unwrap();
|
err.into_result().unwrap();
|
||||||
|
|
||||||
|
let mut asm_buffer = MemoryBufferHolder::empty("asm");
|
||||||
let mut err = ErrorMessageHolder::null();
|
let mut err = ErrorMessageHolder::null();
|
||||||
LLVMTargetMachineEmitToFile(
|
LLVMTargetMachineEmitToMemoryBuffer(
|
||||||
target_machine,
|
target_machine,
|
||||||
self.module_ref,
|
self.module_ref,
|
||||||
CString::new("hello.asm").unwrap().into_raw(),
|
|
||||||
LLVMCodeGenFileType::LLVMAssemblyFile,
|
LLVMCodeGenFileType::LLVMAssemblyFile,
|
||||||
err.borrow_mut(),
|
err.borrow_mut(),
|
||||||
|
&mut asm_buffer.buffer,
|
||||||
);
|
);
|
||||||
err.into_result().unwrap();
|
err.into_result().unwrap();
|
||||||
|
|
||||||
|
let mut obj_buffer = MemoryBufferHolder::empty("obj");
|
||||||
let mut err = ErrorMessageHolder::null();
|
let mut err = ErrorMessageHolder::null();
|
||||||
LLVMTargetMachineEmitToFile(
|
LLVMTargetMachineEmitToMemoryBuffer(
|
||||||
target_machine,
|
target_machine,
|
||||||
self.module_ref,
|
self.module_ref,
|
||||||
CString::new("hello.o").unwrap().into_raw(),
|
|
||||||
LLVMCodeGenFileType::LLVMObjectFile,
|
LLVMCodeGenFileType::LLVMObjectFile,
|
||||||
err.borrow_mut(),
|
err.borrow_mut(),
|
||||||
|
&mut obj_buffer.buffer,
|
||||||
);
|
);
|
||||||
err.into_result().unwrap();
|
err.into_result().unwrap();
|
||||||
|
|
||||||
let module_str = from_cstring(LLVMPrintModuleToString(self.module_ref));
|
CompileOutput {
|
||||||
println!("{}", module_str.unwrap());
|
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::{
|
use std::{
|
||||||
ffi::{CStr, CString, c_char},
|
ffi::{CStr, CString, c_char},
|
||||||
ptr::null_mut,
|
ptr::null_mut,
|
||||||
|
string::FromUtf8Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
use llvm_sys::error::LLVMDisposeErrorMessage;
|
use llvm_sys::{
|
||||||
|
core::{
|
||||||
|
LLVMCreateMemoryBufferWithMemoryRange, LLVMDisposeMemoryBuffer, LLVMGetBufferSize,
|
||||||
|
LLVMGetBufferStart,
|
||||||
|
},
|
||||||
|
error::LLVMDisposeErrorMessage,
|
||||||
|
prelude::LLVMMemoryBufferRef,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Type,
|
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,
|
/// Make sure types for given instructions match. Return Ok(type) if they do,
|
||||||
/// and error otherwise.
|
/// and error otherwise.
|
||||||
pub fn match_types(
|
pub fn match_types(
|
||||||
|
@ -1,18 +1,37 @@
|
|||||||
use std::{env, fs, path::PathBuf};
|
use std::{env, fs, path::PathBuf};
|
||||||
|
|
||||||
use reid::compile;
|
use reid::compile;
|
||||||
|
use reid_lib::compile::CompileOutput;
|
||||||
|
|
||||||
fn main() -> Result<(), std::io::Error> {
|
fn main() -> Result<(), std::io::Error> {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if let Some(filename) = args.get(1) {
|
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 text = fs::read_to_string(&path)?;
|
||||||
let output = match compile(&text, PathBuf::from(path)) {
|
match compile(&text, PathBuf::from(&path)) {
|
||||||
Ok(t) => t,
|
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),
|
Err(e) => panic!("{}", e),
|
||||||
};
|
};
|
||||||
println!("{}", output);
|
|
||||||
} else {
|
} else {
|
||||||
println!("Please input compiled file path!")
|
println!("Please input compiled file path!")
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ use std::path::PathBuf;
|
|||||||
use mir::{
|
use mir::{
|
||||||
linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs,
|
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};
|
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`
|
/// 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
|
/// and `hello.asm` from it, which can be linked using `ld` to produce an
|
||||||
/// executable file.
|
/// 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 path = path.canonicalize().unwrap();
|
||||||
|
|
||||||
let mut mir_context = mir::Context::from(
|
let mut mir_context = mir::Context::from(
|
||||||
@ -167,7 +167,5 @@ pub fn compile(source: &str, path: PathBuf) -> Result<String, ReidError> {
|
|||||||
dbg!(&codegen_modules);
|
dbg!(&codegen_modules);
|
||||||
|
|
||||||
let compiled = codegen_modules.compile();
|
let compiled = codegen_modules.compile();
|
||||||
compiled.output();
|
Ok(compiled.output())
|
||||||
|
|
||||||
Ok(String::new())
|
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,9 @@ impl IndexedVariableReference {
|
|||||||
}
|
}
|
||||||
super::IndexedVariableReferenceKind::Index(inner, _) => {
|
super::IndexedVariableReferenceKind::Index(inner, _) => {
|
||||||
if let Some((mutable, inner_ref)) = inner.find_hint(hints)? {
|
if let Some((mutable, inner_ref)) = inner.find_hint(hints)? {
|
||||||
let inner_ty = inner_ref.as_type();
|
// Check that the resolved type is at least an array, no
|
||||||
|
// need for further resolution.
|
||||||
|
let inner_ty = inner_ref.resolve_weak().unwrap();
|
||||||
match inner_ty {
|
match inner_ty {
|
||||||
Array(type_kind, _) => Ok(hints
|
Array(type_kind, _) => Ok(hints
|
||||||
.from_type(&type_kind)
|
.from_type(&type_kind)
|
||||||
@ -284,7 +286,9 @@ impl Expression {
|
|||||||
ExprKind::Index(expression, index_ty, _) => {
|
ExprKind::Index(expression, index_ty, _) => {
|
||||||
let expr_ty = expression.infer_types(state, type_refs)?;
|
let expr_ty = expression.infer_types(state, type_refs)?;
|
||||||
|
|
||||||
let kind = unsafe { expr_ty.resolve_type() };
|
// Check that the resolved type is at least an array, no
|
||||||
|
// need for further resolution.
|
||||||
|
let kind = expr_ty.resolve_weak().unwrap();
|
||||||
match kind {
|
match kind {
|
||||||
Array(type_kind, _) => {
|
Array(type_kind, _) => {
|
||||||
let elem_ty = type_refs.from_type(&type_kind).unwrap();
|
let elem_ty = type_refs.from_type(&type_kind).unwrap();
|
||||||
|
@ -15,23 +15,22 @@ use super::{
|
|||||||
pub struct TypeRef<'scope>(TypeIdRef, &'scope ScopeTypeRefs<'scope>);
|
pub struct TypeRef<'scope>(TypeIdRef, &'scope ScopeTypeRefs<'scope>);
|
||||||
|
|
||||||
impl<'scope> TypeRef<'scope> {
|
impl<'scope> TypeRef<'scope> {
|
||||||
pub unsafe fn resolve_type(&self) -> TypeKind {
|
/// Resolve current type in a weak manner, not resolving any Arrays or
|
||||||
unsafe {
|
/// further inner types
|
||||||
let resolved = self
|
pub fn resolve_weak(&self) -> Option<TypeKind> {
|
||||||
.1
|
Some(self.1.types.retrieve_type(*self.0.borrow())?)
|
||||||
.types
|
}
|
||||||
.hints
|
|
||||||
.borrow()
|
|
||||||
.get_unchecked(*self.0.borrow())
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
match resolved {
|
/// Resolve type deeply, trying to resolve any inner types as well.
|
||||||
TypeKind::Array(elem_ty, len) => {
|
pub fn resolve_deep(&self) -> Option<TypeKind> {
|
||||||
let resolved_elem_ty = self.1.from_type(&elem_ty).unwrap().resolve_type();
|
let resolved = self.resolve_weak()?;
|
||||||
TypeKind::Array(Box::new(resolved_elem_ty), len)
|
|
||||||
}
|
match resolved {
|
||||||
_ => resolved,
|
TypeKind::Array(elem_ty, len) => {
|
||||||
|
let resolved_elem_ty = self.1.from_type(&elem_ty).unwrap().resolve_weak()?;
|
||||||
|
Some(TypeKind::Array(Box::new(resolved_elem_ty), len))
|
||||||
}
|
}
|
||||||
|
_ => Some(resolved),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +47,7 @@ impl<'scope> std::fmt::Debug for TypeRef<'scope> {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_tuple("Hint")
|
f.debug_tuple("Hint")
|
||||||
.field(&self.0)
|
.field(&self.0)
|
||||||
.field(unsafe { &self.resolve_type() })
|
.field(&self.resolve_deep().unwrap())
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
reid_src/array
Executable file
BIN
reid_src/array
Executable file
Binary file not shown.
38
test.ll
38
test.ll
@ -1,38 +0,0 @@
|
|||||||
; ModuleID = 'test'
|
|
||||||
source_filename = "test"
|
|
||||||
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
|
||||||
target triple = "x86_64-unknown-linux-gnu"
|
|
||||||
|
|
||||||
define ptr @array() {
|
|
||||||
array:
|
|
||||||
%array_alloca = alloca i16, i16 4, align 2
|
|
||||||
%array_gep = getelementptr i16, ptr %array_alloca, i32 0
|
|
||||||
store i16 10, ptr %array_gep, align 2
|
|
||||||
%array_gep1 = getelementptr i16, ptr %array_alloca, i32 1
|
|
||||||
store i16 15, ptr %array_gep1, align 2
|
|
||||||
%array_gep2 = getelementptr i16, ptr %array_alloca, i32 2
|
|
||||||
store i16 7, ptr %array_gep2, align 2
|
|
||||||
%array_gep3 = getelementptr i16, ptr %array_alloca, i32 3
|
|
||||||
store i16 9, ptr %array_gep3, align 2
|
|
||||||
|
|
||||||
%array_alloca4 = alloca ptr, i16 1, align 8
|
|
||||||
%array_gep5 = getelementptr ptr, ptr %array_alloca4, i32 0
|
|
||||||
store ptr %array_alloca, ptr %array_gep5, align 8
|
|
||||||
ret ptr %array_alloca4
|
|
||||||
}
|
|
||||||
|
|
||||||
define i16 @main() {
|
|
||||||
main:
|
|
||||||
%call = call ptr @array()
|
|
||||||
%array_gep = getelementptr ptr, ptr %call, i32 0
|
|
||||||
%load5 = load ptr, ptr %array_gep2, align 8
|
|
||||||
%array_gep1 = getelementptr i16, ptr %load5, i32 3
|
|
||||||
store i16 5, ptr %array_gep1, align 2
|
|
||||||
|
|
||||||
%array_gep2 = getelementptr ptr, ptr %call, i32 0
|
|
||||||
%load = load ptr, ptr %array_gep2, align 8
|
|
||||||
%array_gep3 = getelementptr i16, ptr %load, i32 3
|
|
||||||
%load4 = load i16, ptr %array_gep3, align 2
|
|
||||||
|
|
||||||
ret i16 %load4
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user