Compare commits

...

5 Commits

13 changed files with 769 additions and 73 deletions

View File

@ -0,0 +1,14 @@
extern fn printf(message: *char, num: f64);
fn main() -> i32 {
let b = 5;
let mut otus = i32::malloc(1);
otus[0] = 10500300;
let potus = i32::malloc(1);
i32::memcpy(potus, otus, 1);
printf("log10 %f\n", f64::round(123.3) as f64);
printf("log10 %f\n", potus[0] as f64);
return potus[0];
}

View File

@ -16,7 +16,7 @@ BINARY="$(echo $1 | cut -d'.' -f1)"".out"
echo $1 echo $1
cargo run --example cli $@ && \ cargo run --example cli $@ && \
./$BINARY ; echo "Return value: ""$?" ./$BINARY ; echo "Return value: ""$?"
## Command from: clang -v hello.o -o test ## Command from: clang -v hello.o -o test

View File

@ -6,7 +6,7 @@ use std::{
}; };
use crate::{ use crate::{
CmpPredicate, Context, Instr, InstructionData, TerminatorKind, CmpPredicate, Context, Instr, InstructionData, TerminatorKind, Type,
builder::*, builder::*,
debug_information::{ debug_information::{
DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocalVariable, DebugLocation, DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocalVariable, DebugLocation,

View File

@ -0,0 +1,263 @@
use crate::{CompileResult, Type, TypeCategory, builder::Builder};
#[derive(Clone, Debug)]
pub enum LLVMIntrinsic {
Abs(Type),
Max(Type),
Min(Type),
Memcpy(Type),
Sqrt(Type),
PowI(Type, Type),
Pow(Type),
Sin(Type),
Cos(Type),
Tan(Type),
ASin(Type),
ACos(Type),
ATan(Type),
ATan2(Type),
SinH(Type),
CosH(Type),
TanH(Type),
Log(Type),
Log2(Type),
Log10(Type),
Copysign(Type),
Floor(Type),
Ceil(Type),
Trunc(Type),
RoundEven(Type),
Round(Type),
}
impl LLVMIntrinsic {
pub(crate) fn signature(&self, builder: &Builder) -> CompileResult<(String, Vec<Type>, Type)> {
match self {
LLVMIntrinsic::Max(ty) => {
let name = match ty.category() {
TypeCategory::SignedInteger => format!("llvm.smax.{}", ty.llvm_ty_str(builder)),
TypeCategory::UnsignedInteger => format!("llvm.umax.{}", ty.llvm_ty_str(builder)),
TypeCategory::Real => format!("llvm.maximum.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone(), ty.clone()], ty.clone()))
}
LLVMIntrinsic::Min(ty) => {
let name = match ty.category() {
TypeCategory::SignedInteger => format!("llvm.smin.{}", ty.llvm_ty_str(builder)),
TypeCategory::UnsignedInteger => format!("llvm.umin.{}", ty.llvm_ty_str(builder)),
TypeCategory::Real => format!("llvm.minimum.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone(), ty.clone()], ty.clone()))
}
LLVMIntrinsic::Abs(ty) => {
let name = match ty.category() {
TypeCategory::SignedInteger => format!("llvm.abs.{}", ty.llvm_ty_str(builder)),
TypeCategory::UnsignedInteger => format!("llvm.abs.{}", ty.llvm_ty_str(builder)),
TypeCategory::Real => format!("llvm.fabs.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone(), Type::Bool], ty.clone()))
}
LLVMIntrinsic::Memcpy(ty) => {
let name = match ty.category() {
TypeCategory::Ptr => String::from("llvm.memcpy"),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone(), ty.clone(), Type::U64, Type::Bool], Type::Void))
}
LLVMIntrinsic::Sqrt(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.sqrt.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::PowI(ty1, ty2) => {
let name = match (ty1.category(), ty2.category()) {
(TypeCategory::Real, TypeCategory::SignedInteger) => {
format!("llvm.powi.{}.{}", ty1.llvm_ty_str(builder), ty2.llvm_ty_str(builder))
}
(TypeCategory::Real, TypeCategory::UnsignedInteger) => {
format!("llvm.powi.{}.{}", ty1.llvm_ty_str(builder), ty2.llvm_ty_str(builder))
}
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty1.clone(), ty2.clone()], ty1.clone()))
}
LLVMIntrinsic::Pow(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.pow.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone(), ty.clone()], ty.clone()))
}
LLVMIntrinsic::Sin(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.sin.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::Cos(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.cos.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::Tan(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.tan.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::ASin(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.asin.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::ACos(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.acos.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::ATan(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.atan.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::ATan2(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.atan2.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone(), ty.clone()], ty.clone()))
}
LLVMIntrinsic::SinH(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.sinh.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::CosH(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.cosh.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::TanH(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.tanh.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::Log(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.log.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::Log2(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.log2.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::Log10(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.log10.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::Copysign(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.copysign.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::Floor(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.floor.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::Ceil(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.ceil.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::Trunc(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.trunc.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::RoundEven(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.roundeven.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
LLVMIntrinsic::Round(ty) => {
let name = match ty.category() {
TypeCategory::Real => format!("llvm.rint.{}", ty.llvm_ty_str(builder)),
_ => return Err(crate::ErrorKind::Null),
};
Ok((name, vec![ty.clone()], ty.clone()))
}
}
}
}
impl Type {
fn llvm_ty_str(&self, builder: &Builder) -> String {
match self {
Type::I8 => String::from("i8"),
Type::I16 => String::from("u16"),
Type::I32 => String::from("i32"),
Type::I64 => String::from("i64"),
Type::I128 => String::from("i128"),
Type::U8 => String::from("i8"),
Type::U16 => String::from("i16"),
Type::U32 => String::from("i32"),
Type::U64 => String::from("i64"),
Type::U128 => String::from("i128"),
Type::F16 => String::from("f16"),
Type::F32B => String::from("f32b"),
Type::F32 => String::from("f32"),
Type::F64 => String::from("f64"),
Type::F80 => String::from("x86_fp80"),
Type::F128 => String::from("fp128"),
Type::F128PPC => String::from("ppc_fp128"),
Type::Bool => String::from("i1"),
Type::Void => String::from("void"),
Type::CustomType(type_value) => {
let ty = unsafe { builder.type_data(type_value) };
ty.name.clone()
}
Type::Array(ty, len) => format!("[{} x {}]", len, ty.llvm_ty_str(builder)),
Type::Ptr(_) => String::from("ptr"),
}
}
}

View File

@ -11,12 +11,14 @@ use fmt::PrintableModule;
use crate::{ use crate::{
builder::{ConstantValue, GlobalValue}, builder::{ConstantValue, GlobalValue},
debug_information::DebugScopeValue, debug_information::DebugScopeValue,
intrinsics::LLVMIntrinsic,
}; };
pub mod builder; pub mod builder;
pub mod compile; pub mod compile;
pub mod debug_information; pub mod debug_information;
mod fmt; mod fmt;
pub mod intrinsics;
mod pad_adapter; mod pad_adapter;
mod util; mod util;
@ -95,6 +97,25 @@ impl<'ctx> Module<'ctx> {
} }
} }
pub fn intrinsic(&self, intrinsic: LLVMIntrinsic) -> CompileResult<FunctionValue> {
unsafe {
let (name, params, ret) = intrinsic.signature(&self.builder)?;
Ok(self.builder.add_function(
&self.value,
FunctionData {
name: name.to_owned(),
linkage_name: Some(name.to_owned()),
ret,
params,
flags: FunctionFlags {
is_extern: true,
..Default::default()
},
},
))
}
}
pub fn custom_type(&self, ty: CustomTypeKind) -> TypeValue { pub fn custom_type(&self, ty: CustomTypeKind) -> TypeValue {
unsafe { unsafe {
let (name, kind) = match &ty { let (name, kind) = match &ty {

View File

@ -1021,9 +1021,8 @@ pub fn analyze_expr(
function_autocomplete.extend( function_autocomplete.extend(
get_intrinsic_assoc_functions(&invoked_ty) get_intrinsic_assoc_functions(&invoked_ty)
.iter() .iter()
.filter_map(|(s, f)| f.as_ref().map(|f| (s, f))) .filter(|fun| fun.name.starts_with(name))
.filter(|(_, fun)| fun.name.starts_with(name)) .map(|fun| Autocomplete {
.map(|(_, fun)| Autocomplete {
text: fun.name.clone(), text: fun.name.clone(),
kind: AutocompleteKind::Function(fun.parameters.clone(), fun.return_type.clone()), kind: AutocompleteKind::Function(fun.parameters.clone(), fun.return_type.clone()),
}) })

View File

@ -66,7 +66,7 @@ fn main() -> Result<(), std::io::Error> {
} }
let linker = std::env::var("LD").unwrap_or("ld".to_owned()); let linker = std::env::var("LD").unwrap_or("ld".to_owned());
let mut linker = LDRunner::from_command(&linker).with_library("c"); let mut linker = LDRunner::from_command(&linker).with_library("c").with_library("m");
for library in libraries { for library in libraries {
linker = linker.with_library(&library); linker = linker.with_library(&library);
} }

View File

@ -199,9 +199,9 @@ impl<'a, 'b> TokenStream<'a, 'b> {
} }
} }
pub fn parse_with<T, U>(&mut self, fun: T) -> U pub fn parse_with<T, U>(&mut self, fun: T) -> Result<U, Error>
where where
T: FnOnce(TokenStream) -> U, T: FnOnce(TokenStream) -> Result<U, Error>,
{ {
let mut ref_pos = self.position; let mut ref_pos = self.position;
@ -213,7 +213,13 @@ impl<'a, 'b> TokenStream<'a, 'b> {
position, position,
}; };
fun(clone) match fun(clone) {
Ok(res) => {
self.position = ref_pos.max(self.position);
Ok(res)
}
Err(e) => Err(e),
}
} }
pub fn get_range(&self) -> Option<TokenRange> { pub fn get_range(&self) -> Option<TokenRange> {

View File

@ -1,12 +1,10 @@
use std::{collections::HashMap, hash::Hash};
use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValueKind, Instr, Type}; use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValueKind, Instr, Type};
use crate::{ use crate::{
codegen::{ErrorKind, StackValueKind}, codegen::{ErrorKind, StackValueKind},
mir::{ mir::{
BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, FunctionParam, implement::TypeCategory, BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition,
TypeKind, FunctionDefinitionKind, FunctionParam, TypeKind,
}, },
}; };
@ -35,6 +33,36 @@ const FLOATS: [TypeKind; 7] = [
TypeKind::F128PPC, TypeKind::F128PPC,
]; ];
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum LLVMIntrinsicKind {
Max(TypeKind),
Min(TypeKind),
Abs(TypeKind),
Memcpy(TypeKind),
Sqrt(TypeKind),
PowI(TypeKind, TypeKind),
Pow(TypeKind),
Sin(TypeKind),
Cos(TypeKind),
Tan(TypeKind),
ASin(TypeKind),
ACos(TypeKind),
ATan(TypeKind),
ATan2(TypeKind),
SinH(TypeKind),
CosH(TypeKind),
TanH(TypeKind),
Log(TypeKind),
Log2(TypeKind),
Log10(TypeKind),
Copysign(TypeKind),
Floor(TypeKind),
Ceil(TypeKind),
Trunc(TypeKind),
RoundEven(TypeKind),
Round(TypeKind),
}
const INTRINSIC_IDENT: &str = "reid.intrinsic"; const INTRINSIC_IDENT: &str = "reid.intrinsic";
const MALLOC_IDENT: &str = "malloc"; const MALLOC_IDENT: &str = "malloc";
@ -60,79 +88,305 @@ pub fn form_intrinsics() -> Vec<FunctionDefinition> {
intrinsics intrinsics
} }
pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> HashMap<String, Option<FunctionDefinition>> { pub fn simple_intrinsic<T: Into<String> + Clone>(
let mut map = HashMap::new(); name: T,
map.insert("length".to_owned(), get_intrinsic_assoc_func(ty, "length")); params: Vec<T>,
map.insert("sizeof".to_owned(), get_intrinsic_assoc_func(ty, "sizeof")); ret: TypeKind,
map.insert("malloc".to_owned(), get_intrinsic_assoc_func(ty, "malloc")); intrisic: LLVMIntrinsicKind,
map.insert("null".to_owned(), get_intrinsic_assoc_func(ty, "null")); ) -> FunctionDefinition {
map FunctionDefinition {
name: name.into(),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: ret.clone(),
parameters: params
.iter()
.map(|p| FunctionParam::from(p.clone(), ret.clone()))
.collect(),
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicLLVM(intrisic, ret.clone()))),
source: None,
signature_meta: Default::default(),
}
} }
pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDefinition> { pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> {
let mut intrinsics = Vec::new();
if let TypeKind::Array(_, len) = ty { if let TypeKind::Array(_, len) = ty {
match name { intrinsics.push(FunctionDefinition {
"length" => { name: "length".to_owned(),
return Some(FunctionDefinition { linkage_name: None,
name: "length".to_owned(), is_pub: true,
is_imported: false,
return_type: TypeKind::Void,
parameters: vec![FunctionParam {
name: String::from("self"),
ty: TypeKind::Borrow(Box::new(ty.clone()), false),
meta: Default::default(),
}],
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicConst(*len))),
source: None,
signature_meta: Default::default(),
});
}
if ty.category() == TypeCategory::Real {
intrinsics.push(simple_intrinsic(
"sin",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Sin(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"cos",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Cos(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"tan",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Tan(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"sinh",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::SinH(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"cosh",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::CosH(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"tanh",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::TanH(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"asin",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::ASin(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"acos",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::ACos(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"atan",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::ATan(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"atan2",
vec!["self", "other"],
ty.clone(),
LLVMIntrinsicKind::ATan2(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"log",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Log(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"log2",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Log2(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"log10",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Log10(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"floor",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Floor(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"ceil",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Ceil(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"trunc",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Trunc(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"round",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Round(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"even",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::RoundEven(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"pow",
vec!["self", "exponent"],
ty.clone(),
LLVMIntrinsicKind::Pow(ty.clone()),
));
intrinsics.push(FunctionDefinition {
name: "powi".to_owned(),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: ty.clone(),
parameters: vec![
FunctionParam {
name: String::from("self"),
ty: ty.clone(),
meta: Default::default(),
},
FunctionParam {
name: String::from("exponent"),
ty: TypeKind::U32,
meta: Default::default(),
},
],
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicLLVM(
LLVMIntrinsicKind::PowI(ty.clone(), TypeKind::U32),
ty.clone(),
))),
source: None,
signature_meta: Default::default(),
});
}
match ty.category() {
TypeCategory::Integer | TypeCategory::Real | TypeCategory::Bool => {
intrinsics.push(simple_intrinsic(
"max",
vec!["self", "other"],
ty.clone(),
LLVMIntrinsicKind::Max(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"min",
vec!["self", "other"],
ty.clone(),
LLVMIntrinsicKind::Min(ty.clone()),
));
if ty.signed() {
intrinsics.push(FunctionDefinition {
name: "abs".to_owned(),
linkage_name: None, linkage_name: None,
is_pub: true, is_pub: true,
is_imported: false, is_imported: false,
return_type: TypeKind::U64, return_type: ty.clone(),
parameters: vec![FunctionParam { parameters: vec![FunctionParam {
name: String::from("self"), name: String::from("self"),
ty: TypeKind::Borrow(Box::new(ty.clone()), false), ty: ty.clone(),
meta: Default::default(), meta: Default::default(),
}], }],
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicConst(*len))), kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleUnaryInstr({
let ty = ty.clone();
|scope, param| {
let intrinsic = scope.get_intrinsic(LLVMIntrinsicKind::Abs(ty));
let constant = scope.block.build(Instr::Constant(ConstValueKind::Bool(false))).unwrap();
let value = scope
.block
.build(Instr::FunctionCall(intrinsic, vec![param, constant]))
.unwrap();
value
}
}))),
source: None, source: None,
signature_meta: Default::default(), signature_meta: Default::default(),
}); });
} }
_ => {}
} }
_ => {}
} }
intrinsics.push(FunctionDefinition {
name: "sizeof".to_owned(),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: TypeKind::U64,
parameters: Vec::new(),
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSizeOf(ty.clone()))),
source: None,
signature_meta: Default::default(),
});
intrinsics.push(FunctionDefinition {
name: "malloc".to_owned(),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: TypeKind::UserPtr(Box::new(ty.clone())),
parameters: vec![FunctionParam {
name: String::from("size"),
ty: TypeKind::U64,
meta: Default::default(),
}],
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicMalloc(ty.clone()))),
source: None,
signature_meta: Default::default(),
});
match name { intrinsics.push(FunctionDefinition {
"sizeof" => Some(FunctionDefinition { name: "memcpy".to_owned(),
name: "sizeof".to_owned(), linkage_name: None,
linkage_name: None, is_pub: true,
is_pub: true, is_imported: false,
is_imported: false, return_type: TypeKind::Void,
return_type: TypeKind::U64, parameters: vec![
parameters: Vec::new(), FunctionParam {
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSizeOf(ty.clone()))), name: String::from("destination"),
source: None, ty: TypeKind::UserPtr(Box::new(ty.clone())),
signature_meta: Default::default(), meta: Default::default(),
}), },
"malloc" => Some(FunctionDefinition { FunctionParam {
name: "malloc".to_owned(), name: String::from("source"),
linkage_name: None, ty: TypeKind::UserPtr(Box::new(ty.clone())),
is_pub: true, meta: Default::default(),
is_imported: false, },
return_type: TypeKind::UserPtr(Box::new(ty.clone())), FunctionParam {
parameters: vec![FunctionParam { name: String::from("length"),
name: String::from("size"),
ty: TypeKind::U64, ty: TypeKind::U64,
meta: Default::default(), meta: Default::default(),
}], },
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicMalloc(ty.clone()))), ],
source: None, kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicMemcpy(ty.clone()))),
signature_meta: Default::default(), source: None,
}), signature_meta: Default::default(),
"null" => Some(FunctionDefinition { });
name: "null".to_owned(),
linkage_name: None, intrinsics.push(FunctionDefinition {
is_pub: true, name: "null".to_owned(),
is_imported: false, linkage_name: None,
return_type: TypeKind::UserPtr(Box::new(ty.clone())), is_pub: true,
parameters: Vec::new(), is_imported: false,
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicNullPtr(ty.clone()))), return_type: TypeKind::UserPtr(Box::new(ty.clone())),
source: None, parameters: Vec::new(),
signature_meta: Default::default(), kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicNullPtr(ty.clone()))),
}), source: None,
_ => None, signature_meta: Default::default(),
} });
intrinsics
}
pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDefinition> {
get_intrinsic_assoc_functions(ty).into_iter().find(|f| f.name == name)
} }
fn simple_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition fn simple_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition
@ -152,7 +406,7 @@ where
meta: Default::default(), meta: Default::default(),
}, },
return_type: ty.clone(), return_type: ty.clone(),
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(fun))), fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleBinaryInstr(fun))),
meta: Default::default(), meta: Default::default(),
exported: false, exported: false,
} }
@ -175,7 +429,7 @@ where
meta: Default::default(), meta: Default::default(),
}, },
return_type: lhs.clone(), return_type: lhs.clone(),
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(fun))), fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleBinaryInstr(fun))),
meta: Default::default(), meta: Default::default(),
exported: false, exported: false,
} }
@ -352,12 +606,37 @@ macro_rules! intrinsic_debug {
} }
#[derive(Clone)] #[derive(Clone)]
pub struct IntrinsicSimpleInstr<T>(T) pub struct IntrinsicSimpleUnaryInstr<T>(T)
where
T: FnOnce(&mut Scope, InstructionValue) -> InstructionValue;
impl<T> std::fmt::Debug for IntrinsicSimpleUnaryInstr<T>
where
T: FnOnce(&mut Scope, InstructionValue) -> InstructionValue,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("IntrinsicSimpleUnaryInstr").finish()
}
}
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleUnaryInstr<T>
where
T: FnOnce(&mut Scope, InstructionValue) -> InstructionValue,
{
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
let param = params.get(0).unwrap();
let instr = self.clone().0(scope, param.instr());
Ok(StackValue(StackValueKind::Literal(instr), param.1.clone()))
}
}
#[derive(Clone)]
pub struct IntrinsicSimpleBinaryInstr<T>(T)
where where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue; T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
intrinsic_debug!(IntrinsicSimpleInstr<T>, "IntrinsicSimpleInstr"); intrinsic_debug!(IntrinsicSimpleBinaryInstr<T>, "IntrinsicSimpleBinaryInstr");
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleInstr<T> impl<T: Clone> IntrinsicFunction for IntrinsicSimpleBinaryInstr<T>
where where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{ {
@ -401,6 +680,35 @@ impl IntrinsicFunction for IntrinsicSizeOf {
} }
} }
#[derive(Clone, Debug)]
pub struct IntrinsicMemcpy(TypeKind);
impl IntrinsicFunction for IntrinsicMemcpy {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
let dest = params.get(0).unwrap();
let src = params.get(1).unwrap();
let length = params.get(2).unwrap();
let intrinsic = scope.get_intrinsic(LLVMIntrinsicKind::Memcpy(TypeKind::UserPtr(Box::new(self.0.clone()))));
let sizeof = scope
.block
.build(Instr::Constant(ConstValueKind::U64(
self.0.size_of(&scope.type_map) / 8,
)))
.unwrap();
let bytes = scope.block.build(Instr::Mul(sizeof, length.instr())).unwrap();
dbg!(self.0.size_of(&scope.type_map) / 8);
let params = vec![
dest.instr(),
src.instr(),
bytes,
scope.block.build(Instr::Constant(ConstValueKind::Bool(false))).unwrap(),
];
let value = scope.block.build(Instr::FunctionCall(intrinsic, params)).unwrap();
Ok(StackValue(StackValueKind::Literal(value), TypeKind::Void))
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct IntrinsicMalloc(TypeKind); pub struct IntrinsicMalloc(TypeKind);
impl IntrinsicFunction for IntrinsicMalloc { impl IntrinsicFunction for IntrinsicMalloc {
@ -441,6 +749,7 @@ impl IntrinsicFunction for IntrinsicNullPtr {
)) ))
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct IntrinsicConst(u64); pub struct IntrinsicConst(u64);
impl IntrinsicFunction for IntrinsicConst { impl IntrinsicFunction for IntrinsicConst {
@ -450,6 +759,23 @@ impl IntrinsicFunction for IntrinsicConst {
} }
} }
#[derive(Clone, Debug)]
pub struct IntrinsicLLVM(LLVMIntrinsicKind, TypeKind);
impl IntrinsicFunction for IntrinsicLLVM {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
let intrinsic = scope.get_intrinsic(self.0.clone());
let value = scope
.block
.build(Instr::FunctionCall(
intrinsic,
params.iter().map(|p| p.instr()).collect(),
))
.unwrap();
Ok(StackValue(StackValueKind::Literal(value), self.1.clone()))
}
}
// impl IntrinsicFunction for IntrinsicIAdd { // impl IntrinsicFunction for IntrinsicIAdd {
// fn codegen<'ctx, 'a>( // fn codegen<'ctx, 'a>(
// &self, // &self,

