Skip to content

Commit

Permalink
feat(codegen): add AsValue macro support for enums
Browse files Browse the repository at this point in the history
  • Loading branch information
Wodann committed Oct 23, 2020
1 parent 087d022 commit 41256ee
Show file tree
Hide file tree
Showing 10 changed files with 704 additions and 37 deletions.
1 change: 1 addition & 0 deletions crates/mun_codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ categories = ["Game development", "Mun"]

[dependencies]
abi = { version = "=0.2.0", path = "../mun_abi", package = "mun_abi" }
bytemuck = "1.4.1"
hir = { version = "=0.2.0", path = "../mun_hir", package = "mun_hir" }
itertools = "0.9.0"
mun_codegen_macros = { path = "../mun_codegen_macros", package = "mun_codegen_macros" }
Expand Down
18 changes: 17 additions & 1 deletion crates/mun_codegen/src/ir/types.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::value::{AsValue, IrValueContext, SizedValueType, TransparentValue, Value};
use crate::value::{AsValue, BytesOrPtr, IrValueContext, SizedValueType, TransparentValue, Value};
use itertools::Itertools;
use mun_codegen_macros::AsValue;

Expand All @@ -8,6 +8,10 @@ impl<'ink> TransparentValue<'ink> for abi::Guid {
fn as_target_value(&self, context: &IrValueContext<'ink, '_, '_>) -> Value<'ink, Self::Target> {
self.0.as_value(context)
}

fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![BytesOrPtr::Bytes(self.0.to_vec())]
}
}

