841 lines
29 KiB
Rust
841 lines
29 KiB
Rust
use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValueKind, Instr, Type};
|
|
|
|
use crate::{
|
|
codegen::{ErrorKind, StackValueKind},
|
|
mir::{
|
|
implement::TypeCategory, BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition,
|
|
FunctionDefinitionKind, FunctionParam, TypeKind,
|
|
},
|
|
};
|
|
|
|
use super::scope::{Scope, StackValue};
|
|
|
|
const INTEGERS: [TypeKind; 10] = [
|
|
TypeKind::U8,
|
|
TypeKind::U16,
|
|
TypeKind::U32,
|
|
TypeKind::U64,
|
|
TypeKind::U128,
|
|
TypeKind::I8,
|
|
TypeKind::I16,
|
|
TypeKind::I32,
|
|
TypeKind::I64,
|
|
TypeKind::I128,
|
|
];
|
|
|
|
const FLOATS: [TypeKind; 7] = [
|
|
TypeKind::F16,
|
|
TypeKind::F32,
|
|
TypeKind::F32B,
|
|
TypeKind::F64,
|
|
TypeKind::F80,
|
|
TypeKind::F128,
|
|
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 MALLOC_IDENT: &str = "malloc";
|
|
|
|
pub fn form_intrinsics() -> Vec<FunctionDefinition> {
|
|
let mut intrinsics = Vec::new();
|
|
|
|
intrinsics.push(FunctionDefinition {
|
|
name: MALLOC_IDENT.to_owned(),
|
|
linkage_name: Some("malloc".to_owned()),
|
|
is_pub: false,
|
|
is_imported: true,
|
|
return_type: TypeKind::UserPtr(Box::new(TypeKind::U8)),
|
|
parameters: vec![FunctionParam {
|
|
name: "size".to_owned(),
|
|
ty: TypeKind::U64,
|
|
meta: Default::default(),
|
|
}],
|
|
kind: FunctionDefinitionKind::Extern(false),
|
|
source: None,
|
|
signature_meta: Default::default(),
|
|
});
|
|
|
|
intrinsics
|
|
}
|
|
|
|
pub fn simple_intrinsic<T: Into<String> + Clone>(
|
|
name: T,
|
|
params: Vec<T>,
|
|
ret: TypeKind,
|
|
intrisic: LLVMIntrinsicKind,
|
|
) -> FunctionDefinition {
|
|
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_functions(ty: &TypeKind) -> Vec<FunctionDefinition> {
|
|
let mut intrinsics = Vec::new();
|
|
if let TypeKind::Array(_, len) = ty {
|
|
intrinsics.push(FunctionDefinition {
|
|
name: "length".to_owned(),
|
|
linkage_name: None,
|
|
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,
|
|
is_pub: true,
|
|
is_imported: false,
|
|
return_type: ty.clone(),
|
|
parameters: vec![FunctionParam {
|
|
name: String::from("self"),
|
|
ty: ty.clone(),
|
|
meta: Default::default(),
|
|
}],
|
|
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,
|
|
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(),
|
|
});
|
|
|
|
intrinsics.push(FunctionDefinition {
|
|
name: "memcpy".to_owned(),
|
|
linkage_name: None,
|
|
is_pub: true,
|
|
is_imported: false,
|
|
return_type: TypeKind::Void,
|
|
parameters: vec![
|
|
FunctionParam {
|
|
name: String::from("destination"),
|
|
ty: TypeKind::UserPtr(Box::new(ty.clone())),
|
|
meta: Default::default(),
|
|
},
|
|
FunctionParam {
|
|
name: String::from("source"),
|
|
ty: TypeKind::UserPtr(Box::new(ty.clone())),
|
|
meta: Default::default(),
|
|
},
|
|
FunctionParam {
|
|
name: String::from("length"),
|
|
ty: TypeKind::U64,
|
|
meta: Default::default(),
|
|
},
|
|
],
|
|
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicMemcpy(ty.clone()))),
|
|
source: None,
|
|
signature_meta: Default::default(),
|
|
});
|
|
|
|
intrinsics.push(FunctionDefinition {
|
|
name: "null".to_owned(),
|
|
linkage_name: None,
|
|
is_pub: true,
|
|
is_imported: false,
|
|
return_type: TypeKind::UserPtr(Box::new(ty.clone())),
|
|
parameters: Vec::new(),
|
|
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicNullPtr(ty.clone()))),
|
|
source: 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
|
|
where
|
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
|
{
|
|
BinopDefinition {
|
|
lhs: FunctionParam {
|
|
name: "lhs".to_owned(),
|
|
ty: ty.clone(),
|
|
meta: Default::default(),
|
|
},
|
|
op,
|
|
rhs: FunctionParam {
|
|
name: "rhs".to_owned(),
|
|
ty: ty.clone(),
|
|
meta: Default::default(),
|
|
},
|
|
return_type: ty.clone(),
|
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleBinaryInstr(fun))),
|
|
meta: Default::default(),
|
|
exported: false,
|
|
}
|
|
}
|
|
|
|
fn complex_binop_def<T: Clone + 'static>(op: BinaryOperator, lhs: &TypeKind, rhs: &TypeKind, fun: T) -> BinopDefinition
|
|
where
|
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
|
{
|
|
BinopDefinition {
|
|
lhs: FunctionParam {
|
|
name: "lhs".to_owned(),
|
|
ty: lhs.clone(),
|
|
meta: Default::default(),
|
|
},
|
|
op,
|
|
rhs: FunctionParam {
|
|
name: "rhs".to_owned(),
|
|
ty: rhs.clone(),
|
|
meta: Default::default(),
|
|
},
|
|
return_type: lhs.clone(),
|
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleBinaryInstr(fun))),
|
|
meta: Default::default(),
|
|
exported: false,
|
|
}
|
|
}
|
|
|
|
fn boolean_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition
|
|
where
|
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
|
{
|
|
BinopDefinition {
|
|
lhs: FunctionParam {
|
|
name: "lhs".to_owned(),
|
|
ty: ty.clone(),
|
|
meta: Default::default(),
|
|
},
|
|
op,
|
|
rhs: FunctionParam {
|
|
name: "rhs".to_owned(),
|
|
ty: ty.clone(),
|
|
meta: Default::default(),
|
|
},
|
|
return_type: TypeKind::Bool,
|
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicBooleanInstr(fun))),
|
|
meta: Default::default(),
|
|
exported: false,
|
|
}
|
|
}
|
|
|
|
pub fn form_intrinsic_binops() -> Vec<BinopDefinition> {
|
|
let mut intrinsics = Vec::new();
|
|
|
|
use BinaryOperator::*;
|
|
|
|
for ty in INTEGERS {
|
|
intrinsics.push(simple_binop_def(Add, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::Add(lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(simple_binop_def(Mult, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::Mul(lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(simple_binop_def(Minus, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::Sub(lhs, rhs)).unwrap()
|
|
}));
|
|
if ty.signed() {
|
|
intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::SDiv(lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| {
|
|
let div = scope.block.build(Instr::SDiv(lhs, rhs)).unwrap();
|
|
let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap();
|
|
scope.block.build(Instr::Sub(lhs, mul)).unwrap()
|
|
}));
|
|
} else {
|
|
intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::UDiv(lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| {
|
|
let div = scope.block.build(Instr::UDiv(lhs, rhs)).unwrap();
|
|
let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap();
|
|
scope.block.build(Instr::Sub(lhs, mul)).unwrap()
|
|
}));
|
|
}
|
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GT), &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::ICmp(CmpPredicate::GT, lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GE), &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::ICmp(CmpPredicate::GE, lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LT), &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::ICmp(CmpPredicate::LT, lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LE), &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::ICmp(CmpPredicate::LE, lhs, rhs)).unwrap()
|
|
}));
|
|
|
|
// Bitwise operations
|
|
intrinsics.push(simple_binop_def(BitOr, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::Or(lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(simple_binop_def(BitAnd, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::And(lhs, rhs)).unwrap()
|
|
}));
|
|
|
|
intrinsics.push(complex_binop_def(Xor, &ty, &TypeKind::U64, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::XOr(lhs, rhs)).unwrap()
|
|
}));
|
|
if ty.signed() {
|
|
intrinsics.push(complex_binop_def(BitshiftRight, &ty, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::ShiftRightArithmetic(lhs, rhs)).unwrap()
|
|
}));
|
|
} else {
|
|
intrinsics.push(complex_binop_def(BitshiftRight, &ty, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::ShiftRightLogical(lhs, rhs)).unwrap()
|
|
}));
|
|
}
|
|
intrinsics.push(complex_binop_def(BitshiftLeft, &ty, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::ShiftLeft(lhs, rhs)).unwrap()
|
|
}));
|
|
}
|
|
for ty in INTEGERS.iter().chain(&[TypeKind::Bool, TypeKind::Char]) {
|
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::ICmp(CmpPredicate::EQ, lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::NE), &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::ICmp(CmpPredicate::NE, lhs, rhs)).unwrap()
|
|
}));
|
|
}
|
|
for ty in FLOATS {
|
|
intrinsics.push(simple_binop_def(BinaryOperator::Add, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::FAdd(lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(simple_binop_def(BinaryOperator::Mult, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::FMul(lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(simple_binop_def(BinaryOperator::Minus, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::FSub(lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::FDiv(lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| {
|
|
let div = scope.block.build(Instr::FDiv(lhs, rhs)).unwrap();
|
|
let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap();
|
|
scope.block.build(Instr::Sub(lhs, mul)).unwrap()
|
|
}));
|
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::FCmp(CmpPredicate::EQ, lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::NE), &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::FCmp(CmpPredicate::NE, lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GT), &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::FCmp(CmpPredicate::GT, lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GE), &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::FCmp(CmpPredicate::GE, lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LT), &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::FCmp(CmpPredicate::LT, lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LE), &ty, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::FCmp(CmpPredicate::LE, lhs, rhs)).unwrap()
|
|
}));
|
|
}
|
|
|
|
intrinsics.push(boolean_binop_def(And, &TypeKind::Bool, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::And(lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(boolean_binop_def(Or, &TypeKind::Bool, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::Or(lhs, rhs)).unwrap()
|
|
}));
|
|
intrinsics.push(boolean_binop_def(Xor, &TypeKind::Bool, |scope, lhs, rhs| {
|
|
scope.block.build(Instr::XOr(lhs, rhs)).unwrap()
|
|
}));
|
|
|
|
intrinsics
|
|
}
|
|
|
|
pub trait IntrinsicFunction: std::fmt::Debug {
|
|
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind>;
|
|
}
|
|
|
|
macro_rules! intrinsic_debug {
|
|
($kind:ty, $name:literal) => {
|
|
impl<T> std::fmt::Debug for $kind
|
|
where
|
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
|
{
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_tuple($name).finish()
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
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
|
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
|
|
intrinsic_debug!(IntrinsicSimpleBinaryInstr<T>, "IntrinsicSimpleBinaryInstr");
|
|
|
|
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleBinaryInstr<T>
|
|
where
|
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
|
{
|
|
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
|
let lhs = params.get(0).unwrap();
|
|
let rhs = params.get(1).unwrap();
|
|
let instr = self.clone().0(scope, lhs.instr(), rhs.instr());
|
|
Ok(StackValue(StackValueKind::Literal(instr), lhs.1.clone()))
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct IntrinsicBooleanInstr<T>(T)
|
|
where
|
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
|
|
intrinsic_debug!(IntrinsicBooleanInstr<T>, "IntrinsicBooleanInstr");
|
|
|
|
impl<T: Clone> IntrinsicFunction for IntrinsicBooleanInstr<T>
|
|
where
|
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
|
{
|
|
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
|
let lhs = params.get(0).unwrap();
|
|
let rhs = params.get(1).unwrap();
|
|
let instr = self.clone().0(scope, lhs.instr(), rhs.instr());
|
|
Ok(StackValue(StackValueKind::Literal(instr), TypeKind::Bool))
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct IntrinsicSizeOf(TypeKind);
|
|
impl IntrinsicFunction for IntrinsicSizeOf {
|
|
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
|
let instr = scope
|
|
.block
|
|
.build(Instr::Constant(reid_lib::ConstValueKind::U64(
|
|
self.0.size_of(&scope.type_map) / 8,
|
|
)))
|
|
.unwrap();
|
|
Ok(StackValue(StackValueKind::Literal(instr), self.0.clone()))
|
|
}
|
|
}
|
|
|
|
#[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)]
|
|
pub struct IntrinsicMalloc(TypeKind);
|
|
impl IntrinsicFunction for IntrinsicMalloc {
|
|
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
|
let amount = params.get(0).unwrap();
|
|
let function = scope
|
|
.block
|
|
.find_function(&format!("{}.{}", INTRINSIC_IDENT, MALLOC_IDENT))
|
|
.unwrap();
|
|
|
|
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, amount.instr())).unwrap();
|
|
let instr = scope.block.build(Instr::FunctionCall(function, vec![bytes])).unwrap();
|
|
Ok(StackValue(StackValueKind::Literal(instr), self.0.clone()))
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct IntrinsicNullPtr(TypeKind);
|
|
impl IntrinsicFunction for IntrinsicNullPtr {
|
|
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
|
let zero = scope.block.build(Instr::Constant(ConstValueKind::I8(0))).unwrap();
|
|
let instr = scope
|
|
.block
|
|
.build(Instr::IntToPtr(
|
|
zero,
|
|
Type::Ptr(Box::new(self.0.get_type(scope.type_values))),
|
|
))
|
|
.unwrap();
|
|
Ok(StackValue(
|
|
StackValueKind::Literal(instr),
|
|
TypeKind::UserPtr(Box::new(self.0.clone())),
|
|
))
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct IntrinsicConst(u64);
|
|
impl IntrinsicFunction for IntrinsicConst {
|
|
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
|
let zero = scope.block.build(Instr::Constant(ConstValueKind::U64(self.0))).unwrap();
|
|
Ok(StackValue(StackValueKind::Literal(zero), TypeKind::U64))
|
|
}
|
|
}
|
|
|
|
#[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 {
|
|
// fn codegen<'ctx, 'a>(
|
|
// &self,
|
|
// scope: &mut Scope<'ctx, 'a>,
|
|
// params: &[InstructionValue],
|
|
// ) -> Result<StackValue, ErrorKind> {
|
|
// let lhs = params.get(0).unwrap();
|
|
// let rhs = params.get(1).unwrap();
|
|
// let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
|
|
// Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
|
// }
|
|
// }
|
|
|
|
// #[derive(Debug, Clone)]
|
|
// pub struct IntrinsicIAdd(TypeKind);
|
|
|
|
// impl IntrinsicFunction for IntrinsicIAdd {
|
|
// fn codegen<'ctx, 'a>(
|
|
// &self,
|
|
// scope: &mut Scope<'ctx, 'a>,
|
|
// params: &[InstructionValue],
|
|
// ) -> Result<StackValue, ErrorKind> {
|
|
// let lhs = params.get(0).unwrap();
|
|
// let rhs = params.get(1).unwrap();
|
|
// let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
|
|
// Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
|
// }
|
|
// }
|
|
|
|
// #[derive(Debug, Clone)]
|
|
// pub struct IntrinsicUDiv(TypeKind);
|
|
|
|
// impl IntrinsicFunction for IntrinsicUDiv {
|
|
// fn codegen<'ctx, 'a>(
|
|
// &self,
|
|
// scope: &mut Scope<'ctx, 'a>,
|
|
// params: &[InstructionValue],
|
|
// ) -> Result<StackValue, ErrorKind> {
|
|
// let lhs = params.get(0).unwrap();
|
|
// let rhs = params.get(1).unwrap();
|
|
// let add = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
|
|
// Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
|
// }
|
|
// }
|
|
|
|
// #[derive(Debug, Clone)]
|
|
// pub struct IntrinsicUMod(TypeKind);
|
|
|
|
// impl IntrinsicFunction for IntrinsicUMod {
|
|
// fn codegen<'ctx, 'a>(
|
|
// &self,
|
|
// scope: &mut Scope<'ctx, 'a>,
|
|
// params: &[InstructionValue],
|
|
// ) -> Result<StackValue, ErrorKind> {
|
|
// let lhs = params.get(0).unwrap();
|
|
// let rhs = params.get(1).unwrap();
|
|
// let div = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
|
|
// let mul = scope.block.build(Instr::Mul(*rhs, div)).unwrap();
|
|
// let sub = scope.block.build(Instr::Sub(*lhs, mul)).unwrap();
|
|
// Ok(StackValue(StackValueKind::Literal(sub), self.0.clone()))
|
|
// }
|
|
// }
|