/* * MRustC - Rust Compiler * - By John Hodge (Mutabah/thePowersGang) * * trans/codegen_c.cpp * - Code generation emitting C code */ #include "codegen.hpp" #include "mangling.hpp" #include #include #include #include #include namespace { class CodeGenerator_C: public CodeGenerator { enum class MetadataType { None, Slice, TraitObject, }; const ::HIR::Crate& m_crate; ::StaticTraitResolve m_resolve; ::std::ofstream m_of; const ::MIR::TypeResolve* m_mir_res; public: CodeGenerator_C(const ::HIR::Crate& crate, const ::std::string& outfile): m_crate(crate), m_resolve(crate), m_of(outfile) { m_of << "/*\n" << " * AUTOGENERATED by mrustc\n" << " */\n" << "#include \n" << "#include \n" << "#include \n" << "#include \n" // atomic_* << "#include \n" // abort << "#include \n" // mem* << "typedef uint32_t CHAR;\n" << "typedef struct { } tUNIT;\n" << "typedef struct { } tBANG;\n" << "typedef struct { } tTYPEID;\n" << "typedef struct { void* PTR; size_t META; } SLICE_PTR;\n" << "typedef struct { void* PTR; void* META; } TRAITOBJ_PTR;\n" << "\n" << "extern void _Unwind_Resume(void);\n" << "\n" ; } ~CodeGenerator_C() {} void finalise() override { m_of << "int main(int argc, const char* argv[]) {\n" << "\t" << Trans_Mangle( ::HIR::GenericPath(m_resolve.m_crate.get_lang_item_path(Span(), "start")) ) << "(" << "(uint8_t*)" << Trans_Mangle( ::HIR::GenericPath(::HIR::SimplePath("", {"main"})) ) << ", argc, (uint8_t**)argv" << ");\n" << "}\n"; } void emit_type(const ::HIR::TypeRef& ty) override { TU_IFLET( ::HIR::TypeRef::Data, ty.m_data, Tuple, te, if( te.size() > 0 ) { m_of << "typedef struct {\n"; for(unsigned int i = 0; i < te.size(); i++) { m_of << "\t"; emit_ctype(te[i], FMT_CB(ss, ss << "_" << i;)); m_of << ";\n"; } m_of << "} "; emit_ctype(ty); m_of << ";\n"; } ) else TU_IFLET( ::HIR::TypeRef::Data, ty.m_data, Function, te, m_of << "typedef "; // TODO: ABI marker, need an ABI enum? // TODO: Better emit_ctype call for return type. emit_ctype(*te.m_rettype); m_of << " (*"; emit_ctype(ty); m_of << ")("; if( te.m_arg_types.size() == 0 ) { m_of << "void)"; } else { for(unsigned int i = 0; i < te.m_arg_types.size(); i ++) { if(i != 0) m_of << ","; m_of << " "; emit_ctype(te.m_arg_types[i]); } m_of << " )"; } m_of << ";\n"; ) else TU_IFLET( ::HIR::TypeRef::Data, ty.m_data, Array, te, m_of << "typedef struct {\n"; m_of << "\t"; emit_ctype(*te.inner); m_of << " DATA[" << te.size_val << "];\n"; m_of << "} "; emit_ctype(ty); m_of << ";\n"; ) else { } m_of << "tTYPEID __typeid_" << Trans_Mangle(ty) << ";\n"; } void emit_struct(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Struct& item) override { ::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 emit_struct_fld_ty = [&](const ::HIR::TypeRef& ty, ::FmtLambda inner) { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te, emit_ctype( monomorph(*te.inner), FMT_CB(ss, ss << inner << "[0]";) ); ) else { emit_ctype( monomorph(ty), inner ); } }; m_of << "struct s_" << Trans_Mangle(p) << " {\n"; TU_MATCHA( (item.m_data), (e), (Unit, ), (Tuple, 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, 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"; } ) ) m_of << "};\n"; // Crate constructor function TU_IFLET(::HIR::Struct::Data, item.m_data, Tuple, e, m_of << "struct s_" << Trans_Mangle(p) << " " << Trans_Mangle(p) << "("; for(unsigned int i = 0; i < e.size(); i ++) { if(i != 0) m_of << ", "; emit_ctype( monomorph(e[i].ent), FMT_CB(ss, ss << "_" << i;) ); } m_of << ") {\n"; m_of << "\tstruct s_" << Trans_Mangle(p) << " rv = {"; 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};\n"; m_of << "\treturn rv;\n"; m_of << "}\n"; ) auto struct_ty = ::HIR::TypeRef(p.clone(), &item); auto drop_glue_path = ::HIR::Path(struct_ty.clone(), "#drop_glue"); auto struct_ty_ptr = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Owned, struct_ty.clone()); ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, {}, *(::MIR::Function*)nullptr }; m_mir_res = &mir_res; // - Drop Glue // TOOD: If there's no fields, emit a #define-ed out destructor? m_of << "void " << Trans_Mangle(drop_glue_path) << "(struct s_" << Trans_Mangle(p) << "* rv) {\n"; 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); } ), (Named, for(unsigned int i = 0; i < e.size(); i ++) { const auto& fld = e[i].second; fld_lv.as_Field().field_index = i; emit_destructor_call(fld_lv, monomorph(fld.ent), true); } ) ) m_of << "}\n"; m_mir_res = nullptr; } //virtual void emit_union(const ::HIR::GenericPath& p, const ::HIR::Union& item); void emit_enum(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Enum& item) override { ::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 << "struct e_" << Trans_Mangle(p) << " {\n"; m_of << "\tunsigned int TAG;\n"; m_of << "\tunion {\n"; for(unsigned int i = 0; i < item.m_variants.size(); i ++) { m_of << "\t\tstruct {\n"; TU_MATCHA( (item.m_variants[i].second), (e), (Unit, ), (Value, // TODO: omit ), (Tuple, for(unsigned int i = 0; i < e.size(); i ++) { const auto& fld = e[i]; m_of << "\t\t\t"; emit_ctype( monomorph(fld.ent) ); m_of << " _" << i << ";\n"; } ), (Struct, for(unsigned int i = 0; i < e.size(); i ++) { const auto& fld = e[i]; m_of << "\t\t\t"; emit_ctype( monomorph(fld.second.ent) ); m_of << " _" << i << ";\n"; } ) ) m_of << "\t\t} var_" << i << ";\n"; } m_of << "\t} DATA;\n"; m_of << "};\n"; // TODO: Constructors for tuple variants // --- // - Drop Glue // --- auto struct_ty = ::HIR::TypeRef(p.clone(), &item); auto drop_glue_path = ::HIR::Path(struct_ty.clone(), "#drop_glue"); auto struct_ty_ptr = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Owned, struct_ty.clone()); ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, {}, *(::MIR::Function*)nullptr }; m_mir_res = &mir_res; // TOOD: If there's no fields, emit a #define-ed out destructor? m_of << "void " << Trans_Mangle(drop_glue_path) << "(struct e_" << Trans_Mangle(p) << "* rv) {\n"; auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); auto fld_lv = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Downcast({ box$(self), 0 })), 0 }); m_of << "\tswitch(rv->TAG) {\n"; for(unsigned int var_idx = 0; var_idx < item.m_variants.size(); var_idx ++) { m_of << "\n"; fld_lv.as_Field().val->as_Downcast().variant_index = var_idx; m_of << "\tcase " << var_idx << ":\n"; TU_MATCHA( (item.m_variants[var_idx].second), (e), (Unit, ), (Value, ), (Tuple, for(unsigned int i = 0; i < e.size(); i ++) { fld_lv.as_Field().field_index = i; const auto& fld = e[i]; emit_destructor_call(fld_lv, monomorph(fld.ent), false); } ), (Struct, for(unsigned int i = 0; i < e.size(); i ++) { fld_lv.as_Field().field_index = i; const auto& fld = e[i]; emit_destructor_call(fld_lv, monomorph(fld.second.ent), false); } ) ) m_of << "\tbreak;\n"; } m_of << "\t}\n"; m_of << "}\n"; } void emit_static_ext(const ::HIR::Path& p, const ::HIR::Static& item, const Trans_Params& params) override { TRACE_FUNCTION_F(p); auto type = params.monomorph(m_crate, item.m_type); m_of << "extern "; emit_ctype( type, FMT_CB(ss, ss << Trans_Mangle(p);) ); m_of << ";"; m_of << "\t// static " << p << " : " << type; m_of << "\n"; } void emit_static_local(const ::HIR::Path& p, const ::HIR::Static& item, const Trans_Params& params) override { TRACE_FUNCTION_F(p); auto type = params.monomorph(m_crate, item.m_type); emit_ctype( type, FMT_CB(ss, ss << Trans_Mangle(p);) ); m_of << " = "; emit_literal(type, item.m_value_res, params); m_of << ";"; m_of << "\t// static " << p << " : " << type; m_of << "\n"; } void emit_literal(const ::HIR::TypeRef& ty, const ::HIR::Literal& lit, const Trans_Params& params) { TRACE_FUNCTION_F("ty=" << ty << ", lit=" << lit); Span sp; ::HIR::TypeRef tmp; auto monomorph_with = [&](const ::HIR::PathParams& pp, const ::HIR::TypeRef& ty)->const ::HIR::TypeRef& { if( monomorphise_type_needed(ty) ) { tmp = monomorphise_type_with(sp, ty, monomorphise_type_get_cb(sp, nullptr, &pp, nullptr), false); m_resolve.expand_associated_types(sp, tmp); return tmp; } else { return ty; } }; auto get_inner_type = [&](unsigned int var, unsigned int idx)->const ::HIR::TypeRef& { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te, return *te.inner; ) else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, te, const auto& pp = te.path.m_data.as_Generic().m_params; TU_MATCHA((te.binding), (pbe), (Unbound, BUG(sp, "Unbound type path " << ty); ), (Opaque, BUG(sp, "Opaque type path " << ty); ), (Struct, TU_MATCHA( (pbe->m_data), (se), (Unit, BUG(sp, "Unit struct " << ty); ), (Tuple, return monomorph_with(pp, se.at(idx).ent); ), (Named, return monomorph_with(pp, se.at(idx).second.ent); ) ) ), (Union, TODO(Span(), "Union literals"); ), (Enum, const auto& evar = pbe->m_variants.at(var); TU_MATCHA( (evar.second), (se), (Unit, BUG(sp, "Unit enum var " << ty << " #" << var << " - fld " << idx); ), (Value, BUG(sp, "Value enum var " << ty << " #" << var << " - fld " << idx); ), (Tuple, return monomorph_with(pp, se.at(idx).ent); ), (Struct, return monomorph_with(pp, se.at(idx).second.ent); ) ) ) ) throw ""; ) else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Tuple, te, return te.at(idx); ) else { TODO(Span(), "Unknown type in list literal - " << ty); } }; TU_MATCHA( (lit), (e), (Invalid, m_of << "/* INVALID */"; ), (List, if( ty.m_data.is_Array() ) m_of << "{"; m_of << "{"; for(unsigned int i = 0; i < e.size(); i ++) { if(i != 0) m_of << ","; m_of << " "; emit_literal(get_inner_type(0, i), e[i], params); } m_of << " }"; if( ty.m_data.is_Array() ) m_of << "}"; ), (Variant, m_of << "{" << e.idx << ", { .var_" << e.idx << " = {"; for(unsigned int i = 0; i < e.vals.size(); i ++) { if(i != 0) m_of << ","; m_of << " "; emit_literal(get_inner_type(e.idx, i), e.vals[i], params); } m_of << " }}}"; ), (Integer, m_of << ::std::hex << "0x" << e << ::std::dec; ), (Float, m_of << e; ), (BorrowOf, if( ! ty.m_data.is_Function() ) m_of << "&"; m_of << Trans_Mangle( params.monomorph(m_crate, e)); ), (String, m_of << "{ "; m_of << "\"" << ::std::oct; for(const auto& v : e) { if( ' ' <= v && v < 0x7F && v != '"' && v != '\\' ) m_of << v; else m_of << "\\" << (unsigned int)v; } m_of << "\"" << ::std::dec; m_of << ", " << e.size() << "}"; ) ) } void emit_vtable(const ::HIR::Path& p, const ::HIR::Trait& trait) override { static Span sp; const auto& trait_path = p.m_data.as_UfcsKnown().trait; const auto& type = *p.m_data.as_UfcsKnown().type; { auto vtable_sp = trait_path.m_path; vtable_sp.m_components.back() += "#vtable"; auto vtable_params = trait_path.m_params.clone(); for(const auto& ty : trait.m_type_indexes) { auto aty = ::HIR::TypeRef( ::HIR::Path( type.clone(), trait_path.clone(), ty.first ) ); m_resolve.expand_associated_types(sp, aty); vtable_params.m_types.push_back( mv$(aty) ); } const auto& vtable_ref = m_crate.get_struct_by_path(sp, vtable_sp); ::HIR::TypeRef vtable_ty( ::HIR::GenericPath(mv$(vtable_sp), mv$(vtable_params)), &vtable_ref ); emit_ctype(vtable_ty); m_of << " " << Trans_Mangle(p) << " = {\n"; } auto monomorph_cb_trait = monomorphise_type_get_cb(sp, &type, &trait_path.m_params, nullptr); // TODO: Alignment and destructor for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ ) { if( i != 0 ) m_of << ",\n"; for(const auto& m : trait.m_value_indexes) { if( m.second.first != i ) continue ; //ASSERT_BUG(sp, tr.m_values.at(m.first).is_Function(), "TODO: Handle generating vtables with non-function items"); DEBUG("- " << m.second.first << " = " << m.second.second << " :: " << m.first); 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 << "\n"; m_of << "\t};\n"; } void emit_function_ext(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params) override { m_of << "// extern \"" << item.m_abi << "\" " << p << "\n"; m_of << "extern "; emit_function_header(p, item, params); if( item.m_linkage.name != "" ) { m_of << " asm(\"" << item.m_linkage.name << "\")"; } m_of << ";\n"; } void emit_function_proto(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params) override { if( item.m_linkage.name != "" ) { m_of << "#define " << Trans_Mangle(p) << " " << item.m_linkage.name << "\n"; } emit_function_header(p, item, params); m_of << ";\n"; } void emit_function_code(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params, const ::MIR::FunctionPointer& code) override { static Span sp; TRACE_FUNCTION_F(p); ::MIR::TypeResolve::args_t arg_types; for(const auto& ent : item.m_args) arg_types.push_back(::std::make_pair( ::HIR::Pattern{}, params.monomorph(m_crate, ent.second) )); ::HIR::TypeRef ret_type = params.monomorph(m_crate, item.m_return); ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << p;), ret_type, arg_types, *code }; m_mir_res = &mir_res; m_of << "// " << p << "\n"; emit_function_header(p, item, params); m_of << "\n"; m_of << "{\n"; // Variables m_of << "\t"; emit_ctype(params.monomorph(m_crate, item.m_return), FMT_CB(ss, ss << "rv";)); m_of << ";\n"; for(unsigned int i = 0; i < code->named_variables.size(); i ++) { DEBUG("var" << i << " : " << code->named_variables[i]); m_of << "\t"; emit_ctype(code->named_variables[i], FMT_CB(ss, ss << "var" << i;)); m_of << ";"; m_of << "\t// " << code->named_variables[i]; m_of << "\n"; } for(unsigned int i = 0; i < code->temporaries.size(); i ++) { DEBUG("tmp" << i << " : " << code->temporaries[i]); m_of << "\t"; emit_ctype(code->temporaries[i], FMT_CB(ss, ss << " tmp" << i;)); m_of << ";"; m_of << "\t// " << code->temporaries[i]; m_of << "\n"; } for(unsigned int i = 0; i < code->blocks.size(); i ++) { TRACE_FUNCTION_F(p << " bb" << i); if( code->blocks[i].statements.size() == 0 && code->blocks[i].terminator.is_Diverge() ) { DEBUG("- Diverge only, omitting"); m_of << "bb" << i << ": _Unwind_Resume(); // Diverge\n"; continue ; } m_of << "bb" << i << ":\n"; for(const auto& stmt : code->blocks[i].statements) { mir_res.set_cur_stmt(i, (&stmt - &code->blocks[i].statements.front())); assert( stmt.is_Drop() || stmt.is_Assign() ); if( stmt.is_Drop() ) { const auto& e = stmt.as_Drop(); // TODO: Emit destructor calls ::HIR::TypeRef tmp; const auto& ty = mir_res.get_lvalue_type(tmp, e.slot); if( e.kind == ::MIR::eDropKind::SHALLOW ) { // TODO: Shallow drops are only valid on owned_box } emit_destructor_call(e.slot, ty, false); } else { const auto& e = stmt.as_Assign(); DEBUG("- " << e.dst << " = " << e.src); m_of << "\t"; TU_MATCHA( (e.src), (ve), (Use, emit_lvalue(e.dst); m_of << " = "; emit_lvalue(ve); ), (Constant, TU_MATCHA( (ve), (c), (Int, emit_lvalue(e.dst); m_of << " = "; m_of << c; ), (Uint, emit_lvalue(e.dst); m_of << " = "; m_of << ::std::hex << "0x" << c << ::std::dec; ), (Float, emit_lvalue(e.dst); m_of << " = "; m_of << c; ), (Bool, emit_lvalue(e.dst); m_of << " = "; m_of << (c ? "true" : "false"); ), (Bytes, emit_lvalue(e.dst); m_of << ".PTR = "; m_of << "\"" << ::std::oct; for(const auto& v : c) { if( ' ' <= v && v < 0x7F && v != '"' && v != '\\' ) m_of << v; else m_of << "\\" << (unsigned int)v; } m_of << "\"" << ::std::dec; m_of << ";\n\t"; emit_lvalue(e.dst); m_of << ".META = " << c.size(); ), (StaticString, emit_lvalue(e.dst); m_of << ".PTR = "; m_of << "\"" << ::std::oct; for(const auto& v : c) { if( ' ' <= v && v < 0x7F && v != '"' && v != '\\' ) m_of << v; else m_of << "\\" << (unsigned int)v; } m_of << "\"" << ::std::dec; m_of << ";\n\t"; emit_lvalue(e.dst); m_of << ".META = " << c.size(); ), (Const, // TODO: This should have been eliminated? ::HIR::TypeRef tmp; const auto& ty = mir_res.get_lvalue_type(tmp, e.dst); const auto& lit = get_literal_for_const(c.p); assign_from_literal([&](){ emit_lvalue(e.dst); }, ty, lit); ), (ItemAddr, emit_lvalue(e.dst); m_of << " = "; m_of << "&" << Trans_Mangle(c); ) ) ), (SizedArray, if( ve.count == 0 ) { } else if( ve.count == 1 ) { emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_lvalue(ve.val); } else if( ve.count == 2 ) { emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_lvalue(ve.val); m_of << ";\n\t"; emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_lvalue(ve.val); } else if( ve.count == 3 ) { emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_lvalue(ve.val); m_of << ";\n\t"; emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_lvalue(ve.val); m_of << ";\n\t"; emit_lvalue(e.dst); m_of << ".DATA[2] = "; emit_lvalue(ve.val); } else { m_of << "for(unsigned int i = 0; i < " << ve.count << "; i ++)\n"; m_of << "\t\t"; emit_lvalue(e.dst); m_of << ".DATA[i] = "; emit_lvalue(ve.val); } ), (Borrow, emit_lvalue(e.dst); m_of << " = "; bool special = false; // If the inner value has type [T] or str, create DST based on inner pointer and existing metadata TU_IFLET(::MIR::LValue, ve.val, Deref, e, ::HIR::TypeRef tmp; const auto& ty = mir_res.get_lvalue_type(tmp, ve.val); // NOTE: Checks the result of the deref if( metadata_type(ty) != MetadataType::None ) { emit_lvalue(*e.val); special = true; } ) // TODO: Magic for taking a &-ptr to unsized field of a struct. // - Needs to get metadata from bottom-level pointer. if( !special ) { m_of << "& "; emit_lvalue(ve.val); } ), (Cast, if( m_resolve.is_type_phantom_data(ve.type) ) { m_of << "/* PhandomData cast */\n"; continue ; } emit_lvalue(e.dst); m_of << " = "; m_of << "("; emit_ctype(ve.type); m_of << ")"; // TODO: If the source is an unsized borrow, then extract the pointer bool special = false; ::HIR::TypeRef tmp; const auto& ty = mir_res.get_lvalue_type(tmp, ve.val); if( ve.type.m_data.is_Pointer() && !is_dst( *ve.type.m_data.as_Pointer().inner ) ) { // NOTE: Checks the result of the deref if( (ty.m_data.is_Borrow() && is_dst(*ty.m_data.as_Borrow().inner)) || (ty.m_data.is_Pointer() && is_dst(*ty.m_data.as_Pointer().inner)) ) { emit_lvalue(ve.val); m_of << ".PTR"; special = true; } } if( ve.type.m_data.is_Primitive() && ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Enum() ) { emit_lvalue(ve.val); m_of << ".TAG"; special = true; } if( !special ) { emit_lvalue(ve.val); } ), (BinOp, emit_lvalue(e.dst); m_of << " = "; emit_lvalue(ve.val_l); switch(ve.op) { case ::MIR::eBinOp::ADD: m_of << " + "; break; case ::MIR::eBinOp::SUB: m_of << " - "; break; case ::MIR::eBinOp::MUL: m_of << " * "; break; case ::MIR::eBinOp::DIV: m_of << " / "; break; case ::MIR::eBinOp::MOD: m_of << " % "; break; case ::MIR::eBinOp::BIT_OR: m_of << " | "; break; case ::MIR::eBinOp::BIT_AND: m_of << " & "; break; case ::MIR::eBinOp::BIT_XOR: m_of << " ^ "; break; case ::MIR::eBinOp::BIT_SHR: m_of << " >> "; break; case ::MIR::eBinOp::BIT_SHL: m_of << " << "; break; case ::MIR::eBinOp::EQ: m_of << " == "; break; case ::MIR::eBinOp::NE: m_of << " != "; break; case ::MIR::eBinOp::GT: m_of << " > " ; break; case ::MIR::eBinOp::GE: m_of << " >= "; break; case ::MIR::eBinOp::LT: m_of << " < " ; break; case ::MIR::eBinOp::LE: m_of << " <= "; break; case ::MIR::eBinOp::ADD_OV: case ::MIR::eBinOp::SUB_OV: case ::MIR::eBinOp::MUL_OV: case ::MIR::eBinOp::DIV_OV: TODO(sp, "Overflow"); break; } emit_lvalue(ve.val_r); ), (UniOp, ::HIR::TypeRef tmp; emit_lvalue(e.dst); m_of << " = "; switch(ve.op) { case ::MIR::eUniOp::NEG: m_of << "-"; break; case ::MIR::eUniOp::INV: if( mir_res.get_lvalue_type(tmp, e.dst) == ::HIR::CoreType::Bool ) m_of << "!"; else m_of << "~"; break; } emit_lvalue(ve.val); ), (DstMeta, emit_lvalue(e.dst); m_of << " = "; MIR_ASSERT(mir_res, ve.val.is_Deref(), "DstMeta on non-deref"); emit_lvalue(*ve.val.as_Deref().val); m_of << ".META"; ), (DstPtr, emit_lvalue(e.dst); m_of << " = "; MIR_ASSERT(mir_res, ve.val.is_Deref(), "DstPtr on non-deref"); emit_lvalue(*ve.val.as_Deref().val); m_of << ".PTR"; ), (MakeDst, emit_lvalue(e.dst); m_of << ".PTR = "; emit_lvalue(ve.ptr_val); m_of << ";\n\t"; emit_lvalue(e.dst); m_of << ".META = "; emit_lvalue(ve.meta_val); ), (Tuple, for(unsigned int j = 0; j < ve.vals.size(); j ++) { if( j != 0 ) m_of << ";\n\t"; emit_lvalue(e.dst); m_of << "._" << j << " = "; emit_lvalue(ve.vals[j]); } ), (Array, for(unsigned int j = 0; j < ve.vals.size(); j ++) { if( j != 0 ) m_of << ";\n\t"; emit_lvalue(e.dst); m_of << ".DATA[" << j << "] = "; emit_lvalue(ve.vals[j]); } ), (Variant, TODO(sp, "Handle constructing variants"); ), (Struct, if(ve.variant_idx != ~0u) { emit_lvalue(e.dst); m_of << ".TAG = " << ve.variant_idx; if(ve.vals.size() > 0) m_of << ";\n\t"; } for(unsigned int j = 0; j < ve.vals.size(); j ++) { // HACK: Don't emit assignment of PhantomData ::HIR::TypeRef tmp; if( m_resolve.is_type_phantom_data( mir_res.get_lvalue_type(tmp, ve.vals[j])) ) continue ; if( j != 0 ) m_of << ";\n\t"; emit_lvalue(e.dst); if(ve.variant_idx != ~0u) m_of << ".DATA.var_" << ve.variant_idx; m_of << "._" << j << " = "; emit_lvalue(ve.vals[j]); } ) ) m_of << ";"; m_of << "\t// " << e.dst << " = " << e.src; m_of << "\n"; } } mir_res.set_cur_stmt_term(i); DEBUG("- " << code->blocks[i].terminator); TU_MATCHA( (code->blocks[i].terminator), (e), (Incomplete, m_of << "\tfor(;;);\n"; ), (Return, m_of << "\treturn rv;\n"; ), (Diverge, m_of << "\t_Unwind_Resume();\n"; ), (Goto, m_of << "\tgoto bb" << e << ";\n"; ), (Panic, m_of << "\tgoto bb" << e << "; /* panic */\n"; ), (If, m_of << "\tif("; emit_lvalue(e.cond); m_of << ") goto bb" << e.bb0 << "; else goto bb" << e.bb1 << ";\n"; ), (Switch, m_of << "\tswitch("; emit_lvalue(e.val); m_of << ".TAG) {\n"; for(unsigned int j = 0; j < e.targets.size(); j ++) m_of << "\t\tcase " << j << ": goto bb" << e.targets[j] << ";\n"; m_of << "\t}\n"; ), (Call, m_of << "\t"; if( e.fcn.is_Intrinsic() ) { const auto& name = e.fcn.as_Intrinsic().name; const auto& params = e.fcn.as_Intrinsic().params; struct H { static const char* get_atomic_ordering(const ::MIR::TypeResolve& mir_res, const ::std::string& name, size_t prefix_len) { if( name.size() < prefix_len ) return "memory_order_seq_cst"; const char* suffix = name.c_str() + prefix_len; if( ::std::strcmp(suffix, "acq") == 0 ) { return "memory_order_acquire"; } else if( ::std::strcmp(suffix, "rel") == 0 ) { return "memory_order_release"; } else if( ::std::strcmp(suffix, "relaxed") == 0 ) { return "memory_order_relaxed"; } else if( ::std::strcmp(suffix, "acqrel") == 0 ) { return "memory_order_acq_rel"; } else { MIR_BUG(mir_res, "Unknown atomic ordering suffix - '" << suffix << "'"); } } }; auto emit_atomic_cxchg = [&](const auto& e, const char* o_succ, const char* o_fail) { emit_lvalue(e.ret_val); m_of << "._0 = "; emit_lvalue(e.args.at(1)); m_of << ";\n\t"; emit_lvalue(e.ret_val); m_of << "._1 = atomic_compare_exchange_strong_explicit("; emit_lvalue(e.args.at(0)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0"; m_of << ", "; emit_lvalue(e.args.at(2)); m_of << ", "< Single-ordering atomics else if( name == "atomic_xadd" || name.compare(0, 7+4+1, "atomic_xadd_") == 0 ) { auto ordering = H::get_atomic_ordering(mir_res, name, 7+4+1); emit_lvalue(e.ret_val); m_of << " = atomic_fetch_add_explicit("; emit_lvalue(e.args.at(0)); m_of << ", "; emit_lvalue(e.args.at(1)); m_of << ", " << ordering << ")"; } else if( name == "atomic_xsub" || name.compare(0, 7+4+1, "atomic_xsub_") == 0 ) { auto ordering = H::get_atomic_ordering(mir_res, name, 7+4+1); emit_lvalue(e.ret_val); m_of << " = atomic_fetch_sub_explicit("; emit_lvalue(e.args.at(0)); m_of << ", "; emit_lvalue(e.args.at(1)); m_of << ", " << ordering << ")"; } else if( name == "atomic_load" || name.compare(0, 7+4+1, "atomic_load_") == 0 ) { auto ordering = H::get_atomic_ordering(mir_res, name, 7+4+1); emit_lvalue(e.ret_val); m_of << " = atomic_load_explicit("; emit_lvalue(e.args.at(0)); m_of << ", " << ordering << ")"; } else if( name == "atomic_store" || name.compare(0, 7+5+1, "atomic_store_") == 0 ) { auto ordering = H::get_atomic_ordering(mir_res, name, 7+5+1); m_of << "atomic_store_explicit("; emit_lvalue(e.args.at(0)); m_of << ", "; emit_lvalue(e.args.at(1)); m_of << ", " << ordering << ")"; } // Comare+Exchange (has two orderings) else if( name == "atomic_cxchg_acq_failrelaxed" ) { emit_atomic_cxchg(e, "memory_order_acquire", "memory_order_relaxed"); } else if( name == "atomic_cxchg_acqrel_failrelaxed" ) { emit_atomic_cxchg(e, "memory_order_acq_rel", "memory_order_relaxed"); } else if( name.compare(0, 7+6+4, "atomic_cxchg_fail") == 0 ) { auto fail_ordering = H::get_atomic_ordering(mir_res, name, 7+6+4); emit_atomic_cxchg(e, "memory_order_seq_cst", fail_ordering); } else if( name == "atomic_cxchg" || name.compare(0, 7+6, "atomic_cxchg_") == 0 ) { auto ordering = H::get_atomic_ordering(mir_res, name, 7+6); emit_atomic_cxchg(e, ordering, ordering); } else { MIR_BUG(mir_res, "Unknown intrinsic '" << name << "'"); } m_of << ";\n"; m_of << "\tgoto bb" << e.ret_block << ";\n"; break ; } TU_MATCHA( (e.fcn), (e2), (Value, { ::HIR::TypeRef tmp; const auto& ty = mir_res.get_lvalue_type(tmp, e2); if( !ty.m_data.as_Function().m_rettype->m_data.is_Diverge() ) { emit_lvalue(e.ret_val); m_of << " = "; } } m_of << "("; emit_lvalue(e2); m_of << ")"; ), (Path, { bool is_diverge = false; TU_MATCHA( (e2.m_data), (pe), (Generic, const auto& fcn = m_crate.get_function_by_path(sp, pe.m_path); is_diverge |= fcn.m_return.m_data.is_Diverge(); // TODO: Monomorph. ), (UfcsUnknown, ), (UfcsInherent, // TODO: Check if the return type is ! ), (UfcsKnown, // TODO: Check if the return type is ! ) ) if(!is_diverge) { emit_lvalue(e.ret_val); m_of << " = "; } } m_of << Trans_Mangle(e2); ), (Intrinsic, BUG(sp, "Intrinsic not expected, should be handled above"); ) ) m_of << "("; for(unsigned int j = 0; j < e.args.size(); j ++) { if(j != 0) m_of << ","; m_of << " "; emit_lvalue(e.args[j]); } m_of << " );\n"; m_of << "\tgoto bb" << e.ret_block << ";\n"; ) ) m_of << "\t// ^ " << code->blocks[i].terminator << "\n"; } m_of << "}\n"; m_of.flush(); m_mir_res = nullptr; } private: void emit_function_header(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params) { emit_ctype( params.monomorph(m_crate, item.m_return), FMT_CB(ss, ss << " " << Trans_Mangle(p) << "("; if( item.m_args.size() == 0 ) { ss << "void)"; } else { for(unsigned int i = 0; i < item.m_args.size(); i ++) { if( i != 0 ) m_of << ","; ss << "\n\t\t"; this->emit_ctype( params.monomorph(m_crate, item.m_args[i].second) ); ss << " arg" << i; } ss << "\n\t\t)"; } )); } void emit_destructor_call(const ::MIR::LValue& slot, const ::HIR::TypeRef& ty, bool unsized_valid) { TU_MATCHA( (ty.m_data), (te), // Impossible (Diverge, ), (Infer, ), (ErasedType, ), (Closure, ), (Generic, ), // Nothing (Primitive, ), (Pointer, ), (Function, ), // Has drop glue/destructors (Borrow, if( te.type == ::HIR::BorrowType::Owned ) { // Call drop glue on inner. emit_destructor_call( ::MIR::LValue::make_Deref({ box$(slot.clone()) }), *te.inner, true ); } ), (Path, // Call drop glue // - TODO: If the destructor is known to do nothing, don't call it. auto p = ::HIR::Path(ty.clone(), "#drop_glue"); m_of << "\t" << Trans_Mangle(p) << "(&"; emit_lvalue(slot); m_of << ");\n"; ), (Array, // Emit destructors for all entries if( te.size_val > 0 ) { ::MIR::LValue lv = ::MIR::LValue::make_Field({ box$(slot.clone()), 0 }); for(unsigned int i = 0; i < te.size_val; i ++) { lv.as_Field().field_index = i; emit_destructor_call(lv, *te.inner, false); } } ), (Tuple, // Emit destructors for all entries if( te.size() > 0 ) { ::MIR::LValue lv = ::MIR::LValue::make_Field({ box$(slot.clone()), 0 }); for(unsigned int i = 0; i < te.size(); i ++) { lv.as_Field().field_index = i; emit_destructor_call(lv, te[i], unsized_valid && (i == te.size()-1)); } } ), (TraitObject, MIR_ASSERT(*m_mir_res, unsized_valid, "Dropping TraitObject without a pointer"); //MIR_ASSERT(*m_mir_res, slot.is_Deref(), "Dropping a TraitObject through a non-Deref"); // Call destructor in vtable ), (Slice, MIR_ASSERT(*m_mir_res, unsized_valid, "Dropping Slice without a pointer"); //MIR_ASSERT(*m_mir_res, slot.is_Deref(), "Dropping a slice through a non-Deref"); // Call destructor on all entries ) ) } const ::HIR::Literal& get_literal_for_const(const ::HIR::Path& path) { TU_MATCHA( (path.m_data), (pe), (Generic, if( pe.m_params.m_types.size() > 0 ) MIR_TODO(*m_mir_res, "Paths with generics " << path); return m_crate.get_constant_by_path(Span(), pe.m_path).m_value_res; ), (UfcsUnknown, MIR_BUG(*m_mir_res, "UfcsUnknown " << path); ), (UfcsKnown, MIR_TODO(*m_mir_res, "UfcsKnown " << path); ), (UfcsInherent, MIR_TODO(*m_mir_res, "UfcsInherent " << path); ) ) throw ""; } void assign_from_literal(::std::function emit_dst, const ::HIR::TypeRef& ty, const ::HIR::Literal& lit) { //TRACE_FUNCTION_F("ty=" << ty << ", lit=" << lit); Span sp; ::HIR::TypeRef tmp; auto monomorph_with = [&](const ::HIR::PathParams& pp, const ::HIR::TypeRef& ty)->const ::HIR::TypeRef& { if( monomorphise_type_needed(ty) ) { tmp = monomorphise_type_with(sp, ty, monomorphise_type_get_cb(sp, nullptr, &pp, nullptr), false); m_resolve.expand_associated_types(sp, tmp); return tmp; } else { return ty; } }; auto get_inner_type = [&](unsigned int var, unsigned int idx)->const ::HIR::TypeRef& { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te, return *te.inner; ) else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, te, const auto& pp = te.path.m_data.as_Generic().m_params; TU_MATCHA((te.binding), (pbe), (Unbound, BUG(sp, "Unbound type path " << ty); ), (Opaque, BUG(sp, "Opaque type path " << ty); ), (Struct, TU_MATCHA( (pbe->m_data), (se), (Unit, BUG(sp, "Unit struct " << ty); ), (Tuple, return monomorph_with(pp, se.at(idx).ent); ), (Named, return monomorph_with(pp, se.at(idx).second.ent); ) ) ), (Union, TODO(Span(), "Union literals"); ), (Enum, const auto& evar = pbe->m_variants.at(var); TU_MATCHA( (evar.second), (se), (Unit, BUG(sp, "Unit enum var " << ty << " #" << var << " - fld " << idx); ), (Value, BUG(sp, "Value enum var " << ty << " #" << var << " - fld " << idx); ), (Tuple, return monomorph_with(pp, se.at(idx).ent); ), (Struct, return monomorph_with(pp, se.at(idx).second.ent); ) ) ) ) throw ""; ) else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Tuple, te, return te.at(idx); ) else { TODO(Span(), "Unknown type in list literal - " << ty); } }; TU_MATCHA( (lit), (e), (Invalid, m_of << "/* INVALID */"; ), (List, if( ty.m_data.is_Array() ) { for(unsigned int i = 0; i < e.size(); i ++) { if(i != 0) m_of << ";\n\t"; assign_from_literal([&](){ emit_dst(); m_of << ".DATA[" << i << "]"; }, *ty.m_data.as_Array().inner, e[i]); } } else { for(unsigned int i = 0; i < e.size(); i ++) { if(i != 0) m_of << ";\n\t"; assign_from_literal([&](){ emit_dst(); m_of << "._" << i; }, get_inner_type(0, i), e[i]); } } ), (Variant, emit_dst(); m_of << ".TAG = " << e.idx; for(unsigned int i = 0; i < e.vals.size(); i ++) { m_of << ";\n\t"; assign_from_literal([&](){ emit_dst(); m_of << ".DATA.var_" << e.idx << "._" << i; }, get_inner_type(e.idx, i), e.vals[i]); } ), (Integer, emit_dst(); m_of << " = " << ::std::hex << "0x" << e << ::std::dec; ), (Float, emit_dst(); m_of << " = " << e; ), (BorrowOf, // TODO: If the type is Borrow of a DST, do a fat assign. if( ty.m_data.is_Function() ) { emit_dst(); m_of << " = " << Trans_Mangle(e); } else if( ty.m_data.is_Borrow() ) { const auto& ity = *ty.m_data.as_Borrow().inner; switch( metadata_type(ity) ) { case MetadataType::None: emit_dst(); m_of << " = &" << Trans_Mangle(e); break; case MetadataType::Slice: emit_dst(); m_of << ".PTR = &" << Trans_Mangle(e) << ";\n\t"; // HACK: Since getting the size is hard, use two sizeofs emit_dst(); m_of << ".META = sizeof(" << Trans_Mangle(e) << ") / "; if( ity.m_data.is_Slice() ) { m_of << "sizeof("; emit_ctype(*ity.m_data.as_Slice().inner); m_of << ")"; } else { m_of << "/*TODO*/"; } break; case MetadataType::TraitObject: emit_dst(); m_of << ".PTR = &" << Trans_Mangle(e) << ";\n\t"; emit_dst(); m_of << ".META = /* TODO: Const VTable */"; break; } } else { emit_dst(); m_of << " = &" << Trans_Mangle(e); } ), (String, emit_dst(); m_of << ".PTR = "; m_of << "\"" << ::std::oct; for(const auto& v : e) { if( ' ' <= v && v < 0x7F && v != '"' && v != '\\' ) m_of << v; else m_of << "\\" << (unsigned int)v; } m_of << "\"" << ::std::dec; m_of << ";\n\t"; emit_dst(); m_of << ".META = " << e.size(); ) ) } void emit_lvalue(const ::MIR::LValue& val) { TU_MATCHA( (val), (e), (Variable, m_of << "var" << e; ), (Temporary, m_of << "tmp" << e.idx; ), (Argument, m_of << "arg" << e.idx; ), (Return, m_of << "rv"; ), (Static, m_of << Trans_Mangle(e); ), (Field, ::HIR::TypeRef tmp; const auto& ty = m_mir_res->get_lvalue_type(tmp, *e.val); if( ty.m_data.is_Slice() ) { m_of << "(("; emit_ctype(*ty.m_data.as_Slice().inner); m_of << "*)"; emit_lvalue(*e.val); m_of << ".DATA)[" << e.field_index << "]"; } else if( ty.m_data.is_Array() ) { emit_lvalue(*e.val); m_of << "[" << e.field_index << "]"; } else if( e.val->is_Deref() ) { auto dst_type = metadata_type(ty); if( dst_type != MetadataType::None ) { m_of << "(("; emit_ctype(ty); m_of << "*)"; emit_lvalue(*e.val->as_Deref().val); m_of << ".PTR)->_" << e.field_index; } else { emit_lvalue(*e.val); m_of << "._" << e.field_index; } } else { emit_lvalue(*e.val); m_of << "._" << e.field_index; } ), (Deref, m_of << "(*"; emit_lvalue(*e.val); m_of << ")"; ), (Index, ::HIR::TypeRef tmp; const auto& ty = m_mir_res->get_lvalue_type(tmp, *e.val); m_of << "("; if( ty.m_data.is_Slice() ) { assert(e.val->is_Deref()); m_of << "("; emit_ctype(*ty.m_data.as_Slice().inner); m_of << "*)"; emit_lvalue(*e.val->as_Deref().val); m_of << ".PTR"; } else if( ty.m_data.is_Array() ) { emit_lvalue(*e.val); m_of << ".DATA"; } else { emit_lvalue(*e.val); } m_of << ")["; emit_lvalue(*e.idx); m_of << "]"; ), (Downcast, emit_lvalue(*e.val); m_of << ".DATA.var_" << e.variant_index; ) ) } void emit_ctype(const ::HIR::TypeRef& ty) { emit_ctype(ty, FMT_CB(_,)); } void emit_ctype(const ::HIR::TypeRef& ty, ::FmtLambda inner) { TU_MATCHA( (ty.m_data), (te), (Infer, m_of << "@" << ty << "@" << inner; ), (Diverge, m_of << "tBANG " << inner; ), (Primitive, switch(te) { case ::HIR::CoreType::Usize: m_of << "uintptr_t"; break; case ::HIR::CoreType::Isize: m_of << "intptr_t"; break; case ::HIR::CoreType::U8: m_of << "uint8_t"; break; case ::HIR::CoreType::I8: m_of << "int8_t"; break; case ::HIR::CoreType::U16: m_of << "uint16_t"; break; case ::HIR::CoreType::I16: m_of << "int16_t"; break; case ::HIR::CoreType::U32: m_of << "uint32_t"; break; case ::HIR::CoreType::I32: m_of << "int32_t"; break; case ::HIR::CoreType::U64: m_of << "uint64_t"; break; case ::HIR::CoreType::I64: m_of << "int64_t"; break; case ::HIR::CoreType::F32: m_of << "float"; break; case ::HIR::CoreType::F64: m_of << "double"; break; case ::HIR::CoreType::Bool: m_of << "bool"; break; case ::HIR::CoreType::Char: m_of << "CHAR"; break; case ::HIR::CoreType::Str: BUG(Span(), "Raw str"); } m_of << " " << inner; ), (Path, //if( const auto* ity = m_resolve.is_type_owned_box(ty) ) { // emit_ctype_ptr(*ity, inner); // return ; //} TU_MATCHA( (te.binding), (tpb), (Struct, m_of << "struct s_" << Trans_Mangle(te.path); ), (Union, m_of << "union u_" << Trans_Mangle(te.path); ), (Enum, m_of << "struct e_" << Trans_Mangle(te.path); ), (Unbound, BUG(Span(), "Unbound type path in trans - " << ty); ), (Opaque, BUG(Span(), "Opaque path in trans - " << ty); ) ) m_of << " " << inner; ), (Generic, BUG(Span(), "Generic in trans - " << ty); ), (TraitObject, BUG(Span(), "Raw trait object - " << ty); ), (ErasedType, BUG(Span(), "ErasedType in trans - " << ty); ), (Array, m_of << "t_" << Trans_Mangle(ty) << " " << inner; //emit_ctype(*te.inner, inner); //m_of << "[" << te.size_val << "]"; ), (Slice, BUG(Span(), "Raw slice object - " << ty); ), (Tuple, if( te.size() == 0 ) m_of << "tUNIT"; else { m_of << "TUP_" << te.size(); for(const auto& t : te) m_of << "_" << Trans_Mangle(t); } m_of << " " << inner; ), (Borrow, emit_ctype_ptr(*te.inner, inner); ), (Pointer, emit_ctype_ptr(*te.inner, inner); ), (Function, m_of << "t_" << Trans_Mangle(ty) << " " << inner; ), (Closure, BUG(Span(), "Closure during trans - " << ty); ) ) } MetadataType metadata_type(const ::HIR::TypeRef& ty) { if( ty == ::HIR::CoreType::Str || ty.m_data.is_Slice() ) { return MetadataType::Slice; } else if( ty.m_data.is_TraitObject() ) { return MetadataType::TraitObject; } else if( ty.m_data.is_Path() ) { const ::HIR::TraitMarkings* markings; TU_MATCH_DEF( ::HIR::TypeRef::TypePathBinding, (ty.m_data.as_Path().binding), (tpb), ( BUG(Span(), "Unbound/opaque path in trans - " << ty); ), (Struct, markings = &tpb->m_markings; ), (Union, markings = &tpb->m_markings; ), (Enum, markings = &tpb->m_markings; ) ) switch( markings->dst_type ) { case ::HIR::TraitMarkings::DstType::None: return MetadataType::None; case ::HIR::TraitMarkings::DstType::Possible: // TODO: How to figure out? //TODO(Span(), "Determine DST type when ::Possible - " << ty); return MetadataType::None; case ::HIR::TraitMarkings::DstType::Slice: return MetadataType::Slice; case ::HIR::TraitMarkings::DstType::TraitObject: return MetadataType::TraitObject; } throw ""; } else { return MetadataType::None; } } void emit_ctype_ptr(const ::HIR::TypeRef& inner_ty, ::FmtLambda inner) { if( inner_ty.m_data.is_Array() ) { emit_ctype(inner_ty, FMT_CB(ss, ss << "(*" << inner << ")";)); } else { switch( metadata_type(inner_ty) ) { case MetadataType::None: emit_ctype(inner_ty, FMT_CB(ss, ss << "*" << inner;)); break; case MetadataType::Slice: m_of << "SLICE_PTR " << inner; break; case MetadataType::TraitObject: m_of << "TRAITOBJ_PTR " << inner; break; } } } int is_dst(const ::HIR::TypeRef& ty) const { if( ty == ::HIR::CoreType::Str ) return 1; if( ty.m_data.is_Slice() ) return 1; if( ty.m_data.is_TraitObject() ) return 2; // TODO: Unsized named types. return 0; } }; } ::std::unique_ptr Trans_Codegen_GetGeneratorC(const ::HIR::Crate& crate, const ::std::string& outfile) { return ::std::unique_ptr(new CodeGenerator_C(crate, outfile)); }