View File

@ -393,6 +393,7 @@ impl mir::Module {
}), }),
binops: &binops, binops: &binops,
allocator: Rc::new(RefCell::new(allocator)), allocator: Rc::new(RefCell::new(allocator)),
llvm_intrinsics: Rc::new(RefCell::new(HashMap::new())),
}; };
binop binop
@ -471,6 +472,7 @@ impl mir::Module {
globals: &globals, globals: &globals,
binops: &binops, binops: &binops,
allocator: Rc::new(RefCell::new(allocator)), allocator: Rc::new(RefCell::new(allocator)),
llvm_intrinsics: Rc::new(RefCell::new(HashMap::new())),
}; };
mir_function mir_function
@ -533,6 +535,7 @@ impl mir::Module {
globals: &globals, globals: &globals,
binops: &binops, binops: &binops,
allocator: Rc::new(RefCell::new(allocator)), allocator: Rc::new(RefCell::new(allocator)),
llvm_intrinsics: Rc::new(RefCell::new(HashMap::new())),
}; };
mir_function mir_function

View File

@ -1,12 +1,14 @@
use std::{cell::RefCell, collections::HashMap, mem, rc::Rc}; use std::{cell::RefCell, collections::HashMap, mem, rc::Rc};
use reid_lib::{ use reid_lib::{
builder::{GlobalValue, InstructionValue, TypeValue}, builder::{FunctionValue, GlobalValue, InstructionValue, TypeValue},
debug_information::{DebugInformation, DebugLocation, DebugScopeValue, DebugTypeValue}, debug_information::{DebugInformation, DebugLocation, DebugScopeValue, DebugTypeValue},
intrinsics::LLVMIntrinsic,
Block, Context, Function, Instr, Module, Block, Context, Function, Instr, Module,
}; };
use crate::{ use crate::{
codegen::intrinsics::LLVMIntrinsicKind,
lexer::FullToken, lexer::FullToken,
mir::{ mir::{
pass::{AssociatedFunctionKey, BinopKey}, pass::{AssociatedFunctionKey, BinopKey},
@ -34,6 +36,7 @@ pub struct Scope<'ctx, 'scope> {
pub(super) globals: &'scope HashMap<String, GlobalValue>, pub(super) globals: &'scope HashMap<String, GlobalValue>,
pub(super) debug: Option<Debug<'ctx>>, pub(super) debug: Option<Debug<'ctx>>,
pub(super) allocator: Rc<RefCell<Allocator>>, pub(super) allocator: Rc<RefCell<Allocator>>,
pub(super) llvm_intrinsics: Rc<RefCell<HashMap<LLVMIntrinsicKind, FunctionValue>>>,
} }
impl<'ctx, 'a> Scope<'ctx, 'a> { impl<'ctx, 'a> Scope<'ctx, 'a> {
@ -56,6 +59,7 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
allocator: self.allocator.clone(), allocator: self.allocator.clone(),
globals: self.globals, globals: self.globals,
binops: self.binops, binops: self.binops,
llvm_intrinsics: self.llvm_intrinsics.clone(),
} }
} }
@ -74,6 +78,49 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
pub fn allocate(&self, meta: &Metadata, ty: &TypeKind) -> Option<InstructionValue> { pub fn allocate(&self, meta: &Metadata, ty: &TypeKind) -> Option<InstructionValue> {
self.allocator.borrow_mut().allocate(meta, ty) self.allocator.borrow_mut().allocate(meta, ty)
} }
pub fn get_intrinsic(&self, kind: LLVMIntrinsicKind) -> FunctionValue {
let mut intrinsics = self.llvm_intrinsics.borrow_mut();
if let Some(fun) = intrinsics.get(&kind) {
*fun
} else {
let intrinsic = self
.module
.intrinsic(match &kind {
LLVMIntrinsicKind::Max(ty) => LLVMIntrinsic::Max(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Min(ty) => LLVMIntrinsic::Min(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Abs(ty) => LLVMIntrinsic::Abs(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Memcpy(ty) => LLVMIntrinsic::Memcpy(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Sqrt(ty) => LLVMIntrinsic::Sqrt(ty.get_type(self.type_values)),
LLVMIntrinsicKind::PowI(lhs, rhs) => {
LLVMIntrinsic::PowI(lhs.get_type(self.type_values), rhs.get_type(self.type_values))
}
LLVMIntrinsicKind::Pow(ty) => LLVMIntrinsic::Pow(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Sin(ty) => LLVMIntrinsic::Sin(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Cos(ty) => LLVMIntrinsic::Cos(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Tan(ty) => LLVMIntrinsic::Tan(ty.get_type(self.type_values)),
LLVMIntrinsicKind::ASin(ty) => LLVMIntrinsic::ASin(ty.get_type(self.type_values)),
LLVMIntrinsicKind::ACos(ty) => LLVMIntrinsic::ACos(ty.get_type(self.type_values)),
LLVMIntrinsicKind::ATan(ty) => LLVMIntrinsic::ATan(ty.get_type(self.type_values)),
LLVMIntrinsicKind::ATan2(ty) => LLVMIntrinsic::ATan2(ty.get_type(self.type_values)),
LLVMIntrinsicKind::SinH(ty) => LLVMIntrinsic::SinH(ty.get_type(self.type_values)),
LLVMIntrinsicKind::CosH(ty) => LLVMIntrinsic::CosH(ty.get_type(self.type_values)),
LLVMIntrinsicKind::TanH(ty) => LLVMIntrinsic::TanH(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Log(ty) => LLVMIntrinsic::Log(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Log2(ty) => LLVMIntrinsic::Log2(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Log10(ty) => LLVMIntrinsic::Log10(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Copysign(ty) => LLVMIntrinsic::Copysign(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Floor(ty) => LLVMIntrinsic::Floor(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Ceil(ty) => LLVMIntrinsic::Ceil(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Trunc(ty) => LLVMIntrinsic::Trunc(ty.get_type(self.type_values)),
LLVMIntrinsicKind::RoundEven(ty) => LLVMIntrinsic::RoundEven(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Round(ty) => LLVMIntrinsic::Round(ty.get_type(self.type_values)),
})
.unwrap();
intrinsics.insert(kind, intrinsic.clone());
intrinsic
}
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@ -315,6 +315,16 @@ pub struct FunctionParam {
pub meta: Metadata, pub meta: Metadata,
} }
impl FunctionParam {
pub fn from<T: Into<String>>(name: T, ty: TypeKind) -> FunctionParam {
FunctionParam {
name: name.into(),
ty: ty,
meta: Default::default(),
}
}
}
pub enum SelfKind { pub enum SelfKind {
Borrow, Borrow,
MutBorrow, MutBorrow,

View File

@ -12,6 +12,7 @@ use std::{
use crate::{ use crate::{
mir::{ mir::{
implement::TypeCategory,
pass::{AssociatedFunctionKey, ScopeVariable}, pass::{AssociatedFunctionKey, ScopeVariable},
BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
IfExpression, Module, ReturnKind, StmtKind, TypeKind, VagueType, WhileStatement, IfExpression, Module, ReturnKind, StmtKind, TypeKind, VagueType, WhileStatement,
@ -627,12 +628,18 @@ impl Expression {
if backing_var.is_some() { if backing_var.is_some() {
if let TypeKind::Borrow(inner, _) = type_kind { if let TypeKind::Borrow(inner, _) = type_kind {
let ty_cat = inner.category();
if let TypeKind::Borrow(..) = *inner.clone() { if let TypeKind::Borrow(..) = *inner.clone() {
*type_kind = type_kind.unroll_borrow(); *type_kind = type_kind.unroll_borrow();
let ExprKind::Borrow(val, _) = &first_param.0 else { let ExprKind::Borrow(val, _) = &first_param.0 else {
panic!() panic!()
}; };
*first_param = *val.clone(); *first_param = *val.clone();
} else if ty_cat == TypeCategory::Integer || ty_cat == TypeCategory::Real {
if let ExprKind::Borrow(val, _) = &first_param.0 {
*first_param = *val.clone();
}
*type_kind = *inner.clone();
} }
} }
} else { } else {