Skip to content

Commit

Permalink
Structs,enums and unions now follow the specified layout
Browse files Browse the repository at this point in the history
  • Loading branch information
FractalFir committed Jan 20, 2024
1 parent d66c5e0 commit 637b04f
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 51 deletions.
5 changes: 3 additions & 2 deletions src/aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,10 +306,11 @@ fn aggregate_adt<'tyctx>(
ops.extend(adt_adress_ops);
ops.push(CILOp::LdcI32(variant_idx as i32));
let field_name = "_tag".into();
let field = Type::U8;
let layout = tyctx.layout_of(rustc_middle::ty::ParamEnvAnd{param_env:ParamEnv::reveal_all(),value:adt_type}).expect("Could not get type layout!");
let (disrc_type,_) = crate::utilis::adt::enum_tag_info(&layout.layout,tyctx);
ops.push(CILOp::STField(Box::new(FieldDescriptor::new(
adt_type_ref,
field,
disrc_type,
field_name,
))));
}
Expand Down
20 changes: 10 additions & 10 deletions src/compile_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,8 @@ macro_rules! run_test {
};
}
macro_rules! cargo_test {
($test_name:ident) => {
mod $test_name {
($test_name:ident,$is_stable:ident) => {
mod $test_name { mod $is_stable{

#[cfg(test)]
static COMPILE_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
Expand All @@ -268,7 +268,7 @@ macro_rules! cargo_test {
// Ensures the test directory is present
std::fs::create_dir_all(test_dir).expect("Could not setup the test env");
// Builds the backend if neceasry
let rustflags = super::cargo_build_env();
let rustflags = super::super::cargo_build_env();
// Compiles the test project
let out = std::process::Command::new("cargo")
.env("RUSTFLAGS", &rustflags)
Expand Down Expand Up @@ -303,7 +303,7 @@ macro_rules! cargo_test {
// Ensures the test directory is present
std::fs::create_dir_all(test_dir).expect("Could not setup the test env");
// Builds the backend if neceasry
let rustflags = super::cargo_build_env();
let rustflags = super::super::cargo_build_env();
// Compiles the test project
let mut command = std::process::Command::new("cargo");
command
Expand Down Expand Up @@ -333,7 +333,7 @@ macro_rules! cargo_test {
//let exec_path = concat!("../", stringify!($test_name));
//test_dotnet_executable(exec_path, test_dir);
}
}
}}
};
}
macro_rules! cargo_test_ignored {
Expand Down Expand Up @@ -548,14 +548,14 @@ run_test! {intrinsics,type_id,stable}

run_test! {fuzz,test0,stable}

cargo_test! {hello_world}
cargo_test! {std_hello_world}
cargo_test! {hello_world,stable}
cargo_test! {std_hello_world,stable}
cargo_test_ignored! {build_core}
cargo_test_ignored! {build_alloc}
cargo_test_ignored! {build_std}
cargo_test! {benchmarks}
cargo_test! {glam_test}
cargo_test! {fastrand_test}
cargo_test! {benchmarks,stable}
cargo_test! {glam_test,unstable}
cargo_test! {fastrand_test,stable}

use lazy_static::*;
pub fn get_runtime_config() -> &'static str {
Expand Down
56 changes: 37 additions & 19 deletions src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,33 +114,50 @@ fn create_const_adt_from_bytes<'ctx>(
#[allow(unused_mut)]
let mut curr_offset = variant_size;
let enum_ty = crate::utilis::monomorphize(&method_instance, ty, tyctx);
let enum_ty = tycache.type_from_cache(enum_ty, tyctx, Some(method_instance));
let enum_dotnet: DotnetTypeRef = if let Type::DotnetType(ty_ref) = &enum_ty {
let enum_type = tycache.type_from_cache(enum_ty, tyctx, Some(method_instance));
let enum_dotnet: DotnetTypeRef = if let Type::DotnetType(ty_ref) = &enum_type {
ty_ref.as_ref().clone()
} else {
panic!("Invalid enum type {enum_ty:?}");
panic!("Invalid enum type {enum_type:?}");
};
let mut ops = vec![CILOp::NewTMPLocal(enum_ty.into())];
let curr_variant = match variant_size {
let layout = tyctx.layout_of(rustc_middle::ty::ParamEnvAnd{param_env:ParamEnv::reveal_all(),value:enum_ty}).expect("Could not get type layout!");
let (disrc_type,discr_size) = crate::utilis::adt::enum_tag_info(&layout.layout,tyctx);
let mut ops = vec![CILOp::NewTMPLocal(enum_type.into())];
let curr_variant = match discr_size {
0 => todo!("Can't yet handle constant enums with 0-sized tags."),
1 => {
//curr_offset = 1;
let variant = bytes[0] as u32;
ops.extend([
CILOp::LoadAddresOfTMPLocal,
CILOp::LdcI32(variant as i32),
CILOp::STField(FieldDescriptor::boxed(
enum_dotnet.clone(),
Type::U8,
"_tag".into(),
)),
]);
variant
variant as u64
}
2 => {
//curr_offset = 1;
let variant = u16::from_ne_bytes(bytes[0..2].try_into().unwrap());
variant as u64
}
4 => {
//curr_offset = 1;
let variant = u32::from_ne_bytes(bytes[0..4].try_into().unwrap());
variant as u64
}
8 => {
//curr_offset = 1;
let variant = u64::from_ne_bytes(bytes[0..8].try_into().unwrap());
variant as u64
}
_ => todo!("Can't yet support enums with {variant_size} wide tags."),
};
assert!(curr_variant < adt_def.variants().len() as u32);
let active_variant = &adt_def.variants()[curr_variant.into()];
ops.extend([
CILOp::LoadAddresOfTMPLocal,
CILOp::LdcI64(curr_variant as i64),
CILOp::STField(FieldDescriptor::boxed(
enum_dotnet.clone(),
disrc_type,
"_tag".into(),
)),
]);
assert!(curr_variant < adt_def.variants().len() as u64);
let active_variant = &adt_def.variants()[(curr_variant as u32).into()];
for _field in &active_variant.fields {
// Use offset to get the right bytes
let _ = curr_offset;
Expand Down Expand Up @@ -693,15 +710,16 @@ fn load_const_scalar<'ctx>(
}
TyKind::Adt(adt_def, _subst) => match adt_def.adt_kind() {
AdtKind::Enum => {
let field_type = Type::U8;
let layout = tyctx.layout_of(rustc_middle::ty::ParamEnvAnd{param_env:ParamEnv::reveal_all(),value:scalar_type}).expect("Could not get type layout!");
let (disrc_type,_) = crate::utilis::adt::enum_tag_info(&layout.layout,tyctx);
let enum_dotnet = tpe.as_dotnet().expect("Enum scalar not an ADT!");
vec![
CILOp::NewTMPLocal(tpe.into()),
CILOp::LoadAddresOfTMPLocal,
CILOp::LdcI64(scalar_u128 as i64),
CILOp::STField(Box::new(crate::cil::FieldDescriptor::new(
enum_dotnet.clone(),
field_type,
disrc_type,
"_tag".into(),
))),
CILOp::LoadTMPLocal,
Expand Down
8 changes: 5 additions & 3 deletions src/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,16 +408,18 @@ pub fn handle_rvalue<'tcx>(
let owner_ty = crate::utilis::monomorphize(&method_instance, owner_ty, tyctx);
let owner = tycache.type_from_cache(owner_ty, tyctx, Some(method_instance));
//TODO: chose proper tag type based on variant count of `owner`
let discr_ty = owner_ty.discriminant_ty(tyctx);
let discr_type = tycache.type_from_cache(discr_ty, tyctx, Some(method_instance));
//let discr_ty = owner_ty.discriminant_ty(tyctx);
//let discr_type = tycache.type_from_cache(discr_ty, tyctx, Some(method_instance));
let layout = tyctx.layout_of(rustc_middle::ty::ParamEnvAnd{param_env:ParamEnv::reveal_all(),value:owner_ty}).expect("Could not get type layout!");
let (disrc_type,_) = crate::utilis::adt::enum_tag_info(&layout.layout,tyctx);
let owner = if let crate::r#type::Type::DotnetType(dotnet_type) = owner {
dotnet_type.as_ref().clone()
} else {
panic!();
};
ops.push(CILOp::LDField(Box::new(crate::cil::FieldDescriptor::new(
owner,
discr_type,
disrc_type,
"_tag".into(),
))));
ops
Expand Down
59 changes: 42 additions & 17 deletions src/type/tycache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ impl TyCache {
}
self.cycle_prevention.push(name.into());
let def = match def.adt_kind() {
AdtKind::Struct => self.struct_(name, def, subst, tyctx, method),
AdtKind::Struct => self.struct_(name, def,adt_ty, subst, tyctx, method),
AdtKind::Enum => self.enum_(name, def,adt_ty, subst, tyctx, method),
AdtKind::Union => self.union_(name, def, subst, tyctx, method),
AdtKind::Union => self.union_(name, def, adt_ty,subst, tyctx, method),
};
self.type_def_cache.insert(name.into(), def);
self.cycle_prevention.pop();
Expand All @@ -76,6 +76,7 @@ impl TyCache {
&mut self,
name: &str,
adt: AdtDef<'tyctx>,
adt_ty: Ty<'tyctx>,
subst: &'tyctx List<rustc_middle::ty::GenericArg<'tyctx>>,
tyctx: TyCtxt<'tyctx>,
method: Option<Instance<'tyctx>>,
Expand All @@ -95,13 +96,15 @@ impl TyCache {
}

let access = AccessModifer::Public;

TypeDef::new(access, name.into(), vec![], fields, vec![], None, 0, None)
let layout = tyctx.layout_of(rustc_middle::ty::ParamEnvAnd{param_env:ParamEnv::reveal_all(),value:adt_ty}).expect("Could not get type layout!");
let explicit_offsets = crate::utilis::adt::FieldOffsetIterator::fields(&layout.layout).collect();
TypeDef::new(access, name.into(), vec![], fields, vec![], Some(explicit_offsets), 0, None)
}
fn union_<'tyctx>(
&mut self,
name: &str,
adt: AdtDef<'tyctx>,
adt_ty: Ty<'tyctx>,
subst: &'tyctx List<rustc_middle::ty::GenericArg<'tyctx>>,
tyctx: TyCtxt<'tyctx>,
method: Option<Instance<'tyctx>>,
Expand All @@ -118,15 +121,16 @@ impl TyCache {
}

let access = AccessModifer::Public;
let offsets = adt.all_fields().map(|_| 0).collect();
let layout = tyctx.layout_of(rustc_middle::ty::ParamEnvAnd{param_env:ParamEnv::reveal_all(),value:adt_ty}).expect("Could not get type layout!");
let explicit_offsets = crate::utilis::adt::FieldOffsetIterator::fields(&layout.layout).collect();

TypeDef::new(
access,
name.into(),
vec![],
fields,
vec![],
Some(offsets),
Some(explicit_offsets),
0,
None,
)
Expand All @@ -141,29 +145,50 @@ impl TyCache {
method: Option<Instance<'tyctx>>,
) -> TypeDef {
let access = AccessModifer::Public;
let mut explicit_offsets: Vec<u32> = vec![0];
let mut explicit_offsets: Vec<u32> = vec![];

let layout = tyctx.layout_of(rustc_middle::ty::ParamEnvAnd{param_env:ParamEnv::reveal_all(),value:adt_ty}).expect("Could not get type layout!");
let mut fields = vec![];
let mut variant_offset = 0;
let mut tag_size = 1;
match &layout.variants {
rustc_target::abi::Variants::Single { index }=> todo!("Single variant enum???"),
rustc_target::abi::Variants::Multiple { tag, tag_encoding, tag_field, variants }=>{
assert_eq!(*tag_encoding,rustc_target::abi::TagEncoding::Direct,"Only direct tags supported as of now");

let field = adt.all_fields().nth(*tag_field);
//panic!("Field:{field:?}");
let tag_type = Type::U8; //adt_ty.discriminant_ty(tyctx);
//l//et tag_type = self.type_from_cache(tag_ty, tyctx, method);
fields.push((
"_tag".into(),
tag_type,
));
let layout = tyctx.layout_of(rustc_middle::ty::ParamEnvAnd{param_env:ParamEnv::reveal_all(),value:adt_ty}).expect("Could not get type layout!");
//let explicit_offsets:Vec<_> = crate::utilis::adt::FieldOffsetIterator::fields(&layout.layout).collect();
//eprintln!("explicit_offsets:{explicit_offsets:?}");
//let tag_ty = adt.all_fields().nth(0).unwrap().ty(tyctx,subst); //adt_ty.discriminant_ty(tyctx);
// self.type_from_cache(tag_ty, tyctx, method);
//assert_eq!(*tag_encoding,rustc_target::abi::TagEncoding::Direct,"Only direct tags supported as of now");
match tag_encoding{
rustc_target::abi::TagEncoding::Direct=>{
let (tag_type,offset) = crate::utilis::adt::enum_tag_info(&layout.layout,tyctx);
variant_offset = offset;
fields.push((
"_tag".into(),
tag_type,
));
explicit_offsets.push(0);
},
rustc_target::abi::TagEncoding::Niche{untagged_variant, niche_variants, niche_start}=>{
let (tag_type,offset) = crate::utilis::adt::enum_tag_info(&layout.layout,tyctx);
variant_offset = offset;
fields.push((
"_tag".into(),
tag_type,
));
explicit_offsets.push(*niche_start as u32);
},
}

//todo!("Mult-variant enum!"),
}

}
let tag_size = 1;

explicit_offsets.extend(adt.variants().iter().map(|_| tag_size));
explicit_offsets.extend(adt.variants().iter().map(|_| variant_offset));
//let mut inner_types = vec![];
let mut variants = vec![];
for variant in adt.variants() {
Expand Down
82 changes: 82 additions & 0 deletions src/utilis/adt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use rustc_target::abi::Layout;
use rustc_target::abi::FieldIdx;
use rustc_target::abi::FieldsShape;
use rustc_target::abi::Variants;
use rustc_middle::ty::TyCtxt;
use rustc_target::abi::Size;
use crate::r#type::Type;
pub(crate) enum FieldOffsetIterator{
Explicit{
offsets:Box<[u32]>,
index:usize,
},
NoOffset{
count:u64,
}
}
impl Iterator for FieldOffsetIterator{
type Item = u32;
fn next(&mut self)->Option<u32>{
match self{
Self::Explicit{offsets,index}=>{
let next = offsets.get(*index);
*index += 1;
next.copied()
}
Self::NoOffset{count}=>{
if *count > 0 {
*count -= 1;
Some(0)
}
else{
None
}
}
}

}
}
impl FieldOffsetIterator{
pub fn fields(parent:&Layout)->FieldOffsetIterator{
match parent.fields(){
FieldsShape::Arbitrary{offsets,memory_index}=>{
let offsets:Box<[_]> = memory_index.iter().map(|index|offsets[FieldIdx::from_u32(*index)].bytes() as u32).collect();
FieldOffsetIterator::Explicit{offsets,index:0}
},
FieldsShape::Union(count)=>FieldOffsetIterator::NoOffset{count:Into::<usize>::into(*count) as u64},
_=>todo!()
}
}
}
/// Takes layout of an enum as input, and returns the type of its tag(Void if no tag) and the size of the tag(0 if no tag).
pub fn enum_tag_info<'tyctx>(r#enum:&Layout<'tyctx>,tyctx:TyCtxt<'tyctx>)->(Type,u32){
match r#enum.variants(){
Variants::Single{..}=>(Type::Void,0),
Variants::Multiple{tag,..}=>(scalr_to_type(*tag),tag.size(&tyctx).bytes() as u32),
}
}
fn scalr_to_type(scalar:rustc_target::abi::Scalar)->Type{
let primitive = match scalar {rustc_target::abi::Scalar::Union{value}=>value,rustc_target::abi::Scalar::Initialized{value,..}=>value};
primitive_to_type(primitive)
}
fn primitive_to_type(primitive:rustc_target::abi::Primitive)->Type{
use rustc_target::abi::Primitive;
use rustc_target::abi::Integer;
match primitive{
Primitive::Int(int,sign)=>match (int,sign){
(Integer::I8,true)=>Type::I8,
(Integer::I16,true)=>Type::I16,
(Integer::I32,true)=>Type::I32,
(Integer::I64,true)=>Type::I64,
(Integer::I128,true)=>Type::I128,
(Integer::I8,false)=>Type::U8,
(Integer::I16,false)=>Type::U16,
(Integer::I32,false)=>Type::U32,
(Integer::I64,false)=>Type::U64,
(Integer::I128,false)=>Type::U128,
}
Primitive::F32=>Type::F32,
Primitive::F64=>Type::F64,
Primitive::Pointer(_)=>Type::Ptr(Type::Void.into()),
}
}
1 change: 1 addition & 0 deletions src/utilis.rs → src/utilis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::{
r#type::{DotnetTypeRef, Type},
IString,
};
pub mod adt;
pub fn as_adt(ty: Ty) -> Option<(AdtDef, &List<GenericArg>)> {
match ty.kind() {
TyKind::Adt(adt, subst) => Some((*adt, subst)),
Expand Down

0 comments on commit 637b04f

Please sign in to comment.