diff options
-rw-r--r-- | src/expand/cfg.hpp | 2 | ||||
-rw-r--r-- | src/main.cpp | 19 | ||||
-rw-r--r-- | src/trans/codegen_c.cpp | 1060 | ||||
-rw-r--r-- | src/trans/target.cpp | 55 | ||||
-rw-r--r-- | src/trans/target.hpp | 32 |
5 files changed, 657 insertions, 511 deletions
diff --git a/src/expand/cfg.hpp b/src/expand/cfg.hpp index 8e5fce42..edf17851 100644 --- a/src/expand/cfg.hpp +++ b/src/expand/cfg.hpp @@ -1,6 +1,8 @@ #pragma once +#include <ast/attrs.hpp> + extern void Cfg_SetFlag(::std::string name); extern void Cfg_SetValue(::std::string name, ::std::string val); extern void Cfg_SetValueCb(::std::string name, ::std::function<bool(const ::std::string&)> cb); diff --git a/src/main.cpp b/src/main.cpp index af999dae..27721cb0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ #include "hir_expand/main_bindings.hpp" #include "mir/main_bindings.hpp" #include "trans/main_bindings.hpp" +#include "trans/target.hpp" #include "expand/cfg.hpp" @@ -175,26 +176,10 @@ int main(int argc, char *argv[]) // Set up cfg values Cfg_SetValue("rust_compiler", "mrustc"); - // TODO: Target spec - Cfg_SetFlag("unix"); - Cfg_SetFlag("linux"); - Cfg_SetValue("target_os", "linux"); - Cfg_SetValue("target_family", "unix"); - Cfg_SetValue("target_pointer_width", "64"); - Cfg_SetValue("target_endian", "little"); - Cfg_SetValue("target_arch", "x86_64"); - Cfg_SetValue("target_env", "gnu"); - Cfg_SetValueCb("target_has_atomic", [](const ::std::string& s) { - if(s == "8") return true; // Has an atomic byte - if(s == "ptr") return true; // Has an atomic pointer-sized value - return false; - }); - Cfg_SetValueCb("target_feature", [](const ::std::string& s) { - return false; - }); Cfg_SetValueCb("feature", [¶ms](const ::std::string& s) { return params.features.count(s) != 0; }); + Target_SetCfg(); if( params.test_harness ) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 2841db10..7e0405d1 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -26,6 +26,11 @@ namespace { TraitObject, }; + enum class Compiler { + Gcc, + Msvc + }; + static Span sp; const ::HIR::Crate& m_crate; @@ -37,6 +42,8 @@ namespace { ::std::ofstream m_of; const ::MIR::TypeResolve* m_mir_res; + Compiler m_compiler = Compiler::Gcc; + ::std::map<::HIR::GenericPath, ::std::vector<unsigned>> m_enum_repr_cache; ::std::vector< ::std::pair< ::HIR::GenericPath, const ::HIR::Struct*> > m_box_glue_todo; @@ -55,10 +62,14 @@ namespace { << "#include <stddef.h>\n" << "#include <stdint.h>\n" << "#include <stdbool.h>\n" - << "#include <stdatomic.h>\n" // atomic_* << "#include <stdlib.h>\n" // abort << "#include <string.h>\n" // mem* << "#include <math.h>\n" // round, ... + ; + m_of + << "#include <stdatomic.h>\n" // atomic_* + ; + m_of << "typedef uint32_t CHAR;\n" << "typedef struct { } tUNIT;\n" << "typedef struct { } tBANG;\n" @@ -80,12 +91,20 @@ namespace { << "static inline TRAITOBJ_PTR make_traitobjptr(void* ptr, void* vt) { TRAITOBJ_PTR rv = { ptr, vt }; return rv; }\n" << "\n" << "static inline size_t max(size_t a, size_t b) { return a < b ? b : a; }\n" + << "static inline void noop_drop(void *p) {}\n" + << "\n" + ; + // 64-bit bit ops + m_of << "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" + ; + // u128/i128 ops + m_of << "static inline unsigned __int128 __builtin_bswap128(unsigned __int128 v) {\n" << "\tuint64_t lo = __builtin_bswap64((uint64_t)v);\n" << "\tuint64_t hi = __builtin_bswap64((uint64_t)(v>>64));\n" @@ -98,8 +117,6 @@ namespace { << "\treturn ((v&0xFFFFFFFFFFFFFFFF) == 0 ? __builtin_ctz64(v>>64) + 64 : __builtin_ctz64(v));\n" << "}\n" << "\n" - << "static inline void noop_drop(void *p) {}\n" - << "\n" ; } @@ -134,59 +151,113 @@ namespace { // Execute $CC with the required libraries ::std::vector<::std::string> tmp; + auto cache_str = [&](::std::string s){ tmp.push_back(::std::move(s)); return tmp.back().c_str(); }; ::std::vector<const char*> args; - args.push_back( getenv("CC") ? getenv("CC") : "gcc" ); - args.push_back("-ffunction-sections"); - args.push_back("-pthread"); - switch(opt.opt_level) - { - case 0: break; - case 1: - args.push_back("-O1"); - break; - case 2: - args.push_back("-O2"); - break; - } - if( opt.emit_debug_info ) - { - args.push_back("-g"); - } - args.push_back("-o"); - args.push_back(m_outfile_path.c_str()); - args.push_back(m_outfile_path_c.c_str()); - if( is_executable ) + switch( m_compiler ) { - for( const auto& crate : m_crate.m_ext_crates ) + case Compiler::Gcc: + args.push_back( getenv("CC") ? getenv("CC") : "gcc" ); + args.push_back("-ffunction-sections"); + args.push_back("-pthread"); + switch(opt.opt_level) { - tmp.push_back(crate.second.m_filename + ".o"); - args.push_back(tmp.back().c_str()); + case 0: break; + case 1: + args.push_back("-O1"); + break; + case 2: + args.push_back("-O2"); + break; } - for(const auto& path : opt.library_search_dirs ) + if( opt.emit_debug_info ) { - args.push_back("-L"); args.push_back(path.c_str()); - } - for(const auto& lib : m_crate.m_ext_libs) { - ASSERT_BUG(Span(), lib.name != "", ""); - args.push_back("-l"); args.push_back(lib.name.c_str()); + args.push_back("-g"); } - for( const auto& crate : m_crate.m_ext_crates ) + args.push_back("-o"); + args.push_back(m_outfile_path.c_str()); + args.push_back(m_outfile_path_c.c_str()); + if( is_executable ) { - for(const auto& lib : crate.second.m_data->m_ext_libs) { - ASSERT_BUG(Span(), lib.name != "", "Empty lib from " << crate.first); + for( const auto& crate : m_crate.m_ext_crates ) + { + args.push_back(cache_str( crate.second.m_filename + ".o" )); + } + for(const auto& path : opt.library_search_dirs ) + { + args.push_back("-L"); args.push_back(path.c_str()); + } + for(const auto& lib : m_crate.m_ext_libs) { + ASSERT_BUG(Span(), lib.name != "", ""); args.push_back("-l"); args.push_back(lib.name.c_str()); } + for( const auto& crate : m_crate.m_ext_crates ) + { + for(const auto& lib : crate.second.m_data->m_ext_libs) { + ASSERT_BUG(Span(), lib.name != "", "Empty lib from " << crate.first); + args.push_back("-l"); args.push_back(lib.name.c_str()); + } + } + for(const auto& path : opt.libraries ) + { + args.push_back("-l"); args.push_back(path.c_str()); + } + args.push_back("-z"); args.push_back("muldefs"); + args.push_back("-Wl,--gc-sections"); } - for(const auto& path : opt.libraries ) + else { - args.push_back("-l"); args.push_back(path.c_str()); + args.push_back("-c"); } - args.push_back("-z"); args.push_back("muldefs"); - args.push_back("-Wl,--gc-sections"); - } - else - { - args.push_back("-c"); + break; + case Compiler::Msvc: + args.push_back( "cl.exe" ); + args.push_back(m_outfile_path_c.c_str()); + switch(opt.opt_level) + { + case 0: break; + case 1: + args.push_back("/O1"); + break; + case 2: + args.push_back("/O2"); + break; + } + if(is_executable) + { + for( const auto& crate : m_crate.m_ext_crates ) + { + args.push_back(cache_str( crate.second.m_filename + ".o" )); + } + // Command-line specified linker search directories + for(const auto& path : opt.library_search_dirs ) + { + args.push_back("/link"); + args.push_back("/LIBPATH"); + args.push_back(path.c_str()); + } + // Crate-specified libraries + for(const auto& lib : m_crate.m_ext_libs) { + ASSERT_BUG(Span(), lib.name != "", ""); + args.push_back(lib.name.c_str()); + } + for( const auto& crate : m_crate.m_ext_crates ) + { + for(const auto& lib : crate.second.m_data->m_ext_libs) { + ASSERT_BUG(Span(), lib.name != "", "Empty lib from " << crate.first); + args.push_back(lib.name.c_str()); + } + } + for(const auto& path : opt.libraries ) + { + args.push_back(path.c_str()); + } + } + else + { + args.push_back("/c"); + args.push_back(cache_str( FMT("/Fo" + m_outfile_path) )); + } + break; } ::std::stringstream cmd_ss; @@ -1316,6 +1387,7 @@ namespace { { TRACE_FUNCTION_F(p << " bb" << i); + // HACK: Ignore any blocks that only contain `diverge;` 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"; @@ -1327,454 +1399,7 @@ namespace { for(const auto& stmt : code->blocks[i].statements) { mir_res.set_cur_stmt(i, (&stmt - &code->blocks[i].statements.front())); - switch( stmt.tag() ) - { - case ::MIR::Statement::TAGDEAD: throw ""; - case ::MIR::Statement::TAG_ScopeEnd: - m_of << "// " << stmt << "\n"; - break; - case ::MIR::Statement::TAG_SetDropFlag: { - const auto& e = stmt.as_SetDropFlag(); - m_of << "\tdf" << e.idx << " = "; - if( e.other == ~0u ) - m_of << e.new_val; - else - m_of << (e.new_val ? "!" : "") << "df" << e.other; - m_of << ";\n"; - break; } - case ::MIR::Statement::TAG_Drop: { - const auto& e = stmt.as_Drop(); - ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, e.slot); - - if( e.flag_idx != ~0u ) - m_of << "\tif( df" << e.flag_idx << " ) {\n"; - - switch( e.kind ) - { - case ::MIR::eDropKind::SHALLOW: - // Shallow drops are only valid on owned_box - if( const auto* ity = m_resolve.is_type_owned_box(ty) ) - { - // Emit a call to box_free for the type - ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { ity->clone() } }; - // TODO: This is specific to the official liballoc's owned_box - m_of << "\t" << Trans_Mangle(box_free) << "("; emit_lvalue(e.slot); m_of << "._0._0._0);\n"; - } - else - { - MIR_BUG(mir_res, "Shallow drop on non-Box - " << ty); - } - break; - case ::MIR::eDropKind::DEEP: - emit_destructor_call(e.slot, ty, false); - break; - } - if( e.flag_idx != ~0u ) - m_of << "\t}\n"; - break; } - case ::MIR::Statement::TAG_Asm: { - const auto& e = stmt.as_Asm(); - - struct H { - static bool has_flag(const ::std::vector<::std::string>& flags, const char* des) { - return ::std::find_if(flags.begin(), flags.end(), [des](const auto&x){return x==des;}) != flags.end(); - } - static const char* convert_reg(const char* r) { - if( ::std::strcmp(r, "{eax}") == 0 || ::std::strcmp(r, "{rax}") == 0 ) { - return "a"; - } - else { - return r; - } - } - }; - bool is_volatile = H::has_flag(e.flags, "volatile"); - bool is_intel = H::has_flag(e.flags, "intel"); - - m_of << "\t__asm__ "; - if(is_volatile) m_of << "__volatile__"; - // TODO: Convert format string? - // TODO: Use a C-specific escaper here. - m_of << "(\"" << (is_intel ? ".syntax intel; " : "") << FmtEscaped(e.tpl) << (is_intel ? ".syntax att; " : "") << "\""; - m_of << ": "; - for(unsigned int i = 0; i < e.outputs.size(); i ++ ) - { - const auto& v = e.outputs[i]; - if( i != 0 ) m_of << ", "; - m_of << "\""; - switch(v.first[0]) - { - case '=': m_of << "="; break; - case '+': m_of << "+"; break; - default: MIR_TODO(mir_res, "Handle asm! output leader '" << v.first[0] << "'"); - } - m_of << H::convert_reg(v.first.c_str()+1); - m_of << "\"("; emit_lvalue(v.second); m_of << ")"; - } - m_of << ": "; - for(unsigned int i = 0; i < e.inputs.size(); i ++ ) - { - const auto& v = e.inputs[i]; - if( i != 0 ) m_of << ", "; - m_of << "\"" << v.first << "\"("; emit_lvalue(v.second); m_of << ")"; - } - m_of << ": "; - for(unsigned int i = 0; i < e.clobbers.size(); i ++ ) - { - if( i != 0 ) m_of << ", "; - m_of << "\"" << e.clobbers[i] << "\""; - } - m_of << ");\n"; - break; } - case ::MIR::Statement::TAG_Assign: { - const auto& e = stmt.as_Assign(); - DEBUG("- " << e.dst << " = " << e.src); - m_of << "\t"; - TU_MATCHA( (e.src), (ve), - (Use, - ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, ve); - if( ty == ::HIR::TypeRef::new_diverge() ) { - m_of << "abort()"; - break; - } - emit_lvalue(e.dst); - m_of << " = "; - emit_lvalue(ve); - ), - (Constant, - emit_lvalue(e.dst); - m_of << " = "; - emit_constant(ve, &e.dst); - ), - (SizedArray, - if( ve.count == 0 ) { - } - else if( ve.count == 1 ) { - emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); - } - else if( ve.count == 2 ) { - emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n\t"; - emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); - } - else if( ve.count == 3 ) { - emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n\t"; - emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); m_of << ";\n\t"; - emit_lvalue(e.dst); m_of << ".DATA[2] = "; emit_param(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_param(ve.val); - } - ), - (Borrow, - ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, ve.val); - 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, le, - if( metadata_type(ty) != MetadataType::None ) { - emit_lvalue(e.dst); - m_of << " = "; - emit_lvalue(*le.val); - special = true; - } - ) - // Magic for taking a &-ptr to unsized field of a struct. - // - Needs to get metadata from bottom-level pointer. - else TU_IFLET(::MIR::LValue, ve.val, Field, le, - if( metadata_type(ty) != MetadataType::None ) { - const ::MIR::LValue* base_val = &*le.val; - while(base_val->is_Field()) - base_val = &*base_val->as_Field().val; - MIR_ASSERT(mir_res, base_val->is_Deref(), "DST access must be via a deref"); - const ::MIR::LValue& base_ptr = *base_val->as_Deref().val; - - // Construct the new DST - emit_lvalue(e.dst); m_of << ".META = "; emit_lvalue(base_ptr); m_of << ".META;\n\t"; - emit_lvalue(e.dst); m_of << ".PTR = &"; emit_lvalue(ve.val); - special = true; - } - ) - if( !special ) - { - emit_lvalue(e.dst); - m_of << " = "; - 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 the destination is a thin pointer - 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 << " = "; - ::HIR::TypeRef tmp; - const auto& ty = ve.val_l.is_LValue() ? mir_res.get_lvalue_type(tmp, ve.val_l.as_LValue()) : tmp = mir_res.get_const_type(ve.val_l.as_Constant()); - if( ty.m_data.is_Borrow() ) { - m_of << "(slice_cmp("; emit_param(ve.val_l); m_of << ", "; emit_param(ve.val_r); m_of << ")"; - switch(ve.op) - { - case ::MIR::eBinOp::EQ: m_of << " == 0"; break; - case ::MIR::eBinOp::NE: m_of << " != 0"; break; - case ::MIR::eBinOp::GT: m_of << " > 0"; break; - case ::MIR::eBinOp::GE: m_of << " >= 0"; break; - case ::MIR::eBinOp::LT: m_of << " < 0"; break; - case ::MIR::eBinOp::LE: m_of << " <= 0"; break; - default: - MIR_BUG(mir_res, "Unknown comparison of a &-ptr - " << e.src << " with " << ty); - } - m_of << ")"; - break; - } - else if( const auto* te = ty.m_data.opt_Pointer() ) { - if( metadata_type(*te->inner) != MetadataType::None ) - { - switch(ve.op) - { - case ::MIR::eBinOp::EQ: - emit_param(ve.val_l); m_of << ".PTR == "; emit_param(ve.val_r); m_of << ".PTR && "; - emit_param(ve.val_l); m_of << ".META == "; emit_param(ve.val_r); m_of << ".META"; - break; - case ::MIR::eBinOp::NE: - emit_param(ve.val_l); m_of << ".PTR != "; emit_param(ve.val_r); m_of << ".PTR || "; - emit_param(ve.val_l); m_of << ".META != "; emit_param(ve.val_r); m_of << ".META"; - break; - default: - MIR_BUG(mir_res, "Unknown comparison of a *-ptr - " << e.src << " with " << ty); - } - } - else - { - emit_param(ve.val_l); - switch(ve.op) - { - 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; - default: - MIR_BUG(mir_res, "Unknown comparison of a *-ptr - " << e.src << " with " << ty); - } - emit_param(ve.val_r); - } - break; - } - else if( ve.op == ::MIR::eBinOp::MOD && (ty == ::HIR::CoreType::F32 || ty == ::HIR::CoreType::F64) ) { - if( ty == ::HIR::CoreType::F32 ) - m_of << "remainderf"; - else - m_of << "remainder"; - m_of << "("; emit_param(ve.val_l); m_of << ", "; emit_param(ve.val_r); m_of << ")"; - break; - } - else { - } - - emit_param(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: - MIR_TODO(mir_res, "Overflow"); - break; - } - emit_param(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 << " = "; - emit_lvalue(ve.val); - m_of << ".META"; - ), - (DstPtr, - emit_lvalue(e.dst); - m_of << " = "; - emit_lvalue(ve.val); - m_of << ".PTR"; - ), - (MakeDst, - emit_lvalue(e.dst); - m_of << ".PTR = "; - emit_param(ve.ptr_val); - m_of << ";\n\t"; - 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\t"; - emit_lvalue(e.dst); - m_of << "._" << j << " = "; - emit_param(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_param(ve.vals[j]); - } - ), - (Variant, - const auto& tyi = m_crate.get_typeitem_by_path(sp, ve.path.m_path); - if( tyi.is_Union() ) - { - emit_lvalue(e.dst); - m_of << ".var_" << ve.index << " = "; emit_param(ve.val); - } - else if( const auto* enm_p = tyi.opt_Enum() ) - { - MIR_TODO(mir_res, "Construct enum with RValue::Variant"); - if( enm_p->is_value() ) - { - emit_lvalue(e.dst); m_of << ".TAG = " << enm_p->get_value(ve.index) << ""; - } - else - { - emit_lvalue(e.dst); m_of << ".TAG = " << ve.index << ";\n\t"; - emit_lvalue(e.dst); m_of << ".DATA"; - m_of << ".var_" << ve.index << " = "; emit_param(ve.val); - } - } - else - { - BUG(mir_res.sp, "Unexpected type in Variant"); - } - ), - (Struct, - if(ve.variant_idx != ~0u) - { - ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, e.dst); - const auto* enm_p = ty.m_data.as_Path().binding.as_Enum(); - - auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); - if( it != m_enum_repr_cache.end() ) - { - if( ve.variant_idx == 0 ) { - // TODO: Use nonzero_path - m_of << "memset(&"; emit_lvalue(e.dst); m_of << ", 0, sizeof("; emit_ctype(ty); m_of << "))"; - } - else if( ve.variant_idx == 1 ) { - emit_lvalue(e.dst); - m_of << "._0 = "; - emit_param(ve.vals[0]); - } - else { - } - break; - } - else if( enm_p->is_value() ) - { - emit_lvalue(e.dst); - m_of << ".TAG = " << enm_p->get_value(ve.variant_idx); - assert(ve.vals.size() == 0); - } - else - { - 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( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data( mir_res.get_lvalue_type(tmp, ve.vals[j].as_LValue())) ) - 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_param(ve.vals[j]); - } - ) - ) - m_of << ";"; - m_of << "\t// " << e.dst << " = " << e.src; - m_of << "\n"; - break; } - } + emit_statement(mir_res, stmt); } mir_res.set_cur_stmt_term(i); @@ -1912,6 +1537,457 @@ namespace { m_of.flush(); m_mir_res = nullptr; } + void emit_statement(const ::MIR::TypeResolve& mir_res, const ::MIR::Statement& stmt) + { + switch( stmt.tag() ) + { + case ::MIR::Statement::TAGDEAD: throw ""; + case ::MIR::Statement::TAG_ScopeEnd: + m_of << "// " << stmt << "\n"; + break; + case ::MIR::Statement::TAG_SetDropFlag: { + const auto& e = stmt.as_SetDropFlag(); + m_of << "\tdf" << e.idx << " = "; + if( e.other == ~0u ) + m_of << e.new_val; + else + m_of << (e.new_val ? "!" : "") << "df" << e.other; + m_of << ";\n"; + break; } + case ::MIR::Statement::TAG_Drop: { + const auto& e = stmt.as_Drop(); + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, e.slot); + + if( e.flag_idx != ~0u ) + m_of << "\tif( df" << e.flag_idx << " ) {\n"; + + switch( e.kind ) + { + case ::MIR::eDropKind::SHALLOW: + // Shallow drops are only valid on owned_box + if( const auto* ity = m_resolve.is_type_owned_box(ty) ) + { + // Emit a call to box_free for the type + ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { ity->clone() } }; + // TODO: This is specific to the official liballoc's owned_box + m_of << "\t" << Trans_Mangle(box_free) << "("; emit_lvalue(e.slot); m_of << "._0._0._0);\n"; + } + else + { + MIR_BUG(mir_res, "Shallow drop on non-Box - " << ty); + } + break; + case ::MIR::eDropKind::DEEP: + emit_destructor_call(e.slot, ty, false); + break; + } + if( e.flag_idx != ~0u ) + m_of << "\t}\n"; + break; } + case ::MIR::Statement::TAG_Asm: { + const auto& e = stmt.as_Asm(); + + struct H { + static bool has_flag(const ::std::vector<::std::string>& flags, const char* des) { + return ::std::find_if(flags.begin(), flags.end(), [des](const auto&x){return x==des;}) != flags.end(); + } + static const char* convert_reg(const char* r) { + if( ::std::strcmp(r, "{eax}") == 0 || ::std::strcmp(r, "{rax}") == 0 ) { + return "a"; + } + else { + return r; + } + } + }; + bool is_volatile = H::has_flag(e.flags, "volatile"); + bool is_intel = H::has_flag(e.flags, "intel"); + + m_of << "\t__asm__ "; + if(is_volatile) m_of << "__volatile__"; + // TODO: Convert format string? + // TODO: Use a C-specific escaper here. + m_of << "(\"" << (is_intel ? ".syntax intel; " : "") << FmtEscaped(e.tpl) << (is_intel ? ".syntax att; " : "") << "\""; + m_of << ": "; + for(unsigned int i = 0; i < e.outputs.size(); i ++ ) + { + const auto& v = e.outputs[i]; + if( i != 0 ) m_of << ", "; + m_of << "\""; + switch(v.first[0]) + { + case '=': m_of << "="; break; + case '+': m_of << "+"; break; + default: MIR_TODO(mir_res, "Handle asm! output leader '" << v.first[0] << "'"); + } + m_of << H::convert_reg(v.first.c_str()+1); + m_of << "\"("; emit_lvalue(v.second); m_of << ")"; + } + m_of << ": "; + for(unsigned int i = 0; i < e.inputs.size(); i ++ ) + { + const auto& v = e.inputs[i]; + if( i != 0 ) m_of << ", "; + m_of << "\"" << v.first << "\"("; emit_lvalue(v.second); m_of << ")"; + } + m_of << ": "; + for(unsigned int i = 0; i < e.clobbers.size(); i ++ ) + { + if( i != 0 ) m_of << ", "; + m_of << "\"" << e.clobbers[i] << "\""; + } + m_of << ");\n"; + break; } + case ::MIR::Statement::TAG_Assign: { + const auto& e = stmt.as_Assign(); + DEBUG("- " << e.dst << " = " << e.src); + m_of << "\t"; + TU_MATCHA( (e.src), (ve), + (Use, + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, ve); + if( ty == ::HIR::TypeRef::new_diverge() ) { + m_of << "abort()"; + break; + } + emit_lvalue(e.dst); + m_of << " = "; + emit_lvalue(ve); + ), + (Constant, + emit_lvalue(e.dst); + m_of << " = "; + emit_constant(ve, &e.dst); + ), + (SizedArray, + if( ve.count == 0 ) { + } + else if( ve.count == 1 ) { + emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); + } + else if( ve.count == 2 ) { + emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n\t"; + emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); + } + else if( ve.count == 3 ) { + emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n\t"; + emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); m_of << ";\n\t"; + emit_lvalue(e.dst); m_of << ".DATA[2] = "; emit_param(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_param(ve.val); + } + ), + (Borrow, + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, ve.val); + 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, le, + if( metadata_type(ty) != MetadataType::None ) { + emit_lvalue(e.dst); + m_of << " = "; + emit_lvalue(*le.val); + special = true; + } + ) + // Magic for taking a &-ptr to unsized field of a struct. + // - Needs to get metadata from bottom-level pointer. + else TU_IFLET(::MIR::LValue, ve.val, Field, le, + if( metadata_type(ty) != MetadataType::None ) { + const ::MIR::LValue* base_val = &*le.val; + while(base_val->is_Field()) + base_val = &*base_val->as_Field().val; + MIR_ASSERT(mir_res, base_val->is_Deref(), "DST access must be via a deref"); + const ::MIR::LValue& base_ptr = *base_val->as_Deref().val; + + // Construct the new DST + emit_lvalue(e.dst); m_of << ".META = "; emit_lvalue(base_ptr); m_of << ".META;\n\t"; + emit_lvalue(e.dst); m_of << ".PTR = &"; emit_lvalue(ve.val); + special = true; + } + ) + if( !special ) + { + emit_lvalue(e.dst); + m_of << " = "; + m_of << "& "; emit_lvalue(ve.val); + } + ), + (Cast, + if( m_resolve.is_type_phantom_data(ve.type) ) { + m_of << "/* PhandomData cast */\n"; + return ; + } + + 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 the destination is a thin pointer + 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 << " = "; + ::HIR::TypeRef tmp; + const auto& ty = ve.val_l.is_LValue() ? mir_res.get_lvalue_type(tmp, ve.val_l.as_LValue()) : tmp = mir_res.get_const_type(ve.val_l.as_Constant()); + if( ty.m_data.is_Borrow() ) { + m_of << "(slice_cmp("; emit_param(ve.val_l); m_of << ", "; emit_param(ve.val_r); m_of << ")"; + switch(ve.op) + { + case ::MIR::eBinOp::EQ: m_of << " == 0"; break; + case ::MIR::eBinOp::NE: m_of << " != 0"; break; + case ::MIR::eBinOp::GT: m_of << " > 0"; break; + case ::MIR::eBinOp::GE: m_of << " >= 0"; break; + case ::MIR::eBinOp::LT: m_of << " < 0"; break; + case ::MIR::eBinOp::LE: m_of << " <= 0"; break; + default: + MIR_BUG(mir_res, "Unknown comparison of a &-ptr - " << e.src << " with " << ty); + } + m_of << ")"; + break; + } + else if( const auto* te = ty.m_data.opt_Pointer() ) { + if( metadata_type(*te->inner) != MetadataType::None ) + { + switch(ve.op) + { + case ::MIR::eBinOp::EQ: + emit_param(ve.val_l); m_of << ".PTR == "; emit_param(ve.val_r); m_of << ".PTR && "; + emit_param(ve.val_l); m_of << ".META == "; emit_param(ve.val_r); m_of << ".META"; + break; + case ::MIR::eBinOp::NE: + emit_param(ve.val_l); m_of << ".PTR != "; emit_param(ve.val_r); m_of << ".PTR || "; + emit_param(ve.val_l); m_of << ".META != "; emit_param(ve.val_r); m_of << ".META"; + break; + default: + MIR_BUG(mir_res, "Unknown comparison of a *-ptr - " << e.src << " with " << ty); + } + } + else + { + emit_param(ve.val_l); + switch(ve.op) + { + 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; + default: + MIR_BUG(mir_res, "Unknown comparison of a *-ptr - " << e.src << " with " << ty); + } + emit_param(ve.val_r); + } + break; + } + else if( ve.op == ::MIR::eBinOp::MOD && (ty == ::HIR::CoreType::F32 || ty == ::HIR::CoreType::F64) ) { + if( ty == ::HIR::CoreType::F32 ) + m_of << "remainderf"; + else + m_of << "remainder"; + m_of << "("; emit_param(ve.val_l); m_of << ", "; emit_param(ve.val_r); m_of << ")"; + break; + } + else { + } + + emit_param(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: + MIR_TODO(mir_res, "Overflow"); + break; + } + emit_param(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 << " = "; + emit_lvalue(ve.val); + m_of << ".META"; + ), + (DstPtr, + emit_lvalue(e.dst); + m_of << " = "; + emit_lvalue(ve.val); + m_of << ".PTR"; + ), + (MakeDst, + emit_lvalue(e.dst); + m_of << ".PTR = "; + emit_param(ve.ptr_val); + m_of << ";\n\t"; + 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\t"; + emit_lvalue(e.dst); + m_of << "._" << j << " = "; + emit_param(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_param(ve.vals[j]); + } + ), + (Variant, + const auto& tyi = m_crate.get_typeitem_by_path(sp, ve.path.m_path); + if( tyi.is_Union() ) + { + emit_lvalue(e.dst); + m_of << ".var_" << ve.index << " = "; emit_param(ve.val); + } + else if( const auto* enm_p = tyi.opt_Enum() ) + { + MIR_TODO(mir_res, "Construct enum with RValue::Variant"); + if( enm_p->is_value() ) + { + emit_lvalue(e.dst); m_of << ".TAG = " << enm_p->get_value(ve.index) << ""; + } + else + { + emit_lvalue(e.dst); m_of << ".TAG = " << ve.index << ";\n\t"; + emit_lvalue(e.dst); m_of << ".DATA"; + m_of << ".var_" << ve.index << " = "; emit_param(ve.val); + } + } + else + { + BUG(mir_res.sp, "Unexpected type in Variant"); + } + ), + (Struct, + if(ve.variant_idx != ~0u) + { + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, e.dst); + const auto* enm_p = ty.m_data.as_Path().binding.as_Enum(); + + auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); + if( it != m_enum_repr_cache.end() ) + { + if( ve.variant_idx == 0 ) { + // TODO: Use nonzero_path + m_of << "memset(&"; emit_lvalue(e.dst); m_of << ", 0, sizeof("; emit_ctype(ty); m_of << "))"; + } + else if( ve.variant_idx == 1 ) { + emit_lvalue(e.dst); + m_of << "._0 = "; + emit_param(ve.vals[0]); + } + else { + } + break; + } + else if( enm_p->is_value() ) + { + emit_lvalue(e.dst); + m_of << ".TAG = " << enm_p->get_value(ve.variant_idx); + assert(ve.vals.size() == 0); + } + else + { + 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( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data( mir_res.get_lvalue_type(tmp, ve.vals[j].as_LValue())) ) + 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_param(ve.vals[j]); + } + ) + ) + m_of << ";"; + m_of << "\t// " << e.dst << " = " << e.src; + m_of << "\n"; + break; } + } + } private: const ::HIR::TypeRef& monomorphise_fcn_return(::HIR::TypeRef& tmp, const ::HIR::Function& item, const Trans_Params& params) { diff --git a/src/trans/target.cpp b/src/trans/target.cpp index a85ab12a..d9b3486e 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -7,10 +7,53 @@ */ #include "target.hpp" #include <algorithm> +#include "../expand/cfg.hpp" // TODO: Replace with target selection #define POINTER_SIZE_BYTES 8 +TargetSpec g_target = { + "unix", + "linux", + "gnu", + CodegenMode::Gnu11, + TargetArch { + "x86_64", + 64, false, + { true, false, true, true, true } + } + }; + +void Target_SetCfg() +{ + if(g_target.m_family == "unix") { + Cfg_SetFlag("unix"); + } + else if( g_target.m_family == "windows") { + Cfg_SetFlag("windows"); + } + Cfg_SetValue("target_family", g_target.m_family); + + if( g_target.m_os_name == "linux" ) + { + Cfg_SetFlag("linux"); + } + Cfg_SetValue("target_env", g_target.m_env_name); + + Cfg_SetValue("target_os", g_target.m_os_name); + Cfg_SetValue("target_pointer_width", FMT(g_target.m_arch.m_pointer_bits)); + Cfg_SetValue("target_endian", g_target.m_arch.m_big_endian ? "big" : "little"); + Cfg_SetValue("target_arch", g_target.m_arch.m_name); + Cfg_SetValueCb("target_has_atomic", [&](const ::std::string& s) { + if(s == "8") return g_target.m_arch.m_atomics.u8; // Has an atomic byte + if(s == "ptr") return g_target.m_arch.m_atomics.ptr; // Has an atomic pointer-sized value + return false; + }); + Cfg_SetValueCb("target_feature", [](const ::std::string& s) { + return false; + }); +} + bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align) { TU_MATCHA( (ty.m_data), (te), @@ -55,8 +98,8 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& return true; case ::HIR::CoreType::Usize: case ::HIR::CoreType::Isize: - out_size = POINTER_SIZE_BYTES; - out_align = POINTER_SIZE_BYTES; + out_size = g_target.m_arch.m_pointer_bits / 8; + out_align = g_target.m_arch.m_pointer_bits / 8; return true; case ::HIR::CoreType::F32: out_size = 4; @@ -104,6 +147,11 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& size_t size, align; if( !Target_GetSizeAndAlignOf(sp, t, size,align) ) return false; + if( out_size % align != 0 ) + { + out_size += align; + out_size %= align; + } out_size += size; out_align = ::std::max(out_align, align); } @@ -116,6 +164,9 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& ), (Function, // Pointer size + out_size = g_target.m_arch.m_pointer_bits / 8; + out_align = g_target.m_arch.m_pointer_bits / 8; + return true; ), (Closure, // TODO. diff --git a/src/trans/target.hpp b/src/trans/target.hpp index 1c081b54..80ba0bf2 100644 --- a/src/trans/target.hpp +++ b/src/trans/target.hpp @@ -10,6 +10,38 @@ #include <cstddef> #include <hir/type.hpp> +enum class CodegenMode +{ + Gnu11, + Msvc, +}; + +struct TargetArch +{ + ::std::string m_name; + unsigned m_pointer_bits; + bool m_big_endian; + + struct { + bool u8; + bool u16; + bool u32; + bool u64; + bool ptr; + } m_atomics; +}; +struct TargetSpec +{ + ::std::string m_family; + ::std::string m_os_name; + ::std::string m_env_name; + + CodegenMode m_codegen_mode; + TargetArch m_arch; +}; + + +extern void Target_SetCfg(); extern bool Target_GetSizeOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_size); extern bool Target_GetAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_align); |