reid-llvm/reid-llvm-lib/src/compile.rs

387 lines
13 KiB
Rust

use std::{collections::HashMap, ffi::CString, hash::Hash, process::Termination, ptr::null_mut};
use llvm_sys::{
LLVMIntPredicate,
analysis::LLVMVerifyModule,
core::*,
prelude::*,
target::{
LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos,
LLVM_InitializeAllTargetMCs, LLVM_InitializeAllTargets, LLVMSetModuleDataLayout,
},
target_machine::{
LLVMCodeGenFileType, LLVMCreateTargetDataLayout, LLVMCreateTargetMachine,
LLVMGetDefaultTargetTriple, LLVMGetTargetFromTriple, LLVMTargetMachineEmitToFile,
},
};
use crate::util::{ErrorMessageHolder, from_cstring, into_cstring};
use super::{
ConstValue, Context, Function, IntPredicate, Module, TerminatorKind, Type,
builder::{
BlockHolder, BlockValue, Builder, FunctionHolder, FunctionValue, InstructionHolder,
InstructionValue, ModuleHolder,
},
};
pub struct LLVMContext {
context_ref: LLVMContextRef,
builder_ref: LLVMBuilderRef,
}
impl Context {
pub fn compile(&self) {
unsafe {
let context_ref = LLVMContextCreate();
let context = LLVMContext {
context_ref,
builder_ref: LLVMCreateBuilderInContext(context_ref),
};
for holder in self.builder.get_modules().borrow().iter() {
holder.compile(&context, &self.builder);
}
LLVMDisposeBuilder(context.builder_ref);
LLVMContextDispose(context.context_ref);
}
}
}
pub struct LLVMModule<'a> {
builder: &'a Builder,
context_ref: LLVMContextRef,
builder_ref: LLVMBuilderRef,
module_ref: LLVMModuleRef,
functions: HashMap<FunctionValue, LLVMFunction>,
blocks: HashMap<BlockValue, LLVMBasicBlockRef>,
values: HashMap<InstructionValue, LLVMValue>,
}
#[derive(Clone, Copy)]
pub struct LLVMFunction {
type_ref: LLVMTypeRef,
value_ref: LLVMValueRef,
}
pub struct LLVMValue {
ty: Type,
value_ref: LLVMValueRef,
}
impl ModuleHolder {
fn compile(&self, context: &LLVMContext, builder: &Builder) {
unsafe {
let module_ref = LLVMModuleCreateWithNameInContext(
into_cstring(&self.data.name).as_ptr(),
context.context_ref,
);
// Compile the contents
let mut functions = HashMap::new();
for function in &self.functions {
functions.insert(
function.value,
function.compile_signature(context, module_ref),
);
}
let mut module = LLVMModule {
builder,
context_ref: context.context_ref,
builder_ref: context.builder_ref,
module_ref,
functions,
blocks: HashMap::new(),
values: HashMap::new(),
};
for function in &self.functions {
function.compile(&mut module);
}
LLVM_InitializeAllTargets();
LLVM_InitializeAllTargetInfos();
LLVM_InitializeAllTargetMCs();
LLVM_InitializeAllAsmParsers();
LLVM_InitializeAllAsmPrinters();
let triple = LLVMGetDefaultTargetTriple();
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(
target,
triple,
c"generic".as_ptr(),
c"".as_ptr(),
llvm_sys::target_machine::LLVMCodeGenOptLevel::LLVMCodeGenLevelNone,
llvm_sys::target_machine::LLVMRelocMode::LLVMRelocDefault,
llvm_sys::target_machine::LLVMCodeModel::LLVMCodeModelDefault,
);
let data_layout = LLVMCreateTargetDataLayout(target_machine);
LLVMSetTarget(module_ref, triple);
LLVMSetModuleDataLayout(module_ref, data_layout);
let mut err = ErrorMessageHolder::null();
LLVMVerifyModule(
module_ref,
llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction,
err.borrow_mut(),
);
err.into_result().unwrap();
let mut err = ErrorMessageHolder::null();
LLVMTargetMachineEmitToFile(
target_machine,
module_ref,
CString::new("hello.asm").unwrap().into_raw(),
LLVMCodeGenFileType::LLVMAssemblyFile,
err.borrow_mut(),
);
err.into_result().unwrap();
let mut err = ErrorMessageHolder::null();
LLVMTargetMachineEmitToFile(
target_machine,
module_ref,
CString::new("hello.o").unwrap().into_raw(),
LLVMCodeGenFileType::LLVMObjectFile,
err.borrow_mut(),
);
err.into_result().unwrap();
let module_str = from_cstring(LLVMPrintModuleToString(module_ref));
println!("{}", module_str.unwrap());
}
}
}
impl FunctionHolder {
unsafe fn compile_signature(
&self,
context: &LLVMContext,
module_ref: LLVMModuleRef,
) -> LLVMFunction {
unsafe {
let ret_type = self.data.ret.as_llvm(context.context_ref);
let mut param_types: Vec<LLVMTypeRef> = self
.data
.params
.iter()
.map(|t| t.as_llvm(context.context_ref))
.collect();
let param_ptr = param_types.as_mut_ptr();
let param_len = param_types.len();
let fn_type = LLVMFunctionType(ret_type, param_ptr, param_len as u32, 0);
let function_ref =
LLVMAddFunction(module_ref, into_cstring(&self.data.name).as_ptr(), fn_type);
LLVMFunction {
type_ref: fn_type,
value_ref: function_ref,
}
}
}
unsafe fn compile(&self, module: &mut LLVMModule) {
unsafe {
let own_function = *module.functions.get(&self.value).unwrap();
for block in &self.blocks {
let block_ref = LLVMCreateBasicBlockInContext(
module.context_ref,
into_cstring(&self.data.name).as_ptr(),
);
LLVMAppendExistingBasicBlock(own_function.value_ref, block_ref);
module.blocks.insert(block.value, block_ref);
}
for block in &self.blocks {
block.compile(module, &own_function);
}
}
}
}
impl BlockHolder {
unsafe fn compile(&self, module: &mut LLVMModule, function: &LLVMFunction) {
unsafe {
let block_ref = *module.blocks.get(&self.value).unwrap();
LLVMPositionBuilderAtEnd(module.builder_ref, block_ref);
for instruction in &self.instructions {
let key = instruction.value;
let ret = instruction.compile(module, function, block_ref);
module.values.insert(key, ret);
}
self.data
.terminator
.clone()
.expect(&format!(
"Block {} does not have a terminator!",
self.data.name
))
.compile(module, function, block_ref);
}
}
}
impl InstructionHolder {
unsafe fn compile(
&self,
module: &LLVMModule,
function: &LLVMFunction,
block: LLVMBasicBlockRef,
) -> LLVMValue {
let ty = self.value.get_type(module.builder).unwrap();
let val = unsafe {
use super::InstructionKind::*;
match &self.data.kind {
Param(nth) => LLVMGetParam(function.value_ref, *nth as u32),
Constant(val) => val.as_llvm(module.context_ref),
Add(lhs, rhs) => {
let lhs_val = module.values.get(&lhs).unwrap().value_ref;
let rhs_val = module.values.get(&rhs).unwrap().value_ref;
LLVMBuildAdd(module.builder_ref, lhs_val, rhs_val, c"add".as_ptr())
}
Sub(lhs, rhs) => {
let lhs_val = module.values.get(&lhs).unwrap().value_ref;
let rhs_val = module.values.get(&rhs).unwrap().value_ref;
LLVMBuildSub(module.builder_ref, lhs_val, rhs_val, c"sub".as_ptr())
}
ICmp(pred, lhs, rhs) => {
let lhs_val = module.values.get(&lhs).unwrap().value_ref;
let rhs_val = module.values.get(&rhs).unwrap().value_ref;
LLVMBuildICmp(
module.builder_ref,
pred.as_llvm(ty.signed()),
lhs_val,
rhs_val,
c"icmp".as_ptr(),
)
}
FunctionCall(function_value, instruction_values) => {
let fun = module.functions.get(&function_value).unwrap();
let mut param_list: Vec<LLVMValueRef> = instruction_values
.iter()
.map(|i| module.values.get(i).unwrap().value_ref)
.collect();
LLVMBuildCall2(
module.builder_ref,
fun.type_ref,
fun.value_ref,
param_list.as_mut_ptr(),
param_list.len() as u32,
c"call".as_ptr(),
)
}
Phi(values) => {
let mut inc_values = Vec::new();
let mut inc_blocks = Vec::new();
for item in values {
inc_values.push(module.values.get(&item).unwrap().value_ref);
inc_blocks.push(*module.blocks.get(&item.0).unwrap());
}
let phi = LLVMBuildPhi(
module.builder_ref,
ty.as_llvm(module.context_ref),
c"phi".as_ptr(),
);
LLVMAddIncoming(
phi,
inc_values.as_mut_ptr(),
inc_blocks.as_mut_ptr(),
values.len() as u32,
);
phi
}
}
};
LLVMValue { ty, value_ref: val }
}
}
impl TerminatorKind {
fn compile(
&self,
module: &LLVMModule,
function: &LLVMFunction,
block: LLVMBasicBlockRef,
) -> LLVMValue {
let ty = self.get_type(module.builder).unwrap();
let val = unsafe {
match self {
TerminatorKind::Ret(val) => {
let value = module.values.get(val).unwrap();
LLVMBuildRet(module.builder_ref, value.value_ref)
}
TerminatorKind::Branch(block_value) => {
let dest = *module.blocks.get(block_value).unwrap();
LLVMBuildBr(module.builder_ref, dest)
}
TerminatorKind::CondBr(cond, then_b, else_b) => {
let cond_val = module.values.get(cond).unwrap().value_ref;
let then_bb = *module.blocks.get(then_b).unwrap();
let else_bb = *module.blocks.get(else_b).unwrap();
LLVMBuildCondBr(module.builder_ref, cond_val, then_bb, else_bb)
}
}
};
LLVMValue { ty, value_ref: val }
}
}
impl IntPredicate {
fn as_llvm(&self, signed: bool) -> LLVMIntPredicate {
use IntPredicate::*;
use LLVMIntPredicate::*;
match (self, signed) {
(LessThan, true) => LLVMIntSLT,
(GreaterThan, true) => LLVMIntSGT,
(LessThan, false) => LLVMIntULT,
(GreaterThan, false) => LLVMIntUGT,
}
}
}
impl ConstValue {
fn as_llvm(&self, context: LLVMContextRef) -> LLVMValueRef {
unsafe {
let t = self.get_type().as_llvm(context);
match *self {
ConstValue::I32(val) => LLVMConstInt(t, val as u64, 1),
ConstValue::I16(val) => LLVMConstInt(t, val as u64, 1),
ConstValue::U32(val) => LLVMConstInt(t, val as u64, 0),
}
}
}
}
impl Type {
fn as_llvm(&self, context: LLVMContextRef) -> LLVMTypeRef {
unsafe {
match self {
Type::I32 => LLVMInt32TypeInContext(context),
Type::I16 => LLVMInt16TypeInContext(context),
Type::U32 => LLVMInt32TypeInContext(context),
Type::Bool => LLVMInt1TypeInContext(context),
Type::Void => LLVMVoidType(),
}
}
}
}