Skip to content

Commit

Permalink
Codegen C - Handle alignment overrides properly (requires passing via…
Browse files Browse the repository at this point in the history
… pointer if alignment more than 1 pointer) (ref thepowersgang#194)
  • Loading branch information
thepowersgang authored and rdrpenguin04 committed Nov 14, 2021
1 parent aab5036 commit a2a004f
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 24 deletions.
9 changes: 6 additions & 3 deletions src/hir/from_ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1036,10 +1036,13 @@ ::HIR::Struct LowerHIR_Struct(const Span& sp, ::HIR::ItemPath path, const ::AST:
rv.m_repr = ::HIR::Struct::Repr::Transparent;
}
else if( repr_str == "align" ) {
//ASSERT_BUG(a.span(), a.has_string(), "#[repr(aligned)] attribute malformed, " << *attr_repr);
ASSERT_BUG(a.span(), rv.m_repr != ::HIR::Struct::Repr::Packed, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str);
ASSERT_BUG(a.span(), a.items().size() == 1, "#[repr(aligned)] attribute malformed, " << *attr_repr);
ASSERT_BUG(a.span(), a.items()[0].has_string(), "#[repr(aligned)] attribute malformed, " << *attr_repr);
//ASSERT_BUG(a.span(), rv.m_repr != ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str);
//rv.m_repr = ::HIR::Struct::Repr::Aligned;
//rv.m_forced_alignment = ::std::stol(a.string());
ASSERT_BUG(a.span(), rv.m_forced_alignment == 0, "Conflicting #[repr] attributes");
rv.m_forced_alignment = ::std::stol(a.items()[0].string());
ASSERT_BUG(a.span(), rv.m_forced_alignment > 0, "#[repr(aligned)] attribute malformed, " << *attr_repr);
}
else {
TODO(a.span(), "Handle struct repr '" << repr_str << "'");
Expand Down
45 changes: 34 additions & 11 deletions src/trans/codegen_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1567,8 +1567,9 @@ namespace {
{
// Fill `fields` with ascending indexes (for sorting)
// AND: Determine if the type has a a zero-sized item that has an alignment equal to the structure's alignment
bool has_manual_align = false;
::std::vector<unsigned> fields;
size_t max_align = 0;
bool has_manual_align = false;
for(const auto& ent : repr->fields)
{
fields.push_back(fields.size());
Expand All @@ -1580,6 +1581,10 @@ namespace {
if( sz == 0 && al == repr->align && al > 0 ) {
has_manual_align = true;
}
max_align = std::max(max_align, al);
}
if(!is_packed && max_align != repr->align /*&& repr->size > 0*/) {
has_manual_align = true;
}
// - Sort the fields by offset
::std::sort(fields.begin(), fields.end(), [&](auto a, auto b){ return repr->fields[a].offset < repr->fields[b].offset; });
Expand Down Expand Up @@ -3016,6 +3021,13 @@ namespace {
return false;
}
}
bool type_is_high_align(const ::HIR::TypeRef& ty) const
{
size_t size, align;
// NOTE: Uses the Size+Align version because that doesn't panic on unsized
MIR_ASSERT(*m_mir_res, Target_GetSizeAndAlignOf(sp, m_resolve, ty, size, align), "Unexpected generic? " << ty);
return align >Target_GetPointerBits() / 8;
}

void emit_borrow(const ::MIR::TypeResolve& mir_res, HIR::BorrowType bt, const MIR::LValue& val)
{
Expand Down Expand Up @@ -4168,15 +4180,17 @@ namespace {
for(unsigned int j = 0; j < e.args.size(); j ++) {
if(j != 0) m_of << ",";
m_of << " ";
if( m_options.disallow_empty_structs /*&& TU_TEST1(e.args[j], LValue, .is_Field())*/ )
::HIR::TypeRef tmp;
const auto& ty = m_mir_res->get_param_type(tmp, e.args[j]);

if( this->type_is_high_align(ty) )
{
::HIR::TypeRef tmp;
const auto& ty = m_mir_res->get_param_type(tmp, e.args[j]);
if( this->type_is_bad_zst(ty) )
{
m_of << "zarg" << j;
continue;
}
m_of << "&";
}
if( this->type_is_bad_zst(ty) )
{
m_of << "zarg" << j;
continue;
}
emit_param(e.args[j]);
}
Expand Down Expand Up @@ -4963,7 +4977,9 @@ namespace {
{
if( i != 0 ) m_of << ",";
ss << "\n\t\t";
this->emit_ctype( params.monomorph(m_resolve, item.m_args[i].second), FMT_CB(os, os << "arg" << i;) );
// TODO: If the type has a high alignment, emit as a pointer
auto ty = params.monomorph(m_resolve, item.m_args[i].second);
this->emit_ctype( ty, FMT_CB(os, os << (this->type_is_high_align(ty) ? "*":"") << "arg" << i;) );
}

if( item.m_variadic )
Expand Down Expand Up @@ -6810,7 +6826,14 @@ namespace {
m_of << "rv";
}
TU_ARMA(Argument, e) {
m_of << "arg" << e;
if(this->type_is_high_align(m_mir_res->m_args[e].second)) {
m_of << "(*";
m_of << "arg" << e;
m_of << ")";
}
else {
m_of << "arg" << e;
}
}
TU_ARMA(Local, e) {
if( e == ::MIR::LValue::Storage::MAX_ARG )
Expand Down
25 changes: 15 additions & 10 deletions src/trans/target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -607,11 +607,11 @@ void Target_SetCfg(const ::std::string& target_name)
Cfg_SetValue("target_pointer_width", FMT(g_target.m_arch.m_pointer_bits));
Cfg_SetValue("target_endian", g_target.m_arch.m_big_endian ? "big" : "little");
Cfg_SetValue("target_arch", g_target.m_arch.m_name);
if(g_target.m_arch.m_atomics.u8) { Cfg_SetValue("target_has_atomic", "8" ); Cfg_SetValue("target_has_atomic_load_store", "8"); }
if(g_target.m_arch.m_atomics.u16) { Cfg_SetValue("target_has_atomic", "16" ); Cfg_SetValue("target_has_atomic_load_store", "16"); }
if(g_target.m_arch.m_atomics.u32) { Cfg_SetValue("target_has_atomic", "32" ); Cfg_SetValue("target_has_atomic_load_store", "32"); }
if(g_target.m_arch.m_atomics.u64) { Cfg_SetValue("target_has_atomic", "64" ); Cfg_SetValue("target_has_atomic_load_store", "64"); }
if(g_target.m_arch.m_atomics.ptr) { Cfg_SetValue("target_has_atomic", "ptr"); Cfg_SetValue("target_has_atomic_load_store", "ptr"); }
if(g_target.m_arch.m_atomics.u8) { Cfg_SetValue("target_has_atomic", "8" ); Cfg_SetValue("target_has_atomic_load_store", "8" ); Cfg_SetValue("target_has_atomic_equal_alignment", "8" ); }
if(g_target.m_arch.m_atomics.u16) { Cfg_SetValue("target_has_atomic", "16" ); Cfg_SetValue("target_has_atomic_load_store", "16" ); Cfg_SetValue("target_has_atomic_equal_alignment", "16" ); }
if(g_target.m_arch.m_atomics.u32) { Cfg_SetValue("target_has_atomic", "32" ); Cfg_SetValue("target_has_atomic_load_store", "32" ); Cfg_SetValue("target_has_atomic_equal_alignment", "32"); }
if(g_target.m_arch.m_atomics.u64) { Cfg_SetValue("target_has_atomic", "64" ); Cfg_SetValue("target_has_atomic_load_store", "64" ); Cfg_SetValue("target_has_atomic_equal_alignment", "64"); }
if(g_target.m_arch.m_atomics.ptr) { Cfg_SetValue("target_has_atomic", "ptr"); Cfg_SetValue("target_has_atomic_load_store", "ptr"); Cfg_SetValue("target_has_atomic_equal_alignment", "ptr"); }
// TODO: Atomic compare-and-set option
if(g_target.m_arch.m_atomics.ptr) { Cfg_SetValue("target_has_atomic", "cas"); }
Cfg_SetValueCb("target_feature", [](const ::std::string& s) {
Expand Down Expand Up @@ -901,7 +901,7 @@ namespace {
/// Generate a struct representation using the provided entries
///
/// - Handles (optional) sorting and packing
::std::unique_ptr<TypeRepr> make_type_repr_struct__inner(const Span&sp, const ::HIR::TypeRef& ty, ::std::vector<Ent>& ents, StructSorting sorting)
::std::unique_ptr<TypeRepr> make_type_repr_struct__inner(const Span&sp, const ::HIR::TypeRef& ty, ::std::vector<Ent>& ents, StructSorting sorting, unsigned forced_alignment)
{
if(ents.size() > 0)
{
Expand Down Expand Up @@ -956,6 +956,9 @@ namespace {
cur_ofs += e.size;
}
}
if(forced_alignment > 0) {
max_align = std::max(max_align, static_cast<size_t>(forced_alignment));
}
// If not packing (and the size isn't infinite/unsized) then round the size up to the alignment
if( sorting != StructSorting::Packed && cur_ofs != SIZE_MAX )
{
Expand All @@ -979,6 +982,7 @@ namespace {
TRACE_FUNCTION_F(ty);
::std::vector<Ent> ents;
StructSorting sorting;
unsigned forced_alignment = 0;
if( ty.data().is_Path() && ty.data().as_Path().binding.is_Struct() )
{
const auto& te = ty.data().as_Path();
Expand All @@ -987,6 +991,7 @@ namespace {
if( !struct_enumerate_fields(sp, resolve, ty, ents) )
return nullptr;

forced_alignment = str.m_forced_alignment;
sorting = StructSorting::None; // Defensive default for if repr is invalid
switch(str.m_repr)
{
Expand Down Expand Up @@ -1036,7 +1041,7 @@ namespace {
BUG(sp, "Unexpected type in creating type repr - " << ty);
}

return make_type_repr_struct__inner(sp, ty, ents, sorting);
return make_type_repr_struct__inner(sp, ty, ents, sorting, forced_alignment);
}


Expand Down Expand Up @@ -1414,7 +1419,7 @@ namespace {
std::vector< std::unique_ptr<TypeRepr> > reprs;
for( size_t i = 0; i < variants.size(); i ++ )
{
reprs.push_back( make_type_repr_struct__inner(sp, e[i].type, variants[i].ents, StructSorting::All) );
reprs.push_back( make_type_repr_struct__inner(sp, e[i].type, variants[i].ents, StructSorting::All, 0) );
max_align = std::max(max_align, reprs.back()->align);
size_t var_size = reprs.back()->size;
// If larger than current max, update current max and reset
Expand Down Expand Up @@ -1572,7 +1577,7 @@ namespace {
variants[i].ents[0].field = variants[i].ents.size() - 1;
variants[i].ents[0].ty = niche_ty.clone();
// Create the new repr
reprs[i] = make_type_repr_struct__inner(sp, variants[i].type, variants[i].ents, StructSorting::None);
reprs[i] = make_type_repr_struct__inner(sp, variants[i].type, variants[i].ents, StructSorting::None, 0);
// Make sure that the newly calculated repr doesn't change the size/alignment
assert(reprs[i]->size <= max_size);
assert(reprs[i]->align <= max_align);
Expand Down Expand Up @@ -1663,7 +1668,7 @@ namespace {
ents[0].ty = tag_ty.clone();

// - Create repr and assign
auto repr = make_type_repr_struct__inner(sp, var_ty, ents, StructSorting::None);
auto repr = make_type_repr_struct__inner(sp, var_ty, ents, StructSorting::None, 0);
max_size = std::max(max_size , repr->size );
max_align = std::max(max_align, repr->align);
set_type_repr(sp, var_ty, std::move(repr));
Expand Down

0 comments on commit a2a004f

Please sign in to comment.