diff options
author | John Hodge (Mutabah) <acessdev@gmail.com> | 2018-02-11 15:33:08 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-11 15:33:08 +0800 |
commit | 6caf5739a97774b2602106e616db75e8a0ad5f8a (patch) | |
tree | 9d16f869bbff27743fe7c233fba9c4665a4d9138 | |
parent | 9e864a5d3ea05706ea6c7f68e47d32629a2c877e (diff) | |
parent | 3718f8cb7ee7b8c93e4d69b9aa2e00b4f50efd62 (diff) | |
download | mrust-6caf5739a97774b2602106e616db75e8a0ad5f8a.tar.gz |
Merge pull request #52 from thepowersgang/common_layout
Merge "common_layout" branch
29 files changed, 2527 insertions, 572 deletions
@@ -53,4 +53,5 @@ /bnf/rust.output /bnf/test.bin /vsproject/output +/vsproject/output_mmir /vsproject/standalone_miri/x64 @@ -10,7 +10,9 @@ # DEPENDENCIES # - zlib (-dev) # - curl (bin, for downloading libstd source) - +ifeq ($(OS),Windows_NT) + EXESUF ?= .exe +endif EXESUF ?= CXX ?= g++ V ?= @ @@ -115,7 +117,7 @@ OBJ += mir/check_full.o OBJ += hir/serialise.o hir/deserialise.o hir/serialise_lowlevel.o OBJ += trans/trans_list.o trans/mangling.o OBJ += trans/enumerate.o trans/monomorphise.o trans/codegen.o -OBJ += trans/codegen_c.o trans/codegen_c_structured.o +OBJ += trans/codegen_c.o trans/codegen_c_structured.o trans/codegen_mmir.o OBJ += trans/target.o trans/allocator.o PCHS := ast/ast.hpp @@ -147,7 +149,7 @@ RUSTC_SRC_DL := $(RUSTCSRC)/dl-version MAKE_MINICARGO = $(MAKE) -f minicargo.mk RUSTC_VERSION=$(shell cat $(RUSTC_SRC_DES)) RUSTC_CHANNEL=$(RUSTC_SRC_TY) -output/libstd.hir: $(BIN) $(RUSTC_SRC_DL) +output/libstd.hir: $(BIN) $(MAKE_MINICARGO) $@ output/libtest.hir output/libpanic_unwind.hir output/libproc_macro.hir: output/libstd.hir $(MAKE_MINICARGO) $@ @@ -245,14 +247,14 @@ RUNTIME_ARGS_output/libstd-test := --test-threads 1 RUNTIME_ARGS_output/libstd-test := --skip ::collections::hash::map::test_map::test_index_nonexistent RUNTIME_ARGS_output/libstd-test += --skip ::collections::hash::map::test_map::test_drops -output/lib%-test: $(RUSTCSRC)src/lib%/lib.rs $(RUSTC_SRC_DL) $(TEST_DEPS) +output/lib%-test: $(RUSTCSRC)src/lib%/lib.rs $(TEST_DEPS) @echo "--- [MRUSTC] --test -o $@" @mkdir -p output/ @rm -f $@ $(DBG) $(ENV_$@) $(BIN) --test $< -o $@ $(RUST_FLAGS) $(ARGS_$@) $(PIPECMD) # # HACK: Work around gdb returning success even if the program crashed @test -e $@ -output/lib%-test: $(RUSTCSRC)src/lib%/src/lib.rs $(RUSTC_SRC_DL) $(TEST_DEPS) +output/lib%-test: $(RUSTCSRC)src/lib%/src/lib.rs $(TEST_DEPS) @echo "--- [MRUSTC] $@" @mkdir -p output/ @rm -f $@ @@ -278,7 +280,7 @@ output/rust/test_run-pass_hello_out.txt: output/rust/test_run-pass_hello # # TEST: Rust standard library and the "hello, world" run-pass test # -test: $(RUSTC_SRC_DL) output/libstd.hir output/rust/test_run-pass_hello_out.txt $(BIN) +test: output/libstd.hir output/rust/test_run-pass_hello_out.txt $(BIN) # # TEST: Attempt to compile rust_os (Tifflin) from ../rust_os @@ -305,9 +307,12 @@ $(BIN): $(OBJ) @mkdir -p $(dir $@) @echo [CXX] -o $@ $V$(CXX) -o $@ $(LINKFLAGS) $(OBJ) $(LIBS) +ifeq ($(OS),Windows_NT) +else objcopy --only-keep-debug $(BIN) $(BIN).debug objcopy --add-gnu-debuglink=$(BIN).debug $(BIN) strip $(BIN) +endif $(OBJDIR)%.o: src/%.cpp @mkdir -p $(dir $@) diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index be83b7c3..f6a1b990 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -227,6 +227,7 @@ public: struct ValueVariant { ::std::string name; ::HIR::ExprPtr expr; + // TODO: Signed. uint64_t val; }; TAGGED_UNION(Class, Data, diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 36f09c9c..033e7bf5 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -105,8 +105,11 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const os << "*/"; ), (TraitObject, - os << "("; - os << e.m_trait; + os << "dyn ("; + if( e.m_trait.m_path != ::HIR::GenericPath() ) + { + os << e.m_trait; + } for(const auto& tr : e.m_markers) os << "+" << tr; if( e.m_lifetime.name != "" ) diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp index 6e113d27..478953b9 100644 --- a/src/include/tagged_union.hpp +++ b/src/include/tagged_union.hpp @@ -110,7 +110,7 @@ #define TU_IFLET(CLASS, VAR, TAG, NAME, ...) if(VAR.tag() == CLASS::TAG_##TAG) { auto& NAME = VAR.as_##TAG(); (void)&NAME; __VA_ARGS__ } // Evil hack: two for loops, the inner stops the outer after it's done. -#define TU_ARM(VAR, TAG, NAME) case ::std::remove_reference<decltype(VAR)>::type::TAG_##TAG: for(bool tu_lc = true; tu_lc;) for(auto& NAME = VAR.as_##TAG(); tu_lc; tu_lc=false) +#define TU_ARM(VAR, TAG, NAME) case ::std::remove_reference<decltype(VAR)>::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = VAR.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) //#define TU_TEST(VAL, ...) (VAL.is_##TAG() && VAL.as_##TAG() TEST) #define TU_TEST1(VAL, TAG1, TEST) (VAL.is_##TAG1() && VAL.as_##TAG1() TEST) diff --git a/src/main.cpp b/src/main.cpp index 7fa5e765..ea095367 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -185,6 +185,7 @@ struct ProgramParams bool full_validate_early = false; } debug; struct { + ::std::string codegen_type; ::std::string emit_build_command; } codegen; @@ -603,6 +604,7 @@ int main(int argc, char *argv[]) // - MIR Exportable (public generic, #[inline], or used by a either of those) // - Require codegen (public or used by an exported function) TransOptions trans_opt; + trans_opt.mode = params.codegen.codegen_type == "" ? "c" : params.codegen.codegen_type; trans_opt.build_command_file = params.codegen.emit_build_command; trans_opt.opt_level = params.opt_level; for(const char* libdir : params.lib_search_dirs ) { @@ -782,6 +784,10 @@ ProgramParams::ProgramParams(int argc, char *argv[]) get_optval(); this->codegen.emit_build_command = optval; } + else if( optname == "codegen-type" ) { + get_optval(); + this->codegen.codegen_type = optval; + } else if( optname == "emit-depfile" ) { get_optval(); this->emit_depfile = optval; diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index fb34357e..edb9170a 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -13,9 +13,11 @@ namespace MIR { (Int, os << (e.v < 0 ? "-" : "+"); os << (e.v < 0 ? -e.v : e.v); + os << " " << e.t; ), (Uint, os << e.v; + os << " " << e.t; ), (Float, os << e.v; diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 873a3997..0a83332d 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -1983,6 +1983,8 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) // - Remove calls to `size_of` and `align_of` (replace with value if known) for(auto& bb : fcn.blocks) { + state.set_cur_stmt_term(bb); + MIR_DEBUG(state, bb.terminator); if( !bb.terminator.is_Call() ) continue ; auto& te = bb.terminator.as_Call(); @@ -1994,6 +1996,19 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) size_t size_val = 0; if( Target_GetSizeOf(state.sp, state.m_resolve, tef.params.m_types.at(0), size_val) ) { + DEBUG("size_of = " << size_val); + auto val = ::MIR::Constant::make_Uint({ size_val, ::HIR::CoreType::Usize }); + bb.statements.push_back(::MIR::Statement::make_Assign({ mv$(te.ret_val), mv$(val) })); + bb.terminator = ::MIR::Terminator::make_Goto(te.ret_block); + changed = true; + } + } + else if( tef.name == "size_of_val" ) + { + size_t size_val = 0, tmp; + if( Target_GetSizeAndAlignOf(state.sp, state.m_resolve, tef.params.m_types.at(0), size_val, tmp) && size_val != SIZE_MAX ) + { + DEBUG("size_of_val = " << size_val); auto val = ::MIR::Constant::make_Uint({ size_val, ::HIR::CoreType::Usize }); bb.statements.push_back(::MIR::Statement::make_Assign({ mv$(te.ret_val), mv$(val) })); bb.terminator = ::MIR::Terminator::make_Goto(te.ret_block); @@ -2005,6 +2020,7 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) size_t align_val = 0; if( Target_GetAlignOf(state.sp, state.m_resolve, tef.params.m_types.at(0), align_val) ) { + DEBUG("align_of = " << align_val); auto val = ::MIR::Constant::make_Uint({ align_val, ::HIR::CoreType::Usize }); bb.statements.push_back(::MIR::Statement::make_Assign({ mv$(te.ret_val), mv$(val) })); bb.terminator = ::MIR::Terminator::make_Goto(te.ret_block); diff --git a/src/trans/codegen.cpp b/src/trans/codegen.cpp index b3244072..f008a2b3 100644 --- a/src/trans/codegen.cpp +++ b/src/trans/codegen.cpp @@ -18,7 +18,16 @@ void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const ::HIR::Crate& crate, const TransList& list, bool is_executable) { static Span sp; - auto codegen = Trans_Codegen_GetGeneratorC(crate, outfile); + ::std::unique_ptr<CodeGenerator> codegen; + + if( opt.mode == "monomir" ) + { + codegen = Trans_Codegen_GetGenerator_MonoMir(crate, outfile); + } + else + { + codegen = Trans_Codegen_GetGeneratorC(crate, outfile); + } // 1. Emit structure/type definitions. // - Emit in the order they're needed. diff --git a/src/trans/codegen.hpp b/src/trans/codegen.hpp index 65135d18..b769e350 100644 --- a/src/trans/codegen.hpp +++ b/src/trans/codegen.hpp @@ -56,4 +56,5 @@ public: extern ::std::unique_ptr<CodeGenerator> Trans_Codegen_GetGeneratorC(const ::HIR::Crate& crate, const ::std::string& outfile); +extern ::std::unique_ptr<CodeGenerator> Trans_Codegen_GetGenerator_MonoMir(const ::HIR::Crate& crate, const ::std::string& outfile); diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 57cd0eb5..6cfbaf3b 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -195,8 +195,6 @@ namespace { bool disallow_empty_structs = false; } m_options; - ::std::map<::HIR::GenericPath, ::std::vector<unsigned>> m_enum_repr_cache; - ::std::vector< ::std::pair< ::HIR::GenericPath, const ::HIR::Struct*> > m_box_glue_todo; public: CodeGenerator_C(const ::HIR::Crate& crate, const ::std::string& outfile): @@ -211,6 +209,10 @@ namespace { case CodegenMode::Gnu11: m_compiler = Compiler::Gcc; m_options.emulated_i128 = false; + if( Target_GetCurSpec().m_arch.m_pointer_bits < 64 ) + { + m_options.emulated_i128 = true; + } break; case CodegenMode::Msvc: m_compiler = Compiler::Msvc; @@ -275,8 +277,6 @@ namespace { { case Compiler::Gcc: m_of - << "typedef unsigned __int128 uint128_t;\n" - << "typedef signed __int128 int128_t;\n" << "extern void _Unwind_Resume(void) __attribute__((noreturn));\n" << "#define ALIGNOF(t) __alignof__(t)\n" ; @@ -369,22 +369,15 @@ namespace { m_of << "typedef struct { uint64_t lo, hi; } uint128_t;\n" << "typedef struct { uint64_t lo, hi; } int128_t;\n" - << "static inline int128_t make128s(int64_t v) { int128_t rv = { v, (v < 0 ? -1 : 0) }; return rv; }\n" - << "static inline int128_t add128s(int128_t a, int128_t b) { int128_t v; v.lo = a.lo + b.lo; v.hi = a.hi + b.hi + (v.lo < a.lo ? 1 : 0); return v; }\n" - << "static inline int128_t sub128s(int128_t a, int128_t b) { int128_t v; v.lo = a.lo - b.lo; v.hi = a.hi - b.hi - (v.lo > a.lo ? 1 : 0); return v; }\n" - << "static inline int128_t mul128s(int128_t a, int128_t b) { abort(); }\n" - << "static inline int128_t div128s(int128_t a, int128_t b) { abort(); }\n" - << "static inline int128_t mod128s(int128_t a, int128_t b) { abort(); }\n" - << "static inline int128_t and128s(int128_t a, int128_t b) { int128_t v = { a.lo & b.lo, a.hi & b.hi }; return v; }\n" - << "static inline int128_t or128s (int128_t a, int128_t b) { int128_t v = { a.lo | b.lo, a.hi | b.hi }; return v; }\n" - << "static inline int128_t xor128s(int128_t a, int128_t b) { int128_t v = { a.lo ^ b.lo, a.hi ^ b.hi }; return v; }\n" - << "static inline int128_t shl128s(int128_t a, uint32_t b) { int128_t v; if(b < 64) { v.lo = a.lo << b; v.hi = (a.hi << b) | (a.lo >> (64 - b)); } else { v.hi = a.lo << (b - 64); v.lo = 0; } return v; }\n" - << "static inline int128_t shr128s(int128_t a, uint32_t b) { int128_t v; if(b < 64) { v.lo = (a.lo >> b)|(a.hi << (64 - b)); v.hi = a.hi >> b; } else { v.lo = a.hi >> (b - 64); v.hi = 0; } return v; }\n" << "static inline uint128_t make128(uint64_t v) { uint128_t rv = { v, 0 }; return rv; }\n" - << "static inline uint128_t add128(uint128_t a, uint128_t b) { uint128_t v; v.lo = a.lo + b.lo; v.hi = a.hi + b.hi + (v.lo < a.lo ? 1 : 0); return v; }\n" - << "static inline uint128_t sub128(uint128_t a, uint128_t b) { uint128_t v; v.lo = a.lo - b.lo; v.hi = a.hi - b.hi - (v.lo > a.lo ? 1 : 0); return v; }\n" - << "static inline uint128_t mul128(uint128_t a, uint128_t b) { abort(); }\n" - << "static inline uint128_t div128(uint128_t a, uint128_t b) { abort(); }\n" + << "static inline bool add128_o(uint128_t a, uint128_t b, uint128_t* o) { o->lo = a.lo + b.lo; o->hi = a.hi + b.hi + (o->lo < a.lo ? 1 : 0); return (o->hi >= a.hi); }\n" + << "static inline bool sub128_o(uint128_t a, uint128_t b, uint128_t* o) { o->lo = a.lo - b.lo; o->hi = a.hi - b.hi - (o->lo < a.lo ? 1 : 0); return (o->hi <= a.hi); }\n" + << "static inline bool mul128_o(uint128_t a, uint128_t b, uint128_t* o) { abort(); }\n" + << "static inline bool div128_o(uint128_t a, uint128_t b, uint128_t* o) { abort(); }\n" + << "static inline uint128_t add128(uint128_t a, uint128_t b) { uint128_t v; add128_o(a, b, &v); return v; }\n" + << "static inline uint128_t sub128(uint128_t a, uint128_t b) { uint128_t v; sub128_o(a, b, &v); return v; }\n" + << "static inline uint128_t mul128(uint128_t a, uint128_t b) { uint128_t v; mul128_o(a, b, &v); return v; }\n" + << "static inline uint128_t div128(uint128_t a, uint128_t b) { uint128_t v; div128_o(a, b, &v); return v; }\n" << "static inline uint128_t mod128(uint128_t a, uint128_t b) { abort(); }\n" << "static inline uint128_t and128(uint128_t a, uint128_t b) { uint128_t v = { a.lo & b.lo, a.hi & b.hi }; return v; }\n" << "static inline uint128_t or128 (uint128_t a, uint128_t b) { uint128_t v = { a.lo | b.lo, a.hi | b.hi }; return v; }\n" @@ -401,12 +394,25 @@ namespace { << "\tuint128_t rv = { (v.lo == 0 ? (v.hi == 0 ? 128 : __builtin_ctz64(v.hi) + 64) : __builtin_ctz64(v.lo)), 0 };\n" << "\treturn rv;\n" << "}\n" + << "static inline int128_t make128s(int64_t v) { int128_t rv = { v, (v < 0 ? -1 : 0) }; return rv; }\n" + << "static inline int128_t add128s(int128_t a, int128_t b) { int128_t v; v.lo = a.lo + b.lo; v.hi = a.hi + b.hi + (v.lo < a.lo ? 1 : 0); return v; }\n" + << "static inline int128_t sub128s(int128_t a, int128_t b) { int128_t v; v.lo = a.lo - b.lo; v.hi = a.hi - b.hi - (v.lo > a.lo ? 1 : 0); return v; }\n" + << "static inline int128_t mul128s(int128_t a, int128_t b) { abort(); }\n" + << "static inline int128_t div128s(int128_t a, int128_t b) { abort(); }\n" + << "static inline int128_t mod128s(int128_t a, int128_t b) { abort(); }\n" + << "static inline int128_t and128s(int128_t a, int128_t b) { int128_t v = { a.lo & b.lo, a.hi & b.hi }; return v; }\n" + << "static inline int128_t or128s (int128_t a, int128_t b) { int128_t v = { a.lo | b.lo, a.hi | b.hi }; return v; }\n" + << "static inline int128_t xor128s(int128_t a, int128_t b) { int128_t v = { a.lo ^ b.lo, a.hi ^ b.hi }; return v; }\n" + << "static inline int128_t shl128s(int128_t a, uint32_t b) { int128_t v; if(b < 64) { v.lo = a.lo << b; v.hi = (a.hi << b) | (a.lo >> (64 - b)); } else { v.hi = a.lo << (b - 64); v.lo = 0; } return v; }\n" + << "static inline int128_t shr128s(int128_t a, uint32_t b) { int128_t v; if(b < 64) { v.lo = (a.lo >> b)|(a.hi << (64 - b)); v.hi = a.hi >> b; } else { v.lo = a.hi >> (b - 64); v.hi = 0; } return v; }\n" ; } else { // GCC-only m_of + << "typedef unsigned __int128 uint128_t;\n" + << "typedef signed __int128 int128_t;\n" << "static inline uint128_t __builtin_bswap128(uint128_t v) {\n" << "\tuint64_t lo = __builtin_bswap64((uint64_t)v);\n" << "\tuint64_t hi = __builtin_bswap64((uint64_t)(v>>64));\n" @@ -500,17 +506,21 @@ namespace { // Execute $CC with the required libraries StringList args; +#ifdef _WIN32 + bool is_windows = true; +#else bool is_windows = false; +#endif switch( m_compiler ) { case Compiler::Gcc: if( getenv("CC") ) { args.push_back( getenv("CC") ); - } + } else { //args.push_back( Target_GetCurSpec().m_c_compiler + "-gcc" ); args.push_back( "gcc" ); - } + } args.push_back("-ffunction-sections"); args.push_back("-pthread"); switch(opt.opt_level) @@ -563,7 +573,6 @@ namespace { } break; case Compiler::Msvc: - is_windows = true; // TODO: Look up these paths in the registry and use CreateProcess instead of system args.push_back(detect_msvc().path_vcvarsall); args.push_back( Target_GetCurSpec().m_c_compiler ); @@ -833,94 +842,89 @@ namespace { const auto& lc = p.m_path.m_components.back(); is_vtable = (lc.size() > 7 && ::std::strcmp(lc.c_str() + lc.size() - 7, "#vtable") == 0); }; + bool is_packed = item.m_repr == ::HIR::Struct::Repr::Packed; TRACE_FUNCTION_F(p); - ::HIR::TypeRef tmp; - auto monomorph = [&](const auto& x)->const auto& { - if( monomorphise_type_needed(x) ) { - tmp = monomorphise_type(sp, item.m_params, p.m_params, x); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return x; - } - }; + auto item_ty = ::HIR::TypeRef::new_path(p.clone(), &item); + const auto* repr = Target_GetTypeRepr(sp, m_resolve, item_ty); bool has_unsized = false; - auto emit_struct_fld_ty = [&](const ::HIR::TypeRef& ty_raw, ::FmtLambda inner) { - const auto& ty = monomorph(ty_raw); - TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te, - emit_ctype( *te.inner, FMT_CB(ss, ss << inner << "[0]";) ); - has_unsized = true; - ) - else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, TraitObject, te, - m_of << "unsigned char " << inner << "[0]"; - has_unsized = true; - ) - else if( ty == ::HIR::CoreType::Str ) { - m_of << "uint8_t " << inner << "[0]"; - has_unsized = true; - } - else { - emit_ctype( ty, inner ); - } - }; m_of << "// struct " << p << "\n"; + // For repr(packed), mark as packed + if(is_packed) + { + switch(m_compiler) + { + case Compiler::Msvc: + m_of << "#pragma pack(push, 1)\n"; + break; + case Compiler::Gcc: + break; + } + } m_of << "struct s_" << Trans_Mangle(p) << " {\n"; // HACK: For vtables, insert the alignment and size at the start + // TODO: This should be done in HIR, not here if(is_vtable) { m_of << "\tVTABLE_HDR hdr;\n"; } - TU_MATCHA( (item.m_data), (e), - (Unit, - if( m_options.disallow_empty_structs ) - { - m_of << "\tchar _d;\n"; + ::std::vector<unsigned> fields; + for(const auto& ent : repr->fields) + { + (void)ent; + fields.push_back(fields.size()); + } + ::std::sort(fields.begin(), fields.end(), [&](auto a, auto b){ return repr->fields[a].offset < repr->fields[b].offset; }); + for(unsigned fld : fields) + { + m_of << "\t"; + const auto& ty = repr->fields[fld].ty; + + if( const auto* te = ty.m_data.opt_Slice() ) { + emit_ctype( *te->inner, FMT_CB(ss, ss << "_" << fld << "[0]";) ); + has_unsized = true; } - ), - (Tuple, - if( e.empty() ) - { - if( m_options.disallow_empty_structs ) - { - m_of << "\tchar _d;\n"; - } + else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, TraitObject, te, + m_of << "unsigned char _" << fld << "[0]"; + has_unsized = true; + ) + else if( ty == ::HIR::CoreType::Str ) { + m_of << "uint8_t _" << fld << "[0]"; + has_unsized = true; } - else - { - for(unsigned int i = 0; i < e.size(); i ++) - { - const auto& fld = e[i]; - m_of << "\t"; - emit_struct_fld_ty(fld.ent, FMT_CB(ss, ss << "_" << i;)); - m_of << ";\n"; - } + else { + // TODO: Nested unsized? + emit_ctype( ty, FMT_CB(ss, ss << "_" << fld) ); } - ), - (Named, - if( e.empty() ) + m_of << ";\n"; + } + if( fields.size() == 0 ) + { + if( m_options.disallow_empty_structs ) { - if( m_options.disallow_empty_structs ) - { - m_of << "\tchar _d;\n"; - } + m_of << "\tchar _d;\n"; } - else + } + m_of << "}"; + if(is_packed) + { + switch(m_compiler) { - for(unsigned int i = 0; i < e.size(); i ++) - { - const auto& fld = e[i].second; - m_of << "\t"; - emit_struct_fld_ty(fld.ent, FMT_CB(ss, ss << "_" << i;)); - m_of << ";\n"; - } + case Compiler::Msvc: + m_of << ";\n#pragma pack(pop)\n"; + break; + case Compiler::Gcc: + m_of << " __attribute__((packed));\n"; + break; } - ) - ) - m_of << "};\n"; + } + else + { + m_of << ";\n"; + } + (void)has_unsized; auto struct_ty = ::HIR::TypeRef(p.clone(), &item); auto drop_glue_path = ::HIR::Path(struct_ty.clone(), "#drop_glue"); @@ -959,28 +963,12 @@ namespace { auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 }); - TU_MATCHA( (item.m_data), (e), - (Unit, - ), - (Tuple, - for(unsigned int i = 0; i < e.size(); i ++) - { - const auto& fld = e[i]; - fld_lv.as_Field().field_index = i; - - emit_destructor_call(fld_lv, monomorph(fld.ent), true, 1); - } - ), - (Named, - for(unsigned int i = 0; i < e.size(); i ++) - { - const auto& fld = e[i].second; - fld_lv.as_Field().field_index = i; + for(size_t i = 0; i < repr->fields.size(); i++) + { + fld_lv.as_Field().field_index = i; - emit_destructor_call(fld_lv, monomorph(fld.ent), true, 1); - } - ) - ) + emit_destructor_call(fld_lv, repr->fields[i].ty, /*unsized_valid=*/true, /*indent=*/1); + } m_of << "}\n"; m_mir_res = nullptr; } @@ -991,27 +979,19 @@ namespace { m_mir_res = &top_mir_res; TRACE_FUNCTION_F(p); + auto item_ty = ::HIR::TypeRef::new_path(p.clone(), &item); + const auto* repr = Target_GetTypeRepr(sp, m_resolve, item_ty); + MIR_ASSERT(*m_mir_res, repr != nullptr, "No repr for union " << item_ty); - ::HIR::TypeRef tmp; - auto monomorph = [&](const auto& x)->const auto& { - if( monomorphise_type_needed(x) ) { - tmp = monomorphise_type(sp, item.m_params, p.m_params, x); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return x; - } - }; m_of << "union u_" << Trans_Mangle(p) << " {\n"; - for(unsigned int i = 0; i < item.m_variants.size(); i ++) + for(unsigned int i = 0; i < repr->fields.size(); i ++) { - m_of << "\t"; emit_ctype( monomorph(item.m_variants[i].second.ent), FMT_CB(ss, ss << "var_" << i;) ); m_of << ";\n"; + assert(repr->fields[i].offset == 0); + m_of << "\t"; emit_ctype( repr->fields[i].ty, FMT_CB(ss, ss << "var_" << i;) ); m_of << ";\n"; } m_of << "};\n"; // Drop glue (calls destructor if there is one) - auto item_ty = ::HIR::TypeRef(p.clone(), &item); auto drop_glue_path = ::HIR::Path(item_ty.clone(), "#drop_glue"); auto item_ptr_ty = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Owned, item_ty.clone()); auto drop_impl_path = (item.m_markings.has_drop_impl ? ::HIR::Path(item_ty.clone(), m_resolve.m_lang_Drop, "drop") : ::HIR::Path(::HIR::SimplePath())); @@ -1031,79 +1011,28 @@ namespace { m_of << "}\n"; } - // TODO: Move this to codegen.cpp? - bool get_nonzero_path(const Span& sp, const ::HIR::TypeRef& ty, ::std::vector<unsigned int>& out) const + void emit_enum_path(const TypeRepr* repr, const TypeRepr::FieldPath& path) { - TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), - ( - return false; - ), - (Path, - if( te.binding.is_Struct() ) - { - const auto& str = *te.binding.as_Struct(); - const auto& p = te.path.m_data.as_Generic(); - ::HIR::TypeRef tmp; - auto monomorph = [&](const auto& ty)->const auto& { - if( monomorphise_type_needed(ty) ) { - tmp = monomorphise_type(sp, str.m_params, p.m_params, ty); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return ty; - } - }; - TU_MATCHA( (str.m_data), (se), - (Unit, - ), - (Tuple, - for(size_t i = 0; i < se.size(); i ++) - { - if( get_nonzero_path(sp, monomorph(se[i].ent), out) ) - { - out.push_back(i); - return true; - } - } - ), - (Named, - for(size_t i = 0; i < se.size(); i ++) - { - if( get_nonzero_path(sp, monomorph(se[i].second.ent), out) ) - { - out.push_back(i); - return true; - } - } - ) - ) - } - return false; - ), - (Borrow, - if( metadata_type(*te.inner) != MetadataType::None ) - { - // HACK: If the inner is a DST, emit ~0 as a marker - out.push_back(~0u); - } - return true; - ), - (Function, - return true; - ) - ) - } - void emit_nonzero_path(const ::std::vector<unsigned int>& nonzero_path) { - for(const auto v : nonzero_path) + if( TU_TEST1(repr->variants, Values, .field.index == path.index) ) { - if(v == ~0u) { - // NOTE: Should only ever be the last + m_of << ".TAG"; + } + else + { + m_of << ".DATA.var_" << path.index; + } + const auto* ty = &repr->fields[path.index].ty; + for(auto fld : path.sub_fields) + { + repr = Target_GetTypeRepr(sp, m_resolve, *ty); + ty = &repr->fields[fld].ty; + m_of << "._" << fld; + } + if( const auto* te = ty->m_data.opt_Borrow() ) + { + if( metadata_type(*te->inner) != MetadataType::None ) { m_of << ".PTR"; } - else { - m_of << "._" << v; - } } } @@ -1114,101 +1043,98 @@ namespace { m_mir_res = &top_mir_res; TRACE_FUNCTION_F(p); - ::HIR::TypeRef tmp; - auto monomorph = [&](const auto& x)->const auto& { - if( monomorphise_type_needed(x) ) { - tmp = monomorphise_type(sp, item.m_params, p.m_params, x); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return x; - } - }; + auto item_ty = ::HIR::TypeRef::new_path(p.clone(), &item); + const auto* repr = Target_GetTypeRepr(sp, m_resolve, item_ty); - // TODO: Cache repr info elsewhere (and have core codegen be responsible instead) - // TODO: Do more complex nonzero relations. - ::std::vector<unsigned> nonzero_path; + // 1. Enumerate fields with the same offset as the first (these go into a union) + // TODO: What if all data variants are zero-sized? + ::std::vector<unsigned> union_fields; + for(size_t i = 1; i < repr->fields.size(); i ++) { - // Detect Option (and similar enums) - // - Matches two-variant enums where the first variant is unit-like, and the second is not - if( item.m_data.is_Data() && item.m_data.as_Data().size() == 2 - && item.m_data.as_Data()[0].type == ::HIR::TypeRef::new_unit() - && item.m_data.as_Data()[1].type != ::HIR::TypeRef::new_unit() - ) + // Avoid placing the tag in the union + if( repr->variants.is_Values() && i == repr->variants.as_Values().field.index ) + continue ; + if( repr->fields[i].offset == repr->fields[0].offset ) { - const auto& data_type = monomorph(item.m_data.as_Data()[1].type); - if( get_nonzero_path(sp, data_type, nonzero_path) ) - { - ::std::reverse( nonzero_path.begin(), nonzero_path.end() ); - DEBUG("Correct format for NonZero to apply, and field found at " << nonzero_path); - } - else - { - DEBUG("Correct format for NonZero to apply, but no field"); - assert(nonzero_path.size() == 0); - } + union_fields.push_back(i); } } m_of << "// enum " << p << "\n"; - if( nonzero_path.size() > 0 ) - { - //MIR_ASSERT(*m_mir_res, item.num_variants() == 2, ""); - //MIR_ASSERT(*m_mir_res, item.m_variants[0].second.is_Unit(), ""); - //const auto& data_var = item.m_variants[1]; - //MIR_ASSERT(*m_mir_res, data_var.second.is_Tuple(), ""); - //MIR_ASSERT(*m_mir_res, data_var.second.as_Tuple().size() == 1, ""); - const auto& data_type = monomorph(item.m_data.as_Data()[1].type); - m_of << "struct e_" << Trans_Mangle(p) << " {\n"; - m_of << "\t"; emit_ctype(data_type, FMT_CB(s, s << "_1";)); m_of << ";\n"; - m_of << "};\n"; - } - else if( item.m_data.is_Value() ) + m_of << "struct e_" << Trans_Mangle(p) << " {\n"; + + // If there multiple fields with the same offset, they're the data variants + if( union_fields.size() > 0 ) { - m_of << "struct e_" << Trans_Mangle(p) << " {\n"; - switch(item.m_data.as_Value().repr) + assert(1 + union_fields.size() + 1 >= repr->fields.size()); + // Make the union! + // NOTE: The way the structure generation works is that enum variants are always first, so the field index = the variant index + m_of << "\tunion {\n"; + // > First field + m_of << "\t\t"; + emit_ctype(repr->fields[0].ty, FMT_CB(os, os << "var_0")); + m_of << ";\n"; + // > All others + for(auto idx : union_fields) { - case ::HIR::Enum::Repr::Rust: - case ::HIR::Enum::Repr::C: - m_of << "\tunsigned int TAG;\n"; - break; - case ::HIR::Enum::Repr::Usize: - m_of << "\tuintptr_t TAG;\n"; - break; - case ::HIR::Enum::Repr::U8: - m_of << "\tuint8_t TAG;\n"; - break; - case ::HIR::Enum::Repr::U16: - m_of << "\tuint16_t TAG;\n"; - break; - case ::HIR::Enum::Repr::U32: - m_of << "\tuint32_t TAG;\n"; - break; - case ::HIR::Enum::Repr::U64: - m_of << "\tuint64_t TAG;\n"; - break; + // TODO: if the compiler doesn't allow zero-sized types, don't emit zero-sized fields. + m_of << "\t\t"; + emit_ctype(repr->fields[idx].ty, FMT_CB(os, os << "var_" << idx)); + m_of << ";\n"; + } + m_of << "\t} DATA;\n"; + + if( repr->fields.size() == 1 + union_fields.size() ) + { + // No tag, the tag is in one of the fields. + DEBUG("Untagged, nonzero or other"); + } + else + { + //assert(repr->fields.back().offset != repr->fields.front().offset); + DEBUG("Tag present at offset " << repr->fields.back().offset << " - " << repr->fields.back().ty); + + m_of << "\t"; + emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG")); + m_of << ";\n"; } - m_of << "};\n"; } - else + else if( repr->fields.size() == 1 ) { - const auto& variants = item.m_data.as_Data(); - m_of << "struct e_" << Trans_Mangle(p) << " {\n"; - m_of << "\tunsigned int TAG;\n"; - if( variants.size() > 0 ) + if( repr->variants.is_Values() ) + { + // Tag only. + // - A value-only enum. + m_of << "\t"; + emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "TAG")); + m_of << ";\n"; + } + else { m_of << "\tunion {\n"; - for(unsigned int i = 0; i < variants.size(); i ++) - { - m_of << "\t\t"; - emit_ctype( monomorph(variants[i].type) ); - m_of << " var_" << i << ";\n"; - } + m_of << "\t\t"; + emit_ctype(repr->fields.back().ty, FMT_CB(os, os << "var_0")); + m_of << ";\n"; m_of << "\t} DATA;\n"; + // No tag + } + } + else if( repr->fields.size() == 0 ) + { + // Empty/un-constructable + // - Shouldn't be emitted really? + if( m_options.disallow_empty_structs ) + { + m_of << "\tchar _d;\n"; } - m_of << "};\n"; } + else + { + // One data field and a tag (or all different offsets) + TODO(sp, "No common offsets and more than one field, is this possible? - " << item_ty); + } + + m_of << "};\n"; // --- // - Drop Glue @@ -1234,39 +1160,35 @@ namespace { } auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); - if( nonzero_path.size() > 0 ) + if( const auto* e = repr->variants.opt_NonZero() ) { + unsigned idx = 1 - e->zero_variant; // TODO: Fat pointers? - m_of << "\tif( (*rv)._1"; emit_nonzero_path(nonzero_path); m_of << " ) {\n"; - emit_destructor_call( ::MIR::LValue::make_Field({ box$(self), 1 }), monomorph(item.m_data.as_Data()[1].type), false, 2 ); + m_of << "\tif( (*rv)"; emit_enum_path(repr, e->field); m_of << " != 0 ) {\n"; + emit_destructor_call( ::MIR::LValue::make_Downcast({ box$(self), idx }), repr->fields[idx].ty, false, 2 ); m_of << "\t}\n"; } - else if( const auto* e = item.m_data.opt_Data() ) + else if( repr->fields.size() <= 1 ) + { + // Value enum + // Glue does nothing (except call the destructor, if there is one) + } + else if( const auto* e = repr->variants.opt_Values() ) { auto var_lv =::MIR::LValue::make_Downcast({ box$(self), 0 }); m_of << "\tswitch(rv->TAG) {\n"; - for(unsigned int var_idx = 0; var_idx < e->size(); var_idx ++) + for(unsigned int var_idx = 0; var_idx < e->values.size(); var_idx ++) { var_lv.as_Downcast().variant_index = var_idx; - m_of << "\tcase " << var_idx << ":\n"; - emit_destructor_call(var_lv, monomorph( (*e)[var_idx].type ), false, 2); + m_of << "\tcase " << e->values[var_idx] << ":\n"; + emit_destructor_call(var_lv, repr->fields[var_idx].ty, /*unsized_valid=*/false, /*indent=*/2); m_of << "\tbreak;\n"; } m_of << "\t}\n"; } - else - { - // Value enum - // Glue does nothing (except call the destructor, if there is one) - } m_of << "}\n"; m_mir_res = nullptr; - - if( nonzero_path.size() ) - { - m_enum_repr_cache.insert( ::std::make_pair( p.clone(), mv$(nonzero_path) ) ); - } } void emit_constructor_enum(const Span& sp, const ::HIR::GenericPath& path, const ::HIR::Enum& item, size_t var_idx) override @@ -1286,6 +1208,7 @@ namespace { auto p = path.clone(); p.m_path.m_components.pop_back(); + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ::HIR::TypeRef::new_path(p.clone(), &item)); ASSERT_BUG(sp, item.m_data.is_Data(), ""); const auto& var = item.m_data.as_Data().at(var_idx); @@ -1303,39 +1226,44 @@ namespace { emit_ctype( monomorph(e[i].ent), FMT_CB(ss, ss << "_" << i;) ); } m_of << ") {\n"; - auto it = m_enum_repr_cache.find(p); - if( it != m_enum_repr_cache.end() ) + + //if( repr->variants. + m_of << "\tstruct e_" << Trans_Mangle(p) << " rv = {"; + switch(repr->variants.tag()) { - m_of << "\tstruct e_" << Trans_Mangle(p) << " rv = { _0 };\n"; + case TypeRepr::VariantMode::TAGDEAD: throw ""; + TU_ARM(repr->variants, Values, ve) { + m_of << " .TAG = " << ve.values[var_idx] << ","; + } break; + TU_ARM(repr->variants, NonZero, ve) { + } break; + TU_ARM(repr->variants, None, ve) { + } break; } - else - { - m_of << "\tstruct e_" << Trans_Mangle(p) << " rv = { .TAG = " << var_idx; - if( e.empty() ) + if( e.empty() ) + { + if( m_options.disallow_empty_structs ) { - if( m_options.disallow_empty_structs ) - { - m_of << ", .DATA = { .var_" << var_idx << " = {0} }"; - } - else - { - // No fields, don't initialise - } + m_of << " .DATA = { .var_" << var_idx << " = {0} }"; } else { - m_of << ", .DATA = { .var_" << var_idx << " = {"; - for(unsigned int i = 0; i < e.size(); i ++) - { - if(i != 0) - m_of << ","; - m_of << "\n\t\t_" << i; - } - m_of << "\n\t\t}"; + // No fields, don't initialise } - m_of << " }};\n"; } + else + { + m_of << " .DATA = { .var_" << var_idx << " = {"; + for(unsigned int i = 0; i < e.size(); i ++) + { + if(i != 0) + m_of << ","; + m_of << "\n\t\t_" << i; + } + m_of << "\n\t\t}"; + } + m_of << " }};\n"; m_of << "\treturn rv;\n"; m_of << "}\n"; } @@ -1496,7 +1424,7 @@ namespace { MIR_TODO(*m_mir_res, "Union literals"); ), (Enum, - MIR_ASSERT(*m_mir_res, pbe->m_data.is_Data(), ""); + MIR_ASSERT(*m_mir_res, pbe->m_data.is_Data(), "Getting inner type of a non-Data enum"); const auto& evar = pbe->m_data.as_Data().at(var); return monomorph_with(pp, evar.type); ) @@ -1530,15 +1458,23 @@ namespace { (Variant, MIR_ASSERT(*m_mir_res, ty.m_data.is_Path(), ""); MIR_ASSERT(*m_mir_res, ty.m_data.as_Path().binding.is_Enum(), ""); + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); const auto& enm = *ty.m_data.as_Path().binding.as_Enum(); - auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); - if( it != m_enum_repr_cache.end() ) + if( repr->variants.is_None() ) + { + m_of << "{}"; + } + else if( const auto* ve = repr->variants.opt_NonZero() ) { - if( e.idx == 0 ) { + if( e.idx == ve->zero_variant ) + { m_of << "{0}"; } - else { + else + { + m_of << "{ { .var_" << e.idx << " = "; emit_literal(get_inner_type(e.idx, 0), *e.val, params); + m_of << " } }"; } } else if( enm.is_value() ) @@ -1548,10 +1484,11 @@ namespace { } else { - m_of << "{" << e.idx; - m_of << ", { .var_" << e.idx << " = "; + m_of << "{"; + m_of << " { .var_" << e.idx << " = "; emit_literal(get_inner_type(e.idx, 0), *e.val, params); m_of << " }"; + m_of << ", .TAG = " << repr->variants.as_Values().values[e.idx]; m_of << "}"; } ), @@ -1874,7 +1811,7 @@ namespace { else if( item.m_linkage.name == "CopyFileExW" ) { // Not field access to undo an Option<fn()> - m_of << "\treturn CopyFileExW(arg0, arg1, arg2._1._0, arg3, arg4, arg5);\n"; + m_of << "\treturn CopyFileExW(arg0, arg1, arg2.DATA.var_1._0, arg3, arg4, arg5);\n"; } // BUG: libtest defines this as returning an i32, but it's void else if( item.m_linkage.name == "GetSystemInfo" ) @@ -2616,21 +2553,24 @@ namespace { { ::HIR::TypeRef tmp; const auto& ty = mir_res.get_lvalue_type(tmp, e.dst); + auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); - auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); - if( it != m_enum_repr_cache.end() ) + if( repr->variants.is_None() ) + { + emit_lvalue(e.dst); m_of << ".DATA.var_0 = "; emit_param(ve.val); + } + else if( const auto* re = repr->variants.opt_NonZero() ) { - if( ve.index == 0 ) { + MIR_ASSERT(*m_mir_res, ve.index < 2, ""); + if( ve.index == re->zero_variant ) { // TODO: Use nonzero_path m_of << "memset(&"; emit_lvalue(e.dst); m_of << ", 0, sizeof("; emit_ctype(ty); m_of << "))"; } - else if( ve.index == 1 ) { + else { emit_lvalue(e.dst); - m_of << "._1 = "; + m_of << ".DATA.var_" << ve.index << " = "; emit_param(ve.val); } - else { - } break; } else if( enm_p->is_value() ) @@ -2639,7 +2579,7 @@ namespace { } else { - emit_lvalue(e.dst); m_of << ".TAG = " << ve.index << ";\n\t"; + emit_lvalue(e.dst); m_of << ".TAG = " << repr->variants.as_Values().values[ve.index] << ";\n\t"; emit_lvalue(e.dst); m_of << ".DATA"; m_of << ".var_" << ve.index << " = "; emit_param(ve.val); } @@ -2848,45 +2788,76 @@ namespace { const auto& ty = mir_res.get_lvalue_type(tmp, val); MIR_ASSERT(mir_res, ty.m_data.is_Path(), "Switch over non-Path type"); MIR_ASSERT(mir_res, ty.m_data.as_Path().binding.is_Enum(), "Switch over non-enum"); - const auto* enm = ty.m_data.as_Path().binding.as_Enum(); + const auto* repr = Target_GetTypeRepr(mir_res.sp, m_resolve, ty); + MIR_ASSERT(mir_res, repr, "No repr for " << ty); - auto it = m_enum_repr_cache.find( ty.m_data.as_Path().path.m_data.as_Generic() ); - if( it != m_enum_repr_cache.end() ) + if( const auto* e = repr->variants.opt_NonZero() ) { - //MIR_ASSERT(mir_res, e.targets.size() == 2, "NonZero optimised representation for an enum without two variants"); MIR_ASSERT(mir_res, n_arms == 2, "NonZero optimised switch without two arms"); - m_of << indent << "if("; emit_lvalue(val); m_of << "._1"; emit_nonzero_path(it->second); m_of << ")\n"; - m_of << indent; - cb(1); + m_of << indent << "if( "; emit_lvalue(val); emit_enum_path(repr, e->field); m_of << " != 0 )\n"; + m_of << indent << "\t"; + cb(1 - e->zero_variant); m_of << "\n"; m_of << indent << "else\n"; - m_of << indent; - cb(0); + m_of << indent << "\t"; + cb(e->zero_variant); m_of << "\n"; } - else if( enm->is_value() ) + else if( const auto* e = repr->variants.opt_Values() ) { + const auto& tag_ty = Target_GetInnerType(sp, m_resolve, *repr, e->field.index, e->field.sub_fields); + bool is_signed = false; + switch(tag_ty.m_data.as_Primitive()) + { + case ::HIR::CoreType::I8: + case ::HIR::CoreType::I16: + case ::HIR::CoreType::I32: + case ::HIR::CoreType::I64: + case ::HIR::CoreType::Isize: + is_signed = true; + break; + case ::HIR::CoreType::Bool: + case ::HIR::CoreType::U8: + case ::HIR::CoreType::U16: + case ::HIR::CoreType::U32: + case ::HIR::CoreType::U64: + case ::HIR::CoreType::Usize: + case ::HIR::CoreType::Char: + is_signed = false; + break; + case ::HIR::CoreType::I128: // TODO: Emulation + case ::HIR::CoreType::U128: // TODO: Emulation + break; + case ::HIR::CoreType::F32: + case ::HIR::CoreType::F64: + MIR_TODO(mir_res, "Floating point enum tag."); + break; + case ::HIR::CoreType::Str: + MIR_BUG(mir_res, "Unsized tag?!"); + } m_of << indent << "switch("; emit_lvalue(val); m_of << ".TAG) {\n"; for(size_t j = 0; j < n_arms; j ++) { - m_of << indent << "case " << enm->get_value(j) << ": "; + // TODO: Get type of this field and check if it's signed. + if( is_signed ) { + m_of << indent << "case " << static_cast<int64_t>(e->values[j]) << ": "; + } + else { + m_of << indent << "case " << e->values[j] << ": "; + } cb(j); m_of << "\n"; } m_of << indent << "default: abort();\n"; m_of << indent << "}\n"; } + else if( repr->variants.is_None() ) + { + m_of << indent; cb(0); m_of << "\n"; + } else { - m_of << indent << "switch("; emit_lvalue(val); m_of << ".TAG) {\n"; - for(size_t j = 0; j < n_arms; j ++) - { - m_of << indent << "case " << j << ": "; - cb(j); - m_of << "\n"; - } - m_of << indent << "default: abort();\n"; - m_of << indent << "}\n"; + BUG(sp, "Unexpected variant type - " << repr->variants.tag_str()); } } void emit_term_switchvalue(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& val, const ::MIR::SwitchValues& values, unsigned indent_level, ::std::function<void(size_t)> cb) @@ -3048,6 +3019,9 @@ namespace { if (::std::strcmp(r, "{eax}") == 0 || ::std::strcmp(r, "{rax}") == 0) { return "a"; } + else if (::std::strcmp(r, "{ecx}") == 0 || ::std::strcmp(r, "{rcx}") == 0) { + return "c"; + } else { return r; } @@ -3080,6 +3054,8 @@ namespace { m_of << "%"; else if (*it == '%' && !isdigit(*(it + 1))) m_of << "%%"; + else if (*it == '$' && isdigit(*(it + 1)) && *(it + 2) != 'x') + m_of << "%"; else m_of << *it; } @@ -3097,14 +3073,14 @@ namespace { default: MIR_TODO(mir_res, "Handle asm! output leader '" << v.first[0] << "'"); } m_of << H::convert_reg(v.first.c_str() + 1); - m_of << "\"("; emit_lvalue(v.second); m_of << ")"; + m_of << "\" ("; emit_lvalue(v.second); m_of << ")"; } m_of << ": "; for (unsigned int i = 0; i < e.inputs.size(); i++) { const auto& v = e.inputs[i]; if (i != 0) m_of << ", "; - m_of << "\"" << v.first << "\"("; emit_lvalue(v.second); m_of << ")"; + m_of << "\"" << H::convert_reg(v.first.c_str()) << "\" ("; emit_lvalue(v.second); m_of << ")"; } m_of << ": "; for (unsigned int i = 0; i < e.clobbers.size(); i++) @@ -3590,7 +3566,7 @@ namespace { } else if( name == "write_bytes" ) { // 0: Destination, 1: Value, 2: Count - m_of << "memset( "; emit_param(e.args.at(0)); + m_of << "if( "; emit_param(e.args.at(2)); m_of << " > 0) memset( "; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", "; emit_param(e.args.at(2)); m_of << " * sizeof("; emit_ctype(params.m_types.at(0)); m_of << ")"; m_of << ")"; @@ -3698,19 +3674,26 @@ namespace { else if( name == "discriminant_value" ) { const auto& ty = params.m_types.at(0); emit_lvalue(e.ret_val); m_of << " = "; - if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Enum() ) { - auto it = m_enum_repr_cache.find( ty.m_data.as_Path().path.m_data.as_Generic() ); - if( it != m_enum_repr_cache.end() ) - { - emit_param(e.args.at(0)); m_of << "->_1"; emit_nonzero_path(it->second); m_of << " != 0"; - } - else - { - emit_param(e.args.at(0)); m_of << "->TAG"; - } + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); + if( !repr ) { + m_of << "0"; } else { - m_of << "0"; + switch(repr->variants.tag()) + { + case TypeRepr::VariantMode::TAGDEAD: throw ""; + TU_ARM(repr->variants, None, _e) + m_of << "0"; + break; + TU_ARM(repr->variants, Values, ve) { + m_of << "(*"; emit_param(e.args.at(0)); m_of << ")"; emit_enum_path(repr, ve.field); + } break; + TU_ARM(repr->variants, NonZero, ve) { + m_of << "(*"; emit_param(e.args.at(0)); m_of << ")"; emit_enum_path(repr, ve.field); m_of << " "; + m_of << (ve.zero_variant ? "==" : "!="); + m_of << " 0"; + } break; + } } } // Hints @@ -3727,59 +3710,146 @@ namespace { // Overflowing Arithmatic // HACK: Uses GCC intrinsics else if( name == "add_with_overflow" ) { - switch(m_compiler) + if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::U128) { - case Compiler::Gcc: - emit_lvalue(e.ret_val); m_of << "._1 = __builtin_add_overflow"; + emit_lvalue(e.ret_val); m_of << "._1 = add128_o"; m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; - break; - case Compiler::Msvc: - emit_lvalue(e.ret_val); m_of << "._1 = _addcarry_u" << get_prim_size(params.m_types.at(0)); - m_of << "(0, "; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; - break; + } + else if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::I128) + { + emit_lvalue(e.ret_val); m_of << "._1 = add128s_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + } + else + + { + switch(m_compiler) + { + case Compiler::Gcc: + emit_lvalue(e.ret_val); m_of << "._1 = __builtin_add_overflow"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + break; + case Compiler::Msvc: + emit_lvalue(e.ret_val); m_of << "._1 = _addcarry_u" << get_prim_size(params.m_types.at(0)); + m_of << "(0, "; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + break; + } } } else if( name == "sub_with_overflow" ) { - emit_lvalue(e.ret_val); m_of << "._1 = __builtin_sub_overflow("; emit_param(e.args.at(0)); - m_of << ", "; emit_param(e.args.at(1)); - m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::U128) + { + emit_lvalue(e.ret_val); m_of << "._1 = sub128_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + } + else if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::I128) + { + emit_lvalue(e.ret_val); m_of << "._1 = sub128s_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + } + else + { + switch(m_compiler) + { + case Compiler::Gcc: + emit_lvalue(e.ret_val); m_of << "._1 = __builtin_sub_overflow"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + break; + case Compiler::Msvc: + emit_lvalue(e.ret_val); m_of << "._1 = _subcarry_u" << get_prim_size(params.m_types.at(0)); + m_of << "(0, "; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + break; + } + } } else if( name == "mul_with_overflow" ) { - switch(m_compiler) + if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::U128) { - case Compiler::Gcc: - emit_lvalue(e.ret_val); m_of << "._1 = __builtin_mul_overflow("; emit_param(e.args.at(0)); - m_of << ", "; emit_param(e.args.at(1)); - m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; - break; - case Compiler::Msvc: - emit_lvalue(e.ret_val); m_of << "._1 = __builtin_mul_overflow_" << params.m_types.at(0); + emit_lvalue(e.ret_val); m_of << "._1 = mul128_o"; m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; - break; + } + else if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::I128) + { + emit_lvalue(e.ret_val); m_of << "._1 = mul128s_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + } + else + { + switch(m_compiler) + { + case Compiler::Gcc: + emit_lvalue(e.ret_val); m_of << "._1 = __builtin_mul_overflow("; emit_param(e.args.at(0)); + m_of << ", "; emit_param(e.args.at(1)); + m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + break; + case Compiler::Msvc: + emit_lvalue(e.ret_val); m_of << "._1 = __builtin_mul_overflow_" << params.m_types.at(0); + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)"; + break; + } } } else if( name == "overflowing_add" ) { - switch(m_compiler) + if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::U128) { - case Compiler::Gcc: - m_of << "__builtin_add_overflow"; + m_of << "add128_o"; m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; - break; - case Compiler::Msvc: - m_of << "_addcarry_u" << get_prim_size(params.m_types.at(0)); - m_of << "(0, "; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; - break; + } + else if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::I128) + { + m_of << "add128s_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } + else + { + switch(m_compiler) + { + case Compiler::Gcc: + m_of << "__builtin_add_overflow"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + break; + case Compiler::Msvc: + m_of << "_addcarry_u" << get_prim_size(params.m_types.at(0)); + m_of << "(0, "; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + break; + } } } else if( name == "overflowing_sub" ) { - m_of << "__builtin_sub_overflow("; emit_param(e.args.at(0)); - m_of << ", "; emit_param(e.args.at(1)); - m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::U128) + { + m_of << "sub128_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } + else if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::I128) + { + m_of << "sub128s_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } + else + { + m_of << "__builtin_sub_overflow("; emit_param(e.args.at(0)); + m_of << ", "; emit_param(e.args.at(1)); + m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } } else if( name == "overflowing_mul" ) { - m_of << "__builtin_mul_overflow("; emit_param(e.args.at(0)); - m_of << ", "; emit_param(e.args.at(1)); - m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::U128) + { + m_of << "mul128_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } + else if(m_options.emulated_i128 && params.m_types.at(0) == ::HIR::CoreType::I128) + { + m_of << "mul128s_o"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } + else + { + m_of << "__builtin_mul_overflow("; emit_param(e.args.at(0)); + m_of << ", "; emit_param(e.args.at(1)); + m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")"; + } } // Unchecked Arithmatic else if( name == "unchecked_div" ) { @@ -4325,28 +4395,59 @@ namespace { (Variant, MIR_ASSERT(*m_mir_res, ty.m_data.is_Path(), ""); MIR_ASSERT(*m_mir_res, ty.m_data.as_Path().binding.is_Enum(), ""); - const auto& enm = *ty.m_data.as_Path().binding.as_Enum(); - auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); - if( it != m_enum_repr_cache.end() ) + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); + MIR_ASSERT(*m_mir_res, repr, ""); + switch(repr->variants.tag()) { - if( e.idx == 0 ) { - emit_nonzero_path(it->second); - m_of << " = 0"; + case TypeRepr::VariantMode::TAGDEAD: throw ""; + TU_ARM(repr->variants, None, ve) + BUG(sp, ""); + TU_ARM(repr->variants, NonZero, ve) { + if( e.idx == ve.zero_variant ) { + emit_dst(); emit_enum_path(repr, ve.field); m_of << " = 0"; } else { assign_from_literal([&](){ emit_dst(); }, get_inner_type(e.idx, 0), *e.val); } - } - else if( enm.is_value() ) - { - MIR_ASSERT(*m_mir_res, TU_TEST1((*e.val), List, .empty()), "Value-only enum with fields"); - emit_dst(); m_of << ".TAG = " << enm.get_value(e.idx); - } - else - { - emit_dst(); m_of << ".TAG = " << e.idx; - m_of << ";\n\t"; - assign_from_literal([&](){ emit_dst(); m_of << ".DATA.var_" << e.idx; }, get_inner_type(e.idx, 0), *e.val); + } break; + TU_ARM(repr->variants, Values, ve) { + const auto& tag_ty = Target_GetInnerType(sp, m_resolve, *repr, ve.field.index, ve.field.sub_fields); + emit_dst(); emit_enum_path(repr, ve.field); m_of << " = "; + switch(tag_ty.m_data.as_Primitive()) + { + case ::HIR::CoreType::I8: + case ::HIR::CoreType::I16: + case ::HIR::CoreType::I32: + case ::HIR::CoreType::I64: + case ::HIR::CoreType::Isize: + m_of << static_cast<int64_t>(ve.values[e.idx]); + break; + case ::HIR::CoreType::Bool: + case ::HIR::CoreType::U8: + case ::HIR::CoreType::U16: + case ::HIR::CoreType::U32: + case ::HIR::CoreType::U64: + case ::HIR::CoreType::Usize: + case ::HIR::CoreType::Char: + m_of << ve.values[e.idx]; + break; + case ::HIR::CoreType::I128: // TODO: Emulation + case ::HIR::CoreType::U128: // TODO: Emulation + MIR_TODO(*m_mir_res, "Emulated i128 tag"); + break; + case ::HIR::CoreType::F32: + case ::HIR::CoreType::F64: + MIR_TODO(*m_mir_res, "Floating point enum tag."); + break; + case ::HIR::CoreType::Str: + MIR_BUG(*m_mir_res, "Unsized tag?!"); + } + if( TU_TEST1((*e.val), List, .empty() == false) ) + { + m_of << ";\n\t"; + assign_from_literal([&](){ emit_dst(); m_of << ".DATA.var_" << e.idx; }, get_inner_type(e.idx, 0), *e.val); + } + } break; } ), (Integer, @@ -4509,18 +4610,7 @@ namespace { MIR_ASSERT(*m_mir_res, ty.m_data.is_Path(), "Downcast on non-Path type - " << ty); if( ty.m_data.as_Path().binding.is_Enum() ) { - auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); - if( it != m_enum_repr_cache.end() ) - { - MIR_ASSERT(*m_mir_res, e.variant_index == 1, ""); - // NOTE: Downcast returns a magic tuple - m_of << "._1"; - break ; - } - else - { - m_of << ".DATA"; - } + m_of << ".DATA"; } m_of << ".var_" << e.variant_index; ) diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp new file mode 100644 index 00000000..09167486 --- /dev/null +++ b/src/trans/codegen_mmir.cpp @@ -0,0 +1,826 @@ +// +// +// +#include "codegen.hpp" +#include <hir_typeck/static.hpp> +#include <mir/helpers.hpp> +#include "mangling.hpp" +#include "target.hpp" + +#include <iomanip> +#include <fstream> + +namespace +{ + template<typename T> + struct Fmt + { + const T& e; + Fmt(const T& e): + e(e) + { + } + }; + template<typename T> Fmt<T> fmt(const T& v) { return Fmt<T>(v); } + + ::std::ostream& operator<<(::std::ostream& os, const Fmt<::MIR::LValue>& x) + { + auto fmt_lhs = [](::std::ostream& os, const ::MIR::LValue& lv) { + if( lv.is_Deref() ) { + os << "(" << fmt(lv) << ")"; + } + else { + os << fmt(lv); + } + }; + switch(x.e.tag()) + { + case ::MIR::LValue::TAGDEAD: throw ""; + TU_ARM(x.e, Return, _e) (void)_e; + os << "RETURN"; + break; + TU_ARM(x.e, Local, e) + os << "var" << e; + break; + TU_ARM(x.e, Argument, e) + os << "arg" << e.idx; + break; + TU_ARM(x.e, Static, e) + os << e; + break; + TU_ARM(x.e, Deref, e) + os << "*" << fmt(*e.val); + break; + TU_ARM(x.e, Field, e) { + fmt_lhs(os, *e.val); + // Avoid `0.` existing in the output + if( e.val->is_Field() || e.val->is_Downcast() ) + os << " "; + os << "." << e.field_index; + } break; + TU_ARM(x.e, Index, e) { + fmt_lhs(os, *e.val); + os << "[" << fmt(*e.idx) << "]"; + } break; + TU_ARM(x.e, Downcast, e) { + fmt_lhs(os, *e.val); + os << "@" << e.variant_index; + } break; + } + return os; + } + ::std::ostream& operator<<(::std::ostream& os, const Fmt<::MIR::Constant>& x) + { + struct H { + static uint64_t double_to_u64(double v) { + uint64_t rv; + ::std::memcpy(&rv, &v, sizeof(double)); + return rv; + } + }; + const auto& e = x.e; + switch(e.tag()) + { + case ::MIR::Constant::TAGDEAD: throw ""; + TU_ARM(e, Int, v) { + os << (v.v < 0 ? "" : "+") << v.v << " " << v.t; + } break; + TU_ARM(e, Uint, v) + os << v.v << " " << v.t; + break; + TU_ARM(e, Float, v) { + // TODO: Infinity/nan/... + auto vi = H::double_to_u64(v.v); + bool sign = (vi & (1ull << 63)) != 0; + int exp = (vi >> 52) & 0x7FF; + uint64_t frac = vi & ((1ull << 52) - 1); + os << (sign ? "-" : "+") << "0x1." << ::std::setw(52/4) << ::std::setfill('0') << ::std::hex << frac << ::std::dec << "p" << (exp - 1023); + os << " " << v.t; + } break; + default: + os << e; + break; + } + return os; + } + ::std::ostream& operator<<(::std::ostream& os, const Fmt<::MIR::Param>& x) + { + switch(x.e.tag()) + { + case ::MIR::Param::TAGDEAD: throw ""; + TU_ARM(x.e, LValue, e) + os << fmt(e); + break; + TU_ARM(x.e, Constant, e) + os << fmt(e); + break; + } + return os; + } + + class CodeGenerator_MonoMir: + public CodeGenerator + { + enum class MetadataType { + None, + Slice, + TraitObject, + }; + + static Span sp; + + const ::HIR::Crate& m_crate; + ::StaticTraitResolve m_resolve; + + + ::std::string m_outfile_path; + ::std::ofstream m_of; + const ::MIR::TypeResolve* m_mir_res; + + public: + CodeGenerator_MonoMir(const ::HIR::Crate& crate, const ::std::string& outfile): + m_crate(crate), + m_resolve(crate), + m_outfile_path(outfile + ".mir"), + m_of(m_outfile_path) + { + for( const auto& crate : m_crate.m_ext_crates ) + { + m_of << "crate \"" << FmtEscaped(crate.second.m_path) << ".o.mir\";\n"; + } + } + + void finalise(bool is_executable, const TransOptions& opt) override + { + if( is_executable ) + { + m_of << "fn ::main#(i32, *const *const i8): i32 {\n"; + auto c_start_path = m_resolve.m_crate.get_lang_item_path_opt("mrustc-start"); + if( c_start_path == ::HIR::SimplePath() ) + { + m_of << "\tlet m: fn();\n"; + m_of << "\t0: {\n"; + m_of << "\t\tASSIGN m = &" << ::HIR::GenericPath(m_resolve.m_crate.get_lang_item_path(Span(), "mrustc-main")) << ";\n"; + m_of << "\t\tCALL RETURN = " << ::HIR::GenericPath(m_resolve.m_crate.get_lang_item_path(Span(), "start")) << "(m, arg1, arg2) goto 1 else 1\n"; + } + else + { + m_of << "\t0: {\n"; + m_of << "\t\tCALL RETURN = " << ::HIR::GenericPath(c_start_path) << "(arg1, arg2) goto 1 else 1;\n"; + } + m_of << "\t}\n"; + m_of << "\t1: {\n"; + m_of << "\t\tRETURN\n"; + m_of << "\t}\n"; + m_of << "}\n"; + } + + m_of.flush(); + m_of.close(); + } + + /* + void emit_box_drop_glue(::HIR::GenericPath p, const ::HIR::Struct& item) + { + 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()); + // - Drop Glue + const auto* ity = m_resolve.is_type_owned_box(struct_ty); + + auto inner_ptr = ::HIR::TypeRef::new_pointer( ::HIR::BorrowType::Unique, ity->clone() ); + auto box_free = ::HIR::GenericPath { m_crate.get_lang_item_path(sp, "box_free"), { ity->clone() } }; + + ::std::vector< ::std::pair<::HIR::Pattern,::HIR::TypeRef> > args; + args.push_back( ::std::make_pair( ::HIR::Pattern {}, mv$(inner_ptr) ) ); + + ::MIR::Function empty_fcn; + ::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 << "fn " << Trans_Mangle(drop_glue_path) << "(" << Trans_Mangle(p) << ") {\n"; + + // Obtain inner pointer + // TODO: This is very specific to the structure of the official liballoc's Box. + m_of << "\tlet arg1: "; emit_type(args[0].second); m_of << "\n"; + // Call destructor of inner data + emit_destructor_call( ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) }), *ity, true, 1); + // Emit a call to box_free for the type + m_of << "\t" << Trans_Mangle(box_free) << "(arg0);\n"; + + m_of << "}\n"; + m_mir_res = nullptr; + } + */ + + + void emit_type(const ::HIR::TypeRef& ty) override + { + TRACE_FUNCTION_F(ty); + ::MIR::Function empty_fcn; + ::MIR::TypeResolve top_mir_res { sp, m_resolve, FMT_CB(ss, ss << "type " << ty;), ::HIR::TypeRef(), {}, empty_fcn }; + m_mir_res = &top_mir_res; + + if( const auto* te = ty.m_data.opt_Tuple() ) + { + if( te->size() > 0 ) + { + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); + MIR_ASSERT(*m_mir_res, repr, "No repr for tuple " << ty); + + m_of << "type " << ty << " {\n"; + m_of << "\tSIZE " << repr->size << ", ALIGN " << repr->align << ";\n"; + for(const auto& e : repr->fields) + { + m_of << "\t" << e.offset << " = " << e.ty << ";\n"; + } + m_of << "}\n"; + } +#if 0 + auto drop_glue_path = ::HIR::Path(ty.clone(), "#drop_glue"); + auto args = ::std::vector< ::std::pair<::HIR::Pattern,::HIR::TypeRef> >(); + 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) + { + emit_destructor_call(fld_lv, ity, /*unsized_valid=*/false, 1); + fld_lv.as_Field().field_index ++; + } + m_of << "}\n"; +#endif + } + else { + } + + m_mir_res = nullptr; + } + + void emit_struct(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Struct& item) override + { + ::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); + }; + + TRACE_FUNCTION_F(p); + ::HIR::TypeRef ty = ::HIR::TypeRef::new_path(p.clone(), &item); + + // HACK: For vtables, insert the alignment and size at the start + // TODO: Add this to the vtable in the HIR instead + if(is_vtable) + { + //m_of << "\tVTABLE_HDR hdr;\n"; + } + + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); + MIR_ASSERT(*m_mir_res, repr, "No repr for struct " << ty); + m_of << "type " << p << " {\n"; + m_of << "\tSIZE " << repr->size << ", ALIGN " << repr->align << ";\n"; + for(const auto& e : repr->fields) + { + m_of << "\t" << e.offset << " = " << e.ty << ";\n"; + } + m_of << "}\n"; + + // TODO: Drop glue! +#if 0 + 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()); + // - Drop Glue + + ::std::vector< ::std::pair<::HIR::Pattern,::HIR::TypeRef> > args; + if( item.m_markings.has_drop_impl ) { + // If the type is defined outside the current crate, define as static (to avoid conflicts when we define it) + if( p.m_path.m_crate_name != m_crate.m_crate_name ) + { + if( item.m_params.m_types.size() > 0 ) { + m_of << "static "; + } + else { + m_of << "extern "; + } + } + m_of << "tUNIT " << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ");\n"; + } + else if( m_resolve.is_type_owned_box(struct_ty) ) + { + m_box_glue_todo.push_back( ::std::make_pair( mv$(struct_ty.m_data.as_Path().path.m_data.as_Generic()), &item ) ); + m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ");\n"; + return ; + } + + ::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 }); + TU_MATCHA( (item.m_data), (e), + (Unit, + ), + (Tuple, + for(unsigned int i = 0; i < e.size(); i ++) + { + const auto& fld = e[i]; + fld_lv.as_Field().field_index = i; + + emit_destructor_call(fld_lv, monomorph(fld.ent), true, 1); + } + ), + (Named, + for(unsigned int i = 0; i < e.size(); i ++) + { + const auto& fld = e[i].second; + fld_lv.as_Field().field_index = i; + + emit_destructor_call(fld_lv, monomorph(fld.ent), true, 1); + } + ) + ) + m_of << "}\n"; +#endif + m_mir_res = nullptr; + } + void emit_union(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Union& item) override + { + ::MIR::Function empty_fcn; + ::MIR::TypeResolve top_mir_res { sp, m_resolve, FMT_CB(ss, ss << "union " << p;), ::HIR::TypeRef(), {}, empty_fcn }; + m_mir_res = &top_mir_res; + + TRACE_FUNCTION_F(p); + ::HIR::TypeRef ty = ::HIR::TypeRef::new_path(p.clone(), &item); + + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); + MIR_ASSERT(*m_mir_res, repr, "No repr for union " << ty); + m_of << "type " << p << " {\n"; + m_of << "\tSIZE " << repr->size << ", ALIGN " << repr->align << ";\n"; + for(const auto& e : repr->fields) + { + m_of << "\t" << e.offset << " = " << e.ty << ";\n"; + } + m_of << "}\n"; + + // TODO: Drop glue! +#if 0 + // Drop glue (calls destructor if there is one) + auto item_ty = ::HIR::TypeRef(p.clone(), &item); + auto drop_glue_path = ::HIR::Path(item_ty.clone(), "#drop_glue"); + auto item_ptr_ty = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Owned, item_ty.clone()); + auto drop_impl_path = (item.m_markings.has_drop_impl ? ::HIR::Path(item_ty.clone(), m_resolve.m_lang_Drop, "drop") : ::HIR::Path(::HIR::SimplePath())); + ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), item_ptr_ty, {}, empty_fcn }; + m_mir_res = &mir_res; + + if( item.m_markings.has_drop_impl ) + { + m_of << "tUNIT " << Trans_Mangle(drop_impl_path) << "(union u_" << Trans_Mangle(p) << "*rv);\n"; + } + + m_of << "static void " << Trans_Mangle(drop_glue_path) << "(union u_" << Trans_Mangle(p) << "* rv) {\n"; + if( item.m_markings.has_drop_impl ) + { + m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n"; + } + m_of << "}\n"; +#endif + } + + void emit_enum(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Enum& item) override + { + ::MIR::Function empty_fcn; + ::MIR::TypeResolve top_mir_res { sp, m_resolve, FMT_CB(ss, ss << "enum " << p;), ::HIR::TypeRef(), {}, empty_fcn }; + m_mir_res = &top_mir_res; + + + TRACE_FUNCTION_F(p); + ::HIR::TypeRef ty = ::HIR::TypeRef::new_path(p.clone(), &item); + + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); + MIR_ASSERT(*m_mir_res, repr, "No repr for enum " << ty); + m_of << "type " << p << " {\n"; + m_of << "\tSIZE " << repr->size << ", ALIGN " << repr->align << ";\n"; + for(const auto& e : repr->fields) + { + m_of << "\t" << e.offset << " = " << e.ty << ";\n"; + } + switch(repr->variants.tag()) + { + case TypeRepr::VariantMode::TAGDEAD: throw ""; + TU_ARM(repr->variants, None, _e) (void)_e; + break; + TU_ARM(repr->variants, Values, e) + for(auto v : e.values) + { + m_of << "\t[" << e.field.index << ", " << e.field.sub_fields << "] = \""; + for(size_t i = 0; i < e.field.size; i ++) + { + int val = (v >> (i*8)) & 0xFF; + //if( val == 0 ) + // m_of << "\\0"; + //else + if(val < 16) + m_of << ::std::hex << "\\x0" << val << ::std::dec; + else + m_of << ::std::hex << "\\x" << val << ::std::dec; + } + m_of << "\";\n"; + } + break; + TU_ARM(repr->variants, NonZero, e) { + m_of << "\t[" << e.field.index << ", " << e.field.sub_fields << "] = \""; + for(size_t i = 0; i < e.field.size; i ++) + { + m_of << "\\0"; + } + m_of << "\";\n"; + } break; + } + m_of << "}\n"; + +#if 0 + // --- + // - 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()); + auto drop_impl_path = (item.m_markings.has_drop_impl ? ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") : ::HIR::Path(::HIR::SimplePath())); + ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, {}, empty_fcn }; + m_mir_res = &mir_res; + + if( item.m_markings.has_drop_impl ) + { + m_of << "tUNIT " << Trans_Mangle(drop_impl_path) << "(struct e_" << Trans_Mangle(p) << "*rv);\n"; + } + + 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( nonzero_path.size() > 0 ) + { + // TODO: Fat pointers? + m_of << "\tif( (*rv)._1"; emit_nonzero_path(nonzero_path); m_of << " ) {\n"; + emit_destructor_call( ::MIR::LValue::make_Field({ box$(self), 1 }), monomorph(item.m_data.as_Data()[1].type), false, 2 ); + m_of << "\t}\n"; + } + else if( const auto* e = item.m_data.opt_Data() ) + { + auto var_lv =::MIR::LValue::make_Downcast({ box$(self), 0 }); + + m_of << "\tswitch(rv->TAG) {\n"; + for(unsigned int var_idx = 0; var_idx < e->size(); var_idx ++) + { + var_lv.as_Downcast().variant_index = var_idx; + m_of << "\tcase " << var_idx << ":\n"; + emit_destructor_call(var_lv, monomorph( (*e)[var_idx].type ), false, 2); + m_of << "\tbreak;\n"; + } + m_of << "\t}\n"; + } + else + { + // Value enum + // Glue does nothing (except call the destructor, if there is one) + } + m_of << "}\n"; + + if( nonzero_path.size() ) + { + m_enum_repr_cache.insert( ::std::make_pair( p.clone(), mv$(nonzero_path) ) ); + } +#endif + m_mir_res = nullptr; + } + void emit_function_code(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params, bool is_extern_def, const ::MIR::FunctionPointer& code) override + { + 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_resolve, ent.second) )); + + ::HIR::TypeRef ret_type_tmp; + const auto& ret_type = monomorphise_fcn_return(ret_type_tmp, item, params); + + ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << p;), ret_type, arg_types, *code }; + m_mir_res = &mir_res; + + m_of << "fn " << p << "("; + m_of << "): " << ret_type << " {\n"; + for(unsigned int i = 0; i < code->locals.size(); i ++) { + DEBUG("var" << i << " : " << code->locals[i]); + m_of << "\tlet var" << i << ": " << code->locals[i] << ";\n"; + } + for(unsigned int i = 0; i < code->drop_flags.size(); i ++) { + m_of << "\tlet df" << i << " = " << code->drop_flags[i] << ";\n"; + } + + + for(unsigned int i = 0; i < code->blocks.size(); i ++) + { + TRACE_FUNCTION_F(p << " bb" << i); + + m_of << "\t" << i << ": {\n"; + + for(const auto& stmt : code->blocks[i].statements) + { + m_of << "\t\t"; + mir_res.set_cur_stmt(i, (&stmt - &code->blocks[i].statements.front())); + DEBUG(stmt); + switch(stmt.tag()) + { + case ::MIR::Statement::TAGDEAD: throw ""; + TU_ARM(stmt, Assign, se) { + m_of << "ASSIGN " << fmt(se.dst) << " = "; + switch(se.src.tag()) + { + case ::MIR::RValue::TAGDEAD: throw ""; + TU_ARM(se.src, Use, e) + m_of << "=" << fmt(e); + break; + TU_ARM(se.src, Constant, e) + m_of << fmt(e); + break; + TU_ARM(se.src, SizedArray, e) + m_of << "[" << fmt(e.val) << "; " << e.count << "]"; + break; + TU_ARM(se.src, Borrow, e) { + m_of << "&"; + switch(e.type) + { + case ::HIR::BorrowType::Shared: break; + case ::HIR::BorrowType::Unique: m_of << "mut "; break; + case ::HIR::BorrowType::Owned: m_of << "move "; break; + } + m_of << fmt(e.val); + } break; + TU_ARM(se.src, Cast, e) + m_of << "CAST " << fmt(e.val) << " as " << e.type; + break; + TU_ARM(se.src, BinOp, e) { + m_of << "BINOP " << fmt(e.val_l) << " "; + switch(e.op) + { + case ::MIR::eBinOp::ADD: m_of << "+"; break; + case ::MIR::eBinOp::ADD_OV: m_of << "+^"; break; + case ::MIR::eBinOp::SUB: m_of << "-"; break; + case ::MIR::eBinOp::SUB_OV: m_of << "-^"; break; + case ::MIR::eBinOp::MUL: m_of << "*"; break; + case ::MIR::eBinOp::MUL_OV: m_of << "*^"; break; + case ::MIR::eBinOp::DIV: m_of << "*"; break; + case ::MIR::eBinOp::DIV_OV: 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::NE: m_of << "!="; break; + case ::MIR::eBinOp::EQ: 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; + } + m_of << " " << fmt(e.val_r); + } break; + TU_ARM(se.src, UniOp, e) { + m_of << "UNIOP "; + switch(e.op) + { + case ::MIR::eUniOp::INV: m_of << "!"; break; + case ::MIR::eUniOp::NEG: m_of << "-"; break; + } + m_of << " " << fmt(e.val); + } break; + TU_ARM(se.src, DstMeta, e) + m_of << "DSTMETA " << fmt(e.val); + break; + TU_ARM(se.src, DstPtr, e) + m_of << "DSTPTR " << fmt(e.val); + break; + TU_ARM(se.src, MakeDst, e) + m_of << "MAKEDST " << fmt(e.ptr_val) << ", " << fmt(e.ptr_val); + break; + TU_ARM(se.src, Variant, e) + m_of << "VARIANT " << e.path << " " << e.index << " " << fmt(e.val); + break; + TU_ARM(se.src, Array, e) { + m_of << "[ "; + for(const auto& v : e.vals) + { + m_of << fmt(v) << ", "; + } + m_of << "]"; + } break; + TU_ARM(se.src, Tuple, e) { + m_of << "( "; + for(const auto& v : e.vals) + { + m_of << fmt(v) << ", "; + } + m_of << ")"; + } break; + TU_ARM(se.src, Struct, e) { + m_of << "{ "; + for(const auto& v : e.vals) + { + m_of << fmt(v) << ", "; + } + m_of << "}: " << e.path; + } break; + } + } break; + TU_ARM(stmt, SetDropFlag, se) { + m_of << "SETFLAG df" << se.idx << " = "; + if( se.other == ~0u ) + { + m_of << se.new_val; + } + else + { + m_of << (se.new_val ? "" : "!") << "df" << se.other; + } + } break; + TU_ARM(stmt, Asm, se) { + m_of << "ASM ("; + for(const auto& v : se.outputs) + { + m_of << "\"" << v.first << "\" : " << fmt(v.second) << ", "; + } + m_of << ") = \"" << se.tpl << "\"("; + for(const auto& v : se.inputs) + { + m_of << "\"" << v.first << "\" : " << fmt(v.second) << ", "; + } + m_of << ") ["; + + for(const auto& v : se.clobbers) + { + m_of << "\"" << v << "\", "; + } + m_of << ":" << se.flags << "]"; + } break; + TU_ARM(stmt, ScopeEnd, se) { (void)se; + continue ; + } break; + TU_ARM(stmt, Drop, se) { + m_of << "DROP " << fmt(se.slot); + switch(se.kind) + { + case ::MIR::eDropKind::DEEP: + break; + case ::MIR::eDropKind::SHALLOW: + m_of << " SHALLOW"; + break; + } + if(se.flag_idx != ~0u) + { + m_of << " IF df" << se.flag_idx; + } + } break; + } + m_of << ";\n"; + } + + mir_res.set_cur_stmt_term(i); + const auto& term = code->blocks[i].terminator; + DEBUG("- " << term); + m_of << "\t\t"; + switch(term.tag()) + { + case ::MIR::Terminator::TAGDEAD: throw ""; + TU_ARM(term, Incomplete, _e) (void)_e; + m_of << "INCOMPLTE\n"; + break; + TU_ARM(term, Return, _e) (void)_e; + m_of << "RETURN\n"; + break; + TU_ARM(term, Diverge, _e) (void)_e; + m_of << "DIVERGE\n"; + break; + TU_ARM(term, Goto, e) + m_of << "GOTO " << e << "\n"; + break; + TU_ARM(term, Panic, e) + m_of << "PANIC " << e.dst << "\n"; + break; + TU_ARM(term, If, e) + m_of << "IF " << fmt(e.cond) << " goto " << e.bb0 << " else " << e.bb1 << "\n"; + break; + TU_ARM(term, Switch, e) { + m_of << "SWITCH " << fmt(e.val) << " { "; + m_of << e.targets; + m_of << " }\n"; + } break; + TU_ARM(term, SwitchValue, e) { + m_of << "SWITCHVALUE " << fmt(e.val) << " { "; + switch(e.values.tag()) + { + case ::MIR::SwitchValues::TAGDEAD: throw ""; + TU_ARM(e.values, String, ve) + for(size_t i = 0; i < ve.size(); i++) + { + m_of << "\"" << FmtEscaped(ve[i]) << "\" = " << e.targets[i] << ","; + } + break; + TU_ARM(e.values, Unsigned, ve) + for(size_t i = 0; i < ve.size(); i++) + { + m_of << ve[i] << " = " << e.targets[i] << ","; + } + break; + TU_ARM(e.values, Signed, ve) + for(size_t i = 0; i < ve.size(); i++) + { + m_of << (ve[i] < 0 ? "" : "+") << ve[i] << " = " << e.targets[i] << ","; + } + break; + } + // TODO: Values. + //if( e.values.size() > 0 ) + //{ + // m_of << ", "; + //} + m_of << "_ = " << e.def_target; + m_of << " }\n"; + } break; + TU_ARM(term, Call, e) { + m_of << "CALL " << fmt(e.ret_val) << " = "; + switch(e.fcn.tag()) + { + case ::MIR::CallTarget::TAGDEAD: throw ""; + TU_ARM(e.fcn, Intrinsic, f) m_of << "\"" << f.name << "\"" << f.params; break; + TU_ARM(e.fcn, Value, f) m_of << "(" << fmt(f) << ")"; break; + TU_ARM(e.fcn, Path, f) m_of << f; break; + } + m_of << "("; + for(const auto& a : e.args) + { + m_of << fmt(a) << ", "; + } + m_of << ") goto " << e.ret_block << " else " << e.panic_block << "\n"; + } break; + } + m_of << "\t}\n"; + } + + m_of << "}\n"; + + + m_mir_res = nullptr; + } + + + private: + const ::HIR::TypeRef& monomorphise_fcn_return(::HIR::TypeRef& tmp, const ::HIR::Function& item, const Trans_Params& params) + { + if( visit_ty_with(item.m_return, [&](const auto& x){ return x.m_data.is_ErasedType() || x.m_data.is_Generic(); }) ) + { + tmp = clone_ty_with(Span(), item.m_return, [&](const auto& tpl, auto& out) { + TU_IFLET( ::HIR::TypeRef::Data, tpl.m_data, ErasedType, e, + out = params.monomorph(m_resolve, item.m_code.m_erased_types.at(e.m_index)); + return true; + ) + else if( tpl.m_data.is_Generic() ) { + out = params.get_cb()(tpl).clone(); + return true; + } + else { + return false; + } + }); + m_resolve.expand_associated_types(Span(), tmp); + return tmp; + } + else + { + return item.m_return; + } + } + }; + Span CodeGenerator_MonoMir::sp; +} + +::std::unique_ptr<CodeGenerator> Trans_Codegen_GetGenerator_MonoMir(const ::HIR::Crate& crate, const ::std::string& outfile) +{ + return ::std::unique_ptr<CodeGenerator>(new CodeGenerator_MonoMir(crate, outfile)); +}
\ No newline at end of file diff --git a/src/trans/main_bindings.hpp b/src/trans/main_bindings.hpp index 9c3bfd45..d78991d2 100644 --- a/src/trans/main_bindings.hpp +++ b/src/trans/main_bindings.hpp @@ -15,6 +15,7 @@ class Crate; struct TransOptions { + ::std::string mode = "c"; unsigned int opt_level = 0; bool emit_debug_info = false; ::std::string build_command_file; diff --git a/src/trans/target.cpp b/src/trans/target.cpp index a48038dd..08cad81a 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -66,6 +66,13 @@ namespace ARCH_ARM32 }; } + else if(target_name == "i586-windows-gnu") + { + return TargetSpec { + "windows", "windows", "gnu", CodegenMode::Gnu11, "mingw32", + ARCH_X86 + }; + } else if(target_name == "x86_64-windows-gnu") { return TargetSpec { @@ -137,6 +144,7 @@ namespace { // Returns NULL when the repr can't be determined ::std::unique_ptr<StructRepr> make_struct_repr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty) { + TRACE_FUNCTION_F(ty); ::std::vector<StructRepr::Ent> ents; bool packed = false; bool allow_sort = false; @@ -160,6 +168,8 @@ namespace { size_t size, align; if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) ) return nullptr; + if( size == SIZE_MAX ) + BUG(sp, "Unsized type in tuple struct"); ents.push_back(StructRepr::Ent { idx++, size, align, mv$(ty) }); } ), @@ -171,6 +181,8 @@ namespace { size_t size, align; if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) ) return nullptr; + if( size == SIZE_MAX ) + BUG(sp, "Unsized type in struct"); ents.push_back(StructRepr::Ent { idx++, size, align, mv$(ty) }); } ) @@ -197,6 +209,8 @@ namespace { size_t size, align; if( !Target_GetSizeAndAlignOf(sp, resolve, t, size,align) ) return nullptr; + if( size == SIZE_MAX ) + BUG(sp, "Unsized type in tuple"); ents.push_back(StructRepr::Ent { idx++, size, align, t.clone() }); } } @@ -262,6 +276,7 @@ const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitResolve& bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align) { + TRACE_FUNCTION_FR(ty, "size=" << out_size << ", align=" << out_align); TU_MATCHA( (ty.m_data), (te), (Infer, BUG(sp, "sizeof on _ type"); @@ -316,82 +331,71 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, out_align = 8; return true; case ::HIR::CoreType::Str: - BUG(sp, "sizeof on a `str` - unsized"); + DEBUG("sizeof on a `str` - unsized"); + out_size = SIZE_MAX; + out_align = 1; + return true; } ), (Path, - TU_MATCHA( (te.binding), (be), - (Unbound, - BUG(sp, "Unbound type path " << ty << " encountered"); - ), - (Opaque, - return false; - ), - (Struct, - if( const auto* repr = Target_GetStructRepr(sp, resolve, ty) ) - { - out_size = 0; - out_align = 1; - for(const auto& e : repr->ents) - { - out_size += e.size; - out_align = ::std::max(out_align, e.align); - } - return true; - } - else - { - return false; - } - ), - (Enum, - // Search for alternate repr - // If not found, determine the variant size - // Get data size and alignment. - return false; - ), - (Union, - // Max alignment and max data size + const auto* repr = Target_GetTypeRepr(sp, resolve, ty); + if( !repr ) + { + DEBUG("Cannot get type repr for " << ty); return false; - ) - ) + } + out_size = repr->size; + out_align = repr->align; + return true; ), (Generic, // Unknown - return false + DEBUG("No repr for Generic - " << ty); return false; ), (TraitObject, - BUG(sp, "sizeof on a trait object - unsized"); + out_align = 0; + out_size = SIZE_MAX; + DEBUG("sizeof on a trait object - unsized"); + return true; ), (ErasedType, BUG(sp, "sizeof on an erased type - shouldn't exist"); ), (Array, - size_t size; - if( !Target_GetSizeAndAlignOf(sp, resolve, *te.inner, size,out_align) ) + if( !Target_GetSizeAndAlignOf(sp, resolve, *te.inner, out_size,out_align) ) return false; - size *= te.size_val; - ), - (Slice, - BUG(sp, "sizeof on a slice - unsized"); - ), - (Tuple, - // Same code as structs :) - if( const auto* repr = Target_GetStructRepr(sp, resolve, ty) ) + if( out_size == SIZE_MAX ) + BUG(sp, "Unsized type in array - " << ty); + if( te.size_val == 0 || out_size == 0 ) { out_size = 0; - out_align = 1; - for(const auto& e : repr->ents) - { - out_size += e.size; - out_align = ::std::max(out_align, e.align); - } - return true; } else { + if( SIZE_MAX / te.size_val <= out_size ) + BUG(sp, "Integer overflow calculating array size"); + out_size *= te.size_val; + } + return true; + ), + (Slice, + if( !Target_GetAlignOf(sp, resolve, *te.inner, out_align) ) + return false; + out_size = SIZE_MAX; + DEBUG("sizeof on a slice - unsized"); + return true; + ), + (Tuple, + const auto* repr = Target_GetTypeRepr(sp, resolve, ty); + if( !repr ) + { + DEBUG("Cannot get type repr for " << ty); return false; } + out_size = repr->size; + out_align = repr->align; + return true; ), (Borrow, // - Alignment is machine native @@ -427,6 +431,7 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, ), (Closure, // TODO. + DEBUG("TODO Closure - " << ty); ) ) return false; @@ -434,10 +439,503 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, bool Target_GetSizeOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size) { size_t ignore_align; - return Target_GetSizeAndAlignOf(sp, resolve, ty, out_size, ignore_align); + bool rv = Target_GetSizeAndAlignOf(sp, resolve, ty, out_size, ignore_align); + if( out_size == SIZE_MAX ) + BUG(sp, "Getting size of Unsized type - " << ty); + return rv; } bool Target_GetAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_align) { size_t ignore_size; - return Target_GetSizeAndAlignOf(sp, resolve, ty, ignore_size, out_align); + bool rv = Target_GetSizeAndAlignOf(sp, resolve, ty, ignore_size, out_align); + if( ignore_size == SIZE_MAX ) + BUG(sp, "Getting alignment of Unsized type - " << ty); + return rv; +} + + +namespace { + // Returns NULL when the repr can't be determined + ::std::unique_ptr<TypeRepr> make_type_repr_struct(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty) + { + TRACE_FUNCTION_F(ty); + struct Ent { + unsigned int field; + size_t size; + size_t align; + }; + ::std::vector<TypeRepr::Field> fields; + ::std::vector<Ent> ents; + bool packed = false; + bool allow_sort = false; + if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Struct() ) + { + const auto& te = ty.m_data.as_Path(); + const auto& str = *te.binding.as_Struct(); + auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &te.path.m_data.as_Generic().m_params, nullptr); + auto monomorph = [&](const auto& tpl) { + auto rv = monomorphise_type_with(sp, tpl, monomorph_cb); + resolve.expand_associated_types(sp, rv); + return rv; + }; + TU_MATCHA( (str.m_data), (se), + (Unit, + ), + (Tuple, + unsigned int idx = 0; + for(const auto& e : se) + { + auto ty = monomorph(e.ent); + size_t size, align; + if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) ) + { + DEBUG("Can't get size/align of " << ty); + return nullptr; + } + ents.push_back(Ent { idx++, size, align }); + fields.push_back(TypeRepr::Field { 0, mv$(ty) }); + } + ), + (Named, + unsigned int idx = 0; + for(const auto& e : se) + { + auto ty = monomorph(e.second.ent); + size_t size, align; + if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) ) + { + DEBUG("Can't get size/align of " << ty); + return nullptr; + } + ents.push_back(Ent { idx++, size, align }); + fields.push_back(TypeRepr::Field { 0, mv$(ty) }); + } + ) + ) + switch(str.m_repr) + { + case ::HIR::Struct::Repr::Packed: + packed = true; + TODO(sp, "make_struct_repr - repr(packed)"); // needs codegen help + break; + case ::HIR::Struct::Repr::C: + // No sorting, no packing + break; + case ::HIR::Struct::Repr::Rust: + allow_sort = true; + break; + } + } + else if( const auto* te = ty.m_data.opt_Tuple() ) + { + DEBUG("Tuple " << ty); + unsigned int idx = 0; + for(const auto& t : *te) + { + size_t size, align; + if( !Target_GetSizeAndAlignOf(sp, resolve, t, size,align) ) + { + DEBUG("Can't get size/align of " << t); + return nullptr; + } + if( size == SIZE_MAX ) + { + TODO(sp, "Unsized type in struct - " << t); + } + ents.push_back(Ent { idx++, size, align }); + fields.push_back(TypeRepr::Field { 0, t.clone() }); + } + } + else + { + BUG(sp, "Unexpected type in creating type repr - " << ty); + } + + + if( allow_sort ) + { + // TODO: Sort by alignment then size (largest first) + // - Requires codegen to use this information + // - NOTE: ?Sized fields (which includes unsized fields) MUST be at the end, even after monomorph + } + + TypeRepr rv; + size_t cur_ofs = 0; + size_t max_align = 1; + for(const auto& e : ents) + { + // Increase offset to fit alignment + if( !packed && e.align > 0 ) + { + while( cur_ofs % e.align != 0 ) + { + cur_ofs ++; + } + } + max_align = ::std::max(max_align, e.align); + + fields[e.field].offset = cur_ofs; + if( e.size == SIZE_MAX ) + { + // TODO: Ensure that this is the last item + ASSERT_BUG(sp, &e == &ents.back(), "Unsized item isn't the last item in " << ty); + cur_ofs = SIZE_MAX; + } + else + { + cur_ofs += e.size; + } + } + if( !packed && cur_ofs != SIZE_MAX ) + { + // Size must be a multiple of alignment + while( cur_ofs % max_align != 0 ) + { + cur_ofs ++; + } + } + rv.align = max_align; + rv.size = cur_ofs; + rv.fields = ::std::move(fields); + DEBUG("size = " << rv.size << ", align = " << rv.align); + return box$(rv); + } + + + bool get_nonzero_path(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, TypeRepr::FieldPath& out_path) + { + switch(ty.m_data.tag()) + { + TU_ARM(ty.m_data, Path, te) { + if( te.binding.is_Struct() ) + { + const TypeRepr* r = Target_GetTypeRepr(sp, resolve, ty); + if( !r ) + { + return false; + } + for(size_t i = 0; i < r->fields.size(); i ++) + { + if( get_nonzero_path(sp, resolve, r->fields[i].ty, out_path) ) + { + out_path.sub_fields.push_back(i); + return true; + } + } + } + } break; + TU_ARM(ty.m_data, Borrow, _te) { (void)_te; + //out_path.sub_fields.push_back(0); + Target_GetSizeOf(sp, resolve, ty, out_path.size); + return true; + } break; + TU_ARM(ty.m_data, Function, _te) (void)_te; + //out_path.sub_fields.push_back(0); + Target_GetSizeOf(sp, resolve, ty, out_path.size); + return true; + default: + break; + } + return false; + } + ::std::unique_ptr<TypeRepr> make_type_repr_enum(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty) + { + const auto& te = ty.m_data.as_Path(); + const auto& enm = *te.binding.as_Enum(); + + auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &te.path.m_data.as_Generic().m_params, nullptr); + auto monomorph = [&](const auto& tpl) { + auto rv = monomorphise_type_with(sp, tpl, monomorph_cb); + resolve.expand_associated_types(sp, rv); + return rv; + }; + + TypeRepr rv; + switch(enm.m_data.tag()) + { + case ::HIR::Enum::Class::TAGDEAD: throw ""; + TU_ARM(enm.m_data, Data, e) { + ::std::vector<::HIR::TypeRef> mono_types; + for(const auto& var : e) + { + mono_types.push_back( monomorph(var.type) ); + } + TypeRepr::FieldPath nz_path; + if( e.size() == 2 && mono_types[0] == ::HIR::TypeRef::new_unit() && get_nonzero_path(sp, resolve, mono_types[1], nz_path) ) + { + nz_path.index = 1; + ::std::reverse(nz_path.sub_fields.begin(), nz_path.sub_fields.end()); + size_t max_size = 0; + size_t max_align = 0; + for(auto& t : mono_types) + { + size_t size, align; + if( !Target_GetSizeAndAlignOf(sp, resolve, t, size, align) ) + { + DEBUG("Generic type in enum - " << t); + return nullptr; + } + if( size == SIZE_MAX ) { + BUG(sp, "Unsized type in enum - " << t); + } + max_size = ::std::max(max_size , size); + max_align = ::std::max(max_align, align); + rv.fields.push_back(TypeRepr::Field { 0, mv$(t) }); + } + + rv.size = max_size; + rv.align = max_align; + rv.variants = TypeRepr::VariantMode::make_NonZero({ nz_path, 0 }); + } + else + { + size_t max_size = 0; + size_t max_align = 0; + for(auto& t : mono_types) + { + size_t size, align; + if( !Target_GetSizeAndAlignOf(sp, resolve, t, size, align) ) + { + DEBUG("Generic type in enum - " << t); + return nullptr; + } + if( size == SIZE_MAX ) { + BUG(sp, "Unsized type in enum - " << t); + } + max_size = ::std::max(max_size , size); + max_align = ::std::max(max_align, align); + rv.fields.push_back(TypeRepr::Field { 0, mv$(t) }); + } + DEBUG("max_size = " << max_size << ", max_align = " << max_align); + // HACK: This is required for the C backend, because the union that contains the enum variants is + // padded out to align. + if(max_size > 0) + { + while(max_size % max_align) + max_size ++; + } + size_t tag_size = 0; + // TODO: repr(C) enums + if( mono_types.size() == 0 ) { + // Unreachable + } + else if( mono_types.size() == 1 ) { + // No need for a tag + } + else if( mono_types.size() <= 255 ) { + rv.fields.push_back(TypeRepr::Field { max_size, ::HIR::CoreType::U8 }); + tag_size = 1; + DEBUG("u8 data tag"); + } + else { + ASSERT_BUG(sp, mono_types.size() <= 0xFFFF, ""); + while(max_size % 2) max_size ++; + rv.fields.push_back(TypeRepr::Field { max_size, ::HIR::CoreType::U16 }); + tag_size = 2; + DEBUG("u16 data tag"); + } + max_align = ::std::max(max_align, tag_size); + ::std::vector<uint64_t> vals; + for(size_t i = 0; i < e.size(); i++) + { + vals.push_back(i); + } + if( vals.size() > 1 ) + { + rv.variants = TypeRepr::VariantMode::make_Values({ { mono_types.size(), tag_size, {} }, ::std::move(vals) }); + } + else + { + // Leave the enum with NoVariants + } + if( max_align > 0 ) + { + // Size must be a multiple of alignment + rv.size = (max_size + tag_size); + while(rv.size % max_align) + rv.size ++; + rv.align = max_align; + } + else + { + ASSERT_BUG(sp, max_size == 0, "Zero alignment, but non-zero size"); + } + + // TODO: Variants. + } + } break; + TU_ARM(enm.m_data, Value, e) { + switch(e.repr) + { + case ::HIR::Enum::Repr::C: + // No auto-sizing, just i32? + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U32 }); + break; + case ::HIR::Enum::Repr::Rust: { + int pow8 = 0; + for( const auto& v : e.variants ) + { + auto v2 = static_cast<int64_t>(v.val); + if( -0x80 <= v2 && v2 < 0x80 ) + { + pow8 = ::std::max(pow8, 1); + } + else if( -0x8000 <= v2 && v2 < 0x8000 ) + { + pow8 = ::std::max(pow8, 2); + } + else if( -0x80000000 <= v2 && v2 < 0x80000000 ) + { + pow8 = ::std::max(pow8, 3); + } + else + { + pow8 = 4; + } + } + switch(pow8) + { + case 0: break; + case 1: + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I8 }); + break; + case 2: + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I16 }); + break; + case 3: + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I32 }); + break; + case 4: + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::I64 }); + break; + default: + break; + } + } break; + case ::HIR::Enum::Repr::U8: + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U8 }); + break; + case ::HIR::Enum::Repr::U16: + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U16 }); + break; + case ::HIR::Enum::Repr::U32: + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U32 }); + break; + case ::HIR::Enum::Repr::U64: + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U64 }); + break; + case ::HIR::Enum::Repr::Usize: + if( g_target.m_arch.m_pointer_bits == 16 ) + { + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U16 }); + } + else if( g_target.m_arch.m_pointer_bits == 32 ) + { + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U32 }); + } + else if( g_target.m_arch.m_pointer_bits == 64 ) + { + rv.fields.push_back(TypeRepr::Field { 0, ::HIR::CoreType::U64 }); + } + break; + } + if( rv.fields.size() > 0 ) + { + // Can't return false or unsized + Target_GetSizeAndAlignOf(sp, resolve, rv.fields.back().ty, rv.size, rv.align); + + ::std::vector<uint64_t> vals; + for(const auto& v : e.variants) + { + vals.push_back(v.val); + } + rv.variants = TypeRepr::VariantMode::make_Values({ { 0, static_cast<uint8_t>(rv.size), {} }, ::std::move(vals) }); + } + } break; + } + DEBUG("rv.variants = " << rv.variants.tag_str()); + return box$(rv); + } + ::std::unique_ptr<TypeRepr> make_type_repr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty) + { + TRACE_FUNCTION_F(ty); + if( TU_TEST1(ty.m_data, Path, .binding.is_Struct()) || ty.m_data.is_Tuple() ) + { + return make_type_repr_struct(sp, resolve, ty); + } + else if( TU_TEST1(ty.m_data, Path, .binding.is_Union()) ) + { + const auto& te = ty.m_data.as_Path(); + const auto& unn = *te.binding.as_Union(); + + auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &te.path.m_data.as_Generic().m_params, nullptr); + auto monomorph = [&](const auto& tpl) { + auto rv = monomorphise_type_with(sp, tpl, monomorph_cb); + resolve.expand_associated_types(sp, rv); + return rv; + }; + + TypeRepr rv; + for(const auto& var : unn.m_variants) + { + rv.fields.push_back({ 0, monomorph(var.second.ent) }); + size_t size, align; + if( !Target_GetSizeAndAlignOf(sp, resolve, rv.fields.back().ty, size, align) ) + { + // Generic? - Not good. + DEBUG("Generic type encounterd after monomorphise in union - " << rv.fields.back().ty); + return nullptr; + } + if( size == SIZE_MAX ) { + BUG(sp, "Unsized type in union"); + } + rv.size = ::std::max(rv.size , size ); + rv.align = ::std::max(rv.align, align); + } + return box$(rv); + } + else if( TU_TEST1(ty.m_data, Path, .binding.is_Enum()) ) + { + return make_type_repr_enum(sp, resolve, ty); + } + else if( ty.m_data.is_Primitive() ) + { + return nullptr; + } + else if( ty.m_data.is_Borrow() || ty.m_data.is_Pointer() ) + { + return nullptr; + } + else + { + TODO(sp, "Type repr for " << ty); + return nullptr; + } + } +} +const TypeRepr* Target_GetTypeRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty) +{ + // TODO: Thread safety + // Map of generic types to type representations. + static ::std::map<::HIR::TypeRef, ::std::unique_ptr<TypeRepr>> s_cache; + + auto it = s_cache.find(ty); + if( it != s_cache.end() ) + { + return it->second.get(); + } + + auto ires = s_cache.insert(::std::make_pair( ty.clone(), make_type_repr(sp, resolve, ty) )); + return ires.first->second.get(); +} +const ::HIR::TypeRef& Target_GetInnerType(const Span& sp, const StaticTraitResolve& resolve, const TypeRepr& repr, size_t idx, const ::std::vector<size_t>& sub_fields, size_t ofs) +{ + const auto& ty = repr.fields.at(idx).ty; + if( sub_fields.size() == ofs ) + { + return ty; + } + const auto* inner_repr = Target_GetTypeRepr(sp, resolve, ty); + ASSERT_BUG(sp, inner_repr, "No inner repr for " << ty); + return Target_GetInnerType(sp, resolve, *inner_repr, sub_fields[ofs], sub_fields, ofs+1); } diff --git a/src/trans/target.hpp b/src/trans/target.hpp index e82d25ff..81205831 100644 --- a/src/trans/target.hpp +++ b/src/trans/target.hpp @@ -54,10 +54,54 @@ struct StructRepr // Ordered as they would be emitted ::std::vector<Ent> ents; }; +struct TypeRepr +{ + size_t align = 0; + size_t size = 0; + + struct FieldPath { + size_t index; + size_t size; + ::std::vector<size_t> sub_fields; + }; + TAGGED_UNION(VariantMode, None, + (None, struct { + }), + // Tag is a fixed set of values in an offset. + (Values, struct { + FieldPath field; + ::std::vector<uint64_t> values; + }), + // Tag is based on a range of values + //(Ranges, struct { + // size_t offset; + // size_t size; + // ::std::vector<::std::pair<uint64_t,uint64_t>> values; + // }), + // Tag is a boolean based on if a region is zero/non-zero + // Only valid for two-element enums + (NonZero, struct { + FieldPath field; + uint8_t zero_variant; + }) + ); + VariantMode variants; + + struct Field { + size_t offset; + ::HIR::TypeRef ty; + }; + ::std::vector<Field> fields; +}; extern const TargetSpec& Target_GetCurSpec(); extern void Target_SetCfg(const ::std::string& target_name); extern bool Target_GetSizeOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size); extern bool Target_GetAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_align); +extern bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align); extern const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& struct_ty); +extern const TypeRepr* Target_GetTypeRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty); + +extern const ::HIR::TypeRef& Target_GetInnerType(const Span& sp, const StaticTraitResolve& resolve, const TypeRepr& repr, size_t idx, const ::std::vector<size_t>& sub_fields={}, size_t ofs=0); + diff --git a/tools/minicargo/Makefile b/tools/minicargo/Makefile index 336b2410..71e266b0 100644 --- a/tools/minicargo/Makefile +++ b/tools/minicargo/Makefile @@ -3,12 +3,16 @@ # - Interprets Cargo.toml files and emits makefiles # - Supports overriding build script output # +ifeq ($(OS),Windows_NT) + EXESUF ?= .exe +endif +EXESUF ?= V ?= @ OBJDIR := .obj/ -BIN := ../bin/minicargo +BIN := ../bin/minicargo$(EXESUF) OBJS := main.o build.o manifest.o repository.o OBJS += toml.o path.o debug.o diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 0006623c..d7a8143e 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -5,9 +5,18 @@ * build.cpp * - Logic related to invoking the compiler */ -#ifdef _WIN32 +#ifdef _MSC_VER # define _CRT_SECURE_NO_WARNINGS // Allows use of getenv (this program doesn't set env vars) #endif + +#if defined(__MINGW32__) +# define DISABLE_MULTITHREAD // Mingw32 doesn't have c++11 threads +// Mingw doesn't define putenv() +extern "C" { +extern int _putenv_s(const char*, const char*); +} +#endif + #include "manifest.h" #include "build.h" #include "debug.h" @@ -16,9 +25,11 @@ #include <algorithm> #include <sstream> // stringstream #include <cstdlib> // setenv -#include <thread> -#include <mutex> -#include <condition_variable> +#ifndef DISABLE_MULTITHREAD +# include <thread> +# include <mutex> +# include <condition_variable> +#endif #include <climits> #include <cassert> #ifdef _WIN32 @@ -34,7 +45,12 @@ #ifdef _WIN32 # define EXESUF ".exe" -# define HOST_TARGET "x86_64-windows-msvc" +# ifdef _MSC_VER +# define HOST_TARGET "x86_64-windows-msvc" +# elif defined(__MINGW32__) +# define HOST_TARGET "x86_64-windows-gnu" +# else +# endif #else # define EXESUF "" # define HOST_TARGET "x86_64-unknown-linux-gnu" @@ -314,6 +330,7 @@ bool BuildList::build(BuildOptions opts, unsigned num_jobs) // Actually do the build if( num_jobs > 1 ) { +#ifndef DISABLE_MULTITHREAD class Semaphore { ::std::mutex mutex; @@ -446,7 +463,18 @@ bool BuildList::build(BuildOptions opts, unsigned num_jobs) { return false; } +#else + while( !state.build_queue.empty() ) + { + auto cur = state.get_next(); + if( ! builder.build_library(*m_list[cur].package, m_list[cur].is_host) ) + { + return false; + } + state.complete_package(cur, m_list); + } +#endif } else if( num_jobs == 1 ) { @@ -514,7 +542,11 @@ Builder::Builder(BuildOptions opts): ::helpers::path minicargo_path { buf }; minicargo_path.pop_component(); +#ifdef __MINGW32__ + m_compiler_path = (minicargo_path / "..\\..\\bin\\mrustc.exe").normalise(); +#else m_compiler_path = minicargo_path / "mrustc.exe"; +#endif #else char buf[1024]; size_t s = readlink("/proc/self/exe", buf, sizeof(buf)-1); @@ -623,6 +655,11 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& args.push_back("-C"); args.push_back(format("emit-build-command=",outfile,".sh")); } } + if( m_opts.emit_mmir ) + { + args.push_back("-C"); args.push_back("codegen-type=monomir"); + } + args.push_back("-o"); args.push_back(outfile); args.push_back("-L"); args.push_back(this->get_output_dir(is_for_host).str()); for(const auto& dir : manifest.build_script_output().rustc_link_search) { diff --git a/tools/minicargo/build.h b/tools/minicargo/build.h index 16d0bea0..0b3e949b 100644 --- a/tools/minicargo/build.h +++ b/tools/minicargo/build.h @@ -12,6 +12,7 @@ struct BuildOptions ::helpers::path output_dir; ::helpers::path build_script_overrides; ::std::vector<::helpers::path> lib_search_dirs; + bool emit_mmir = false; const char* target_name = nullptr; // if null, host is used }; diff --git a/tools/minicargo/debug.cpp b/tools/minicargo/debug.cpp index f6fca62e..a3fb9956 100644 --- a/tools/minicargo/debug.cpp +++ b/tools/minicargo/debug.cpp @@ -5,6 +5,9 @@ * debug.cpp * - Debugging helpers */ +#if defined(__MINGW32__) +# define DISABLE_MULTITHREAD // Mingw32 doesn't have c++11 threads +#endif #include <set> #include <iostream> #include "debug.h" @@ -13,7 +16,9 @@ static int giIndentLevel = 0; static const char* gsDebugPhase = ""; static ::std::set<::std::string> gmDisabledDebug; +#ifndef DISABLE_MULTITHREAD static ::std::mutex gDebugLock; +#endif void Debug_SetPhase(const char* phase_name) { @@ -33,7 +38,9 @@ void Debug_Print(::std::function<void(::std::ostream& os)> cb) { if( !Debug_IsEnabled() ) return ; +#ifndef DISABLE_MULTITHREAD ::std::unique_lock<::std::mutex> _lh { gDebugLock }; +#endif ::std::cout << gsDebugPhase << "- "; for(auto i = giIndentLevel; i --; ) @@ -45,7 +52,9 @@ void Debug_EnterScope(const char* name, dbg_cb_t cb) { if( !Debug_IsEnabled() ) return ; +#ifndef DISABLE_MULTITHREAD ::std::unique_lock<::std::mutex> _lh { gDebugLock }; +#endif ::std::cout << gsDebugPhase << "- "; for(auto i = giIndentLevel; i --; ) @@ -59,7 +68,9 @@ void Debug_LeaveScope(const char* name, dbg_cb_t cb) { if( !Debug_IsEnabled() ) return ; +#ifndef DISABLE_MULTITHREAD ::std::unique_lock<::std::mutex> _lh { gDebugLock }; +#endif ::std::cout << gsDebugPhase << "- "; giIndentLevel --; diff --git a/tools/minicargo/main.cpp b/tools/minicargo/main.cpp index 008ae0aa..50e08619 100644 --- a/tools/minicargo/main.cpp +++ b/tools/minicargo/main.cpp @@ -27,6 +27,9 @@ struct ProgramOptions // Output/build directory const char* output_directory = nullptr; + // Emit Monomorphised MIR instead of C + bool emit_mmir = false; + // Target name (if null, defaults to host) const char* target = nullptr; @@ -84,6 +87,7 @@ int main(int argc, const char* argv[]) build_opts.build_script_overrides = ::std::move(bs_override_dir); build_opts.output_dir = opts.output_directory ? ::helpers::path(opts.output_directory) : ::helpers::path("output"); build_opts.lib_search_dirs.reserve(opts.lib_search_dirs.size()); + build_opts.emit_mmir = opts.emit_mmir; build_opts.target_name = opts.target; for(const auto* d : opts.lib_search_dirs) build_opts.lib_search_dirs.push_back( ::helpers::path(d) ); @@ -158,6 +162,25 @@ int ProgramOptions::parse(int argc, const char* argv[]) } this->build_jobs = ::std::strtol(argv[++i], nullptr, 10); break; + case 'Z': + if( arg[2] != '\0' ) { + arg = arg + 2; + } + else { + if(i+1 == argc) { + ::std::cerr << "Flag " << arg << " takes an argument" << ::std::endl; + return 1; + } + arg = argv[++i]; + } + if( ::std::strcmp(arg, "emit-mmir") == 0 ) { + this->emit_mmir = true; + } + else { + ::std::cerr << "Unknown debug option -Z " << arg << ::std::endl; + return 1; + } + break; case 'n': this->build_jobs = 0; break; diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index 090e0f6b..0010e202 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -12,6 +12,7 @@ size_t HIR::TypeRef::get_size(size_t ofs) const { + const size_t POINTER_SIZE = 8; if( this->wrappers.size() <= ofs ) { switch(this->inner_type) @@ -33,7 +34,12 @@ size_t HIR::TypeRef::get_size(size_t ofs) const return 8; case RawType::U128: case RawType::I128: return 16; + + case RawType::Function: // This should probably be invalid? + case RawType::USize: case RawType::ISize: + return POINTER_SIZE; } + throw ""; } switch(this->wrappers[ofs].type) @@ -48,21 +54,21 @@ size_t HIR::TypeRef::get_size(size_t ofs) const if( this->inner_type == RawType::Composite ) throw "TODO"; else if( this->inner_type == RawType::Str ) - return 8*2; + return POINTER_SIZE*2; else if( this->inner_type == RawType::TraitObject ) - return 8*2; + return POINTER_SIZE*2; else { - return 8; + return POINTER_SIZE; } } else if( this->wrappers[ofs+1].type == TypeWrapper::Ty::Slice ) { - return 8*2; + return POINTER_SIZE*2; } else { - return 8; + return POINTER_SIZE; } case TypeWrapper::Ty::Slice: throw "Invalid"; diff --git a/tools/standalone_miri/lex.cpp b/tools/standalone_miri/lex.cpp index a602128a..48a9e0cd 100644 --- a/tools/standalone_miri/lex.cpp +++ b/tools/standalone_miri/lex.cpp @@ -53,6 +53,9 @@ double Token::real() const case TokenClass::String: os << "\"" << x.strval << "\""; break; + case TokenClass::ByteString: + os << "b\"" << x.strval << "\""; + break; } return os; } @@ -75,6 +78,18 @@ const Token& Lexer::next() const { return m_cur; } +const Token& Lexer::lookahead() +{ + if( !m_next_valid ) + { + auto tmp = ::std::move(m_cur); + advance(); + m_next = ::std::move(m_cur); + m_cur = ::std::move(tmp); + m_next_valid = true; + } + return m_next; +} Token Lexer::consume() { auto rv = ::std::move(m_cur); @@ -107,6 +122,13 @@ void Lexer::check(const char* s) void Lexer::advance() { + if( m_next_valid ) + { + m_cur = ::std::move(m_next); + m_next_valid = false; + return ; + } + char ch; do { @@ -177,6 +199,20 @@ void Lexer::advance() ch = '#'; } + if(ch == 'b') + { + ch = m_if.get(); + if( ch == '"' ) { + auto val = this->parse_string(); + m_cur = Token { TokenClass::ByteString, ::std::move(val) }; + return ; + } + else { + m_if.unget(); + } + ch = 'b'; + } + if( m_if.eof() ) { m_cur = Token { TokenClass::Eof, "" }; @@ -203,7 +239,7 @@ void Lexer::advance() throw "ERROR"; uint64_t rv = 0; - while(::std::isdigit(ch)) + while(::std::isxdigit(ch)) { rv *= 16; if( ch <= '9' ) @@ -218,9 +254,65 @@ void Lexer::advance() } if( ch == '.' || ch == 'p' ) { + uint64_t frac = 0; + if( ch == '.' ) + { + ch = m_if.get(); + int pos = 0; + while(::std::isxdigit(ch)) + { + frac *= 16; + if( ch <= '9' ) + frac += ch - '0'; + else if( ch <= 'F' ) + frac += ch - 'A' + 10; + else if( ch <= 'f' ) + frac += ch - 'a' + 10; + else + throw ""; + pos ++; + ch = m_if.get(); + } + while(pos < 52/4) + { + frac *= 16; + pos ++; + } + } + int exp = 0; + if( ch == 'p' ) + { + ch = m_if.get(); + bool neg = false; + if( ch == '-' ) { + neg = true; + ch = m_if.get(); + } + if( !::std::isdigit(ch) ) + throw "ERROR"; + while(::std::isdigit(ch)) + { + exp *= 10; + exp += ch - '0'; + ch = m_if.get(); + } + if(neg) + exp = -exp; + } // Floats! - ::std::cerr << *this << "TODO - Hex floats" << ::std::endl; - throw "TODO"; + //::std::cerr << *this << "TODO - Hex floats - " << rv << "." << frac << "p" << exp << ::std::endl; + if( rv != 1 ) { + ::std::cerr << *this << "Invalid hex float literal, whole component must be 1" << ::std::endl; + throw "ERROR"; + } + if( frac >= (1ull << 52) ) { + ::std::cerr << *this << "Invalid hex float literal, fractional component is more than 52 bits" << ::std::endl; + throw "ERROR"; + } + uint64_t vi = (static_cast<uint64_t>(exp) << 52) | frac; + m_cur = Token { TokenClass::Real, "" }; + m_cur.numbers.real_val = *reinterpret_cast<const double*>(&vi); + return ; } m_if.unget(); @@ -254,31 +346,7 @@ void Lexer::advance() } else if( ch == '"' ) { - ::std::string val; - while( (ch = m_if.get()) != '"' ) - { - if( ch == '\\' ) - { - switch( (ch = m_if.get()) ) - { - case '0': val.push_back(0); break; - case 'n': val.push_back(10); break; - case 'x': { - char tmp[3] = { static_cast<char>(m_if.get()), static_cast<char>(m_if.get()), 0}; - val.push_back( static_cast<char>(::std::strtol(tmp, nullptr, 16)) ); - break; } - case '"': val.push_back('"'); break; - case '\\': val.push_back('\\'); break; - default: - ::std::cerr << *this << "Unexpected escape sequence '\\" << ch << "'" << ::std::endl; - throw "ERROR"; - } - } - else - { - val.push_back(ch); - } - } + auto val = this->parse_string(); m_cur = Token { TokenClass::String, ::std::move(val) }; } else @@ -304,6 +372,7 @@ void Lexer::advance() case '&': m_cur = Token { TokenClass::Symbol, "&" }; break; case '*': m_cur = Token { TokenClass::Symbol, "*" }; break; case '/': m_cur = Token { TokenClass::Symbol, "/" }; break; + case '%': m_cur = Token { TokenClass::Symbol, "%" }; break; case '-': m_cur = Token { TokenClass::Symbol, "-" }; break; case '+': m_cur = Token { TokenClass::Symbol, "+" }; break; case '^': m_cur = Token { TokenClass::Symbol, "^" }; break; @@ -314,7 +383,19 @@ void Lexer::advance() case '(': m_cur = Token { TokenClass::Symbol, "(" }; break; case ')': m_cur = Token { TokenClass::Symbol, ")" }; break; - case '<': m_cur = Token { TokenClass::Symbol, "<" }; break; + case '<': + // Combine << (note, doesn't need to happen for >>) + ch = m_if.get(); + if( ch == '<' ) + { + m_cur = Token { TokenClass::Symbol, "<<" }; + } + else + { + m_if.unget(); + m_cur = Token { TokenClass::Symbol, "<" }; + } + break; case '>': m_cur = Token { TokenClass::Symbol, ">" }; break; case '[': m_cur = Token { TokenClass::Symbol, "[" }; break; case ']': m_cur = Token { TokenClass::Symbol, "]" }; break; @@ -326,6 +407,83 @@ void Lexer::advance() } } } +::std::string Lexer::parse_string() +{ + ::std::string val; + char ch; + while( (ch = m_if.get()) != '"' ) + { + if( ch == '\\' ) + { + switch( (ch = m_if.get()) ) + { + case '0': val.push_back(0); break; + case 'n': val.push_back(10); break; + case 'x': { + char tmp[3] = { static_cast<char>(m_if.get()), static_cast<char>(m_if.get()), 0}; + val.push_back( static_cast<char>(::std::strtol(tmp, nullptr, 16)) ); + } break; + case 'u': { + ch = m_if.get(); + if( ch != '{' ) { + ::std::cerr << *this << "Unexpected character in unicode escape - '" << ch << "'" << ::std::endl; + throw "ERROR"; + } + ch = m_if.get(); + uint32_t v = 0; + do { + if( !isxdigit(ch) ) { + ::std::cerr << *this << "Unexpected character in unicode escape - '" << ch << "'" << ::std::endl; + throw "ERROR"; + } + v *= 16; + if( ch <= '9' ) + v += ch - '0'; + else if( ch <= 'F' ) + v += ch - 'A' + 10; + else if( ch <= 'f' ) + v += ch - 'a' + 10; + else + throw ""; + ch = m_if.get(); + } while(ch != '}'); + + if( v < 0x80 ) { + val.push_back(static_cast<char>(v)); + } + else if( v < (0x1F+1)<<(1*6) ) { + val += (char)(0xC0 | ((v >> 6) & 0x1F)); + val += (char)(0x80 | ((v >> 0) & 0x3F)); + } + else if( v < (0x0F+1)<<(2*6) ) { + val += (char)(0xE0 | ((v >> 12) & 0x0F)); + val += (char)(0x80 | ((v >> 6) & 0x3F)); + val += (char)(0x80 | ((v >> 0) & 0x3F)); + } + else if( v < (0x07+1)<<(3*6) ) { + val += (char)(0xF0 | ((v >> 18) & 0x07)); + val += (char)(0x80 | ((v >> 12) & 0x3F)); + val += (char)(0x80 | ((v >> 6) & 0x3F)); + val += (char)(0x80 | ((v >> 0) & 0x3F)); + } + else { + throw ""; + } + } break; + case '"': val.push_back('"'); break; + case '\\': val.push_back('\\'); break; + default: + ::std::cerr << *this << "Unexpected escape sequence '\\" << ch << "'" << ::std::endl; + throw "ERROR"; + } + } + else + { + val.push_back(ch); + } + } + return val; +} ::std::ostream& operator<<(::std::ostream& os, const Lexer& x) { diff --git a/tools/standalone_miri/lex.hpp b/tools/standalone_miri/lex.hpp index 8c785a5f..95130111 100644 --- a/tools/standalone_miri/lex.hpp +++ b/tools/standalone_miri/lex.hpp @@ -13,6 +13,7 @@ enum class TokenClass Integer, Real, String, + ByteString, }; struct Token @@ -43,16 +44,21 @@ class Lexer unsigned m_cur_line; ::std::ifstream m_if; Token m_cur; + bool m_next_valid = false; + Token m_next; public: Lexer(const ::std::string& path); + const Token& next() const; + const Token& lookahead(); Token consume(); void check(TokenClass tc); void check(char ch); void check(const char* s); - void check_consume(char ch) { check(ch); consume(); } - void check_consume(const char* s) { check(s); consume(); } + Token check_consume(TokenClass tc) { check(tc); return consume(); } + Token check_consume(char ch) { check(ch); return consume(); } + Token check_consume(const char* s) { check(s); return consume(); } bool consume_if(char ch) { if(next() == ch) { consume(); return true; } return false; } bool consume_if(const char* s) { if(next() == s) { consume(); return true; } return false; } @@ -60,4 +66,6 @@ public: private: void advance(); + + ::std::string parse_string(); }; diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 34d0376b..f056481b 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -33,6 +33,12 @@ struct Parser void ModuleTree::load_file(const ::std::string& path) { + if( !loaded_files.insert(path).second ) + { + ::std::cout << "DEBUG: load_file(" << path << ") - Already loaded" << ::std::endl; + return ; + } + ::std::cout << "DEBUG: load_file(" << path << ")" << ::std::endl; //TRACE_FUNCTION_F(path); auto parse = Parser { *this, path }; @@ -74,9 +80,10 @@ bool Parser::parse_one() while(lex.next() != ')') { arg_tys.push_back( parse_type() ); - lex.check_consume(','); + if( !lex.consume_if(',') ) + break; } - lex.consume(); + lex.check_consume(')'); ::HIR::TypeRef rv_ty; if( lex.consume_if(':') ) { @@ -109,11 +116,6 @@ bool Parser::parse_one() lex.check_consume(','); lex.check_consume("ALIGN"); rv.alignment = lex.consume().integer(); - if( rv.alignment == 0 ) - { - ::std::cerr << lex << "Alignment of zero is invalid, " << p << ::std::endl; - throw "ERROR"; - } lex.check_consume(';'); // TODO: DST Meta @@ -145,10 +147,15 @@ bool Parser::parse_one() lex.consume(); size_t base_idx = lex.consume().integer(); ::std::vector<size_t> other_idx; - while(lex.next() == ',') + if( lex.consume_if(',') ) { - lex.consume(); - other_idx.push_back( lex.consume().integer() ); + while(lex.next() != ']') + { + lex.check(TokenClass::Integer); + other_idx.push_back( lex.consume().integer() ); + if( !lex.consume_if(',') ) + break; + } } lex.check_consume(']'); lex.check_consume('='); @@ -170,6 +177,12 @@ bool Parser::parse_one() } lex.check_consume('}'); + if( rv.alignment == 0 && rv.fields.size() != 0 ) + { + ::std::cerr << lex << "Alignment of zero with fields is invalid, " << p << ::std::endl; + throw "ERROR"; + } + auto it = this->tree.data_types.find(p); if( it != this->tree.data_types.end() ) { @@ -179,7 +192,8 @@ bool Parser::parse_one() } else { - ::std::cerr << lex << "Duplicate definition of " << p << ::std::endl; + //::std::cerr << lex << "Duplicate definition of " << p << ::std::endl; + // Not really an error, can happen when loading crates //throw "ERROR"; } @@ -302,11 +316,37 @@ bool Parser::parse_one() auto cty = p.parse_core_type(); return ::MIR::Constant::make_Uint({ static_cast<uint64_t>(v), cty }); } + else if( p.lex.next() == TokenClass::String ) { + auto v = ::std::move( p.lex.consume().strval ); + return ::MIR::Constant::make_StaticString(::std::move(v)); + } + else if( p.lex.next() == TokenClass::ByteString ) { + ::std::vector<uint8_t> v; + for(char c : p.lex.consume().strval ) + { + v.push_back( static_cast<uint8_t>(c) ); + } + return ::MIR::Constant::make_Bytes(::std::move(v)); + } else if( p.lex.next() == '+' || p.lex.next() == '-' ) { bool is_neg = (p.lex.consume() == '-'); - auto v = static_cast<int64_t>(p.lex.consume().integer()); - auto cty = p.parse_core_type(); - return ::MIR::Constant::make_Int({ is_neg ? -v : v, cty }); + if( p.lex.next() == TokenClass::Integer ) + { + auto v = static_cast<int64_t>(p.lex.consume().integer()); + auto cty = p.parse_core_type(); + return ::MIR::Constant::make_Int({ is_neg ? -v : v, cty }); + } + else if( p.lex.next() == TokenClass::Real ) + { + auto v = p.lex.consume().real(); + auto cty = p.parse_core_type(); + return ::MIR::Constant::make_Float({ is_neg ? -v : v, cty }); + } + else + { + ::std::cerr << p.lex << "Expected an integer or float, got " << p.lex.next() << ::std::endl; + throw "ERROR"; + } } else if( p.lex.consume_if("true") ) { return ::MIR::Constant::make_Bool({ true }); @@ -328,10 +368,15 @@ bool Parser::parse_one() // Parse a "Param" (constant or lvalue) static ::MIR::Param parse_param(Parser& p, ::std::vector<::std::string>& var_names) { - if( p.lex.next() == TokenClass::Integer || p.lex.next() == '+' || p.lex.next() == '-' || p.lex.next() == '&' || p.lex.next() == "true" || p.lex.next() == "false" ) { + if( p.lex.next() == TokenClass::Integer || p.lex.next() == TokenClass::String || p.lex.next() == TokenClass::ByteString + || p.lex.next() == '+' || p.lex.next() == '-' || p.lex.next() == '&' + || p.lex.next() == "true" || p.lex.next() == "false" + ) + { return parse_const(p); } - else { + else + { return parse_lvalue(p, var_names); } } @@ -384,7 +429,11 @@ bool Parser::parse_one() lex.check_consume('='); ::MIR::RValue src_rval; // Literals - if( lex.next() == TokenClass::Integer || lex.next() == '+' || lex.next() == '-' || lex.next() == "true" || lex.next() == "false" ) { + if( lex.next() == TokenClass::Integer || lex.next() == TokenClass::String || lex.next() == TokenClass::ByteString + || lex.next() == '+' || lex.next() == '-' + || lex.next() == "true" || lex.next() == "false" + ) + { src_rval = H::parse_const(*this); } // LValue (prefixed by =) @@ -513,8 +562,9 @@ bool Parser::parse_one() case '|': op = ::MIR::eBinOp::BIT_OR ; break; case '&': op = ::MIR::eBinOp::BIT_AND; break; case '^': op = ::MIR::eBinOp::BIT_XOR; break; + case '%': op = ::MIR::eBinOp::MOD; break; case '<': - if( lex.consume_if('<') ) + if( t.strval[1] == '<' ) op = ::MIR::eBinOp::BIT_SHL; else if( lex.consume_if('=') ) op = ::MIR::eBinOp::LE; @@ -530,7 +580,9 @@ bool Parser::parse_one() op = ::MIR::eBinOp::GT; break; case '=': - op = ::MIR::eBinOp::EQ; if(0) + op = ::MIR::eBinOp::EQ; + lex.check_consume('='); + break; case '!': op = ::MIR::eBinOp::NE; lex.check_consume('='); @@ -620,9 +672,57 @@ bool Parser::parse_one() stmts.push_back(::MIR::Statement::make_Drop({ kind, ::std::move(slot), flag_idx })); } - else if(lex.next() == "ASM") + else if( lex.consume_if("ASM") ) { - throw "TODO"; + lex.check_consume('('); + ::std::vector<::std::pair<::std::string, ::MIR::LValue>> out_vals; + while(lex.next() != ')') + { + auto cons = ::std::move(lex.check_consume(TokenClass::String).strval); + lex.check_consume(':'); + auto lv = H::parse_lvalue(*this, var_names); + if(!lex.consume_if(',')) + break; + out_vals.push_back(::std::make_pair(::std::move(cons), ::std::move(lv))); + } + lex.check_consume(')'); + lex.check_consume('='); + auto tpl = ::std::move(lex.check_consume(TokenClass::String).strval); + + lex.check_consume('('); + ::std::vector<::std::pair<::std::string, ::MIR::LValue>> in_vals; + while(lex.next() != ')') + { + auto cons = ::std::move(lex.check_consume(TokenClass::String).strval); + lex.check_consume(':'); + auto lv = H::parse_lvalue(*this, var_names); + if(!lex.consume_if(',')) + break; + in_vals.push_back(::std::make_pair(::std::move(cons), ::std::move(lv))); + } + lex.check_consume(')'); + + lex.check_consume('['); + ::std::vector<::std::string> clobbers; + while(lex.next() != ':') + { + clobbers.push_back( ::std::move(lex.check_consume(TokenClass::String).strval) ); + if(!lex.consume_if(',')) + break; + } + lex.check_consume(':'); + ::std::vector<::std::string> flags; + while(lex.next() != ']') + { + flags.push_back( ::std::move(lex.check_consume(TokenClass::Ident).strval) ); + if(!lex.consume_if(',')) + break; + } + lex.check_consume(']'); + + stmts.push_back(::MIR::Statement::make_Asm({ + ::std::move(tpl), ::std::move(out_vals), ::std::move(in_vals), ::std::move(clobbers), ::std::move(flags) + })); } else { @@ -673,10 +773,57 @@ bool Parser::parse_one() term = ::MIR::Terminator::make_Switch({ ::std::move(val), ::std::move(targets) }); } - else if( lex.consume_if("SWITCHVAL") ) + else if( lex.consume_if("SWITCHVALUE") ) { auto val = H::parse_lvalue(*this, var_names); - throw "TODO"; + ::std::vector<::MIR::BasicBlockId> targets; + lex.check_consume('{'); + ::MIR::SwitchValues vals; + if( lex.next() == TokenClass::Integer ) { + ::std::vector<uint64_t> values; + while(lex.next() != '_') + { + values.push_back( lex.check_consume(TokenClass::Integer).integer() ); + lex.check_consume('='); + targets.push_back( static_cast<unsigned>( lex.check_consume(TokenClass::Integer).integer() ) ); + lex.check_consume(','); + } + vals = ::MIR::SwitchValues::make_Unsigned(::std::move(values)); + } + else if( lex.next() == '+' || lex.next() == '-' ) { + ::std::vector<int64_t> values; + while(lex.next() != '_') + { + auto neg = lex.consume() == '-'; + int64_t val = static_cast<int64_t>( lex.check_consume(TokenClass::Integer).integer() ); + values.push_back( neg ? -val : val ); + lex.check_consume('='); + targets.push_back( static_cast<unsigned>( lex.check_consume(TokenClass::Integer).integer() ) ); + lex.check_consume(','); + } + vals = ::MIR::SwitchValues::make_Signed(::std::move(values)); + } + else if( lex.next() == TokenClass::String ) { + ::std::vector<::std::string> values; + while(lex.next() != '_') + { + values.push_back( ::std::move(lex.check_consume(TokenClass::String).strval) ); + lex.check_consume('='); + targets.push_back( static_cast<unsigned>( lex.check_consume(TokenClass::Integer).integer() ) ); + lex.check_consume(','); + } + vals = ::MIR::SwitchValues::make_String(::std::move(values)); + } + else { + ::std::cerr << lex << "Unexpected token for SWITCHVALUE value - " << lex.next() << ::std::endl; + throw "ERROR"; + } + lex.check_consume('_'); + lex.check_consume('='); + auto def_tgt = static_cast<unsigned>( lex.check_consume(TokenClass::Integer).integer() ); + lex.check_consume('}'); + + term = ::MIR::Terminator::make_SwitchValue({ ::std::move(val), def_tgt, ::std::move(targets), ::std::move(vals) }); } else if( lex.consume_if("CALL") ) { @@ -777,9 +924,12 @@ bool Parser::parse_one() ::HIR::SimplePath Parser::parse_simplepath() { lex.check_consume("::"); - lex.check(TokenClass::String); - auto crate = lex.consume().strval; - lex.check_consume("::"); + ::std::string crate; + if( lex.next() == TokenClass::String ) + { + crate = lex.consume().strval; + lex.check_consume("::"); + } ::std::vector<::std::string> ents; do { @@ -954,14 +1104,17 @@ RawType Parser::parse_core_type() // Good. return ::HIR::TypeRef(it->second.get()); } - else if( lex.next() == "extern" || lex.next() == "fn" ) + else if( lex.next() == "extern" || lex.next() == "fn" || lex.next() == "unsafe" ) { + bool is_unsafe = false; ::std::string abi = "Rust"; + if( lex.consume_if("unsafe") ) + { + is_unsafe = true; + } if( lex.consume_if("extern") ) { - // TODO: Save the ABI - lex.check(TokenClass::String); - abi = lex.consume().strval; + abi = ::std::move(lex.check_consume(TokenClass::String).strval); } lex.check_consume("fn"); lex.check_consume('('); @@ -973,9 +1126,16 @@ RawType Parser::parse_core_type() break; } lex.check_consume(')'); - lex.check_consume('-'); - lex.check_consume('>'); - auto ret_ty = parse_type(); + ::HIR::TypeRef ret_ty; + if( lex.consume_if('-') ) + { + lex.check_consume('>'); + ret_ty = parse_type(); + } + else + { + ret_ty = ::HIR::TypeRef::unit(); + } return ::HIR::TypeRef(RawType::Function); // TODO: Use abi/ret_ty/args as part of that } @@ -983,19 +1143,41 @@ RawType Parser::parse_core_type() { lex.consume_if('('); ::HIR::GenericPath base_trait; + ::std::vector<::std::pair<::std::string, ::HIR::TypeRef>> atys; if( lex.next() != '+' ) { - base_trait = parse_genericpath(); + // Custom TraitPath parsing. + base_trait.m_simplepath = parse_simplepath(); + if( lex.consume_if('<') ) + { + while(lex.next() != '>') + { + if( lex.next() == TokenClass::Ident && lex.lookahead() == '=' ) + { + auto name = ::std::move(lex.consume().strval); + lex.check_consume('='); + auto ty = parse_type(); + atys.push_back(::std::make_pair( ::std::move(name), ::std::move(ty) )); + } + else + { + base_trait.m_params.tys.push_back( parse_type() ); + } + if( !lex.consume_if(',') ) + break ; + } + lex.check_consume('>'); + } } ::std::vector<::HIR::GenericPath> markers; while(lex.consume_if('+')) { + // TODO: Detect/parse lifetimes? markers.push_back(parse_genericpath()); - // TODO: Lifetimes? } lex.consume_if(')'); return ::HIR::TypeRef(RawType::TraitObject); - // TODO: Figure out how to include the traits in this type. + // TODO: Generate the vtable path and locate that struct } else if( lex.next() == TokenClass::Ident ) { @@ -1010,12 +1192,15 @@ RawType Parser::parse_core_type() ::HIR::SimplePath ModuleTree::find_lang_item(const char* name) const { - return ::HIR::SimplePath({ "core", { "start" } }); + return ::HIR::SimplePath({ "", { "main#" } }); } const Function& ModuleTree::get_function(const ::HIR::Path& p) const { auto it = functions.find(p); if(it == functions.end()) + { + ::std::cerr << "Unable to find function " << p << " for invoke" << ::std::endl; throw ""; + } return it->second; }
\ No newline at end of file diff --git a/tools/standalone_miri/module_tree.hpp b/tools/standalone_miri/module_tree.hpp index ecc19625..ce831621 100644 --- a/tools/standalone_miri/module_tree.hpp +++ b/tools/standalone_miri/module_tree.hpp @@ -5,6 +5,7 @@ #include <string> #include <vector> #include <map> +#include <set> #include "../../src/mir/mir.hpp" #include "hir_sim.hpp" @@ -21,6 +22,8 @@ class ModuleTree { friend struct Parser; + ::std::set<::std::string> loaded_files; + ::std::map<::HIR::Path, Function> functions; // Hack: Tuples are stored as `::""::<A,B,C,...>` ::std::map<::HIR::GenericPath, ::std::unique_ptr<DataType>> data_types; diff --git a/vsproject/build_rustc_minicargo.cmd b/vsproject/build_rustc_minicargo.cmd index 4e36dc89..c778502a 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 hello.exe +x64\Release\mrustc.exe ..\rustc-1.19.0-src\src\test\run-pass\hello.rs -L output -o output\hello.exe if %errorlevel% neq 0 exit /b %errorlevel% hello.exe if %errorlevel% neq 0 exit /b %errorlevel%
\ No newline at end of file diff --git a/vsproject/build_rustc_minicargo_mmir.cmd b/vsproject/build_rustc_minicargo_mmir.cmd new file mode 100644 index 00000000..a6409391 --- /dev/null +++ b/vsproject/build_rustc_minicargo_mmir.cmd @@ -0,0 +1,12 @@ +@echo off +x64\Release\minicargo.exe ..\rustc-1.19.0-src\src\libstd --script-overrides ..\script-overrides\stable-1.19.0 --output-dir output_mmir -Z emit-mmir +if %errorlevel% neq 0 exit /b %errorlevel% +x64\Release\minicargo.exe ..\rustc-1.19.0-src\src\libpanic_unwind --script-overrides ..\script-overrides\stable-1.19.0 --output-dir output_mmir -Z emit-mmir +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 --output-dir output_mmir -Z emit-mmir +if %errorlevel% neq 0 exit /b %errorlevel% + +x64\Release\mrustc.exe ..\rustc-1.19.0-src\src\test\run-pass\hello.rs -L output_mmir -o output_mmir\hello.exe -C codegen-type=monomir +if %errorlevel% neq 0 exit /b %errorlevel% +x64\Release\standalone_miri.exe output_mmir\hello.exe.mir +if %errorlevel% neq 0 exit /b %errorlevel%
\ No newline at end of file diff --git a/vsproject/mrustc.vcxproj b/vsproject/mrustc.vcxproj index 41d4b42a..c48d0444 100644 --- a/vsproject/mrustc.vcxproj +++ b/vsproject/mrustc.vcxproj @@ -244,6 +244,7 @@ <ClCompile Include="..\src\trans\codegen.cpp" /> <ClCompile Include="..\src\trans\codegen_c.cpp" /> <ClCompile Include="..\src\trans\codegen_c_structured.cpp" /> + <ClCompile Include="..\src\trans\codegen_mmir.cpp" /> <ClCompile Include="..\src\trans\enumerate.cpp" /> <ClCompile Include="..\src\trans\mangling.cpp" /> <ClCompile Include="..\src\trans\monomorphise.cpp" /> diff --git a/vsproject/mrustc.vcxproj.filters b/vsproject/mrustc.vcxproj.filters index 8a326741..6c0ba794 100644 --- a/vsproject/mrustc.vcxproj.filters +++ b/vsproject/mrustc.vcxproj.filters @@ -389,6 +389,9 @@ <ClCompile Include="..\src\expand\proc_macro.cpp"> <Filter>Source Files\expand</Filter> </ClCompile> + <ClCompile Include="..\src\trans\codegen_mmir.cpp"> + <Filter>Source Files\trans</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\src\common.hpp"> |