summaryrefslogtreecommitdiff
path: root/src/trans/target.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/trans/target.cpp')
-rw-r--r--src/trans/target.cpp535
1 files changed, 482 insertions, 53 deletions
diff --git a/src/trans/target.cpp b/src/trans/target.cpp
index a48038dd..28d874e5 100644
--- a/src/trans/target.cpp
+++ b/src/trans/target.cpp
@@ -137,6 +137,7 @@ namespace {
// Returns NULL when the repr can't be determined
::std::unique_ptr<StructRepr> make_struct_repr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty)
{
+ TRACE_FUNCTION_F(ty);
::std::vector<StructRepr::Ent> ents;
bool packed = false;
bool allow_sort = false;
@@ -160,6 +161,8 @@ namespace {
size_t size, align;
if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) )
return nullptr;
+ if( size == SIZE_MAX )
+ BUG(sp, "Unsized type in tuple struct");
ents.push_back(StructRepr::Ent { idx++, size, align, mv$(ty) });
}
),
@@ -171,6 +174,8 @@ namespace {
size_t size, align;
if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) )
return nullptr;
+ if( size == SIZE_MAX )
+ BUG(sp, "Unsized type in struct");
ents.push_back(StructRepr::Ent { idx++, size, align, mv$(ty) });
}
)
@@ -197,6 +202,8 @@ namespace {
size_t size, align;
if( !Target_GetSizeAndAlignOf(sp, resolve, t, size,align) )
return nullptr;
+ if( size == SIZE_MAX )
+ BUG(sp, "Unsized type in tuple");
ents.push_back(StructRepr::Ent { idx++, size, align, t.clone() });
}
}
@@ -316,52 +323,33 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve,
out_align = 8;
return true;
case ::HIR::CoreType::Str:
- BUG(sp, "sizeof on a `str` - unsized");
+ DEBUG("sizeof on a `str` - unsized");
+ out_size = SIZE_MAX;
+ out_align = 1;
+ return true;
}
),
(Path,
- TU_MATCHA( (te.binding), (be),
- (Unbound,
- BUG(sp, "Unbound type path " << ty << " encountered");
- ),
- (Opaque,
- return false;
- ),
- (Struct,
- if( const auto* repr = Target_GetStructRepr(sp, resolve, ty) )
- {
- out_size = 0;
- out_align = 1;
- for(const auto& e : repr->ents)
- {
- out_size += e.size;
- out_align = ::std::max(out_align, e.align);
- }
- return true;
- }
- else
- {
- return false;
- }
- ),
- (Enum,
- // Search for alternate repr
- // If not found, determine the variant size
- // Get data size and alignment.
- return false;
- ),
- (Union,
- // Max alignment and max data size
+ const auto* repr = Target_GetTypeRepr(sp, resolve, ty);
+ if( !repr )
+ {
+ DEBUG("Cannot get type repr for " << ty);
return false;
- )
- )
+ }
+ out_size = repr->size;
+ out_align = repr->align;
+ return true;
),
(Generic,
// Unknown - return false
+ DEBUG("No repr for Generic - " << ty);
return false;
),
(TraitObject,
- BUG(sp, "sizeof on a trait object - unsized");
+ out_align = 0;
+ out_size = SIZE_MAX;
+ DEBUG("sizeof on a trait object - unsized");
+ return true;
),
(ErasedType,
BUG(sp, "sizeof on an erased type - shouldn't exist");
@@ -370,28 +358,37 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve,
size_t size;
if( !Target_GetSizeAndAlignOf(sp, resolve, *te.inner, size,out_align) )
return false;
- size *= te.size_val;
+ if( size == SIZE_MAX )
+ BUG(sp, "Unsized type in array - " << ty);
+ if( te.size_val == 0 )
+ {
+ size = 0;
+ }
+ else
+ {
+ if( SIZE_MAX / te.size_val <= size )
+ BUG(sp, "Integer overflow calculating array size");
+ size *= te.size_val;
+ }
+ return true;
),
(Slice,
- BUG(sp, "sizeof on a slice - unsized");
+ if( !Target_GetAlignOf(sp, resolve, *te.inner, out_align) )
+ return false;
+ out_size = SIZE_MAX;
+ DEBUG("sizeof on a slice - unsized");
+ return true;
),
(Tuple,
- // Same code as structs :)
- if( const auto* repr = Target_GetStructRepr(sp, resolve, ty) )
- {
- out_size = 0;
- out_align = 1;
- for(const auto& e : repr->ents)
- {
- out_size += e.size;
- out_align = ::std::max(out_align, e.align);
- }
- return true;
- }
- else
+ const auto* repr = Target_GetTypeRepr(sp, resolve, ty);
+ if( !repr )
{
+ DEBUG("Cannot get type repr for " << ty);
return false;
}
+ out_size = repr->size;
+ out_align = repr->align;
+ return true;
),
(Borrow,
// - Alignment is machine native
@@ -427,6 +424,7 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve,
),
(Closure,
// TODO.
+ DEBUG("TODO Closure - " << ty);
)
)
return false;
@@ -434,10 +432,441 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve,
bool Target_GetSizeOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size)
{
size_t ignore_align;
- return Target_GetSizeAndAlignOf(sp, resolve, ty, out_size, ignore_align);
+ bool rv = Target_GetSizeAndAlignOf(sp, resolve, ty, out_size, ignore_align);
+ if( out_size == SIZE_MAX )
+ BUG(sp, "Getting size of Unsized type - " << ty);
+ return rv;
}
bool Target_GetAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_align)
{
size_t ignore_size;
- return Target_GetSizeAndAlignOf(sp, resolve, ty, ignore_size, out_align);
+ bool rv = Target_GetSizeAndAlignOf(sp, resolve, ty, ignore_size, out_align);
+ if( ignore_size == SIZE_MAX )
+ BUG(sp, "Getting alignment of Unsized type - " << ty);
+ return rv;
+}
+
+
+namespace {
+ // Returns NULL when the repr can't be determined
+ ::std::unique_ptr<TypeRepr> make_type_repr_struct(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty)
+ {
+ TRACE_FUNCTION_F(ty);
+ struct Ent {
+ unsigned int field;
+ size_t size;
+ size_t align;
+ };
+ ::std::vector<TypeRepr::Field> fields;
+ ::std::vector<Ent> ents;
+ bool packed = false;
+ bool allow_sort = false;
+ if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Struct() )
+ {
+ const auto& te = ty.m_data.as_Path();
+ const auto& str = *te.binding.as_Struct();
+ auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &te.path.m_data.as_Generic().m_params, nullptr);
+ auto monomorph = [&](const auto& tpl) {
+ auto rv = monomorphise_type_with(sp, tpl, monomorph_cb);
+ resolve.expand_associated_types(sp, rv);
+ return rv;
+ };
+ TU_MATCHA( (str.m_data), (se),
+ (Unit,
+ ),
+ (Tuple,
+ unsigned int idx = 0;
+ for(const auto& e : se)
+ {
+ auto ty = monomorph(e.ent);
+ size_t size, align;
+ if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) )
+ {
+ DEBUG("Can't get size/align of " << ty);
+ return nullptr;
+ }
+ ents.push_back(Ent { idx++, size, align });
+ fields.push_back(TypeRepr::Field { 0, mv$(ty) });
+ }
+ ),
+ (Named,
+ unsigned int idx = 0;
+ for(const auto& e : se)
+ {
+ auto ty = monomorph(e.second.ent);
+ size_t size, align;
+ if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) )
+ {
+ DEBUG("Can't get size/align of " << ty);
+ return nullptr;
+ }
+ ents.push_back(Ent { idx++, size, align });
+ fields.push_back(TypeRepr::Field { 0, mv$(ty) });
+ }
+ )
+ )
+ switch(str.m_repr)
+ {
+ case ::HIR::Struct::Repr::Packed:
+ packed = true;
+ TODO(sp, "make_struct_repr - repr(packed)"); // needs codegen help
+ break;
+ case ::HIR::Struct::Repr::C:
+ // No sorting, no packing
+ break;
+ case ::HIR::Struct::Repr::Rust:
+ allow_sort = true;
+ break;
+ }
+ }
+ else if( const auto* te = ty.m_data.opt_Tuple() )
+ {
+ DEBUG("Tuple " << ty);
+ unsigned int idx = 0;
+ for(const auto& t : *te)
+ {
+ size_t size, align;
+ if( !Target_GetSizeAndAlignOf(sp, resolve, t, size,align) )
+ {
+ DEBUG("Can't get size/align of " << t);
+ return nullptr;
+ }
+ if( size == SIZE_MAX )
+ {
+ TODO(sp, "Unsized type in struct - " << t);
+ }
+ ents.push_back(Ent { idx++, size, align });
+ fields.push_back(TypeRepr::Field { 0, t.clone() });
+ }
+ }
+ else
+ {
+ BUG(sp, "Unexpected type in creating type repr - " << ty);
+ }
+
+
+ if( allow_sort )
+ {
+ // TODO: Sort by alignment then size (largest first)
+ // - Requires codegen to use this information
+ // - NOTE: ?Sized fields (which includes unsized fields) MUST be at the end, even after monomorph
+ }
+
+ TypeRepr rv;
+ size_t cur_ofs = 0;
+ size_t max_align = 1;
+ for(const auto& e : ents)
+ {
+ // Increase offset to fit alignment
+ if( !packed && e.align > 0 )
+ {
+ while( cur_ofs % e.align != 0 )
+ {
+ cur_ofs ++;
+ }
+ }
+ max_align = ::std::max(max_align, e.align);
+
+ fields[e.field].offset = cur_ofs;
+ if( e.size == SIZE_MAX )
+ {
+ // TODO: Ensure that this is the last item
+ ASSERT_BUG(sp, &e == &ents.back(), "Unsized item isn't the last item");
+ cur_ofs = SIZE_MAX;
+ }
+ else
+ {
+ cur_ofs += e.size;
+ }
+ }
+ if( !packed && cur_ofs != SIZE_MAX )
+ {
+ while( cur_ofs % max_align != 0 )
+ {
+ cur_ofs ++;
+ }
+ }
+ rv.align = max_align;
+ rv.size = cur_ofs;
+ rv.fields = ::std::move(fields);
+ DEBUG("size = " << rv.size << ", align = " << rv.align);
+ return box$(rv);
+ }
+
+
+ bool get_nonzero_path(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, TypeRepr::FieldPath& out_path)
+ {
+ switch(ty.m_data.tag())
+ {
+ TU_ARM(ty.m_data, Path, te) {
+ if( te.binding.is_Struct() )
+ {
+ const TypeRepr* r = Target_GetTypeRepr(sp, resolve, ty);
+ if( !r )
+ {
+ return false;
+ }
+ for(size_t i = 0; i < r->fields.size(); i ++)
+ {
+ if( get_nonzero_path(sp, resolve, r->fields[i].ty, out_path) )
+ {
+ out_path.sub_fields.push_back(i);
+ return true;
+ }
+ }
+ }
+ } break;
+ TU_ARM(ty.m_data, Borrow, te) {
+ out_path.sub_fields.push_back(0);
+ Target_GetSizeOf(sp, resolve, ty, out_path.size);
+ return true;
+ } break;
+ TU_ARM(ty.m_data, Function, _te)
+ out_path.sub_fields.push_back(0);
+ Target_GetSizeOf(sp, resolve, ty, out_path.size);
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+ ::std::unique_ptr<TypeRepr> make_type_repr_enum(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty)
+ {
+ const auto& te = ty.m_data.as_Path();
+ const auto& enm = *te.binding.as_Enum();
+
+ auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &te.path.m_data.as_Generic().m_params, nullptr);
+ auto monomorph = [&](const auto& tpl) {
+ auto rv = monomorphise_type_with(sp, tpl, monomorph_cb);
+ resolve.expand_associated_types(sp, rv);
+ return rv;
+ };
+
+ TypeRepr rv;
+ switch(enm.m_data.tag())
+ {
+ case ::HIR::Enum::Class::TAGDEAD: throw "";
+ TU_ARM(enm.m_data, Data, e) {
+ ::std::vector<::HIR::TypeRef> mono_types;
+ for(const auto& var : e)
+ {
+ mono_types.push_back( monomorph(var.type) );
+ }
+ TypeRepr::FieldPath nz_path;
+ if( e.size() == 2 && mono_types[0] == ::HIR::TypeRef::new_unit() && get_nonzero_path(sp, resolve, mono_types[1], nz_path) )
+ {
+ nz_path.index = 1;
+ ::std::reverse(nz_path.sub_fields.begin(), nz_path.sub_fields.end());
+ size_t max_size = 0;
+ size_t max_align = 0;
+ for(auto& t : mono_types)
+ {
+ size_t size, align;
+ if( !Target_GetSizeAndAlignOf(sp, resolve, t, size, align) )
+ {
+ DEBUG("Generic type in enum - " << t);
+ return nullptr;
+ }
+ if( size == SIZE_MAX ) {
+ BUG(sp, "Unsized type in enum - " << t);
+ }
+ max_size = ::std::max(max_size , size);
+ max_align = ::std::max(max_align, align);
+ rv.fields.push_back(TypeRepr::Field { 0, mv$(t) });
+ }
+
+ rv.size = max_size;
+ rv.align = max_align;
+ rv.variants = TypeRepr::VariantMode::make_NonZero({ nz_path, 0 });
+ }
+ else
+ {
+ size_t max_size = 0;
+ size_t max_align = 0;
+ for(auto& t : mono_types)
+ {
+ size_t size, align;
+ if( !Target_GetSizeAndAlignOf(sp, resolve, t, size, align) )
+ {
+ DEBUG("Generic type in enum - " << t);
+ return nullptr;
+ }
+ if( size == SIZE_MAX ) {
+ BUG(sp, "Unsized type in enum - " << t);
+ }
+ max_size = ::std::max(max_size , size);
+ max_align = ::std::max(max_align, align);
+ rv.fields.push_back(TypeRepr::Field { 0, mv$(t) });
+ }
+ size_t tag_size = 0;
+ // TODO: repr(C) enums
+ if( mono_types.size() == 0 ) {
+ // Unreachable
+ }
+ else if( mono_types.size() == 1 ) {
+ // No need for a tag
+ }
+ else if( mono_types.size() <= 255 ) {
+ rv.fields.push_back(TypeRepr::Field { max_size, ::HIR::CoreType::U8 });
+ tag_size = 1;
+ }
+ else {
+ ASSERT_BUG(sp, mono_types.size() <= 0xFFFF, "");
+ while(max_size % 2) max_size ++;
+ rv.fields.push_back(TypeRepr::Field { max_size, ::HIR::CoreType::U16 });
+ tag_size = 2;
+ }
+ max_align = ::std::max(max_align, tag_size);
+ ::std::vector<uint64_t> vals;
+ for(size_t i = 0; i < e.size(); i++)
+ {
+ vals.push_back(i);
+ }
+ rv.variants = TypeRepr::VariantMode::make_Values({ { mono_types.size(), tag_size, {} }, ::std::move(vals) });
+ if( max_align > 0 )
+ {
+ rv.size = (max_size + tag_size);
+ while(rv.size % max_align)
+ rv.size ++;
+ rv.align = max_align;
+ }
+ else
+ {
+ ASSERT_BUG(sp, max_size == 0, "Zero alignment, but non-zero size");
+ }
+
+ // TODO: Variants.
+ }
+ } break;
+ TU_ARM(enm.m_data, Value, e) {
+ switch(e.repr)
+ {
+ case ::HIR::Enum::Repr::C:
+ // No auto-sizing, just i32?
+ rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U32 });
+ break;
+ case ::HIR::Enum::Repr::Rust:
+ if( e.variants.size() == 0 ) {
+ }
+ else if( e.variants.size() == 1 ) {
+ }
+ else if( e.variants.size() <= 255 ) {
+ rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U8 });
+ }
+ else if( e.variants.size() <= 0xFFFF ) {
+ rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U16 });
+ }
+ else if( e.variants.size() <= 0xFFFFFFFF ) {
+ rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U32 });
+ }
+ else {
+ rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U64 });
+ }
+ break;
+ case ::HIR::Enum::Repr::U8:
+ rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U8 });
+ break;
+ case ::HIR::Enum::Repr::U16:
+ rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U16 });
+ break;
+ case ::HIR::Enum::Repr::U32:
+ rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U32 });
+ break;
+ case ::HIR::Enum::Repr::U64:
+ rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U64 });
+ break;
+ case ::HIR::Enum::Repr::Usize:
+ if( g_target.m_arch.m_pointer_bits == 16 )
+ {
+ rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U16 });
+ }
+ else if( g_target.m_arch.m_pointer_bits == 32 )
+ {
+ rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U32 });
+ }
+ else if( g_target.m_arch.m_pointer_bits == 64 )
+ {
+ rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U64 });
+ }
+ break;
+ }
+ if( rv.fields.size() > 0 )
+ {
+ // Can't return false or unsized
+ Target_GetSizeAndAlignOf(sp, resolve, rv.fields.back().ty, rv.size, rv.align);
+
+ ::std::vector<uint64_t> vals;
+ for(const auto& v : e.variants)
+ {
+ vals.push_back(v.val);
+ }
+ rv.variants = TypeRepr::VariantMode::make_Values({ 0, rv.size, ::std::move(vals) });
+ }
+ } break;
+ }
+ return box$(rv);
+ }
+ ::std::unique_ptr<TypeRepr> make_type_repr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty)
+ {
+ TRACE_FUNCTION_F(ty);
+ if( TU_TEST1(ty.m_data, Path, .binding.is_Struct()) || ty.m_data.is_Tuple() )
+ {
+ return make_type_repr_struct(sp, resolve, ty);
+ }
+ else if( TU_TEST1(ty.m_data, Path, .binding.is_Union()) )
+ {
+ const auto& te = ty.m_data.as_Path();
+ const auto& unn = *te.binding.as_Union();
+
+ auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &te.path.m_data.as_Generic().m_params, nullptr);
+ auto monomorph = [&](const auto& tpl) {
+ auto rv = monomorphise_type_with(sp, tpl, monomorph_cb);
+ resolve.expand_associated_types(sp, rv);
+ return rv;
+ };
+
+ TypeRepr rv;
+ for(const auto& var : unn.m_variants)
+ {
+ rv.fields.push_back({ 0, monomorph(var.second.ent) });
+ size_t size, align;
+ if( !Target_GetSizeAndAlignOf(sp, resolve, rv.fields.back().ty, size, align) )
+ {
+ // Generic? - Not good.
+ DEBUG("Generic type encounterd after monomorphise in union - " << rv.fields.back().ty);
+ return nullptr;
+ }
+ if( size == SIZE_MAX ) {
+ BUG(sp, "Unsized type in union");
+ }
+ rv.size = ::std::max(rv.size , size );
+ rv.align = ::std::max(rv.align, align);
+ }
+ return box$(rv);
+ }
+ else if( TU_TEST1(ty.m_data, Path, .binding.is_Enum()) )
+ {
+ return make_type_repr_enum(sp, resolve, ty);
+ }
+ else
+ {
+ TODO(sp, "Type repr for " << ty);
+ return nullptr;
+ }
+ }
+}
+const TypeRepr* Target_GetTypeRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty)
+{
+ // TODO: Thread safety
+ // Map of generic types to type representations.
+ static ::std::map<::HIR::TypeRef, ::std::unique_ptr<TypeRepr>> s_cache;
+
+ auto it = s_cache.find(ty);
+ if( it != s_cache.end() )
+ {
+ return it->second.get();
+ }
+
+ auto ires = s_cache.insert(::std::make_pair( ty.clone(), make_type_repr(sp, resolve, ty) ));
+ return ires.first->second.get();
}