impl<'ink> TransparentValue<'ink> for abi::Privacy {
Expand All @@ -16,6 +20,10 @@ impl<'ink> TransparentValue<'ink> for abi::Privacy {
fn as_target_value(&self, context: &IrValueContext<'ink, '_, '_>) -> Value<'ink, Self::Target> {
(*self as u8).as_value(context)
}

fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![BytesOrPtr::Bytes(vec![*self as u8])]
}
}

impl<'ink> TransparentValue<'ink> for abi::TypeGroup {
Expand All @@ -24,6 +32,10 @@ impl<'ink> TransparentValue<'ink> for abi::TypeGroup {
fn as_target_value(&self, context: &IrValueContext<'ink, '_, '_>) -> Value<'ink, Self::Target> {
(*self as u8).as_value(context)
}

fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![BytesOrPtr::Bytes(vec![*self as u8])]
}
}

impl<'ink> TransparentValue<'ink> for abi::StructMemoryKind {
Expand All @@ -32,6 +44,10 @@ impl<'ink> TransparentValue<'ink> for abi::StructMemoryKind {
fn as_target_value(&self, context: &IrValueContext<'ink, '_, '_>) -> Value<'ink, Self::Target> {
(self.clone() as u8).as_value(context)
}

fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![BytesOrPtr::Bytes(vec![self.clone() as u8])]
}
}

#[derive(AsValue)]
Expand Down
20 changes: 14 additions & 6 deletions crates/mun_codegen/src/value/array_value.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::value::{
AddressableType, AsValue, ConcreteValueType, IrTypeContext, IrValueContext, PointerValueType,
SizedValueType, TypeValue, Value, ValueType,
use super::{
AddressableType, AsValue, ConcreteValueType, HasConstValue, IrTypeContext, IrValueContext,
PointerValueType, SizedValueType, TypeValue, Value, ValueType,
};
use inkwell::{
types::{BasicType, PointerType},
values::PointerValue,
AddressSpace,
};
use inkwell::types::{BasicType, PointerType};
use inkwell::values::PointerValue;
use inkwell::AddressSpace;

impl<'ink, T: ConcreteValueType<'ink>> ConcreteValueType<'ink> for [T] {
type Value = inkwell::values::ArrayValue<'ink>;
Expand Down Expand Up @@ -91,6 +93,12 @@ impl_array!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80, 0x100
);

impl<'ink, T: ConcreteValueType<'ink> + HasConstValue> HasConstValue for &[T] {
fn has_const_value() -> bool {
T::has_const_value()
}
}

impl<'ink, E: SizedValueType<'ink>, T: AsValue<'ink, E>> AsValue<'ink, [E]> for &[T]
where
E::Value: ConstArrayValue<'ink>,
Expand Down
30 changes: 27 additions & 3 deletions crates/mun_codegen/src/value/float_value.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use super::{
AsValue, ConcreteValueType, IrTypeContext, IrValueContext, PointerValueType, SizedValueType,
Value,
AddressableType, AsBytesAndPtrs, AsValue, BytesOrPtr, ConcreteValueType, HasConstValue,
IrTypeContext, IrValueContext, PointerValueType, SizedValueType, Value,
};
use crate::value::AddressableType;
use inkwell::{types::PointerType, AddressSpace};

impl<'ink> ConcreteValueType<'ink> for f32 {
Expand Down Expand Up @@ -44,17 +43,42 @@ impl<'ink> PointerValueType<'ink> for f64 {
impl<'ink> AddressableType<'ink, f32> for f32 {}
impl<'ink> AddressableType<'ink, f64> for f64 {}

impl HasConstValue for f32 {
fn has_const_value() -> bool {
true
}
}

impl HasConstValue for f64 {
fn has_const_value() -> bool {
true
}
}

impl<'ink> AsValue<'ink, f32> for f32 {
fn as_value(&self, context: &IrValueContext<'ink, '_, '_>) -> Value<'ink, f32> {
Value::from_raw(
<Self as SizedValueType>::get_ir_type(context.type_context).const_float(*self as f64),
)
}
}

impl<'ink> AsValue<'ink, f64> for f64 {
fn as_value(&self, context: &IrValueContext<'ink, '_, '_>) -> Value<'ink, f64> {
Value::from_raw(
<Self as SizedValueType>::get_ir_type(context.type_context).const_float(*self),
)
}
}

impl<'ink> AsBytesAndPtrs<'ink> for f32 {
fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![bytemuck::cast_ref::<f32, [u8; 4]>(self).to_vec().into()]
}
}

impl<'ink> AsBytesAndPtrs<'ink> for f64 {
fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![bytemuck::cast_ref::<f64, [u8; 8]>(self).to_vec().into()]
}
}
58 changes: 56 additions & 2 deletions crates/mun_codegen/src/value/int_value.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{
AddressableType, AsValue, ConcreteValueType, IrTypeContext, IrValueContext, PointerValueType,
SizedValueType, Value,
AddressableType, AsBytesAndPtrs, AsValue, BytesOrPtr, ConcreteValueType, HasConstValue,
IrTypeContext, IrValueContext, PointerValueType, SizedValueType, Value,
};
use inkwell::AddressSpace;

Expand All @@ -24,6 +24,12 @@ macro_rules! impl_as_int_ir_value {
}

impl<'ink> AddressableType<'ink, $ty> for $ty {}

impl HasConstValue for $ty {
fn has_const_value() -> bool {
true
}
}
)*
}
}
Expand Down Expand Up @@ -110,3 +116,51 @@ impl<'ink> AsValue<'ink, i64> for i64 {
)
}
}

impl<'ink> AsBytesAndPtrs<'ink> for u8 {
fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![bytemuck::cast_ref::<u8, [u8; 1]>(self).to_vec().into()]
}
}

impl<'ink> AsBytesAndPtrs<'ink> for u16 {
fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![bytemuck::cast_ref::<u16, [u8; 2]>(self).to_vec().into()]
}
}

impl<'ink> AsBytesAndPtrs<'ink> for u32 {
fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![bytemuck::cast_ref::<u32, [u8; 4]>(self).to_vec().into()]
}
}

impl<'ink> AsBytesAndPtrs<'ink> for u64 {
fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![bytemuck::cast_ref::<u64, [u8; 8]>(self).to_vec().into()]
}
}

