From 11d1bc911f80ed81ee4c96c8c1157d60d889d4d2 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 27 Jan 2018 15:51:48 +0800 Subject: Trans - Move struct/enum layout calculation to target.cpp --- src/trans/codegen_c.cpp | 508 ++++++++++++++++++------------------------------ 1 file changed, 190 insertions(+), 318 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 57cd0eb5..9b4f7c84 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -506,11 +506,11 @@ namespace { case Compiler::Gcc: if( getenv("CC") ) { args.push_back( getenv("CC") ); - } + } else { //args.push_back( Target_GetCurSpec().m_c_compiler + "-gcc" ); args.push_back( "gcc" ); - } + } args.push_back("-ffunction-sections"); args.push_back("-pthread"); switch(opt.opt_level) @@ -833,94 +833,83 @@ namespace { const auto& lc = p.m_path.m_components.back(); is_vtable = (lc.size() > 7 && ::std::strcmp(lc.c_str() + lc.size() - 7, "#vtable") == 0); }; + bool is_packed = item.m_repr == ::HIR::Struct::Repr::Packed; TRACE_FUNCTION_F(p); - ::HIR::TypeRef tmp; - auto monomorph = [&](const auto& x)->const auto& { - if( monomorphise_type_needed(x) ) { - tmp = monomorphise_type(sp, item.m_params, p.m_params, x); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return x; - } - }; + auto item_ty = ::HIR::TypeRef::new_path(p.clone(), &item); + const auto* repr = Target_GetTypeRepr(sp, m_resolve, item_ty); bool has_unsized = false; - auto emit_struct_fld_ty = [&](const ::HIR::TypeRef& ty_raw, ::FmtLambda inner) { - const auto& ty = monomorph(ty_raw); + m_of << "// struct " << p << "\n"; + // For repr(packed), mark as packed + if(is_packed) + { + switch(m_compiler) + { + case Compiler::Msvc: + m_of << "#pragma pack(push, 1)\n"; + break; + case Compiler::Gcc: + break; + } + } + m_of << "struct s_" << Trans_Mangle(p) << " {\n"; + + // HACK: For vtables, insert the alignment and size at the start + // TODO: This should be done in HIR, not here + if(is_vtable) + { + m_of << "\tVTABLE_HDR hdr;\n"; + } + + ::std::vector fields; + for(const auto& ent : repr->fields) + { + fields.push_back(fields.size()); + } + ::std::sort(fields.begin(), fields.end(), [&](auto a, auto b){ return repr->fields[a].offset < repr->fields[b].offset; }); + for(const auto fld : fields) + { + m_of << "\t"; + const auto& ty = repr->fields[fld].ty; + TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te, - emit_ctype( *te.inner, FMT_CB(ss, ss << inner << "[0]";) ); + emit_ctype( *te.inner, FMT_CB(ss, ss << "_" << fld << "[0]";) ); has_unsized = true; ) else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, TraitObject, te, - m_of << "unsigned char " << inner << "[0]"; + m_of << "unsigned char _" << fld << "[0]"; has_unsized = true; ) else if( ty == ::HIR::CoreType::Str ) { - m_of << "uint8_t " << inner << "[0]"; + m_of << "uint8_t _" << fld << "[0]"; has_unsized = true; } else { - emit_ctype( ty, inner ); + // TODO: Nested unsized? + emit_ctype( ty, FMT_CB(ss, ss << "_" << fld) ); } - }; - m_of << "// struct " << p << "\n"; - m_of << "struct s_" << Trans_Mangle(p) << " {\n"; - - // HACK: For vtables, insert the alignment and size at the start - if(is_vtable) - { - m_of << "\tVTABLE_HDR hdr;\n"; + m_of << ";\n"; } - - TU_MATCHA( (item.m_data), (e), - (Unit, + if( fields.size() == 0 ) + { if( m_options.disallow_empty_structs ) { m_of << "\tchar _d;\n"; } - ), - (Tuple, - if( e.empty() ) - { - if( m_options.disallow_empty_structs ) - { - m_of << "\tchar _d;\n"; - } - } - else - { - for(unsigned int i = 0; i < e.size(); i ++) - { - const auto& fld = e[i]; - m_of << "\t"; - emit_struct_fld_ty(fld.ent, FMT_CB(ss, ss << "_" << i;)); - m_of << ";\n"; - } - } - ), - (Named, - if( e.empty() ) - { - if( m_options.disallow_empty_structs ) - { - m_of << "\tchar _d;\n"; - } - } - else + } + m_of << "}"; + if(is_packed) + { + switch(m_compiler) { - for(unsigned int i = 0; i < e.size(); i ++) - { - const auto& fld = e[i].second; - m_of << "\t"; - emit_struct_fld_ty(fld.ent, FMT_CB(ss, ss << "_" << i;)); - m_of << ";\n"; - } + case Compiler::Msvc: + m_of << ";\n#pragma pack(pop)\n"; + break; + case Compiler::Gcc: + m_of << " __attribute__((packed));\n"; + break; } - ) - ) - m_of << "};\n"; + } auto struct_ty = ::HIR::TypeRef(p.clone(), &item); auto drop_glue_path = ::HIR::Path(struct_ty.clone(), "#drop_glue"); @@ -959,28 +948,12 @@ namespace { auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 }); - TU_MATCHA( (item.m_data), (e), - (Unit, - ), - (Tuple, - for(unsigned int i = 0; i < e.size(); i ++) - { - const auto& fld = e[i]; - fld_lv.as_Field().field_index = i; - - emit_destructor_call(fld_lv, monomorph(fld.ent), true, 1); - } - ), - (Named, - for(unsigned int i = 0; i < e.size(); i ++) - { - const auto& fld = e[i].second; - fld_lv.as_Field().field_index = i; + for(size_t i = 0; i < repr->fields.size(); i++) + { + fld_lv.as_Field().field_index = i; - emit_destructor_call(fld_lv, monomorph(fld.ent), true, 1); - } - ) - ) + emit_destructor_call(fld_lv, repr->fields[i].ty, /*unsized_valid=*/true, /*indent=*/1); + } m_of << "}\n"; m_mir_res = nullptr; } @@ -991,27 +964,19 @@ namespace { m_mir_res = &top_mir_res; TRACE_FUNCTION_F(p); + auto item_ty = ::HIR::TypeRef::new_path(p.clone(), &item); + const auto* repr = Target_GetTypeRepr(sp, m_resolve, item_ty); + MIR_ASSERT(*m_mir_res, repr != nullptr, "No repr for union " << item_ty); - ::HIR::TypeRef tmp; - auto monomorph = [&](const auto& x)->const auto& { - if( monomorphise_type_needed(x) ) { - tmp = monomorphise_type(sp, item.m_params, p.m_params, x); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return x; - } - }; m_of << "union u_" << Trans_Mangle(p) << " {\n"; - for(unsigned int i = 0; i < item.m_variants.size(); i ++) + for(unsigned int i = 0; i < repr->fields.size(); i ++) { - m_of << "\t"; emit_ctype( monomorph(item.m_variants[i].second.ent), FMT_CB(ss, ss << "var_" << i;) ); m_of << ";\n"; + assert(repr->fields[i].offset == 0); + m_of << "\t"; emit_ctype( repr->fields[i].ty, FMT_CB(ss, ss << "var_" << i;) ); m_of << ";\n"; } m_of << "};\n"; // Drop glue (calls destructor if there is one) - auto item_ty = ::HIR::TypeRef(p.clone(), &item); auto drop_glue_path = ::HIR::Path(item_ty.clone(), "#drop_glue"); auto item_ptr_ty = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Owned, item_ty.clone()); auto drop_impl_path = (item.m_markings.has_drop_impl ? ::HIR::Path(item_ty.clone(), m_resolve.m_lang_Drop, "drop") : ::HIR::Path(::HIR::SimplePath())); @@ -1031,79 +996,19 @@ namespace { m_of << "}\n"; } - // TODO: Move this to codegen.cpp? - bool get_nonzero_path(const Span& sp, const ::HIR::TypeRef& ty, ::std::vector& out) const + void emit_enum_path(const TypeRepr* repr, const TypeRepr::FieldPath& path) { - TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), - ( - return false; - ), - (Path, - if( te.binding.is_Struct() ) - { - const auto& str = *te.binding.as_Struct(); - const auto& p = te.path.m_data.as_Generic(); - ::HIR::TypeRef tmp; - auto monomorph = [&](const auto& ty)->const auto& { - if( monomorphise_type_needed(ty) ) { - tmp = monomorphise_type(sp, str.m_params, p.m_params, ty); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return ty; - } - }; - TU_MATCHA( (str.m_data), (se), - (Unit, - ), - (Tuple, - for(size_t i = 0; i < se.size(); i ++) - { - if( get_nonzero_path(sp, monomorph(se[i].ent), out) ) - { - out.push_back(i); - return true; - } - } - ), - (Named, - for(size_t i = 0; i < se.size(); i ++) - { - if( get_nonzero_path(sp, monomorph(se[i].second.ent), out) ) - { - out.push_back(i); - return true; - } - } - ) - ) - } - return false; - ), - (Borrow, - if( metadata_type(*te.inner) != MetadataType::None ) - { - // HACK: If the inner is a DST, emit ~0 as a marker - out.push_back(~0u); - } - return true; - ), - (Function, - return true; - ) - ) - } - void emit_nonzero_path(const ::std::vector& nonzero_path) { - for(const auto v : nonzero_path) + if( path.index == repr->fields.size() - 1 ) { - if(v == ~0u) { - // NOTE: Should only ever be the last - m_of << ".PTR"; - } - else { - m_of << "._" << v; - } + m_of << ".TAG"; + } + else + { + m_of << ".DATA.var_" << path.index; + } + for(auto fld : path.sub_fields) + { + m_of << "._" << fld; } } @@ -1114,102 +1019,74 @@ namespace { m_mir_res = &top_mir_res; TRACE_FUNCTION_F(p); - ::HIR::TypeRef tmp; - auto monomorph = [&](const auto& x)->const auto& { - if( monomorphise_type_needed(x) ) { - tmp = monomorphise_type(sp, item.m_params, p.m_params, x); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return x; - } - }; + auto item_ty = ::HIR::TypeRef::new_path(p.clone(), &item); + const auto* repr = Target_GetTypeRepr(sp, m_resolve, item_ty); - // TODO: Cache repr info elsewhere (and have core codegen be responsible instead) - // TODO: Do more complex nonzero relations. - ::std::vector nonzero_path; + // 1. Enumerate fields with the same offset as the first (these go into a union) + ::std::vector union_fields; + for(size_t i = 1; i < repr->fields.size(); i ++) { - // Detect Option (and similar enums) - // - Matches two-variant enums where the first variant is unit-like, and the second is not - if( item.m_data.is_Data() && item.m_data.as_Data().size() == 2 - && item.m_data.as_Data()[0].type == ::HIR::TypeRef::new_unit() - && item.m_data.as_Data()[1].type != ::HIR::TypeRef::new_unit() - ) + if( repr->fields[i].offset == repr->fields[0].offset ) { - const auto& data_type = monomorph(item.m_data.as_Data()[1].type); - if( get_nonzero_path(sp, data_type, nonzero_path) ) - { - ::std::reverse( nonzero_path.begin(), nonzero_path.end() ); - DEBUG("Correct format for NonZero to apply, and field found at " << nonzero_path); - } - else - { - DEBUG("Correct format for NonZero to apply, but no field"); - assert(nonzero_path.size() == 0); - } + union_fields.push_back(i); } } m_of << "// enum " << p << "\n"; - if( nonzero_path.size() > 0 ) - { - //MIR_ASSERT(*m_mir_res, item.num_variants() == 2, ""); - //MIR_ASSERT(*m_mir_res, item.m_variants[0].second.is_Unit(), ""); - //const auto& data_var = item.m_variants[1]; - //MIR_ASSERT(*m_mir_res, data_var.second.is_Tuple(), ""); - //MIR_ASSERT(*m_mir_res, data_var.second.as_Tuple().size() == 1, ""); - const auto& data_type = monomorph(item.m_data.as_Data()[1].type); - m_of << "struct e_" << Trans_Mangle(p) << " {\n"; - m_of << "\t"; emit_ctype(data_type, FMT_CB(s, s << "_1";)); m_of << ";\n"; - m_of << "};\n"; - } - else if( item.m_data.is_Value() ) + m_of << "struct e_" << Trans_Mangle(p) << " {\n"; + + // If there multiple fields with the same offset, they're the data variants + if( union_fields.size() > 0 ) { - m_of << "struct e_" << Trans_Mangle(p) << " {\n"; - switch(item.m_data.as_Value().repr) + assert(1 + union_fields.size() + 1 >= repr->fields.size()); + // Make the union! + // NOTE: The way the structure generation works is that enum variants are always first, so the field index = the variant index + m_of << "\tunion {\n"; + // > First field + m_of << "\t\t"; + emit_ctype(repr->fields[0].ty, FMT_CB(os, os << "var_0")); + m_of << ";\n"; + // > All others + for(auto idx : union_fields) { - case ::HIR::Enum::Repr::Rust: - case ::HIR::Enum::Repr::C: - m_of << "\tunsigned int TAG;\n"; - break; - case ::HIR::Enum::Repr::Usize: - m_of << "\tuintptr_t TAG;\n"; - break; - case ::HIR::Enum::Repr::U8: - m_of << "\tuint8_t TAG;\n"; - break; - case ::HIR::Enum::Repr::U16: - m_of << "\tuint16_t TAG;\n"; - break; - case ::HIR::Enum::Repr::U32: - m_of << "\tuint32_t TAG;\n"; - break; - case ::HIR::Enum::Repr::U64: - m_of << "\tuint64_t TAG;\n"; - break; + // TODO: if the compiler doesn't allow zero-sized types, don't emit zero-sized fields. + m_of << "\t\t"; + emit_ctype(repr->fields[idx].ty, FMT_CB(os, os << "var_" << idx)); + m_of << ";\n"; } - m_of << "};\n"; + m_of << "\t} DATA;\n"; + + if( repr->fields.size() == 1 + union_fields.size() ) + { + // No tag, the tag is in one of the fields. + DEBUG("Untagged, nonzero or other"); + } + else + { + assert(repr->fields.back().offset != repr->fields.front().offset); + DEBUG("Tag present at offset " << repr->fields.back().offset << " - " << repr->fields.back().ty); + + m_of << "\t"; + emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG")); + m_of << ";\n"; + } + } + else if( repr->fields.size() == 1 ) + { + // Tag only. + // - A value-only enum. + m_of << "\t"; + emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG")); + m_of << ";\n"; } else { - const auto& variants = item.m_data.as_Data(); - m_of << "struct e_" << Trans_Mangle(p) << " {\n"; - m_of << "\tunsigned int TAG;\n"; - if( variants.size() > 0 ) - { - m_of << "\tunion {\n"; - for(unsigned int i = 0; i < variants.size(); i ++) - { - m_of << "\t\t"; - emit_ctype( monomorph(variants[i].type) ); - m_of << " var_" << i << ";\n"; - } - m_of << "\t} DATA;\n"; - } - m_of << "};\n"; + // One data field and a tag (or all different offsets) + TODO(sp, "No common offsets and more than one field, is this possible? - " << item_ty); } + m_of << "};\n"; + // --- // - Drop Glue // --- @@ -1234,39 +1111,35 @@ namespace { } auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); - if( nonzero_path.size() > 0 ) + if( const auto* e = repr->variants.opt_NonZero() ) { + unsigned idx = 1 - e->zero_variant; // TODO: Fat pointers? - m_of << "\tif( (*rv)._1"; emit_nonzero_path(nonzero_path); m_of << " ) {\n"; - emit_destructor_call( ::MIR::LValue::make_Field({ box$(self), 1 }), monomorph(item.m_data.as_Data()[1].type), false, 2 ); + m_of << "\tif( rv"; emit_enum_path(repr, e->field); m_of << "!= 0 ) {\n"; + emit_destructor_call( ::MIR::LValue::make_Field({ box$(self), idx }), repr->fields[idx].ty, false, 2 ); m_of << "\t}\n"; } - else if( const auto* e = item.m_data.opt_Data() ) + else if( repr->fields.size() == 1 ) + { + // Value enum + // Glue does nothing (except call the destructor, if there is one) + } + else if( const auto* e = repr->variants.opt_Values() ) { auto var_lv =::MIR::LValue::make_Downcast({ box$(self), 0 }); m_of << "\tswitch(rv->TAG) {\n"; - for(unsigned int var_idx = 0; var_idx < e->size(); var_idx ++) + for(unsigned int var_idx = 0; var_idx < e->values.size(); var_idx ++) { var_lv.as_Downcast().variant_index = var_idx; - m_of << "\tcase " << var_idx << ":\n"; - emit_destructor_call(var_lv, monomorph( (*e)[var_idx].type ), false, 2); + m_of << "\tcase " << e->values[var_idx] << ":\n"; + emit_destructor_call(var_lv, repr->fields[var_idx].ty, /*unsized_valid=*/false, /*indent=*/2); m_of << "\tbreak;\n"; } m_of << "\t}\n"; } - else - { - // Value enum - // Glue does nothing (except call the destructor, if there is one) - } m_of << "}\n"; m_mir_res = nullptr; - - if( nonzero_path.size() ) - { - m_enum_repr_cache.insert( ::std::make_pair( p.clone(), mv$(nonzero_path) ) ); - } } void emit_constructor_enum(const Span& sp, const ::HIR::GenericPath& path, const ::HIR::Enum& item, size_t var_idx) override @@ -2848,28 +2721,27 @@ namespace { const auto& ty = mir_res.get_lvalue_type(tmp, val); MIR_ASSERT(mir_res, ty.m_data.is_Path(), "Switch over non-Path type"); MIR_ASSERT(mir_res, ty.m_data.as_Path().binding.is_Enum(), "Switch over non-enum"); - const auto* enm = ty.m_data.as_Path().binding.as_Enum(); + const auto* repr = Target_GetTypeRepr(mir_res.sp, m_resolve, ty); + MIR_ASSERT(mir_res, repr, "No repr for " << ty); - auto it = m_enum_repr_cache.find( ty.m_data.as_Path().path.m_data.as_Generic() ); - if( it != m_enum_repr_cache.end() ) + if( const auto* e = repr->variants.opt_NonZero() ) { - //MIR_ASSERT(mir_res, e.targets.size() == 2, "NonZero optimised representation for an enum without two variants"); MIR_ASSERT(mir_res, n_arms == 2, "NonZero optimised switch without two arms"); - m_of << indent << "if("; emit_lvalue(val); m_of << "._1"; emit_nonzero_path(it->second); m_of << ")\n"; + m_of << indent << "if( "; emit_lvalue(val); emit_enum_path(repr, e->field); m_of << " != 0)\n"; m_of << indent; - cb(1); + cb(1 - e->zero_variant); m_of << "\n"; m_of << indent << "else\n"; m_of << indent; - cb(0); + cb(e->zero_variant); m_of << "\n"; } - else if( enm->is_value() ) + else if( const auto* e = repr->variants.opt_Values() ) { m_of << indent << "switch("; emit_lvalue(val); m_of << ".TAG) {\n"; for(size_t j = 0; j < n_arms; j ++) { - m_of << indent << "case " << enm->get_value(j) << ": "; + m_of << indent << "case " << e->values[j] << ": "; cb(j); m_of << "\n"; } @@ -2878,15 +2750,7 @@ namespace { } else { - m_of << indent << "switch("; emit_lvalue(val); m_of << ".TAG) {\n"; - for(size_t j = 0; j < n_arms; j ++) - { - m_of << indent << "case " << j << ": "; - cb(j); - m_of << "\n"; - } - m_of << indent << "default: abort();\n"; - m_of << indent << "}\n"; + BUG(sp, ""); } } void emit_term_switchvalue(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& val, const ::MIR::SwitchValues& values, unsigned indent_level, ::std::function cb) @@ -3698,20 +3562,27 @@ namespace { else if( name == "discriminant_value" ) { const auto& ty = params.m_types.at(0); emit_lvalue(e.ret_val); m_of << " = "; - if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Enum() ) { - auto it = m_enum_repr_cache.find( ty.m_data.as_Path().path.m_data.as_Generic() ); - if( it != m_enum_repr_cache.end() ) - { - emit_param(e.args.at(0)); m_of << "->_1"; emit_nonzero_path(it->second); m_of << " != 0"; - } - else + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); + if( !repr ) { + m_of << "0"; + } + else { + switch(repr->variants.tag()) { + case TypeRepr::VariantMode::TAGDEAD: throw ""; + TU_ARM(repr->variants, None, _e) + m_of << "0"; + break; + TU_ARM(repr->variants, Values, _e) { emit_param(e.args.at(0)); m_of << "->TAG"; + } break; + TU_ARM(repr->variants, NonZero, ve) { + emit_param(e.args.at(0)); emit_enum_path(repr, ve.field); m_of << " "; + m_of << (ve.zero_variant ? "==" : "!="); + m_of << "0"; + } break; } } - else { - m_of << "0"; - } } // Hints else if( name == "unreachable" ) { @@ -4325,28 +4196,29 @@ namespace { (Variant, MIR_ASSERT(*m_mir_res, ty.m_data.is_Path(), ""); MIR_ASSERT(*m_mir_res, ty.m_data.as_Path().binding.is_Enum(), ""); - const auto& enm = *ty.m_data.as_Path().binding.as_Enum(); - auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); - if( it != m_enum_repr_cache.end() ) + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); + MIR_ASSERT(*m_mir_res, repr, ""); + switch(repr->variants.tag()) { - if( e.idx == 0 ) { - emit_nonzero_path(it->second); - m_of << " = 0"; + case TypeRepr::VariantMode::TAGDEAD: throw ""; + TU_ARM(repr->variants, None, ve) + BUG(sp, ""); + TU_ARM(repr->variants, NonZero, ve) { + if( e.idx == ve.zero_variant ) { + emit_dst(); emit_enum_path(repr, ve.field); m_of << " = 0"; } else { assign_from_literal([&](){ emit_dst(); }, get_inner_type(e.idx, 0), *e.val); } - } - else if( enm.is_value() ) - { - MIR_ASSERT(*m_mir_res, TU_TEST1((*e.val), List, .empty()), "Value-only enum with fields"); - emit_dst(); m_of << ".TAG = " << enm.get_value(e.idx); - } - else - { - emit_dst(); m_of << ".TAG = " << e.idx; - m_of << ";\n\t"; - assign_from_literal([&](){ emit_dst(); m_of << ".DATA.var_" << e.idx; }, get_inner_type(e.idx, 0), *e.val); + } break; + TU_ARM(repr->variants, Values, ve) { + emit_dst(); emit_enum_path(repr, ve.field); m_of << " = " << ve.values[e.idx]; + if( TU_TEST1((*e.val), List, .empty() == false) ) + { + m_of << ";\n\t"; + assign_from_literal([&](){ emit_dst(); m_of << ".DATA.var_" << e.idx; }, get_inner_type(e.idx, 0), *e.val); + } + } break; } ), (Integer, -- cgit v1.2.3 From 05e399b35d71118b375510d35ca5a89876bcbfcd Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 1 Feb 2018 18:03:08 +0800 Subject: Codegen C - Minor fixes from target structure layout --- src/trans/codegen_c.cpp | 139 ++++++++++++++++++++++++++---------------------- src/trans/target.cpp | 6 +-- 2 files changed, 78 insertions(+), 67 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 9b4f7c84..b7bdfec4 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -195,8 +195,6 @@ namespace { bool disallow_empty_structs = false; } m_options; - ::std::map<::HIR::GenericPath, ::std::vector> m_enum_repr_cache; - ::std::vector< ::std::pair< ::HIR::GenericPath, const ::HIR::Struct*> > m_box_glue_todo; public: CodeGenerator_C(const ::HIR::Crate& crate, const ::std::string& outfile): @@ -910,6 +908,10 @@ namespace { break; } } + else + { + m_of << ";\n"; + } auto struct_ty = ::HIR::TypeRef(p.clone(), &item); auto drop_glue_path = ::HIR::Path(struct_ty.clone(), "#drop_glue"); @@ -998,7 +1000,7 @@ namespace { void emit_enum_path(const TypeRepr* repr, const TypeRepr::FieldPath& path) { - if( path.index == repr->fields.size() - 1 ) + if( path.index == repr->fields.size() - 1 && !repr->variants.is_NonZero() ) { m_of << ".TAG"; } @@ -1006,10 +1008,19 @@ namespace { { m_of << ".DATA.var_" << path.index; } + const auto* ty = &repr->fields[path.index].ty; for(auto fld : path.sub_fields) { + repr = Target_GetTypeRepr(sp, m_resolve, *ty); + ty = &repr->fields[fld].ty; m_of << "._" << fld; } + if( const auto* te = ty->m_data.opt_Borrow() ) + { + if( metadata_type(*te->inner) != MetadataType::None ) { + m_of << ".PTR"; + } + } } void emit_enum(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Enum& item) override @@ -1023,9 +1034,13 @@ namespace { const auto* repr = Target_GetTypeRepr(sp, m_resolve, item_ty); // 1. Enumerate fields with the same offset as the first (these go into a union) + // TODO: What if all data variants are zero-sized? ::std::vector union_fields; for(size_t i = 1; i < repr->fields.size(); i ++) { + // Avoid placing the tag in the union + if( repr->variants.is_Values() && i == repr->variants.as_Values().field.index ) + continue ; if( repr->fields[i].offset == repr->fields[0].offset ) { union_fields.push_back(i); @@ -1063,7 +1078,7 @@ namespace { } else { - assert(repr->fields.back().offset != repr->fields.front().offset); + //assert(repr->fields.back().offset != repr->fields.front().offset); DEBUG("Tag present at offset " << repr->fields.back().offset << " - " << repr->fields.back().ty); m_of << "\t"; @@ -1079,6 +1094,15 @@ namespace { emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG")); m_of << ";\n"; } + else if( repr->fields.size() == 0 ) + { + // Empty/un-constructable + // - Shouldn't be emitted really? + if( m_options.disallow_empty_structs ) + { + m_of << "\tchar _d;\n"; + } + } else { // One data field and a tag (or all different offsets) @@ -1115,11 +1139,11 @@ namespace { { unsigned idx = 1 - e->zero_variant; // TODO: Fat pointers? - m_of << "\tif( rv"; emit_enum_path(repr, e->field); m_of << "!= 0 ) {\n"; - emit_destructor_call( ::MIR::LValue::make_Field({ box$(self), idx }), repr->fields[idx].ty, false, 2 ); + m_of << "\tif( (*rv)"; emit_enum_path(repr, e->field); m_of << " != 0 ) {\n"; + emit_destructor_call( ::MIR::LValue::make_Downcast({ box$(self), idx }), repr->fields[idx].ty, false, 2 ); m_of << "\t}\n"; } - else if( repr->fields.size() == 1 ) + else if( repr->fields.size() <= 1 ) { // Value enum // Glue does nothing (except call the destructor, if there is one) @@ -1159,6 +1183,7 @@ namespace { auto p = path.clone(); p.m_path.m_components.pop_back(); + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ::HIR::TypeRef::new_path(p.clone(), &item)); ASSERT_BUG(sp, item.m_data.is_Data(), ""); const auto& var = item.m_data.as_Data().at(var_idx); @@ -1176,39 +1201,33 @@ namespace { emit_ctype( monomorph(e[i].ent), FMT_CB(ss, ss << "_" << i;) ); } m_of << ") {\n"; - auto it = m_enum_repr_cache.find(p); - if( it != m_enum_repr_cache.end() ) - { - m_of << "\tstruct e_" << Trans_Mangle(p) << " rv = { _0 };\n"; - } - else - { - m_of << "\tstruct e_" << Trans_Mangle(p) << " rv = { .TAG = " << var_idx; - if( e.empty() ) + //if( repr->variants. + m_of << "\tstruct e_" << Trans_Mangle(p) << " rv = { .TAG = " << var_idx; + + if( e.empty() ) + { + if( m_options.disallow_empty_structs ) { - if( m_options.disallow_empty_structs ) - { - m_of << ", .DATA = { .var_" << var_idx << " = {0} }"; - } - else - { - // No fields, don't initialise - } + m_of << ", .DATA = { .var_" << var_idx << " = {0} }"; } else { - m_of << ", .DATA = { .var_" << var_idx << " = {"; - for(unsigned int i = 0; i < e.size(); i ++) - { - if(i != 0) - m_of << ","; - m_of << "\n\t\t_" << i; - } - m_of << "\n\t\t}"; + // No fields, don't initialise + } + } + else + { + m_of << ", .DATA = { .var_" << var_idx << " = {"; + for(unsigned int i = 0; i < e.size(); i ++) + { + if(i != 0) + m_of << ","; + m_of << "\n\t\t_" << i; } - m_of << " }};\n"; + m_of << "\n\t\t}"; } + m_of << " }};\n"; m_of << "\treturn rv;\n"; m_of << "}\n"; } @@ -1369,7 +1388,7 @@ namespace { MIR_TODO(*m_mir_res, "Union literals"); ), (Enum, - MIR_ASSERT(*m_mir_res, pbe->m_data.is_Data(), ""); + MIR_ASSERT(*m_mir_res, pbe->m_data.is_Data(), "Getting inner type of a non-Data enum"); const auto& evar = pbe->m_data.as_Data().at(var); return monomorph_with(pp, evar.type); ) @@ -1403,15 +1422,19 @@ namespace { (Variant, MIR_ASSERT(*m_mir_res, ty.m_data.is_Path(), ""); MIR_ASSERT(*m_mir_res, ty.m_data.as_Path().binding.is_Enum(), ""); + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); const auto& enm = *ty.m_data.as_Path().binding.as_Enum(); - auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); - if( it != m_enum_repr_cache.end() ) + if( const auto* ve = repr->variants.opt_NonZero() ) { - if( e.idx == 0 ) { + if( e.idx == ve->zero_variant ) + { m_of << "{0}"; } - else { + else + { + m_of << "{ { .var_" << e.idx << " = "; emit_literal(get_inner_type(e.idx, 0), *e.val, params); + m_of << " } }"; } } else if( enm.is_value() ) @@ -1421,10 +1444,10 @@ namespace { } else { - m_of << "{" << e.idx; - m_of << ", { .var_" << e.idx << " = "; + m_of << "{"; + m_of << " { .var_" << e.idx << " = "; emit_literal(get_inner_type(e.idx, 0), *e.val, params); - m_of << " }"; + m_of << " }, .TAG = " << e.idx; m_of << "}"; } ), @@ -1747,7 +1770,7 @@ namespace { else if( item.m_linkage.name == "CopyFileExW" ) { // Not field access to undo an Option - m_of << "\treturn CopyFileExW(arg0, arg1, arg2._1._0, arg3, arg4, arg5);\n"; + m_of << "\treturn CopyFileExW(arg0, arg1, arg2.DATA.var_1._0, arg3, arg4, arg5);\n"; } // BUG: libtest defines this as returning an i32, but it's void else if( item.m_linkage.name == "GetSystemInfo" ) @@ -2489,21 +2512,20 @@ namespace { { ::HIR::TypeRef tmp; const auto& ty = mir_res.get_lvalue_type(tmp, e.dst); + auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); - auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); - if( it != m_enum_repr_cache.end() ) + if( const auto* re = repr->variants.opt_NonZero() ) { - if( ve.index == 0 ) { + MIR_ASSERT(*m_mir_res, ve.index < 2, ""); + if( ve.index == re->zero_variant ) { // TODO: Use nonzero_path m_of << "memset(&"; emit_lvalue(e.dst); m_of << ", 0, sizeof("; emit_ctype(ty); m_of << "))"; } - else if( ve.index == 1 ) { + else { emit_lvalue(e.dst); - m_of << "._1 = "; + m_of << ".DATA.var_" << ve.index << " = "; emit_param(ve.val); } - else { - } break; } else if( enm_p->is_value() ) @@ -2727,12 +2749,12 @@ namespace { if( const auto* e = repr->variants.opt_NonZero() ) { MIR_ASSERT(mir_res, n_arms == 2, "NonZero optimised switch without two arms"); - m_of << indent << "if( "; emit_lvalue(val); emit_enum_path(repr, e->field); m_of << " != 0)\n"; - m_of << indent; + m_of << indent << "if( "; emit_lvalue(val); emit_enum_path(repr, e->field); m_of << " != 0 )\n"; + m_of << indent << "\t"; cb(1 - e->zero_variant); m_of << "\n"; m_of << indent << "else\n"; - m_of << indent; + m_of << indent << "\t"; cb(e->zero_variant); m_of << "\n"; } @@ -4381,18 +4403,7 @@ namespace { MIR_ASSERT(*m_mir_res, ty.m_data.is_Path(), "Downcast on non-Path type - " << ty); if( ty.m_data.as_Path().binding.is_Enum() ) { - auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); - if( it != m_enum_repr_cache.end() ) - { - MIR_ASSERT(*m_mir_res, e.variant_index == 1, ""); - // NOTE: Downcast returns a magic tuple - m_of << "._1"; - break ; - } - else - { - m_of << ".DATA"; - } + m_of << ".DATA"; } m_of << ".var_" << e.variant_index; ) diff --git a/src/trans/target.cpp b/src/trans/target.cpp index b67bc0ea..cf4d0fbc 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -571,7 +571,7 @@ namespace { 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"); + ASSERT_BUG(sp, &e == &ents.back(), "Unsized item isn't the last item in " << ty); cur_ofs = SIZE_MAX; } else @@ -617,12 +617,12 @@ namespace { } } break; TU_ARM(ty.m_data, Borrow, _te) { (void)_te; - out_path.sub_fields.push_back(0); + //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) (void)_te; - out_path.sub_fields.push_back(0); + //out_path.sub_fields.push_back(0); Target_GetSizeOf(sp, resolve, ty, out_path.size); return true; default: -- cgit v1.2.3 From 8fb6df4340c186fbc391b18dc026cd868f74b6ac Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 4 Feb 2018 17:38:57 +0800 Subject: Trans - mingw32 target attempt (still being worked on) --- src/include/tagged_union.hpp | 2 +- src/trans/codegen_c.cpp | 282 ++++++++++++++++++++++++++++++++++--------- src/trans/codegen_mmir.cpp | 13 +- src/trans/target.cpp | 32 +++-- src/trans/target.hpp | 2 + 5 files changed, 262 insertions(+), 69 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp index 9d95038c..478953b9 100644 --- a/src/include/tagged_union.hpp +++ b/src/include/tagged_union.hpp @@ -110,7 +110,7 @@ #define TU_IFLET(CLASS, VAR, TAG, NAME, ...) if(VAR.tag() == CLASS::TAG_##TAG) { auto& NAME = VAR.as_##TAG(); (void)&NAME; __VA_ARGS__ } // Evil hack: two for loops, the inner stops the outer after it's done. -#define TU_ARM(VAR, TAG, NAME) case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = VAR.as_##TAG(); tu_lc; tu_lc=false) +#define TU_ARM(VAR, TAG, NAME) case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = VAR.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) //#define TU_TEST(VAL, ...) (VAL.is_##TAG() && VAL.as_##TAG() TEST) #define TU_TEST1(VAL, TAG1, TEST) (VAL.is_##TAG1() && VAL.as_##TAG1() TEST) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index b7bdfec4..724b40cd 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -209,6 +209,10 @@ namespace { case CodegenMode::Gnu11: m_compiler = Compiler::Gcc; m_options.emulated_i128 = false; + if( Target_GetCurSpec().m_arch.m_pointer_bits < 64 ) + { + m_options.emulated_i128 = true; + } break; case CodegenMode::Msvc: m_compiler = Compiler::Msvc; @@ -273,8 +277,6 @@ namespace { { case Compiler::Gcc: m_of - << "typedef unsigned __int128 uint128_t;\n" - << "typedef signed __int128 int128_t;\n" << "extern void _Unwind_Resume(void) __attribute__((noreturn));\n" << "#define ALIGNOF(t) __alignof__(t)\n" ; @@ -367,22 +369,15 @@ namespace { m_of << "typedef struct { uint64_t lo, hi; } uint128_t;\n" << "typedef struct { uint64_t lo, hi; } int128_t;\n" - << "static inline int128_t make128s(int64_t v) { int128_t rv = { v, (v < 0 ? -1 : 0) }; return rv; }\n" - << "static inline int128_t add128s(int128_t a, int128_t b) { int128_t v; v.lo = a.lo + b.lo; v.hi = a.hi + b.hi + (v.lo < a.lo ? 1 : 0); return v; }\n" - << "static inline int128_t sub128s(int128_t a, int128_t b) { int128_t v; v.lo = a.lo - b.lo; v.hi = a.hi - b.hi - (v.lo > a.lo ? 1 : 0); return v; }\n" - << "static inline int128_t mul128s(int128_t a, int128_t b) { abort(); }\n" - << "static inline int128_t div128s(int128_t a, int128_t b) { abort(); }\n" - << "static inline int128_t mod128s(int128_t a, int128_t b) { abort(); }\n" - << "static inline int128_t and128s(int128_t a, int128_t b) { int128_t v = { a.lo & b.lo, a.hi & b.hi }; return v; }\n" - << "static inline int128_t or128s (int128_t a, int128_t b) { int128_t v = { a.lo | b.lo, a.hi | b.hi }; return v; }\n" - << "static inline int128_t xor128s(int128_t a, int128_t b) { int128_t v = { a.lo ^ b.lo, a.hi ^ b.hi }; return v; }\n" - << "static inline int128_t shl128s(int128_t a, uint32_t b) { int128_t v; if(b < 64) { v.lo = a.lo << b; v.hi = (a.hi << b) | (a.lo >> (64 - b)); } else { v.hi = a.lo << (b - 64); v.lo = 0; } return v; }\n" - << "static inline int128_t shr128s(int128_t a, uint32_t b) { int128_t v; if(b < 64) { v.lo = (a.lo >> b)|(a.hi << (64 - b)); v.hi = a.hi >> b; } else { v.lo = a.hi >> (b - 64); v.hi = 0; } return v; }\n" << "static inline uint128_t make128(uint64_t v) { uint128_t rv = { v, 0 }; return rv; }\n" - << "static inline uint128_t add128(uint128_t a, uint128_t b) { uint128_t v; v.lo = a.lo + b.lo; v.hi = a.hi + b.hi + (v.lo < a.lo ? 1 : 0); return v; }\n" - << "static inline uint128_t sub128(uint128_t a, uint128_t b) { uint128_t v; v.lo = a.lo - b.lo; v.hi = a.hi - b.hi - (v.lo > a.lo ? 1 : 0); return v; }\n" - << "static inline uint128_t mul128(uint128_t a, uint128_t b) { abort(); }\n" - << "static inline uint128_t div128(uint128_t a, uint128_t b) { abort(); }\n" + << "static inline bool add128_o(uint128_t a, uint128_t b, uint128_t* o) { o->lo = a.lo + b.lo; o->hi = a.hi + b.hi + (o->lo < a.lo ? 1 : 0); return (o->hi >= a.hi); }\n" + << "static inline bool sub128_o(uint128_t a, uint128_t b, uint128_t* o) { o->lo = a.lo - b.lo; o->hi = a.hi - b.hi - (o->lo < a.lo ? 1 : 0); return (o->hi <= a.hi); }\n" + << "static inline bool mul128_o(uint128_t a, uint128_t b, uint128_t* o) { abort(); }\n" + << "static inline bool div128_o(uint128_t a, uint128_t b, uint128_t* o) { abort(); }\n" + << "static inline uint128_t add128(uint128_t a, uint128_t b) { uint128_t v; add128_o(a, b, &v); return v; }\n" + << "static inline uint128_t sub128(uint128_t a, uint128_t b) { uint128_t v; sub128_o(a, b, &v); return v; }\n" + << "static inline uint128_t mul128(uint128_t a, uint128_t b) { uint128_t v; mul128_o(a, b, &v); return v; }\n" + << "static inline uint128_t div128(uint128_t a, uint128_t b) { uint128_t v; div128_o(a, b, &v); return v; }\n" << "static inline uint128_t mod128(uint128_t a, uint128_t b) { abort(); }\n" << "static inline uint128_t and128(uint128_t a, uint128_t b) { uint128_t v = { a.lo & b.lo, a.hi & b.hi }; return v; }\n" << "static inline uint128_t or128 (uint128_t a, uint128_t b) { uint128_t v = { a.lo | b.lo, a.hi | b.hi }; return v; }\n" @@ -399,12 +394,25 @@ namespace { << "\tuint128_t rv = { (v.lo == 0 ? (v.hi == 0 ? 128 : __builtin_ctz64(v.hi) + 64) : __builtin_ctz64(v.lo)), 0 };\n" << "\treturn rv;\n" << "}\n" + << "static inline int128_t make128s(int64_t v) { int128_t rv = { v, (v < 0 ? -1 : 0) }; return rv; }\n" + << "static inline int128_t add128s(int128_t a, int128_t b) { int128_t v; v.lo = a.lo + b.lo; v.hi = a.hi + b.hi + (v.lo < a.lo ? 1 : 0); return v; }\n" + << "static inline int128_t sub128s(int128_t a, int128_t b) { int128_t v; v.lo = a.lo - b.lo; v.hi = a.hi - b.hi - (v.lo > a.lo ? 1 : 0); return v; }\n" + << "static inline int128_t mul128s(int128_t a, int128_t b) { abort(); }\n" + << "static inline int128_t div128s(int128_t a, int128_t b) { abort(); }\n" + << "static inline int128_t mod128s(int128_t a, int128_t b) { abort(); }\n" + << "static inline int128_t and128s(int128_t a, int128_t b) { int128_t v = { a.lo & b.lo, a.hi & b.hi }; return v; }\n" + << "static inline int128_t or128s (int128_t a, int128_t b) { int128_t v = { a.lo | b.lo, a.hi | b.hi }; return v; }\n" + << "static inline int128_t xor128s(int128_t a, int128_t b) { int128_t v = { a.lo ^ b.lo, a.hi ^ b.hi }; return v; }\n" + << "static inline int128_t shl128s(int128_t a, uint32_t b) { int128_t v; if(b < 64) { v.lo = a.lo << b; v.hi = (a.hi << b) | (a.lo >> (64 - b)); } else { v.hi = a.lo << (b - 64); v.lo = 0; } return v; }\n" + << "static inline int128_t shr128s(int128_t a, uint32_t b) { int128_t v; if(b < 64) { v.lo = (a.lo >> b)|(a.hi << (64 - b)); v.hi = a.hi >> b; } else { v.lo = a.hi >> (b - 64); v.hi = 0; } return v; }\n" ; } else { // GCC-only m_of + << "typedef unsigned __int128 uint128_t;\n" + << "typedef signed __int128 int128_t;\n" << "static inline uint128_t __builtin_bswap128(uint128_t v) {\n" << "\tuint64_t lo = __builtin_bswap64((uint64_t)v);\n" << "\tuint64_t hi = __builtin_bswap64((uint64_t)(v>>64));\n" @@ -498,7 +506,11 @@ namespace { // Execute $CC with the required libraries StringList args; +#ifdef _WIN32 + bool is_windows = true; +#else bool is_windows = false; +#endif switch( m_compiler ) { case Compiler::Gcc: @@ -561,7 +573,6 @@ namespace { } break; case Compiler::Msvc: - is_windows = true; // TODO: Look up these paths in the registry and use CreateProcess instead of system args.push_back(detect_msvc().path_vcvarsall); args.push_back( Target_GetCurSpec().m_c_compiler ); @@ -862,6 +873,7 @@ namespace { ::std::vector fields; for(const auto& ent : repr->fields) { + (void)ent; fields.push_back(fields.size()); } ::std::sort(fields.begin(), fields.end(), [&](auto a, auto b){ return repr->fields[a].offset < repr->fields[b].offset; }); @@ -2760,10 +2772,46 @@ namespace { } else if( const auto* e = repr->variants.opt_Values() ) { + const auto& tag_ty = Target_GetInnerType(sp, m_resolve, *repr, e->field.index, e->field.sub_fields); + bool is_signed = false; + switch(tag_ty.m_data.as_Primitive()) + { + case ::HIR::CoreType::I8: + case ::HIR::CoreType::I16: + case ::HIR::CoreType::I32: + case ::HIR::CoreType::I64: + case ::HIR::CoreType::Isize: + is_signed = true; + break; + case ::HIR::CoreType::Bool: + case ::HIR::CoreType::U8: + case ::HIR::CoreType::U16: + case ::HIR::CoreType::U32: + case ::HIR::CoreType::U64: + case ::HIR::CoreType::Usize: + case ::HIR::CoreType::Char: + is_signed = false; + break; + case ::HIR::CoreType::I128: // TODO: Emulation + case ::HIR::CoreType::U128: // TODO: Emulation + break; + case ::HIR::CoreType::F32: + case ::HIR::CoreType::F64: + MIR_TODO(mir_res, "Floating point enum tag."); + break; + case ::HIR::CoreType::Str: + MIR_BUG(mir_res, "Unsized tag?!"); + } m_of << indent << "switch("; emit_lvalue(val); m_of << ".TAG) {\n"; for(size_t j = 0; j < n_arms; j ++) { - m_of << indent << "case " << e->values[j] << ": "; + // TODO: Get type of this field and check if it's signed. + if( is_signed ) { + m_of << indent << "case " << static_cast(e->values[j]) << ": "; + } + else { + m_of << indent << "case " << e->values[j] << ": "; + } cb(j); m_of << "\n"; } @@ -2934,6 +2982,9 @@ namespace { if (::std::strcmp(r, "{eax}") == 0 || ::std::strcmp(r, "{rax}") == 0) { return "a"; } + else if (::std::strcmp(r, "{ecx}") == 0 || ::std::strcmp(r, "{rcx}") == 0) { + return "c"; + } else { return r; } @@ -2966,6 +3017,8 @@ namespace { m_of << "%"; else if (*it == '%' && !isdigit(*(it + 1))) m_of << "%%"; + else if (*it == '$' && isdigit(*(it + 1)) && *(it + 2) != 'x') + m_of << "%"; else m_of << *it; } @@ -2983,14 +3036,14 @@ namespace { default: MIR_TODO(mir_res, "Handle asm! output leader '" << v.first[0] << "'"); } m_of << H::convert_reg(v.first.c_str() + 1); - m_of << "\"("; emit_lvalue(v.second); m_of << ")"; + m_of << "\" ("; emit_lvalue(v.second); m_of << ")"; } m_of << ": "; for (unsigned int i = 0; i < e.inputs.size(); i++) { const auto& v = e.inputs[i]; if (i != 0) m_of << ", "; - m_of << "\"" << v.first << "\"("; emit_lvalue(v.second); m_of << ")"; + m_of << "\"" << H::convert_reg(v.first.c_str()) << "\" ("; emit_lvalue(v.second); m_of << ")"; } m_of << ": "; for (unsigned int i = 0; i < e.clobbers.size(); i++) @@ -3620,59 +3673,146 @@ namespace { // Overflowing Arithmatic // HACK: Uses GCC intrinsics else if( name == "add_with_overflow" ) { - switch(m_compiler) + if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::U128) { - case Compiler::Gcc: - emit_lvalue(e.ret_val); m_of << "._1 = __builtin_add_overflow"; + emit_lvalue(e.ret_val); m_of << "._1 = add128_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + } + else if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::I128) + { + emit_lvalue(e.ret_val); m_of << "._1 = add128s_o"; m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; - break; - case Compiler::Msvc: - emit_lvalue(e.ret_val); m_of << "._1 = _addcarry_u" << get_prim_size(params.m_types.at(0)); - m_of << "(0, "; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; - break; + } + else + + { + switch(m_compiler) + { + case Compiler::Gcc: + emit_lvalue(e.ret_val); m_of << "._1 = __builtin_add_overflow"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + break; + case Compiler::Msvc: + emit_lvalue(e.ret_val); m_of << "._1 = _addcarry_u" << get_prim_size(params.m_types.at(0)); + m_of << "(0, "; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + break; + } } } else if( name == "sub_with_overflow" ) { - emit_lvalue(e.ret_val); m_of << "._1 = __builtin_sub_overflow("; emit_param(e.args.at(0)); - m_of << ", "; emit_param(e.args.at(1)); - m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::U128) + { + emit_lvalue(e.ret_val); m_of << "._1 = sub128_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + } + else if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::I128) + { + emit_lvalue(e.ret_val); m_of << "._1 = sub128s_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + } + else + { + switch(m_compiler) + { + case Compiler::Gcc: + emit_lvalue(e.ret_val); m_of << "._1 = __builtin_sub_overflow"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + break; + case Compiler::Msvc: + emit_lvalue(e.ret_val); m_of << "._1 = _subcarry_u" << get_prim_size(params.m_types.at(0)); + m_of << "(0, "; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + break; + } + } } else if( name == "mul_with_overflow" ) { - switch(m_compiler) + if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::U128) { - case Compiler::Gcc: - emit_lvalue(e.ret_val); m_of << "._1 = __builtin_mul_overflow("; emit_param(e.args.at(0)); - m_of << ", "; emit_param(e.args.at(1)); - m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; - break; - case Compiler::Msvc: - emit_lvalue(e.ret_val); m_of << "._1 = __builtin_mul_overflow_" << params.m_types.at(0); + emit_lvalue(e.ret_val); m_of << "._1 = mul128_o"; m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; - break; + } + else if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::I128) + { + emit_lvalue(e.ret_val); m_of << "._1 = mul128s_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + } + else + { + switch(m_compiler) + { + case Compiler::Gcc: + emit_lvalue(e.ret_val); m_of << "._1 = __builtin_mul_overflow("; emit_param(e.args.at(0)); + m_of << ", "; emit_param(e.args.at(1)); + m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + break; + case Compiler::Msvc: + emit_lvalue(e.ret_val); m_of << "._1 = __builtin_mul_overflow_" << params.m_types.at(0); + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + break; + } } } else if( name == "overflowing_add" ) { - switch(m_compiler) + if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::U128) { - case Compiler::Gcc: - m_of << "__builtin_add_overflow"; + m_of << "add128_o"; m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; - break; - case Compiler::Msvc: - m_of << "_addcarry_u" << get_prim_size(params.m_types.at(0)); - m_of << "(0, "; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; - break; + } + else if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::I128) + { + m_of << "add128s_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } + else + { + switch(m_compiler) + { + case Compiler::Gcc: + m_of << "__builtin_add_overflow"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + break; + case Compiler::Msvc: + m_of << "_addcarry_u" << get_prim_size(params.m_types.at(0)); + m_of << "(0, "; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + break; + } } } else if( name == "overflowing_sub" ) { - m_of << "__builtin_sub_overflow("; emit_param(e.args.at(0)); - m_of << ", "; emit_param(e.args.at(1)); - m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::U128) + { + m_of << "sub128_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } + else if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::I128) + { + m_of << "sub128s_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } + else + { + m_of << "__builtin_sub_overflow("; emit_param(e.args.at(0)); + m_of << ", "; emit_param(e.args.at(1)); + m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } } else if( name == "overflowing_mul" ) { - m_of << "__builtin_mul_overflow("; emit_param(e.args.at(0)); - m_of << ", "; emit_param(e.args.at(1)); - m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::U128) + { + m_of << "mul128_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } + else if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::I128) + { + m_of << "mul128s_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } + else + { + m_of << "__builtin_mul_overflow("; emit_param(e.args.at(0)); + m_of << ", "; emit_param(e.args.at(1)); + m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } } // Unchecked Arithmatic else if( name == "unchecked_div" ) { @@ -4234,7 +4374,37 @@ namespace { } } break; TU_ARM(repr->variants, Values, ve) { - emit_dst(); emit_enum_path(repr, ve.field); m_of << " = " << ve.values[e.idx]; + const auto& tag_ty = Target_GetInnerType(sp, m_resolve, *repr, ve.field.index, ve.field.sub_fields); + emit_dst(); emit_enum_path(repr, ve.field); m_of << " = "; + switch(tag_ty.m_data.as_Primitive()) + { + case ::HIR::CoreType::I8: + case ::HIR::CoreType::I16: + case ::HIR::CoreType::I32: + case ::HIR::CoreType::I64: + case ::HIR::CoreType::Isize: + m_of << static_cast(ve.values[e.idx]); + break; + case ::HIR::CoreType::Bool: + case ::HIR::CoreType::U8: + case ::HIR::CoreType::U16: + case ::HIR::CoreType::U32: + case ::HIR::CoreType::U64: + case ::HIR::CoreType::Usize: + case ::HIR::CoreType::Char: + m_of << ve.values[e.idx]; + break; + case ::HIR::CoreType::I128: // TODO: Emulation + case ::HIR::CoreType::U128: // TODO: Emulation + MIR_TODO(*m_mir_res, "Emulated i128 tag"); + break; + case ::HIR::CoreType::F32: + case ::HIR::CoreType::F64: + MIR_TODO(*m_mir_res, "Floating point enum tag."); + break; + case ::HIR::CoreType::Str: + MIR_BUG(*m_mir_res, "Unsized tag?!"); + } if( TU_TEST1((*e.val), List, .empty() == false) ) { m_of << ";\n\t"; diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 9ab406e0..09167486 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -71,6 +71,13 @@ namespace } ::std::ostream& operator<<(::std::ostream& os, const Fmt<::MIR::Constant>& x) { + struct H { + static uint64_t double_to_u64(double v) { + uint64_t rv; + ::std::memcpy(&rv, &v, sizeof(double)); + return rv; + } + }; const auto& e = x.e; switch(e.tag()) { @@ -83,7 +90,7 @@ namespace break; TU_ARM(e, Float, v) { // TODO: Infinity/nan/... - auto vi = *reinterpret_cast(&v.v); + auto vi = H::double_to_u64(v.v); bool sign = (vi & (1ull << 63)) != 0; int exp = (vi >> 52) & 0x7FF; uint64_t frac = vi & ((1ull << 52) - 1); @@ -222,7 +229,6 @@ namespace m_of << "type " << ty << " {\n"; m_of << "\tSIZE " << repr->size << ", ALIGN " << repr->align << ";\n"; - size_t ofs = 0; for(const auto& e : repr->fields) { m_of << "\t" << e.offset << " = " << e.ty << ";\n"; @@ -277,7 +283,6 @@ namespace MIR_ASSERT(*m_mir_res, repr, "No repr for struct " << ty); m_of << "type " << p << " {\n"; m_of << "\tSIZE " << repr->size << ", ALIGN " << repr->align << ";\n"; - size_t ofs = 0; for(const auto& e : repr->fields) { m_of << "\t" << e.offset << " = " << e.ty << ";\n"; @@ -362,7 +367,6 @@ namespace MIR_ASSERT(*m_mir_res, repr, "No repr for union " << ty); m_of << "type " << p << " {\n"; m_of << "\tSIZE " << repr->size << ", ALIGN " << repr->align << ";\n"; - size_t ofs = 0; for(const auto& e : repr->fields) { m_of << "\t" << e.offset << " = " << e.ty << ";\n"; @@ -407,7 +411,6 @@ namespace MIR_ASSERT(*m_mir_res, repr, "No repr for enum " << ty); m_of << "type " << p << " {\n"; m_of << "\tSIZE " << repr->size << ", ALIGN " << repr->align << ";\n"; - size_t ofs = 0; for(const auto& e : repr->fields) { m_of << "\t" << e.offset << " = " << e.ty << ";\n"; diff --git a/src/trans/target.cpp b/src/trans/target.cpp index cf4d0fbc..d1a5cabe 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -66,6 +66,13 @@ namespace ARCH_ARM32 }; } + else if(target_name == "i586-windows-gnu") + { + return TargetSpec { + "windows", "windows", "gnu", CodegenMode::Gnu11, "mingw32", + ARCH_X86 + }; + } else if(target_name == "x86_64-windows-gnu") { return TargetSpec { @@ -750,17 +757,17 @@ namespace { } 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() <= 128 ) { + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I8 }); } - else if( e.variants.size() <= 0xFFFF ) { - rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U16 }); + else if( e.variants.size() <= 0x7FFF ) { + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I16 }); } - else if( e.variants.size() <= 0xFFFFFFFF ) { - rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U32 }); + else if( e.variants.size() <= 0x7FFFFFFF ) { + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I32 }); } else { - rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U64 }); + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I64 }); } break; case ::HIR::Enum::Repr::U8: @@ -870,3 +877,14 @@ const TypeRepr* Target_GetTypeRepr(const Span& sp, const StaticTraitResolve& res auto ires = s_cache.insert(::std::make_pair( ty.clone(), make_type_repr(sp, resolve, ty) )); return ires.first->second.get(); } +const ::HIR::TypeRef& Target_GetInnerType(const Span& sp, const StaticTraitResolve& resolve, const TypeRepr& repr, size_t idx, const ::std::vector& sub_fields, size_t ofs) +{ + const auto& ty = repr.fields.at(idx).ty; + if( sub_fields.size() == ofs ) + { + return ty; + } + const auto* inner_repr = Target_GetTypeRepr(sp, resolve, ty); + ASSERT_BUG(sp, inner_repr, "No inner repr for " << ty); + return Target_GetInnerType(sp, resolve, *inner_repr, sub_fields[ofs], sub_fields, ofs+1); +} diff --git a/src/trans/target.hpp b/src/trans/target.hpp index 939cabbf..81205831 100644 --- a/src/trans/target.hpp +++ b/src/trans/target.hpp @@ -103,3 +103,5 @@ extern const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitR extern const TypeRepr* Target_GetTypeRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty); +extern const ::HIR::TypeRef& Target_GetInnerType(const Span& sp, const StaticTraitResolve& resolve, const TypeRepr& repr, size_t idx, const ::std::vector& sub_fields={}, size_t ofs=0); + -- cgit v1.2.3 From a8f95ea32bb024751087caf5a5568788e107abbf Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 4 Feb 2018 19:53:27 +0800 Subject: Codegen C - Avoid ICE with gcc 5.4.0 (ubuntu), clean up some warnings --- src/trans/codegen_c.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 724b40cd..1bf2d923 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -877,15 +877,15 @@ namespace { fields.push_back(fields.size()); } ::std::sort(fields.begin(), fields.end(), [&](auto a, auto b){ return repr->fields[a].offset < repr->fields[b].offset; }); - for(const auto fld : fields) + for(unsigned fld : fields) { m_of << "\t"; const auto& ty = repr->fields[fld].ty; - TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te, - emit_ctype( *te.inner, FMT_CB(ss, ss << "_" << fld << "[0]";) ); + if( const auto* te = ty.m_data.opt_Slice() ) { + emit_ctype( *te->inner, FMT_CB(ss, ss << "_" << fld << "[0]";) ); has_unsized = true; - ) + } else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, TraitObject, te, m_of << "unsigned char _" << fld << "[0]"; has_unsized = true; @@ -924,6 +924,7 @@ namespace { { m_of << ";\n"; } + (void)has_unsized; auto struct_ty = ::HIR::TypeRef(p.clone(), &item); auto drop_glue_path = ::HIR::Path(struct_ty.clone(), "#drop_glue"); @@ -1195,7 +1196,7 @@ namespace { auto p = path.clone(); p.m_path.m_components.pop_back(); - const auto* repr = Target_GetTypeRepr(sp, m_resolve, ::HIR::TypeRef::new_path(p.clone(), &item)); + //const auto* repr = Target_GetTypeRepr(sp, m_resolve, ::HIR::TypeRef::new_path(p.clone(), &item)); ASSERT_BUG(sp, item.m_data.is_Data(), ""); const auto& var = item.m_data.as_Data().at(var_idx); -- cgit v1.2.3 From b6e4b12bdc3f55b23f71c42c8f3e34bb8c383f3a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 4 Feb 2018 22:57:59 +0800 Subject: Trans - Fixes to edge cases with enum variants --- src/trans/codegen_c.cpp | 12 ++++++++++-- src/trans/target.cpp | 12 +++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 1bf2d923..d208c2ca 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1437,7 +1437,11 @@ namespace { MIR_ASSERT(*m_mir_res, ty.m_data.as_Path().binding.is_Enum(), ""); const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); const auto& enm = *ty.m_data.as_Path().binding.as_Enum(); - if( const auto* ve = repr->variants.opt_NonZero() ) + if( repr->variants.is_None() ) + { + m_of << "{}"; + } + else if( const auto* ve = repr->variants.opt_NonZero() ) { if( e.idx == ve->zero_variant ) { @@ -2527,7 +2531,11 @@ namespace { const auto& ty = mir_res.get_lvalue_type(tmp, e.dst); auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); - if( const auto* re = repr->variants.opt_NonZero() ) + if( repr->variants.is_None() ) + { + emit_lvalue(e.dst); m_of << ".TAG = "; emit_param(ve.val); + } + else if( const auto* re = repr->variants.opt_NonZero() ) { MIR_ASSERT(*m_mir_res, ve.index < 2, ""); if( ve.index == re->zero_variant ) { diff --git a/src/trans/target.cpp b/src/trans/target.cpp index 09fc45b7..61789a75 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -729,7 +729,14 @@ namespace { { vals.push_back(i); } - rv.variants = TypeRepr::VariantMode::make_Values({ { mono_types.size(), tag_size, {} }, ::std::move(vals) }); + if( vals.size() > 1 ) + { + rv.variants = TypeRepr::VariantMode::make_Values({ { mono_types.size(), tag_size, {} }, ::std::move(vals) }); + } + else + { + // Leave the enum with NoVariants + } if( max_align > 0 ) { rv.size = (max_size + tag_size); @@ -755,8 +762,7 @@ namespace { case ::HIR::Enum::Repr::Rust: if( e.variants.size() == 0 ) { } - else if( e.variants.size() == 1 ) { - } + // NOTE: Even with 1 variant, we need to save the value else if( e.variants.size() <= 128 ) { rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I8 }); } -- cgit v1.2.3 From 34e5fe1f59e0c4b446cd765464d7bcdaded9433d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 10 Feb 2018 12:30:45 +0800 Subject: Trans - Fix mismatches between mrustc's sizings and C's sizings --- src/hir/hir.hpp | 1 + src/mir/optimise.cpp | 16 ++++++++++++ src/trans/codegen_c.cpp | 56 ++++++++++++++++++++++++++++++----------- src/trans/target.cpp | 67 +++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 115 insertions(+), 25 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index be83b7c3..f6a1b990 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -227,6 +227,7 @@ public: struct ValueVariant { ::std::string name; ::HIR::ExprPtr expr; + // TODO: Signed. uint64_t val; }; TAGGED_UNION(Class, Data, diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 873a3997..0a83332d 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -1983,6 +1983,8 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) // - Remove calls to `size_of` and `align_of` (replace with value if known) for(auto& bb : fcn.blocks) { + state.set_cur_stmt_term(bb); + MIR_DEBUG(state, bb.terminator); if( !bb.terminator.is_Call() ) continue ; auto& te = bb.terminator.as_Call(); @@ -1994,6 +1996,19 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) size_t size_val = 0; if( Target_GetSizeOf(state.sp, state.m_resolve, tef.params.m_types.at(0), size_val) ) { + DEBUG("size_of = " << 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) })); + bb.terminator = ::MIR::Terminator::make_Goto(te.ret_block); + changed = true; + } + } + else if( tef.name == "size_of_val" ) + { + size_t size_val = 0, tmp; + if( Target_GetSizeAndAlignOf(state.sp, state.m_resolve, tef.params.m_types.at(0), size_val, tmp) && size_val != SIZE_MAX ) + { + DEBUG("size_of_val = " << 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) })); bb.terminator = ::MIR::Terminator::make_Goto(te.ret_block); @@ -2005,6 +2020,7 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) size_t align_val = 0; if( Target_GetAlignOf(state.sp, state.m_resolve, tef.params.m_types.at(0), align_val) ) { + DEBUG("align_of = " << 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) })); bb.terminator = ::MIR::Terminator::make_Goto(te.ret_block); diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index d208c2ca..bcf5f20f 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1013,7 +1013,7 @@ namespace { void emit_enum_path(const TypeRepr* repr, const TypeRepr::FieldPath& path) { - if( path.index == repr->fields.size() - 1 && !repr->variants.is_NonZero() ) + if( TU_TEST1(repr->variants, Values, .field.index == path.index) ) { m_of << ".TAG"; } @@ -1101,11 +1101,23 @@ namespace { } else if( repr->fields.size() == 1 ) { - // Tag only. - // - A value-only enum. - m_of << "\t"; - emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG")); - m_of << ";\n"; + if( repr->variants.is_Values() ) + { + // Tag only. + // - A value-only enum. + m_of << "\t"; + emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG")); + m_of << ";\n"; + } + else + { + m_of << "\tunion {\n"; + m_of << "\t\t"; + emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "var_0")); + m_of << ";\n"; + m_of << "\t} DATA;\n"; + // No tag + } } else if( repr->fields.size() == 0 ) { @@ -1196,7 +1208,7 @@ namespace { auto p = path.clone(); p.m_path.m_components.pop_back(); - //const auto* repr = Target_GetTypeRepr(sp, m_resolve, ::HIR::TypeRef::new_path(p.clone(), &item)); + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ::HIR::TypeRef::new_path(p.clone(), &item)); ASSERT_BUG(sp, item.m_data.is_Data(), ""); const auto& var = item.m_data.as_Data().at(var_idx); @@ -1216,13 +1228,24 @@ namespace { m_of << ") {\n"; //if( repr->variants. - m_of << "\tstruct e_" << Trans_Mangle(p) << " rv = { .TAG = " << var_idx; + m_of << "\tstruct e_" << Trans_Mangle(p) << " rv = {"; + switch(repr->variants.tag()) + { + case TypeRepr::VariantMode::TAGDEAD: throw ""; + TU_ARM(repr->variants, Values, ve) + m_of << " .TAG = " << ve.values[var_idx] << ","; + break; + TU_ARM(repr->variants, NonZero, ve) + break; + TU_ARM(repr->variants, None, ve) + break; + } if( e.empty() ) { if( m_options.disallow_empty_structs ) { - m_of << ", .DATA = { .var_" << var_idx << " = {0} }"; + m_of << " .DATA = { .var_" << var_idx << " = {0} }"; } else { @@ -1231,7 +1254,7 @@ namespace { } else { - m_of << ", .DATA = { .var_" << var_idx << " = {"; + m_of << " .DATA = { .var_" << var_idx << " = {"; for(unsigned int i = 0; i < e.size(); i ++) { if(i != 0) @@ -1464,7 +1487,8 @@ namespace { m_of << "{"; m_of << " { .var_" << e.idx << " = "; emit_literal(get_inner_type(e.idx, 0), *e.val, params); - m_of << " }, .TAG = " << e.idx; + m_of << " }"; + m_of << ", .TAG = " << repr->variants.as_Values().values[e.idx]; m_of << "}"; } ), @@ -2533,7 +2557,7 @@ namespace { if( repr->variants.is_None() ) { - emit_lvalue(e.dst); m_of << ".TAG = "; emit_param(ve.val); + emit_lvalue(e.dst); m_of << ".DATA.var_0 = "; emit_param(ve.val); } else if( const auto* re = repr->variants.opt_NonZero() ) { @@ -2555,7 +2579,7 @@ namespace { } else { - emit_lvalue(e.dst); m_of << ".TAG = " << ve.index << ";\n\t"; + emit_lvalue(e.dst); m_of << ".TAG = " << repr->variants.as_Values().values[ve.index] << ";\n\t"; emit_lvalue(e.dst); m_of << ".DATA"; m_of << ".var_" << ve.index << " = "; emit_param(ve.val); } @@ -2827,9 +2851,13 @@ namespace { m_of << indent << "default: abort();\n"; m_of << indent << "}\n"; } + else if( repr->variants.is_None() ) + { + m_of << indent; cb(0); m_of << "\n"; + } else { - BUG(sp, ""); + BUG(sp, "Unexpected variant type - " << repr->variants.tag_str()); } } void emit_term_switchvalue(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& val, const ::MIR::SwitchValues& values, unsigned indent_level, ::std::function cb) diff --git a/src/trans/target.cpp b/src/trans/target.cpp index 61789a75..08cad81a 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -588,6 +588,7 @@ namespace { } if( !packed && cur_ofs != SIZE_MAX ) { + // Size must be a multiple of alignment while( cur_ofs % max_align != 0 ) { cur_ofs ++; @@ -705,6 +706,14 @@ namespace { max_align = ::std::max(max_align, align); rv.fields.push_back(TypeRepr::Field { 0, mv$(t) }); } + DEBUG("max_size = " << max_size << ", max_align = " << max_align); + // HACK: This is required for the C backend, because the union that contains the enum variants is + // padded out to align. + if(max_size > 0) + { + while(max_size % max_align) + max_size ++; + } size_t tag_size = 0; // TODO: repr(C) enums if( mono_types.size() == 0 ) { @@ -716,12 +725,14 @@ namespace { else if( mono_types.size() <= 255 ) { rv.fields.push_back(TypeRepr::Field { max_size, ::HIR::CoreType::U8 }); tag_size = 1; + DEBUG("u8 data tag"); } 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; + DEBUG("u16 data tag"); } max_align = ::std::max(max_align, tag_size); ::std::vector vals; @@ -739,6 +750,7 @@ namespace { } if( max_align > 0 ) { + // Size must be a multiple of alignment rv.size = (max_size + tag_size); while(rv.size % max_align) rv.size ++; @@ -759,23 +771,47 @@ namespace { // 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 ) { + case ::HIR::Enum::Repr::Rust: { + int pow8 = 0; + for( const auto& v : e.variants ) + { + auto v2 = static_cast(v.val); + if( -0x80 <= v2 && v2 < 0x80 ) + { + pow8 = ::std::max(pow8, 1); + } + else if( -0x8000 <= v2 && v2 < 0x8000 ) + { + pow8 = ::std::max(pow8, 2); + } + else if( -0x80000000 <= v2 && v2 < 0x80000000 ) + { + pow8 = ::std::max(pow8, 3); + } + else + { + pow8 = 4; + } } - // NOTE: Even with 1 variant, we need to save the value - else if( e.variants.size() <= 128 ) { + switch(pow8) + { + case 0: break; + case 1: rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I8 }); - } - else if( e.variants.size() <= 0x7FFF ) { + break; + case 2: rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I16 }); - } - else if( e.variants.size() <= 0x7FFFFFFF ) { + break; + case 3: rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I32 }); - } - else { + break; + case 4: rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I64 }); + break; + default: + break; } - break; + } break; case ::HIR::Enum::Repr::U8: rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U8 }); break; @@ -817,6 +853,7 @@ namespace { } } break; } + DEBUG("rv.variants = " << rv.variants.tag_str()); return box$(rv); } ::std::unique_ptr make_type_repr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty) @@ -861,6 +898,14 @@ namespace { { return make_type_repr_enum(sp, resolve, ty); } + else if( ty.m_data.is_Primitive() ) + { + return nullptr; + } + else if( ty.m_data.is_Borrow() || ty.m_data.is_Pointer() ) + { + return nullptr; + } else { TODO(sp, "Type repr for " << ty); -- cgit v1.2.3 From aeda962b0b24582ec39c8a866918c9477157e83c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 11 Feb 2018 13:59:31 +0800 Subject: Codegen C - Fix some minor issues --- src/trans/codegen_c.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index bcf5f20f..6cfbaf3b 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1232,13 +1232,13 @@ namespace { switch(repr->variants.tag()) { case TypeRepr::VariantMode::TAGDEAD: throw ""; - TU_ARM(repr->variants, Values, ve) + TU_ARM(repr->variants, Values, ve) { m_of << " .TAG = " << ve.values[var_idx] << ","; - break; - TU_ARM(repr->variants, NonZero, ve) - break; - TU_ARM(repr->variants, None, ve) - break; + } break; + TU_ARM(repr->variants, NonZero, ve) { + } break; + TU_ARM(repr->variants, None, ve) { + } break; } if( e.empty() ) @@ -3566,7 +3566,7 @@ namespace { } else if( name == "write_bytes" ) { // 0: Destination, 1: Value, 2: Count - m_of << "memset( "; emit_param(e.args.at(0)); + m_of << "if( "; emit_param(e.args.at(2)); m_of << " > 0) memset( "; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", "; emit_param(e.args.at(2)); m_of << " * sizeof("; emit_ctype(params.m_types.at(0)); m_of << ")"; m_of << ")"; @@ -3685,13 +3685,13 @@ namespace { TU_ARM(repr->variants, None, _e) m_of << "0"; break; - TU_ARM(repr->variants, Values, _e) { - emit_param(e.args.at(0)); m_of << "->TAG"; + TU_ARM(repr->variants, Values, ve) { + m_of << "(*"; emit_param(e.args.at(0)); m_of << ")"; emit_enum_path(repr, ve.field); } break; TU_ARM(repr->variants, NonZero, ve) { - emit_param(e.args.at(0)); emit_enum_path(repr, ve.field); m_of << " "; + m_of << "(*"; emit_param(e.args.at(0)); m_of << ")"; emit_enum_path(repr, ve.field); m_of << " "; m_of << (ve.zero_variant ? "==" : "!="); - m_of << "0"; + m_of << " 0"; } break; } } -- cgit v1.2.3