summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/hir/hir.hpp1
-rw-r--r--src/mir/optimise.cpp4
-rw-r--r--src/trans/codegen_c.cpp15
-rw-r--r--src/trans/target.cpp218
-rw-r--r--src/trans/target.hpp18
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);