impl<'ink> AsBytesAndPtrs<'ink> for i8 {
fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![bytemuck::cast_ref::<i8, [u8; 1]>(self).to_vec().into()]
}
}

impl<'ink> AsBytesAndPtrs<'ink> for i16 {
fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![bytemuck::cast_ref::<i16, [u8; 2]>(self).to_vec().into()]
}
}

impl<'ink> AsBytesAndPtrs<'ink> for i32 {
fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![bytemuck::cast_ref::<i32, [u8; 4]>(self).to_vec().into()]
}
}

impl<'ink> AsBytesAndPtrs<'ink> for i64 {
fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![bytemuck::cast_ref::<i64, [u8; 8]>(self).to_vec().into()]
}
}
54 changes: 53 additions & 1 deletion crates/mun_codegen/src/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use std::hash::Hash;
/// is returned. This allows transparent composition. e.g.:
///
/// ```rust
/// # use mun_codegen::value::{AsValue, IrValueContext, TransparentValue, Value};
/// # use mun_codegen::value::{AsValue, BytesOrPtr, IrValueContext, TransparentValue, Value};
/// struct Foo {
/// value: u32,
/// bar: f32,
Expand All @@ -49,6 +49,13 @@ use std::hash::Hash;
/// fn as_target_value(&self, context: &IrValueContext<'ink, '_, '_>) -> Value<'ink, Self::Target> {
/// (self.value, self.bar).as_value(context)
/// }
///
/// fn as_bytes_and_ptrs(&self, context: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
/// vec![
/// bytemuck::cast_ref::<u32, [u8; 4]>(&self.value).to_vec().into(),
/// bytemuck::cast_ref::<f32, [u8; 4]>(&self.bar).to_vec().into(),
/// ]
/// }
/// }
/// ```
///
Expand Down Expand Up @@ -87,6 +94,42 @@ pub trait TransparentValue<'ink> {

/// Converts the instance to the target value
fn as_target_value(&self, context: &IrValueContext<'ink, '_, '_>) -> Value<'ink, Self::Target>;

/// Converts the instance to bytes and pointers.
fn as_bytes_and_ptrs(&self, context: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>>;
}

/// Contains either a value converted to bytes or a pointer to the value.
///
/// This is used for generating constant enum types.
#[derive(Clone, Debug)]
pub enum BytesOrPtr<'ink> {
Bytes(Vec<u8>),
UntypedPtr(PointerValue<'ink>),
}

impl<'ink> From<Vec<u8>> for BytesOrPtr<'ink> {
fn from(bytes: Vec<u8>) -> Self {
BytesOrPtr::Bytes(bytes)
}
}

impl<'ink> From<PointerValue<'ink>> for BytesOrPtr<'ink> {
fn from(ptr: PointerValue<'ink>) -> Self {
BytesOrPtr::UntypedPtr(ptr)
}
}

/// Converts a value to its raw byte representation, while leaving pointers intact.
pub trait AsBytesAndPtrs<'ink> {
/// Converts the instance to bytes and pointers.
fn as_bytes_and_ptrs(&self, context: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>>;
}

/// Signals whether the instance can construct aa matching LLVM constant IR value.
pub trait HasConstValue {
/// Returns whether the instance can be converted into an LLVM IR value.
fn has_const_value() -> bool;
}

/// The context in which an `IrType` operates.
Expand Down Expand Up @@ -389,6 +432,15 @@ impl<
}
}

impl<'ink, T> HasConstValue for T
where
T: TransparentValue<'ink>,
{
fn has_const_value() -> bool {
true
}
}

// Transparent values can also be represented as `Value<Self>`.
impl<'ink, T> AsValue<'ink, T> for T
where
Expand Down
30 changes: 25 additions & 5 deletions crates/mun_codegen/src/value/pointer_value.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::value::{
AddressableType, ConcreteValueType, IrTypeContext, IrValueContext, PointerValueType,
SizedValueType, Value,
use super::{
AddressableType, AsBytesAndPtrs, BytesOrPtr, ConcreteValueType, HasConstValue, IrTypeContext,
IrValueContext, PointerValueType, SizedValueType, Value,
};
use inkwell::types::PointerType;
use inkwell::AddressSpace;
use inkwell::{types::PointerType, AddressSpace};

impl<'ink, T: PointerValueType<'ink>> ConcreteValueType<'ink> for *const T {
type Value = inkwell::values::PointerValue<'ink>;
}

