From efc32154cf37aaec675eb0031c030e3032f94c10 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 25 Feb 2018 20:06:11 +0800 Subject: HIR+Codegen C - Encode drop/size/align in VTables at HIR level, working on MSVC compilation --- src/hir_expand/vtable.cpp | 12 ++ src/trans/codegen_c.cpp | 309 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 225 insertions(+), 96 deletions(-) diff --git a/src/hir_expand/vtable.cpp b/src/hir_expand/vtable.cpp index 45e531b8..81c0de00 100644 --- a/src/hir_expand/vtable.cpp +++ b/src/hir_expand/vtable.cpp @@ -186,6 +186,18 @@ namespace { }; VtableConstruct vtc { this, &tr, {} }; + // - Drop glue pointer + ::HIR::FunctionType ft; + ft.is_unsafe = false; + ft.m_abi = ABI_RUST; + ft.m_rettype.reset( new ::HIR::TypeRef(::HIR::TypeRef::new_unit()) ); + ft.m_arg_types.push_back( ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Owned, ::HIR::TypeRef::new_unit()) ); + vtc.fields.push_back(::std::make_pair( "#drop_glue", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::TypeRef(mv$(ft)) } )); + // - Size of data + vtc.fields.push_back(::std::make_pair( "#size", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::CoreType::Usize } )); + // - Alignment of data + vtc.fields.push_back(::std::make_pair( "#align", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::CoreType::Usize } )); + // - Add methods if( ! vtc.add_ents_from_trait(tr, trait_path) ) { tr.m_value_indexes.clear(); diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index b8770c30..3d1134f2 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -252,7 +252,7 @@ namespace { << "typedef uint32_t RUST_CHAR;\n" << "typedef struct { void* PTR; size_t META; } SLICE_PTR;\n" << "typedef struct { void* PTR; void* META; } TRAITOBJ_PTR;\n" - << "typedef struct { size_t size; size_t align; void (*drop)(void*); } VTABLE_HDR;\n" + << "typedef struct { void (*drop)(void*); size_t size; size_t align; } VTABLE_HDR;\n" ; if( m_options.disallow_empty_structs ) { @@ -441,7 +441,7 @@ namespace { << "static inline TRAITOBJ_PTR make_traitobjptr(void* ptr, void* vt) { TRAITOBJ_PTR rv = { ptr, vt }; return rv; }\n" << "\n" << "static inline size_t mrustc_max(size_t a, size_t b) { return a < b ? b : a; }\n" - << "static inline void noop_drop(void *p) {}\n" + << "static inline tUNIT noop_drop(tUNIT *p) {}\n" << "\n" // A linear (fast-fail) search of a list of strings << "static inline size_t mrustc_string_search_linear(SLICE_PTR val, size_t count, SLICE_PTR* options) {\n" @@ -806,13 +806,16 @@ namespace { auto ty_ptr = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Owned, ty.clone()); ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), ty_ptr, args, empty_fcn }; m_mir_res = &mir_res; - m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(ty); m_of << "* rv) {"; - auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); - auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 }); - for(const auto& ity : te) + m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(ty); m_of << "* rv) {\n"; + if( m_resolve.type_needs_drop_glue(sp, ty) ) { - emit_destructor_call(fld_lv, ity, /*unsized_valid=*/false, 1); - fld_lv.as_Field().field_index ++; + auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); + auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 }); + for(const auto& ity : te) + { + emit_destructor_call(fld_lv, ity, /*unsized_valid=*/false, 1); + fld_lv.as_Field().field_index ++; + } } m_of << "}\n"; ) @@ -863,13 +866,6 @@ namespace { } 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) { @@ -899,7 +895,7 @@ namespace { size_t s, a; Target_GetSizeAndAlignOf(sp, m_resolve, ty, s, a); if( s == 0 && m_options.disallow_empty_structs ) { - m_of << "// ZST\n"; + m_of << "// ZST: " << ty << "\n"; continue ; } else { @@ -962,19 +958,21 @@ namespace { ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, args, empty_fcn }; m_mir_res = &mir_res; m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ") {\n"; - - // If this type has an impl of Drop, call that impl - if( item.m_markings.has_drop_impl ) { - m_of << "\t" << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "(rv);\n"; - } - - auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); - auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 }); - for(size_t i = 0; i < repr->fields.size(); i++) + if( m_resolve.type_needs_drop_glue(sp, item_ty) ) { - fld_lv.as_Field().field_index = i; + // If this type has an impl of Drop, call that impl + if( item.m_markings.has_drop_impl ) { + m_of << "\t" << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "(rv);\n"; + } + + auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); + auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 }); + for(size_t i = 0; i < repr->fields.size(); i++) + { + fld_lv.as_Field().field_index = i; - emit_destructor_call(fld_lv, repr->fields[i].ty, /*unsized_valid=*/true, /*indent=*/1); + emit_destructor_call(fld_lv, repr->fields[i].ty, /*unsized_valid=*/true, /*indent=*/1); + } } m_of << "}\n"; m_mir_res = nullptr; @@ -1159,40 +1157,42 @@ namespace { } m_of << "static void " << Trans_Mangle(drop_glue_path) << "(struct e_" << Trans_Mangle(p) << "* rv) {\n"; - - // If this type has an impl of Drop, call that impl - if( item.m_markings.has_drop_impl ) - { - m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n"; - } - auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); - - if( const auto* e = repr->variants.opt_NonZero() ) - { - 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_Downcast({ box$(self), idx }), repr->fields[idx].ty, false, 2 ); - m_of << "\t}\n"; - } - else if( repr->fields.size() <= 1 ) + if( m_resolve.type_needs_drop_glue(sp, item_ty) ) { - // 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 }); + // If this type has an impl of Drop, call that impl + if( item.m_markings.has_drop_impl ) + { + m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n"; + } + auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); - m_of << "\tswitch(rv->TAG) {\n"; - for(unsigned int var_idx = 0; var_idx < e->values.size(); var_idx ++) + if( const auto* e = repr->variants.opt_NonZero() ) + { + 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_Downcast({ box$(self), idx }), repr->fields[idx].ty, false, 2 ); + m_of << "\t}\n"; + } + else if( repr->fields.size() <= 1 ) { - var_lv.as_Downcast().variant_index = var_idx; - 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"; + // 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->values.size(); var_idx ++) + { + var_lv.as_Downcast().variant_index = var_idx; + 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"; } - m_of << "\t}\n"; } m_of << "}\n"; m_mir_res = nullptr; @@ -1299,13 +1299,22 @@ namespace { } m_of << ") {\n"; m_of << "\tstruct s_" << Trans_Mangle(p) << " rv = {"; + bool emitted = false; for(unsigned int i = 0; i < e.size(); i ++) { - if(i != 0) + if( this->type_is_bad_zst(monomorph(e[i].ent)) ) + continue ; + if(emitted) m_of << ","; + emitted = true; m_of << "\n\t\t_" << i; } - m_of << "\n\t\t};\n"; + if( !emitted ) + { + m_of << "\n\t\t0"; + } + m_of << "\n"; + m_of << "\t\t};\n"; m_of << "\treturn rv;\n"; m_of << "}\n"; } @@ -1753,25 +1762,23 @@ namespace { auto monomorph_cb_trait = monomorphise_type_get_cb(sp, &type, &trait_path.m_params, nullptr); // Size, Alignment, and destructor - m_of << "\t{ "; - m_of << "sizeof("; emit_ctype(type); m_of << "),"; - m_of << "ALIGNOF("; emit_ctype(type); m_of << "),"; if( type.m_data.is_Borrow() || m_resolve.type_is_copy(sp, type) ) { - m_of << "noop_drop,"; + m_of << "\t""noop_drop,\n"; } else { - m_of << "(void*)" << Trans_Mangle(::HIR::Path(type.clone(), "#drop_glue")) << ","; + m_of << "\t""(void*)" << Trans_Mangle(::HIR::Path(type.clone(), "#drop_glue")) << ",\n"; } - m_of << "}"; // No newline, added below + m_of << "\t""sizeof("; emit_ctype(type); m_of << "),\n"; + m_of << "\t""ALIGNOF("; emit_ctype(type); m_of << "),\n"; for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ ) { - m_of << ",\n"; + // Find the corresponding vtable entry for(const auto& m : trait.m_value_indexes) { - if( m.second.first != i ) + if( m.second.first != 3+i ) continue ; //MIR_ASSERT(*m_mir_res, tr.m_values.at(m.first).is_Function(), "TODO: Handle generating vtables with non-function items"); @@ -1779,10 +1786,9 @@ namespace { auto gpath = monomorphise_genericpath_with(sp, m.second.second, monomorph_cb_trait, false); // NOTE: `void*` cast avoids mismatched pointer type errors due to the receiver being &mut()/&() in the vtable - m_of << "\t(void*)" << Trans_Mangle( ::HIR::Path(type.clone(), mv$(gpath), m.first) ); + m_of << "\t(void*)" << Trans_Mangle( ::HIR::Path(type.clone(), mv$(gpath), m.first) ) << ",\n"; } } - m_of << "\n"; m_of << "\t};\n"; m_mir_res = nullptr; @@ -2186,6 +2192,21 @@ namespace { { return m_options.emulated_i128 && (ty == ::HIR::CoreType::I128 || ty == ::HIR::CoreType::U128); } + // Returns true if the input type is a ZST and ZSTs are not being emitted + bool type_is_bad_zst(const ::HIR::TypeRef& ty) const + { + if( m_options.disallow_empty_structs ) + { + 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 size == 0; + } + else + { + return false; + } + } void emit_statement(const ::MIR::TypeResolve& mir_res, const ::MIR::Statement& stmt, unsigned indent_level=1) { @@ -2259,6 +2280,13 @@ namespace { m_of << "abort()"; break; } + + if( ve.is_Field() && this->type_is_bad_zst(ty) ) + { + m_of << "/* ZST field */"; + break; + } + emit_lvalue(e.dst); m_of << " = "; emit_lvalue(ve); @@ -2317,6 +2345,64 @@ namespace { special = true; } ) + else { + } + + // NOTE: If disallow_empty_structs is set, structs don't include ZST fields + // In this case, we need to avoid mentioning the removed fields + if( !special && m_options.disallow_empty_structs && ve.val.is_Field() && this->type_is_bad_zst(ty) ) + { + // Work backwards to the first non-ZST field + const auto* val_fp = &ve.val.as_Field(); + while( val_fp->val->is_Field() ) + { + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, *val_fp->val); + if( !this->type_is_bad_zst(ty) ) + break; + } + // Here, we have `val_fp` be a LValue::Field that refers to a ZST, but the inner of the field points to a non-ZST or a local + + emit_lvalue(e.dst); + m_of << " = "; + + // If the index is zero, then the best option is to borrow the source + if( val_fp->field_index == 0 ) + { + m_of << "(void*)& "; emit_lvalue(*val_fp->val); + } + else + { + ::HIR::TypeRef tmp; + auto tmp_lv = ::MIR::LValue::make_Field({ box$(val_fp->val->clone()), val_fp->field_index - 1 }); + bool use_parent = false; + for(;;) + { + const auto& ty = mir_res.get_lvalue_type(tmp, tmp_lv); + if( !this->type_is_bad_zst(ty) ) + break; + if( tmp_lv.as_Field().field_index == 0 ) + { + use_parent = true; + break; + } + tmp_lv.as_Field().field_index -= 1; + } + + // Reached index zero, with still ZST + if( use_parent ) + { + m_of << "(void*)& "; emit_lvalue(*val_fp->val); + } + // Use the address after the previous item + else + { + m_of << "(void*)( & "; emit_lvalue(tmp_lv); m_of << " + 1 )"; + } + } + special = true; + } + if( !special ) { emit_lvalue(e.dst); @@ -2535,8 +2621,25 @@ namespace { emit_lvalue(e.dst); m_of << ".META = "; emit_param(ve.meta_val); ), (Tuple, - for(unsigned int j = 0; j < ve.vals.size(); j ++) { - if( j != 0 ) m_of << ";\n" << indent; + bool has_emitted = false; + for(unsigned int j = 0; j < ve.vals.size(); j ++) + { + if( m_options.disallow_empty_structs ) + { + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_param_type(tmp, ve.vals[j]); + + if( this->type_is_bad_zst(ty) ) + { + continue ; + } + } + + if(has_emitted) { + m_of << ";\n" << indent; + } + has_emitted = true; + emit_lvalue(e.dst); m_of << "._" << j << " = "; emit_param(ve.vals[j]); @@ -2597,11 +2700,9 @@ namespace { } ), (Struct, - bool is_val_enum = false; - if( ve.vals.empty() ) { - if( m_options.disallow_empty_structs && !is_val_enum) + if( m_options.disallow_empty_structs ) { emit_lvalue(e.dst); m_of << "._d = 0"; @@ -2609,14 +2710,25 @@ namespace { } else { + bool has_emitted = false; for(unsigned int j = 0; j < ve.vals.size(); j ++) { // HACK: Don't emit assignment of PhantomData ::HIR::TypeRef tmp; - if( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data( mir_res.get_lvalue_type(tmp, ve.vals[j].as_LValue())) ) + const auto& ty = mir_res.get_param_type(tmp, ve.vals[j]); + if( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data(ty) ) continue ; - if( j != 0 ) m_of << ";\n" << indent; + if( this->type_is_bad_zst(ty) ) + { + continue ; + } + + if(has_emitted) { + m_of << ";\n" << indent; + } + has_emitted = true; + emit_lvalue(e.dst); m_of << "._" << j << " = "; emit_param(ve.vals[j]); @@ -3011,7 +3123,18 @@ namespace { m_of << "("; for(unsigned int j = 0; j < e.args.size(); j ++) { if(j != 0) m_of << ","; - m_of << " "; emit_param(e.args[j]); + 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_bad_zst(ty) ) + { + m_of << "{0}"; + continue; + } + } + emit_param(e.args[j]); } m_of << " );\n"; } @@ -3420,7 +3543,6 @@ namespace { emit_lvalue(e.ret_val); m_of << " = "; const auto& ty = params.m_types.at(0); //TODO: Get the unsized type and use that in place of MetadataType - #if 1 auto inner_ty = get_inner_unsized_type(ty); if( inner_ty == ::HIR::TypeRef() ) { m_of << "sizeof("; emit_ctype(ty); m_of << ")"; @@ -3441,27 +3563,14 @@ namespace { if( ! ty.m_data.is_TraitObject() ) { m_of << "sizeof("; emit_ctype(ty); m_of << ") + "; } - m_of << "((VTABLE_HDR*)"; emit_param(e.args.at(0)); m_of << ".META)->size"; + //auto vtable_path = inner_ty.m_data.as_TraitObject().m_trait.m_path.clone(); + //vtable_path.m_path.m_components.back() += "#vtable"; + //auto vtable_ty = ::HIR::TypeRef + m_of << "((VTABLE_HDR*)"; emit_param(e.args.at(0)); m_of << ".META)->_1"; } else { MIR_BUG(mir_res, "Unknown inner unsized type " << inner_ty << " for " << ty); } - #else - switch( metadata_type(ty) ) - { - case MetadataType::None: - m_of << "sizeof("; emit_ctype(ty); m_of << ")"; - break; - case MetadataType::Slice: { - // TODO: Have a function that fetches the inner type for types like `Path` or `str` - const auto& ity = *ty.m_data.as_Slice().inner; - emit_param(e.args.at(0)); m_of << ".META * sizeof("; emit_ctype(ity); m_of << ")"; - break; } - case MetadataType::TraitObject: - m_of << "((VTABLE_HDR*)"; emit_param(e.args.at(0)); m_of << ".META)->size"; - break; - } - #endif } else if( name == "min_align_of_val" ) { emit_lvalue(e.ret_val); m_of << " = "; @@ -4243,7 +4352,15 @@ namespace { switch( metadata_type(ty) ) { case MetadataType::None: - m_of << indent << Trans_Mangle(p) << "(&"; emit_lvalue(slot); m_of << ");\n"; + + if( this->type_is_bad_zst(ty) && slot.is_Field() ) + { + m_of << indent << Trans_Mangle(p) << "((void*)&"; emit_lvalue(*slot.as_Field().val); m_of << ");\n"; + } + else + { + m_of << indent << Trans_Mangle(p) << "(&"; emit_lvalue(slot); m_of << ");\n"; + } break; case MetadataType::Slice: make_fcn = "make_sliceptr"; if(0) -- cgit v1.2.3 From ef510a561218f56eca12d5cd4cbeb28298832430 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 25 Feb 2018 20:33:14 +0800 Subject: Codegen C - Minor fix with vtable handling, more work on MSVC zsts --- src/trans/codegen_c.cpp | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 3d1134f2..0232c40a 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -841,10 +841,6 @@ namespace { ::MIR::Function empty_fcn; ::MIR::TypeResolve top_mir_res { sp, m_resolve, FMT_CB(ss, ss << "struct " << p;), ::HIR::TypeRef(), {}, empty_fcn }; m_mir_res = &top_mir_res; - bool is_vtable; { - 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); @@ -3041,6 +3037,27 @@ namespace { auto indent = RepeatLitStr { "\t", static_cast(indent_level) }; m_of << indent; + bool has_zst = false; + for(unsigned int j = 0; j < e.args.size(); j ++) { + 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_bad_zst(ty) ) + { + if(!has_zst) { + m_of << "{\n"; + indent.n ++ ; + m_of << indent; + } + has_zst = true; + emit_ctype(ty, FMT_CB(ss, ss << "zarg" << j;)); + m_of << " = {0};\n"; + m_of << indent; + } + } + } + TU_MATCHA( (e.fcn), (e2), (Value, { @@ -3130,13 +3147,19 @@ namespace { const auto& ty = m_mir_res->get_param_type(tmp, e.args[j]); if( this->type_is_bad_zst(ty) ) { - m_of << "{0}"; + m_of << "zarg" << j; continue; } } emit_param(e.args[j]); } m_of << " );\n"; + + if( has_zst ) + { + indent.n --; + m_of << indent << "}\n"; + } } void emit_asm_gcc(const ::MIR::TypeResolve& mir_res, const ::MIR::Statement::Data_Asm& e, unsigned indent_level) { @@ -3566,7 +3589,7 @@ namespace { //auto vtable_path = inner_ty.m_data.as_TraitObject().m_trait.m_path.clone(); //vtable_path.m_path.m_components.back() += "#vtable"; //auto vtable_ty = ::HIR::TypeRef - m_of << "((VTABLE_HDR*)"; emit_param(e.args.at(0)); m_of << ".META)->_1"; + m_of << "((VTABLE_HDR*)"; emit_param(e.args.at(0)); m_of << ".META)->size"; } else { MIR_BUG(mir_res, "Unknown inner unsized type " << inner_ty << " for " << ty); -- cgit v1.2.3 From f53157332c997212f78836343a8f543b5b45b334 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 25 Feb 2018 20:40:41 +0800 Subject: Codegen C - Don't add `_d` field when there's an unsized --- src/trans/codegen_c.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 0232c40a..3dddb0c2 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -902,7 +902,7 @@ namespace { } m_of << ";\n"; } - if( sized_fields == 0 && m_options.disallow_empty_structs ) + if( sized_fields == 0 && !has_unsized && m_options.disallow_empty_structs ) { m_of << "\tchar _d;\n"; } -- cgit v1.2.3 From 11081bf939c598a4f21018b5562f53caa57467b8 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 25 Feb 2018 20:56:24 +0800 Subject: Codegen C - Literals and omitted ZSTs --- src/trans/codegen_c.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 3dddb0c2..b00e95c6 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1456,12 +1456,18 @@ namespace { if( ty.m_data.is_Array() ) m_of << "{"; m_of << "{"; + bool emitted_field = false; for(unsigned int i = 0; i < e.size(); i ++) { - if(i != 0) m_of << ","; + const auto& ity = get_inner_type(0, i); + // Don't emit ZSTs if they're being omitted + if( this->type_is_bad_zst(ity) ) + continue ; + if(emitted_field) m_of << ","; + emitted_field = true; m_of << " "; - emit_literal(get_inner_type(0, i), e[i], params); + emit_literal(ity, e[i], params); } - if( (ty.m_data.is_Path() || ty.m_data.is_Tuple()) && e.size() == 0 && m_options.disallow_empty_structs ) + if( (ty.m_data.is_Path() || ty.m_data.is_Tuple()) && !emitted_field && m_options.disallow_empty_structs ) m_of << "0"; m_of << " }"; if( ty.m_data.is_Array() ) @@ -4578,10 +4584,19 @@ namespace { } else { + bool emitted_field = false; for(unsigned int i = 0; i < e.size(); i ++) { - if(i != 0) m_of << ";\n\t"; + const auto& ity = get_inner_type(0, i); + // Don't emit ZSTs if they're being omitted + if( this->type_is_bad_zst(ity) ) + continue ; + if(emitted_field) m_of << ";\n\t"; + emitted_field = true; assign_from_literal([&](){ emit_dst(); m_of << "._" << i; }, get_inner_type(0, i), e[i]); } + //if( !emitted_field ) + //{ + //} } ), (Variant, -- cgit v1.2.3 From 0f92b181139f9b27dd0becb0d10ccbea59b922d7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 25 Feb 2018 21:33:33 +0800 Subject: Codegen C - More work on MSVC functions --- src/trans/codegen_c.cpp | 56 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index b00e95c6..75ac1b57 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -302,7 +302,7 @@ namespace { << "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n" << "}\n" ; - break; + break; case Compiler::Msvc: m_of << "static inline uint64_t __builtin_popcount(uint64_t v) {\n" @@ -360,6 +360,22 @@ namespace { << "\tif( (b == -1) && (a == INT64_MIN)) return true;\n" << "\treturn false;\n" << "}\n" + << "static inline _subcarry_u64(uint64_t a, uint64_t b, uint64_t* o) {\n" + << "\t""*o = a - b;\n" + << "\t""return (a > b ? *o >= b : *o > a);\n" + << "}\n" + << "static inline _subcarry_u32(uint32_t a, uint32_t b, uint32_t* o) {\n" + << "\t""*o = a - b;\n" + << "\t""return (a > b ? *o >= b : *o > a);\n" + << "}\n" + << "static inline _subcarry_u16(uint16_t a, uint16_t b, uint16_t* o) {\n" + << "\t""*o = a - b;\n" + << "\t""return (a > b ? *o >= b : *o > a);\n" + << "}\n" + << "static inline _subcarry_u8(uint8_t a, uint8_t b, uint8_t* o) {\n" + << "\t""*o = a - b;\n" + << "\t""return (a > b ? *o >= b : *o > a);\n" + << "}\n" ; break; } @@ -370,15 +386,16 @@ namespace { << "typedef struct { uint64_t lo, hi; } uint128_t;\n" << "typedef struct { uint64_t lo, hi; } int128_t;\n" << "static inline uint128_t make128(uint64_t v) { uint128_t rv = { v, 0 }; return rv; }\n" + << "static inline int cmp128(uint128_t a, uint128_t b) { if(a.hi != b.hi) return a.hi < b.hi ? -1 : 1; if(a.lo != b.lo) return a.lo < b.lo ? -1 : 1; return 0; }\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 bool div128_o(uint128_t a, uint128_t b, uint128_t* q, uint128_t* r) { 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 div128(uint128_t a, uint128_t b) { uint128_t v; div128_o(a, b, &v, NULL); return v; }\n" + << "static inline uint128_t mod128(uint128_t a, uint128_t b) { uint128_t v; div128_o(a, b, NULL, &v); return v;}\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" << "static inline uint128_t xor128(uint128_t a, uint128_t b) { uint128_t v = { a.lo ^ b.lo, a.hi ^ b.hi }; return v; }\n" @@ -395,11 +412,16 @@ namespace { << "\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 int cmp128s(int128_t a, int128_t b) { if(a.hi != b.hi) return (int64_t)a.hi < (int64_t)b.hi ? -1 : 1; if(a.lo != b.lo) return a.lo < b.lo ? -1 : 1; return 0; }\n" + << "static inline bool add128s_o(int128_t a, int128_t b, int128_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 sub128s_o(int128_t a, int128_t b, int128_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 mul128s_o(int128_t a, int128_t b, int128_t* o) { abort(); }\n" + << "static inline bool div128s_o(int128_t a, int128_t b, int128_t* q, int128_t* r) { abort(); }\n" + << "static inline int128_t add128s(int128_t a, int128_t b) { int128_t v; add128s_o(a, b, &v); return v; }\n" + << "static inline int128_t sub128s(int128_t a, int128_t b) { int128_t v; sub128s_o(a, b, &v); return v; }\n" + << "static inline int128_t mul128s(int128_t a, int128_t b) { int128_t v; mul128s_o(a, b, &v); return v; }\n" + << "static inline int128_t div128s(int128_t a, int128_t b) { int128_t v; div128s_o(a, b, &v, NULL); return v; }\n" + << "static inline int128_t mod128s(int128_t a, int128_t b) { int128_t v; div128s_o(a, b, NULL, &v); return v; }\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" @@ -3912,7 +3934,7 @@ namespace { 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)"; + 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; } } @@ -3983,9 +4005,17 @@ namespace { } 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 << ")"; + 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 << ")"; + break; + case Compiler::Msvc: + m_of << "_subcarry_u" << get_prim_size(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 << ")"; + break; + } } } else if( name == "overflowing_mul" ) { -- cgit v1.2.3 From 4cf4467d55580b2895fa65fb8906e37153d82fba Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 28 Feb 2018 19:33:32 +0800 Subject: Codegen C - MSVC fiddling still, fix compile error on gcc --- src/trans/codegen_c.cpp | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 75ac1b57..c59e1c79 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -242,8 +242,7 @@ namespace { case Compiler::Msvc: m_of << "#include \n" - << "#define INFINITY ((float)(1e300*1e300))\n" - << "#define NAN ((float)(INFINITY*0.0))\n" + << "#include \n" // fabsf, ... << "void abort(void);\n" ; break; @@ -308,6 +307,14 @@ namespace { << "static inline uint64_t __builtin_popcount(uint64_t v) {\n" << "\treturn (v >> 32 != 0 ? __popcnt64(v>>32) : 32 + __popcnt64(v));\n" << "}\n" + << "static inline int __builtin_ctz(uint32_t v) { int rv; _BitScanReverse(&rv, v); return rv; }\n" + << "static inline int __builtin_clz(uint32_t v) { int rv; _BitScanForward(&rv, v); return rv; }\n" + << "static inline uint64_t __builtin_clz64(uint64_t v) {\n" + << "\treturn (v >> 32 != 0 ? __builtin_clz(v>>32) : 32 + __builtin_clz(v));\n" + << "}\n" + << "static inline uint64_t __builtin_ctz64(uint64_t v) {\n" + << "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n" + << "}\n" << "static inline bool __builtin_mul_overflow_u8(uint8_t a, uint8_t b, uint8_t* out) {\n" << "\t*out = a*b;\n" << "\tif(a > UINT8_MAX/b) return true;\n" @@ -360,6 +367,12 @@ namespace { << "\tif( (b == -1) && (a == INT64_MIN)) return true;\n" << "\treturn false;\n" << "}\n" + << "static inline bool __builtin_mul_overflow_usize(uintptr_t a, uintptr_t b, uintptr_t* out) {\n" + << "\treturn __builtin_mul_overflow_u" << Target_GetCurSpec().m_arch.m_pointer_bits << "(a, b, out);\n" + << "}\n" + << "static inline bool __builtin_mul_overflow_isize(intptr_t a, intptr_t b, intptr_t* out) {\n" + << "\treturn __builtin_mul_overflow_i" << Target_GetCurSpec().m_arch.m_pointer_bits << "(a, b, out);\n" + << "}\n" << "static inline _subcarry_u64(uint64_t a, uint64_t b, uint64_t* o) {\n" << "\t""*o = a - b;\n" << "\t""return (a > b ? *o >= b : *o > a);\n" @@ -376,6 +389,7 @@ namespace { << "\t""*o = a - b;\n" << "\t""return (a > b ? *o >= b : *o > a);\n" << "}\n" + << "static inline uint64_t __builtin_bswap64(uint64_t v) { return _byteswap_uint64(v); }\n" ; break; } @@ -3875,7 +3889,15 @@ namespace { } // Hints else if( name == "unreachable" ) { - m_of << "__builtin_unreachable()"; + switch(m_compiler) + { + case Compiler::Gcc: + m_of << "__builtin_unreachable()"; + break; + case Compiler::Msvc: + m_of << "for(;;)"; + break; + } } else if( name == "assume" ) { // I don't assume :) @@ -4008,7 +4030,7 @@ namespace { switch(m_compiler) { case Compiler::Gcc: - emit_lvalue(e.ret_val); m_of << "._1 = __builtin_sub_overflow"; + m_of << "__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 << ")"; break; case Compiler::Msvc: @@ -4031,9 +4053,17 @@ namespace { } 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 << ")"; + switch(m_compiler) + { + case Compiler::Gcc: + m_of << "__builtin_mul_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 << "__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 << ")"; + break; + } } } // Unchecked Arithmatic -- cgit v1.2.3 From babad564a946dbf253cec72197f9d338494554ed Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Mar 2018 12:05:51 +0800 Subject: Tests - Add test for #63, reproduces on Mint 18.3 --- samples/test/gcc5_codegen_bug.rs | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 samples/test/gcc5_codegen_bug.rs diff --git a/samples/test/gcc5_codegen_bug.rs b/samples/test/gcc5_codegen_bug.rs new file mode 100644 index 00000000..9dab5a82 --- /dev/null +++ b/samples/test/gcc5_codegen_bug.rs @@ -0,0 +1,43 @@ +// compile-flags: -O + +// ::"core"::iter::Map<::"core"::iter::Chain<::"core"::iter::sources::Once<::"syntax"::ast::NodeId/*S*/,>/*S*/,::"core"::iter::Map<::"core"::slice::Iter<::"syntax"::codemap::Spanned<::"syntax"::ast::PathListItem_/*S*/,>/*S*/,>/*S*/,::"rustc"::closure_I_82<::"rustc"::hir::lowering::LoweringContext/*S*/,>/*S*/,>/*S*/,>/*S*/,::"rustc"::closure_I_83<::"rustc"::hir::lowering::LoweringContext/*S*/,>/*S*/,> + +#[derive(Copy,Debug)] +struct NodeId(u32); +struct Ident(u32); +struct PathListItem_ +{ + i: Ident, + i2: Option, + n: NodeId, +} +struct Span(u32, u32, u32); +struct Spanned +{ + v: T, + sp: Span, +} +#[derive(Copy,Debug)] +struct ItemId { + id: NodeId, +} + +fn main() +{ + // return iter::once(i.id).chain(imports.iter().map(|import| import.node.id)).map(|id| hir::ItemId { id: id }).collect(); + //let list = [ Spanned { v: PathListItem_ { i: Ident(0), i2: None, n: NodeId(0) }, sp: Span(1,1,1) } ]; + let list: [Spanned; 0] = [ ]; + + println!("{:?}", foo(0, &[])); + println!("{:?}", foo(0, &[ Spanned { v: PathListItem_ { i: Ident(0), i2: None, n: NodeId(0) }, sp: Span(1,1,1) } ])); + println!("{:?}", foo(0, &vec![])); +} + +fn foo(n: u32, list: &[Spanned]) -> Vec { + Iterator::chain( + ::std::iter::once(NodeId(0)), + list.iter().map(|v| v.v.n) + ).map(|id| ItemId { id: id }) + .collect() +} + -- cgit v1.2.3 From a098a18b95d2520ca9787cec9f0254caf0f1364e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Mar 2018 12:47:48 +0800 Subject: Codegen C - More work with MSVC support (darn atomics) --- src/trans/codegen_c.cpp | 141 ++++++++++++++++++++++++++++-------------------- 1 file changed, 82 insertions(+), 59 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index c59e1c79..acd54528 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -390,6 +390,14 @@ namespace { << "\t""return (a > b ? *o >= b : *o > a);\n" << "}\n" << "static inline uint64_t __builtin_bswap64(uint64_t v) { return _byteswap_uint64(v); }\n" + << "static inline uint8_t InterlockedCompareExchange8(volatile uint8_t* v, uint8_t n, uint8_t e){ return _InterlockedCompareExchange8(v, n, e); }\n" + << "static inline uint8_t InterlockedCompareExchangeNoFence8(volatile uint8_t* v, uint8_t n, uint8_t e){ return InterlockedCompareExchange8(v, n, e); }\n" + << "static inline uint8_t InterlockedCompareExchangeAcquire8(volatile uint8_t* v, uint8_t n, uint8_t e){ return InterlockedCompareExchange8(v, n, e); }\n" + << "static inline uint8_t InterlockedCompareExchangeRelease8(volatile uint8_t* v, uint8_t n, uint8_t e){ return InterlockedCompareExchange8(v, n, e); }\n" + //<< "static inline uint8_t InterlockedExchange8(volatile uint8_t* v, uint8_t n){ return _InterlockedExchange8((volatile char*)v, (char)n); }\n" + << "static inline uint8_t InterlockedExchangeNoFence8(volatile uint8_t* v, uint8_t n){ return InterlockedExchange8(v, n); }\n" + << "static inline uint8_t InterlockedExchangeAcquire8(volatile uint8_t* v, uint8_t n){ return InterlockedExchange8(v, n); }\n" + << "static inline uint8_t InterlockedExchangeRelease8(volatile uint8_t* v, uint8_t n){ return InterlockedExchange8(v, n); }\n" ; break; } @@ -3423,43 +3431,53 @@ namespace { void emit_intrinsic_call(const ::std::string& name, const ::HIR::PathParams& params, const ::MIR::Terminator::Data_Call& e) { const auto& mir_res = *m_mir_res; - auto get_atomic_ordering = [&](const ::std::string& name, size_t prefix_len)->const char* { + enum class Ordering + { + SeqCst, + Acquire, + Release, + Relaxed, + AcqRel, + }; + auto get_atomic_ty_gcc = [&](Ordering o)->const char* { + switch(o) + { + case Ordering::SeqCst: return "memory_order_seq_cst"; + case Ordering::Acquire: return "memory_order_acquire"; + case Ordering::Release: return "memory_order_release"; + case Ordering::Relaxed: return "memory_order_relaxed"; + case Ordering::AcqRel: return "memory_order_acq_rel"; + } + throw ""; + }; + auto get_atomic_suffix_msvc = [&](Ordering o)->const char* { + switch(o) + { + case Ordering::SeqCst: return ""; + case Ordering::Acquire: return "Acquire"; + case Ordering::Release: return "Release"; + case Ordering::Relaxed: return "NoFence"; + case Ordering::AcqRel: return ""; // this is either Acquire or Release + } + throw ""; + }; + auto get_atomic_ordering = [&](const ::std::string& name, size_t prefix_len)->Ordering { if( name.size() < prefix_len ) { - switch(m_compiler) - { - case Compiler::Gcc: return "memory_order_seq_cst"; - case Compiler::Msvc: return ""; - } + return Ordering::SeqCst; } const char* suffix = name.c_str() + prefix_len; if( ::std::strcmp(suffix, "acq") == 0 ) { - switch (m_compiler) - { - case Compiler::Gcc: return "memory_order_acquire"; - case Compiler::Msvc: return "Acquire"; - } + return Ordering::Acquire; } else if( ::std::strcmp(suffix, "rel") == 0 ) { - switch (m_compiler) - { - case Compiler::Gcc: return "memory_order_release"; - case Compiler::Msvc: return "Release"; - } + return Ordering::Release; } else if( ::std::strcmp(suffix, "relaxed") == 0 ) { - switch (m_compiler) - { - case Compiler::Gcc: return "memory_order_relaxed"; - case Compiler::Msvc: return "NoFence"; - } + return Ordering::Relaxed; } else if( ::std::strcmp(suffix, "acqrel") == 0 ) { - switch (m_compiler) - { - case Compiler::Gcc: return "memory_order_acq_rel"; - case Compiler::Msvc: return ""; // TODO: This is either Acquire or Release - } + return Ordering::AcqRel; } else { MIR_BUG(mir_res, "Unknown atomic ordering suffix - '" << suffix << "'"); @@ -3494,33 +3512,35 @@ namespace { MIR_BUG(mir_res, "Unknown primitive for getting size- " << ty); } }; - auto emit_msvc_atomic_op = [&](const char* name, const char* ordering) { + auto emit_msvc_atomic_op = [&](const char* name, Ordering ordering, bool is_before_size=false) { + const char* o_before = is_before_size ? get_atomic_suffix_msvc(ordering) : ""; + const char* o_after = is_before_size ? "" : get_atomic_suffix_msvc(ordering); switch (params.m_types.at(0).m_data.as_Primitive()) { case ::HIR::CoreType::U8: case ::HIR::CoreType::I8: - m_of << name << "8" << ordering << "("; + m_of << name << o_before << "8" << o_after << "("; break; case ::HIR::CoreType::U16: - m_of << name << "16" << ordering << "("; + m_of << name << o_before << "16" << o_after << "("; break; case ::HIR::CoreType::U32: - m_of << name << ordering << "("; + m_of << name << o_before << o_after << "("; break; case ::HIR::CoreType::U64: //case ::HIR::CoreType::I64: - m_of << name << "64" << ordering << "("; + m_of << name << o_before << "64" << o_after << "("; break; case ::HIR::CoreType::Usize: case ::HIR::CoreType::Isize: - m_of << name; + m_of << name << o_before; if( Target_GetCurSpec().m_arch.m_pointer_bits == 64 ) m_of << "64"; else if( Target_GetCurSpec().m_arch.m_pointer_bits == 32 ) m_of << ""; else MIR_TODO(mir_res, "Handle non 32/64 bit pointer types"); - m_of << ordering << "("; + m_of << o_after << "("; break; default: MIR_BUG(mir_res, "Unsupported atomic type - " << params.m_types.at(0)); @@ -3529,7 +3549,7 @@ namespace { auto emit_atomic_cast = [&]() { m_of << "(_Atomic "; emit_ctype(params.m_types.at(0)); m_of << "*)"; }; - auto emit_atomic_cxchg = [&](const auto& e, const char* o_succ, const char* o_fail, bool is_weak) { + auto emit_atomic_cxchg = [&](const auto& e, Ordering o_succ, Ordering o_fail, bool is_weak) { switch(m_compiler) { case Compiler::Gcc: @@ -3538,18 +3558,18 @@ namespace { emit_atomic_cast(); emit_param(e.args.at(0)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0"; m_of << ", "; emit_param(e.args.at(2)); - m_of << ", "< Date: Sat, 3 Mar 2018 17:30:13 +0800 Subject: Codegen C - Work around InterlockedExchangeSubtract not existing for all types by emulating with add --- src/trans/codegen_c.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index acd54528..10bbdecc 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -3606,8 +3606,12 @@ namespace { } switch(op) { - case AtomicOp::Add: emit_msvc_atomic_op("InterlockedExchangeAdd", ordering); break; - case AtomicOp::Sub: emit_msvc_atomic_op("InterlockedExchangeSubtract", ordering); break; + case AtomicOp::Add: emit_msvc_atomic_op("InterlockedExchangeAdd", ordering, true); break; + case AtomicOp::Sub: + emit_msvc_atomic_op("InterlockedExchangeAdd", ordering, true); + emit_param(e.args.at(0)); m_of << ", ~("; + emit_param(e.args.at(1)); m_of << ")+1)"; + return ; case AtomicOp::And: emit_msvc_atomic_op("InterlockedAnd", ordering); break; case AtomicOp::Or: emit_msvc_atomic_op("InterlockedOr", ordering); break; case AtomicOp::Xor: emit_msvc_atomic_op("InterlockedXor", ordering); break; -- cgit v1.2.3 From ec4afe2cd3bf1049d5eabd4f9ae788e8e8c0f594 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Mar 2018 19:52:27 +0800 Subject: Codegen C - A few more MSVC compile fixes, now compiling (after patching libstd to remove unused extern) --- src/trans/codegen_c.cpp | 24 +++++++++++++++++++----- vsproject/build_rustc_minicargo.cmd | 4 ++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 10bbdecc..f847e5d9 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -282,7 +282,7 @@ namespace { break; case Compiler::Msvc: m_of - << "__declspec(noreturn) void _Unwind_Resume(void) { abort(); }\n" + << "__declspec(noreturn) static void _Unwind_Resume(void) { abort(); }\n" << "#define ALIGNOF(t) __alignof(t)\n" ; break; @@ -485,7 +485,7 @@ namespace { << "static inline TRAITOBJ_PTR make_traitobjptr(void* ptr, void* vt) { TRAITOBJ_PTR rv = { ptr, vt }; return rv; }\n" << "\n" << "static inline size_t mrustc_max(size_t a, size_t b) { return a < b ? b : a; }\n" - << "static inline tUNIT noop_drop(tUNIT *p) {}\n" + << "static inline tUNIT noop_drop(tUNIT *p) { tUNIT v = {0}; return v; }\n" << "\n" // A linear (fast-fail) search of a list of strings << "static inline size_t mrustc_string_search_linear(SLICE_PTR val, size_t count, SLICE_PTR* options) {\n" @@ -634,6 +634,11 @@ namespace { //args.push_back("/O2"); break; } + if( opt.emit_debug_info ) + { + args.push_back("/DEBUG"); + args.push_back("/Zi"); + } if(is_executable) { args.push_back(FMT("/Fe" << m_outfile_path)); @@ -662,7 +667,7 @@ namespace { // Command-line specified linker search directories args.push_back("/link"); - args.push_back("/verbose"); + //args.push_back("/verbose"); for(const auto& path : link_dirs ) { args.push_back(FMT("/LIBPATH:" << path)); @@ -1848,7 +1853,15 @@ namespace { TRACE_FUNCTION_F(p); m_of << "// EXTERN extern \"" << item.m_abi << "\" " << p << "\n"; - m_of << "extern "; + // For MSVC, make a static wrapper that goes and calls the actual function + if( item.m_linkage.name != "" && m_compiler == Compiler::Msvc ) + { + m_of << "static "; + } + else + { + m_of << "extern "; + } emit_function_header(p, item, params); if( item.m_linkage.name != "" ) { @@ -3565,7 +3578,8 @@ namespace { emit_msvc_atomic_op("InterlockedCompareExchange", Ordering::SeqCst, true); // TODO: Use ordering, but which one? emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", "; emit_param(e.args.at(2)); m_of << ")"; m_of << ";\n\t"; - emit_lvalue(e.ret_val); m_of << "._1 = ("; emit_lvalue(e.ret_val); m_of << "._0 == "; emit_param(e.args.at(2)); m_of << ")"; + // If the result equals the expected value, return true + emit_lvalue(e.ret_val); m_of << "._1 = ("; emit_lvalue(e.ret_val); m_of << "._0 == "; emit_param(e.args.at(1)); m_of << ")"; break; } }; diff --git a/vsproject/build_rustc_minicargo.cmd b/vsproject/build_rustc_minicargo.cmd index c778502a..8bbce672 100644 --- a/vsproject/build_rustc_minicargo.cmd +++ b/vsproject/build_rustc_minicargo.cmd @@ -6,7 +6,7 @@ if %errorlevel% neq 0 exit /b %errorlevel% x64\Release\minicargo.exe ..\rustc-1.19.0-src\src\libtest --script-overrides ..\script-overrides\stable-1.19.0 if %errorlevel% neq 0 exit /b %errorlevel% -x64\Release\mrustc.exe ..\rustc-1.19.0-src\src\test\run-pass\hello.rs -L output -o output\hello.exe +x64\Release\mrustc.exe ..\rustc-1.19.0-src\src\test\run-pass\hello.rs -L output -o output\hello.exe -g if %errorlevel% neq 0 exit /b %errorlevel% -hello.exe +output\hello.exe if %errorlevel% neq 0 exit /b %errorlevel% \ No newline at end of file -- cgit v1.2.3 From e44cf19bbf20ff3715ffa3e5c8d4fd4e92617825 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Mar 2018 21:43:03 +0800 Subject: Codegen C - Fix ordering of InterlockedCompareExchange arguments --- src/trans/codegen_c.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index f847e5d9..829aa7f7 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -3569,14 +3569,15 @@ namespace { emit_lvalue(e.ret_val); m_of << "._0 = "; emit_param(e.args.at(1)); m_of << ";\n\t"; emit_lvalue(e.ret_val); m_of << "._1 = atomic_compare_exchange_" << (is_weak ? "weak" : "strong") << "_explicit("; emit_atomic_cast(); emit_param(e.args.at(0)); - m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0"; - m_of << ", "; emit_param(e.args.at(2)); + m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0"; // Expected (i.e. the check value) + m_of << ", "; emit_param(e.args.at(2)); // `desired` (the new value for the slot if equal) m_of << ", " << get_atomic_ty_gcc(o_succ) << ", " << get_atomic_ty_gcc(o_fail) << ")"; break; case Compiler::Msvc: emit_lvalue(e.ret_val); m_of << "._0 = "; emit_msvc_atomic_op("InterlockedCompareExchange", Ordering::SeqCst, true); // TODO: Use ordering, but which one? - emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", "; emit_param(e.args.at(2)); m_of << ")"; + // Slot, Exchange (new value), Comparand (expected value) - Note different order to the gcc/stdc version + emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(2)); m_of << ", "; emit_param(e.args.at(1)); m_of << ")"; m_of << ";\n\t"; // If the result equals the expected value, return true emit_lvalue(e.ret_val); m_of << "._1 = ("; emit_lvalue(e.ret_val); m_of << "._0 == "; emit_param(e.args.at(1)); m_of << ")"; -- cgit v1.2.3 From 5c1cc3810b0256f295ef7e838b1874731ec0e1e0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Mar 2018 21:43:39 +0800 Subject: Trans Enumerate - Some work on doing selective library enumeration (has some holes, so is still disabled) --- src/trans/codegen.cpp | 2 +- src/trans/enumerate.cpp | 95 +++++++++++++++++++++++++++---------------------- 2 files changed, 54 insertions(+), 43 deletions(-) diff --git a/src/trans/codegen.cpp b/src/trans/codegen.cpp index f008a2b3..12252465 100644 --- a/src/trans/codegen.cpp +++ b/src/trans/codegen.cpp @@ -102,7 +102,7 @@ void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const codegen->emit_function_proto(ent.first, fcn, ent.second->pp, is_extern); } } - + // - External functions for(const auto& ent : list.m_functions) { //DEBUG("FUNCTION " << ent.first); diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index b1774041..4c91f5f3 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -91,53 +91,64 @@ TransList Trans_Enumerate_Main(const ::HIR::Crate& crate) } namespace { - void Trans_Enumerate_Public_Mod(EnumState& state, ::HIR::Module& mod, ::HIR::SimplePath mod_path, bool is_visible) + void Trans_Enumerate_ValItem(EnumState& state, const ::HIR::ValueItem& vi, bool is_visible, ::std::function<::HIR::SimplePath()> get_path) { - // TODO: Make this configurable, and debug cases where it breaks - // (needs to be `true` currently) - // - Errors likely caused by re-exports making items visible that - // aren't otherwise. - const bool EMIT_ALL = true; - for(auto& vi : mod.m_value_items) + switch(vi.tag()) { - TU_MATCHA( (vi.second->ent), (e), - (Import, - // TODO: If visible, ensure that target is visited. - ), - (StructConstant, - ), - (StructConstructor, - ), - (Constant, - ), - (Static, - if( EMIT_ALL || (is_visible && vi.second->is_public) ) - { - // HACK: Refuse to emit unused generated statics - // - Needed because all items are visited (regardless of - // visibility) - if(e.m_type.m_data.is_Infer()) - continue ; - //state.enum_static(mod_path + vi.first, *e); - auto* ptr = state.rv.add_static(mod_path + vi.first); - if(ptr) - Trans_Enumerate_FillFrom(state, e, *ptr); - } - ), - (Function, - if( e.m_params.m_types.size() == 0 ) + case ::HIR::ValueItem::TAGDEAD: throw ""; + TU_ARM(vi, Import, e) { + // TODO: If visible, ensure that target is visited. + if( is_visible ) + { + if( ! e.is_variant && e.path.m_crate_name == state.crate.m_crate_name ) { - if( EMIT_ALL || (is_visible && vi.second->is_public) ) { - state.enum_fcn(mod_path + vi.first, e, {}); - } + const auto& vi2 = state.crate.get_valitem_by_path(Span(), e.path, false); + Trans_Enumerate_ValItem(state, vi2, is_visible, [&](){ return e.path; }); } - else - { - const_cast<::HIR::Function&>(e).m_save_code = true; - // TODO: If generic, enumerate concrete functions used + } + } break; + TU_ARM(vi, StructConstant, e) { + } break; + TU_ARM(vi, StructConstructor, e) { + } break; + TU_ARM(vi, Constant, e) { + } break; + TU_ARM(vi, Static, e) { + if( is_visible ) + { + // HACK: Refuse to emit unused generated statics + // - Needed because all items are visited (regardless of + // visibility) + if(e.m_type.m_data.is_Infer()) + continue ; + //state.enum_static(mod_path + vi.first, *e); + auto* ptr = state.rv.add_static( get_path() ); + if(ptr) + Trans_Enumerate_FillFrom(state, e, *ptr); + } + } break; + TU_ARM(vi, Function, e) { + if( e.m_params.m_types.size() == 0 ) + { + if( is_visible ) { + state.enum_fcn(get_path(), e, {}); } - ) - ) + } + else + { + const_cast<::HIR::Function&>(e).m_save_code = true; + // TODO: If generic, enumerate concrete functions used + } + } break; + } + } + void Trans_Enumerate_Public_Mod(EnumState& state, ::HIR::Module& mod, ::HIR::SimplePath mod_path, bool is_visible) + { + // TODO: Fix the TODO in Function above (scan generics for the concretes they use) and set this to false again + const bool EMIT_ALL = true; + for(auto& vi : mod.m_value_items) + { + Trans_Enumerate_ValItem(state, vi.second->ent, EMIT_ALL || (is_visible && vi.second->is_public), [&](){ return mod_path + vi.first; }); } for(auto& ti : mod.m_mod_items) -- cgit v1.2.3 From 31a104f0be799974bb8143fff8228797eb3089be Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Mar 2018 13:32:48 +0800 Subject: Tests - Reduction of the GCC5 bug --- samples/test/gcc5_codegen_bug.rs | 41 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/samples/test/gcc5_codegen_bug.rs b/samples/test/gcc5_codegen_bug.rs index 9dab5a82..fde709b6 100644 --- a/samples/test/gcc5_codegen_bug.rs +++ b/samples/test/gcc5_codegen_bug.rs @@ -1,43 +1,24 @@ // compile-flags: -O +// A reduction of issue #63, where gcc5 (but not 6) will generate invalid code for the following iterator adapter's +// `next` function (seen in librustc) // ::"core"::iter::Map<::"core"::iter::Chain<::"core"::iter::sources::Once<::"syntax"::ast::NodeId/*S*/,>/*S*/,::"core"::iter::Map<::"core"::slice::Iter<::"syntax"::codemap::Spanned<::"syntax"::ast::PathListItem_/*S*/,>/*S*/,>/*S*/,::"rustc"::closure_I_82<::"rustc"::hir::lowering::LoweringContext/*S*/,>/*S*/,>/*S*/,>/*S*/,::"rustc"::closure_I_83<::"rustc"::hir::lowering::LoweringContext/*S*/,>/*S*/,> - -#[derive(Copy,Debug)] -struct NodeId(u32); -struct Ident(u32); -struct PathListItem_ -{ - i: Ident, - i2: Option, - n: NodeId, -} -struct Span(u32, u32, u32); -struct Spanned -{ - v: T, - sp: Span, -} -#[derive(Copy,Debug)] -struct ItemId { - id: NodeId, -} +// +// fn main() { - // return iter::once(i.id).chain(imports.iter().map(|import| import.node.id)).map(|id| hir::ItemId { id: id }).collect(); - //let list = [ Spanned { v: PathListItem_ { i: Ident(0), i2: None, n: NodeId(0) }, sp: Span(1,1,1) } ]; - let list: [Spanned; 0] = [ ]; - + // The function call is kinda needed to trigger the bug + // - Probably because of how it sets up `rbx` to be non-zero println!("{:?}", foo(0, &[])); - println!("{:?}", foo(0, &[ Spanned { v: PathListItem_ { i: Ident(0), i2: None, n: NodeId(0) }, sp: Span(1,1,1) } ])); - println!("{:?}", foo(0, &vec![])); } -fn foo(n: u32, list: &[Spanned]) -> Vec { +// Has to have the second map - even if it's just identity +fn foo(n: u32, list: &[u32]) -> Vec { Iterator::chain( - ::std::iter::once(NodeId(0)), - list.iter().map(|v| v.v.n) - ).map(|id| ItemId { id: id }) + ::std::iter::once(0u32), + list.iter().map(|v| *v) + ).map(|id| id) .collect() } -- cgit v1.2.3 From 8a8472b9111b7d8684af1ed0de598e159100883e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Mar 2018 21:47:43 +0800 Subject: Tests - More reduction of GCC5 bug --- samples/test/gcc5_codegen_bug.rs | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/samples/test/gcc5_codegen_bug.rs b/samples/test/gcc5_codegen_bug.rs index fde709b6..60a54ea9 100644 --- a/samples/test/gcc5_codegen_bug.rs +++ b/samples/test/gcc5_codegen_bug.rs @@ -1,24 +1,36 @@ // compile-flags: -O +extern crate test; // A reduction of issue #63, where gcc5 (but not 6) will generate invalid code for the following iterator adapter's // `next` function (seen in librustc) // ::"core"::iter::Map<::"core"::iter::Chain<::"core"::iter::sources::Once<::"syntax"::ast::NodeId/*S*/,>/*S*/,::"core"::iter::Map<::"core"::slice::Iter<::"syntax"::codemap::Spanned<::"syntax"::ast::PathListItem_/*S*/,>/*S*/,>/*S*/,::"rustc"::closure_I_82<::"rustc"::hir::lowering::LoweringContext/*S*/,>/*S*/,>/*S*/,>/*S*/,::"rustc"::closure_I_83<::"rustc"::hir::lowering::LoweringContext/*S*/,>/*S*/,> // -// - -fn main() -{ - // The function call is kinda needed to trigger the bug - // - Probably because of how it sets up `rbx` to be non-zero - println!("{:?}", foo(0, &[])); -} +// Symptom is an abort due to bad enum tag on Option when handling the second call to `it.next()` -// Has to have the second map - even if it's just identity -fn foo(n: u32, list: &[u32]) -> Vec { - Iterator::chain( +fn main() { + let n = 0; + let list: &[u32] = &[1]; // List can be zero length, it's appears to be the _last_ result that leads to a bad tag. + // Has to have the second map - even if it's just identity, first map probably needs to exist + let mut it = Iterator::chain( ::std::iter::once(0u32), list.iter().map(|v| *v) - ).map(|id| id) - .collect() + ).map(|id| id); + + // First works, and Foo is printed + it.next(); + println!("Foo"); + // Second one will crash with an abort (used in condition to avoid it being optimised out) + if it.next().is_none() { + println!("Bar"); + } + else { + println!("Not-Bar"); + } + if it.next().is_none() { + println!("Bar"); + } + else { + println!("Not-Bar"); + } } -- cgit v1.2.3 From 4fd34c0410ee16cda693e9f1e7b9a6e5a7a0b0aa Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Mar 2018 22:08:40 +0800 Subject: Codegen C - Avoid attempting to get type of a non-LValue when looking for ZSTs --- src/trans/codegen_c.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 829aa7f7..5c180fe7 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -2774,13 +2774,16 @@ namespace { { // HACK: Don't emit assignment of PhantomData ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_param_type(tmp, ve.vals[j]); - if( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data(ty) ) - continue ; - - if( this->type_is_bad_zst(ty) ) + if( ve.vals[j].is_LValue() ) { - continue ; + const auto& ty = mir_res.get_param_type(tmp, ve.vals[j]); + if( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data(ty) ) + continue ; + + if( this->type_is_bad_zst(ty) ) + { + continue ; + } } if(has_emitted) { -- cgit v1.2.3 From 4f529660c1f725186a6bfe680557f98b066cf709 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Mar 2018 23:32:07 +0800 Subject: Codegen C - Avoid warning from msvc change --- src/trans/codegen_c.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 5c180fe7..c7750209 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -485,7 +485,7 @@ namespace { << "static inline TRAITOBJ_PTR make_traitobjptr(void* ptr, void* vt) { TRAITOBJ_PTR rv = { ptr, vt }; return rv; }\n" << "\n" << "static inline size_t mrustc_max(size_t a, size_t b) { return a < b ? b : a; }\n" - << "static inline tUNIT noop_drop(tUNIT *p) { tUNIT v = {0}; return v; }\n" + << "static inline tUNIT noop_drop(tUNIT *p) { tUNIT v = {" << (m_options.disallow_empty_structs ? "0" : "") << "}; return v; }\n" << "\n" // A linear (fast-fail) search of a list of strings << "static inline size_t mrustc_string_search_linear(SLICE_PTR val, size_t count, SLICE_PTR* options) {\n" -- cgit v1.2.3