Skip to content

Commit

Permalink
Merge Type and Aggregate into a copyable Type (FuelLabs#3730)
Browse files Browse the repository at this point in the history
This is the second step towards achieving FuelLabs#2819.

Combining Type and Aggregate into a single data structure enables offset
computations for complex indexing (i.e., a nesting of arrays and
structs) which will be needed when we introduce GEPs. The new function
`get_indexed_type` does this computation.

The core of this PR is in `irtype.rs`. Everything else is just to
accommodate that.

Co-authored-by: Joshua Batty <[email protected]>
  • Loading branch information
vaivaswatha and JoshuaBatty authored Jan 14, 2023
1 parent 7c95013 commit 0c402c3
Show file tree
Hide file tree
Showing 23 changed files with 871 additions and 722 deletions.
43 changes: 20 additions & 23 deletions sway-core/src/asm_generation/data_section.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::asm_generation::from_ir::ir_type_size_in_bytes;

use sway_ir::{AggregateContent, Constant, ConstantValue, Context, Type};
use sway_ir::{Constant, ConstantValue, Context};

use std::fmt::{self, Write};

Expand Down Expand Up @@ -50,28 +50,25 @@ impl Entry {
let size = Some(ir_type_size_in_bytes(context, &constant.ty) as usize);

// Is this constant a tagged union?
if let Type::Struct(struct_agg) = &constant.ty {
if let AggregateContent::FieldTypes(field_tys) = struct_agg.get_content(context) {
if field_tys.len() == 2
&& matches!(
(field_tys[0], field_tys[1]),
(Type::Uint(_), Type::Union(_))
)
{
// OK, this looks very much like a tagged union enum, which is the only place
// we use unions (otherwise we should be generalising this a bit more).
if let ConstantValue::Struct(els) = &constant.value {
if els.len() == 2 {
let tag_entry = Entry::from_constant(context, &els[0]);

// Here's the special case. We need to get the size of the union and
// attach it to this constant entry which will be one of the variants.
let mut val_entry = Entry::from_constant(context, &els[1]);
val_entry.size = ir_type_size_in_bytes(context, &field_tys[1]) as usize;

// Return here from our special case.
return Entry::new_collection(vec![tag_entry, val_entry], size);
}
if constant.ty.is_struct(context) {
let field_tys = constant.ty.get_field_types(context);
if field_tys.len() == 2
&& field_tys[0].is_uint(context)
&& field_tys[1].is_union(context)
{
// OK, this looks very much like a tagged union enum, which is the only place
// we use unions (otherwise we should be generalising this a bit more).
if let ConstantValue::Struct(els) = &constant.value {
if els.len() == 2 {
let tag_entry = Entry::from_constant(context, &els[0]);

// Here's the special case. We need to get the size of the union and
// attach it to this constant entry which will be one of the variants.
let mut val_entry = Entry::from_constant(context, &els[1]);
val_entry.size = ir_type_size_in_bytes(context, &field_tys[1]) as usize;

// Return here from our special case.
return Entry::new_collection(vec![tag_entry, val_entry], size);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions sway-core/src/asm_generation/evm/evm_asm_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ impl<'ir> EvmAsmBuilder<'ir> {
&mut self,
instr_val: &Value,
array: &Value,
ty: &Aggregate,
ty: &Type,
index_val: &Value,
) {
todo!();
Expand All @@ -506,7 +506,7 @@ impl<'ir> EvmAsmBuilder<'ir> {
&mut self,
instr_val: &Value,
array: &Value,
ty: &Aggregate,
ty: &Type,
value: &Value,
index_val: &Value,
) {
Expand Down
124 changes: 53 additions & 71 deletions sway-core/src/asm_generation/from_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,40 +196,26 @@ pub enum StateAccessType {
}

pub(crate) fn ir_type_size_in_bytes(context: &Context, ty: &Type) -> u64 {
match ty {
Type::Unit | Type::Bool | Type::Uint(_) => 8,
Type::Slice => 16,
Type::B256 => 32,
Type::String(n) => size_bytes_round_up_to_word_alignment!(n),
Type::Array(aggregate) => {
if let AggregateContent::ArrayType(el_ty, cnt) = aggregate.get_content(context) {
cnt * ir_type_size_in_bytes(context, el_ty)
} else {
unreachable!("Wrong content for array.")
}
}
Type::Struct(aggregate) => {
if let AggregateContent::FieldTypes(field_tys) = aggregate.get_content(context) {
// Sum up all the field sizes.
field_tys
.iter()
.map(|field_ty| ir_type_size_in_bytes(context, field_ty))
.sum()
} else {
unreachable!("Wrong content for struct.")
}
match ty.get_content(context) {
TypeContent::Unit | TypeContent::Bool | TypeContent::Uint(_) => 8,
TypeContent::Slice => 16,
TypeContent::B256 => 32,
TypeContent::String(n) => size_bytes_round_up_to_word_alignment!(*n),
TypeContent::Array(el_ty, cnt) => cnt * ir_type_size_in_bytes(context, el_ty),
TypeContent::Struct(field_tys) => {
// Sum up all the field sizes.
field_tys
.iter()
.map(|field_ty| ir_type_size_in_bytes(context, field_ty))
.sum()
}
Type::Union(aggregate) => {
if let AggregateContent::FieldTypes(field_tys) = aggregate.get_content(context) {
// Find the max size for field sizes.
field_tys
.iter()
.map(|field_ty| ir_type_size_in_bytes(context, field_ty))
.max()
.unwrap_or(0)
} else {
unreachable!("Wrong content for union.")
}
TypeContent::Union(field_tys) => {
// Find the max size for field sizes.
field_tys
.iter()
.map(|field_ty| ir_type_size_in_bytes(context, field_ty))
.max()
.unwrap_or(0)
}
}
}
Expand All @@ -240,44 +226,40 @@ pub(crate) fn aggregate_idcs_to_field_layout(
ty: &Type,
idcs: &[u64],
) -> ((u64, u64), Type) {
idcs.iter()
.fold(((0, 0), *ty), |((offs, _), ty), idx| match ty {
Type::Struct(aggregate) => {
let idx = *idx as usize;
let field_types = &aggregate.get_content(context).field_types();
let field_type = field_types[idx];
let field_offs_in_bytes = field_types
.iter()
.take(idx)
.map(|field_ty| ir_type_size_in_bytes(context, field_ty))
.sum::<u64>();
let field_size_in_bytes = ir_type_size_in_bytes(context, &field_type);

idcs.iter().fold(((0, 0), *ty), |((offs, _), ty), idx| {
if ty.is_struct(context) {
let idx = *idx as usize;
let field_types = ty.get_field_types(context);
let field_type = field_types[idx];
let field_offs_in_bytes = field_types
.iter()
.take(idx)
.map(|field_ty| ir_type_size_in_bytes(context, field_ty))
.sum::<u64>();
let field_size_in_bytes = ir_type_size_in_bytes(context, &field_type);

(
(
(
offs + size_bytes_in_words!(field_offs_in_bytes),
field_size_in_bytes,
),
field_type,
)
}

Type::Union(aggregate) => {
let idx = *idx as usize;
let field_type = aggregate.get_content(context).field_types()[idx];
let union_size_in_bytes = ir_type_size_in_bytes(context, &ty);
let field_size_in_bytes = ir_type_size_in_bytes(context, &field_type);

// The union fields are at offset (union_size - variant_size) due to left padding.
offs + size_bytes_in_words!(field_offs_in_bytes),
field_size_in_bytes,
),
field_type,
)
} else if ty.is_union(context) {
let idx = *idx as usize;
let field_type = ty.get_field_types(context)[idx];
let union_size_in_bytes = ir_type_size_in_bytes(context, &ty);
let field_size_in_bytes = ir_type_size_in_bytes(context, &field_type);
// The union fields are at offset (union_size - variant_size) due to left padding.
(
(
(
offs + size_bytes_in_words!(union_size_in_bytes - field_size_in_bytes),
field_size_in_bytes,
),
field_type,
)
}

_otherwise => panic!("Attempt to access field in non-aggregate."),
})
offs + size_bytes_in_words!(union_size_in_bytes - field_size_in_bytes),
field_size_in_bytes,
),
field_type,
)
} else {
panic!("Attempt to access field in non-aggregate.")
}
})
}
Loading

0 comments on commit 0c402c3

Please sign in to comment.