impl<'ink, T: PointerValueType<'ink>> ConcreteValueType<'ink> for *mut T {
type Value = inkwell::values::PointerValue<'ink>;
}
Expand All @@ -22,6 +22,7 @@ impl<'ink, T: PointerValueType<'ink>> SizedValueType<'ink> for *mut T {
T::get_ptr_type(context, None)
}
}

impl<'ink, T: PointerValueType<'ink>> PointerValueType<'ink> for *mut T {
fn get_ptr_type(
context: &IrTypeContext<'ink, '_>,
Expand All @@ -30,6 +31,7 @@ impl<'ink, T: PointerValueType<'ink>> PointerValueType<'ink> for *mut T {
Self::get_ir_type(context).ptr_type(address_space.unwrap_or(AddressSpace::Generic))
}
}

impl<'ink, T: PointerValueType<'ink>> PointerValueType<'ink> for *const T {
fn get_ptr_type(
context: &IrTypeContext<'ink, '_>,
Expand All @@ -49,3 +51,21 @@ impl<'ink, T: SizedValueType<'ink, Value = inkwell::values::PointerValue<'ink>>>
impl<'ink, T> AddressableType<'ink, *const T> for *const T where *const T: ConcreteValueType<'ink> {}

impl<'ink, T> AddressableType<'ink, *mut T> for *mut T where *mut T: ConcreteValueType<'ink> {}

impl<'ink, T> HasConstValue for Value<'ink, T>
where
T: SizedValueType<'ink, Value = inkwell::values::PointerValue<'ink>>,
{
fn has_const_value() -> bool {
true
}
}

impl<'ink, T> AsBytesAndPtrs<'ink> for Value<'ink, T>
where
T: SizedValueType<'ink, Value = inkwell::values::PointerValue<'ink>>,
{
fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
vec![BytesOrPtr::UntypedPtr(self.value)]
}
}
14 changes: 13 additions & 1 deletion crates/mun_codegen/src/value/string.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{AsValue, Global, IrValueContext, TransparentValue, Value};
use super::{AsValue, BytesOrPtr, Global, IrValueContext, TransparentValue, Value};
use std::ffi::{CStr, CString};

/// Enables internalizing certain data structures like strings.
Expand Down Expand Up @@ -57,6 +57,12 @@ impl<'ink> TransparentValue<'ink> for CString {
fn as_target_value(&self, context: &IrValueContext<'ink, '_, '_>) -> Value<'ink, Self::Target> {
self.as_bytes_with_nul().as_value(context)
}

fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
unreachable!(
"`as_bytes_and_ptrs` should never be called on a `String`, as it cannot be a member of an enum."
)
}
}

impl<'ink> TransparentValue<'ink> for String {
Expand All @@ -65,4 +71,10 @@ impl<'ink> TransparentValue<'ink> for String {
fn as_target_value(&self, context: &IrValueContext<'ink, '_, '_>) -> Value<'ink, Self::Target> {
self.as_bytes().as_value(context)
}

fn as_bytes_and_ptrs(&self, _: &IrValueContext<'ink, '_, '_>) -> Vec<BytesOrPtr<'ink>> {
unreachable!(
"`as_bytes_and_ptrs` should never be called on a `String`, as it cannot be a member of an enum."
);
}
}
5 changes: 3 additions & 2 deletions crates/mun_codegen_macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ edition = "2018"
proc-macro = true

[dependencies]
syn="1.0"
quote="1.0"
proc-macro2 = "1.0"
quote = "1.0"
syn = "1.0"
Loading

0 comments on commit 41256ee

Please sign in to comment.