diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hir/hir.hpp | 1 | ||||
-rw-r--r-- | src/mir/optimise.cpp | 4 | ||||
-rw-r--r-- | src/trans/codegen_c.cpp | 15 | ||||
-rw-r--r-- | src/trans/target.cpp | 218 | ||||
-rw-r--r-- | src/trans/target.hpp | 18 |
5 files changed, 219 insertions, 37 deletions
diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index f13b1860..72b8d7dc 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -260,7 +260,6 @@ public: Rust, C, Packed, - //Union, }; TAGGED_UNION(Data, Unit, (Unit, struct {}), diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 6601c03b..2d336457 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -1699,7 +1699,7 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) if( tef.name == "size_of" ) { size_t size_val = 0; - if( Target_GetSizeOf(state.sp, tef.params.m_types.at(0), size_val) ) + if( Target_GetSizeOf(state.sp, state.m_resolve, tef.params.m_types.at(0), size_val) ) { auto val = ::MIR::Constant::make_Uint({ size_val, ::HIR::CoreType::Usize }); bb.statements.push_back(::MIR::Statement::make_Assign({ mv$(te.ret_val), mv$(val) })); @@ -1710,7 +1710,7 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) else if( tef.name == "align_of" ) { size_t align_val = 0; - if( Target_GetAlignOf(state.sp, tef.params.m_types.at(0), align_val) ) + if( Target_GetAlignOf(state.sp, state.m_resolve, tef.params.m_types.at(0), align_val) ) { auto val = ::MIR::Constant::make_Uint({ align_val, ::HIR::CoreType::Usize }); bb.statements.push_back(::MIR::Statement::make_Assign({ mv$(te.ret_val), mv$(val) })); diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 082d461d..42def258 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -2009,19 +2009,18 @@ namespace { (SwitchValue, if( const auto* ve = e.values.opt_String() ) { assert(ve->size() == e.targets.size()); - m_of << "\t{\n"; - m_of << "\t\tint cmp;\n"; - m_of << "\t\t"; + m_of << "\t{ int cmp;\n"; + m_of << "\t"; for(size_t i = 0; i < e.targets.size(); i++) { const auto& v = (*ve)[i]; m_of << "if( (cmp = slice_cmp("; emit_lvalue(e.val); m_of << ", make_sliceptr("; this->print_escaped_string(v); m_of << "," << v.size() << "))) < 0)\n"; - m_of << "\t\t\tgoto bb" << e.def_target << ";\n"; - m_of << "\t\telse if( cmp == 0 )\n"; - m_of << "\t\t\tgoto bb" << e.targets[i] << ";\n"; - m_of << "\t\telse "; + m_of << "\t\tgoto bb" << e.def_target << ";\n"; + m_of << "\telse if( cmp == 0 )\n"; + m_of << "\t\tgoto bb" << e.targets[i] << ";\n"; + m_of << "\telse "; } - m_of << "\n\t\t\tgoto bb" << e.def_target << ";\n"; + m_of << "\n\t\tgoto bb" << e.def_target << ";\n"; m_of << "\t}\n"; } diff --git a/src/trans/target.cpp b/src/trans/target.cpp index bb0227fc..d653a086 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -9,6 +9,9 @@ #include <algorithm> #include "../expand/cfg.hpp" #include <fstream> +#include <map> +#include <hir/hir.hpp> +#include <hir_typeck/helpers.hpp> TargetArch ARCH_X86_64 = { "x86_64", @@ -22,6 +25,9 @@ TargetArch ARCH_X86 = { }; TargetSpec g_target; + +bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align); + namespace { TargetSpec load_spec_from_file(const ::std::string& filename) @@ -107,7 +113,124 @@ void Target_SetCfg(const ::std::string& target_name) }); } -bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align) +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) + { + ::std::vector<StructRepr::Ent> ents; + bool packed = false; + bool allow_sort = false; + if( const auto* te = ty.m_data.opt_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) ) + return nullptr; + ents.push_back(StructRepr::Ent { idx++, size, align, 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) ) + return nullptr; + ents.push_back(StructRepr::Ent { idx++, size, align, 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() ) + { + unsigned int idx = 0; + for(const auto& t : *te) + { + size_t size, align; + if( !Target_GetSizeAndAlignOf(sp, resolve, t, size,align) ) + return nullptr; + ents.push_back(StructRepr::Ent { idx++, size, align, t.clone() }); + } + } + else + { + BUG(sp, "Unexpected type in creating struct repr"); + } + + + if( allow_sort ) + { + // TODO: Sort by alignment then size (largest first) + // - Requires codegen to use this information + } + + StructRepr rv; + size_t cur_ofs = 0; + for(auto& e : ents) + { + // Increase offset to fit alignment + if( !packed ) + { + while( cur_ofs % e.align != 0 ) + { + rv.ents.push_back({ ~0u, 1, 1, ::HIR::TypeRef( ::HIR::CoreType::U8 ) }); + cur_ofs ++; + } + } + + rv.ents.push_back(mv$(e)); + cur_ofs += e.size; + } + return box$(rv); + } +} +const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty) +{ + // TODO: Thread safety + // Map of generic paths to struct representations. + static ::std::map<::HIR::TypeRef, ::std::unique_ptr<StructRepr>> 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_struct_repr(sp, resolve, ty) )); + return ires.first->second.get(); +} + +// TODO: Include NonZero and other repr optimisations here + +bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align) { TU_MATCHA( (ty.m_data), (te), (Infer, @@ -167,8 +290,41 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& } ), (Path, - // TODO: - return false; + 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 + return false; + ) + ) ), (Generic, // Unknown - return false @@ -181,9 +337,8 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& BUG(sp, "sizeof on an erased type - shouldn't exist"); ), (Array, - // TODO: size_t size; - if( !Target_GetSizeAndAlignOf(sp, *te.inner, size,out_align) ) + if( !Target_GetSizeAndAlignOf(sp, resolve, *te.inner, size,out_align) ) return false; size *= te.size_val; ), @@ -191,29 +346,44 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& BUG(sp, "sizeof on a slice - unsized"); ), (Tuple, - out_size = 0; - out_align = 0; - - // TODO: Struct reordering - for(const auto& t : te) + // Same code as structs :) + if( const auto* repr = Target_GetStructRepr(sp, resolve, ty) ) { - size_t size, align; - if( !Target_GetSizeAndAlignOf(sp, t, size,align) ) - return false; - if( out_size % align != 0 ) + out_size = 0; + out_align = 1; + for(const auto& e : repr->ents) { - out_size += align; - out_size %= align; + out_size += e.size; + out_align = ::std::max(out_align, e.align); } - out_size += size; - out_align = ::std::max(out_align, align); + return true; + } + else + { + return false; } ), (Borrow, - // TODO + // - Alignment is machine native + out_align = g_target.m_arch.m_pointer_bits / 8; + // - Size depends on Sized-nes of the parameter + if( resolve.type_is_sized(sp, *te.inner) ) + { + out_size = g_target.m_arch.m_pointer_bits / 8; + return true; + } + // TODO: Handle different types of Unsized ), (Pointer, - // TODO + // - Alignment is machine native + out_align = g_target.m_arch.m_pointer_bits / 8; + // - Size depends on Sized-nes of the parameter + if( resolve.type_is_sized(sp, *te.inner) ) + { + out_size = g_target.m_arch.m_pointer_bits / 8; + return true; + } + // TODO: Handle different types of Unsized ), (Function, // Pointer size @@ -227,13 +397,13 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& ) return false; } -bool Target_GetSizeOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_size) +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, ty, out_size, ignore_align); + return Target_GetSizeAndAlignOf(sp, resolve, ty, out_size, ignore_align); } -bool Target_GetAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_align) +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, ty, ignore_size, out_align); + return Target_GetSizeAndAlignOf(sp, resolve, ty, ignore_size, out_align); } diff --git a/src/trans/target.hpp b/src/trans/target.hpp index f39882e6..36e06d57 100644 --- a/src/trans/target.hpp +++ b/src/trans/target.hpp @@ -9,6 +9,7 @@ #include <cstddef> #include <hir/type.hpp> +#include <hir_typeck/static.hpp> enum class CodegenMode { @@ -40,9 +41,22 @@ struct TargetSpec TargetArch m_arch; }; +struct StructRepr +{ + struct Ent { + unsigned int field_idx; + size_t size; + size_t align; + ::HIR::TypeRef ty; + }; + // List of types, including padding (indicated by a UINT_MAX field idx) + // Ordered as they would be emitted + ::std::vector<Ent> ents; +}; extern const TargetSpec& Target_GetCurSpec(); extern void Target_SetCfg(const ::std::string& target_name); -extern bool Target_GetSizeOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_size); -extern bool Target_GetAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_align); +extern bool Target_GetSizeOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size); +extern bool Target_GetAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_align); +extern const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& struct_ty); |