summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge (Mutabah) <acessdev@gmail.com>2018-02-11 15:33:08 +0800
committerGitHub <noreply@github.com>2018-02-11 15:33:08 +0800
commit6caf5739a97774b2602106e616db75e8a0ad5f8a (patch)
tree9d16f869bbff27743fe7c233fba9c4665a4d9138
parent9e864a5d3ea05706ea6c7f68e47d32629a2c877e (diff)
parent3718f8cb7ee7b8c93e4d69b9aa2e00b4f50efd62 (diff)
downloadmrust-6caf5739a97774b2602106e616db75e8a0ad5f8a.tar.gz
Merge pull request #52 from thepowersgang/common_layout
Merge "common_layout" branch
-rw-r--r--.gitignore1
-rw-r--r--Makefile17
-rw-r--r--src/hir/hir.hpp1
-rw-r--r--src/hir/type.cpp7
-rw-r--r--src/include/tagged_union.hpp2
-rw-r--r--src/main.cpp6
-rw-r--r--src/mir/mir.cpp2
-rw-r--r--src/mir/optimise.cpp16
-rw-r--r--src/trans/codegen.cpp11
-rw-r--r--src/trans/codegen.hpp1
-rw-r--r--src/trans/codegen_c.cpp944
-rw-r--r--src/trans/codegen_mmir.cpp826
-rw-r--r--src/trans/main_bindings.hpp1
-rw-r--r--src/trans/target.cpp608
-rw-r--r--src/trans/target.hpp44
-rw-r--r--tools/minicargo/Makefile6
-rw-r--r--tools/minicargo/build.cpp47
-rw-r--r--tools/minicargo/build.h1
-rw-r--r--tools/minicargo/debug.cpp11
-rw-r--r--tools/minicargo/main.cpp23
-rw-r--r--tools/standalone_miri/hir_sim.cpp16
-rw-r--r--tools/standalone_miri/lex.cpp216
-rw-r--r--tools/standalone_miri/lex.hpp12
-rw-r--r--tools/standalone_miri/module_tree.cpp259
-rw-r--r--tools/standalone_miri/module_tree.hpp3
-rw-r--r--vsproject/build_rustc_minicargo.cmd2
-rw-r--r--vsproject/build_rustc_minicargo_mmir.cmd12
-rw-r--r--vsproject/mrustc.vcxproj1
-rw-r--r--vsproject/mrustc.vcxproj.filters3
29 files changed, 2527 insertions, 572 deletions
diff --git a/.gitignore b/.gitignore
index 3b3c93d3..62e8c51c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,4 +53,5 @@
/bnf/rust.output
/bnf/test.bin
/vsproject/output
+/vsproject/output_mmir
/vsproject/standalone_miri/x64
diff --git a/Makefile b/Makefile
index 0cd36b1e..b1d484d8 100644
--- a/Makefile
+++ b/Makefile
@@ -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">