Compare commits
No commits in common. "236032b8889f11687bb6744eb0c62ae7c5f6fbf7" and "4e714cb53b5c82f41a17b1e79a979c1e5a3010a2" have entirely different histories.
236032b888
...
4e714cb53b
@ -13,7 +13,7 @@ use super::*;
|
|||||||
pub struct Any<'ctx>(pub BasicTypeEnum<'ctx>);
|
pub struct Any<'ctx>(pub BasicTypeEnum<'ctx>);
|
||||||
|
|
||||||
impl<'ctx> ModelBase<'ctx> for Any<'ctx> {
|
impl<'ctx> ModelBase<'ctx> for Any<'ctx> {
|
||||||
fn llvm_type_impl(&self, _size_t: IntType<'ctx>, _ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
fn get_type_impl(&self, _size_t: IntType<'ctx>, _ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||||
self.0.as_basic_type_enum()
|
self.0.as_basic_type_enum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{fmt, marker::PhantomData};
|
use std::fmt;
|
||||||
|
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::Context,
|
context::Context,
|
||||||
@ -11,8 +11,8 @@ use crate::codegen::{CodeGenContext, CodeGenerator};
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Trait for Rust structs identifying length values for [`Array`].
|
/// Trait for Rust structs identifying length values for [`Array`].
|
||||||
pub trait ArrayLen: fmt::Debug + Clone + Copy {
|
pub trait LenKind: fmt::Debug + Clone + Copy {
|
||||||
fn length(&self) -> u32;
|
fn get_length(&self) -> u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A statically known length.
|
/// A statically known length.
|
||||||
@ -23,14 +23,14 @@ pub struct Len<const N: u32>;
|
|||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct AnyLen(pub u32);
|
pub struct AnyLen(pub u32);
|
||||||
|
|
||||||
impl<const N: u32> ArrayLen for Len<N> {
|
impl<const N: u32> LenKind for Len<N> {
|
||||||
fn length(&self) -> u32 {
|
fn get_length(&self) -> u32 {
|
||||||
N
|
N
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArrayLen for AnyLen {
|
impl LenKind for AnyLen {
|
||||||
fn length(&self) -> u32 {
|
fn get_length(&self) -> u32 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,24 +39,17 @@ impl ArrayLen for AnyLen {
|
|||||||
///
|
///
|
||||||
/// `Len` should be of a [`LenKind`] and `Item` should be a of [`Model`].
|
/// `Len` should be of a [`LenKind`] and `Item` should be a of [`Model`].
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct Array<'ctx, Len: ArrayLen, Item: ModelBase<'ctx>> {
|
pub struct Array<Len, Item> {
|
||||||
/// Length of this array.
|
/// Length of this array.
|
||||||
pub len: Len,
|
pub len: Len,
|
||||||
/// [`Model`] of the array items.
|
/// [`Model`] of the array items.
|
||||||
pub item: Item,
|
pub item: Item,
|
||||||
pub _phantom: PhantomData<&'ctx ()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, Len: ArrayLen, Item: ModelBase<'ctx>> Array<'ctx, Len, Item> {
|
impl<'ctx, Len: LenKind, Item: ModelBase<'ctx>> ModelBase<'ctx> for Array<Len, Item> {
|
||||||
pub fn new(len: Len, item: Item) -> Self {
|
fn get_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||||
Array { len, item, _phantom: PhantomData }
|
let item = self.item.get_type_impl(size_t, ctx);
|
||||||
}
|
item.array_type(self.len.get_length()).into()
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, Len: ArrayLen, Item: ModelBase<'ctx>> ModelBase<'ctx> for Array<'ctx, Len, Item> {
|
|
||||||
fn llvm_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
|
||||||
let item = self.item.llvm_type_impl(size_t, ctx);
|
|
||||||
item.array_type(self.len.length()).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_type_impl(
|
fn check_type_impl(
|
||||||
@ -69,11 +62,11 @@ impl<'ctx, Len: ArrayLen, Item: ModelBase<'ctx>> ModelBase<'ctx> for Array<'ctx,
|
|||||||
return Err(ModelError(format!("Expecting ArrayType, but got {ty:?}")));
|
return Err(ModelError(format!("Expecting ArrayType, but got {ty:?}")));
|
||||||
};
|
};
|
||||||
|
|
||||||
if ty.len() != self.len.length() {
|
if ty.len() != self.len.get_length() {
|
||||||
return Err(ModelError(format!(
|
return Err(ModelError(format!(
|
||||||
"Expecting ArrayType with size {}, but got an ArrayType with size {}",
|
"Expecting ArrayType with size {}, but got an ArrayType with size {}",
|
||||||
ty.len(),
|
ty.len(),
|
||||||
self.len.length()
|
self.len.get_length()
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,33 +78,33 @@ impl<'ctx, Len: ArrayLen, Item: ModelBase<'ctx>> ModelBase<'ctx> for Array<'ctx,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, Len: ArrayLen, Item: Model<'ctx>> Model<'ctx> for Array<'ctx, Len, Item> {
|
impl<'ctx, Len: LenKind, Item: Model<'ctx>> Model<'ctx> for Array<Len, Item> {
|
||||||
type Type = ArrayType<'ctx>;
|
type Type = ArrayType<'ctx>;
|
||||||
type Value = ArrayValue<'ctx>;
|
type Value = ArrayValue<'ctx>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, Len: ArrayLen, Item: Model<'ctx>> Instance<'ctx, Ptr<Array<'ctx, Len, Item>>> {
|
impl<'ctx, Len: LenKind, Item: Model<'ctx>> Instance<'ctx, Ptr<Array<Len, Item>>> {
|
||||||
/// Get the pointer to the `i`-th (0-based) array element.
|
/// Get the pointer to the `i`-th (0-based) array element.
|
||||||
pub fn gep(
|
pub fn gep(
|
||||||
&self,
|
&self,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
i: IntValue<'ctx>,
|
i: IntValue<'ctx>,
|
||||||
) -> Instance<'ctx, Ptr<Item>> {
|
) -> Instance<'ctx, Ptr<Item>> {
|
||||||
let zero = ctx.ctx.i64_type().const_zero();
|
let zero = ctx.ctx.i32_type().const_zero();
|
||||||
let ptr = unsafe { ctx.builder.build_in_bounds_gep(self.value, &[zero, i], "").unwrap() };
|
let ptr = unsafe { ctx.builder.build_in_bounds_gep(self.value, &[zero, i], "").unwrap() };
|
||||||
|
|
||||||
unsafe { Ptr::new(self.model.item.item).believe_value(ptr) }
|
Ptr(self.model.0.item).believe_value(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `gep` but `i` is a constant.
|
/// Like `gep` but `i` is a constant.
|
||||||
pub fn gep_const(&self, ctx: &CodeGenContext<'ctx, '_>, i: u64) -> Instance<'ctx, Ptr<Item>> {
|
pub fn gep_const(&self, ctx: &CodeGenContext<'ctx, '_>, i: u64) -> Instance<'ctx, Ptr<Item>> {
|
||||||
assert!(
|
assert!(
|
||||||
i < u64::from(self.model.item.len.length()),
|
i < u64::from(self.model.0.len.get_length()),
|
||||||
"Index {i} is out of bounds. Array length = {}",
|
"Index {i} is out of bounds. Array length = {}",
|
||||||
self.model.item.len.length()
|
self.model.0.len.get_length()
|
||||||
);
|
);
|
||||||
|
|
||||||
let i = ctx.ctx.i64_type().const_int(i, true);
|
let i = ctx.ctx.i32_type().const_int(i, false);
|
||||||
self.gep(ctx, i)
|
self.gep(ctx, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ use crate::codegen::{CodeGenContext, CodeGenerator};
|
|||||||
pub struct ModelError(pub String);
|
pub struct ModelError(pub String);
|
||||||
|
|
||||||
impl ModelError {
|
impl ModelError {
|
||||||
/// Append a context message to the error.
|
// Append a context message to the error.
|
||||||
pub(super) fn under_context(mut self, context: &str) -> Self {
|
pub(super) fn under_context(mut self, context: &str) -> Self {
|
||||||
self.0.push_str(" ... in ");
|
self.0.push_str(" ... in ");
|
||||||
self.0.push_str(context);
|
self.0.push_str(context);
|
||||||
@ -24,8 +24,8 @@ pub trait ModelBase<'ctx> {
|
|||||||
// NOTE: Taking `size_t` here instead of `CodeGenerator` to be object safe.
|
// NOTE: Taking `size_t` here instead of `CodeGenerator` to be object safe.
|
||||||
// In fact, all the entire model abstraction need from the `CodeGenerator` is its `get_size_type()`.
|
// In fact, all the entire model abstraction need from the `CodeGenerator` is its `get_size_type()`.
|
||||||
|
|
||||||
// NOTE: Model's llvm_type but object-safe and returns BasicTypeEnum, instead of a known BasicType variant.
|
// NOTE: Model's get_type but object-safe and returns BasicTypeEnum, instead of a known BasicType variant.
|
||||||
fn llvm_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx>;
|
fn get_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx>;
|
||||||
|
|
||||||
// NOTE: Model's check_type but object-safe.
|
// NOTE: Model's check_type but object-safe.
|
||||||
fn check_type_impl(
|
fn check_type_impl(
|
||||||
@ -45,7 +45,7 @@ pub trait ModelBase<'ctx> {
|
|||||||
/// - [`Int<AnyInt>`] identifies an [`IntType`] with bit-width of whatever is set in the [`AnyInt`] object.
|
/// - [`Int<AnyInt>`] identifies an [`IntType`] with bit-width of whatever is set in the [`AnyInt`] object.
|
||||||
/// - [`Any`] identifies a [`BasicType`] set in the [`Any`] object itself.
|
/// - [`Any`] identifies a [`BasicType`] set in the [`Any`] object itself.
|
||||||
///
|
///
|
||||||
/// You can get the [`BasicType`] out of a model with [`Model::llvm_type`].
|
/// You can get the [`BasicType`] out of a model with [`Model::get_type`].
|
||||||
///
|
///
|
||||||
/// Furthermore, [`Instance<'ctx, M>`] is a simple structure that carries a [`BasicValue`] with [`BasicType`] identified by model `M`.
|
/// Furthermore, [`Instance<'ctx, M>`] is a simple structure that carries a [`BasicValue`] with [`BasicType`] identified by model `M`.
|
||||||
///
|
///
|
||||||
@ -85,14 +85,10 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
|
|||||||
|
|
||||||
/// Return the [`BasicType`] of this model.
|
/// Return the [`BasicType`] of this model.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn llvm_type<G: CodeGenerator + ?Sized>(
|
fn get_type<G: CodeGenerator + ?Sized>(&self, generator: &G, ctx: &'ctx Context) -> Self::Type {
|
||||||
&self,
|
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
) -> Self::Type {
|
|
||||||
let size_t = generator.get_size_type(ctx);
|
let size_t = generator.get_size_type(ctx);
|
||||||
|
|
||||||
let ty = self.llvm_type_impl(size_t, ctx);
|
let ty = self.get_type_impl(size_t, ctx);
|
||||||
match Self::Type::try_from(ty) {
|
match Self::Type::try_from(ty) {
|
||||||
Ok(ty) => ty,
|
Ok(ty) => ty,
|
||||||
_ => panic!("Model::Type is inconsistent with what is returned from ModelBase::get_type_impl()! Got {ty:?}."),
|
_ => panic!("Model::Type is inconsistent with what is returned from ModelBase::get_type_impl()! Got {ty:?}."),
|
||||||
@ -100,12 +96,12 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the number of bytes of the [`BasicType`] of this model.
|
/// Get the number of bytes of the [`BasicType`] of this model.
|
||||||
fn size_of<G: CodeGenerator + ?Sized>(
|
fn sizeof<G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
self.llvm_type(generator, ctx).size_of().unwrap()
|
self.get_type(generator, ctx).size_of().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a [`BasicType`] matches the [`BasicType`] of this model.
|
/// Check if a [`BasicType`] matches the [`BasicType`] of this model.
|
||||||
@ -121,11 +117,9 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
|
|||||||
|
|
||||||
/// Create an instance from a value.
|
/// Create an instance from a value.
|
||||||
///
|
///
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Caller must make sure the type of `value` and the type of this `model` are equivalent.
|
/// Caller must make sure the type of `value` and the type of this `model` are equivalent.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
unsafe fn believe_value(&self, value: Self::Value) -> Instance<'ctx, Self> {
|
fn believe_value(&self, value: Self::Value) -> Instance<'ctx, Self> {
|
||||||
Instance { model: *self, value }
|
Instance { model: *self, value }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +138,7 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
|
|||||||
let Ok(value) = Self::Value::try_from(value) else {
|
let Ok(value) = Self::Value::try_from(value) else {
|
||||||
unreachable!("check_type() has bad implementation")
|
unreachable!("check_type() has bad implementation")
|
||||||
};
|
};
|
||||||
Ok(unsafe { self.believe_value(value) })
|
Ok(self.believe_value(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a value on the stack and return its pointer.
|
// Allocate a value on the stack and return its pointer.
|
||||||
@ -153,8 +147,8 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
) -> Instance<'ctx, Ptr<Self>> {
|
) -> Instance<'ctx, Ptr<Self>> {
|
||||||
let p = ctx.builder.build_alloca(self.llvm_type(generator, ctx.ctx), "").unwrap();
|
let p = ctx.builder.build_alloca(self.get_type(generator, ctx.ctx), "").unwrap();
|
||||||
unsafe { Ptr::new(*self).believe_value(p) }
|
Ptr(*self).believe_value(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate an array on the stack and return its pointer.
|
// Allocate an array on the stack and return its pointer.
|
||||||
@ -164,9 +158,8 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
|
|||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
len: IntValue<'ctx>,
|
len: IntValue<'ctx>,
|
||||||
) -> Instance<'ctx, Ptr<Self>> {
|
) -> Instance<'ctx, Ptr<Self>> {
|
||||||
let p =
|
let p = ctx.builder.build_array_alloca(self.get_type(generator, ctx.ctx), len, "").unwrap();
|
||||||
ctx.builder.build_array_alloca(self.llvm_type(generator, ctx.ctx), len, "").unwrap();
|
Ptr(*self).believe_value(p)
|
||||||
unsafe { Ptr::new(*self).believe_value(p) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn var_alloca<G: CodeGenerator + ?Sized>(
|
fn var_alloca<G: CodeGenerator + ?Sized>(
|
||||||
@ -175,9 +168,9 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
|
|||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
name: Option<&str>,
|
name: Option<&str>,
|
||||||
) -> Result<Instance<'ctx, Ptr<Self>>, String> {
|
) -> Result<Instance<'ctx, Ptr<Self>>, String> {
|
||||||
let ty = self.llvm_type(generator, ctx.ctx).as_basic_type_enum();
|
let ty = self.get_type(generator, ctx.ctx).as_basic_type_enum();
|
||||||
let p = generator.gen_var_alloc(ctx, ty, name)?;
|
let p = generator.gen_var_alloc(ctx, ty, name)?;
|
||||||
Ok(unsafe { Ptr::new(*self).believe_value(p) })
|
Ok(Ptr(*self).believe_value(p))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn array_var_alloca<G: CodeGenerator + ?Sized>(
|
fn array_var_alloca<G: CodeGenerator + ?Sized>(
|
||||||
@ -188,9 +181,9 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
|
|||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Result<Instance<'ctx, Ptr<Self>>, String> {
|
) -> Result<Instance<'ctx, Ptr<Self>>, String> {
|
||||||
// TODO: Remove ArraySliceValue
|
// TODO: Remove ArraySliceValue
|
||||||
let ty = self.llvm_type(generator, ctx.ctx).as_basic_type_enum();
|
let ty = self.get_type(generator, ctx.ctx).as_basic_type_enum();
|
||||||
let p = generator.gen_array_var_alloc(ctx, ty, len, name)?;
|
let p = generator.gen_array_var_alloc(ctx, ty, len, name)?;
|
||||||
Ok(unsafe { Ptr::new(*self).believe_value(PointerValue::from(p)) })
|
Ok(Ptr(*self).believe_value(PointerValue::from(p)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate a constant array.
|
/// Allocate a constant array.
|
||||||
@ -199,7 +192,7 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
values: &[Instance<'ctx, Self>],
|
values: &[Instance<'ctx, Self>],
|
||||||
) -> Instance<'ctx, Array<'ctx, AnyLen, Self>> {
|
) -> Instance<'ctx, Array<AnyLen, Self>> {
|
||||||
macro_rules! make {
|
macro_rules! make {
|
||||||
($t:expr, $into_value:expr) => {
|
($t:expr, $into_value:expr) => {
|
||||||
$t.const_array(
|
$t.const_array(
|
||||||
@ -211,7 +204,7 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = match self.llvm_type(generator, ctx).as_basic_type_enum() {
|
let value = match self.get_type(generator, ctx).as_basic_type_enum() {
|
||||||
BasicTypeEnum::ArrayType(t) => make!(t, BasicValueEnum::into_array_value),
|
BasicTypeEnum::ArrayType(t) => make!(t, BasicValueEnum::into_array_value),
|
||||||
BasicTypeEnum::IntType(t) => make!(t, BasicValueEnum::into_int_value),
|
BasicTypeEnum::IntType(t) => make!(t, BasicValueEnum::into_int_value),
|
||||||
BasicTypeEnum::FloatType(t) => make!(t, BasicValueEnum::into_float_value),
|
BasicTypeEnum::FloatType(t) => make!(t, BasicValueEnum::into_float_value),
|
||||||
@ -220,8 +213,9 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
|
|||||||
BasicTypeEnum::VectorType(t) => make!(t, BasicValueEnum::into_vector_value),
|
BasicTypeEnum::VectorType(t) => make!(t, BasicValueEnum::into_vector_value),
|
||||||
};
|
};
|
||||||
|
|
||||||
let model = Array::new(AnyLen(values.len() as u32), *self);
|
Array { len: AnyLen(values.len() as u32), item: *self }
|
||||||
model.check_value(generator, ctx, value).unwrap()
|
.check_value(generator, ctx, value)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +223,6 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
|
|||||||
pub struct Instance<'ctx, M: Model<'ctx>> {
|
pub struct Instance<'ctx, M: Model<'ctx>> {
|
||||||
/// The model of this instance.
|
/// The model of this instance.
|
||||||
pub model: M,
|
pub model: M,
|
||||||
|
|
||||||
/// The value of this instance.
|
/// The value of this instance.
|
||||||
///
|
///
|
||||||
/// It is guaranteed the [`BasicType`] of `value` is consistent with that of `model`.
|
/// It is guaranteed the [`BasicType`] of `value` is consistent with that of `model`.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{fmt, marker::PhantomData};
|
use std::fmt;
|
||||||
|
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::Context,
|
context::Context,
|
||||||
@ -9,7 +9,7 @@ use inkwell::{
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub trait FloatKind<'ctx>: fmt::Debug + Clone + Copy {
|
pub trait FloatKind<'ctx>: fmt::Debug + Clone + Copy {
|
||||||
fn float_type(&self, ctx: &'ctx Context) -> FloatType<'ctx>;
|
fn get_float_type(&self, ctx: &'ctx Context) -> FloatType<'ctx>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
@ -18,13 +18,13 @@ pub struct Float32;
|
|||||||
pub struct Float64;
|
pub struct Float64;
|
||||||
|
|
||||||
impl<'ctx> FloatKind<'ctx> for Float32 {
|
impl<'ctx> FloatKind<'ctx> for Float32 {
|
||||||
fn float_type(&self, ctx: &'ctx Context) -> FloatType<'ctx> {
|
fn get_float_type(&self, ctx: &'ctx Context) -> FloatType<'ctx> {
|
||||||
ctx.f32_type()
|
ctx.f32_type()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> FloatKind<'ctx> for Float64 {
|
impl<'ctx> FloatKind<'ctx> for Float64 {
|
||||||
fn float_type(&self, ctx: &'ctx Context) -> FloatType<'ctx> {
|
fn get_float_type(&self, ctx: &'ctx Context) -> FloatType<'ctx> {
|
||||||
ctx.f64_type()
|
ctx.f64_type()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,26 +33,17 @@ impl<'ctx> FloatKind<'ctx> for Float64 {
|
|||||||
pub struct AnyFloat<'ctx>(FloatType<'ctx>);
|
pub struct AnyFloat<'ctx>(FloatType<'ctx>);
|
||||||
|
|
||||||
impl<'ctx> FloatKind<'ctx> for AnyFloat<'ctx> {
|
impl<'ctx> FloatKind<'ctx> for AnyFloat<'ctx> {
|
||||||
fn float_type(&self, _ctx: &'ctx Context) -> FloatType<'ctx> {
|
fn get_float_type(&self, _ctx: &'ctx Context) -> FloatType<'ctx> {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct Float<'ctx, N: FloatKind<'ctx>> {
|
pub struct Float<N>(pub N);
|
||||||
kind: N,
|
|
||||||
_phantom: PhantomData<&'ctx ()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, N: FloatKind<'ctx>> Float<'ctx, N> {
|
impl<'ctx, N: FloatKind<'ctx>> ModelBase<'ctx> for Float<N> {
|
||||||
pub fn new(kind: N) -> Self {
|
fn get_type_impl(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||||
Float { kind, _phantom: PhantomData }
|
self.0.get_float_type(ctx).into()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, N: FloatKind<'ctx>> ModelBase<'ctx> for Float<'ctx, N> {
|
|
||||||
fn llvm_type_impl(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
|
||||||
self.kind.float_type(ctx).into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_type_impl(
|
fn check_type_impl(
|
||||||
@ -65,7 +56,7 @@ impl<'ctx, N: FloatKind<'ctx>> ModelBase<'ctx> for Float<'ctx, N> {
|
|||||||
return Err(ModelError(format!("Expecting FloatType, but got {ty:?}")));
|
return Err(ModelError(format!("Expecting FloatType, but got {ty:?}")));
|
||||||
};
|
};
|
||||||
|
|
||||||
let expected_ty = self.kind.float_type(ctx);
|
let expected_ty = self.0.get_float_type(ctx);
|
||||||
if ty != expected_ty {
|
if ty != expected_ty {
|
||||||
return Err(ModelError(format!("Expecting {expected_ty:?}, but got {ty:?}")));
|
return Err(ModelError(format!("Expecting {expected_ty:?}, but got {ty:?}")));
|
||||||
}
|
}
|
||||||
@ -74,7 +65,7 @@ impl<'ctx, N: FloatKind<'ctx>> ModelBase<'ctx> for Float<'ctx, N> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, N: FloatKind<'ctx>> Model<'ctx> for Float<'ctx, N> {
|
impl<'ctx, N: FloatKind<'ctx>> Model<'ctx> for Float<N> {
|
||||||
type Value = FloatValue<'ctx>;
|
type Value = FloatValue<'ctx>;
|
||||||
type Type = FloatType<'ctx>;
|
type Type = FloatType<'ctx>;
|
||||||
}
|
}
|
||||||
|
@ -35,20 +35,20 @@ struct Arg<'ctx> {
|
|||||||
/// If `my_function_name` has not been declared in `ctx.module`, once `.returning()` is called, a function
|
/// If `my_function_name` has not been declared in `ctx.module`, once `.returning()` is called, a function
|
||||||
/// declaration of `my_function_name` is added to `ctx.module`, where the [`FunctionType`] is deduced from
|
/// declaration of `my_function_name` is added to `ctx.module`, where the [`FunctionType`] is deduced from
|
||||||
/// the argument types and returning type.
|
/// the argument types and returning type.
|
||||||
pub struct FnCall<'ctx, 'a, 'b, G: CodeGenerator + ?Sized> {
|
pub struct CallFunction<'ctx, 'a, 'b, 'c, 'd, G: CodeGenerator + ?Sized> {
|
||||||
generator: &'b mut G,
|
generator: &'d mut G,
|
||||||
ctx: &'b CodeGenContext<'ctx, 'a>,
|
ctx: &'b CodeGenContext<'ctx, 'a>,
|
||||||
/// Function name
|
/// Function name
|
||||||
name: &'b str,
|
name: &'c str,
|
||||||
/// Call arguments
|
/// Call arguments
|
||||||
args: Vec<Arg<'ctx>>,
|
args: Vec<Arg<'ctx>>,
|
||||||
/// LLVM function Attributes
|
/// LLVM function Attributes
|
||||||
attrs: Vec<&'static str>,
|
attrs: Vec<&'static str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, 'a, 'b, G: CodeGenerator + ?Sized> FnCall<'ctx, 'a, 'b, G> {
|
impl<'ctx, 'a, 'b, 'c, 'd, G: CodeGenerator + ?Sized> CallFunction<'ctx, 'a, 'b, 'c, 'd, G> {
|
||||||
pub fn begin(generator: &'b mut G, ctx: &'b CodeGenContext<'ctx, 'a>, name: &'b str) -> Self {
|
pub fn begin(generator: &'d mut G, ctx: &'b CodeGenContext<'ctx, 'a>, name: &'c str) -> Self {
|
||||||
FnCall { generator, ctx, name, args: Vec::new(), attrs: Vec::new() }
|
CallFunction { generator, ctx, name, args: Vec::new(), attrs: Vec::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push a list of LLVM function attributes to the function declaration.
|
/// Push a list of LLVM function attributes to the function declaration.
|
||||||
@ -63,7 +63,7 @@ impl<'ctx, 'a, 'b, G: CodeGenerator + ?Sized> FnCall<'ctx, 'a, 'b, G> {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn arg<M: Model<'ctx>>(mut self, arg: Instance<'ctx, M>) -> Self {
|
pub fn arg<M: Model<'ctx>>(mut self, arg: Instance<'ctx, M>) -> Self {
|
||||||
let arg = Arg {
|
let arg = Arg {
|
||||||
ty: arg.model.llvm_type(self.generator, self.ctx.ctx).as_basic_type_enum().into(),
|
ty: arg.model.get_type(self.generator, self.ctx.ctx).as_basic_type_enum().into(),
|
||||||
val: arg.value.as_basic_value_enum().into(),
|
val: arg.value.as_basic_value_enum().into(),
|
||||||
};
|
};
|
||||||
self.args.push(arg);
|
self.args.push(arg);
|
||||||
@ -73,7 +73,7 @@ impl<'ctx, 'a, 'b, G: CodeGenerator + ?Sized> FnCall<'ctx, 'a, 'b, G> {
|
|||||||
/// Call the function and expect the function to return a value of type of `return_model`.
|
/// Call the function and expect the function to return a value of type of `return_model`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn returning<M: Model<'ctx>>(self, name: &str, return_model: M) -> Instance<'ctx, M> {
|
pub fn returning<M: Model<'ctx>>(self, name: &str, return_model: M) -> Instance<'ctx, M> {
|
||||||
let ret_ty = return_model.llvm_type(self.generator, self.ctx.ctx);
|
let ret_ty = return_model.get_type(self.generator, self.ctx.ctx);
|
||||||
|
|
||||||
let ret = self.call(|tys| ret_ty.fn_type(tys, false), name);
|
let ret = self.call(|tys| ret_ty.fn_type(tys, false), name);
|
||||||
let ret = BasicValueEnum::try_from(ret.as_any_value_enum()).unwrap(); // Must work
|
let ret = BasicValueEnum::try_from(ret.as_any_value_enum()).unwrap(); // Must work
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{cmp::Ordering, fmt, marker::PhantomData};
|
use std::{cmp::Ordering, fmt};
|
||||||
|
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::Context,
|
context::Context,
|
||||||
@ -12,7 +12,7 @@ use crate::codegen::{CodeGenContext, CodeGenerator};
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub trait IntKind<'ctx>: fmt::Debug + Clone + Copy {
|
pub trait IntKind<'ctx>: fmt::Debug + Clone + Copy {
|
||||||
fn int_type(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx>;
|
fn get_int_type(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
@ -27,31 +27,31 @@ pub struct Int64;
|
|||||||
pub struct SizeT;
|
pub struct SizeT;
|
||||||
|
|
||||||
impl<'ctx> IntKind<'ctx> for Bool {
|
impl<'ctx> IntKind<'ctx> for Bool {
|
||||||
fn int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> {
|
fn get_int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> {
|
||||||
ctx.bool_type()
|
ctx.bool_type()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> IntKind<'ctx> for Byte {
|
impl<'ctx> IntKind<'ctx> for Byte {
|
||||||
fn int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> {
|
fn get_int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> {
|
||||||
ctx.i8_type()
|
ctx.i8_type()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> IntKind<'ctx> for Int32 {
|
impl<'ctx> IntKind<'ctx> for Int32 {
|
||||||
fn int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> {
|
fn get_int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> {
|
||||||
ctx.i32_type()
|
ctx.i32_type()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> IntKind<'ctx> for Int64 {
|
impl<'ctx> IntKind<'ctx> for Int64 {
|
||||||
fn int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> {
|
fn get_int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> {
|
||||||
ctx.i64_type()
|
ctx.i64_type()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> IntKind<'ctx> for SizeT {
|
impl<'ctx> IntKind<'ctx> for SizeT {
|
||||||
fn int_type(&self, size_t: IntType<'ctx>, _ctx: &'ctx Context) -> IntType<'ctx> {
|
fn get_int_type(&self, size_t: IntType<'ctx>, _ctx: &'ctx Context) -> IntType<'ctx> {
|
||||||
size_t
|
size_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,20 +60,17 @@ impl<'ctx> IntKind<'ctx> for SizeT {
|
|||||||
pub struct AnyInt<'ctx>(pub IntType<'ctx>);
|
pub struct AnyInt<'ctx>(pub IntType<'ctx>);
|
||||||
|
|
||||||
impl<'ctx> IntKind<'ctx> for AnyInt<'ctx> {
|
impl<'ctx> IntKind<'ctx> for AnyInt<'ctx> {
|
||||||
fn int_type(&self, _size_t: IntType<'ctx>, _ctx: &'ctx Context) -> IntType<'ctx> {
|
fn get_int_type(&self, _size_t: IntType<'ctx>, _ctx: &'ctx Context) -> IntType<'ctx> {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct Int<'ctx, N: IntKind<'ctx>> {
|
pub struct Int<N>(pub N);
|
||||||
kind: N,
|
|
||||||
_phantom: PhantomData<&'ctx ()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, N: IntKind<'ctx>> ModelBase<'ctx> for Int<'ctx, N> {
|
impl<'ctx, N: IntKind<'ctx>> ModelBase<'ctx> for Int<N> {
|
||||||
fn llvm_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
fn get_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||||
self.kind.int_type(size_t, ctx).into()
|
self.0.get_int_type(size_t, ctx).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_type_impl(
|
fn check_type_impl(
|
||||||
@ -86,7 +83,7 @@ impl<'ctx, N: IntKind<'ctx>> ModelBase<'ctx> for Int<'ctx, N> {
|
|||||||
return Err(ModelError(format!("Expecting IntType, but got {ty:?}")));
|
return Err(ModelError(format!("Expecting IntType, but got {ty:?}")));
|
||||||
};
|
};
|
||||||
|
|
||||||
let exp_ty = self.kind.int_type(size_t, ctx);
|
let exp_ty = self.0.get_int_type(size_t, ctx);
|
||||||
if ty.get_bit_width() != exp_ty.get_bit_width() {
|
if ty.get_bit_width() != exp_ty.get_bit_width() {
|
||||||
return Err(ModelError(format!(
|
return Err(ModelError(format!(
|
||||||
"Expecting IntType to have {} bit(s), but got {} bit(s)",
|
"Expecting IntType to have {} bit(s), but got {} bit(s)",
|
||||||
@ -99,25 +96,20 @@ impl<'ctx, N: IntKind<'ctx>> ModelBase<'ctx> for Int<'ctx, N> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, N: IntKind<'ctx>> Model<'ctx> for Int<'ctx, N> {
|
impl<'ctx, N: IntKind<'ctx>> Model<'ctx> for Int<N> {
|
||||||
type Type = IntType<'ctx>;
|
type Type = IntType<'ctx>;
|
||||||
type Value = IntValue<'ctx>;
|
type Value = IntValue<'ctx>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
|
impl<'ctx, N: IntKind<'ctx>> Int<N> {
|
||||||
pub fn new(kind: N) -> Self {
|
|
||||||
Int { kind, _phantom: PhantomData }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn const_int<G: CodeGenerator + ?Sized>(
|
pub fn const_int<G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
value: u64,
|
value: u64,
|
||||||
sign_extend: bool,
|
|
||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
let value = self.llvm_type(generator, ctx).const_int(value, sign_extend);
|
let value = self.get_type(generator, ctx).const_int(value, false);
|
||||||
unsafe { self.believe_value(value) }
|
self.believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn const_0<G: CodeGenerator + ?Sized>(
|
pub fn const_0<G: CodeGenerator + ?Sized>(
|
||||||
@ -125,8 +117,8 @@ impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
let value = self.llvm_type(generator, ctx).const_zero();
|
let value = self.get_type(generator, ctx).const_zero();
|
||||||
unsafe { self.believe_value(value) }
|
self.believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn const_1<G: CodeGenerator + ?Sized>(
|
pub fn const_1<G: CodeGenerator + ?Sized>(
|
||||||
@ -134,7 +126,7 @@ impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
self.const_int(generator, ctx, 1, false)
|
self.const_int(generator, ctx, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn const_all_ones<G: CodeGenerator + ?Sized>(
|
pub fn const_all_ones<G: CodeGenerator + ?Sized>(
|
||||||
@ -142,8 +134,8 @@ impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
let value = self.llvm_type(generator, ctx).const_all_ones();
|
let value = self.get_type(generator, ctx).const_all_ones();
|
||||||
unsafe { self.believe_value(value) }
|
self.believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn s_extend_or_bit_cast<G: CodeGenerator + ?Sized>(
|
pub fn s_extend_or_bit_cast<G: CodeGenerator + ?Sized>(
|
||||||
@ -154,13 +146,13 @@ impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
|
|||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
assert!(
|
assert!(
|
||||||
value.get_type().get_bit_width()
|
value.get_type().get_bit_width()
|
||||||
<= self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
|
<= self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
|
||||||
);
|
);
|
||||||
let value = ctx
|
let value = ctx
|
||||||
.builder
|
.builder
|
||||||
.build_int_s_extend_or_bit_cast(value, self.llvm_type(generator, ctx.ctx), "")
|
.build_int_s_extend_or_bit_cast(value, self.get_type(generator, ctx.ctx), "")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
unsafe { self.believe_value(value) }
|
self.believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn s_extend<G: CodeGenerator + ?Sized>(
|
pub fn s_extend<G: CodeGenerator + ?Sized>(
|
||||||
@ -171,11 +163,11 @@ impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
|
|||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
assert!(
|
assert!(
|
||||||
value.get_type().get_bit_width()
|
value.get_type().get_bit_width()
|
||||||
< self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
|
< self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
|
||||||
);
|
);
|
||||||
let value =
|
let value =
|
||||||
ctx.builder.build_int_s_extend(value, self.llvm_type(generator, ctx.ctx), "").unwrap();
|
ctx.builder.build_int_s_extend(value, self.get_type(generator, ctx.ctx), "").unwrap();
|
||||||
unsafe { self.believe_value(value) }
|
self.believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn z_extend_or_bit_cast<G: CodeGenerator + ?Sized>(
|
pub fn z_extend_or_bit_cast<G: CodeGenerator + ?Sized>(
|
||||||
@ -186,13 +178,13 @@ impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
|
|||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
assert!(
|
assert!(
|
||||||
value.get_type().get_bit_width()
|
value.get_type().get_bit_width()
|
||||||
<= self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
|
<= self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
|
||||||
);
|
);
|
||||||
let value = ctx
|
let value = ctx
|
||||||
.builder
|
.builder
|
||||||
.build_int_z_extend_or_bit_cast(value, self.llvm_type(generator, ctx.ctx), "")
|
.build_int_z_extend_or_bit_cast(value, self.get_type(generator, ctx.ctx), "")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
unsafe { self.believe_value(value) }
|
self.believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn z_extend<G: CodeGenerator + ?Sized>(
|
pub fn z_extend<G: CodeGenerator + ?Sized>(
|
||||||
@ -203,11 +195,11 @@ impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
|
|||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
assert!(
|
assert!(
|
||||||
value.get_type().get_bit_width()
|
value.get_type().get_bit_width()
|
||||||
< self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
|
< self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
|
||||||
);
|
);
|
||||||
let value =
|
let value =
|
||||||
ctx.builder.build_int_z_extend(value, self.llvm_type(generator, ctx.ctx), "").unwrap();
|
ctx.builder.build_int_z_extend(value, self.get_type(generator, ctx.ctx), "").unwrap();
|
||||||
unsafe { self.believe_value(value) }
|
self.believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn truncate_or_bit_cast<G: CodeGenerator + ?Sized>(
|
pub fn truncate_or_bit_cast<G: CodeGenerator + ?Sized>(
|
||||||
@ -218,13 +210,13 @@ impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
|
|||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
assert!(
|
assert!(
|
||||||
value.get_type().get_bit_width()
|
value.get_type().get_bit_width()
|
||||||
>= self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
|
>= self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
|
||||||
);
|
);
|
||||||
let value = ctx
|
let value = ctx
|
||||||
.builder
|
.builder
|
||||||
.build_int_truncate_or_bit_cast(value, self.llvm_type(generator, ctx.ctx), "")
|
.build_int_truncate_or_bit_cast(value, self.get_type(generator, ctx.ctx), "")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
unsafe { self.believe_value(value) }
|
self.believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn truncate<G: CodeGenerator + ?Sized>(
|
pub fn truncate<G: CodeGenerator + ?Sized>(
|
||||||
@ -235,11 +227,11 @@ impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
|
|||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
assert!(
|
assert!(
|
||||||
value.get_type().get_bit_width()
|
value.get_type().get_bit_width()
|
||||||
> self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
|
> self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
|
||||||
);
|
);
|
||||||
let value =
|
let value =
|
||||||
ctx.builder.build_int_truncate(value, self.llvm_type(generator, ctx.ctx), "").unwrap();
|
ctx.builder.build_int_truncate(value, self.get_type(generator, ctx.ctx), "").unwrap();
|
||||||
unsafe { self.believe_value(value) }
|
self.believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `sext` or `trunc` an int to this model's int type. Does nothing if equal bit-widths.
|
/// `sext` or `trunc` an int to this model's int type. Does nothing if equal bit-widths.
|
||||||
@ -251,10 +243,10 @@ impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
|
|||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
let their_width = value.get_type().get_bit_width();
|
let their_width = value.get_type().get_bit_width();
|
||||||
let our_width =
|
let our_width =
|
||||||
self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width();
|
self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width();
|
||||||
match their_width.cmp(&our_width) {
|
match their_width.cmp(&our_width) {
|
||||||
Ordering::Less => self.s_extend(generator, ctx, value),
|
Ordering::Less => self.s_extend(generator, ctx, value),
|
||||||
Ordering::Equal => unsafe { self.believe_value(value) },
|
Ordering::Equal => self.believe_value(value),
|
||||||
Ordering::Greater => self.truncate(generator, ctx, value),
|
Ordering::Greater => self.truncate(generator, ctx, value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,43 +260,43 @@ impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
|
|||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
let their_width = value.get_type().get_bit_width();
|
let their_width = value.get_type().get_bit_width();
|
||||||
let our_width =
|
let our_width =
|
||||||
self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width();
|
self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width();
|
||||||
match their_width.cmp(&our_width) {
|
match their_width.cmp(&our_width) {
|
||||||
Ordering::Less => self.z_extend(generator, ctx, value),
|
Ordering::Less => self.z_extend(generator, ctx, value),
|
||||||
Ordering::Equal => unsafe { self.believe_value(value) },
|
Ordering::Equal => self.believe_value(value),
|
||||||
Ordering::Greater => self.truncate(generator, ctx, value),
|
Ordering::Greater => self.truncate(generator, ctx, value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> Int<'ctx, Bool> {
|
impl Int<Bool> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn const_false<G: CodeGenerator + ?Sized>(
|
pub fn const_false<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
self.const_int(generator, ctx, 0, false)
|
self.const_int(generator, ctx, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn const_true<G: CodeGenerator + ?Sized>(
|
pub fn const_true<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
) -> Instance<'ctx, Self> {
|
) -> Instance<'ctx, Self> {
|
||||||
self.const_int(generator, ctx, 1, false)
|
self.const_int(generator, ctx, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<'ctx, N>> {
|
impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<N>> {
|
||||||
pub fn s_extend_or_bit_cast<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
pub fn s_extend_or_bit_cast<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
to_int_kind: NewN,
|
to_int_kind: NewN,
|
||||||
) -> Instance<'ctx, Int<'ctx, NewN>> {
|
) -> Instance<'ctx, Int<NewN>> {
|
||||||
Int::new(to_int_kind).s_extend_or_bit_cast(generator, ctx, self.value)
|
Int(to_int_kind).s_extend_or_bit_cast(generator, ctx, self.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn s_extend<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
pub fn s_extend<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
||||||
@ -312,8 +304,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<'ctx, N>> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
to_int_kind: NewN,
|
to_int_kind: NewN,
|
||||||
) -> Instance<'ctx, Int<'ctx, NewN>> {
|
) -> Instance<'ctx, Int<NewN>> {
|
||||||
Int::new(to_int_kind).s_extend(generator, ctx, self.value)
|
Int(to_int_kind).s_extend(generator, ctx, self.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn z_extend_or_bit_cast<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
pub fn z_extend_or_bit_cast<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
||||||
@ -321,8 +313,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<'ctx, N>> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
to_int_kind: NewN,
|
to_int_kind: NewN,
|
||||||
) -> Instance<'ctx, Int<'ctx, NewN>> {
|
) -> Instance<'ctx, Int<NewN>> {
|
||||||
Int::new(to_int_kind).z_extend_or_bit_cast(generator, ctx, self.value)
|
Int(to_int_kind).z_extend_or_bit_cast(generator, ctx, self.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn z_extend<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
pub fn z_extend<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
||||||
@ -330,8 +322,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<'ctx, N>> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
to_int_kind: NewN,
|
to_int_kind: NewN,
|
||||||
) -> Instance<'ctx, Int<'ctx, NewN>> {
|
) -> Instance<'ctx, Int<NewN>> {
|
||||||
Int::new(to_int_kind).z_extend(generator, ctx, self.value)
|
Int(to_int_kind).z_extend(generator, ctx, self.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn truncate_or_bit_cast<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
pub fn truncate_or_bit_cast<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
||||||
@ -339,8 +331,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<'ctx, N>> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
to_int_kind: NewN,
|
to_int_kind: NewN,
|
||||||
) -> Instance<'ctx, Int<'ctx, NewN>> {
|
) -> Instance<'ctx, Int<NewN>> {
|
||||||
Int::new(to_int_kind).truncate_or_bit_cast(generator, ctx, self.value)
|
Int(to_int_kind).truncate_or_bit_cast(generator, ctx, self.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn truncate<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
pub fn truncate<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
||||||
@ -348,8 +340,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<'ctx, N>> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
to_int_kind: NewN,
|
to_int_kind: NewN,
|
||||||
) -> Instance<'ctx, Int<'ctx, NewN>> {
|
) -> Instance<'ctx, Int<NewN>> {
|
||||||
Int::new(to_int_kind).truncate(generator, ctx, self.value)
|
Int(to_int_kind).truncate(generator, ctx, self.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn s_extend_or_truncate<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
pub fn s_extend_or_truncate<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
||||||
@ -357,8 +349,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<'ctx, N>> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
to_int_kind: NewN,
|
to_int_kind: NewN,
|
||||||
) -> Instance<'ctx, Int<'ctx, NewN>> {
|
) -> Instance<'ctx, Int<NewN>> {
|
||||||
Int::new(to_int_kind).s_extend_or_truncate(generator, ctx, self.value)
|
Int(to_int_kind).s_extend_or_truncate(generator, ctx, self.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn z_extend_or_truncate<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
pub fn z_extend_or_truncate<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
|
||||||
@ -366,26 +358,26 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<'ctx, N>> {
|
|||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
to_int_kind: NewN,
|
to_int_kind: NewN,
|
||||||
) -> Instance<'ctx, Int<'ctx, NewN>> {
|
) -> Instance<'ctx, Int<NewN>> {
|
||||||
Int::new(to_int_kind).z_extend_or_truncate(generator, ctx, self.value)
|
Int(to_int_kind).z_extend_or_truncate(generator, ctx, self.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn add(&self, ctx: &CodeGenContext<'ctx, '_>, other: Self) -> Self {
|
pub fn add(&self, ctx: &CodeGenContext<'ctx, '_>, other: Self) -> Self {
|
||||||
let value = ctx.builder.build_int_add(self.value, other.value, "").unwrap();
|
let value = ctx.builder.build_int_add(self.value, other.value, "").unwrap();
|
||||||
unsafe { self.model.believe_value(value) }
|
self.model.believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn sub(&self, ctx: &CodeGenContext<'ctx, '_>, other: Self) -> Self {
|
pub fn sub(&self, ctx: &CodeGenContext<'ctx, '_>, other: Self) -> Self {
|
||||||
let value = ctx.builder.build_int_sub(self.value, other.value, "").unwrap();
|
let value = ctx.builder.build_int_sub(self.value, other.value, "").unwrap();
|
||||||
unsafe { self.model.believe_value(value) }
|
self.model.believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn mul(&self, ctx: &CodeGenContext<'ctx, '_>, other: Self) -> Self {
|
pub fn mul(&self, ctx: &CodeGenContext<'ctx, '_>, other: Self) -> Self {
|
||||||
let value = ctx.builder.build_int_mul(self.value, other.value, "").unwrap();
|
let value = ctx.builder.build_int_mul(self.value, other.value, "").unwrap();
|
||||||
unsafe { self.model.believe_value(value) }
|
self.model.believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compare(
|
pub fn compare(
|
||||||
@ -393,8 +385,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<'ctx, N>> {
|
|||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
op: IntPredicate,
|
op: IntPredicate,
|
||||||
other: Self,
|
other: Self,
|
||||||
) -> Instance<'ctx, Int<'ctx, Bool>> {
|
) -> Instance<'ctx, Int<Bool>> {
|
||||||
let value = ctx.builder.build_int_compare(op, self.value, other.value, "").unwrap();
|
let value = ctx.builder.build_int_compare(op, self.value, other.value, "").unwrap();
|
||||||
unsafe { Int::new(Bool).believe_value(value) }
|
Int(Bool).believe_value(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,32 +15,22 @@ use super::*;
|
|||||||
///
|
///
|
||||||
// TODO: LLVM 15: `Item` is a Rust type-hint for the LLVM type of value the `.store()/.load()` family
|
// TODO: LLVM 15: `Item` is a Rust type-hint for the LLVM type of value the `.store()/.load()` family
|
||||||
// of functions return. If a truly opaque pointer is needed, tell the programmer to use `OpaquePtr`.
|
// of functions return. If a truly opaque pointer is needed, tell the programmer to use `OpaquePtr`.
|
||||||
//
|
|
||||||
// NOTE: Do not put `Item: ModelBase<'ctx>`. See the LLVM 15 note above.
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct Ptr<Item> {
|
pub struct Ptr<Item>(pub Item);
|
||||||
pub item: Item,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An opaque pointer. Like [`Ptr`] but without any Rust type-hints about its element type.
|
/// An opaque pointer. Like [`Ptr`] but without any Rust type-hints about its element type.
|
||||||
///
|
///
|
||||||
/// `.load()/.store()` is not available for [`Instance`]s of opaque pointers.
|
/// `.load()/.store()` is not available for [`Instance`]s of opaque pointers.
|
||||||
pub type OpaquePtr = Ptr<()>;
|
pub type OpaquePtr = Ptr<()>;
|
||||||
|
|
||||||
impl<Item> Ptr<Item> {
|
|
||||||
pub fn new(item: Item) -> Self {
|
|
||||||
Ptr { item }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: LLVM 15: `Item: ModelBase<'ctx>` don't even need to be a model anymore. It will only be
|
// TODO: LLVM 15: `Item: ModelBase<'ctx>` don't even need to be a model anymore. It will only be
|
||||||
// a type-hint for the `.load()/.store()` functions for the `pointee_ty`.
|
// a type-hint for the `.load()/.store()` functions for the `pointee_ty`.
|
||||||
//
|
//
|
||||||
// See https://thedan64.github.io/inkwell/inkwell/builder/struct.Builder.html#method.build_load.
|
// See https://thedan64.github.io/inkwell/inkwell/builder/struct.Builder.html#method.build_load.
|
||||||
impl<'ctx, Item: ModelBase<'ctx>> ModelBase<'ctx> for Ptr<Item> {
|
impl<'ctx, Item: ModelBase<'ctx>> ModelBase<'ctx> for Ptr<Item> {
|
||||||
fn llvm_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
fn get_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||||
// TODO: LLVM 15: ctx.ptr_type(AddressSpace::default())
|
// TODO: LLVM 15: ctx.ptr_type(AddressSpace::default())
|
||||||
let item = self.item.llvm_type_impl(size_t, ctx);
|
let item = self.0.get_type_impl(size_t, ctx);
|
||||||
item.ptr_type(AddressSpace::default()).into()
|
item.ptr_type(AddressSpace::default()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +53,7 @@ impl<'ctx, Item: ModelBase<'ctx>> ModelBase<'ctx> for Ptr<Item> {
|
|||||||
|
|
||||||
// TODO: inkwell `get_element_type()` will be deprecated.
|
// TODO: inkwell `get_element_type()` will be deprecated.
|
||||||
// Remove the check for `get_element_type()` when the time comes.
|
// Remove the check for `get_element_type()` when the time comes.
|
||||||
self.item
|
self.0
|
||||||
.check_type_impl(size_t, ctx, elem_ty)
|
.check_type_impl(size_t, ctx, elem_ty)
|
||||||
.map_err(|err| err.under_context("a PointerType"))?;
|
.map_err(|err| err.under_context("a PointerType"))?;
|
||||||
|
|
||||||
@ -84,8 +74,8 @@ impl<'ctx, Item: Model<'ctx>> Ptr<Item> {
|
|||||||
ctx: &'ctx Context,
|
ctx: &'ctx Context,
|
||||||
) -> Instance<'ctx, Ptr<Item>> {
|
) -> Instance<'ctx, Ptr<Item>> {
|
||||||
// TODO: LLVM 15: Write in an impl where `Item` does not have to be `Model<'ctx>`.
|
// TODO: LLVM 15: Write in an impl where `Item` does not have to be `Model<'ctx>`.
|
||||||
let ptr = self.llvm_type(generator, ctx).const_null();
|
let ptr = self.get_type(generator, ctx).const_null();
|
||||||
unsafe { self.believe_value(ptr) }
|
self.believe_value(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cast a pointer into this model with [`inkwell::builder::Builder::build_pointer_cast`]
|
/// Cast a pointer into this model with [`inkwell::builder::Builder::build_pointer_cast`]
|
||||||
@ -100,9 +90,9 @@ impl<'ctx, Item: Model<'ctx>> Ptr<Item> {
|
|||||||
// ```
|
// ```
|
||||||
// return self.believe_value(ptr);
|
// return self.believe_value(ptr);
|
||||||
// ```
|
// ```
|
||||||
let t = self.llvm_type(generator, ctx.ctx);
|
let t = self.get_type(generator, ctx.ctx);
|
||||||
let ptr = ctx.builder.build_pointer_cast(ptr, t, "").unwrap();
|
let ptr = ctx.builder.build_pointer_cast(ptr, t, "").unwrap();
|
||||||
unsafe { self.believe_value(ptr) }
|
self.believe_value(ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +105,7 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
|
|||||||
offset: IntValue<'ctx>,
|
offset: IntValue<'ctx>,
|
||||||
) -> Instance<'ctx, Ptr<Item>> {
|
) -> Instance<'ctx, Ptr<Item>> {
|
||||||
let p = unsafe { ctx.builder.build_in_bounds_gep(self.value, &[offset], "").unwrap() };
|
let p = unsafe { ctx.builder.build_in_bounds_gep(self.value, &[offset], "").unwrap() };
|
||||||
unsafe { self.model.believe_value(p) }
|
self.model.believe_value(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Offset the pointer by [`inkwell::builder::Builder::build_in_bounds_gep`] by a constant offset.
|
/// Offset the pointer by [`inkwell::builder::Builder::build_in_bounds_gep`] by a constant offset.
|
||||||
@ -123,9 +113,9 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
|
|||||||
pub fn offset_const(
|
pub fn offset_const(
|
||||||
&self,
|
&self,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
offset: i64,
|
offset: u64,
|
||||||
) -> Instance<'ctx, Ptr<Item>> {
|
) -> Instance<'ctx, Ptr<Item>> {
|
||||||
let offset = ctx.ctx.i64_type().const_int(offset as u64, true);
|
let offset = ctx.ctx.i32_type().const_int(offset, false);
|
||||||
self.offset(ctx, offset)
|
self.offset(ctx, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +131,7 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
|
|||||||
pub fn set_index_const(
|
pub fn set_index_const(
|
||||||
&self,
|
&self,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
index: i64,
|
index: u64,
|
||||||
value: Instance<'ctx, Item>,
|
value: Instance<'ctx, Item>,
|
||||||
) {
|
) {
|
||||||
self.offset_const(ctx, index).store(ctx, value);
|
self.offset_const(ctx, index).store(ctx, value);
|
||||||
@ -160,7 +150,7 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
|
|||||||
&self,
|
&self,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
index: i64,
|
index: u64,
|
||||||
) -> Instance<'ctx, Item> {
|
) -> Instance<'ctx, Item> {
|
||||||
self.offset_const(ctx, index).load(generator, ctx)
|
self.offset_const(ctx, index).load(generator, ctx)
|
||||||
}
|
}
|
||||||
@ -172,7 +162,7 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
|
|||||||
ctx: &CodeGenContext<'ctx, '_>,
|
ctx: &CodeGenContext<'ctx, '_>,
|
||||||
) -> Instance<'ctx, Item> {
|
) -> Instance<'ctx, Item> {
|
||||||
let value = ctx.builder.build_load(self.value, "").unwrap();
|
let value = ctx.builder.build_load(self.value, "").unwrap();
|
||||||
self.model.item.check_value(generator, ctx.ctx, value).unwrap() // If unwrap() panics, there is a logic error.
|
self.model.0.check_value(generator, ctx.ctx, value).unwrap() // If unwrap() panics, there is a logic error.
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Store a value with [`inkwell::builder::Builder::build_store`].
|
/// Store a value with [`inkwell::builder::Builder::build_store`].
|
||||||
@ -188,19 +178,19 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
|
|||||||
new_item: NewItem,
|
new_item: NewItem,
|
||||||
) -> Instance<'ctx, Ptr<NewItem>> {
|
) -> Instance<'ctx, Ptr<NewItem>> {
|
||||||
// TODO: LLVM 15: Write in an impl where `Item` does not have to be `Model<'ctx>`.
|
// TODO: LLVM 15: Write in an impl where `Item` does not have to be `Model<'ctx>`.
|
||||||
Ptr::new(new_item).pointer_cast(generator, ctx, self.value)
|
Ptr(new_item).pointer_cast(generator, ctx, self.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the pointer is null with [`inkwell::builder::Builder::build_is_null`].
|
/// Check if the pointer is null with [`inkwell::builder::Builder::build_is_null`].
|
||||||
pub fn is_null(&self, ctx: &CodeGenContext<'ctx, '_>) -> Instance<'ctx, Int<'ctx, Bool>> {
|
pub fn is_null(&self, ctx: &CodeGenContext<'ctx, '_>) -> Instance<'ctx, Int<Bool>> {
|
||||||
let value = ctx.builder.build_is_null(self.value, "").unwrap();
|
let value = ctx.builder.build_is_null(self.value, "").unwrap();
|
||||||
unsafe { Int::new(Bool).believe_value(value) }
|
Int(Bool).believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the pointer is not null with [`inkwell::builder::Builder::build_is_not_null`].
|
/// Check if the pointer is not null with [`inkwell::builder::Builder::build_is_not_null`].
|
||||||
pub fn is_not_null(&self, ctx: &CodeGenContext<'ctx, '_>) -> Instance<'ctx, Int<'ctx, Bool>> {
|
pub fn is_not_null(&self, ctx: &CodeGenContext<'ctx, '_>) -> Instance<'ctx, Int<Bool>> {
|
||||||
let value = ctx.builder.build_is_not_null(self.value, "").unwrap();
|
let value = ctx.builder.build_is_not_null(self.value, "").unwrap();
|
||||||
unsafe { Int::new(Bool).believe_value(value) }
|
Int(Bool).believe_value(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `memcpy` from another pointer.
|
/// `memcpy` from another pointer.
|
||||||
@ -212,9 +202,9 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
|
|||||||
num_items: IntValue<'ctx>,
|
num_items: IntValue<'ctx>,
|
||||||
) {
|
) {
|
||||||
// Force extend `num_items` and `itemsize` to `i64` so their types would match.
|
// Force extend `num_items` and `itemsize` to `i64` so their types would match.
|
||||||
let itemsize = self.model.size_of(generator, ctx.ctx);
|
let itemsize = self.model.sizeof(generator, ctx.ctx);
|
||||||
let itemsize = Int::new(Int64).z_extend_or_truncate(generator, ctx, itemsize);
|
let itemsize = Int(Int64).z_extend_or_truncate(generator, ctx, itemsize);
|
||||||
let num_items = Int::new(Int64).z_extend_or_truncate(generator, ctx, num_items);
|
let num_items = Int(Int64).z_extend_or_truncate(generator, ctx, num_items);
|
||||||
let totalsize = itemsize.mul(ctx, num_items);
|
let totalsize = itemsize.mul(ctx, num_items);
|
||||||
|
|
||||||
let is_volatile = ctx.ctx.bool_type().const_zero(); // is_volatile = false
|
let is_volatile = ctx.ctx.bool_type().const_zero(); // is_volatile = false
|
||||||
|
@ -72,21 +72,29 @@ pub trait StructKind<'ctx>: fmt::Debug + Clone + Copy {
|
|||||||
/// Get the LLVM [`StructType`] of this [`StructKind`].
|
/// Get the LLVM [`StructType`] of this [`StructKind`].
|
||||||
fn get_struct_type(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> StructType<'ctx> {
|
fn get_struct_type(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> StructType<'ctx> {
|
||||||
let entries = self.entries();
|
let entries = self.entries();
|
||||||
let entries =
|
let entries = entries.into_iter().map(|t| t.model.get_type_impl(size_t, ctx)).collect_vec();
|
||||||
entries.into_iter().map(|t| t.model.llvm_type_impl(size_t, ctx)).collect_vec();
|
|
||||||
ctx.struct_type(&entries, false)
|
ctx.struct_type(&entries, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct Struct<'ctx, S: StructKind<'ctx>> {
|
pub struct Struct<S>(pub S);
|
||||||
pub kind: S,
|
|
||||||
_phantom: PhantomData<&'ctx ()>,
|
impl<'ctx, S: StructKind<'ctx>> Struct<S> {
|
||||||
|
pub fn const_struct<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
fields: &[BasicValueEnum<'ctx>],
|
||||||
|
) -> Instance<'ctx, Self> {
|
||||||
|
let val = ctx.const_struct(fields, false);
|
||||||
|
self.check_value(generator, ctx, val).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, S: StructKind<'ctx>> ModelBase<'ctx> for Struct<'ctx, S> {
|
impl<'ctx, S: StructKind<'ctx>> ModelBase<'ctx> for Struct<S> {
|
||||||
fn llvm_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
fn get_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
|
||||||
self.kind.get_struct_type(size_t, ctx).as_basic_type_enum()
|
self.0.get_struct_type(size_t, ctx).as_basic_type_enum()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_type_impl(
|
fn check_type_impl(
|
||||||
@ -99,7 +107,7 @@ impl<'ctx, S: StructKind<'ctx>> ModelBase<'ctx> for Struct<'ctx, S> {
|
|||||||
return Err(ModelError(format!("Expecting StructType, but got {ty:?}")));
|
return Err(ModelError(format!("Expecting StructType, but got {ty:?}")));
|
||||||
};
|
};
|
||||||
|
|
||||||
let entries = self.kind.entries();
|
let entries = self.0.entries();
|
||||||
let field_types = ty.get_field_types();
|
let field_types = ty.get_field_types();
|
||||||
|
|
||||||
// Check the number of fields.
|
// Check the number of fields.
|
||||||
@ -123,28 +131,12 @@ impl<'ctx, S: StructKind<'ctx>> ModelBase<'ctx> for Struct<'ctx, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, S: StructKind<'ctx>> Model<'ctx> for Struct<'ctx, S> {
|
impl<'ctx, S: StructKind<'ctx>> Model<'ctx> for Struct<S> {
|
||||||
type Type = StructType<'ctx>;
|
type Type = StructType<'ctx>;
|
||||||
type Value = StructValue<'ctx>;
|
type Value = StructValue<'ctx>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, S: StructKind<'ctx>> Struct<'ctx, S> {
|
impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Struct<S>> {
|
||||||
pub fn new(kind: S) -> Self {
|
|
||||||
Struct { kind, _phantom: PhantomData }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn const_struct<G: CodeGenerator + ?Sized>(
|
|
||||||
&self,
|
|
||||||
generator: &mut G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
fields: &[BasicValueEnum<'ctx>],
|
|
||||||
) -> Instance<'ctx, Self> {
|
|
||||||
let val = ctx.const_struct(fields, false);
|
|
||||||
self.check_value(generator, ctx, val).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Struct<'ctx, S>> {
|
|
||||||
/// Get a field with [`StructValue::get_field_at_index`].
|
/// Get a field with [`StructValue::get_field_at_index`].
|
||||||
pub fn get_field<G: CodeGenerator + ?Sized, M, GetField>(
|
pub fn get_field<G: CodeGenerator + ?Sized, M, GetField>(
|
||||||
&self,
|
&self,
|
||||||
@ -156,13 +148,13 @@ impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Struct<'ctx, S>> {
|
|||||||
M: Model<'ctx>,
|
M: Model<'ctx>,
|
||||||
GetField: FnOnce(S::Fields) -> Field<M>,
|
GetField: FnOnce(S::Fields) -> Field<M>,
|
||||||
{
|
{
|
||||||
let field = get_field(self.model.kind.fields());
|
let field = get_field(self.model.0.fields());
|
||||||
let val = self.value.get_field_at_index(field.gep_index).unwrap();
|
let val = self.value.get_field_at_index(field.gep_index).unwrap();
|
||||||
field.model.check_value(generator, ctx, val).unwrap()
|
field.model.check_value(generator, ctx, val).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Ptr<Struct<'ctx, S>>> {
|
impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Ptr<Struct<S>>> {
|
||||||
/// Get a pointer to a field with [`Builder::build_in_bounds_gep`].
|
/// Get a pointer to a field with [`Builder::build_in_bounds_gep`].
|
||||||
pub fn gep<M, GetField>(
|
pub fn gep<M, GetField>(
|
||||||
&self,
|
&self,
|
||||||
@ -173,7 +165,7 @@ impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Ptr<Struct<'ctx, S>>> {
|
|||||||
M: Model<'ctx>,
|
M: Model<'ctx>,
|
||||||
GetField: FnOnce(S::Fields) -> Field<M>,
|
GetField: FnOnce(S::Fields) -> Field<M>,
|
||||||
{
|
{
|
||||||
let field = get_field(self.model.item.kind.fields());
|
let field = get_field(self.model.0 .0.fields());
|
||||||
let llvm_i32 = ctx.ctx.i32_type();
|
let llvm_i32 = ctx.ctx.i32_type();
|
||||||
|
|
||||||
let ptr = unsafe {
|
let ptr = unsafe {
|
||||||
@ -186,7 +178,7 @@ impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Ptr<Struct<'ctx, S>>> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe { Ptr::new(field.model).believe_value(ptr) }
|
Ptr(field.model).believe_value(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience function equivalent to `.gep(...).load(...)`.
|
/// Convenience function equivalent to `.gep(...).load(...)`.
|
||||||
@ -222,19 +214,19 @@ impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Ptr<Struct<'ctx, S>>> {
|
|||||||
// Example: NDArray.
|
// Example: NDArray.
|
||||||
//
|
//
|
||||||
// Compared to List, it has no generic models.
|
// Compared to List, it has no generic models.
|
||||||
pub struct NDArrayFields<'ctx> {
|
pub struct NDArrayFields {
|
||||||
data: Field<Ptr<Int<'ctx, Byte>>>,
|
data: Field<Ptr<Int<Byte>>>,
|
||||||
itemsize: Field<Int<'ctx, SizeT>>,
|
itemsize: Field<Int<SizeT>>,
|
||||||
ndims: Field<Int<'ctx, SizeT>>,
|
ndims: Field<Int<SizeT>>,
|
||||||
shape: Field<Ptr<Int<'ctx, SizeT>>>,
|
shape: Field<Ptr<Int<SizeT>>>,
|
||||||
strides: Field<Ptr<Int<'ctx, SizeT>>>,
|
strides: Field<Ptr<Int<SizeT>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
struct NDArray;
|
struct NDArray;
|
||||||
|
|
||||||
impl<'ctx> StructKind<'ctx> for NDArray {
|
impl<'ctx> StructKind<'ctx> for NDArray {
|
||||||
type Fields = NDArrayFields<'ctx>;
|
type Fields = NDArrayFields;
|
||||||
|
|
||||||
fn iter_fields(&self, mapper: &mut FieldMapper<'ctx>) -> Self::Fields {
|
fn iter_fields(&self, mapper: &mut FieldMapper<'ctx>) -> Self::Fields {
|
||||||
NDArrayFields {
|
NDArrayFields {
|
||||||
@ -252,7 +244,7 @@ impl<'ctx> StructKind<'ctx> for NDArray {
|
|||||||
// Compared to NDArray, it has generic models.
|
// Compared to NDArray, it has generic models.
|
||||||
pub struct ListFields<'ctx, Item: Model<'ctx>> {
|
pub struct ListFields<'ctx, Item: Model<'ctx>> {
|
||||||
items: Field<Ptr<Item>>,
|
items: Field<Ptr<Item>>,
|
||||||
len: Field<Int<'ctx, SizeT>>,
|
len: Field<Int<SizeT>>,
|
||||||
_phantom: PhantomData<&'ctx ()>,
|
_phantom: PhantomData<&'ctx ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,7 +259,7 @@ impl<'ctx, Item: Model<'ctx> + 'ctx> StructKind<'ctx> for List<'ctx, Item> {
|
|||||||
|
|
||||||
fn iter_fields(&self, mapper: &mut FieldMapper<'ctx>) -> Self::Fields {
|
fn iter_fields(&self, mapper: &mut FieldMapper<'ctx>) -> Self::Fields {
|
||||||
ListFields {
|
ListFields {
|
||||||
items: mapper.add("items", Ptr::new(self.item)),
|
items: mapper.add("items", Ptr(self.item)),
|
||||||
len: mapper.add_auto("len"),
|
len: mapper.add_auto("len"),
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user