summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge (bugs) <tpg@mutabah.net>2017-07-06 17:41:10 +0800
committerJohn Hodge (bugs) <tpg@mutabah.net>2017-07-06 17:41:10 +0800
commit48e2c4973d5401c9f7d0ee2bac22ac6015744961 (patch)
treeb93fb21b85343633e2d0c00c42ea7a388bb6f883
parentce3d36a90b9efd11c94f9084b5e727d65b6509a7 (diff)
parentc4e88b3c49736e71534c918a83956885c052beb8 (diff)
downloadmrust-48e2c4973d5401c9f7d0ee2bac22ac6015744961.tar.gz
Merge branch 'master' of https://github.com/thepowersgang/mrustc
# Conflicts: # src/trans/codegen_c.cpp
-rw-r--r--Makefile15
-rw-r--r--Notes/todo.txt9
-rw-r--r--run_rustc/Makefile6
-rw-r--r--src/ast/expr.cpp8
-rw-r--r--src/ast/expr.hpp7
-rw-r--r--src/ast/path.cpp20
-rw-r--r--src/common.hpp4
-rw-r--r--src/expand/cfg.hpp2
-rw-r--r--src/expand/file_line.cpp17
-rw-r--r--src/expand/macro_rules.cpp5
-rw-r--r--src/expand/macro_rules.hpp2
-rw-r--r--src/expand/mod.cpp51
-rw-r--r--src/hir/deserialise.cpp32
-rw-r--r--src/hir/dump.cpp16
-rw-r--r--src/hir/from_ast.cpp2
-rw-r--r--src/hir/from_ast_expr.cpp46
-rw-r--r--src/hir/serialise.cpp42
-rw-r--r--src/hir/type.cpp2
-rw-r--r--src/hir/type.hpp10
-rw-r--r--src/hir_conv/bind.cpp13
-rw-r--r--src/hir_conv/constant_evaluation.cpp25
-rw-r--r--src/hir_expand/const_eval_full.cpp32
-rw-r--r--src/hir_expand/erased_types.cpp44
-rw-r--r--src/hir_expand/ufcs_everything.cpp6
-rw-r--r--src/hir_typeck/expr_check.cpp4
-rw-r--r--src/hir_typeck/expr_cs.cpp288
-rw-r--r--src/hir_typeck/helpers.cpp4
-rw-r--r--src/hir_typeck/static.cpp119
-rw-r--r--src/include/debug.hpp12
-rw-r--r--src/include/span.hpp2
-rw-r--r--src/include/synext_decorator.hpp22
-rw-r--r--src/include/synext_macro.hpp22
-rw-r--r--src/include/tagged_union.hpp18
-rw-r--r--src/macro_rules/eval.cpp25
-rw-r--r--src/macro_rules/macro_rules.hpp2
-rw-r--r--src/macro_rules/parse.cpp6
-rw-r--r--src/main.cpp119
-rw-r--r--src/mir/check.cpp106
-rw-r--r--src/mir/check_full.cpp299
-rw-r--r--src/mir/cleanup.cpp15
-rw-r--r--src/mir/dump.cpp45
-rw-r--r--src/mir/from_hir.cpp45
-rw-r--r--src/mir/from_hir.hpp67
-rw-r--r--src/mir/from_hir_match.cpp28
-rw-r--r--src/mir/helpers.cpp118
-rw-r--r--src/mir/helpers.hpp11
-rw-r--r--src/mir/main_bindings.hpp2
-rw-r--r--src/mir/mir.cpp84
-rw-r--r--src/mir/mir.hpp42
-rw-r--r--src/mir/mir_builder.cpp731
-rw-r--r--src/mir/operations.hpp1
-rw-r--r--src/mir/optimise.cpp938
-rw-r--r--src/parse/expr.cpp16
-rw-r--r--src/parse/lex.cpp8
-rw-r--r--src/parse/parseerror.cpp20
-rw-r--r--src/parse/pattern.cpp6
-rw-r--r--src/parse/root.cpp26
-rw-r--r--src/parse/tokenstream.cpp14
-rw-r--r--src/parse/tokenstream.hpp4
-rw-r--r--src/parse/types.cpp2
-rw-r--r--src/resolve/absolute.cpp12
-rw-r--r--src/span.cpp3
-rw-r--r--src/trans/codegen_c.cpp1467
-rw-r--r--src/trans/codegen_c.hpp47
-rw-r--r--src/trans/codegen_c_structured.cpp298
-rw-r--r--src/trans/enumerate.cpp35
-rw-r--r--src/trans/monomorphise.cpp27
-rw-r--r--src/trans/target.cpp55
-rw-r--r--src/trans/target.hpp32
69 files changed, 3390 insertions, 2273 deletions
diff --git a/Makefile b/Makefile
index 51f2b3be..d2f588cc 100644
--- a/Makefile
+++ b/Makefile
@@ -49,6 +49,7 @@ CXXFLAGS += -Wno-misleading-indentation
RUST_FLAGS := --cfg debug_assertions
RUST_FLAGS += -g
RUST_FLAGS += -O
+RUST_FLAGS += $(RUST_FLAGS_EXTRA)
SHELL = bash
@@ -110,7 +111,8 @@ OBJ += mir/check.o mir/cleanup.o mir/optimise.o
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 trans/codegen_c.o
+OBJ += trans/enumerate.o trans/monomorphise.o trans/codegen.o
+OBJ += trans/codegen_c.o trans/codegen_c_structured.o
OBJ += trans/target.o
PCHS := ast/ast.hpp
@@ -372,6 +374,8 @@ DISABLED_TESTS += run-pass/out-of-stack
# - Requires jemalloc
DISABLED_TESTS += run-pass/allocator-default
DISABLED_TESTS += run-pass/allocator-override
+# - Really odd behavior:
+DISABLED_TESTS += run-pass/move-guard-const # Moves are allowed in match arm guards (should error in mrustc)
# - Lazy.
DISABLED_TESTS += run-pass/associated-types-projection-in-where-clause # Not normalizing bounds
DISABLED_TESTS += run-pass/cast # Disallows cast from char to i32
@@ -715,7 +719,7 @@ DISABLED_TESTS += run-pass/issue-13027 # Infinite loop (match?)
DISABLED_TESTS += run-pass/issue-36936 # assert_eq failing on equal values
# - BUG: signed ctpop/cttz/ctlz
DISABLED_TESTS += run-pass/intrinsics-integer # todo - bswap<i8>
-# - BUG: Incorrect drop order of ?
+# - BUG: Incorrect drop ordering
DISABLED_TESTS += run-pass/issue-23338-ensure-param-drop-order
# - BUG: Incorrect consteval
DISABLED_TESTS += run-pass/issue-23968-const-not-overflow # !0 / 2 incorrect value
@@ -750,15 +754,14 @@ DISABLED_TESTS += run-pass/type-sizes
DISABLED_TESTS += run-pass/discrim-explicit-23030
DISABLED_TESTS += run-pass/issue-13902
# - BUG: Bad floats
-DISABLED_TESTS += run-pass/float-nan
-DISABLED_TESTS += run-pass/float_math
-DISABLED_TESTS += run-pass/floatlits
+DISABLED_TESTS += run-pass/float_math # Missing intrinsic
DISABLED_TESTS += run-pass/intrinsics-math
+DISABLED_TESTS += run-pass/issue-32805 # Possible f32 literal rounding isue
# - BUG: MIR Generation
DISABLED_TESTS += run-pass/union/union-drop-assign # No drop when assiging to union field
DISABLED_TESTS += run-pass/issue-4734 # Destructor on unused rvalue
DISABLED_TESTS += run-pass/issue-8860 # No drop of un-moved arguments
-DISABLED_TESTS += run-pass/issue-15080 # Inifinte loop from incorrect match generation
+DISABLED_TESTS += run-pass/issue-15080 # Infinte loop from incorrect match generation
# - BUG: Codegen
DISABLED_TESTS += run-pass/union/union-transmute # Incorrect union behavior, likey backend UB
DISABLED_TESTS += run-pass/mir_overflow_off # out-of-range shift behavior
diff --git a/Notes/todo.txt b/Notes/todo.txt
index 54956718..8146bfd6 100644
--- a/Notes/todo.txt
+++ b/Notes/todo.txt
@@ -23,3 +23,12 @@ TODO:
- This should reduce the amount of code needed for validation, but will be a
BIG change.
+
+
+## Optimisations
+- Argument propagation: replace assignments from Argument(_) if target is only
+ written once
+- Dead assignment removal (Delete `<val> = Use(<val>)`
+- Tuple destructure removal
+ - Spot `#1 = (...,)`, `#2 = (#1).n` where #1 is Write-once, borrow-none
+
diff --git a/run_rustc/Makefile b/run_rustc/Makefile
index 385bfd9c..71c124a3 100644
--- a/run_rustc/Makefile
+++ b/run_rustc/Makefile
@@ -4,8 +4,8 @@ RUSTC := ../output/rustc
RUST_SRC := ../rustc-nightly/src/
PREFIX := prefix/
-BINDIR := $(PREFIX)bin
-LIBDIR := $(PREFIX)lib
+BINDIR := $(PREFIX)bin/
+LIBDIR := $(PREFIX)lib/
V ?= @
@@ -24,7 +24,7 @@ $(BINDIR)rustc: $(RUSTC)
$(LIBDIR)%.rlib: $(RUST_SRC)%/lib.rs $(RUSTC)
@mkdir -p $(dir $@)
@echo "[RUSTC] -o $@"
- time $(RUSTC) $(RUSTFLAGS_$@) -L output/ -L ../output/libs $< -o $@
+ $Vtime $(RUSTC) $(RUSTFLAGS_$@) -L output/ -L ../output/libs $< -o $@
$(LIBDIR)%.rlib: $(RUST_SRC)%/src/lib.rs $(RUSTC)
@mkdir -p $(dir $@)
@echo "[RUSTC] -o $@"
diff --git a/src/ast/expr.cpp b/src/ast/expr.cpp
index dd586683..c1baf9b4 100644
--- a/src/ast/expr.cpp
+++ b/src/ast/expr.cpp
@@ -69,11 +69,11 @@ ExprNode::~ExprNode() {
#define OPT_CLONE(node) (node.get() ? node->clone() : ::AST::ExprNodeP())
namespace {
- static inline ExprNodeP mk_exprnodep(const Position& pos, AST::ExprNode* en) {
- en->set_pos(pos);
+ static inline ExprNodeP mk_exprnodep(const Span& pos, AST::ExprNode* en) {
+ en->set_span(pos);
return ExprNodeP(en);
}
- #define NEWNODE(type, ...) mk_exprnodep(get_pos(), new type(__VA_ARGS__))
+ #define NEWNODE(type, ...) mk_exprnodep(span(), new type(__VA_ARGS__))
}
NODE(ExprNode_Block, {
@@ -453,7 +453,7 @@ NV(ExprNode_Block, {
})
NV(ExprNode_Macro,
{
- BUG(node.get_pos(), "Hit unexpanded macro in expression - " << node);
+ BUG(node.span(), "Hit unexpanded macro in expression - " << node);
})
NV(ExprNode_Asm,
{
diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp
index ee1da656..a6b58e03 100644
--- a/src/ast/expr.hpp
+++ b/src/ast/expr.hpp
@@ -26,7 +26,7 @@ class NodeVisitor;
class ExprNode
{
MetaItems m_attrs;
- Position m_pos;
+ Span m_span;
public:
virtual ~ExprNode() = 0;
@@ -34,9 +34,8 @@ public:
virtual void print(::std::ostream& os) const = 0;
virtual ::std::unique_ptr<ExprNode> clone() const = 0;
- void set_pos(Position p) { m_pos = ::std::move(p); }
- const Position& get_pos() const { return m_pos; }
- Span span() const { return m_pos; }
+ void set_span(Span s) { m_span = ::std::move(s); }
+ const Span& span() const { return m_span; }
void set_attrs(MetaItems&& mi) {
m_attrs = mv$(mi);
diff --git a/src/ast/path.cpp b/src/ast/path.cpp
index ebec5d5a..37428b1a 100644
--- a/src/ast/path.cpp
+++ b/src/ast/path.cpp
@@ -190,18 +190,18 @@ void Path::bind_variable(unsigned int slot)
}
void Path::bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector<TypeRef>& /*args*/)
{
- auto it = ::std::find_if(ent.variants().begin(), ent.variants().end(), [&](const auto& x) { return x.m_name == name; });
- if( it == ent.variants().end() )
- {
- throw ParseError::Generic("Enum variant not found");
- }
- unsigned int idx = it - ent.variants().begin();
+ auto it = ::std::find_if(ent.variants().begin(), ent.variants().end(), [&](const auto& x) { return x.m_name == name; });
+ if( it == ent.variants().end() )
+ {
+ throw ParseError::Generic("Enum variant not found");
+ }
+ unsigned int idx = it - ent.variants().begin();
DEBUG("Bound to enum variant '" << name << "' (#" << idx << ")");
- ::AST::PathBinding::Data_EnumVar tmp;
- tmp.enum_ = &ent;
- tmp.idx = idx;
- m_binding = PathBinding::make_EnumVar(tmp);
+ ::AST::PathBinding::Data_EnumVar tmp = {};
+ tmp.enum_ = &ent;
+ tmp.idx = idx;
+ m_binding = PathBinding::make_EnumVar( mv$(tmp) );
}
Path& Path::operator+=(const Path& other)
diff --git a/src/common.hpp b/src/common.hpp
index 55e0f833..dec40191 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -12,7 +12,7 @@
#include <memory>
#ifdef _MSC_VER
-#define __attribute__(x)
+#define __attribute__(x) /* no-op */
#endif
#define FMT(ss) (dynamic_cast< ::std::stringstream&>(::std::stringstream() << ss).str())
@@ -22,7 +22,7 @@
#define rc_new$(...) ::make_shared_ptr(::std::move(__VA_ARGS__))
#include "include/debug.hpp"
-#include "include/rustic.hpp" // slice and option
+#include "include/rustic.hpp" // slice and option
#include "include/compile_error.hpp"
template<typename T>
diff --git a/src/expand/cfg.hpp b/src/expand/cfg.hpp
index 8e5fce42..edf17851 100644
--- a/src/expand/cfg.hpp
+++ b/src/expand/cfg.hpp
@@ -1,6 +1,8 @@
#pragma once
+#include <ast/attrs.hpp>
+
extern void Cfg_SetFlag(::std::string name);
extern void Cfg_SetValue(::std::string name, ::std::string val);
extern void Cfg_SetValueCb(::std::string name, ::std::function<bool(const ::std::string&)> cb);
diff --git a/src/expand/file_line.cpp b/src/expand/file_line.cpp
index 8dfb7e6d..7e117993 100644
--- a/src/expand/file_line.cpp
+++ b/src/expand/file_line.cpp
@@ -9,12 +9,23 @@
#include "../parse/common.hpp"
#include "../parse/ttstream.hpp"
+namespace {
+ const Span& get_top_span(const Span& sp) {
+ if( sp.outer_span ) {
+ return get_top_span(*sp.outer_span);
+ }
+ else {
+ return sp;
+ }
+ }
+}
+
class CExpanderFile:
public ExpandProcMacro
{
::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
{
- return box$( TTStreamO(TokenTree(Token(TOK_STRING, sp.filename.c_str()))) );
+ return box$( TTStreamO(TokenTree(Token(TOK_STRING, get_top_span(sp).filename.c_str()))) );
}
};
@@ -23,7 +34,7 @@ class CExpanderLine:
{
::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
{
- return box$( TTStreamO(TokenTree(Token((uint64_t)sp.start_line, CORETYPE_U32))) );
+ return box$( TTStreamO(TokenTree(Token((uint64_t)get_top_span(sp).start_line, CORETYPE_U32))) );
}
};
@@ -32,7 +43,7 @@ class CExpanderColumn:
{
::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
{
- return box$( TTStreamO(TokenTree(Token((uint64_t)sp.start_ofs, CORETYPE_U32))) );
+ return box$( TTStreamO(TokenTree(Token((uint64_t)get_top_span(sp).start_ofs, CORETYPE_U32))) );
}
};
diff --git a/src/expand/macro_rules.cpp b/src/expand/macro_rules.cpp
index 338edd12..0375f430 100644
--- a/src/expand/macro_rules.cpp
+++ b/src/expand/macro_rules.cpp
@@ -169,11 +169,6 @@ class CMacroReexportHandler:
}
};
-::std::unique_ptr<TokenStream> Macro_Invoke(const char* name, const MacroRules& rules, TokenTree tt, AST::Module& mod)
-{
- return Macro_InvokeRules(name, rules, mv$(tt), mod);
-}
-
STATIC_MACRO("macro_rules", CMacroRulesExpander);
STATIC_DECORATOR("macro_use", CMacroUseHandler);
diff --git a/src/expand/macro_rules.hpp b/src/expand/macro_rules.hpp
index b5f09f1c..00332dd5 100644
--- a/src/expand/macro_rules.hpp
+++ b/src/expand/macro_rules.hpp
@@ -12,5 +12,3 @@ namespace AST {
class TokenTree;
class TokenStream;
class MacroRules;
-
-extern ::std::unique_ptr<TokenStream> Macro_Invoke(const char* name, const MacroRules& rules, TokenTree tt, AST::Module& mod);
diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp
index 01786284..5c3be722 100644
--- a/src/expand/mod.cpp
+++ b/src/expand/mod.cpp
@@ -11,12 +11,13 @@
#include <synext.hpp>
#include <map>
#include "macro_rules.hpp"
+#include "../macro_rules/macro_rules.hpp"
#include "../parse/common.hpp" // For reparse from macros
#include <ast/expr.hpp>
#include "cfg.hpp"
-DecoratorDef* g_decorators_list = nullptr;
-MacroDef* g_macros_list = nullptr;
+DecoratorDef* g_decorators_list = nullptr;
+MacroDef* g_macros_list = nullptr;
::std::map< ::std::string, ::std::unique_ptr<ExpandDecorator> > g_decorators;
::std::map< ::std::string, ::std::unique_ptr<ExpandProcMacro> > g_macros;
@@ -26,18 +27,18 @@ void Expand_Expr(::AST::Crate& crate, LList<const AST::Module*> modstack, AST::E
void Expand_Expr(::AST::Crate& crate, LList<const AST::Module*> modstack, ::std::shared_ptr<AST::ExprNode>& node);
void Register_Synext_Decorator(::std::string name, ::std::unique_ptr<ExpandDecorator> handler) {
- g_decorators.insert(::std::make_pair( mv$(name), mv$(handler) ));
+ g_decorators.insert(::std::make_pair( mv$(name), mv$(handler) ));
}
void Register_Synext_Macro(::std::string name, ::std::unique_ptr<ExpandProcMacro> handler) {
- g_macros.insert(::std::make_pair( mv$(name), mv$(handler) ));
+ g_macros.insert(::std::make_pair( mv$(name), mv$(handler) ));
}
void Register_Synext_Decorator_Static(DecoratorDef* def) {
- def->prev = g_decorators_list;
- g_decorators_list = def;
+ def->prev = g_decorators_list;
+ g_decorators_list = def;
}
void Register_Synext_Macro_Static(MacroDef* def) {
- def->prev = g_macros_list;
- g_macros_list = def;
+ def->prev = g_macros_list;
+ g_macros_list = def;
}
@@ -115,7 +116,7 @@ void Expand_Attrs(::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate
if( input_ident != "" )
ERROR(mi_span, E0000, "macro_rules! macros can't take an ident");
- auto e = Macro_Invoke(name.c_str(), *mr.data, mv$(input_tt), mod);
+ auto e = Macro_InvokeRules(name.c_str(), *mr.data, mi_span, mv$(input_tt), mod);
return e;
}
}
@@ -134,7 +135,7 @@ void Expand_Attrs(::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate
}
if( last_mac )
{
- auto e = Macro_Invoke(name.c_str(), *last_mac, mv$(input_tt), mod);
+ auto e = Macro_InvokeRules(name.c_str(), *last_mac, mi_span, mv$(input_tt), mod);
return e;
}
}
@@ -317,7 +318,7 @@ struct CExpandExpr:
{
this->visit(cnode);
if(cnode.get() == nullptr)
- ERROR(parent.get_pos(), E0000, "#[cfg] not allowed in this position");
+ ERROR(parent.span(), E0000, "#[cfg] not allowed in this position");
}
assert( ! this->replacement );
}
@@ -343,7 +344,7 @@ struct CExpandExpr:
::AST::ExprNodeP rv;
auto& mod = this->cur_mod();
- auto ttl = Expand_Macro( crate, modstack, mod, Span(node.get_pos()), node.m_name, node.m_ident, node.m_tokens );
+ auto ttl = Expand_Macro( crate, modstack, mod, node.span(), node.m_name, node.m_ident, node.m_tokens );
if( !ttl.get() )
{
// No expansion
@@ -362,7 +363,7 @@ struct CExpandExpr:
auto newexpr = Parse_ExprBlockLine_WithItems(*ttl, local_mod_ptr, add_silence_if_end);
if( tmp_local_mod )
- TODO(node.get_pos(), "Handle edge case where a macro expansion outside of a _Block creates an item");
+ TODO(node.span(), "Handle edge case where a macro expansion outside of a _Block creates an item");
if( newexpr )
{
@@ -382,7 +383,7 @@ struct CExpandExpr:
if( ttl->lookahead(0) != TOK_EOF )
{
if( !nodes_out ) {
- ERROR(node.get_pos(), E0000, "Unused tokens at the end of macro expansion - " << ttl->getToken());
+ ERROR(node.span(), E0000, "Unused tokens at the end of macro expansion - " << ttl->getToken());
}
}
}
@@ -1074,17 +1075,17 @@ void Expand_Mod_IndexAnon(::AST::Crate& crate, ::AST::Module& mod)
}
void Expand(::AST::Crate& crate)
{
- // Fill macro/decorator map from init list
- while(g_decorators_list)
- {
- g_decorators.insert(::std::make_pair( mv$(g_decorators_list->name), mv$(g_decorators_list->def) ));
- g_decorators_list = g_decorators_list->prev;
- }
- while (g_macros_list)
- {
- g_macros.insert(::std::make_pair(mv$(g_macros_list->name), mv$(g_macros_list->def)));
- g_macros_list = g_macros_list->prev;
- }
+ // Fill macro/decorator map from init list
+ while(g_decorators_list)
+ {
+ g_decorators.insert(::std::make_pair( mv$(g_decorators_list->name), mv$(g_decorators_list->def) ));
+ g_decorators_list = g_decorators_list->prev;
+ }
+ while (g_macros_list)
+ {
+ g_macros.insert(::std::make_pair(mv$(g_macros_list->name), mv$(g_macros_list->def)));
+ g_macros_list = g_macros_list->prev;
+ }
auto modstack = LList<const ::AST::Module*>(nullptr, &crate.m_root_module);
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp
index 0ff4d63b..3cb58a2e 100644
--- a/src/hir/deserialise.cpp
+++ b/src/hir/deserialise.cpp
@@ -338,11 +338,10 @@ namespace {
switch(auto tag = m_in.read_tag())
{
#define _(x, ...) case ::MIR::LValue::TAG_##x: return ::MIR::LValue::make_##x( __VA_ARGS__ );
- _(Variable, static_cast<unsigned int>(m_in.read_count()) )
- _(Temporary, { static_cast<unsigned int>(m_in.read_count()) } )
- _(Argument, { static_cast<unsigned int>(m_in.read_count()) } )
- _(Static, deserialise_path() )
_(Return, {})
+ _(Argument, { static_cast<unsigned int>(m_in.read_count()) } )
+ _(Local, static_cast<unsigned int>(m_in.read_count()) )
+ _(Static, deserialise_path() )
_(Field, {
box$( deserialise_mir_lvalue() ),
static_cast<unsigned int>(m_in.read_count())
@@ -505,10 +504,10 @@ namespace {
::HIR::Linkage deserialise_linkage()
{
- ::HIR::Linkage l;
- l.type = ::HIR::Linkage::Type::Auto;
- l.name = m_in.read_string();
- return l;
+ ::HIR::Linkage l;
+ l.type = ::HIR::Linkage::Type::Auto;
+ l.name = m_in.read_string();
+ return l;
}
// - Value items
@@ -962,8 +961,8 @@ namespace {
::MIR::Function rv;
- rv.named_variables = deserialise_vec< ::HIR::TypeRef>( );
- rv.temporaries = deserialise_vec< ::HIR::TypeRef>( );
+ rv.locals = deserialise_vec< ::HIR::TypeRef>( );
+ //rv.local_names = deserialise_vec< ::std::string>( );
rv.drop_flags = deserialise_vec<bool>();
rv.blocks = deserialise_vec< ::MIR::BasicBlock>( );
@@ -1004,15 +1003,14 @@ namespace {
deserialise_vec< ::std::string>()
});
case 3: {
- ::MIR::Statement::Data_SetDropFlag sdf;
- sdf.idx = static_cast<unsigned int>(m_in.read_count());
- sdf.new_val = m_in.read_bool();
- sdf.other = static_cast<unsigned int>(m_in.read_count());
- return ::MIR::Statement::make_SetDropFlag(sdf);
- }
+ ::MIR::Statement::Data_SetDropFlag sdf;
+ sdf.idx = static_cast<unsigned int>(m_in.read_count());
+ sdf.new_val = m_in.read_bool();
+ sdf.other = static_cast<unsigned int>(m_in.read_count());
+ return ::MIR::Statement::make_SetDropFlag(sdf);
+ }
case 4:
return ::MIR::Statement::make_ScopeEnd({
- deserialise_vec<unsigned int>(),
deserialise_vec<unsigned int>()
});
default:
diff --git a/src/hir/dump.cpp b/src/hir/dump.cpp
index 649116e0..75dde59f 100644
--- a/src/hir/dump.cpp
+++ b/src/hir/dump.cpp
@@ -262,13 +262,13 @@ namespace {
void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override
{
m_os << indent() << "const " << p.get_name() << ": " << item.m_type << " = " << item.m_value_res;
- if( item.m_value )
- {
- m_os << " /*= ";
- item.m_value->visit(*this);
- m_os << "*/";
- }
- m_os << ";\n";
+ if( item.m_value )
+ {
+ m_os << " /*= ";
+ item.m_value->visit(*this);
+ m_os << "*/";
+ }
+ m_os << ";\n";
}
// - Misc
@@ -530,7 +530,7 @@ namespace {
m_os << ", ";
}
m_os << ")";
- m_os << "/* : " << node.m_res_type << " */";
+ m_os << "/* : " << node.m_res_type << " */";
}
void visit(::HIR::ExprNode_CallValue& node) override
{
diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp
index c0a3151e..e0429aca 100644
--- a/src/hir/from_ast.cpp
+++ b/src/hir/from_ast.cpp
@@ -702,7 +702,7 @@
{
if( ptr->m_datatype == CORETYPE_UINT || ptr->m_datatype == CORETYPE_ANY )
{
- // TODO: Limit check.
+ // TODO: Limit check.
auto size_val = static_cast<unsigned int>( ptr->m_value );
return ::HIR::TypeRef::new_array( mv$(inner), size_val );
}
diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp
index 9085bd3b..296bdce1 100644
--- a/src/hir/from_ast_expr.cpp
+++ b/src/hir/from_ast_expr.cpp
@@ -30,7 +30,7 @@ struct LowerHIR_ExprNode_Visitor:
auto rv = new ::HIR::ExprNode_Block(v.span());
for(const auto& n : v.m_nodes)
{
- ASSERT_BUG(v.get_pos(), n, "NULL node encountered in block");
+ ASSERT_BUG(v.span(), n, "NULL node encountered in block");
rv->m_nodes.push_back( LowerHIR_ExprNode_Inner( *n ) );
}
if( v.m_yields_final_value && ! rv->m_nodes.empty() )
@@ -48,7 +48,7 @@ struct LowerHIR_ExprNode_Visitor:
m_rv.reset( static_cast< ::HIR::ExprNode*>(rv) );
}
virtual void visit(::AST::ExprNode_Macro& v) override {
- BUG(v.get_pos(), "Hit ExprNode_Macro");
+ BUG(v.span(), "Hit ExprNode_Macro");
}
virtual void visit(::AST::ExprNode_Asm& v) override {
::std::vector< ::HIR::ExprNode_Asm::ValRef> outputs;
@@ -72,7 +72,7 @@ struct LowerHIR_ExprNode_Visitor:
case ::AST::ExprNode_Flow::CONTINUE:
case ::AST::ExprNode_Flow::BREAK:
if( v.m_value )
- TODO(v.get_pos(), "Handle break/continue values in HIR");
+ TODO(v.span(), "Handle break/continue values in HIR");
m_rv.reset( new ::HIR::ExprNode_LoopControl( v.span(), v.m_target, (v.m_type == ::AST::ExprNode_Flow::CONTINUE) ) );
break;
}
@@ -167,7 +167,7 @@ struct LowerHIR_ExprNode_Visitor:
}
break; }
case ::AST::ExprNode_BinOp::PLACE_IN:
- TODO(v.get_pos(), "Desugar placement syntax");
+ TODO(v.span(), "Desugar placement syntax");
break;
case ::AST::ExprNode_BinOp::CMPEQU : op = ::HIR::ExprNode_BinOp::Op::CmpEqu ; if(0)
@@ -213,7 +213,7 @@ struct LowerHIR_ExprNode_Visitor:
));
} break;
case ::AST::ExprNode_UniOp::QMARK:
- BUG(v.get_pos(), "Encounterd question mark operator (should have been expanded in AST)");
+ BUG(v.span(), "Encounterd question mark operator (should have been expanded in AST)");
break;
case ::AST::ExprNode_UniOp::REF:
@@ -262,7 +262,7 @@ struct LowerHIR_ExprNode_Visitor:
TU_MATCH_DEF(::AST::PathBinding, (v.m_path.binding()), (e),
(
m_rv.reset( new ::HIR::ExprNode_CallPath( v.span(),
- LowerHIR_Path(Span(v.get_pos()), v.m_path),
+ LowerHIR_Path(v.span(), v.m_path),
mv$( args )
) );
),
@@ -361,7 +361,7 @@ struct LowerHIR_ExprNode_Visitor:
break; }
case ::AST::ExprNode_Loop::FOR:
// NOTE: This should already be desugared (as a pass before resolve)
- BUG(v.get_pos(), "Encountered still-sugared for loop");
+ BUG(v.span(), "Encountered still-sugared for loop");
break;
}
@@ -507,7 +507,7 @@ struct LowerHIR_ExprNode_Visitor:
}
m_rv.reset( new ::HIR::ExprNode_Literal( v.span(),
::HIR::ExprNode_Literal::Data::make_Integer({
- H::get_type( Span(v.get_pos()), v.m_datatype ),
+ H::get_type( v.span(), v.m_datatype ),
v.m_value
})
) );
@@ -520,7 +520,7 @@ struct LowerHIR_ExprNode_Visitor:
case CORETYPE_F32: ct = ::HIR::CoreType::F32; break;
case CORETYPE_F64: ct = ::HIR::CoreType::F64; break;
default:
- BUG(v.get_pos(), "Unknown type for float literal");
+ BUG(v.span(), "Unknown type for float literal");
}
m_rv.reset( new ::HIR::ExprNode_Literal( v.span(),
::HIR::ExprNode_Literal::Data::make_Float({ ct, v.m_value })
@@ -560,7 +560,7 @@ struct LowerHIR_ExprNode_Visitor:
ERROR(v.span(), E0000, "Union constructors can't take a base value");
m_rv.reset( new ::HIR::ExprNode_UnionLiteral( v.span(),
- LowerHIR_GenericPath(v.get_pos(), v.m_path),
+ LowerHIR_GenericPath(v.span(), v.m_path),
v.m_values[0].first,
LowerHIR_ExprNode_Inner(*v.m_values[0].second)
) );
@@ -571,7 +571,7 @@ struct LowerHIR_ExprNode_Visitor:
for(const auto& val : v.m_values)
values.push_back( ::std::make_pair(val.first, LowerHIR_ExprNode_Inner(*val.second)) );
m_rv.reset( new ::HIR::ExprNode_StructLiteral( v.span(),
- LowerHIR_GenericPath(v.get_pos(), v.m_path),
+ LowerHIR_GenericPath(v.span(), v.m_path),
! v.m_path.binding().is_EnumVar(),
LowerHIR_ExprNode_Inner_Opt(v.m_base_value.get()),
mv$(values)
@@ -604,7 +604,7 @@ struct LowerHIR_ExprNode_Visitor:
virtual void visit(::AST::ExprNode_NamedValue& v) override {
TU_IFLET(::AST::Path::Class, v.m_path.m_class, Local, e,
if( !v.m_path.binding().is_Variable() ) {
- BUG(v.get_pos(), "Named value was a local, but wasn't bound - " << v.m_path);
+ BUG(v.span(), "Named value was a local, but wasn't bound - " << v.m_path);
}
auto slot = v.m_path.binding().as_Variable().slot;
m_rv.reset( new ::HIR::ExprNode_Variable( v.span(), e.name, slot ) );
@@ -612,7 +612,7 @@ struct LowerHIR_ExprNode_Visitor:
else {
TU_MATCH_DEF(::AST::PathBinding, (v.m_path.binding()), (e),
(
- auto p = LowerHIR_Path(Span(v.get_pos()), v.m_path);
+ auto p = LowerHIR_Path(v.span(), v.m_path);
if( p.m_data.is_Generic() ) {
BUG(v.span(), "Unknown binding for PathValue but path is generic - " << v.m_path);
}
@@ -643,10 +643,10 @@ struct LowerHIR_ExprNode_Visitor:
}
}
if( is_tuple_constructor ) {
- m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::STRUCT_CONSTR ) );
+ m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::STRUCT_CONSTR ) );
}
else {
- m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(Span(v.get_pos()), v.m_path), true ) );
+ m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), true ) );
}
),
(EnumVar,
@@ -680,33 +680,33 @@ struct LowerHIR_ExprNode_Visitor:
}
(void)var_idx; // TODO: Save time later by saving this.
if( is_tuple_constructor ) {
- m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::ENUM_VAR_CONSTR ) );
+ m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::ENUM_VAR_CONSTR ) );
}
else {
- m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(Span(v.get_pos()), v.m_path), false ) );
+ m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), false ) );
}
),
(Function,
- m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::FUNCTION ) );
+ m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::FUNCTION ) );
),
(Static,
if( e.static_ )
{
if( e.static_->s_class() != ::AST::Static::CONST ) {
- m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::STATIC ) );
+ m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::STATIC ) );
}
else {
- m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::CONSTANT ) );
+ m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::CONSTANT ) );
}
}
else if( e.hir )
{
- m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::STATIC ) );
+ m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::STATIC ) );
}
// HACK: If the HIR pointer is nullptr, then it refers to a `const
else
{
- m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::CONSTANT ) );
+ m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::CONSTANT ) );
}
)
)
@@ -739,7 +739,7 @@ struct LowerHIR_ExprNode_Visitor:
const_cast<::AST::ExprNode*>(&e)->visit( v );
if( ! v.m_rv ) {
- BUG(e.get_pos(), typeid(e).name() << " - Yielded a nullptr HIR node");
+ BUG(e.span(), typeid(e).name() << " - Yielded a nullptr HIR node");
}
return mv$( v.m_rv );
}
diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp
index 77e17dba..78efe261 100644
--- a/src/hir/serialise.cpp
+++ b/src/hir/serialise.cpp
@@ -77,6 +77,9 @@ namespace {
m_out.write_count(e.first);
serialise(e.second);
}
+ //void serialise(::MIR::BasicBlockId val) {
+ // m_out.write_count(val);
+ //}
void serialise_type(const ::HIR::TypeRef& ty)
{
@@ -457,8 +460,8 @@ namespace {
void serialise(const ::MIR::Function& mir)
{
// Write out MIR.
- serialise_vec( mir.named_variables );
- serialise_vec( mir.temporaries );
+ serialise_vec( mir.locals );
+ //serialise_vec( mir.slot_names );
serialise_vec( mir.drop_flags );
serialise_vec( mir.blocks );
}
@@ -498,8 +501,7 @@ namespace {
),
(ScopeEnd,
m_out.write_tag(4);
- serialise_vec(e.vars);
- serialise_vec(e.tmps);
+ serialise_vec(e.slots);
)
)
}
@@ -532,6 +534,12 @@ namespace {
for(auto t : e.targets)
m_out.write_count(t);
),
+ (SwitchValue,
+ serialise(e.val);
+ m_out.write_count(e.def_target);
+ serialise_vec(e.targets);
+ serialise(e.values);
+ ),
(Call,
m_out.write_count(e.ret_block);
m_out.write_count(e.panic_block);
@@ -541,6 +549,21 @@ namespace {
)
)
}
+ void serialise(const ::MIR::SwitchValues& sv)
+ {
+ m_out.write_tag( static_cast<int>(sv.tag()) );
+ TU_MATCHA( (sv), (e),
+ (Unsigned,
+ serialise_vec(e);
+ ),
+ (Signed,
+ serialise_vec(e);
+ ),
+ (String,
+ serialise_vec(e);
+ )
+ )
+ }
void serialise(const ::MIR::CallTarget& ct)
{
m_out.write_tag( static_cast<int>(ct.tag()) );
@@ -571,20 +594,17 @@ namespace {
TRACE_FUNCTION_F("LValue = "<<lv);
m_out.write_tag( static_cast<int>(lv.tag()) );
TU_MATCHA( (lv), (e),
- (Variable,
- m_out.write_count(e);
- ),
- (Temporary,
- m_out.write_count(e.idx);
+ (Return,
),
(Argument,
m_out.write_count(e.idx);
),
+ (Local,
+ m_out.write_count(e);
+ ),
(Static,
serialise_path(e);
),
- (Return,
- ),
(Field,
serialise(e.val);
m_out.write_count(e.field_index);
diff --git a/src/hir/type.cpp b/src/hir/type.cpp
index 7dd8dc80..c672b3bd 100644
--- a/src/hir/type.cpp
+++ b/src/hir/type.cpp
@@ -781,7 +781,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x
(Enum , return ::HIR::TypeRef::TypePathBinding(e); )
)
assert(!"Fell off end of clone_binding");
- throw "";
+ throw "";
}
diff --git a/src/hir/type.hpp b/src/hir/type.hpp
index a832e8e9..cc0894d2 100644
--- a/src/hir/type.hpp
+++ b/src/hir/type.hpp
@@ -178,8 +178,8 @@ public:
Data m_data;
TypeRef():
- m_data(Data::make_Infer({ ~0u, InferClass::None }))
- {}
+ m_data(Data::make_Infer({ ~0u, InferClass::None }))
+ {}
TypeRef(TypeRef&& ) = default;
TypeRef(const TypeRef& ) = delete;
TypeRef& operator=(TypeRef&& ) = default;
@@ -212,9 +212,9 @@ public:
static TypeRef new_diverge() {
return TypeRef(Data::make_Diverge({}));
}
- static TypeRef new_infer(unsigned int idx = ~0u, InferClass ty_class = InferClass::None) {
- return TypeRef(Data::make_Infer({idx, ty_class}));
- }
+ static TypeRef new_infer(unsigned int idx = ~0u, InferClass ty_class = InferClass::None) {
+ return TypeRef(Data::make_Infer({idx, ty_class}));
+ }
static TypeRef new_borrow(BorrowType bt, TypeRef inner) {
return TypeRef(Data::make_Borrow({bt, box$(mv$(inner))}));
}
diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp
index cf443eb6..beac3b84 100644
--- a/src/hir_conv/bind.cpp
+++ b/src/hir_conv/bind.cpp
@@ -480,14 +480,12 @@ namespace {
static void visit_lvalue(Visitor& upper_visitor, ::MIR::LValue& lv)
{
TU_MATCHA( (lv), (e),
- (Variable,
+ (Return,
),
- (Temporary,
+ (Local,
),
(Argument,
),
- (Return,
- ),
(Static,
upper_visitor.visit_path(e, ::HIR::Visitor::PathContext::VALUE);
),
@@ -529,9 +527,7 @@ namespace {
)
}
};
- for(auto& ty : expr.m_mir->named_variables)
- this->visit_type(ty);
- for(auto& ty : expr.m_mir->temporaries)
+ for(auto& ty : expr.m_mir->locals)
this->visit_type(ty);
for(auto& block : expr.m_mir->blocks)
{
@@ -621,6 +617,9 @@ namespace {
(Switch,
H::visit_lvalue(*this, te.val);
),
+ (SwitchValue,
+ H::visit_lvalue(*this, te.val);
+ ),
(Call,
H::visit_lvalue(*this, te.ret_val);
TU_MATCHA( (te.fcn), (e2),
diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp
index a950a3dd..e8138169 100644
--- a/src/hir_conv/constant_evaluation.cpp
+++ b/src/hir_conv/constant_evaluation.cpp
@@ -1026,32 +1026,25 @@ namespace {
::MIR::TypeResolve state { sp, resolve, FMT_CB(,), exp, {}, fcn };
::HIR::Literal retval;
- ::std::vector< ::HIR::Literal> locals;
- ::std::vector< ::HIR::Literal> temps;
- locals.resize( fcn.named_variables.size() );
- temps.resize( fcn.temporaries.size() );
+ ::std::vector< ::HIR::Literal> locals( fcn.locals.size() );
auto get_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal& {
TU_MATCHA( (lv), (e),
- (Variable,
- if( e >= locals.size() )
- BUG(sp, "Local index out of range - " << e << " >= " << locals.size());
- return locals[e];
- ),
- (Temporary,
- if( e.idx >= temps.size() )
- BUG(sp, "Temp index out of range - " << e.idx << " >= " << temps.size());
- return temps[e.idx];
+ (Return,
+ return retval;
),
(Argument,
+ ASSERT_BUG(sp, e.idx < args.size(), "Argument index out of range - " << e.idx << " >= " << args.size());
return args[e.idx];
),
+ (Local,
+ if( e >= locals.size() )
+ BUG(sp, "Local index out of range - " << e << " >= " << locals.size());
+ return locals[e];
+ ),
(Static,
TODO(sp, "LValue::Static");
),
- (Return,
- return retval;
- ),
(Field,
TODO(sp, "LValue::Field");
),
diff --git a/src/hir_expand/const_eval_full.cpp b/src/hir_expand/const_eval_full.cpp
index 538693f4..04575a6e 100644
--- a/src/hir_expand/const_eval_full.cpp
+++ b/src/hir_expand/const_eval_full.cpp
@@ -292,49 +292,41 @@ namespace {
::MIR::TypeResolve state { sp, resolve, name, ::HIR::TypeRef(), {}, fcn };
::HIR::Literal retval;
- ::std::vector< ::HIR::Literal> locals;
- ::std::vector< ::HIR::Literal> temps;
- locals.resize( fcn.named_variables.size() );
- temps.resize( fcn.temporaries.size() );
+ ::std::vector< ::HIR::Literal> locals( fcn.locals.size() );
struct LocalState {
typedef ::std::vector< ::HIR::Literal> t_vec_lit;
::MIR::TypeResolve& state;
::HIR::Literal& retval;
- ::std::vector< ::HIR::Literal>& locals;
- ::std::vector< ::HIR::Literal>& temps;
::std::vector< ::HIR::Literal>& args;
+ ::std::vector< ::HIR::Literal>& locals;
- LocalState(::MIR::TypeResolve& state, ::HIR::Literal& retval, t_vec_lit& locals, t_vec_lit& temps, t_vec_lit& args):
+ LocalState(::MIR::TypeResolve& state, ::HIR::Literal& retval, t_vec_lit& args, t_vec_lit& locals):
state(state),
retval(retval),
- locals(locals),
- temps(temps),
- args(args)
+ args(args),
+ locals(locals)
{}
::HIR::Literal& get_lval(const ::MIR::LValue& lv)
{
TU_MATCHA( (lv), (e),
- (Variable,
+ (Return,
+ return retval;
+ ),
+ (Local,
if( e >= locals.size() )
MIR_BUG(state, "Local index out of range - " << e << " >= " << locals.size());
return locals[e];
),
- (Temporary,
- if( e.idx >= temps.size() )
- MIR_BUG(state, "Temp index out of range - " << e.idx << " >= " << temps.size());
- return temps[e.idx];
- ),
(Argument,
+ if( e.idx >= args.size() )
+ MIR_BUG(state, "Local index out of range - " << e.idx << " >= " << args.size());
return args[e.idx];
),
(Static,
MIR_TODO(state, "LValue::Static - " << e);
),
- (Return,
- return retval;
- ),
(Field,
auto& val = get_lval(*e.val);
MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv);
@@ -362,7 +354,7 @@ namespace {
throw "";
}
};
- LocalState local_state( state, retval, locals, temps, args );
+ LocalState local_state( state, retval, args, locals );
auto get_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal& { return local_state.get_lval(lv); };
auto read_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal {
diff --git a/src/hir_expand/erased_types.cpp b/src/hir_expand/erased_types.cpp
index aca58207..caf42a79 100644
--- a/src/hir_expand/erased_types.cpp
+++ b/src/hir_expand/erased_types.cpp
@@ -14,21 +14,23 @@
const ::HIR::Function& HIR_Expand_ErasedType_GetFunction(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::Path& origin_path, t_cb_generic& monomorph_cb, ::HIR::PathParams& impl_params)
{
const ::HIR::Function* fcn_ptr = nullptr;
- switch(origin_path.m_data.tag())
- {
- case ::HIR::Path::Data::TAG_UfcsUnknown:
- BUG(Span(), "UfcsUnknown in ErasedType - " << origin_path);
- case ::HIR::Path::Data::TAG_Generic: {
- const auto& pe = origin_path.m_data.as_Generic();
- monomorph_cb = monomorphise_type_get_cb(sp, nullptr, nullptr, &pe.m_params);
- fcn_ptr = &resolve.m_crate.get_function_by_path(sp, pe.m_path);
- } break;
- case ::HIR::Path::Data::TAG_UfcsKnown:
- // NOTE: This isn't possible yet (will it be? or will it expand to an associated type?)
- TODO(sp, "Replace ErasedType - " << origin_path << " with source (UfcsKnown)");
- break;
- case ::HIR::Path::Data::TAG_UfcsInherent: {
- const auto& pe = origin_path.m_data.as_UfcsInherent();
+ switch(origin_path.m_data.tag())
+ {
+ case ::HIR::Path::Data::TAGDEAD:
+ BUG(Span(), "DEAD in ErasedType - " << origin_path);
+ case ::HIR::Path::Data::TAG_UfcsUnknown:
+ BUG(Span(), "UfcsUnknown in ErasedType - " << origin_path);
+ case ::HIR::Path::Data::TAG_Generic: {
+ const auto& pe = origin_path.m_data.as_Generic();
+ monomorph_cb = monomorphise_type_get_cb(sp, nullptr, nullptr, &pe.m_params);
+ fcn_ptr = &resolve.m_crate.get_function_by_path(sp, pe.m_path);
+ } break;
+ case ::HIR::Path::Data::TAG_UfcsKnown:
+ // NOTE: This isn't possible yet (will it be? or will it expand to an associated type?)
+ TODO(sp, "Replace ErasedType - " << origin_path << " with source (UfcsKnown)");
+ break;
+ case ::HIR::Path::Data::TAG_UfcsInherent: {
+ const auto& pe = origin_path.m_data.as_UfcsInherent();
// 1. Find correct impl block for the path
const ::HIR::TypeImpl* impl_ptr = nullptr;
resolve.m_crate.find_type_impls(*pe.type, [&](const auto& ty)->const auto& { return ty; },
@@ -52,16 +54,16 @@ const ::HIR::Function& HIR_Expand_ErasedType_GetFunction(const Span& sp, const S
return ::HIR::Compare::Equal;
});
for(const auto& t : impl_params.m_types)
- {
+ {
if( t == ::HIR::TypeRef() )
- {
+ {
TODO(sp, "Handle ErasedType where an impl parameter comes from a bound - " << origin_path);
- }
- }
+ }
+ }
monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &impl_params, &pe.params);
- } break;
- }
+ } break;
+ }
assert(fcn_ptr);
return *fcn_ptr;
}
diff --git a/src/hir_expand/ufcs_everything.cpp b/src/hir_expand/ufcs_everything.cpp
index 44921105..adae855c 100644
--- a/src/hir_expand/ufcs_everything.cpp
+++ b/src/hir_expand/ufcs_everything.cpp
@@ -289,7 +289,7 @@ namespace {
ASSERT_BUG(sp, ty_slot == ty_val, "Types must equal for non-operator assignment, " << ty_slot << " != " << ty_val);
return ;
_(Shr): {langitem = "shr_assign"; opname = "shr_assign"; } if(0)
- _(Shl): {langitem = "shl_assign"; opname = "shl_assign"; }
+ _(Shl): {langitem = "shl_assign"; opname = "shl_assign"; }
if( is_op_valid_shift(ty_slot, ty_val) ) {
return ;
}
@@ -385,8 +385,8 @@ namespace {
auto ty_r_ref = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ty_r.clone() );
::std::vector< ::HIR::ExprNodeP> args;
- auto sp_left = node.m_left ->span();
- auto sp_right = node.m_right->span();
+ auto sp_left = node.m_left ->span();
+ auto sp_right = node.m_right->span();
args.push_back(NEWNODE(ty_l_ref.clone(), Borrow, sp_left , ::HIR::BorrowType::Shared, mv$(node.m_left ) ));
args.push_back(NEWNODE(ty_r_ref.clone(), Borrow, sp_right, ::HIR::BorrowType::Shared, mv$(node.m_right) ));
diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp
index fe67865f..a5d34186 100644
--- a/src/hir_typeck/expr_check.cpp
+++ b/src/hir_typeck/expr_check.cpp
@@ -640,7 +640,7 @@ namespace {
fcn_ptr = &fcn;
- monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &trait_params, &path_params);
+ monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &trait_params, &path_params);
),
(UfcsUnknown,
TODO(sp, "Hit a UfcsUnknown (" << path << ") - Is this an error?");
@@ -672,7 +672,7 @@ namespace {
// Create monomorphise callback
const auto& fcn_params = e.params;
- monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &impl_params, &fcn_params);
+ monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &impl_params, &fcn_params);
)
)
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index eb922414..de7f05ec 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -1643,9 +1643,7 @@ namespace {
(Function,
fix_param_count(sp, this->context, *e.type, false, node.m_path, ie.m_params, e.params);
- const auto& fcn_params = e.params;
- const auto& trait_params = e.trait.m_params;
- auto monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &e.trait.m_params, &e.params);
+ auto monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &e.trait.m_params, &e.params);
::HIR::FunctionType ft {
ie.m_unsafe, ie.m_abi,
box$( monomorphise_type_with(sp, ie.m_return, monomorph_cb) ),
@@ -2368,148 +2366,148 @@ namespace {
const auto& ty = *ty_p;
DEBUG("- ty = " << ty);
- if( const auto* e = ty.m_data.opt_Closure() )
- {
- for( const auto& arg : e->m_arg_types )
- node.m_arg_types.push_back(arg.clone());
- node.m_arg_types.push_back(e->m_rettype->clone());
- node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Unknown;
- }
- else if( const auto* e = ty.m_data.opt_Function() )
- {
- for( const auto& arg : e->m_arg_types )
- node.m_arg_types.push_back(arg.clone());
- node.m_arg_types.push_back(e->m_rettype->clone());
- node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Fn;
- }
- else if( ty.m_data.is_Infer() )
- {
- // No idea yet
- return ;
- }
- else
- {
- ::HIR::TypeRef fcn_args_tup;
- ::HIR::TypeRef fcn_ret;
-
- // TODO: Use `find_trait_impls` instead of two different calls
- // - This will get the TraitObject impl search too
-
- // Locate an impl of FnOnce (exists for all other Fn* traits)
- unsigned int count = 0;
- this->context.m_resolve.find_trait_impls(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp)->bool {
- count++;
-
- auto tup = impl.get_trait_ty_param(0);
- if (!tup.m_data.is_Tuple())
- ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup);
- fcn_args_tup = mv$(tup);
-
- fcn_ret = impl.get_type("Output");
- DEBUG("[visit:_CallValue] fcn_args_tup=" << fcn_args_tup << ", fcn_ret=" << fcn_ret);
- return cmp == ::HIR::Compare::Equal;
- });
- DEBUG("Found " << count << " impls of FnOnce");
- if(count > 1) {
- return;
- }
- if(count == 1)
- {
-
- // 3. Locate the most permissive implemented Fn* trait (Fn first, then FnMut, then assume just FnOnce)
- // NOTE: Borrowing is added by the expansion to CallPath
- if( this->context.m_resolve.find_trait_impls(node.span(), lang_Fn, trait_pp, ty, [&](auto impl, auto cmp) {
- // TODO: Take the value of `cmp` into account
- fcn_ret = impl.get_type("Output");
- return true;
- //return cmp == ::HIR::Compare::Equal;
- }) )
- {
- DEBUG("-- Using Fn");
- node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Fn;
-
- this->context.equate_types_assoc(node.span(), node.m_res_type, lang_Fn, ::make_vec1(fcn_args_tup.clone()), ty, "Output");
- }
- else if( this->context.m_resolve.find_trait_impls(node.span(), lang_FnMut, trait_pp, ty, [&](auto impl, auto cmp) {
- // TODO: Take the value of `cmp` into account
- fcn_ret = impl.get_type("Output");
- return true;
- //return cmp == ::HIR::Compare::Equal;
- }) )
- {
- DEBUG("-- Using FnMut");
- node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::FnMut;
-
- this->context.equate_types_assoc(node.span(), node.m_res_type, lang_FnMut, ::make_vec1(fcn_args_tup.clone()), ty, "Output");
- }
- else
- {
- DEBUG("-- Using FnOnce (default)");
- node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::FnOnce;
-
- this->context.equate_types_assoc(node.span(), node.m_res_type, lang_FnOnce, ::make_vec1(fcn_args_tup.clone()), ty, "Output");
- }
-
- // If the return type wasn't found in the impls, emit it as a UFCS
- if(fcn_ret == ::HIR::TypeRef())
- {
- fcn_ret = ::HIR::TypeRef(::HIR::Path(::HIR::Path::Data::make_UfcsKnown({
- box$(ty.clone()),
- // - Clone argument tuple, as it's stolen into cache below
- ::HIR::GenericPath(lang_FnOnce, ::HIR::PathParams(fcn_args_tup.clone())),
- "Output",
- {}
- })));
- }
- }
- else if( const auto* e = ty.m_data.opt_Borrow() )
- {
- deref_count++;
- ty_p = &this->context.get_type(*e->inner);
- DEBUG("Deref " << ty << " -> " << *ty_p);
- keep_looping = true;
- continue;
- }
- else
- {
- if( !ty.m_data.is_Generic() )
- {
- bool found = this->context.m_resolve.find_trait_impls_crate(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp)->bool {
- if (cmp == ::HIR::Compare::Fuzzy)
- TODO(node.span(), "Handle fuzzy match - " << impl);
-
- auto tup = impl.get_trait_ty_param(0);
- if (!tup.m_data.is_Tuple())
- ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup);
- fcn_args_tup = mv$(tup);
- fcn_ret = impl.get_type("Output");
- ASSERT_BUG(node.span(), fcn_ret != ::HIR::TypeRef(), "Impl didn't have a type for Output - " << impl);
- return true;
- });
- if (found) {
- // Fill cache and leave the TU_MATCH
- node.m_arg_types = mv$(fcn_args_tup.m_data.as_Tuple());
- node.m_arg_types.push_back(mv$(fcn_ret));
- node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Unknown;
- break; // leaves TU_MATCH
- }
- }
- if( const auto* next_ty_p = this->context.m_resolve.autoderef(node.span(), ty, tmp_type) )
- {
- DEBUG("Deref (autoderef) " << ty << " -> " << *next_ty_p);
- deref_count++;
- ty_p = next_ty_p;
- keep_looping = true;
- continue;
- }
-
- // Didn't find anything. Error?
- ERROR(node.span(), E0000, "Unable to find an implementation of Fn*" << trait_pp << " for " << this->context.m_ivars.fmt_type(ty));
- }
-
- node.m_arg_types = mv$(fcn_args_tup.m_data.as_Tuple());
- node.m_arg_types.push_back(mv$(fcn_ret));
- }
+ if( const auto* e = ty.m_data.opt_Closure() )
+ {
+ for( const auto& arg : e->m_arg_types )
+ node.m_arg_types.push_back(arg.clone());
+ node.m_arg_types.push_back(e->m_rettype->clone());
+ node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Unknown;
+ }
+ else if( const auto* e = ty.m_data.opt_Function() )
+ {
+ for( const auto& arg : e->m_arg_types )
+ node.m_arg_types.push_back(arg.clone());
+ node.m_arg_types.push_back(e->m_rettype->clone());
+ node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Fn;
+ }
+ else if( ty.m_data.is_Infer() )
+ {
+ // No idea yet
+ return ;
+ }
+ else
+ {
+ ::HIR::TypeRef fcn_args_tup;
+ ::HIR::TypeRef fcn_ret;
+
+ // TODO: Use `find_trait_impls` instead of two different calls
+ // - This will get the TraitObject impl search too
+
+ // Locate an impl of FnOnce (exists for all other Fn* traits)
+ unsigned int count = 0;
+ this->context.m_resolve.find_trait_impls(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp)->bool {
+ count++;
+
+ auto tup = impl.get_trait_ty_param(0);
+ if (!tup.m_data.is_Tuple())
+ ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup);
+ fcn_args_tup = mv$(tup);
+
+ fcn_ret = impl.get_type("Output");
+ DEBUG("[visit:_CallValue] fcn_args_tup=" << fcn_args_tup << ", fcn_ret=" << fcn_ret);
+ return cmp == ::HIR::Compare::Equal;
+ });
+ DEBUG("Found " << count << " impls of FnOnce");
+ if(count > 1) {
+ return;
+ }
+ if(count == 1)
+ {
+
+ // 3. Locate the most permissive implemented Fn* trait (Fn first, then FnMut, then assume just FnOnce)
+ // NOTE: Borrowing is added by the expansion to CallPath
+ if( this->context.m_resolve.find_trait_impls(node.span(), lang_Fn, trait_pp, ty, [&](auto impl, auto cmp) {
+ // TODO: Take the value of `cmp` into account
+ fcn_ret = impl.get_type("Output");
+ return true;
+ //return cmp == ::HIR::Compare::Equal;
+ }) )
+ {
+ DEBUG("-- Using Fn");
+ node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Fn;
+
+ this->context.equate_types_assoc(node.span(), node.m_res_type, lang_Fn, ::make_vec1(fcn_args_tup.clone()), ty, "Output");
+ }
+ else if( this->context.m_resolve.find_trait_impls(node.span(), lang_FnMut, trait_pp, ty, [&](auto impl, auto cmp) {
+ // TODO: Take the value of `cmp` into account
+ fcn_ret = impl.get_type("Output");
+ return true;
+ //return cmp == ::HIR::Compare::Equal;
+ }) )
+ {
+ DEBUG("-- Using FnMut");
+ node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::FnMut;
+
+ this->context.equate_types_assoc(node.span(), node.m_res_type, lang_FnMut, ::make_vec1(fcn_args_tup.clone()), ty, "Output");
+ }
+ else
+ {
+ DEBUG("-- Using FnOnce (default)");
+ node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::FnOnce;
+
+ this->context.equate_types_assoc(node.span(), node.m_res_type, lang_FnOnce, ::make_vec1(fcn_args_tup.clone()), ty, "Output");
+ }
+
+ // If the return type wasn't found in the impls, emit it as a UFCS
+ if(fcn_ret == ::HIR::TypeRef())
+ {
+ fcn_ret = ::HIR::TypeRef(::HIR::Path(::HIR::Path::Data::make_UfcsKnown({
+ box$(ty.clone()),
+ // - Clone argument tuple, as it's stolen into cache below
+ ::HIR::GenericPath(lang_FnOnce, ::HIR::PathParams(fcn_args_tup.clone())),
+ "Output",
+ {}
+ })));
+ }
+ }
+ else if( const auto* e = ty.m_data.opt_Borrow() )
+ {
+ deref_count++;
+ ty_p = &this->context.get_type(*e->inner);
+ DEBUG("Deref " << ty << " -> " << *ty_p);
+ keep_looping = true;
+ continue;
+ }
+ else
+ {
+ if( !ty.m_data.is_Generic() )
+ {
+ bool found = this->context.m_resolve.find_trait_impls_crate(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp)->bool {
+ if (cmp == ::HIR::Compare::Fuzzy)
+ TODO(node.span(), "Handle fuzzy match - " << impl);
+
+ auto tup = impl.get_trait_ty_param(0);
+ if (!tup.m_data.is_Tuple())
+ ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup);
+ fcn_args_tup = mv$(tup);
+ fcn_ret = impl.get_type("Output");
+ ASSERT_BUG(node.span(), fcn_ret != ::HIR::TypeRef(), "Impl didn't have a type for Output - " << impl);
+ return true;
+ });
+ if (found) {
+ // Fill cache and leave the TU_MATCH
+ node.m_arg_types = mv$(fcn_args_tup.m_data.as_Tuple());
+ node.m_arg_types.push_back(mv$(fcn_ret));
+ node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Unknown;
+ break; // leaves TU_MATCH
+ }
+ }
+ if( const auto* next_ty_p = this->context.m_resolve.autoderef(node.span(), ty, tmp_type) )
+ {
+ DEBUG("Deref (autoderef) " << ty << " -> " << *next_ty_p);
+ deref_count++;
+ ty_p = next_ty_p;
+ keep_looping = true;
+ continue;
+ }
+
+ // Didn't find anything. Error?
+ ERROR(node.span(), E0000, "Unable to find an implementation of Fn*" << trait_pp << " for " << this->context.m_ivars.fmt_type(ty));
+ }
+
+ node.m_arg_types = mv$(fcn_args_tup.m_data.as_Tuple());
+ node.m_arg_types.push_back(mv$(fcn_ret));
+ }
} while( keep_looping );
if( deref_count > 0 )
diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp
index a3fe9b1c..c860c6ce 100644
--- a/src/hir_typeck/helpers.cpp
+++ b/src/hir_typeck/helpers.cpp
@@ -436,7 +436,7 @@ void HMTypeInferrence::add_ivars(::HIR::TypeRef& type)
e.index = this->new_ivar();
this->get_type(type).m_data.as_Infer().ty_class = e.ty_class;
this->mark_change();
- DEBUG("New ivar " << type);
+ DEBUG("New ivar " << type);
}
),
(Diverge,
@@ -2020,7 +2020,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp,
ERROR(sp, E0000, "Couldn't find assocated type " << pe.item << " in " << pe.trait);
if( impl.has_magic_params() ) {
- }
+ }
// TODO: What if there's multiple impls?
DEBUG("Converted UfcsKnown - " << e.path << " = " << ty);
diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp
index d8b692c9..0067eb7f 100644
--- a/src/hir_typeck/static.cpp
+++ b/src/hir_typeck/static.cpp
@@ -331,39 +331,39 @@ bool StaticTraitResolve::find_impl(
if( m_crate.get_trait_by_path(sp, trait_path).m_is_marker )
{
- struct H {
- static bool find_impl__auto_trait_check(const StaticTraitResolve& self,
- const Span& sp, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams* trait_params, const ::HIR::TypeRef& type,
- t_cb_find_impl found_cb,
- const ::HIR::MarkerImpl& impl, bool& out_rv
- )
- {
- DEBUG("- Auto " << (impl.is_positive ? "Pos" : "Neg")
- << " impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " " << impl.m_params.fmt_bounds());
- if (impl.is_positive)
- {
- return self.find_impl__check_crate_raw(sp, trait_path, trait_params, type, impl.m_params, impl.m_trait_args, impl.m_type,
- [&](auto impl_params, auto placeholders, auto cmp)->bool {
- //rv = found_cb( ImplRef(impl_params, trait_path, impl, mv$(placeholders)), (cmp == ::HIR::Compare::Fuzzy) );
- out_rv = found_cb(ImplRef(&type, trait_params, &null_assoc), cmp == ::HIR::Compare::Fuzzy);
- return out_rv;
- });
- }
- else
- {
- return self.find_impl__check_crate_raw(sp, trait_path, trait_params, type, impl.m_params, impl.m_trait_args, impl.m_type,
- [&](auto impl_params, auto placeholders, auto cmp)->bool {
- out_rv = false;
- return true;
- });
- }
- }
- };
+ struct H {
+ static bool find_impl__auto_trait_check(const StaticTraitResolve& self,
+ const Span& sp, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams* trait_params, const ::HIR::TypeRef& type,
+ t_cb_find_impl found_cb,
+ const ::HIR::MarkerImpl& impl, bool& out_rv
+ )
+ {
+ DEBUG("- Auto " << (impl.is_positive ? "Pos" : "Neg")
+ << " impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " " << impl.m_params.fmt_bounds());
+ if (impl.is_positive)
+ {
+ return self.find_impl__check_crate_raw(sp, trait_path, trait_params, type, impl.m_params, impl.m_trait_args, impl.m_type,
+ [&](auto impl_params, auto placeholders, auto cmp)->bool {
+ //rv = found_cb( ImplRef(impl_params, trait_path, impl, mv$(placeholders)), (cmp == ::HIR::Compare::Fuzzy) );
+ out_rv = found_cb(ImplRef(&type, trait_params, &null_assoc), cmp == ::HIR::Compare::Fuzzy);
+ return out_rv;
+ });
+ }
+ else
+ {
+ return self.find_impl__check_crate_raw(sp, trait_path, trait_params, type, impl.m_params, impl.m_trait_args, impl.m_type,
+ [&](auto impl_params, auto placeholders, auto cmp)->bool {
+ out_rv = false;
+ return true;
+ });
+ }
+ }
+ };
// Positive/negative impls
bool rv = false;
ret = this->m_crate.find_auto_trait_impls(trait_path, type, cb_ident, [&](const auto& impl)->bool {
- return H::find_impl__auto_trait_check(*this, sp, trait_path, trait_params, type, found_cb, impl, rv);
+ return H::find_impl__auto_trait_check(*this, sp, trait_path, trait_params, type, found_cb, impl, rv);
});
if(ret)
return rv;
@@ -592,9 +592,9 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
// Bounds
for(const auto& bound : impl_params_def.m_bounds) {
- if( const auto* ep = bound.opt_TraitBound() )
- {
- const auto& e = *ep;
+ if( const auto* ep = bound.opt_TraitBound() )
+ {
+ const auto& e = *ep;
DEBUG("Trait bound " << e.type << " : " << e.trait);
auto b_ty_mono = monomorphise_type_with(sp, e.type, cb_monomorph);
@@ -665,11 +665,11 @@ bool StaticTraitResolve::find_impl__check_crate_raw(
return false;
}
}
- }
- else // bound.opt_TraitBound()
- {
- // Ignore
- }
+ }
+ else // bound.opt_TraitBound()
+ {
+ // Ignore
+ }
}
return found_cb( mv$(impl_params), mv$(placeholders), match );
@@ -705,9 +705,9 @@ bool StaticTraitResolve::find_impl__check_crate(
};
// - If the type is a path (struct/enum/...), search for impls for all contained types.
- if( const auto* ep = type.m_data.opt_Path() )
- {
- const auto& e = *ep;
+ if( const auto* ep = type.m_data.opt_Path() )
+ {
+ const auto& e = *ep;
::HIR::Compare res = ::HIR::Compare::Equal;
TU_MATCH( ::HIR::Path::Data, (e.path.m_data), (pe),
(Generic,
@@ -828,9 +828,9 @@ bool StaticTraitResolve::find_impl__check_crate(
)
)
return res;
- }
- else if( const auto* ep = type.m_data.opt_Tuple() )
- {
+ }
+ else if( const auto* ep = type.m_data.opt_Tuple() )
+ {
::HIR::Compare res = ::HIR::Compare::Equal;
for(const auto& sty : *ep)
{
@@ -839,11 +839,11 @@ bool StaticTraitResolve::find_impl__check_crate(
return ::HIR::Compare::Unequal;
}
return res;
- }
+ }
else if( const auto* e = type.m_data.opt_Array() )
- {
+ {
return type_impls_trait(*e->inner);
- }
+ }
// Otherwise, there's no negative so it must be positive
else {
return ::HIR::Compare::Equal;
@@ -986,9 +986,9 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI
bool rv;
bool assume_opaque = true;
rv = this->iterate_bounds([&](const auto& b)->bool {
- if( const auto* bep = b.opt_TraitBound() )
- {
- const auto& be = *bep;
+ if( const auto* bep = b.opt_TraitBound() )
+ {
+ const auto& be = *bep;
DEBUG("Trait bound - " << be.type << " : " << be.trait);
// 1. Check if the type matches
// - TODO: This should be a fuzzier match?
@@ -1040,20 +1040,20 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI
}
// - Didn't match
- }
- else if( const auto* bep = b.opt_TypeEquality() )
- {
- const auto& be = *bep;
+ }
+ else if( const auto* bep = b.opt_TypeEquality() )
+ {
+ const auto& be = *bep;
DEBUG("Equality - " << be.type << " = " << be.other_type);
if( input == be.type ) {
input = be.other_type.clone();
return true;
}
- }
- else
- {
- // Nothing.
- }
+ }
+ else
+ {
+ // Nothing.
+ }
return false;
});
if( rv ) {
@@ -1670,6 +1670,7 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR
TU_MATCH(::HIR::TypeRef::Data, (ty.m_data), (e),
(Generic,
+ // TODO: Is this an error?
return true;
),
(Path,
@@ -1797,7 +1798,7 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR
(Tuple,
for(const auto& ty : e)
{
- if( !type_needs_drop_glue(sp, ty) )
+ if( type_needs_drop_glue(sp, ty) )
return true;
}
return false;
diff --git a/src/include/debug.hpp b/src/include/debug.hpp
index 2bbecb39..2f593cfb 100644
--- a/src/include/debug.hpp
+++ b/src/include/debug.hpp
@@ -42,10 +42,10 @@ class NullSink
{
public:
NullSink()
- {}
+ {}
- template<typename T>
- const NullSink& operator<<(const T&) const { return *this; }
+ template<typename T>
+ const NullSink& operator<<(const T&) const { return *this; }
};
class TraceLog
@@ -62,9 +62,9 @@ public:
struct FmtLambda
{
::std::function<void(::std::ostream&)> m_cb;
- FmtLambda(::std::function<void(::std::ostream&)> cb):
- m_cb(cb)
- { }
+ FmtLambda(::std::function<void(::std::ostream&)> cb):
+ m_cb(cb)
+ { }
friend ::std::ostream& operator<<(::std::ostream& os, const FmtLambda& x) {
x.m_cb(os);
return os;
diff --git a/src/include/span.hpp b/src/include/span.hpp
index 11ffc005..59c960fc 100644
--- a/src/include/span.hpp
+++ b/src/include/span.hpp
@@ -9,6 +9,7 @@
#include <rc_string.hpp>
#include <functional>
+#include <memory>
enum ErrorType
{
@@ -30,6 +31,7 @@ struct ProtoSpan
};
struct Span
{
+ ::std::shared_ptr<Span> outer_span; // Expansion target for macros
RcString filename;
unsigned int start_line;
diff --git a/src/include/synext_decorator.hpp b/src/include/synext_decorator.hpp
index 4988c624..77b55710 100644
--- a/src/include/synext_decorator.hpp
+++ b/src/include/synext_decorator.hpp
@@ -63,19 +63,19 @@ extern void Register_Synext_Decorator_Static(DecoratorDef* def);
struct DecoratorDef
{
- DecoratorDef* prev;
- ::std::string name;
- ::std::unique_ptr<ExpandDecorator> def;
- DecoratorDef(::std::string name, ::std::unique_ptr<ExpandDecorator> def):
- name(::std::move(name)),
- def(::std::move(def)),
- prev(nullptr)
- {
- Register_Synext_Decorator_Static(this);
- }
+ DecoratorDef* prev;
+ ::std::string name;
+ ::std::unique_ptr<ExpandDecorator> def;
+ DecoratorDef(::std::string name, ::std::unique_ptr<ExpandDecorator> def):
+ prev(nullptr),
+ name(::std::move(name)),
+ def(::std::move(def))
+ {
+ Register_Synext_Decorator_Static(this);
+ }
};
-#define STATIC_DECORATOR(ident, _handler_class) static DecoratorDef s_register_##_handler_class ( ident, ::std::unique_ptr<ExpandDecorator>(new _handler_class()) );
+#define STATIC_DECORATOR(ident, _handler_class) static DecoratorDef s_register_##_handler_class ( ident, ::std::unique_ptr<ExpandDecorator>(new _handler_class()) );
#endif
diff --git a/src/include/synext_macro.hpp b/src/include/synext_macro.hpp
index c109b56e..0359d508 100644
--- a/src/include/synext_macro.hpp
+++ b/src/include/synext_macro.hpp
@@ -31,19 +31,19 @@ extern void Register_Synext_Macro_Static(MacroDef* def);
struct MacroDef
{
- MacroDef* prev;
- ::std::string name;
- ::std::unique_ptr<ExpandProcMacro> def;
- MacroDef(::std::string name, ::std::unique_ptr<ExpandProcMacro> def) :
- name(::std::move(name)),
- def(::std::move(def)),
- prev(nullptr)
- {
- Register_Synext_Macro_Static(this);
- }
+ MacroDef* prev;
+ ::std::string name;
+ ::std::unique_ptr<ExpandProcMacro> def;
+ MacroDef(::std::string name, ::std::unique_ptr<ExpandProcMacro> def) :
+ prev(nullptr),
+ name(::std::move(name)),
+ def(::std::move(def))
+ {
+ Register_Synext_Macro_Static(this);
+ }
};
-#define STATIC_MACRO(ident, _handler_class) static MacroDef s_register_##_handler_class(ident, ::std::unique_ptr<ExpandProcMacro>(new _handler_class()));
+#define STATIC_MACRO(ident, _handler_class) static MacroDef s_register_##_handler_class(ident, ::std::unique_ptr<ExpandProcMacro>(new _handler_class()));
#endif
diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp
index fbd42a77..f30cb7f2 100644
--- a/src/include/tagged_union.hpp
+++ b/src/include/tagged_union.hpp
@@ -13,13 +13,13 @@
#include <string>
#define TU_FIRST(a, ...) a
-#define TU_EXP1(x) x
+#define TU_EXP1(x) x
#define TU_EXP(...) __VA_ARGS__
-#define TU_CASE_ITEM(src, mod, var, name) mod auto& name = src.as_##var(); (void)&name;
-#define TU_CASE_BODY(class,var, ...) case class::var: { __VA_ARGS__ } break;
-#define TU_CASE(mod, class, var, name,src, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(src,mod,var,name) __VA_ARGS__)
-#define TU_CASE2(mod, class, var, n1,s1, n2,s2, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(s1,mod,var,n1) TU_CASE_ITEM(s2,mod,var,n2) __VA_ARGS__)
+#define TU_CASE_ITEM(src, mod, var, name) mod auto& name = src.as_##var(); (void)&name;
+#define TU_CASE_BODY(class,var, ...) case class::var: { __VA_ARGS__ } break;
+#define TU_CASE(mod, class, var, name,src, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(src,mod,var,name) __VA_ARGS__)
+#define TU_CASE2(mod, class, var, n1,s1, n2,s2, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(s1,mod,var,n1) TU_CASE_ITEM(s2,mod,var,n2) __VA_ARGS__)
// Argument iteration
@@ -31,7 +31,7 @@
#define TU_DISP5(n, a1,a2,a3, b1,b2 ) TU_DISP3(n, a1,a2,a3) TU_DISP2(n, b1,b2)
#define TU_DISP6(n, a1,a2,a3, b1,b2,b3) TU_DISP3(n, a1,a2,a3) TU_DISP3(n, b1,b2,b3)
#define TU_DISP7(n, a1,a2,a3,a4, b1,b2,b3 ) TU_DISP4(n, a1,a2,a3,a4) TU_DISP3(n, b1,b2,b3)
-#define TU_DISP8(n, a1,a2,a3,a4, b1,b2,b3,b4) TU_DISP4(n, a1,a2,a3,a4) TU_DISP4(n, b1,b2,b3,b4)
+#define TU_DISP8(n, a1,a2,a3,a4, b1,b2,b3,b4) TU_DISP4(n, a1,a2,a3,a4) TU_DISP4(n, b1,b2,b3,b4)
#define TU_DISP9(n, a1,a2,a3,a4, b1,b2,b3,b4, c1 ) TU_DISP4(n, a1,a2,a3,a4) TU_DISP3(n, b1,b2,b3 ) TU_DISP2(n, b4,c1)
#define TU_DISP10(n, a1,a2,a3,a4, b1,b2,b3,b4, c1,c2 ) TU_DISP4(n, a1,a2,a3,a4) TU_DISP4(n, b1,b2,b3,b4) TU_DISP2(n, c1,c2)
#define TU_DISP11(n, a1,a2,a3,a4, b1,b2,b3,b4, c1,c2,c3 ) TU_DISP4(n, a1,a2,a3,a4) TU_DISP4(n, b1,b2,b3,b4) TU_DISP3(n, c1,c2,c3)
@@ -48,7 +48,7 @@
#define TU_DISPO4(n, v, v2, v3, v4) n(v) n(v2) n(v3) n(v4)
#define TU_DISPO5(n, a1,a2,a3, b1,b2 ) TU_DISPO3(n, a1,a2,a3) TU_DISPO2(n, b1,b2)
#define TU_DISPO6(n, a1,a2,a3, b1,b2,b3) TU_DISPO3(n, a1,a2,a3) TU_DISPO3(n, b1,b2,b3)
-#define TU_DISPO7(n, a1,a2,a3,a4, b1,b2,b3 ) TU_DISPO4(n, a1,a2,a3,a4) TU_DISPO3(n, b1,b2,b3)
+#define TU_DISPO7(n, a1,a2,a3,a4, b1,b2,b3 ) TU_DISPO4(n, a1,a2,a3,a4) TU_DISPO3(n, b1,b2,b3)
#define TU_DISPO8(n, a1,a2,a3,a4, b1,b2,b3,b4) TU_DISPO4(n, a1,a2,a3,a4) TU_DISPO4(n, b1,b2,b3,b4)
#define TU_DISPO9(n, a1,a2,a3,a4, b1,b2,b3,b4, c1) TU_DISPO4(n, a1,a2,a3,a4) TU_DISPO3(n, b1,b2,b3) TU_DISPO2(n, b4,c1)
#define TU_DISPO10(n, a1,a2,a3,a4, b1,b2,b3,b4, c1,c2) TU_DISPO4(n, a1,a2,a3,a4) TU_DISPO4(n, b1,b2,b3,b4) TU_DISPO2(n, c1,c2)
@@ -61,8 +61,8 @@
#define TU_DISPA(n, a) n a
#define TU_DISPA1(n, a, _1) TU_DISPA(n, (TU_EXP a, TU_EXP _1))
-#define TU_DISPA2(n, a, _1, _2) TU_DISPA(n, (TU_EXP a, TU_EXP _1)) TU_DISPA(n, (TU_EXP a, TU_EXP _2))
-#define TU_DISPA3(n, a, _1, _2, _3) TU_DISPA(n, (TU_EXP a, TU_EXP _1)) TU_DISPA(n, (TU_EXP a, TU_EXP _2)) TU_DISPA(n, (TU_EXP a, TU_EXP _3))
+#define TU_DISPA2(n, a, _1, _2) TU_DISPA(n, (TU_EXP a, TU_EXP _1)) TU_DISPA(n, (TU_EXP a, TU_EXP _2))
+#define TU_DISPA3(n, a, _1, _2, _3) TU_DISPA(n, (TU_EXP a, TU_EXP _1)) TU_DISPA(n, (TU_EXP a, TU_EXP _2)) TU_DISPA(n, (TU_EXP a, TU_EXP _3))
#define TU_DISPA4(n, a, a1,a2, b1,b2) TU_DISPA2(n,a, a1,a2) TU_DISPA2(n,a, b1,b2)
#define TU_DISPA5(n, a, a1,a2,a3, b1,b2) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA2(n,a, b1,b2)
#define TU_DISPA6(n, a, a1,a2,a3, b1,b2,b3) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3)
diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp
index 18ef563e..fffe9b68 100644
--- a/src/macro_rules/eval.cpp
+++ b/src/macro_rules/eval.cpp
@@ -577,6 +577,7 @@ class MacroExpander:
const RcString m_macro_filename;
const ::std::string m_crate_name;
+ ::std::shared_ptr<Span> m_invocation_span;
ParameterMappings m_mappings;
MacroExpandState m_state;
@@ -588,9 +589,10 @@ class MacroExpander:
public:
MacroExpander(const MacroExpander& x) = delete;
- MacroExpander(const ::std::string& macro_name, const Ident::Hygiene& parent_hygiene, const ::std::vector<MacroExpansionEnt>& contents, ParameterMappings mappings, ::std::string crate_name):
+ MacroExpander(const ::std::string& macro_name, const Span& sp, const Ident::Hygiene& parent_hygiene, const ::std::vector<MacroExpansionEnt>& contents, ParameterMappings mappings, ::std::string crate_name):
m_macro_filename( FMT("Macro:" << macro_name) ),
m_crate_name( mv$(crate_name) ),
+ m_invocation_span( new Span(sp) ),
m_mappings( mv$(mappings) ),
m_state( contents, m_mappings ),
m_hygiene( Ident::Hygiene::new_scope_chained(parent_hygiene) )
@@ -598,6 +600,7 @@ public:
}
Position getPosition() const override;
+ ::std::shared_ptr<Span> outerSpan() const override;
Ident::Hygiene realGetHygiene() const override;
Token realGetToken() override;
};
@@ -618,9 +621,9 @@ bool Macro_TryPatternCap(TokenStream& lex, MacroPatEnt::Type type)
switch(type)
{
case MacroPatEnt::PAT_TOKEN:
- BUG(lex.getPosition(), "");
+ BUG(lex.point_span(), "");
case MacroPatEnt::PAT_LOOP:
- BUG(lex.getPosition(), "");
+ BUG(lex.point_span(), "");
case MacroPatEnt::PAT_BLOCK:
return LOOK_AHEAD(lex) == TOK_BRACE_OPEN || LOOK_AHEAD(lex) == TOK_INTERPOLATED_BLOCK;
case MacroPatEnt::PAT_IDENT:
@@ -651,7 +654,7 @@ bool Macro_TryPatternCap(TokenStream& lex, MacroPatEnt::Type type)
case MacroPatEnt::PAT_ITEM:
return is_token_item( LOOK_AHEAD(lex) );
}
- BUG(lex.getPosition(), "");
+ BUG(lex.point_span(), "Fell through");
}
bool Macro_TryPattern(TokenStream& lex, const MacroPatEnt& pat)
{
@@ -680,9 +683,9 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type
switch(type)
{
case MacroPatEnt::PAT_TOKEN:
- BUG(lex.getPosition(), "Encountered PAT_TOKEN when handling capture");
+ BUG(lex.point_span(), "Encountered PAT_TOKEN when handling capture");
case MacroPatEnt::PAT_LOOP:
- BUG(lex.getPosition(), "Encountered PAT_LOOP when handling capture");
+ BUG(lex.point_span(), "Encountered PAT_LOOP when handling capture");
case MacroPatEnt::PAT_TT:
if( GET_TOK(tok, lex) == TOK_EOF )
@@ -722,7 +725,7 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type
}
/// Parse the input TokenTree according to the `macro_rules!` patterns and return a token stream of the replacement
-::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, TokenTree input, AST::Module& mod)
+::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod)
{
TRACE_FUNCTION_F("'" << name << "', " << input);
@@ -741,7 +744,7 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type
// Run through the expansion counting the number of times each fragment is used
Macro_InvokeRules_CountSubstUses(bound_tts, rule.m_contents);
- TokenStream* ret_ptr = new MacroExpander(name, rules.m_hygiene, rule.m_contents, mv$(bound_tts), rules.m_source_crate);
+ TokenStream* ret_ptr = new MacroExpander(name, sp, rules.m_hygiene, rule.m_contents, mv$(bound_tts), rules.m_source_crate);
return ::std::unique_ptr<TokenStream>( ret_ptr );
}
@@ -1065,9 +1068,13 @@ void Macro_InvokeRules_CountSubstUses(ParameterMappings& bound_tts, const ::std:
Position MacroExpander::getPosition() const
{
- // TODO: Return a far better span - invocaion location?
+ // TODO: Return the attached position of the last fetched token
return Position(m_macro_filename, 0, m_state.top_pos());
}
+::std::shared_ptr<Span> MacroExpander::outerSpan() const
+{
+ return m_invocation_span;
+}
Ident::Hygiene MacroExpander::realGetHygiene() const
{
if( m_ttstream )
diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp
index aed0e8ce..2a588a78 100644
--- a/src/macro_rules/macro_rules.hpp
+++ b/src/macro_rules/macro_rules.hpp
@@ -156,7 +156,7 @@ public:
SERIALISABLE_PROTOTYPES();
};
-extern ::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, TokenTree input, AST::Module& mod);
+extern ::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod);
extern MacroRulesPtr Parse_MacroRules(TokenStream& lex);
#endif // MACROS_HPP_INCLUDED
diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp
index 8264180f..1b7509fd 100644
--- a/src/macro_rules/parse.cpp
+++ b/src/macro_rules/parse.cpp
@@ -82,7 +82,7 @@ public:
else if( type == "item" )
ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_ITEM) );
else
- ERROR(lex.getPosition(), E0000, "Unknown fragment type '" << type << "'");
+ ERROR(lex.point_span(), E0000, "Unknown fragment type '" << type << "'");
break; }
case TOK_PAREN_OPEN: {
auto subpat = Parse_MacroRules_Pat(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names);
@@ -155,7 +155,7 @@ public:
{
DEBUG("depth--");
if(depth == 0)
- ERROR(lex.getPosition(), E0000, "Unmatched " << Token(close) << " in macro content");
+ ERROR(lex.point_span(), E0000, "Unmatched " << Token(close) << " in macro content");
depth --;
}
@@ -206,7 +206,7 @@ public:
auto name = tok.type() == TOK_IDENT ? tok.str() : FMT(tok);
unsigned int idx = ::std::find(var_names.begin(), var_names.end(), name) - var_names.begin();
if( idx == var_names.size() )
- ERROR(lex.getPosition(), E0000, "Macro variable $" << name << " not found");
+ ERROR(lex.point_span(), E0000, "Macro variable $" << name << " not found");
if( var_set_ptr ) {
var_set_ptr->insert( ::std::make_pair(idx,true) );
}
diff --git a/src/main.cpp b/src/main.cpp
index ec4e9f38..c442fd94 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -23,6 +23,7 @@
#include "hir_expand/main_bindings.hpp"
#include "mir/main_bindings.hpp"
#include "trans/main_bindings.hpp"
+#include "trans/target.hpp"
#include "expand/cfg.hpp"
@@ -63,6 +64,7 @@ void init_debug_list()
g_debug_disable_map.insert( "Dump HIR" );
g_debug_disable_map.insert( "Lower MIR" );
g_debug_disable_map.insert( "MIR Validate" );
+ g_debug_disable_map.insert( "MIR Validate Full Early" );
g_debug_disable_map.insert( "Dump MIR" );
g_debug_disable_map.insert( "Constant Evaluate Full" );
g_debug_disable_map.insert( "MIR Cleanup" );
@@ -142,6 +144,13 @@ struct ProgramParams
::std::set< ::std::string> features;
+
+ struct {
+ bool disable_mir_optimisations = false;
+ bool full_validate = false;
+ bool full_validate_early = false;
+ } debug;
+
ProgramParams(int argc, char *argv[]);
};
@@ -174,26 +183,10 @@ int main(int argc, char *argv[])
// Set up cfg values
Cfg_SetValue("rust_compiler", "mrustc");
- // TODO: Target spec
- Cfg_SetFlag("unix");
- Cfg_SetFlag("linux");
- Cfg_SetValue("target_os", "linux");
- Cfg_SetValue("target_family", "unix");
- Cfg_SetValue("target_pointer_width", "64");
- Cfg_SetValue("target_endian", "little");
- Cfg_SetValue("target_arch", "x86_64");
- Cfg_SetValue("target_env", "gnu");
- Cfg_SetValueCb("target_has_atomic", [](const ::std::string& s) {
- if(s == "8") return true; // Has an atomic byte
- if(s == "ptr") return true; // Has an atomic pointer-sized value
- return false;
- });
- Cfg_SetValueCb("target_feature", [](const ::std::string& s) {
- return false;
- });
Cfg_SetValueCb("feature", [&params](const ::std::string& s) {
return params.features.count(s) != 0;
});
+ Target_SetCfg();
if( params.test_harness )
@@ -258,18 +251,18 @@ int main(int argc, char *argv[])
crate_name = ::std::string(params.infile.begin() + s, params.infile.begin() + e);
for(auto& b : crate_name)
{
- if ('0' <= b && b <= '9') {
- }
- else if ('A' <= b && b <= 'Z') {
- }
- else if (b == '_') {
- }
- else if (b == '-') {
- b = '_';
- }
- else {
- // TODO: Error?
- }
+ if ('0' <= b && b <= '9') {
+ }
+ else if ('A' <= b && b <= 'Z') {
+ }
+ else if (b == '_') {
+ }
+ else if (b == '-') {
+ b = '_';
+ }
+ else {
+ // TODO: Error?
+ }
}
}
crate.m_crate_name = crate_name;
@@ -448,16 +441,16 @@ int main(int argc, char *argv[])
CompilePhaseV("MIR Cleanup", [&]() {
MIR_CleanupCrate(*hir_crate);
});
- if( getenv("MRUSTC_FULL_VALIDATE_PREOPT") )
+ if( params.debug.full_validate_early || getenv("MRUSTC_FULL_VALIDATE_PREOPT") )
{
- CompilePhaseV("MIR Validate Full", [&]() {
+ CompilePhaseV("MIR Validate Full Early", [&]() {
MIR_CheckCrate_Full(*hir_crate);
});
}
// Optimise the MIR
CompilePhaseV("MIR Optimise", [&]() {
- MIR_OptimiseCrate(*hir_crate);
+ MIR_OptimiseCrate(*hir_crate, params.debug.disable_mir_optimisations);
});
CompilePhaseV("Dump MIR", [&]() {
@@ -470,7 +463,7 @@ int main(int argc, char *argv[])
// - Exhaustive MIR validation (follows every code path and checks variable validity)
// > DEBUGGING ONLY
CompilePhaseV("MIR Validate Full", [&]() {
- if( getenv("MRUSTC_FULL_VALIDATE") )
+ if( params.debug.full_validate || getenv("MRUSTC_FULL_VALIDATE") )
MIR_CheckCrate_Full(*hir_crate);
});
@@ -571,14 +564,14 @@ ProgramParams::ProgramParams(int argc, char *argv[])
if( arg[0] != '-' )
{
- if (this->infile == "")
- {
- this->infile = arg;
- }
- else
- {
- // TODO: Error
- }
+ if (this->infile == "")
+ {
+ this->infile = arg;
+ }
+ else
+ {
+ // TODO: Error
+ }
}
else if( arg[1] != '-' )
{
@@ -610,6 +603,32 @@ ProgramParams::ProgramParams(int argc, char *argv[])
this->libraries.push_back( arg+1 );
}
continue ;
+ case 'Z': {
+ ::std::string optname;
+ if( arg[1] == '\0' ) {
+ if( i == argc - 1) {
+ exit(1);
+ }
+ optname = argv[++i];
+ }
+ else {
+ optname = arg+1;
+ }
+
+ if( optname == "disable-mir-opt" ) {
+ this->debug.disable_mir_optimisations = true;
+ }
+ else if( optname == "full-validate" ) {
+ this->debug.full_validate = true;
+ }
+ else if( optname == "full-validate-early" ) {
+ this->debug.full_validate_early = true;
+ }
+ else {
+ ::std::cerr << "Unknown debug option: '" << optname << "'" << ::std::endl;
+ exit(1);
+ }
+ } continue;
default:
break;
@@ -647,15 +666,15 @@ ProgramParams::ProgramParams(int argc, char *argv[])
}
this->crate_path = argv[++i];
}
- else if (strcmp(arg, "--out-dir") == 0) {
- if (i == argc - 1) {
- ::std::cerr << "Flag " << arg << " requires an argument" << ::std::endl;
- exit(1);
- }
- this->output_dir = argv[++i];
- if (this->output_dir == "") {
- // TODO: Error?
- }
+ else if (strcmp(arg, "--out-dir") == 0) {
+ if (i == argc - 1) {
+ ::std::cerr << "Flag " << arg << " requires an argument" << ::std::endl;
+ exit(1);
+ }
+ this->output_dir = argv[++i];
+ if (this->output_dir == "") {
+ // TODO: Error?
+ }
if( this->output_dir.back() != '/' )
this->output_dir += '/';
}
diff --git a/src/mir/check.cpp b/src/mir/check.cpp
index 4b9dfd8b..7c0cd4d8 100644
--- a/src/mir/check.cpp
+++ b/src/mir/check.cpp
@@ -105,15 +105,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
Valid,
};
State ret_state = State::Invalid;
- ::std::vector<State> arguments;
- ::std::vector<State> temporaries;
- ::std::vector<State> variables;
+ ::std::vector<State> args;
+ ::std::vector<State> locals;
ValStates() {}
- ValStates(size_t n_args, size_t n_temps, size_t n_vars):
- arguments(n_args, State::Valid),
- temporaries(n_temps),
- variables(n_vars)
+ ValStates(size_t n_args, size_t n_locals):
+ args(n_args, State::Valid),
+ locals(n_locals)
{
}
@@ -144,22 +142,20 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
}
}
};
- fmt_val_range("arg", this->arguments);
- fmt_val_range("tmp", this->temporaries);
- fmt_val_range("var", this->variables);
+ fmt_val_range("arg", this->args);
+ fmt_val_range("_", this->locals);
os << "}";
}
bool operator==(const ValStates& x) const {
- if( ret_state != x.ret_state ) return false;
- if( arguments != x.arguments ) return false;
- if( temporaries != x.temporaries ) return false;
- if( variables != x.variables ) return false;
+ if( ret_state != x.ret_state ) return false;
+ if( args != x.args ) return false;
+ if( locals != x.locals ) return false;
return true;
}
bool empty() const {
- return arguments.empty() && temporaries.empty() && variables.empty();
+ return locals.empty() && args.empty();
}
bool merge(unsigned bb_idx, ValStates& other)
@@ -178,9 +174,8 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
{
bool rv = false;
rv |= ValStates::merge_state(this->ret_state, other.ret_state);
- rv |= ValStates::merge_lists(this->arguments , other.arguments);
- rv |= ValStates::merge_lists(this->temporaries, other.temporaries);
- rv |= ValStates::merge_lists(this->variables , other.variables);
+ rv |= ValStates::merge_lists(this->args , other.args );
+ rv |= ValStates::merge_lists(this->locals, other.locals);
return rv;
}
}
@@ -194,42 +189,32 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
ret_state = is_valid ? State::Valid : State::Invalid;
),
(Argument,
- MIR_ASSERT(state, e.idx < this->arguments.size(), "");
- DEBUG("arg" << e.idx << " = " << (is_valid ? "Valid" : "Invalid"));
- this->arguments[e.idx] = is_valid ? State::Valid : State::Invalid;
+ MIR_ASSERT(state, e.idx < this->args.size(), "Argument index out of range");
+ DEBUG("arg$" << e.idx << " = " << (is_valid ? "Valid" : "Invalid"));
+ this->args[e.idx] = is_valid ? State::Valid : State::Invalid;
),
- (Variable,
- MIR_ASSERT(state, e < this->variables.size(), "");
- DEBUG("var" << e << " = " << (is_valid ? "Valid" : "Invalid"));
- this->variables[e] = is_valid ? State::Valid : State::Invalid;
- ),
- (Temporary,
- MIR_ASSERT(state, e.idx < this->temporaries.size(), "");
- DEBUG("tmp" << e.idx << " = " << (is_valid ? "Valid" : "Invalid"));
- this->temporaries[e.idx] = is_valid ? State::Valid : State::Invalid;
+ (Local,
+ MIR_ASSERT(state, e < this->locals.size(), "Local index out of range");
+ DEBUG("_" << e << " = " << (is_valid ? "Valid" : "Invalid"));
+ this->locals[e] = is_valid ? State::Valid : State::Invalid;
)
)
}
void ensure_valid(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv)
{
TU_MATCH( ::MIR::LValue, (lv), (e),
- (Variable,
- MIR_ASSERT(state, e < this->variables.size(), "");
- if( this->variables[e] != State::Valid )
- MIR_BUG(state, "Use of non-valid variable - " << lv);
- ),
- (Temporary,
- MIR_ASSERT(state, e.idx < this->temporaries.size(), "");
- if( this->temporaries[e.idx] != State::Valid )
- MIR_BUG(state, "Use of non-valid temporary - " << lv);
+ (Return,
+ if( this->ret_state != State::Valid )
+ MIR_BUG(state, "Use of non-valid lvalue - " << lv);
),
(Argument,
- MIR_ASSERT(state, e.idx < this->arguments.size(), "");
- if( this->arguments[e.idx] != State::Valid )
- MIR_BUG(state, "Use of non-valid argument - " << lv);
+ MIR_ASSERT(state, e.idx < this->args.size(), "Arg index out of range");
+ if( this->args[e.idx] != State::Valid )
+ MIR_BUG(state, "Use of non-valid lvalue - " << lv);
),
- (Return,
- if( this->ret_state != State::Valid )
+ (Local,
+ MIR_ASSERT(state, e < this->locals.size(), "Local index out of range");
+ if( this->locals[e] != State::Valid )
MIR_BUG(state, "Use of non-valid lvalue - " << lv);
),
(Static,
@@ -309,7 +294,7 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
src_path.push_back(idx);
to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), mv$(vs) } );
};
- add_to_visit( 0, {}, ValStates { state.m_args.size(), fcn.temporaries.size(), fcn.named_variables.size() } );
+ add_to_visit( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } );
while( to_visit_blocks.size() > 0 )
{
auto block = to_visit_blocks.back().bb;
@@ -430,12 +415,12 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
// Check if the return value has been set
val_state.ensure_valid( state, ::MIR::LValue::make_Return({}) );
// Ensure that no other non-Copy values are valid
- for(unsigned int i = 0; i < val_state.variables.size(); i ++)
+ for(unsigned int i = 0; i < val_state.locals.size(); i ++)
{
- if( val_state.variables[i] == ValStates::State::Invalid )
+ if( val_state.locals[i] == ValStates::State::Invalid )
{
}
- else if( state.m_resolve.type_is_copy(state.sp, fcn.named_variables[i]) )
+ else if( state.m_resolve.type_is_copy(state.sp, fcn.locals[i]) )
{
}
else
@@ -467,6 +452,14 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
add_to_visit( tgt, path, val_state );
}
),
+ (SwitchValue,
+ val_state.ensure_valid( state, e.val );
+ for(const auto& tgt : e.targets)
+ {
+ add_to_visit( tgt, path, val_state );
+ }
+ add_to_visit( e.def_target, path, val_state );
+ ),
(Call,
if( e.fcn.is_Value() )
val_state.ensure_valid( state, e.fcn.as_Value() );
@@ -549,6 +542,12 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
PUSH_BB(e.targets[i], "Switch V" << i);
}
),
+ (SwitchValue,
+ for(unsigned int i = 0; i < e.targets.size(); i++ ) {
+ PUSH_BB(e.targets[i], "SwitchValue " << i);
+ }
+ PUSH_BB(e.def_target, "SwitchValue def");
+ ),
(Call,
PUSH_BB(e.ret_block, "Call ret");
PUSH_BB(e.panic_block, "Call panic");
@@ -689,7 +688,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
// TODO: Check suitability of source type (COMPLEX)
),
(BinOp,
- /*
+ /*
::HIR::TypeRef tmp_l, tmp_r;
const auto& ty_l = state.get_lvalue_type(tmp_l, e.val_l);
const auto& ty_r = state.get_lvalue_type(tmp_r, e.val_r);
@@ -723,7 +722,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
ity_p = &*ty.m_data.as_Pointer().inner;
else {
MIR_BUG(state, "DstMeta requires a &-ptr as input, got " << ty);
- }
+ }
const auto& ity = *ity_p;
if( ity.m_data.is_Generic() )
;
@@ -757,7 +756,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
ity_p = &*ty.m_data.as_Pointer().inner;
else {
MIR_BUG(state, "DstPtr requires a &-ptr as input, got " << ty);
- }
+ }
const auto& ity = *ity_p;
if( ity.m_data.is_Slice() )
;
@@ -785,7 +784,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
ity_p = &*te->inner;
else {
MIR_BUG(state, "DstMeta requires a pointer as output, got " << ty);
- }
+ }
assert(ity_p);
auto meta = get_metadata_type(state, *ity_p);
if( meta == ::HIR::TypeRef() )
@@ -844,6 +843,9 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
(Switch,
// Check that the condition is an enum
),
+ (SwitchValue,
+ // Check that the condition's type matches the values
+ ),
(Call,
if( e.fcn.is_Value() )
{
diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp
index cacd9bef..1f86c40a 100644
--- a/src/mir/check_full.cpp
+++ b/src/mir/check_full.cpp
@@ -24,6 +24,11 @@ namespace
// other = 1-based index into `inner_states`
unsigned int index;
+ explicit State(const State&) = default;
+ State(State&& x) = default;
+ State& operator=(const State&) = delete;
+ State& operator=(State&& ) = default;
+
State(): index(0) {}
State(bool valid): index(valid ? ~0u : 0) {}
State(size_t idx):
@@ -51,20 +56,20 @@ namespace
struct StateFmt {
const ValueStates& vss;
- State s;
- StateFmt( const ValueStates& vss, State s ):
+ const State& s;
+ StateFmt( const ValueStates& vss, const State& s ):
vss(vss), s(s)
{}
};
+::std::ostream& operator<<(::std::ostream& os, const StateFmt& x);
namespace
{
struct ValueStates
{
- ::std::vector<State> vars;
- ::std::vector<State> temporaries;
- ::std::vector<State> arguments;
State return_value;
+ ::std::vector<State> args;
+ ::std::vector<State> locals;
::std::vector<bool> drop_flags;
::std::vector< ::std::vector<State> > inner_states;
@@ -73,8 +78,27 @@ namespace
ValueStates clone() const
{
+ struct H {
+ static ::std::vector<State> clone_state_list(const ::std::vector<State>& l) {
+ ::std::vector<State> rv;
+ rv.reserve(l.size());
+ for(const auto& s : l)
+ rv.push_back( State(s) );
+ return rv;
+ }
+ };
+ ValueStates rv;
+ rv.return_value = State(this->return_value);
+ rv.args = H::clone_state_list(this->args);
+ rv.locals = H::clone_state_list(this->locals);
+ rv.drop_flags = this->drop_flags;
+ rv.inner_states.reserve( this->inner_states.size() );
+ for(const auto& isl : this->inner_states)
+ rv.inner_states.push_back( H::clone_state_list(isl) );
+ rv.bb_path = this->bb_path;
return *this;
}
+
bool is_equivalent_to(const ValueStates& x) const
{
struct H {
@@ -113,22 +137,18 @@ namespace
return false;
if( ! H::equal(*this, return_value, x, x.return_value) )
return false;
- assert(vars.size() == x.vars.size());
- for(size_t i = 0; i < vars.size(); i ++)
- {
- if( ! H::equal(*this, vars[i], x, x.vars[i]) )
- return false;
- }
- assert(temporaries.size() == x.temporaries.size());
- for(size_t i = 0; i < temporaries.size(); i ++)
+
+ assert(args.size() == x.args.size());
+ for(size_t i = 0; i < args.size(); i ++)
{
- if( ! H::equal(*this, temporaries[i], x, x.temporaries[i]) )
+ if( ! H::equal(*this, args[i], x, x.args[i]) )
return false;
}
- assert(arguments.size() == x.arguments.size());
- for(size_t i = 0; i < arguments.size(); i ++)
+
+ assert(locals.size() == x.locals.size());
+ for(size_t i = 0; i < locals.size(); i ++)
{
- if( ! H::equal(*this, arguments[i], x, x.arguments[i]) )
+ if( ! H::equal(*this, locals[i], x, x.locals[i]) )
return false;
}
return true;
@@ -147,7 +167,7 @@ namespace
}
void ensure_lvalue_valid(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const
{
- auto vs = get_lvalue_state(mir_res, lv);
+ const auto& vs = get_lvalue_state(mir_res, lv);
::std::vector<unsigned int> path;
ensure_valid(mir_res, lv, vs, path);
}
@@ -371,29 +391,46 @@ namespace
Marker m;
m.used.resize(this->inner_states.size(), false);
- for(const auto& s : this->vars)
- m.mark_from_state(*this, s);
- for(const auto& s : this->temporaries)
+ m.mark_from_state(*this, this->return_value);
+ for(const auto& s : this->args)
m.mark_from_state(*this, s);
- for(const auto& s : this->arguments)
+ for(const auto& s : this->locals)
m.mark_from_state(*this, s);
- m.mark_from_state(*this, this->return_value);
}
private:
- State allocate_composite(unsigned int n_fields, State basis)
+ ::std::vector<State>& allocate_composite_int(State& out_state)
{
- assert(n_fields > 0);
+ // 1. Search for an unused (empty) slot
for(size_t i = 0; i < this->inner_states.size(); i ++)
{
if( this->inner_states[i].size() == 0 )
{
- inner_states[i] = ::std::vector<State>(n_fields, basis);
- return State(i);
+ out_state = State(i);
+ return inner_states[i];
}
}
+ // 2. If none avaliable, allocate a new slot
auto idx = inner_states.size();
- inner_states.push_back( ::std::vector<State>(n_fields, basis) );
- return State(idx);
+ inner_states.push_back({});
+ out_state = State(idx);
+ return inner_states.back();
+ }
+ State allocate_composite(unsigned int n_fields, const State& basis)
+ {
+ assert(n_fields > 0);
+ assert(!basis.is_composite());
+
+ State rv;
+ auto& sub_states = allocate_composite_int(rv);
+ assert(sub_states.size() == 0);
+
+ sub_states.reserve(n_fields);
+ while(n_fields--)
+ {
+ sub_states.push_back( State(basis) );
+ }
+
+ return rv;
}
public:
@@ -407,26 +444,24 @@ namespace
MIR_ASSERT(mir_res, vs.index-1 < this->inner_states.size(), "");
return this->inner_states.at( vs.index - 1 );
}
- State get_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const
+ const State& get_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const
{
TU_MATCHA( (lv), (e),
- (Variable,
- return vars.at(e);
- ),
- (Temporary,
- return temporaries.at(e.idx);
+ (Return,
+ return return_value;
),
(Argument,
- return arguments.at(e.idx);
+ return args.at(e.idx);
),
- (Static,
- return State(true);
+ (Local,
+ return locals.at(e);
),
- (Return,
- return return_value;
+ (Static,
+ static State state_of_static(true);
+ return state_of_static;
),
(Field,
- auto vs = get_lvalue_state(mir_res, *e.val);
+ const auto& vs = get_lvalue_state(mir_res, *e.val);
if( vs.is_composite() )
{
const auto& states = this->get_composite(mir_res, vs);
@@ -439,7 +474,7 @@ namespace
}
),
(Deref,
- auto vs = get_lvalue_state(mir_res, *e.val);
+ const auto& vs = get_lvalue_state(mir_res, *e.val);
if( vs.is_composite() )
{
MIR_TODO(mir_res, "Deref with composite state");
@@ -450,18 +485,20 @@ namespace
}
),
(Index,
- auto vs_v = get_lvalue_state(mir_res, *e.val);
- auto vs_i = get_lvalue_state(mir_res, *e.idx);
+ const auto& vs_v = get_lvalue_state(mir_res, *e.val);
+ const auto& vs_i = get_lvalue_state(mir_res, *e.idx);
MIR_ASSERT(mir_res, !vs_v.is_composite(), "");
MIR_ASSERT(mir_res, !vs_i.is_composite(), "");
- return State(vs_v.is_valid() && vs_i.is_valid());
+ //return State(vs_v.is_valid() && vs_i.is_valid());
+ MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value");
+ return vs_v;
),
(Downcast,
- auto vs_v = get_lvalue_state(mir_res, *e.val);
+ const auto& vs_v = get_lvalue_state(mir_res, *e.val);
if( vs_v.is_composite() )
{
const auto& states = this->get_composite(mir_res, vs_v);
- MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size");
+ MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs_v));
return states[0];
}
else
@@ -473,32 +510,45 @@ namespace
throw "";
}
+ void clear_state(const ::MIR::TypeResolve& mir_res, State& s) {
+ if(s.is_composite()) {
+ auto& sub_states = this->get_composite(mir_res, s);
+ for(auto& ss : sub_states)
+ this->clear_state(mir_res, ss);
+ sub_states.clear();
+ }
+ }
+
void set_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv, State new_vs)
{
+ TRACE_FUNCTION_F(lv << " = " << StateFmt(*this, new_vs) << " (from " << StateFmt(*this, get_lvalue_state(mir_res, lv)) << ")");
TU_MATCHA( (lv), (e),
- (Variable,
- vars.at(e) = new_vs;
- ),
- (Temporary,
- temporaries.at(e.idx) = new_vs;
+ (Return,
+ this->clear_state(mir_res, return_value);
+ return_value = mv$(new_vs);
),
(Argument,
- arguments.at(e.idx) = new_vs;
+ auto& slot = args.at(e.idx);
+ this->clear_state(mir_res, slot);
+ slot = mv$(new_vs);
+ ),
+ (Local,
+ auto& slot = locals.at(e);
+ this->clear_state(mir_res, slot);
+ slot = mv$(new_vs);
),
(Static,
// Ignore.
),
- (Return,
- return_value = new_vs;
- ),
(Field,
- auto cur_vs = get_lvalue_state(mir_res, *e.val);
+ const auto& cur_vs = get_lvalue_state(mir_res, *e.val);
if( !cur_vs.is_composite() && cur_vs == new_vs )
{
// Not a composite, and no state change
}
else
{
+ ::std::vector<State>* states_p;
if( !cur_vs.is_composite() )
{
::HIR::TypeRef tmp;
@@ -526,41 +576,55 @@ namespace
else {
MIR_BUG(mir_res, "Unknown type being accessed with Field - " << ty);
}
- cur_vs = this->allocate_composite(n_fields, cur_vs);
- set_lvalue_state(mir_res, *e.val, cur_vs);
+
+ auto new_cur_vs = this->allocate_composite(n_fields, cur_vs);
+ set_lvalue_state(mir_res, *e.val, State(new_cur_vs));
+ states_p = &this->get_composite(mir_res, new_cur_vs);
+ }
+ else
+ {
+ states_p = &this->get_composite(mir_res, cur_vs);
}
// Get composite state and assign into it
- auto& states = this->get_composite(mir_res, cur_vs);
+ auto& states = *states_p;
MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range");
- states[e.field_index] = new_vs;
+ this->clear_state(mir_res, states[e.field_index]);
+ states[e.field_index] = mv$(new_vs);
}
),
(Deref,
- auto cur_vs = get_lvalue_state(mir_res, *e.val);
+ const auto& cur_vs = get_lvalue_state(mir_res, *e.val);
if( !cur_vs.is_composite() && cur_vs == new_vs )
{
// Not a composite, and no state change
}
else
{
+ ::std::vector<State>* states_p;
if( !cur_vs.is_composite() )
{
//::HIR::TypeRef tmp;
//const auto& ty = mir_res.get_lvalue_type(tmp, *e.val);
// TODO: Should this check if the type is Box?
- cur_vs = this->allocate_composite(2, cur_vs);
- set_lvalue_state(mir_res, *e.val, cur_vs);
+ auto new_cur_vs = this->allocate_composite(2, cur_vs);
+ set_lvalue_state(mir_res, *e.val, State(new_cur_vs));
+ states_p = &this->get_composite(mir_res, new_cur_vs);
+ }
+ else
+ {
+ states_p = &this->get_composite(mir_res, cur_vs);
}
// Get composite state and assign into it
- auto& states = this->get_composite(mir_res, cur_vs);
+ auto& states = *states_p;
MIR_ASSERT(mir_res, states.size() == 2, "Deref with invalid state list size");
- states[1] = new_vs;
+ this->clear_state(mir_res, states[1]);
+ states[1] = mv$(new_vs);
}
),
(Index,
- auto vs_v = get_lvalue_state(mir_res, *e.val);
- auto vs_i = get_lvalue_state(mir_res, *e.idx);
+ const auto& vs_v = get_lvalue_state(mir_res, *e.val);
+ const auto& vs_i = get_lvalue_state(mir_res, *e.idx);
MIR_ASSERT(mir_res, !vs_v.is_composite(), "");
MIR_ASSERT(mir_res, !vs_i.is_composite(), "");
@@ -570,22 +634,30 @@ namespace
// NOTE: Ignore
),
(Downcast,
- auto cur_vs = get_lvalue_state(mir_res, *e.val);
+ const auto& cur_vs = get_lvalue_state(mir_res, *e.val);
if( !cur_vs.is_composite() && cur_vs == new_vs )
{
// Not a composite, and no state change
}
else
{
+ ::std::vector<State>* states_p;
if( !cur_vs.is_composite() )
{
- cur_vs = this->allocate_composite(1, cur_vs);
- set_lvalue_state(mir_res, *e.val, cur_vs);
+ auto new_cur_vs = this->allocate_composite(1, cur_vs);
+ set_lvalue_state(mir_res, *e.val, State(new_cur_vs));
+ states_p = &this->get_composite(mir_res, new_cur_vs);
+ }
+ else
+ {
+ states_p = &this->get_composite(mir_res, cur_vs);
}
+
// Get composite state and assign into it
- auto& states = this->get_composite(mir_res, cur_vs);
- MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size");
- states[0] = new_vs;
+ auto& states = *states_p;
+ MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << *e.val << " - " << this->fmt_state(mir_res, *e.val));
+ this->clear_state(mir_res, states[0]);
+ states[0] = mv$(new_vs);
}
)
)
@@ -648,12 +720,10 @@ namespace std {
os << "ValueStates(path=[" << x.bb_path << "]";
print_val(",rv", x.return_value);
- for(unsigned int i = 0; i < x.arguments.size(); i ++)
- print_val(FMT_CB(ss, ss << ",a" << i;), x.arguments[i]);
- for(unsigned int i = 0; i < x.vars.size(); i ++)
- print_val(FMT_CB(ss, ss << ",_" << i;), x.vars[i]);
- for(unsigned int i = 0; i < x.temporaries.size(); i ++)
- print_val(FMT_CB(ss, ss << ",t" << i;), x.temporaries[i]);
+ for(unsigned int i = 0; i < x.args.size(); i ++)
+ print_val(FMT_CB(ss, ss << ",a" << i;), x.args[i]);
+ for(unsigned int i = 0; i < x.locals.size(); i ++)
+ print_val(FMT_CB(ss, ss << ",_" << i;), x.locals[i]);
for(unsigned int i = 0; i < x.drop_flags.size(); i++)
if(x.drop_flags[i])
os << ",df" << i;
@@ -677,9 +747,17 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio
DEBUG(lifetimes.m_block_offsets);
ValueStates state;
- state.arguments.resize( mir_res.m_args.size(), State(true) );
- state.vars.resize( fcn.named_variables.size() );
- state.temporaries.resize( fcn.temporaries.size() );
+ struct H {
+ static ::std::vector<State> make_list(size_t n, bool pop) {
+ ::std::vector<State> rv;
+ rv.reserve(n);
+ while(n--)
+ rv.push_back(State(pop));
+ return rv;
+ }
+ };
+ state.args = H::make_list(mir_res.m_args.size(), true);
+ state.locals = H::make_list(fcn.locals.size(), false);
state.drop_flags = fcn.drop_flags;
::std::vector< ::std::pair<unsigned int, ValueStates> > todo_queue;
@@ -692,46 +770,25 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio
// Mask off any values which aren't valid in the first statement of this block
{
- for(unsigned i = 0; i < state.vars.size(); i ++)
- {
- /*if( !variables_copy[i] )
- {
- // Not Copy, don't apply masking
- }
- else*/ if( ! state.vars[i].is_valid() )
- {
- // Already invalid
- }
- else if( lifetimes.var_valid(i, cur_block, 0) )
- {
- // Expected to be valid in this block, leave as-is
- }
- else
- {
- // Copy value not used at/after this block, mask to false
- DEBUG("BB" << cur_block << " - var$" << i << " - Outside lifetime, discard");
- state.vars[i] = State(false);
- }
- }
- for(unsigned i = 0; i < state.temporaries.size(); i ++)
+ for(unsigned i = 0; i < state.locals.size(); i ++)
{
/*if( !variables_copy[i] )
{
// Not Copy, don't apply masking
}
- else*/ if( ! state.temporaries[i].is_valid() )
+ else*/ if( ! state.locals[i].is_valid() )
{
// Already invalid
}
- else if( lifetimes.tmp_valid(i, cur_block, 0) )
+ else if( lifetimes.slot_valid(i, cur_block, 0) )
{
// Expected to be valid in this block, leave as-is
}
else
{
// Copy value not used at/after this block, mask to false
- DEBUG("BB" << cur_block << " - tmp$" << i << " - Outside lifetime, discard");
- state.temporaries[i] = State(false);
+ DEBUG("BB" << cur_block << " - _" << i << " - Outside lifetime, discard");
+ state.locals[i] = State(false);
}
}
}
@@ -755,9 +812,9 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio
TU_MATCHA( (blk.statements[i]), (se),
(Assign,
if( ENABLE_LEAK_DETECTOR )
- {
- // TODO: Check if the target isn't valid. Allow if either invaid, or too complex to know.
- }
+ {
+ // TODO: Check if the target isn't valid. Allow if either invaid, or too complex to know.
+ }
TU_MATCHA( (se.src), (ve),
(Use,
state.move_lvalue(mir_res, ve);
@@ -845,7 +902,7 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio
{
// HACK: A move out of a Box generates the following pattern: `[[[[X_]]X]]`
// - Ensure that that is the pattern we're seeing here.
- auto vs = state.get_lvalue_state(mir_res, se.slot);
+ const auto& vs = state.get_lvalue_state(mir_res, se.slot);
MIR_ASSERT(mir_res, vs.index != ~0u, "Shallow drop on fully-valid value - " << se.slot);
@@ -910,11 +967,11 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio
}
}
};
- for(unsigned i = 0; i < state.arguments.size(); i ++ ) {
- ensure_dropped(state.arguments[i], ::MIR::LValue::make_Argument({i}));
+ for(unsigned i = 0; i < state.locals.size(); i ++ ) {
+ ensure_dropped(state.locals[i], ::MIR::LValue::make_Local(i));
}
- for(unsigned i = 0; i < state.vars.size(); i ++ ) {
- ensure_dropped(state.vars[i], ::MIR::LValue::make_Variable(i));
+ for(unsigned i = 0; i < state.args.size(); i ++ ) {
+ ensure_dropped(state.args[i], ::MIR::LValue::make_Argument({i}));
}
}
),
@@ -938,6 +995,14 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio
todo_queue.push_back( ::std::make_pair(te.targets[i], i == te.targets.size()-1 ? mv$(state) : state.clone()) );
}
),
+ (SwitchValue,
+ state.ensure_lvalue_valid(mir_res, te.val);
+ for(size_t i = 0; i < te.targets.size(); i ++)
+ {
+ todo_queue.push_back( ::std::make_pair(te.targets[i], state.clone()) );
+ }
+ todo_queue.push_back( ::std::make_pair(te.def_target, mv$(state)) );
+ ),
(Call,
if(const auto* e = te.fcn.opt_Value())
{
diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp
index 17dca948..f26f2bdd 100644
--- a/src/mir/cleanup.cpp
+++ b/src/mir/cleanup.cpp
@@ -32,8 +32,8 @@ struct MirMutator
::MIR::LValue new_temporary(::HIR::TypeRef ty)
{
- auto rv = ::MIR::LValue::make_Temporary({ static_cast<unsigned int>(m_fcn.temporaries.size()) });
- m_fcn.temporaries.push_back( mv$(ty) );
+ auto rv = ::MIR::LValue::make_Local( static_cast<unsigned int>(m_fcn.locals.size()) );
+ m_fcn.locals.push_back( mv$(ty) );
return rv;
}
@@ -831,15 +831,13 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::MIR::LValue& lval)
{
TU_MATCHA( (lval), (le),
- (Variable,
- ),
- (Temporary,
+ (Return,
),
(Argument,
),
- (Static,
+ (Local,
),
- (Return,
+ (Static,
),
(Field,
MIR_Cleanup_LValue(state, mutator, *le.val);
@@ -1105,6 +1103,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
(Switch,
MIR_Cleanup_LValue(state, mutator, e.val);
),
+ (SwitchValue,
+ MIR_Cleanup_LValue(state, mutator, e.val);
+ ),
(Call,
MIR_Cleanup_LValue(state, mutator, e.ret_val);
if( e.fcn.is_Value() ) {
diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp
index b4177295..a029023a 100644
--- a/src/mir/dump.cpp
+++ b/src/mir/dump.cpp
@@ -25,13 +25,9 @@ namespace {
void dump_mir(const ::MIR::Function& fcn)
{
- for(unsigned int i = 0; i < fcn.named_variables.size(); i ++)
+ for(size_t i = 0; i < fcn.locals.size(); i ++)
{
- m_os << indent() << "let _#" << i << ": " << fcn.named_variables[i] << ";\n";
- }
- for(unsigned int i = 0; i < fcn.temporaries.size(); i ++)
- {
- m_os << indent() << "let tmp$" << i << ": " << fcn.temporaries[i] << ";\n";
+ m_os << indent() << "let _$" << i << ": " << fcn.locals[i] << ";\n";
}
for(unsigned int i = 0; i < fcn.drop_flags.size(); i ++)
{
@@ -102,10 +98,8 @@ namespace {
),
(ScopeEnd,
m_os << "// Scope End: ";
- for(auto idx : e.vars)
- m_os << "var$" << idx << ",";
- for(auto idx : e.tmps)
- m_os << "tmp$" << idx << ",";
+ for(auto idx : e.slots)
+ m_os << "_$" << idx << ",";
m_os << "\n";
)
)
@@ -137,6 +131,24 @@ namespace {
m_os << j << " => bb" << e.targets[j] << ", ";
m_os << "}\n";
),
+ (SwitchValue,
+ m_os << "switch " << FMT_M(e.val) << " {";
+ TU_MATCHA( (e.values), (ve),
+ (Unsigned,
+ for(unsigned int j = 0; j < e.targets.size(); j ++)
+ m_os << ve[j] << " => bb" << e.targets[j] << ", ";
+ ),
+ (Signed,
+ for(unsigned int j = 0; j < e.targets.size(); j ++)
+ m_os << (ve[j] >= 0 ? "+" : "") << ve[j] << " => bb" << e.targets[j] << ", ";
+ ),
+ (String,
+ for(unsigned int j = 0; j < e.targets.size(); j ++)
+ m_os << "\"" << ve[j] << "\" => bb" << e.targets[j] << ", ";
+ )
+ )
+ m_os << "_ => bb" << e.def_target << "}\n";
+ ),
(Call,
m_os << FMT_M(e.ret_val) << " = ";
TU_MATCHA( (e.fcn), (e2),
@@ -165,21 +177,18 @@ namespace {
}
void fmt_val(::std::ostream& os, const ::MIR::LValue& lval) {
TU_MATCHA( (lval), (e),
- (Variable,
- os << "_#" << e;
- ),
- (Temporary,
- os << "tmp$" << e.idx;
+ (Return,
+ os << "RETURN";
),
(Argument,
os << "arg$" << e.idx;
),
+ (Local,
+ os << "_$" << e;
+ ),
(Static,
os << e;
),
- (Return,
- os << "RETURN";
- ),
(Field,
os << "(";
fmt_val(os, *e.val);
diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp
index d9796aed..786c2243 100644
--- a/src/mir/from_hir.cpp
+++ b/src/mir/from_hir.cpp
@@ -175,16 +175,16 @@ namespace {
switch( pat.m_binding.m_type )
{
case ::HIR::PatternBinding::Type::Move:
- m_builder.push_stmt_assign( sp, ::MIR::LValue::make_Variable(pat.m_binding.m_slot), mv$(lval) );
+ m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, pat.m_binding.m_slot), mv$(lval) );
break;
case ::HIR::PatternBinding::Type::Ref:
if(m_borrow_raise_target)
{
DEBUG("- Raising destructure borrow of " << lval << " to scope " << *m_borrow_raise_target);
- m_builder.raise_variables(sp, lval, *m_borrow_raise_target);
+ m_builder.raise_temporaries(sp, lval, *m_borrow_raise_target);
}
- m_builder.push_stmt_assign( sp, ::MIR::LValue::make_Variable(pat.m_binding.m_slot), ::MIR::RValue::make_Borrow({
+ m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, pat.m_binding.m_slot), ::MIR::RValue::make_Borrow({
0, ::HIR::BorrowType::Shared, mv$(lval)
}) );
break;
@@ -192,9 +192,9 @@ namespace {
if(m_borrow_raise_target)
{
DEBUG("- Raising destructure borrow of " << lval << " to scope " << *m_borrow_raise_target);
- m_builder.raise_variables(sp, lval, *m_borrow_raise_target);
+ m_builder.raise_temporaries(sp, lval, *m_borrow_raise_target);
}
- m_builder.push_stmt_assign( sp, ::MIR::LValue::make_Variable(pat.m_binding.m_slot), ::MIR::RValue::make_Borrow({
+ m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, pat.m_binding.m_slot), ::MIR::RValue::make_Borrow({
0, ::HIR::BorrowType::Unique, mv$(lval)
}) );
break;
@@ -390,7 +390,7 @@ namespace {
);
// Construct fat pointer
- m_builder.push_stmt_assign( sp, ::MIR::LValue::make_Variable(e.extra_bind.m_slot), ::MIR::RValue::make_MakeDst({ mv$(ptr_val), mv$(len_val) }) );
+ m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, e.extra_bind.m_slot), ::MIR::RValue::make_MakeDst({ mv$(ptr_val), mv$(len_val) }) );
}
if( e.trailing.size() > 0 )
{
@@ -536,7 +536,7 @@ namespace {
if( node.m_pattern.m_binding.is_valid() && node.m_pattern.m_data.is_Any() && node.m_pattern.m_binding.m_type == ::HIR::PatternBinding::Type::Move )
{
- m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Variable(node.m_pattern.m_binding.m_slot), mv$(res) );
+ m_builder.push_stmt_assign( node.span(), m_builder.get_variable(node.span(), node.m_pattern.m_binding.m_slot), mv$(res) );
}
else
{
@@ -548,8 +548,8 @@ namespace {
void visit(::HIR::ExprNode_Loop& node) override
{
TRACE_FUNCTION_FR("_Loop", "_Loop");
- auto loop_body_scope = m_builder.new_scope_loop(node.span());
auto loop_block = m_builder.new_bb_linked();
+ auto loop_body_scope = m_builder.new_scope_loop(node.span());
auto loop_next = m_builder.new_bb_unlinked();
auto loop_tmp_scope = m_builder.new_scope_temp(node.span());
@@ -663,7 +663,7 @@ namespace {
if( m_builder.block_active() ) {
auto res = m_builder.get_result(arm.m_code->span());
- m_builder.raise_variables( arm.m_code->span(), res, scope, /*to_above=*/true);
+ m_builder.raise_temporaries( arm.m_code->span(), res, scope, /*to_above=*/true);
m_builder.set_result(arm.m_code->span(), mv$(res));
m_builder.terminate_scope( node.span(), mv$(tmp_scope) );
@@ -1157,7 +1157,7 @@ namespace {
if( m_borrow_raise_target )
{
DEBUG("- Raising borrow to scope " << *m_borrow_raise_target);
- m_builder.raise_variables(node.span(), val, *m_borrow_raise_target);
+ m_builder.raise_temporaries(node.span(), val, *m_borrow_raise_target);
}
m_builder.set_result( node.span(), ::MIR::RValue::make_Borrow({ 0, node.m_type, mv$(val) }) );
@@ -1438,7 +1438,7 @@ namespace {
if( m_borrow_raise_target && m_in_borrow )
{
DEBUG("- Raising deref in borrow to scope " << *m_borrow_raise_target);
- m_builder.raise_variables(node.span(), val, *m_borrow_raise_target);
+ m_builder.raise_temporaries(node.span(), val, *m_borrow_raise_target);
}
@@ -2057,7 +2057,7 @@ namespace {
void visit(::HIR::ExprNode_Variable& node) override
{
TRACE_FUNCTION_F("_Variable - " << node.m_name << " #" << node.m_slot);
- m_builder.set_result( node.span(), ::MIR::LValue::make_Variable(node.m_slot) );
+ m_builder.set_result( node.span(), m_builder.get_variable(node.span(), node.m_slot) );
}
void visit(::HIR::ExprNode_StructLiteral& node) override
@@ -2239,9 +2239,9 @@ namespace {
TRACE_FUNCTION;
::MIR::Function fcn;
- fcn.named_variables.reserve(ptr.m_bindings.size());
+ fcn.locals.reserve(ptr.m_bindings.size());
for(const auto& t : ptr.m_bindings)
- fcn.named_variables.push_back( t.clone() );
+ fcn.locals.push_back( t.clone() );
// Scope ensures that builder cleanup happens before `fcn` is moved
{
@@ -2252,8 +2252,15 @@ namespace {
unsigned int i = 0;
for( const auto& arg : args )
{
- ev.define_vars_from(ptr->span(), arg.first);
- ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i}));
+ const auto& pat = arg.first;
+ if( pat.m_binding.is_valid() && pat.m_binding.m_type == ::HIR::PatternBinding::Type::Move )
+ {
+ }
+ else
+ {
+ ev.define_vars_from(ptr->span(), arg.first);
+ ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i}));
+ }
i ++;
}
@@ -2262,8 +2269,14 @@ namespace {
root_node.visit( ev );
}
+ // NOTE: Can't clean up yet, as consteval isn't done
+ //MIR_Cleanup(resolve, path, fcn, args, ptr->m_res_type);
MIR_Validate(resolve, path, fcn, args, ptr->m_res_type);
+ if( getenv("MRUSTC_VALIDATE_FULL_EARLY") ) {
+ MIR_Validate_Full(resolve, path, fcn, args, ptr->m_res_type);
+ }
+
return ::MIR::FunctionPointer(new ::MIR::Function(mv$(fcn)));
}
diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp
index 6b10d5bd..c4be91a2 100644
--- a/src/mir/from_hir.hpp
+++ b/src/mir/from_hir.hpp
@@ -79,20 +79,18 @@ extern ::std::ostream& operator<<(::std::ostream& os, const VarState& x);
struct SplitArm {
bool has_early_terminated = false;
bool always_early_terminated = false; // Populated on completion
- ::std::map<unsigned int, VarState> var_states;
- ::std::map<unsigned int, VarState> tmp_states;
+ ::std::map<unsigned int, VarState> states;
+ ::std::map<unsigned int, VarState> arg_states;
};
struct SplitEnd {
- ::std::map<unsigned int, VarState> var_states;
- ::std::map<unsigned int, VarState> tmp_states;
+ ::std::map<unsigned int, VarState> states;
+ ::std::map<unsigned int, VarState> arg_states;
};
-TAGGED_UNION(ScopeType, Variables,
- (Variables, struct {
- ::std::vector<unsigned int> vars; // List of owned variables
- }),
- (Temporaries, struct {
- ::std::vector<unsigned int> temporaries; // Controlled temporaries
+TAGGED_UNION(ScopeType, Owning,
+ (Owning, struct {
+ bool is_temporary;
+ ::std::vector<unsigned int> slots; // List of owned variables
}),
(Split, struct {
bool end_state_valid = false;
@@ -101,10 +99,18 @@ TAGGED_UNION(ScopeType, Variables,
}),
(Loop, struct {
// NOTE: This contains the original state for variables changed after `exit_state_valid` is true
- ::std::map<unsigned int,VarState> changed_vars;
- ::std::map<unsigned int,VarState> changed_tmps;
+ ::std::map<unsigned int,VarState> changed_slots;
+ ::std::map<unsigned int,VarState> changed_args;
bool exit_state_valid;
SplitEnd exit_state;
+ // TODO: Any drop flags allocated in the loop must be re-initialised at the start of the loop (or before a loopback)
+ ::MIR::BasicBlockId entry_bb;
+ ::std::vector<unsigned> drop_flags;
+ }),
+ // State which should end up with no mutation of variable states
+ (Freeze, struct {
+ //::std::map<unsigned int,VarState> changed_slots;
+ //::std::map<unsigned int,VarState> changed_args;
})
);
@@ -134,11 +140,13 @@ class MirBuilder
::MIR::RValue m_result;
bool m_result_valid;
- // TODO: Extra information.
+ // TODO: Extra information (e.g. mutability)
VarState m_return_state;
::std::vector<VarState> m_arg_states;
- ::std::vector<VarState> m_variable_states;
- ::std::vector<VarState> m_temporary_states;
+ ::std::vector<VarState> m_slot_states;
+ size_t m_first_temp_idx;
+
+ ::std::map<unsigned,unsigned> m_var_arg_mappings;
struct ScopeDef
{
@@ -177,6 +185,15 @@ public:
const ::HIR::TypeRef* is_type_owned_box(const ::HIR::TypeRef& ty) const;
// - Values
+ ::MIR::LValue get_variable(const Span& sp, unsigned idx) const {
+ // DIASBLED: State tracking doesn't support arguments in loops/splits
+#if 1
+ auto it = m_var_arg_mappings.find(idx);
+ if(it != m_var_arg_mappings.end())
+ return ::MIR::LValue::make_Argument({ it->second });
+#endif
+ return ::MIR::LValue::make_Local( idx );
+ }
::MIR::LValue new_temporary(const ::HIR::TypeRef& ty);
::MIR::LValue lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val);
@@ -228,8 +245,8 @@ public:
void mark_value_assigned(const Span& sp, const ::MIR::LValue& val);
// Moves control of temporaries up to the specified scope (or to above it)
- void raise_variables(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above=false);
- void raise_variables(const Span& sp, const ::MIR::RValue& rval, const ScopeHandle& scope, bool to_above=false);
+ void raise_temporaries(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above=false);
+ void raise_temporaries(const Span& sp, const ::MIR::RValue& rval, const ScopeHandle& scope, bool to_above=false);
void set_cur_block(unsigned int new_block);
::MIR::BasicBlockId pause_cur_block();
@@ -248,6 +265,7 @@ public:
ScopeHandle new_scope_temp(const Span& sp);
ScopeHandle new_scope_split(const Span& sp);
ScopeHandle new_scope_loop(const Span& sp);
+ ScopeHandle new_scope_freeze(const Span& sp);
/// Raises every variable defined in the source scope into the target scope
void raise_all(const Span& sp, ScopeHandle src, const ScopeHandle& target);
@@ -256,7 +274,7 @@ public:
/// Terminates a scope early (e.g. via return/break/...)
void terminate_scope_early(const Span& sp, const ScopeHandle& , bool loop_exit=false);
/// Marks the end of a split arm (end match arm, if body, ...)
- void end_split_arm(const Span& sp, const ScopeHandle& , bool reachable);
+ void end_split_arm(const Span& sp, const ScopeHandle& , bool reachable, bool early=false);
/// Terminates the current split early (TODO: What does this mean?)
void end_split_arm_early(const Span& sp);
@@ -269,13 +287,12 @@ public:
// Helper - Marks a variable/... as moved (and checks if the move is valid)
void moved_lvalue(const Span& sp, const ::MIR::LValue& lv);
private:
- const VarState& get_slot_state(const Span& sp, VarGroup ty, unsigned int idx, unsigned int skip_count=0) const;
- VarState& get_slot_state_mut(const Span& sp, VarGroup ty, unsigned int idx);
-
- const VarState& get_variable_state(const Span& sp, unsigned int idx, unsigned int skip_count=0) const;
- VarState& get_variable_state_mut(const Span& sp, unsigned int idx);
- const VarState& get_temp_state(const Span& sp, unsigned int idx, unsigned int skip_count=0) const;
- VarState& get_temp_state_mut(const Span& sp, unsigned int idx);
+ enum class SlotType {
+ Local, // Local ~0u is return
+ Argument
+ };
+ const VarState& get_slot_state(const Span& sp, unsigned int idx, SlotType type, unsigned int skip_count=0) const;
+ VarState& get_slot_state_mut(const Span& sp, unsigned int idx, SlotType type);
const VarState& get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count=0);
VarState& get_val_state_mut(const Span& sp, const ::MIR::LValue& lv);
diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp
index a68fd1bf..c10f170b 100644
--- a/src/mir/from_hir_match.cpp
+++ b/src/mir/from_hir_match.cpp
@@ -82,8 +82,7 @@ struct ArmCode {
::MIR::BasicBlockId code = 0;
bool has_condition = false;
::MIR::BasicBlockId cond_start;
- ::MIR::BasicBlockId cond_end;
- ::MIR::LValue cond_lval;
+ ::MIR::BasicBlockId cond_false;
::std::vector< ::MIR::BasicBlockId> destructures; // NOTE: Incomplete
mutable ::MIR::BasicBlockId cond_fail_tgt = 0;
@@ -219,7 +218,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod
{
if( pat.m_binding.m_type != ::HIR::PatternBinding::Type::Move)
return false;
- return !builder.lvalue_is_copy( sp, ::MIR::LValue::make_Variable( pat.m_binding.m_slot) );
+ return !builder.lvalue_is_copy( sp, builder.get_variable(sp, pat.m_binding.m_slot) );
}
TU_MATCHA( (pat.m_data), (e),
(Any,
@@ -355,9 +354,12 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod
}
builder.terminate_scope( sp, mv$(pat_scope) );
+ ac.code = builder.new_bb_unlinked();
+
// Condition
// NOTE: Lack of drop due to early exit from this arm isn't an issue. All captures must be Copy
// - The above is rustc E0008 "cannot bind by-move into a pattern guard"
+ // TODO: Create a special wrapping scope for the conditions that forces any moves to use a drop flag
if(arm.m_cond)
{
if( H::is_pattern_move(sp, builder, arm.m_patterns[0]) )
@@ -370,11 +372,18 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod
ac.cond_start = builder.new_bb_unlinked();
builder.set_cur_block( ac.cond_start );
+ auto freeze_scope = builder.new_scope_freeze(arm.m_cond->span());
auto tmp_scope = builder.new_scope_temp(arm.m_cond->span());
conv.visit_node_ptr( arm.m_cond );
- ac.cond_lval = builder.get_result_in_if_cond(arm.m_cond->span());
+ auto cond_lval = builder.get_result_in_if_cond(arm.m_cond->span());
builder.terminate_scope( arm.m_code->span(), mv$(tmp_scope) );
- ac.cond_end = builder.pause_cur_block();
+ ac.cond_false = builder.new_bb_unlinked();
+ builder.end_block(::MIR::Terminator::make_If({ mv$(cond_lval), ac.code, ac.cond_false }));
+
+ builder.set_cur_block(ac.cond_false);
+ builder.end_split_arm(arm.m_cond->span(), match_scope, true, true);
+ builder.pause_cur_block();
+ builder.terminate_scope( arm.m_code->span(), mv$(freeze_scope) );
// NOTE: Paused so that later code (which knows what the false branch will be) can end it correctly
@@ -390,7 +399,6 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod
// Code
DEBUG("-- Body Code");
- ac.code = builder.new_bb_unlinked();
auto tmp_scope = builder.new_scope_temp(arm.m_code->span());
builder.set_cur_block( ac.code );
conv.visit_node_ptr( arm.m_code );
@@ -1923,8 +1931,8 @@ void MIR_LowerHIR_Match_Simple( MirBuilder& builder, MirConverter& conv, ::HIR::
}
if( arm_code.has_condition )
{
- builder.set_cur_block( arm_code.cond_end );
- builder.end_block( ::MIR::Terminator::make_If({ mv$(arm_code.cond_lval), arm_code.code, next_arm_bb }) );
+ builder.set_cur_block( arm_code.cond_false );
+ builder.end_block( ::MIR::Terminator::make_Goto(next_arm_bb) );
}
builder.set_cur_block( next_arm_bb );
}
@@ -2625,8 +2633,8 @@ void MatchGenGrouped::gen_for_slice(t_rules_subset arm_rules, size_t ofs, ::MIR:
{
ac.cond_fail_tgt = next;
- m_builder.set_cur_block( ac.cond_end );
- m_builder.end_block( ::MIR::Terminator::make_If({ ac.cond_lval.clone(), ac.code, next }) );
+ m_builder.set_cur_block( ac.cond_false );
+ m_builder.end_block( ::MIR::Terminator::make_Goto(next) );
}
}
diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp
index c38e73e9..e51c9180 100644
--- a/src/mir/helpers.cpp
+++ b/src/mir/helpers.cpp
@@ -70,24 +70,20 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_static_type(::HIR::TypeRef& tmp, c
const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val) const
{
TU_MATCH(::MIR::LValue, (val), (e),
- (Variable,
- MIR_ASSERT(*this, e < m_fcn.named_variables.size(), val << " out of range (" << m_fcn.named_variables.size() << ")");
- return m_fcn.named_variables.at(e);
- ),
- (Temporary,
- MIR_ASSERT(*this, e.idx < m_fcn.temporaries.size(), val << " out of range (" << m_fcn.temporaries.size() << ")");
- return m_fcn.temporaries.at(e.idx);
+ (Return,
+ return m_ret_type;
),
(Argument,
- MIR_ASSERT(*this, e.idx < m_args.size(), val << " out of range (" << m_args.size() << ")");
+ MIR_ASSERT(*this, e.idx < m_args.size(), "Argument " << val << " out of range (" << m_args.size() << ")");
return m_args.at(e.idx).second;
),
+ (Local,
+ MIR_ASSERT(*this, e < m_fcn.locals.size(), "Local " << val << " out of range (" << m_fcn.locals.size() << ")");
+ return m_fcn.locals.at(e);
+ ),
(Static,
return get_static_type(tmp, e);
),
- (Return,
- return m_ret_type;
- ),
(Field,
const auto& ty = this->get_lvalue_type(tmp, *e.val);
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
@@ -292,11 +288,40 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
}
),
(ItemAddr,
- MIR_TODO(*this, "get_const_type - Get type for constant `" << c << "`");
+ MonomorphState p;
+ auto v = m_resolve.get_value(this->sp, e, p, /*signature_only=*/true);
+ TU_MATCHA( (v), (ve),
+ (NotFound,
+ MIR_BUG(*this, "get_const_type - ItemAddr points to unknown value - " << c);
+ ),
+ (Constant,
+ MIR_TODO(*this, "get_const_type - Get type for constant borrow `" << c << "`");
+ ),
+ (Static,
+ MIR_TODO(*this, "get_const_type - Get type for static borrow `" << c << "`");
+ ),
+ (Function,
+ ::HIR::FunctionType ft;
+ ft.is_unsafe = ve->m_unsafe;
+ ft.m_abi = ve->m_abi;
+ ft.m_rettype = box$( p.monomorph(this->sp, ve->m_return) );
+ ft.m_arg_types.reserve(ve->m_args.size());
+ for(const auto& arg : ve->m_args)
+ ft.m_arg_types.push_back( p.monomorph(this->sp, arg.second) );
+ auto rv = ::HIR::TypeRef( mv$(ft) );
+ m_resolve.expand_associated_types(this->sp, rv);
+ return rv;
+ )
+ )
)
)
throw "";
}
+bool ::MIR::TypeResolve::lvalue_is_copy(const ::MIR::LValue& val) const
+{
+ ::HIR::TypeRef tmp;
+ return m_resolve.type_is_copy( this->sp, get_lvalue_type(tmp, val) );
+}
const ::HIR::TypeRef* ::MIR::TypeResolve::is_type_owned_box(const ::HIR::TypeRef& ty) const
{
return m_resolve.is_type_owned_box(ty);
@@ -314,16 +339,14 @@ namespace visit {
if( cb(lv, u) )
return true;
TU_MATCHA( (lv), (e),
- (Variable,
+ (Return,
),
(Argument,
),
- (Temporary,
+ (Local,
),
(Static,
),
- (Return,
- ),
(Field,
return visit_mir_lvalue(*e.val, u, cb);
),
@@ -458,6 +481,9 @@ namespace visit {
(Switch,
rv |= visit_mir_lvalue(e.val, ValUsage::Read, cb);
),
+ (SwitchValue,
+ rv |= visit_mir_lvalue(e.val, ValUsage::Read, cb);
+ ),
(Call,
if( e.fcn.is_Value() ) {
rv |= visit_mir_lvalue(e.fcn.as_Value(), ValUsage::Read, cb);
@@ -547,28 +573,32 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c
}
block_offsets.push_back(statement_count); // Store the final limit for later code to use.
- ::std::vector<ValueLifetime> temporary_lifetimes( fcn.temporaries.size(), ValueLifetime(statement_count) );
- ::std::vector<ValueLifetime> variable_lifetimes( fcn.named_variables.size(), ValueLifetime(statement_count) );
-
+ ::std::vector<ValueLifetime> slot_lifetimes( fcn.locals.size(), ValueLifetime(statement_count) );
// Enumerate direct assignments of variables (linear iteration of BB list)
for(size_t bb_idx = 0; bb_idx < fcn.blocks.size(); bb_idx ++)
{
auto assigned_lvalue = [&](size_t bb_idx, size_t stmt_idx, const ::MIR::LValue& lv) {
// NOTE: Fills the first statement after running, just to ensure that any assigned value has _a_ lifetime
- if( const auto* de = lv.opt_Variable() )
- {
- MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, variable_lifetimes[*de]);
- variable_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
- }
- else if( const auto* de = lv.opt_Temporary() )
+ if( const auto* de = lv.opt_Local() )
{
- MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, temporary_lifetimes[de->idx]);
- temporary_lifetimes[de->idx].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
+ MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]);
+ slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
}
else
{
- // Not a direct assignment of a slot
+ // Not a direct assignment of a slot. But check if a slot is mutated as part of this.
+ ::MIR::visit::visit_mir_lvalue(lv, ValUsage::Write, [&](const auto& ilv, ValUsage vu) {
+ if( const auto* de = ilv.opt_Local() )
+ {
+ if( vu == ValUsage::Write )
+ {
+ MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]);
+ slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
+ }
+ }
+ return false;
+ });
}
};
@@ -589,6 +619,14 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c
assigned_lvalue(bb_idx, stmt_idx+1, e.second);
}
}
+ else if( const auto* se = stmt.opt_Drop() )
+ {
+ // HACK: Mark values as valid wherever there's a drop (prevents confusion by simple validator)
+ if( const auto* de = se->slot.opt_Local() )
+ {
+ slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx);
+ }
+ }
}
state.set_cur_stmt_term(bb_idx);
@@ -601,25 +639,18 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c
// Dump out variable lifetimes.
if( dump_debug )
{
- for(unsigned int i = 0; i < temporary_lifetimes.size(); i ++)
- {
- temporary_lifetimes[i].dump_debug("tmp", i, block_offsets);
- }
- for(unsigned int i = 0; i < variable_lifetimes.size(); i ++)
+ for(size_t i = 0; i < slot_lifetimes.size(); i ++)
{
- variable_lifetimes[i].dump_debug("var", i, block_offsets);
+ slot_lifetimes[i].dump_debug("_", i, block_offsets);
}
}
::MIR::ValueLifetimes rv;
rv.m_block_offsets = mv$(block_offsets);
- rv.m_temporaries.reserve( temporary_lifetimes.size() );
- for(auto& lft : temporary_lifetimes)
- rv.m_temporaries.push_back( ::MIR::ValueLifetime(mv$(lft.stmt_bitmap)) );
- rv.m_variables.reserve( variable_lifetimes.size() );
- for(auto& lft : variable_lifetimes)
- rv.m_variables.push_back( ::MIR::ValueLifetime(mv$(lft.stmt_bitmap)) );
+ rv.m_slots.reserve( slot_lifetimes.size() );
+ for(auto& lft : slot_lifetimes)
+ rv.m_slots.push_back( ::MIR::ValueLifetime(mv$(lft.stmt_bitmap)) );
return rv;
}
void MIR_Helper_GetLifetimes_DetermineValueLifetime(
@@ -923,6 +954,13 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(
m_states_to_do.push_back( ::std::make_pair(te.targets[i], mv$(s)) );
}
),
+ (SwitchValue,
+ for(size_t i = 0; i < te.targets.size(); i ++)
+ {
+ m_states_to_do.push_back( ::std::make_pair(te.targets[i], state.clone()) );
+ }
+ m_states_to_do.push_back( ::std::make_pair(te.def_target, mv$(state)) );
+ ),
(Call,
if( te.ret_val == m_lv )
{
diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp
index 802ce88f..f241753e 100644
--- a/src/mir/helpers.hpp
+++ b/src/mir/helpers.hpp
@@ -104,6 +104,7 @@ public:
::HIR::TypeRef get_const_type(const ::MIR::Constant& c) const;
+ bool lvalue_is_copy(const ::MIR::LValue& val) const;
const ::HIR::TypeRef* is_type_owned_box(const ::HIR::TypeRef& ty) const;
friend ::std::ostream& operator<<(::std::ostream& os, const TypeResolve& x) {
@@ -158,14 +159,10 @@ public:
struct ValueLifetimes
{
::std::vector<size_t> m_block_offsets;
- ::std::vector<ValueLifetime> m_temporaries;
- ::std::vector<ValueLifetime> m_variables;
+ ::std::vector<ValueLifetime> m_slots;
- bool var_valid(unsigned var_idx, unsigned bb_idx, unsigned stmt_idx) const {
- return m_variables.at(var_idx).valid_at( m_block_offsets[bb_idx] + stmt_idx );
- }
- bool tmp_valid(unsigned tmp_idx, unsigned bb_idx, unsigned stmt_idx) const {
- return m_temporaries.at(tmp_idx).valid_at( m_block_offsets[bb_idx] + stmt_idx );
+ bool slot_valid(unsigned idx, unsigned bb_idx, unsigned stmt_idx) const {
+ return m_slots.at(idx).valid_at( m_block_offsets[bb_idx] + stmt_idx );
}
};
diff --git a/src/mir/main_bindings.hpp b/src/mir/main_bindings.hpp
index 0d6074cb..4e7e3b78 100644
--- a/src/mir/main_bindings.hpp
+++ b/src/mir/main_bindings.hpp
@@ -18,4 +18,4 @@ extern void MIR_CheckCrate(/*const*/ ::HIR::Crate& crate);
extern void MIR_CheckCrate_Full(/*const*/ ::HIR::Crate& crate);
extern void MIR_CleanupCrate(::HIR::Crate& crate);
-extern void MIR_OptimiseCrate(::HIR::Crate& crate);
+extern void MIR_OptimiseCrate(::HIR::Crate& crate, bool minimal_optimisations);
diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp
index 9edc925b..09e978f9 100644
--- a/src/mir/mir.cpp
+++ b/src/mir/mir.cpp
@@ -92,21 +92,18 @@ namespace MIR {
::std::ostream& operator<<(::std::ostream& os, const LValue& x)
{
TU_MATCHA( (x), (e),
- (Variable,
- os << "Variable(" << e << ")";
- ),
- (Temporary,
- os << "Temporary(" << e.idx << ")";
+ (Return,
+ os << "Return";
),
(Argument,
os << "Argument(" << e.idx << ")";
),
+ (Local,
+ os << "Local(" << e << ")";
+ ),
(Static,
os << "Static(" << e << ")";
),
- (Return,
- os << "Return";
- ),
(Field,
os << "Field(" << e.field_index << ", " << *e.val << ")";
),
@@ -127,20 +124,17 @@ namespace MIR {
if( a.tag() != b.tag() )
return a.tag() < b.tag();
TU_MATCHA( (a, b), (ea, eb),
- (Variable,
- return ea < eb;
- ),
- (Temporary,
- return ea.idx < eb.idx;
+ (Return,
+ return false;
),
(Argument,
return ea.idx < eb.idx;
),
- (Static,
+ (Local,
return ea < eb;
),
- (Return,
- return false;
+ (Static,
+ return ea < eb;
),
(Field,
if( *ea.val != *eb.val )
@@ -170,20 +164,17 @@ namespace MIR {
if( a.tag() != b.tag() )
return false;
TU_MATCHA( (a, b), (ea, eb),
- (Variable,
- return ea == eb;
- ),
- (Temporary,
- return ea.idx == eb.idx;
+ (Return,
+ return true;
),
(Argument,
return ea.idx == eb.idx;
),
- (Static,
+ (Local,
return ea == eb;
),
- (Return,
- return true;
+ (Static,
+ return ea == eb;
),
(Field,
if( *ea.val != *eb.val )
@@ -428,6 +419,24 @@ namespace MIR {
os << j << " => bb" << e.targets[j] << ", ";
os << ")";
),
+ (SwitchValue,
+ os << "SwitchValue( " << e.val << " : ";
+ TU_MATCHA( (e.values), (ve),
+ (Unsigned,
+ for(unsigned int j = 0; j < e.targets.size(); j ++)
+ os << ve[j] << " => bb" << e.targets[j] << ", ";
+ ),
+ (Signed,
+ for(unsigned int j = 0; j < e.targets.size(); j ++)
+ os << (ve[j] >= 0 ? "+" : "") << ve[j] << " => bb" << e.targets[j] << ", ";
+ ),
+ (String,
+ for(unsigned int j = 0; j < e.targets.size(); j ++)
+ os << "\"" << ve[j] << "\" => bb" << e.targets[j] << ", ";
+ )
+ )
+ os << "else bb" << e.def_target << ")";
+ ),
(Call,
os << "Call( " << e.ret_val << " = ";
TU_MATCHA( (e.fcn), (e2),
@@ -486,10 +495,8 @@ namespace MIR {
),
(ScopeEnd,
os << "ScopeEnd(";
- for(auto idx : e.vars)
- os << "var$" << idx << ",";
- for(auto idx : e.tmps)
- os << "tmp$" << idx << ",";
+ for(auto idx : e.slots)
+ os << "_$" << idx << ",";
os << ")";
)
)
@@ -500,11 +507,10 @@ namespace MIR {
::MIR::LValue MIR::LValue::clone() const
{
TU_MATCHA( (*this), (e),
- (Variable, return LValue(e); ),
- (Temporary, return LValue(e); ),
+ (Return, return LValue(e); ),
(Argument, return LValue(e); ),
+ (Local, return LValue(e); ),
(Static, return LValue(e.clone()); ),
- (Return, return LValue(e); ),
(Field, return LValue::make_Field({
box$( e.val->clone() ),
e.field_index
@@ -616,3 +622,19 @@ namespace MIR {
throw "";
}
+::MIR::SwitchValues MIR::SwitchValues::clone() const
+{
+ TU_MATCHA( (*this), (ve),
+ (Unsigned,
+ return ve;
+ ),
+ (Signed,
+ return ve;
+ ),
+ (String,
+ return ve;
+ )
+ )
+ throw "";
+}
+
diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp
index c22f8d5d..987e0498 100644
--- a/src/mir/mir.hpp
+++ b/src/mir/mir.hpp
@@ -17,21 +17,15 @@ typedef unsigned int RegionId;
typedef unsigned int BasicBlockId;
// "LVALUE" - Assignable values
-TAGGED_UNION_EX(LValue, (), Variable, (
- // User-named variable
- (Variable, unsigned int),
- // Temporary with no user-defined name
- (Temporary, struct {
- unsigned int idx;
- }),
- // Function argument (matters for destructuring)
- (Argument, struct {
- unsigned int idx;
- }),
- // `static` or `static mut`
- (Static, ::HIR::Path),
+TAGGED_UNION_EX(LValue, (), Return, (
// Function return
(Return, struct{}),
+ // Function argument (input)
+ (Argument, struct { unsigned int idx; }),
+ // Variable/Temporary
+ (Local, unsigned int),
+ // `static` or `static mut`
+ (Static, ::HIR::Path),
// Field access (tuple, struct, tuple struct, enum field, ...)
// NOTE: Also used to index an array/slice by a compile-time known index (e.g. in destructuring)
(Field, struct {
@@ -217,6 +211,14 @@ TAGGED_UNION(CallTarget, Intrinsic,
::HIR::PathParams params;
})
);
+TAGGED_UNION_EX(SwitchValues, (), Unsigned, (
+ (Unsigned, ::std::vector<uint64_t>),
+ (Signed, ::std::vector<int64_t>),
+ (String, ::std::vector<::std::string>)
+ ), (),(), (
+ SwitchValues clone() const;
+ )
+ );
TAGGED_UNION(Terminator, Incomplete,
(Incomplete, struct {}), // Block isn't complete (ERROR in output)
@@ -233,6 +235,12 @@ TAGGED_UNION(Terminator, Incomplete,
LValue val;
::std::vector<BasicBlockId> targets;
}),
+ (SwitchValue, struct {
+ LValue val;
+ BasicBlockId def_target;
+ ::std::vector<BasicBlockId> targets;
+ SwitchValues values;
+ }),
(Call, struct {
BasicBlockId ret_block;
BasicBlockId panic_block;
@@ -274,8 +282,7 @@ TAGGED_UNION(Statement, Assign,
unsigned int flag_idx; // Valid if != ~0u
}),
(ScopeEnd, struct {
- ::std::vector<unsigned> vars;
- ::std::vector<unsigned> tmps;
+ ::std::vector<unsigned> slots;
})
);
extern ::std::ostream& operator<<(::std::ostream& os, const Statement& x);
@@ -290,9 +297,8 @@ struct BasicBlock
class Function
{
public:
- // TODO: Unify Variables, Temporaries, and Arguments
- ::std::vector< ::HIR::TypeRef> named_variables;
- ::std::vector< ::HIR::TypeRef> temporaries;
+ ::std::vector< ::HIR::TypeRef> locals;
+ //::std::vector< ::std::string> local_names;
::std::vector<bool> drop_flags;
::std::vector<BasicBlock> blocks;
diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp
index 478146e8..97942ba2 100644
--- a/src/mir/mir_builder.cpp
+++ b/src/mir/mir_builder.cpp
@@ -26,21 +26,30 @@ MirBuilder::MirBuilder(const Span& sp, const StaticTraitResolve& resolve, const
}
set_cur_block( new_bb_unlinked() );
- m_scopes.push_back( ScopeDef { sp } );
+ m_scopes.push_back( ScopeDef { sp, ScopeType::make_Owning({ false, {} }) } );
m_scope_stack.push_back( 0 );
- m_scopes.push_back( ScopeDef { sp, ScopeType::make_Temporaries({}) } );
+ m_scopes.push_back( ScopeDef { sp, ScopeType::make_Owning({ true, {} }) } );
m_scope_stack.push_back( 1 );
+ m_arg_states.reserve( args.size() );
+ for(size_t i = 0; i < args.size(); i ++)
+ m_arg_states.push_back( VarState::make_Valid({}) );
+ m_slot_states.resize( output.locals.size() );
+ m_first_temp_idx = output.locals.size();
+ DEBUG("First temporary will be " << m_first_temp_idx);
m_if_cond_lval = this->new_temporary(::HIR::CoreType::Bool);
- m_arg_states.reserve( args.size() );
- for(size_t i = 0; i < args.size(); i ++ )
- m_arg_states.push_back( VarState::make_Valid({}) );
- m_variable_states.reserve( output.named_variables.size() );
- for(size_t i = 0; i < output.named_variables.size(); i ++ )
- m_variable_states.push_back( VarState::make_Invalid(InvalidType::Uninit) );
+ // Determine which variables can be replaced by arguents
+ for(size_t i = 0; i < args.size(); i ++)
+ {
+ const auto& pat = args[i].first;
+ if( pat.m_binding.is_valid() && pat.m_binding.m_type == ::HIR::PatternBinding::Type::Move )
+ {
+ m_var_arg_mappings[pat.m_binding.m_slot] = i;
+ }
+ }
}
MirBuilder::~MirBuilder()
{
@@ -51,8 +60,9 @@ MirBuilder::~MirBuilder()
{
push_stmt_assign( sp, ::MIR::LValue::make_Return({}), get_result(sp) );
}
- terminate_scope( sp, ScopeHandle { *this, 1 } );
- terminate_scope( sp, mv$(m_fcn_scope) );
+
+ terminate_scope_early(sp, fcn_scope());
+
end_block( ::MIR::Terminator::make_Return({}) );
}
}
@@ -74,7 +84,7 @@ const ::HIR::TypeRef* MirBuilder::is_type_owned_box(const ::HIR::TypeRef& ty) co
if( pe.m_path != *m_lang_Box ) {
return nullptr;
}
- // TODO: Properly assert?
+ // TODO: Properly assert the size?
return &pe.m_params.m_types.at(0);
}
else
@@ -85,18 +95,21 @@ const ::HIR::TypeRef* MirBuilder::is_type_owned_box(const ::HIR::TypeRef& ty) co
void MirBuilder::define_variable(unsigned int idx)
{
- DEBUG("DEFINE var" << idx << ": " << m_output.named_variables.at(idx));
+ DEBUG("DEFINE (var) _" << idx << ": " << m_output.locals.at(idx));
for( auto scope_idx : ::reverse(m_scope_stack) )
{
auto& scope_def = m_scopes.at(scope_idx);
TU_MATCH_DEF( ScopeType, (scope_def.data), (e),
(
),
- (Variables,
- auto it = ::std::find(e.vars.begin(), e.vars.end(), idx);
- assert(it == e.vars.end());
- e.vars.push_back( idx );
- return ;
+ (Owning,
+ if( !e.is_temporary )
+ {
+ auto it = ::std::find(e.slots.begin(), e.slots.end(), idx);
+ assert(it == e.slots.end());
+ e.slots.push_back( idx );
+ return ;
+ }
),
(Split,
BUG(Span(), "Variable " << idx << " introduced within a Split");
@@ -107,20 +120,24 @@ void MirBuilder::define_variable(unsigned int idx)
}
::MIR::LValue MirBuilder::new_temporary(const ::HIR::TypeRef& ty)
{
- unsigned int rv = m_output.temporaries.size();
- DEBUG("DEFINE tmp" << rv << ": " << ty);
+ unsigned int rv = m_output.locals.size();
+ DEBUG("DEFINE (temp) _" << rv << ": " << ty);
- m_output.temporaries.push_back( ty.clone() );
- m_temporary_states.push_back( VarState::make_Invalid(InvalidType::Uninit) );
- assert(m_output.temporaries.size() == m_temporary_states.size());
+ assert(m_output.locals.size() == m_slot_states.size());
+ m_output.locals.push_back( ty.clone() );
+ m_slot_states.push_back( VarState::make_Invalid(InvalidType::Uninit) );
+ assert(m_output.locals.size() == m_slot_states.size());
ScopeDef* top_scope = nullptr;
for(unsigned int i = m_scope_stack.size(); i --; )
{
auto idx = m_scope_stack[i];
- if( m_scopes.at( idx ).data.is_Temporaries() ) {
- top_scope = &m_scopes.at(idx);
- break ;
+ if( const auto* e = m_scopes.at( idx ).data.opt_Owning() ) {
+ if( e->is_temporary )
+ {
+ top_scope = &m_scopes.at(idx);
+ break ;
+ }
}
else if( m_scopes.at(idx).data.is_Loop() )
{
@@ -140,9 +157,10 @@ void MirBuilder::define_variable(unsigned int idx)
}
}
assert( top_scope );
- auto& tmp_scope = top_scope->data.as_Temporaries();
- tmp_scope.temporaries.push_back( rv );
- return ::MIR::LValue::make_Temporary({rv});
+ auto& tmp_scope = top_scope->data.as_Owning();
+ assert(tmp_scope.is_temporary);
+ tmp_scope.slots.push_back( rv );
+ return ::MIR::LValue::make_Local(rv);
}
::MIR::LValue MirBuilder::lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val)
{
@@ -151,7 +169,7 @@ void MirBuilder::define_variable(unsigned int idx)
)
else {
auto temp = new_temporary(ty);
- push_stmt_assign( sp, ::MIR::LValue(temp.as_Temporary()), mv$(val) );
+ push_stmt_assign( sp, temp.clone(), mv$(val) );
return temp;
}
}
@@ -320,12 +338,6 @@ void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int
}
this->push_stmt(sp, ::MIR::Statement::make_Drop({ ::MIR::eDropKind::DEEP, mv$(val), flag }));
-
- if( flag != ~0u )
- {
- // Reset flag value back to default.
- push_stmt_set_dropflag_val(sp, flag, m_output.drop_flags.at(flag));
- }
}
void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/)
{
@@ -335,12 +347,6 @@ void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val, unsig
// TODO: Ensure that the type is a Box?
this->push_stmt(sp, ::MIR::Statement::make_Drop({ ::MIR::eDropKind::SHALLOW, mv$(val), flag }));
-
- if( flag != ~0u )
- {
- // Reset flag value back to default.
- push_stmt_set_dropflag_val(sp, flag, m_output.drop_flags.at(flag));
- }
}
void MirBuilder::push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data)
{
@@ -355,7 +361,7 @@ void MirBuilder::push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data)
}
void MirBuilder::push_stmt_set_dropflag_val(const Span& sp, unsigned int idx, bool value)
{
- this->push_stmt(sp, ::MIR::Statement::make_SetDropFlag({ idx, value }));
+ this->push_stmt(sp, ::MIR::Statement::make_SetDropFlag({ idx, value, ~0u }));
}
void MirBuilder::push_stmt_set_dropflag_other(const Span& sp, unsigned int idx, unsigned int other)
{
@@ -363,7 +369,7 @@ void MirBuilder::push_stmt_set_dropflag_other(const Span& sp, unsigned int idx,
}
void MirBuilder::push_stmt_set_dropflag_default(const Span& sp, unsigned int idx)
{
- this->push_stmt(sp, ::MIR::Statement::make_SetDropFlag({ idx, this->get_drop_flag_default(sp, idx) }));
+ this->push_stmt(sp, ::MIR::Statement::make_SetDropFlag({ idx, this->get_drop_flag_default(sp, idx), ~0u }));
}
void MirBuilder::push_stmt(const Span& sp, ::MIR::Statement stmt)
{
@@ -378,26 +384,15 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst)
TU_MATCH_DEF(::MIR::LValue, (dst), (e),
(
),
- (Temporary,
- state_p = &get_temp_state_mut(sp, e.idx);
- if( const auto* se = state_p->opt_Invalid() )
- {
- if( *se != InvalidType::Uninit ) {
- BUG(sp, "Reassigning temporary " << e.idx << " - " << *state_p);
- }
- }
- else {
- // TODO: This should be a bug, but some of the match code ends up reassigning so..
- //BUG(sp, "Reassigning temporary " << e.idx << " - " << *state_p);
- }
- ),
(Return,
// Don't drop.
// No state tracking for the return value
),
- (Variable,
- // TODO: Ensure that slot is mutable (information is lost, assume true)
- state_p = &get_variable_state_mut(sp, e);
+ (Argument,
+ state_p = &get_slot_state_mut(sp, e.idx, SlotType::Argument);
+ ),
+ (Local,
+ state_p = &get_slot_state_mut(sp, e, SlotType::Local);
)
)
@@ -411,7 +406,7 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst)
}
}
-void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above/*=false*/)
+void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above/*=false*/)
{
TRACE_FUNCTION_F(val);
TU_MATCH_DEF(::MIR::LValue, (val), (e),
@@ -422,29 +417,34 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const
// TODO: This may not be correct, because it can change the drop points and ordering
// HACK: Working around cases where values are dropped while the result is not yet used.
(Index,
- raise_variables(sp, *e.val, scope, to_above);
- raise_variables(sp, *e.idx, scope, to_above);
+ raise_temporaries(sp, *e.val, scope, to_above);
+ raise_temporaries(sp, *e.idx, scope, to_above);
return ;
),
(Deref,
- raise_variables(sp, *e.val, scope, to_above);
+ raise_temporaries(sp, *e.val, scope, to_above);
return ;
),
(Field,
- raise_variables(sp, *e.val, scope, to_above);
+ raise_temporaries(sp, *e.val, scope, to_above);
return ;
),
(Downcast,
- raise_variables(sp, *e.val, scope, to_above);
+ raise_temporaries(sp, *e.val, scope, to_above);
return ;
),
// Actual value types
- (Variable,
- ),
- (Temporary,
+ (Local,
)
)
- ASSERT_BUG(sp, val.is_Variable() || val.is_Temporary(), "Hit value raising code with non-variable value - " << val);
+ ASSERT_BUG(sp, val.is_Local(), "Hit value raising code with non-variable value - " << val);
+ const auto idx = val.as_Local();
+ bool is_temp = (idx >= m_first_temp_idx);
+ /*
+ if( !is_temp ) {
+ return ;
+ }
+ */
// Find controlling scope
auto scope_it = m_scope_stack.rbegin();
@@ -457,30 +457,20 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const
DEBUG(val << " defined in or above target (scope " << scope << ")");
}
- TU_IFLET( ScopeType, scope_def.data, Variables, e,
- if( const auto* ve = val.opt_Variable() )
+ TU_IFLET( ScopeType, scope_def.data, Owning, e,
+ if( e.is_temporary == is_temp )
{
- auto idx = *ve;
- auto tmp_it = ::std::find( e.vars.begin(), e.vars.end(), idx );
- if( tmp_it != e.vars.end() )
+ auto tmp_it = ::std::find(e.slots.begin(), e.slots.end(), idx);
+ if( tmp_it != e.slots.end() )
{
- e.vars.erase( tmp_it );
- DEBUG("Raise variable " << idx << " from " << *scope_it);
+ e.slots.erase( tmp_it );
+ DEBUG("Raise slot " << idx << " from " << *scope_it);
break ;
}
}
- )
- else TU_IFLET( ScopeType, scope_def.data, Temporaries, e,
- if( const auto* ve = val.opt_Temporary() )
+ else
{
- auto idx = ve->idx;
- auto tmp_it = ::std::find( e.temporaries.begin(), e.temporaries.end(), idx );
- if( tmp_it != e.temporaries.end() )
- {
- e.temporaries.erase( tmp_it );
- DEBUG("Raise temporary " << idx << " from " << *scope_it);
- break ;
- }
+ // TODO: Should this care about variables?
}
)
else
@@ -536,26 +526,12 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const
target_seen = true;
}
- TU_IFLET( ScopeType, scope_def.data, Variables, e,
- if( target_seen )
+ TU_IFLET( ScopeType, scope_def.data, Owning, e,
+ if( target_seen && e.is_temporary == is_temp )
{
- if( const auto* ve = val.opt_Variable() )
- {
- e.vars.push_back( *ve );
- DEBUG("- to " << *scope_it);
- return ;
- }
- }
- )
- else TU_IFLET( ScopeType, scope_def.data, Temporaries, e,
- if( target_seen )
- {
- if( const auto* ve = val.opt_Temporary() )
- {
- e.temporaries.push_back( ve->idx );
- DEBUG("- to " << *scope_it);
- return ;
- }
+ e.slots.push_back( idx );
+ DEBUG("- to " << *scope_it);
+ return ;
}
)
else if( auto* sd_loop = scope_def.data.opt_Loop() )
@@ -566,19 +542,8 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const
if( sd_loop->exit_state_valid )
{
DEBUG("Adding " << val << " as unset to loop exit state");
- if( const auto* ve = val.opt_Variable() )
- {
- auto v = sd_loop->exit_state.var_states.insert( ::std::make_pair(*ve, VarState(InvalidType::Uninit)) );
- ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry");
- }
- else if( const auto* ve = val.opt_Temporary() )
- {
- auto v = sd_loop->exit_state.tmp_states.insert( ::std::make_pair(ve->idx, VarState(InvalidType::Uninit)) );
- ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry");
- }
- else {
- BUG(sp, "Impossible raise value");
- }
+ auto v = sd_loop->exit_state.states.insert( ::std::make_pair(idx, VarState(InvalidType::Uninit)) );
+ ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry");
}
else
{
@@ -592,19 +557,8 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const
if( sd_split->end_state_valid )
{
DEBUG("Adding " << val << " as unset to loop exit state");
- if( const auto* ve = val.opt_Variable() )
- {
- auto v = sd_split->end_state.var_states.insert( ::std::make_pair(*ve, VarState(InvalidType::Uninit)) );
- ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry");
- }
- else if( const auto* ve = val.opt_Temporary() )
- {
- auto v = sd_split->end_state.tmp_states.insert( ::std::make_pair(ve->idx, VarState(InvalidType::Uninit)) );
- ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry");
- }
- else {
- BUG(sp, "Impossible raise value");
- }
+ auto v = sd_split->end_state.states.insert( ::std::make_pair(idx, VarState(InvalidType::Uninit)) );
+ ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry");
}
else
{
@@ -613,20 +567,8 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const
// TODO: This should update the outer state to unset.
auto& arm = sd_split->arms.back();
- if( const auto* ve = val.opt_Variable() )
- {
- arm.var_states.insert(::std::make_pair( *ve, get_variable_state(sp, *ve).clone() ));
- m_variable_states.at(*ve) = VarState(InvalidType::Uninit);
- }
- else if( const auto* ve = val.opt_Temporary() )
- {
- arm.tmp_states.insert(::std::make_pair( ve->idx, get_temp_state(sp, ve->idx).clone() ));
- m_temporary_states.at(ve->idx) = VarState(InvalidType::Uninit);
- }
- else
- {
- BUG(sp, "Impossible raise value");
- }
+ arm.states.insert(::std::make_pair( idx, get_slot_state(sp, idx, SlotType::Local).clone() ));
+ m_slot_states.at(idx) = VarState(InvalidType::Uninit);
}
else
{
@@ -635,15 +577,15 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const
}
BUG(sp, "Couldn't find a scope to raise " << val << " into");
}
-void MirBuilder::raise_variables(const Span& sp, const ::MIR::RValue& rval, const ScopeHandle& scope, bool to_above/*=false*/)
+void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::RValue& rval, const ScopeHandle& scope, bool to_above/*=false*/)
{
auto raise_vars = [&](const ::MIR::Param& p) {
if( const auto* e = p.opt_LValue() )
- this->raise_variables(sp, *e, scope, to_above);
+ this->raise_temporaries(sp, *e, scope, to_above);
};
TU_MATCHA( (rval), (e),
(Use,
- this->raise_variables(sp, e, scope, to_above);
+ this->raise_temporaries(sp, e, scope, to_above);
),
(Constant,
),
@@ -652,23 +594,23 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::RValue& rval, cons
),
(Borrow,
// TODO: Wait, is this valid?
- this->raise_variables(sp, e.val, scope, to_above);
+ this->raise_temporaries(sp, e.val, scope, to_above);
),
(Cast,
- this->raise_variables(sp, e.val, scope, to_above);
+ this->raise_temporaries(sp, e.val, scope, to_above);
),
(BinOp,
raise_vars(e.val_l);
raise_vars(e.val_r);
),
(UniOp,
- this->raise_variables(sp, e.val, scope, to_above);
+ this->raise_temporaries(sp, e.val, scope, to_above);
),
(DstMeta,
- this->raise_variables(sp, e.val, scope, to_above);
+ this->raise_temporaries(sp, e.val, scope, to_above);
),
(DstPtr,
- this->raise_variables(sp, e.val, scope, to_above);
+ this->raise_temporaries(sp, e.val, scope, to_above);
),
(MakeDst,
raise_vars(e.ptr_val);
@@ -743,6 +685,14 @@ unsigned int MirBuilder::new_drop_flag(bool default_state)
{
auto rv = m_output.drop_flags.size();
m_output.drop_flags.push_back(default_state);
+ for(size_t i = m_scope_stack.size(); i --;)
+ {
+ if( auto* e = m_scopes.at(m_scope_stack[i]).data.opt_Loop() )
+ {
+ e->drop_flags.push_back(rv);
+ break;
+ }
+ }
DEBUG("(" << default_state << ") = " << rv);
return rv;
}
@@ -760,7 +710,7 @@ bool MirBuilder::get_drop_flag_default(const Span& sp, unsigned int idx)
ScopeHandle MirBuilder::new_scope_var(const Span& sp)
{
unsigned int idx = m_scopes.size();
- m_scopes.push_back( ScopeDef {sp, ScopeType::make_Variables({})} );
+ m_scopes.push_back( ScopeDef {sp, ScopeType::make_Owning({ false, {} })} );
m_scope_stack.push_back( idx );
DEBUG("START (var) scope " << idx);
return ScopeHandle { *this, idx };
@@ -768,7 +718,8 @@ ScopeHandle MirBuilder::new_scope_var(const Span& sp)
ScopeHandle MirBuilder::new_scope_temp(const Span& sp)
{
unsigned int idx = m_scopes.size();
- m_scopes.push_back( ScopeDef {sp, ScopeType::make_Temporaries({})} );
+
+ m_scopes.push_back( ScopeDef {sp, ScopeType::make_Owning({ true, {} })} );
m_scope_stack.push_back( idx );
DEBUG("START (temp) scope " << idx);
return ScopeHandle { *this, idx };
@@ -786,10 +737,19 @@ ScopeHandle MirBuilder::new_scope_loop(const Span& sp)
{
unsigned int idx = m_scopes.size();
m_scopes.push_back( ScopeDef {sp, ScopeType::make_Loop({})} );
+ m_scopes.back().data.as_Loop().entry_bb = m_current_block;
m_scope_stack.push_back( idx );
DEBUG("START (loop) scope " << idx);
return ScopeHandle { *this, idx };
}
+ScopeHandle MirBuilder::new_scope_freeze(const Span& sp)
+{
+ unsigned int idx = m_scopes.size();
+ m_scopes.push_back( ScopeDef {sp, ScopeType::make_Freeze({})} );
+ m_scope_stack.push_back( idx );
+ DEBUG("START (freeze) scope " << idx);
+ return ScopeHandle { *this, idx };
+}
void MirBuilder::terminate_scope(const Span& sp, ScopeHandle scope, bool emit_cleanup/*=true*/)
{
TRACE_FUNCTION_F("DONE scope " << scope.idx << " - " << (emit_cleanup ? "CLEANUP" : "NO CLEANUP"));
@@ -852,11 +812,13 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle
auto& src_scope_def = m_scopes.at(source.idx);
#if 1
- ASSERT_BUG(sp, src_scope_def.data.is_Temporaries(), "Rasising scopes can only be done on temporaries (source)");
- auto& src_list = src_scope_def.data.as_Temporaries().temporaries;
+ ASSERT_BUG(sp, src_scope_def.data.is_Owning(), "Rasising scopes can only be done on temporaries (source)");
+ ASSERT_BUG(sp, src_scope_def.data.as_Owning().is_temporary, "Rasising scopes can only be done on temporaries (source)");
+ auto& src_list = src_scope_def.data.as_Owning().slots;
for(auto idx : src_list)
{
- DEBUG("> Raising " << ::MIR::LValue::make_Temporary({ idx }));
+ DEBUG("> Raising " << ::MIR::LValue::make_Local(idx));
+ assert(idx >= m_first_temp_idx);
}
// Seek up stack until the target scope is seen
@@ -873,7 +835,7 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle
// Insert these values as Invalid, both in the existing exit state, and in the changed list
for(auto idx : src_list)
{
- auto v = sd_loop->exit_state.tmp_states.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) ));
+ auto v = sd_loop->exit_state.states.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) ));
ASSERT_BUG(sp, v.second, "");
}
}
@@ -884,7 +846,7 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle
for(auto idx : src_list)
{
- auto v2 = sd_loop->changed_tmps.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) ));
+ auto v2 = sd_loop->changed_slots.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) ));
ASSERT_BUG(sp, v2.second, "");
}
}
@@ -896,7 +858,7 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle
// Insert these indexes as Invalid
for(auto idx : src_list)
{
- auto v = sd_split->end_state.tmp_states.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) ));
+ auto v = sd_split->end_state.states.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) ));
ASSERT_BUG(sp, v.second, "");
}
}
@@ -910,8 +872,8 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle
auto& arm = sd_split->arms.back();
for(auto idx : src_list)
{
- arm.tmp_states.insert(::std::make_pair( idx, mv$(m_temporary_states.at(idx)) ));
- m_temporary_states.at(idx) = VarState(InvalidType::Uninit);
+ arm.states.insert(::std::make_pair( idx, mv$(m_slot_states.at(idx)) ));
+ m_slot_states.at(idx) = VarState(InvalidType::Uninit);
}
}
}
@@ -920,16 +882,17 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle
BUG(sp, "Moving values to a scope not on the stack - scope " << target.idx);
}
auto& tgt_scope_def = m_scopes.at(target.idx);
- ASSERT_BUG(sp, tgt_scope_def.data.is_Temporaries(), "Rasising scopes can only be done on temporaries (target)");
+ ASSERT_BUG(sp, tgt_scope_def.data.is_Owning(), "Rasising scopes can only be done on temporaries (target)");
+ ASSERT_BUG(sp, tgt_scope_def.data.as_Owning().is_temporary, "Rasising scopes can only be done on temporaries (target)");
// Move all defined variables from one to the other
- auto& tgt_list = tgt_scope_def.data.as_Temporaries().temporaries;
+ auto& tgt_list = tgt_scope_def.data.as_Owning().slots;
tgt_list.insert( tgt_list.end(), src_list.begin(), src_list.end() );
#else
auto list = src_scope_def.data.as_Temporaries().temporaries;
for(auto idx : list)
{
- this->raise_variables(sp, ::MIR::LValue::make_Temporary({ idx }), target);
+ this->raise_temporaries(sp, ::MIR::LValue::make_Temporary({ idx }), target);
}
#endif
@@ -985,6 +948,18 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope,
)
}
}
+
+
+ // Index 0 is the function scope, this only happens when about to return/panic
+ if( scope.idx == 0 )
+ {
+ // Ensure that all arguments are dropped if they were not moved
+ for(size_t i = 0; i < m_arg_states.size(); i ++)
+ {
+ const auto& state = get_slot_state(sp, i, SlotType::Argument);
+ this->drop_value_from_state(sp, state, ::MIR::LValue::make_Argument({ static_cast<unsigned>(i) }));
+ }
+ }
}
namespace
@@ -1017,6 +992,9 @@ namespace
old_state = VarState::make_Optional( new_flag );
#else
// TODO: Rewrite history. I.e. visit all previous branches and set this drop flag to `false` in all of them
+ for(auto pos : other_arms) {
+ builder.push_df_set_at(pos, flag_idx, false);
+ }
TODO(sp, "Drop flag default not false when going Invalid->Optional");
#endif
}
@@ -1041,6 +1019,10 @@ namespace
builder.push_stmt_set_dropflag_other(sp, new_flag, nse.outer_flag);
builder.push_stmt_set_dropflag_default(sp, nse.outer_flag);
ose.outer_flag = new_flag;
+#if 0
+ for(auto pos : other_arms) {
+ }
+#endif
}
}
else
@@ -1388,45 +1370,39 @@ void MirBuilder::terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_l
{
// Insert copies of parent state for newly changed values
// and Merge all changed values
- for(const auto& ent : sd_loop.changed_vars)
- {
- auto idx = ent.first;
- if( sd_loop.exit_state.var_states.count(idx) == 0 ) {
- sd_loop.exit_state.var_states.insert(::std::make_pair( idx, ent.second.clone() ));
- }
- auto& old_state = sd_loop.exit_state.var_states.at(idx);
- merge_state(sp, *this, ::MIR::LValue::make_Variable(idx), old_state, get_variable_state(sp, idx));
- }
- for(const auto& ent : sd_loop.changed_tmps)
- {
- auto idx = ent.first;
- if( sd_loop.exit_state.tmp_states.count(idx) == 0 ) {
- sd_loop.exit_state.tmp_states.insert(::std::make_pair( idx, ent.second.clone() ));
+ auto merge_list = [sp,this](const auto& changed, auto& exit_states, ::std::function<::MIR::LValue(unsigned)> val_cb, auto type) {
+ for(const auto& ent : changed)
+ {
+ auto idx = ent.first;
+ auto it = exit_states.find(idx);
+ if( it == exit_states.end() ) {
+ it = exit_states.insert(::std::make_pair( idx, ent.second.clone() )).first;
+ }
+ auto& old_state = it->second;
+ merge_state(sp, *this, val_cb(idx), old_state, get_slot_state(sp, idx, type));
}
- auto& old_state = sd_loop.exit_state.tmp_states.at(idx);
- merge_state(sp, *this, ::MIR::LValue::make_Temporary({idx}), old_state, get_temp_state(sp, idx));
- }
+ };
+ merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::make_Local, SlotType::Local);
+ merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::make_Argument({v}); }, SlotType::Argument);
}
else
{
+ auto init_list = [sp,this](const auto& changed, auto& exit_states, auto type) {
+ for(const auto& ent : changed)
+ {
+ DEBUG("Slot(" << ent.first << ") = " << ent.second);
+ auto idx = ent.first;
+ exit_states.insert(::std::make_pair( idx, get_slot_state(sp, idx, type).clone() ));
+ }
+ };
// Obtain states of changed variables/temporaries
- for(const auto& ent : sd_loop.changed_vars)
- {
- DEBUG("Variable(" << ent.first << ") = " << ent.second);
- auto idx = ent.first;
- sd_loop.exit_state.var_states.insert(::std::make_pair( idx, get_variable_state(sp, idx).clone() ));
- }
- for(const auto& ent : sd_loop.changed_tmps)
- {
- DEBUG("Temporary(" << ent.first << ") = " << ent.second);
- auto idx = ent.first;
- sd_loop.exit_state.tmp_states.insert(::std::make_pair( idx, get_temp_state(sp, idx).clone() ));
- }
+ init_list(sd_loop.changed_slots, sd_loop.exit_state.states, SlotType::Local);
+ init_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, SlotType::Argument);
sd_loop.exit_state_valid = true;
}
}
-void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool reachable)
+void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool reachable, bool early/*=false*/)
{
ASSERT_BUG(sp, handle.idx < m_scopes.size(), "Handle passed to end_split_arm is invalid");
auto& sd = m_scopes.at( handle.idx );
@@ -1445,41 +1421,29 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r
{
if( reachable )
{
- // Insert copies of the parent state
- for(const auto& ent : this_arm_state.var_states) {
- if( sd_split.end_state.var_states.count(ent.first) == 0 ) {
- sd_split.end_state.var_states.insert(::std::make_pair( ent.first, get_variable_state(sp, ent.first, 1).clone() ));
- }
- }
- for(const auto& ent : this_arm_state.tmp_states) {
- if( sd_split.end_state.tmp_states.count(ent.first) == 0 ) {
- sd_split.end_state.tmp_states.insert(::std::make_pair( ent.first, get_temp_state(sp, ent.first, 1).clone() ));
+ auto merge_list = [sp,this](const auto& states, auto& end_states, auto type) {
+ // Insert copies of the parent state
+ for(const auto& ent : states) {
+ if( end_states.count(ent.first) == 0 ) {
+ end_states.insert(::std::make_pair( ent.first, get_slot_state(sp, ent.first, type, 1).clone() ));
+ }
}
- }
-
- // Merge state
- for(auto& ent : sd_split.end_state.var_states)
- {
- auto idx = ent.first;
- auto& out_state = ent.second;
-
- // Merge the states
- auto it = this_arm_state.var_states.find(idx);
- const auto& src_state = (it != this_arm_state.var_states.end() ? it->second : get_variable_state(sp, idx, 1));
-
- merge_state(sp, *this, ::MIR::LValue::make_Variable(idx), out_state, src_state);
- }
- for(auto& ent : sd_split.end_state.tmp_states)
- {
- auto idx = ent.first;
- auto& out_state = ent.second;
+ // Merge state
+ for(auto& ent : end_states)
+ {
+ auto idx = ent.first;
+ auto& out_state = ent.second;
- // Merge the states
- auto it = this_arm_state.tmp_states.find(idx);
- const auto& src_state = (it != this_arm_state.tmp_states.end() ? it->second : get_temp_state(sp, idx, 1));
+ // Merge the states
+ auto it = states.find(idx);
+ const auto& src_state = (it != states.end() ? it->second : get_slot_state(sp, idx, type, 1));
- merge_state(sp, *this, ::MIR::LValue::make_Temporary({idx}), out_state, src_state);
- }
+ auto lv = (type == SlotType::Local ? ::MIR::LValue::make_Local(idx) : ::MIR::LValue::make_Argument({idx}));
+ merge_state(sp, *this, mv$(lv), out_state, src_state);
+ }
+ };
+ merge_list(this_arm_state.states, sd_split.end_state.states, SlotType::Local);
+ merge_list(this_arm_state.arg_states, sd_split.end_state.arg_states, SlotType::Argument);
}
else
{
@@ -1489,27 +1453,34 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r
else
{
// Clone this arm's state
- for(auto& ent : this_arm_state.var_states)
+ for(auto& ent : this_arm_state.states)
{
- DEBUG("Variable(" << ent.first << ") = " << ent.second);
- sd_split.end_state.var_states.insert(::std::make_pair( ent.first, ent.second.clone() ));
+ DEBUG("Slot(" << ent.first << ") = " << ent.second);
+ sd_split.end_state.states.insert(::std::make_pair( ent.first, ent.second.clone() ));
}
- for(auto& ent : this_arm_state.tmp_states)
+ for(auto& ent : this_arm_state.arg_states)
{
- DEBUG("Temporary(" << ent.first << ") = " << ent.second);
- sd_split.end_state.tmp_states.insert(::std::make_pair( ent.first, ent.second.clone() ));
+ DEBUG("Argument(" << ent.first << ") = " << ent.second);
+ sd_split.end_state.arg_states.insert(::std::make_pair( ent.first, ent.second.clone() ));
}
sd_split.end_state_valid = true;
}
- sd_split.arms.push_back( {} );
+ if( reachable )
+ {
+ assert(m_block_active);
+ }
+ if( !early )
+ {
+ sd_split.arms.push_back( {} );
+ }
}
void MirBuilder::end_split_arm_early(const Span& sp)
{
TRACE_FUNCTION_F("");
size_t i = m_scope_stack.size();
- // Terminate all scopes until a split is found.
- while( i -- && ! (m_scopes.at(m_scope_stack[i]).data.is_Split() || m_scopes.at(m_scope_stack[i]).data.is_Loop()) )
+ // Terminate every sequence of owning scopes
+ while( i -- && m_scopes.at(m_scope_stack[i]).data.is_Owning() )
{
auto& scope_def = m_scopes[m_scope_stack[i]];
// Fully drop the scope
@@ -1529,6 +1500,7 @@ void MirBuilder::end_split_arm_early(const Span& sp)
// TODO: Create drop flags if required?
}
+ // TODO: What if this is a loop?
}
}
void MirBuilder::complete_scope(ScopeDef& sd)
@@ -1536,37 +1508,37 @@ void MirBuilder::complete_scope(ScopeDef& sd)
sd.complete = true;
TU_MATCHA( (sd.data), (e),
- (Temporaries,
- DEBUG("Temporaries - " << e.temporaries);
- ),
- (Variables,
- DEBUG("Variables - " << e.vars);
+ (Owning,
+ DEBUG("Owning (" << (e.is_temporary ? "temps" : "vars") << ") - " << e.slots);
),
(Loop,
DEBUG("Loop");
),
(Split,
+ ),
+ (Freeze,
+ //DEBUG("Freeze");
)
)
struct H {
static void apply_end_state(const Span& sp, MirBuilder& builder, SplitEnd& end_state)
{
- for(auto& ent : end_state.var_states)
+ for(auto& ent : end_state.states)
{
- auto& vs = builder.get_variable_state_mut(sp, ent.first);
+ auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Local);
if( vs != ent.second )
{
- DEBUG(::MIR::LValue::make_Variable(ent.first) << " " << vs << " => " << ent.second);
+ DEBUG(::MIR::LValue::make_Local(ent.first) << " " << vs << " => " << ent.second);
vs = ::std::move(ent.second);
}
}
- for(auto& ent : end_state.tmp_states)
+ for(auto& ent : end_state.arg_states)
{
- auto& vs = builder.get_temp_state_mut(sp, ent.first);
+ auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Argument);
if( vs != ent.second )
{
- DEBUG(::MIR::LValue::make_Temporary({ent.first}) << " " << vs << " => " << ent.second);
+ DEBUG(::MIR::LValue::make_Argument({ent.first}) << " " << vs << " => " << ent.second);
vs = ::std::move(ent.second);
}
}
@@ -1574,13 +1546,20 @@ void MirBuilder::complete_scope(ScopeDef& sd)
};
// No macro for better debug output.
- if( sd.data.is_Loop() )
+ if( auto* e = sd.data.opt_Loop() )
{
- auto& e = sd.data.as_Loop();
TRACE_FUNCTION_F("Loop");
- if( e.exit_state_valid )
+ if( e->exit_state_valid )
+ {
+ H::apply_end_state(sd.span, *this, e->exit_state);
+ }
+
+ // Insert sets of drop flags to the first block (at the start of that block)
+ auto& stmts = m_output.blocks.at(e->entry_bb).statements;
+ for(auto idx : e->drop_flags)
{
- H::apply_end_state(sd.span, *this, e.exit_state);
+ DEBUG("Reset df$" << idx);
+ stmts.insert( stmts.begin(), ::MIR::Statement::make_SetDropFlag({ idx, m_output.drop_flags.at(idx), ~0u }) );
}
}
else if( sd.data.is_Split() )
@@ -1596,16 +1575,15 @@ void MirBuilder::complete_scope(ScopeDef& sd)
void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb) const
{
TU_MATCH(::MIR::LValue, (val), (e),
- (Variable,
- cb( m_output.named_variables.at(e) );
- ),
- (Temporary,
- cb( m_output.temporaries.at(e.idx) );
+ (Return,
+ TODO(sp, "Return");
),
(Argument,
- ASSERT_BUG(sp, e.idx < m_args.size(), "Argument number out of range");
cb( m_args.at(e.idx).second );
),
+ (Local,
+ cb( m_output.locals.at(e) );
+ ),
(Static,
TU_MATCHA( (e.m_data), (pe),
(Generic,
@@ -1624,9 +1602,6 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
)
)
),
- (Return,
- TODO(sp, "Return");
- ),
(Field,
with_val_type(sp, *e.val, [&](const auto& ty){
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
@@ -1821,7 +1796,7 @@ bool MirBuilder::lvalue_is_copy(const Span& sp, const ::MIR::LValue& val) const
return rv == 2;
}
-const VarState& MirBuilder::get_slot_state(const Span& sp, VarGroup ty, unsigned int idx, unsigned int skip_count/*=0*/) const
+const VarState& MirBuilder::get_slot_state(const Span& sp, unsigned int idx, SlotType type, unsigned int skip_count/*=0*/) const
{
// 1. Find an applicable Split scope
for( auto scope_idx : ::reverse(m_scope_stack) )
@@ -1830,146 +1805,114 @@ const VarState& MirBuilder::get_slot_state(const Span& sp, VarGroup ty, unsigned
TU_MATCH_DEF( ScopeType, (scope_def.data), (e),
(
),
- (Temporaries,
- if( ty == VarGroup::Temporary )
+ (Owning,
+ if( type == SlotType::Local )
{
- auto it = ::std::find(e.temporaries.begin(), e.temporaries.end(), idx);
- if( it != e.temporaries.end() ) {
- break ;
- }
- }
- ),
- (Variables,
- if( ty == VarGroup::Variable )
- {
- auto it = ::std::find(e.vars.begin(), e.vars.end(), idx);
- if( it != e.vars.end() ) {
- // If controlled by this block, exit early (won't find it elsewhere)
+ auto it = ::std::find(e.slots.begin(), e.slots.end(), idx);
+ if( it != e.slots.end() ) {
break ;
}
}
),
(Split,
const auto& cur_arm = e.arms.back();
- if( ty == VarGroup::Variable )
+ const auto& list = (type == SlotType::Local ? cur_arm.states : cur_arm.arg_states);
+ auto it = list.find(idx);
+ if( it != list.end() )
{
- auto it = cur_arm.var_states.find(idx);
- if( it != cur_arm.var_states.end() )
+ if( ! skip_count -- )
{
- if( ! skip_count -- )
- {
- return it->second;
- }
- }
- }
- else if( ty == VarGroup::Temporary )
- {
- auto it = cur_arm.tmp_states.find(idx);
- if( it != cur_arm.tmp_states.end() )
- {
- if( ! skip_count -- )
- {
- return it->second;
- }
+ return it->second;
}
}
)
)
}
- switch(ty)
+ switch(type)
{
- case VarGroup::Return:
- return m_return_state;
- case VarGroup::Argument:
+ case SlotType::Local:
+ if( idx == ~0u )
+ {
+ return m_return_state;
+ }
+ else
+ {
+ ASSERT_BUG(sp, idx < m_slot_states.size(), "Slot " << idx << " out of range for state table");
+ return m_slot_states.at(idx);
+ }
+ break;
+ case SlotType::Argument:
ASSERT_BUG(sp, idx < m_arg_states.size(), "Argument " << idx << " out of range for state table");
return m_arg_states.at(idx);
- case VarGroup::Variable:
- ASSERT_BUG(sp, idx < m_variable_states.size(), "Variable " << idx << " out of range for state table");
- return m_variable_states[idx];
- case VarGroup::Temporary:
- ASSERT_BUG(sp, idx < m_temporary_states.size(), "Temporary " << idx << " out of range for state table");
- return m_temporary_states[idx];
}
- BUG(sp, "Fell off the end of get_slot_state");
+ throw "";
}
-VarState& MirBuilder::get_slot_state_mut(const Span& sp, VarGroup ty, unsigned int idx)
+VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotType type)
{
VarState* ret = nullptr;
for( auto scope_idx : ::reverse(m_scope_stack) )
{
auto& scope_def = m_scopes.at(scope_idx);
- if( const auto* e = scope_def.data.opt_Variables() )
- {
- if( ty == VarGroup::Variable )
- {
- auto it = ::std::find(e->vars.begin(), e->vars.end(), idx);
- if( it != e->vars.end() ) {
- break ;
- }
- }
- }
- else if( const auto* e = scope_def.data.opt_Temporaries() )
+ if( const auto* e = scope_def.data.opt_Owning() )
{
- if( ty == VarGroup::Temporary )
+ if( type == SlotType::Local )
{
- auto it = ::std::find(e->temporaries.begin(), e->temporaries.end(), idx);
- if( it != e->temporaries.end() ) {
+ auto it = ::std::find(e->slots.begin(), e->slots.end(), idx);
+ if( it != e->slots.end() ) {
break ;
}
}
}
- else if( scope_def.data.is_Split() )
+ else if( auto* e = scope_def.data.opt_Split() )
{
- auto& e = scope_def.data.as_Split();
- auto& cur_arm = e.arms.back();
+ auto& cur_arm = e->arms.back();
if( ! ret )
{
- ::std::map<unsigned int, VarState>* states;
- switch(ty)
- {
- case VarGroup::Return: states = nullptr; break;
- case VarGroup::Argument: BUG(sp, "Mutating state of argument"); break;
- case VarGroup::Variable: states = &cur_arm.var_states; break;
- case VarGroup::Temporary: states = &cur_arm.tmp_states; break;
+ if( idx == ~0u ) {
}
-
- if( states )
- {
- auto it = states->find(idx);
- if( it == states->end() )
+ else {
+ auto& states = (type == SlotType::Local ? cur_arm.states : cur_arm.arg_states);
+ auto it = states.find(idx);
+ if( it == states.end() )
{
DEBUG("Split new (scope " << scope_idx << ")");
- ret = &( (*states)[idx] = get_slot_state(sp, ty, idx).clone() );
+ it = states.insert(::std::make_pair( idx, get_slot_state(sp, idx, type).clone() )).first;
}
else
{
DEBUG("Split existing (scope " << scope_idx << ")");
- ret = &it->second;
}
+ ret = &it->second;
}
}
}
- else if( scope_def.data.is_Loop() )
+ else if( auto* e = scope_def.data.opt_Loop() )
{
- auto& e = scope_def.data.as_Loop();
- ::std::map<unsigned int, VarState>* states = nullptr;
- switch(ty)
+ if( idx == ~0u )
{
- case VarGroup::Return: states = nullptr; break;
- case VarGroup::Argument: BUG(sp, "Mutating state of argument"); break;
- case VarGroup::Variable: states = &e.changed_vars; break;
- case VarGroup::Temporary: states = &e.changed_tmps; break;
}
-
- if( states )
+ else
{
- if( states->count(idx) == 0 )
+ auto& states = (type == SlotType::Local ? e->changed_slots : e->changed_args);
+ if( states.count(idx) == 0 )
{
- auto state = e.exit_state_valid ? get_slot_state(sp, ty, idx).clone() : VarState::make_Valid({});
- states->insert(::std::make_pair( idx, mv$(state) ));
+ auto state = e->exit_state_valid ? get_slot_state(sp, idx, type).clone() : VarState::make_Valid({});
+ states.insert(::std::make_pair( idx, mv$(state) ));
}
}
}
+ else if( scope_def.data.is_Freeze() )
+ {
+ if( type == SlotType::Local && idx == m_if_cond_lval.as_Local() )
+ {
+ }
+ else
+ {
+ // NOTE: This is only used in match conditions
+ DEBUG("Mutating state of ?" << idx);
+ ERROR(sp, E0000, "Attempting to move/initialise a value where not allowed");
+ }
+ }
else
{
}
@@ -1980,39 +1923,23 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, VarGroup ty, unsigned i
}
else
{
- switch(ty)
+ switch(type)
{
- case VarGroup::Return:
- return m_return_state;
- case VarGroup::Argument:
- ASSERT_BUG(sp, idx < m_arg_states.size(), "Argument " << idx << " out of range for state table");
+ case SlotType::Local:
+ if( idx == ~0u )
+ {
+ return m_return_state;
+ }
+ else
+ {
+ return m_slot_states.at(idx);
+ }
+ case SlotType::Argument:
return m_arg_states.at(idx);
- case VarGroup::Variable:
- ASSERT_BUG(sp, idx < m_variable_states.size(), "Variable " << idx << " out of range for state table");
- return m_variable_states[idx];
- case VarGroup::Temporary:
- ASSERT_BUG(sp, idx < m_temporary_states.size(), "Temporary " << idx << " out of range for state table");
- return m_temporary_states[idx];
- }
- BUG(sp, "Fell off the end of get_slot_state_mut");
+ }
+ throw "";
}
}
-const VarState& MirBuilder::get_variable_state(const Span& sp, unsigned int idx, unsigned int skip_count) const
-{
- return get_slot_state(sp, VarGroup::Variable, idx, skip_count);
-}
-VarState& MirBuilder::get_variable_state_mut(const Span& sp, unsigned int idx)
-{
- return get_slot_state_mut(sp, VarGroup::Variable, idx);
-}
-const VarState& MirBuilder::get_temp_state(const Span& sp, unsigned int idx, unsigned int skip_count) const
-{
- return get_slot_state(sp, VarGroup::Temporary, idx, skip_count);
-}
-VarState& MirBuilder::get_temp_state_mut(const Span& sp, unsigned int idx)
-{
- return get_slot_state_mut(sp, VarGroup::Temporary, idx);
-}
const VarState& MirBuilder::get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count)
{
@@ -2022,22 +1949,19 @@ VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv)
{
TRACE_FUNCTION_F(lv);
TU_MATCHA( (lv), (e),
- (Variable,
- return get_slot_state_mut(sp, VarGroup::Variable, e);
- ),
- (Temporary,
- return get_slot_state_mut(sp, VarGroup::Temporary, e.idx);
+ (Return,
+ BUG(sp, "Move of return value");
+ return get_slot_state_mut(sp, ~0u, SlotType::Local);
),
(Argument,
- return get_slot_state_mut(sp, VarGroup::Argument, e.idx);
+ return get_slot_state_mut(sp, e.idx, SlotType::Argument);
+ ),
+ (Local,
+ return get_slot_state_mut(sp, e, SlotType::Local);
),
(Static,
BUG(sp, "Attempting to mutate state of a static");
),
- (Return,
- BUG(sp, "Move of return value");
- return get_slot_state_mut(sp, VarGroup::Return, 0);
- ),
(Field,
auto& ivs = get_val_state_mut(sp, *e.val);
VarState tpl;
@@ -2117,13 +2041,10 @@ VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv)
this->push_stmt_assign(sp, inner_lv.clone(), ::MIR::RValue( mv$(*e.val) ));
*e.val = inner_lv.clone();
),
- (Variable,
- inner_lv = ::MIR::LValue(ei);
- ),
- (Temporary,
+ (Argument,
inner_lv = ::MIR::LValue(ei);
),
- (Argument,
+ (Local,
inner_lv = ::MIR::LValue(ei);
)
)
@@ -2252,20 +2173,12 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR
void MirBuilder::drop_scope_values(const ScopeDef& sd)
{
TU_MATCHA( (sd.data), (e),
- (Temporaries,
- for(auto tmp_idx : ::reverse(e.temporaries))
- {
- const auto& vs = get_temp_state(sd.span, tmp_idx);
- DEBUG("tmp" << tmp_idx << " - " << vs);
- drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Temporary({ tmp_idx }) );
- }
- ),
- (Variables,
- for(auto var_idx : ::reverse(e.vars))
+ (Owning,
+ for(auto idx : ::reverse(e.slots))
{
- const auto& vs = get_variable_state(sd.span, var_idx);
- DEBUG("var" << var_idx << " - " << vs);
- drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Variable(var_idx) );
+ const auto& vs = get_slot_state(sd.span, idx, SlotType::Local);
+ DEBUG("slot" << idx << " - " << vs);
+ drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Local(idx) );
}
),
(Split,
@@ -2273,6 +2186,8 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd)
),
(Loop,
// No values
+ ),
+ (Freeze,
)
)
}
diff --git a/src/mir/operations.hpp b/src/mir/operations.hpp
index 1c06bc8c..d8769dc4 100644
--- a/src/mir/operations.hpp
+++ b/src/mir/operations.hpp
@@ -16,5 +16,6 @@ extern void MIR_Validate_Full(const StaticTraitResolve& resolve, const ::HIR::It
extern void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type);
// Optimise the MIR
extern void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type);
+extern void MIR_SortBlocks(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn);
extern void MIR_Dump_Fcn(::std::ostream& sink, const ::MIR::Function& fcn, unsigned int il=0);
diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp
index 8e350c45..73cbaa04 100644
--- a/src/mir/optimise.cpp
+++ b/src/mir/optimise.cpp
@@ -17,9 +17,11 @@
#include <iomanip>
#include <trans/target.hpp>
-#define DUMP_BEFORE_ALL 0
+#define DUMP_BEFORE_ALL 1
#define DUMP_BEFORE_CONSTPROPAGATE 0
-#define CHECK_AFTER_PASS 0
+#define CHECK_AFTER_PASS 1
+#define CHECK_AFTER_ALL 1
+#define DUMP_AFTER_PASS 1
#define DUMP_AFTER_DONE 0
#define CHECK_AFTER_DONE 1
@@ -59,16 +61,14 @@ namespace {
if( cb(lv, u) )
return true;
TU_MATCHA( (lv), (e),
- (Variable,
+ (Return,
),
(Argument,
),
- (Temporary,
+ (Local,
),
(Static,
),
- (Return,
- ),
(Field,
return visit_mir_lvalue_mut(*e.val, u, cb);
),
@@ -222,6 +222,9 @@ namespace {
(Switch,
visit_mir_lvalue_mut(e.val, ValUsage::Read, cb);
),
+ (SwitchValue,
+ visit_mir_lvalue_mut(e.val, ValUsage::Read, cb);
+ ),
(Call,
if( e.fcn.is_Value() ) {
visit_mir_lvalue_mut(e.fcn.as_Value(), ValUsage::Read, cb);
@@ -392,6 +395,42 @@ namespace {
}
+ void visit_terminator_target_mut(::MIR::Terminator& term, ::std::function<void(::MIR::BasicBlockId&)> cb) {
+ TU_MATCHA( (term), (e),
+ (Incomplete,
+ ),
+ (Return,
+ ),
+ (Diverge,
+ ),
+ (Goto,
+ cb(e);
+ ),
+ (Panic,
+ ),
+ (If,
+ cb(e.bb0);
+ cb(e.bb1);
+ ),
+ (Switch,
+ for(auto& target : e.targets)
+ cb(target);
+ ),
+ (SwitchValue,
+ for(auto& target : e.targets)
+ cb(target);
+ cb(e.def_target);
+ ),
+ (Call,
+ cb(e.ret_block);
+ cb(e.panic_block);
+ )
+ )
+ }
+ void visit_terminator_target(const ::MIR::Terminator& term, ::std::function<void(const ::MIR::BasicBlockId&)> cb) {
+ visit_terminator_target_mut(const_cast<::MIR::Terminator&>(term), cb);
+ }
+
void visit_blocks_mut(::MIR::TypeResolve& state, ::MIR::Function& fcn, ::std::function<void(::MIR::BasicBlockId, ::MIR::BasicBlock&)> cb)
{
::std::vector<bool> visited( fcn.blocks.size() );
@@ -406,47 +445,47 @@ namespace {
cb(bb, block);
- TU_MATCHA( (block.terminator), (e),
- (Incomplete,
- ),
- (Return,
- ),
- (Diverge,
- ),
- (Goto,
+ visit_terminator_target(block.terminator, [&](auto e){
if( !visited[e] )
to_visit.push_back(e);
- ),
- (Panic,
- ),
- (If,
- if( !visited[e.bb0] )
- to_visit.push_back(e.bb0);
- if( !visited[e.bb1] )
- to_visit.push_back(e.bb1);
- ),
- (Switch,
- for(auto& target : e.targets)
- if( !visited[target] )
- to_visit.push_back(target);
- ),
- (Call,
- if( !visited[e.ret_block] )
- to_visit.push_back(e.ret_block);
- if( !visited[e.panic_block] )
- to_visit.push_back(e.panic_block);
- )
- )
+ });
}
}
void visit_blocks(::MIR::TypeResolve& state, const ::MIR::Function& fcn, ::std::function<void(::MIR::BasicBlockId, const ::MIR::BasicBlock&)> cb) {
visit_blocks_mut(state, const_cast<::MIR::Function&>(fcn), [cb](auto id, auto& blk){ cb(id, blk); });
}
+
+ bool statement_invalidates_lvalue(const ::MIR::Statement& stmt, const ::MIR::LValue& lv)
+ {
+ return visit_mir_lvalues(stmt, [&](const auto& v, auto vu) {
+ if( v == lv ) {
+ return vu != ValUsage::Read;
+ }
+ return false;
+ });
+ }
+ bool terminator_invalidates_lvalue(const ::MIR::Terminator& term, const ::MIR::LValue& lv)
+ {
+ if( const auto* e = term.opt_Call() )
+ {
+ return visit_mir_lvalue(e->ret_val, ValUsage::Write, [&](const auto& v, auto vu) {
+ if( v == lv ) {
+ return vu != ValUsage::Read;
+ }
+ return false;
+ });
+ }
+ else
+ {
+ return false;
+ }
+ }
}
bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn);
-bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn);
+bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool minimal);
bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::Function& fcn);
+bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Function& fcn);
bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& fcn);
bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn);
bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn);
@@ -454,12 +493,40 @@ bool MIR_Optimise_DeadDropFlags(::MIR::TypeResolve& state, ::MIR::Function& fcn)
bool MIR_Optimise_GarbageCollect_Partial(::MIR::TypeResolve& state, ::MIR::Function& fcn);
bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn);
-void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type)
+/// A minimum set of optimisations:
+/// - Inlines `#[inline(always)]` functions
+/// - Simplifies the call graph (by removing chained gotos)
+/// - Sorts blocks into a rough flow order
+void MIR_OptimiseMin(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type)
{
static Span sp;
TRACE_FUNCTION_F(path);
::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn };
+ while( MIR_Optimise_Inlining(state, fcn, true) )
+ {
+ MIR_Cleanup(resolve, path, fcn, args, ret_type);
+ //MIR_Dump_Fcn(::std::cout, fcn);
+ #if CHECK_AFTER_ALL
+ MIR_Validate(resolve, path, fcn, args, ret_type);
+ #endif
+ }
+
+ MIR_Optimise_BlockSimplify(state, fcn);
+ MIR_Optimise_UnifyBlocks(state, fcn);
+
+ //MIR_Optimise_GarbageCollect_Partial(state, fcn);
+
+ MIR_Optimise_GarbageCollect(state, fcn);
+ //MIR_Validate_Full(resolve, path, fcn, args, ret_type);
+ MIR_SortBlocks(resolve, path, fcn);
+ return ;
+}
+void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type)
+{
+ static Span sp;
+ TRACE_FUNCTION_F(path);
+ ::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn };
bool change_happened;
unsigned int pass_num = 0;
@@ -468,39 +535,68 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
change_happened = false;
TRACE_FUNCTION_FR("Pass " << pass_num, change_happened);
- // >> Simplify call graph
+ // >> Simplify call graph (removes gotos to blocks with a single use)
MIR_Optimise_BlockSimplify(state, fcn);
// >> Apply known constants
change_happened |= MIR_Optimise_ConstPropagte(state, fcn);
-
- // >> Inline short functions
- bool inline_happened = MIR_Optimise_Inlining(state, fcn);
- if( inline_happened )
- {
- // Apply cleanup again (as monomorpisation in inlining may have exposed a vtable call)
- MIR_Cleanup(resolve, path, fcn, args, ret_type);
- //MIR_Dump_Fcn(::std::cout, fcn);
- change_happened = true;
- }
+ #if CHECK_AFTER_ALL
+ MIR_Validate(resolve, path, fcn, args, ret_type);
+ #endif
+
+ // >> Replace values from composites if they're known
+ // - Undoes the inefficiencies from the `match (a, b) { ... }` pattern
+ change_happened |= MIR_Optimise_PropagateKnownValues(state, fcn);
+#if CHECK_AFTER_ALL
+ MIR_Validate(resolve, path, fcn, args, ret_type);
+#endif
// TODO: Convert `&mut *mut_foo` into `mut_foo` if the source is movable and not used afterwards
+#if DUMP_BEFORE_ALL || DUMP_BEFORE_PSA
+ if( debug_enabled() ) MIR_Dump_Fcn(::std::cout, fcn);
+#endif
// >> Propagate/remove dead assignments
while( MIR_Optimise_PropagateSingleAssignments(state, fcn) )
change_happened = true;
+ #if CHECK_AFTER_ALL
+ MIR_Validate(resolve, path, fcn, args, ret_type);
+ #endif
change_happened |= MIR_Optimise_UnifyBlocks(state, fcn);
// >> Unify duplicate temporaries
// If two temporaries don't overlap in lifetime (blocks in which they're valid), unify the two
change_happened |= MIR_Optimise_UnifyTemporaries(state, fcn);
+ #if CHECK_AFTER_ALL
+ MIR_Validate(resolve, path, fcn, args, ret_type);
+ #endif
// >> Combine Duplicate Blocks
change_happened |= MIR_Optimise_UnifyBlocks(state, fcn);
// >> Remove assignments of unsed drop flags
change_happened |= MIR_Optimise_DeadDropFlags(state, fcn);
+ #if CHECK_AFTER_ALL
+ MIR_Validate(resolve, path, fcn, args, ret_type);
+ #endif
+
+ // >> Inline short functions
+ if( !change_happened )
+ {
+ bool inline_happened = MIR_Optimise_Inlining(state, fcn, false);
+ if( inline_happened )
+ {
+ // Apply cleanup again (as monomorpisation in inlining may have exposed a vtable call)
+ MIR_Cleanup(resolve, path, fcn, args, ret_type);
+ //MIR_Dump_Fcn(::std::cout, fcn);
+ change_happened = true;
+ }
+ #if CHECK_AFTER_ALL
+ MIR_Validate(resolve, path, fcn, args, ret_type);
+ #endif
+ }
+
if( change_happened )
{
#if DUMP_AFTER_PASS
@@ -508,7 +604,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
MIR_Dump_Fcn(::std::cout, fcn);
}
#endif
- #if CHECK_AFTER_PASS
+ #if CHECK_AFTER_PASS && !CHECK_AFTER_ALL
MIR_Validate(resolve, path, fcn, args, ret_type);
#endif
}
@@ -531,8 +627,9 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
// - Find unused blocks, then delete and rewrite all references.
MIR_Optimise_GarbageCollect(state, fcn);
- //MIR_Validate(resolve, path, fcn, args, ret_type);
//MIR_Validate_Full(resolve, path, fcn, args, ret_type);
+
+ MIR_SortBlocks(resolve, path, fcn);
}
// --------------------------------------------------------------------
@@ -553,12 +650,9 @@ bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn)
auto& dst = (it-1)->as_ScopeEnd();
const auto& src = it->as_ScopeEnd();
DEBUG("Unify " << *(it-1) << " and " << *it);
- for(auto v : src.vars)
- dst.vars.push_back(v);
- for(auto v : src.tmps)
- dst.tmps.push_back(v);
- ::std::sort(dst.vars.begin(), dst.vars.end());
- ::std::sort(dst.tmps.begin(), dst.tmps.end());
+ for(auto v : src.slots)
+ dst.slots.push_back(v);
+ ::std::sort(dst.slots.begin(), dst.slots.end());
it = block.statements.erase(it);
}
else
@@ -568,32 +662,10 @@ bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn)
}
}
- TU_MATCHA( (block.terminator), (e),
- (Incomplete,
- ),
- (Return,
- ),
- (Diverge,
- ),
- (Goto,
+ visit_terminator_target_mut(block.terminator, [&](auto& e) {
if( &fcn.blocks[e] != &block )
e = get_new_target(state, e);
- ),
- (Panic,
- ),
- (If,
- e.bb0 = get_new_target(state, e.bb0);
- e.bb1 = get_new_target(state, e.bb1);
- ),
- (Switch,
- for(auto& target : e.targets)
- target = get_new_target(state, target);
- ),
- (Call,
- e.ret_block = get_new_target(state, e.ret_block);
- e.panic_block = get_new_target(state, e.panic_block);
- )
- )
+ });
}
// >> Merge blocks where a block goto-s to a single-use block.
@@ -611,40 +683,10 @@ bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn)
visited[bb] = true;
const auto& block = fcn.blocks[bb];
- TU_MATCHA( (block.terminator), (e),
- (Incomplete,
- ),
- (Return,
- ),
- (Diverge,
- ),
- (Goto,
+ visit_terminator_target(block.terminator, [&](const auto& e) {
if( !visited[e] ) to_visit.push_back(e);
uses[e] ++;
- ),
- (Panic,
- ),
- (If,
- if( !visited[e.bb0] ) to_visit.push_back(e.bb0);
- if( !visited[e.bb1] ) to_visit.push_back(e.bb1);
- uses[e.bb0] ++;
- uses[e.bb1] ++;
- ),
- (Switch,
- for(auto& target : e.targets)
- {
- if( !visited[target] )
- to_visit.push_back(target);
- uses[target] ++;
- }
- ),
- (Call,
- if( !visited[e.ret_block] ) to_visit.push_back(e.ret_block);
- if( !visited[e.panic_block] ) to_visit.push_back(e.panic_block);
- uses[e.ret_block] ++;
- uses[e.panic_block] ++;
- )
- )
+ });
}
unsigned int i = 0;
@@ -685,18 +727,26 @@ bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn)
// --------------------------------------------------------------------
// If two temporaries don't overlap in lifetime (blocks in which they're valid), unify the two
// --------------------------------------------------------------------
-bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn)
+bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool minimal)
{
TRACE_FUNCTION;
struct H
{
- static bool can_inline(const ::HIR::Path& path, const ::MIR::Function& fcn)
+ static bool can_inline(const ::HIR::Path& path, const ::MIR::Function& fcn, bool minimal)
{
+ // TODO: If the function is marked as `inline(always)`, then inline it regardless of the contents
+
+ if( minimal ) {
+ return false;
+ }
+
+ // TODO: If the function is marked as `inline(never)`, then don't inline
+
// TODO: Allow functions that are just a switch on an input.
if( fcn.blocks.size() == 1 )
{
- return fcn.blocks[0].statements.size() < 5 && ! fcn.blocks[0].terminator.is_Goto();
+ return fcn.blocks[0].statements.size() < 10 && ! fcn.blocks[0].terminator.is_Goto();
}
else if( fcn.blocks.size() == 3 && fcn.blocks[0].terminator.is_Call() )
{
@@ -724,6 +774,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn)
const Span& sp;
const ::StaticTraitResolve& resolve;
const ::MIR::Terminator::Data_Call& te;
+ ::std::vector<unsigned> copy_args; // Local indexes containing copies of Copy args
ParamsSet params;
unsigned int bb_base = ~0u;
unsigned int tmp_base = ~0u;
@@ -731,13 +782,17 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn)
unsigned int df_base = ~0u;
size_t tmp_end = 0;
- mutable ::std::vector< ::MIR::Constant > const_assignments;
+ mutable ::std::vector< ::MIR::Param > const_assignments;
+
+ ::MIR::LValue retval;
Cloner(const Span& sp, const ::StaticTraitResolve& resolve, ::MIR::Terminator::Data_Call& te):
sp(sp),
resolve(resolve),
- te(te)
- {}
+ te(te),
+ copy_args(te.args.size(), ~0u)
+ {
+ }
::HIR::TypeRef monomorph(const ::HIR::TypeRef& ty) const {
auto rv = monomorphise_type_with(sp, ty, params.get_cb(sp));
@@ -824,17 +879,20 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn)
),
(ScopeEnd,
::MIR::Statement::Data_ScopeEnd new_se;
- new_se.vars.reserve(se.vars.size());
- for(auto idx : se.vars)
- new_se.vars.push_back(this->var_base + idx);
- new_se.tmps.reserve(se.tmps.size());
- for(auto idx : se.tmps)
- new_se.tmps.push_back(this->tmp_base + idx);
+ new_se.slots.reserve(se.slots.size());
+ for(auto idx : se.slots)
+ new_se.slots.push_back(this->var_base + idx);
rv.statements.push_back(::MIR::Statement( mv$(new_se) ));
)
)
+ DEBUG("-> " << rv.statements.back());
}
DEBUG("BB" << src_idx << "->BB" << new_idx << "/" << rv.statements.size() << ": " << src.terminator);
+ if(src.terminator.is_Return())
+ {
+ rv.statements.push_back(::MIR::Statement::make_Assign({ this->te.ret_val.clone(), this->retval.clone() }));
+ DEBUG("++ " << rv.statements.back());
+ }
rv.terminator = this->clone_term(src.terminator);
DEBUG("-> " << rv.terminator);
return rv;
@@ -871,6 +929,13 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn)
arms.push_back( bbi + this->bb_base );
return ::MIR::Terminator::make_Switch({ this->clone_lval(se.val), mv$(arms) });
),
+ (SwitchValue,
+ ::std::vector<::MIR::BasicBlockId> arms;
+ arms.reserve(se.targets.size());
+ for(const auto& bbi : se.targets)
+ arms.push_back( bbi + this->bb_base );
+ return ::MIR::Terminator::make_SwitchValue({ this->clone_lval(se.val), se.def_target + this->bb_base, mv$(arms), se.values.clone() });
+ ),
(Call,
::MIR::CallTarget tgt;
TU_MATCHA( (se.fcn), (ste),
@@ -919,26 +984,27 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn)
rv.push_back( this->clone_param(lv) );
return rv;
}
+
::MIR::LValue clone_lval(const ::MIR::LValue& src) const
{
TU_MATCHA( (src), (se),
- (Variable,
- return ::MIR::LValue::make_Variable(se + this->var_base);
- ),
- (Temporary,
- return ::MIR::LValue::make_Temporary({se.idx + this->tmp_base});
+ (Return,
+ return this->retval.clone();
),
(Argument,
const auto& arg = this->te.args.at(se.idx);
- if( const auto* e = arg.opt_Constant() ) {
- auto tmp = ::MIR::LValue::make_Temporary({ static_cast<unsigned>(this->tmp_end + this->const_assignments.size()) });
- this->const_assignments.push_back( e->clone() );
- return tmp;
+ if( this->copy_args[se.idx] != ~0u )
+ {
+ return ::MIR::LValue::make_Local(this->copy_args[se.idx]);
+ }
+ else
+ {
+ assert( !arg.is_Constant() ); // Should have been handled in the above
+ return arg.as_LValue().clone();
}
- return arg.as_LValue().clone();
),
- (Return,
- return this->te.ret_val.clone();
+ (Local,
+ return ::MIR::LValue::make_Local(this->var_base + se);
),
(Static,
return this->monomorph( se );
@@ -983,8 +1049,9 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
TU_MATCHA( (src), (se),
(LValue,
- if( se.is_Argument() )
- return this->te.args.at(se.as_Argument().idx).clone();
+ // NOTE: No need to use `copy_args` here as all uses of Param are copies/moves
+ //if( const auto* ae = se.opt_Argument() )
+ // return this->te.args.at(ae->idx).clone();
return clone_lval(se);
),
(Constant, return clone_constant(se); )
@@ -995,9 +1062,9 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
TU_MATCHA( (src), (se),
(Use,
- if( se.is_Argument() )
- if( const auto* e = this->te.args.at(se.as_Argument().idx).opt_Constant() )
- return e->clone();
+ //if( const auto* ae = se.opt_Argument() )
+ // if( const auto* e = this->te.args.at(ae->idx).opt_Constant() )
+ // return e->clone();
return ::MIR::RValue( this->clone_lval(se) );
),
(Constant,
@@ -1064,24 +1131,45 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn)
// Inline IF:
// - First BB ends with a call and total count is 3
// - Statement count smaller than 10
- if( ! H::can_inline(path, *called_mir) )
+ if( ! H::can_inline(path, *called_mir, minimal) )
{
DEBUG("Can't inline " << path);
continue ;
}
+ DEBUG(state << fcn.blocks[i].terminator);
TRACE_FUNCTION_F("Inline " << path);
- // Monomorph values and append
- cloner.var_base = fcn.named_variables.size();
- for(const auto& ty : called_mir->named_variables)
- fcn.named_variables.push_back( cloner.monomorph(ty) );
- cloner.tmp_base = fcn.temporaries.size();
- for(const auto& ty : called_mir->temporaries)
- fcn.temporaries.push_back( cloner.monomorph(ty) );
- cloner.tmp_end = fcn.temporaries.size();
+ // Allocate a temporary for the return value
+ {
+ cloner.retval = ::MIR::LValue::make_Local( fcn.locals.size() );
+ DEBUG("- Storing return value in " << cloner.retval);
+ ::HIR::TypeRef tmp_ty;
+ fcn.locals.push_back( state.get_lvalue_type(tmp_ty, te->ret_val).clone() );
+ //fcn.local_names.push_back( "" );
+ }
+
+ // Monomorph locals and append
+ cloner.var_base = fcn.locals.size();
+ for(const auto& ty : called_mir->locals)
+ fcn.locals.push_back( cloner.monomorph(ty) );
+ cloner.tmp_end = fcn.locals.size();
+
cloner.df_base = fcn.drop_flags.size();
fcn.drop_flags.insert( fcn.drop_flags.end(), called_mir->drop_flags.begin(), called_mir->drop_flags.end() );
cloner.bb_base = fcn.blocks.size();
+
+ // Store all Copy lvalue arguments and Constants in variables
+ for(size_t i = 0; i < te->args.size(); i++)
+ {
+ const auto& a = te->args[i];
+ if( !a.is_LValue() || state.lvalue_is_copy(a.as_LValue()) )
+ {
+ cloner.copy_args[i] = cloner.tmp_end + cloner.const_assignments.size();
+ cloner.const_assignments.push_back( a.clone() );
+ DEBUG("- Taking a copy of arg " << i << " (" << a << ") in Local(" << cloner.copy_args[i] << ")");
+ }
+ }
+
// Append monomorphised copy of all blocks.
// > Arguments replaced by input lvalues
::std::vector<::MIR::BasicBlock> new_blocks;
@@ -1090,13 +1178,18 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
new_blocks.push_back( cloner.clone_bb(bb, (&bb - called_mir->blocks.data()), fcn.blocks.size() + new_blocks.size()) );
}
+
// > Append new temporaries
for(auto& val : cloner.const_assignments)
{
- auto ty = state.get_const_type(val);
- auto lv = ::MIR::LValue::make_Temporary({ static_cast<unsigned>(fcn.temporaries.size()) });
- fcn.temporaries.push_back( mv$(ty) );
- new_blocks[0].statements.insert( new_blocks[0].statements.begin(), ::MIR::Statement::make_Assign({ mv$(lv), mv$(val) }) );
+ ::HIR::TypeRef tmp;
+ auto ty = val.is_Constant() ? state.get_const_type(val.as_Constant()) : state.get_lvalue_type(tmp, val.as_LValue()).clone();
+ auto lv = ::MIR::LValue::make_Local( static_cast<unsigned>(fcn.locals.size()) );
+ fcn.locals.push_back( mv$(ty) );
+ auto rval = val.is_Constant() ? ::MIR::RValue(mv$(val.as_Constant())) : ::MIR::RValue( mv$(val.as_LValue()) );
+ auto stmt = ::MIR::Statement::make_Assign({ mv$(lv), mv$(rval) });
+ DEBUG("++ " << stmt);
+ new_blocks[0].statements.insert( new_blocks[0].statements.begin(), mv$(stmt) );
}
cloner.const_assignments.clear();
@@ -1120,19 +1213,19 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn)
bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
TRACE_FUNCTION;
- ::std::vector<bool> replacable( fcn.temporaries.size() );
+ ::std::vector<bool> replacable( fcn.locals.size() );
// 1. Enumerate which (if any) temporaries share the same type
{
unsigned int n_found = 0;
- for(unsigned int tmpidx = 0; tmpidx < fcn.temporaries.size(); tmpidx ++)
+ for(unsigned int tmpidx = 0; tmpidx < fcn.locals.size(); tmpidx ++)
{
if( replacable[tmpidx] )
continue ;
- for(unsigned int i = tmpidx+1; i < fcn.temporaries.size(); i ++ )
+ for(unsigned int i = tmpidx+1; i < fcn.locals.size(); i ++ )
{
if( replacable[i] )
continue ;
- if( fcn.temporaries[i] == fcn.temporaries[tmpidx] )
+ if( fcn.locals[i] == fcn.locals[tmpidx] )
{
replacable[i] = true;
replacable[tmpidx] = true;
@@ -1145,34 +1238,33 @@ bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& f
}
auto lifetimes = MIR_Helper_GetLifetimes(state, fcn, /*dump_debug=*/true);
- //::std::vector<::MIR::ValueLifetime> var_lifetimes = mv$(lifetimes.m_variables);
- ::std::vector<::MIR::ValueLifetime> tmp_lifetimes = mv$(lifetimes.m_temporaries);
+ ::std::vector<::MIR::ValueLifetime> slot_lifetimes = mv$(lifetimes.m_slots);
// 2. Unify variables of the same type with distinct non-overlapping lifetimes
::std::map<unsigned int, unsigned int> replacements;
- ::std::vector<bool> visited( fcn.temporaries.size() );
+ ::std::vector<bool> visited( fcn.locals.size() );
bool replacement_needed = false;
- for(unsigned int tmpidx = 0; tmpidx < fcn.temporaries.size(); tmpidx ++)
+ for(unsigned int local_idx = 0; local_idx < fcn.locals.size(); local_idx ++)
{
- if( ! replacable[tmpidx] ) continue ;
- if( visited[tmpidx] ) continue ;
- if( ! tmp_lifetimes[tmpidx].is_used() ) continue ;
- visited[tmpidx] = true;
+ if( ! replacable[local_idx] ) continue ;
+ if( visited[local_idx] ) continue ;
+ if( ! slot_lifetimes[local_idx].is_used() ) continue ;
+ visited[local_idx] = true;
- for(unsigned int i = tmpidx+1; i < fcn.temporaries.size(); i ++)
+ for(unsigned int i = local_idx+1; i < fcn.locals.size(); i ++)
{
if( !replacable[i] )
continue ;
- if( fcn.temporaries[i] != fcn.temporaries[tmpidx] )
+ if( fcn.locals[i] != fcn.locals[local_idx] )
continue ;
- if( ! tmp_lifetimes[i].is_used() )
+ if( ! slot_lifetimes[i].is_used() )
continue ;
// Variables are of the same type, check if they overlap
- if( tmp_lifetimes[tmpidx].overlaps( tmp_lifetimes[i] ) )
+ if( slot_lifetimes[local_idx].overlaps( slot_lifetimes[i] ) )
continue ;
// They don't overlap, unify
- tmp_lifetimes[tmpidx].unify( tmp_lifetimes[i] );
- replacements[i] = tmpidx;
+ slot_lifetimes[local_idx].unify( slot_lifetimes[i] );
+ replacements[i] = local_idx;
replacement_needed = true;
visited[i] = true;
}
@@ -1182,12 +1274,12 @@ bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& f
{
DEBUG("Replacing temporaries using {" << replacements << "}");
visit_mir_lvalues_mut(state, fcn, [&](auto& lv, auto ) {
- if( auto* ve = lv.opt_Temporary() ) {
- auto it = replacements.find(ve->idx);
+ if( auto* ve = lv.opt_Local() ) {
+ auto it = replacements.find(*ve);
if( it != replacements.end() )
{
- MIR_DEBUG(state, lv << " => Temporary(" << it->second << ")");
- ve->idx = it->second;
+ MIR_DEBUG(state, lv << " => Local(" << it->second << ")");
+ *ve = it->second;
return true;
}
}
@@ -1201,6 +1293,7 @@ bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& f
}
// --------------------------------------------------------------------
+// Combine identical blocks
// --------------------------------------------------------------------
bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
@@ -1249,9 +1342,7 @@ bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn)
return false;
),
(ScopeEnd,
- if( ae.vars != be.vars )
- return false;
- if( ae.tmps == be.tmps )
+ if( ae.slots != be.slots )
return false;
)
)
@@ -1287,6 +1378,30 @@ bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn)
if( ae.targets != be.targets )
return false;
),
+ (SwitchValue,
+ if( ae.val != be.val )
+ return false;
+ if( ae.targets != be.targets )
+ return false;
+ if( ae.def_target != be.def_target )
+ return false;
+ if( ae.values.tag() != be.values.tag() )
+ return false;
+ TU_MATCHA( (ae.values, be.values), (ae2, be2),
+ (Unsigned,
+ if( ae2 != be2 )
+ return false;
+ ),
+ (Signed,
+ if( ae2 != be2 )
+ return false;
+ ),
+ (String,
+ if( ae2 != be2 )
+ return false;
+ )
+ )
+ ),
(Call,
if( ae.ret_block != be.ret_block )
return false;
@@ -1358,32 +1473,9 @@ bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
if( bb.terminator.tag() == ::MIR::Terminator::TAGDEAD )
continue ;
- TU_MATCHA( (bb.terminator), (te),
- (Incomplete,
- ),
- (Return,
- ),
- (Diverge,
- ),
- (Goto,
+ visit_terminator_target_mut(bb.terminator, [&](auto& te) {
patch_tgt(te);
- ),
- (Panic,
- patch_tgt(te.dst);
- ),
- (If,
- patch_tgt(te.bb0);
- patch_tgt(te.bb1);
- ),
- (Switch,
- for(auto& tgt : te.targets)
- patch_tgt(tgt);
- ),
- (Call,
- patch_tgt(te.ret_block);
- patch_tgt(te.panic_block);
- )
- )
+ });
//DEBUG("- " << bb.terminator);
}
@@ -1401,6 +1493,165 @@ bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn)
}
}
+// --------------------------------------------------------------------
+// Propagate source values when a composite (tuple) is read
+// --------------------------------------------------------------------
+bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Function& fcn)
+{
+ TRACE_FUNCTION;
+ // 1. Determine reference counts for blocks (allows reversing up BB tree)
+ ::std::vector<size_t> block_origins( fcn.blocks.size(), SIZE_MAX );
+ {
+ ::std::vector<unsigned int> block_uses( fcn.blocks.size() );
+ ::std::vector<bool> visited( fcn.blocks.size() );
+ ::std::vector< ::MIR::BasicBlockId> to_visit;
+ to_visit.push_back( 0 );
+ block_uses[0] ++;
+ while( to_visit.size() > 0 )
+ {
+ auto bb = to_visit.back(); to_visit.pop_back();
+ if( visited[bb] )
+ continue ;
+ visited[bb] = true;
+ const auto& block = fcn.blocks[bb];
+
+ visit_terminator_target(block.terminator, [&](const auto& idx) {
+ if( !visited[idx] )
+ to_visit.push_back(idx);
+ if(block_uses[idx] == 0)
+ block_origins[idx] = bb;
+ else
+ block_origins[idx] = SIZE_MAX;
+ block_uses[idx] ++;
+ });
+ }
+ }
+
+ // 2. Find any assignments (or function uses?) of the form FIELD(LOCAL, _)
+ // > Restricted to simplify logic (and because that's the inefficient pattern observed)
+ // 3. Search backwards from that point until the referenced local is assigned
+ bool change_happend = false;
+ auto get_field = [&](const ::MIR::LValue& slot_lvalue, unsigned field, size_t start_bb_idx, size_t start_stmt_idx)->const ::MIR::LValue* {
+ TRACE_FUNCTION_F(slot_lvalue << "." << field << " BB" << start_bb_idx << "/" << start_stmt_idx);
+ // NOTE: An infinite loop is (theoretically) impossible.
+ auto bb_idx = start_bb_idx;
+ auto stmt_idx = start_stmt_idx;
+ for(;;)
+ {
+ const auto& bb = fcn.blocks[bb_idx];
+ while(stmt_idx --)
+ {
+ if( stmt_idx == bb.statements.size() )
+ {
+ DEBUG("BB" << bb_idx << "/TERM - " << bb.terminator);
+ if( terminator_invalidates_lvalue(bb.terminator, slot_lvalue) ) {
+ return nullptr;
+ }
+ continue ;
+ }
+ const auto& stmt = bb.statements[stmt_idx];
+ DEBUG("BB" << bb_idx << "/" << stmt_idx << " - " << stmt);
+ if( const auto* se = stmt.opt_Assign() )
+ {
+ if( se->dst == slot_lvalue )
+ {
+ if( !se->src.is_Tuple() )
+ return nullptr;
+ const auto& src_param = se->src.as_Tuple().vals.at(field);
+ DEBUG("> Found a source " << src_param);
+ // TODO: Support returning a Param
+ if( !src_param.is_LValue() )
+ return nullptr;
+ const auto& src_lval = src_param.as_LValue();
+ // Visit all statements between the start and here, checking for mutation of this value.
+ auto end_bb_idx = bb_idx;
+ auto end_stmt_idx = stmt_idx;
+ bb_idx = start_bb_idx;
+ stmt_idx = start_stmt_idx;
+ for(;;)
+ {
+ const auto& bb = fcn.blocks[bb_idx];
+ while(stmt_idx--)
+ {
+ if(bb_idx == end_bb_idx && stmt_idx == end_stmt_idx)
+ return &src_lval;
+ if(stmt_idx == bb.statements.size())
+ {
+ DEBUG("BB" << bb_idx << "/TERM - " << bb.terminator);
+ if( terminator_invalidates_lvalue(bb.terminator, src_lval) ) {
+ // Invalidated: Return.
+ return nullptr;
+ }
+ continue ;
+ }
+ if( statement_invalidates_lvalue(bb.statements[stmt_idx], src_lval) ) {
+ // Invalidated: Return.
+ return nullptr;
+ }
+ }
+ assert( block_origins[bb_idx] != SIZE_MAX );
+ bb_idx = block_origins[bb_idx];
+ stmt_idx = fcn.blocks[bb_idx].statements.size() + 1;
+ }
+ throw "";
+ }
+ }
+
+ // Check if the slot is invalidated (mutated)
+ if( statement_invalidates_lvalue(stmt, slot_lvalue) ) {
+ return nullptr;
+ }
+ }
+ if( block_origins[bb_idx] == SIZE_MAX )
+ break;
+ bb_idx = block_origins[bb_idx];
+ stmt_idx = fcn.blocks[bb_idx].statements.size() + 1;
+ }
+ return nullptr;
+ };
+ for(auto& block : fcn.blocks)
+ {
+ size_t bb_idx = &block - &fcn.blocks.front();
+ for(size_t i = 0; i < block.statements.size(); i++)
+ {
+ state.set_cur_stmt(bb_idx, i);
+ DEBUG(state << block.statements[i]);
+ visit_mir_lvalues_mut(block.statements[i], [&](::MIR::LValue& lv, auto vu) {
+ if(const auto* e = lv.opt_Field())
+ {
+ if(vu == ValUsage::Read && e->val->is_Local() ) {
+ // TODO: This value _must_ be Copy for this optimisation to work.
+ // - OR, it has to somehow invalidate the original tuple
+ DEBUG(state << "Locating origin of " << lv);
+ ::HIR::TypeRef tmp;
+ if( !state.m_resolve.type_is_copy(state.sp, state.get_lvalue_type(tmp, *e->val)) )
+ {
+ DEBUG(state << "- not Copy, can't optimise");
+ return false;
+ }
+ const auto* source_lvalue = get_field(*e->val, e->field_index, bb_idx, i);
+ if( source_lvalue )
+ {
+ if( lv != *source_lvalue )
+ {
+ DEBUG(state << "Source is " << *source_lvalue);
+ lv = source_lvalue->clone();
+ change_happend = true;
+ }
+ else
+ {
+ DEBUG(state << "No change");
+ }
+ return false;
+ }
+ }
+ }
+ return false;
+ });
+ }
+ }
+ return change_happend;
+}
// --------------------------------------------------------------------
// Propagate constants and eliminate known paths
@@ -1721,7 +1972,7 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
// - Locate `temp = SOME_CONST` and record value
if( const auto* e = stmt.opt_Assign() )
{
- if( e->dst.is_Temporary() || e->dst.is_Variable() )
+ if( e->dst.is_Local() )
{
if( const auto* ce = e->src.opt_Constant() )
{
@@ -1743,9 +1994,7 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
const auto& te = bb.terminator.as_If();
// Restrict condition to being a temporary/variable
- if( te.cond.is_Temporary() )
- ;
- else if( te.cond.is_Argument() )
+ if( te.cond.is_Local() )
;
else
continue;
@@ -1813,24 +2062,16 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
unsigned int borrow = 0;
};
struct {
- ::std::vector<ValUse> var_uses;
- ::std::vector<ValUse> tmp_uses;
+ ::std::vector<ValUse> local_uses;
void use_lvalue(const ::MIR::LValue& lv, ValUsage ut) {
TU_MATCHA( (lv), (e),
- (Variable,
- auto& vu = var_uses[e];
- switch(ut)
- {
- case ValUsage::Read: vu.read += 1; break;
- case ValUsage::Write: vu.write += 1; break;
- case ValUsage::Borrow: vu.borrow += 1; break;
- }
+ (Return,
),
(Argument,
),
- (Temporary,
- auto& vu = tmp_uses[e.idx];
+ (Local,
+ auto& vu = local_uses[e];
switch(ut)
{
case ValUsage::Read: vu.read += 1; break;
@@ -1840,8 +2081,6 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
),
(Static,
),
- (Return,
- ),
(Field,
use_lvalue(*e.val, ut);
),
@@ -1858,8 +2097,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
)
}
} val_uses = {
- ::std::vector<ValUse>(fcn.named_variables.size()),
- ::std::vector<ValUse>(fcn.temporaries.size())
+ ::std::vector<ValUse>(fcn.locals.size())
};
visit_mir_lvalues(state, fcn, [&](const auto& lv, auto ut){ val_uses.use_lvalue(lv, ut); return false; });
@@ -1886,19 +2124,10 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
continue ;
const auto& e = stmt.as_Assign();
// > Of a temporary from with a RValue::Use
- if( const auto* de = e.dst.opt_Temporary() )
+ if( const auto* de = e.dst.opt_Local() )
{
- const auto& vu = val_uses.tmp_uses[de->idx];
- DEBUG(e.dst << " - VU " << e.dst << " R:" << vu.read << " W:" << vu.write);
- // TODO: Allow write many?
- // > Where the temporary is written once and read once
- if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
- continue ;
- }
- else if( const auto* de = e.dst.opt_Variable() )
- {
- const auto& vu = val_uses.var_uses[*de];
- DEBUG(e.dst << " - VU " << e.dst << " R:" << vu.read << " W:" << vu.write);
+ const auto& vu = val_uses.local_uses[*de];
+ DEBUG(e.dst << " - VU " << e.dst << " R:" << vu.read << " W:" << vu.write << " B:" << vu.borrow);
// TODO: Allow write many?
// > Where the variable is written once and read once
if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
@@ -1915,7 +2144,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
const auto* srcp = &e.src.as_Use();
while( srcp->is_Field() )
srcp = &*srcp->as_Field().val;
- if( !( srcp->is_Temporary() || srcp->is_Variable() || srcp->is_Argument() ) )
+ if( !srcp->is_Local() )
continue ;
if( replacements.find(*srcp) != replacements.end() )
@@ -2004,6 +2233,11 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
found = true;
stop = true;
),
+ (SwitchValue,
+ if( src_is_lvalue && visit_mir_lvalue(e.val, ValUsage::Read, is_lvalue_usage) )
+ found = true;
+ stop = true;
+ ),
(Call,
if( e.fcn.is_Value() )
if( src_is_lvalue && visit_mir_lvalue(e.fcn.as_Value(), ValUsage::Read, is_lvalue_usage) )
@@ -2030,6 +2264,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
} // for(stmt : block.statements)
}
+ // Apply replacements within replacements
for(;;)
{
unsigned int inner_replaced_count = 0;
@@ -2131,9 +2366,9 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
if( it->as_Assign().src.tag() == ::MIR::RValue::TAGDEAD )
continue ;
auto& to_replace_lval = it->as_Assign().dst;
- if( const auto* e = to_replace_lval.opt_Temporary() ) {
- const auto& vu = val_uses.tmp_uses[e->idx];
- if( !( vu.read == 1 && vu.write == 1 ) )
+ if( const auto* e = to_replace_lval.opt_Local() ) {
+ const auto& vu = val_uses.local_uses[*e];
+ if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
continue ;
}
else {
@@ -2155,6 +2390,19 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
const auto& new_dst_lval = it2->as_Assign().dst;
// `... = Use(to_replace_lval)`
+ // TODO: Ensure that the target isn't borrowed.
+ if( const auto* e = new_dst_lval.opt_Local() ) {
+ const auto& vu = val_uses.local_uses[*e];
+ if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
+ break ;
+ }
+ else if( new_dst_lval.is_Return() ) {
+ // Return, can't be borrowed?
+ }
+ else {
+ break;
+ }
+
// Ensure that the target doesn't change in the intervening time.
bool was_invalidated = false;
for(auto it3 = it+1; it3 != it2; it3++)
@@ -2201,10 +2449,9 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
{
// TODO: What if the destination located here is a 1:1 and its usage is listed to be replaced by the return value.
auto& e = block.terminator.as_Call();
- // TODO: Support variables too?
- if( !e.ret_val.is_Temporary() )
+ if( !e.ret_val.is_Local() )
continue ;
- const auto& vu = val_uses.tmp_uses[e.ret_val.as_Temporary().idx];
+ const auto& vu = val_uses.local_uses[e.ret_val.as_Local()];
if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
continue ;
@@ -2256,22 +2503,28 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
{
for(auto it = block.statements.begin(); it != block.statements.end(); ++it)
{
+ state.set_cur_stmt(&block - &fcn.blocks.front(), it - block.statements.begin());
if( const auto& se = it->opt_Assign() )
{
- TU_MATCH_DEF( ::MIR::LValue, (se->dst), (de),
- (
- ),
- (Variable,
- const auto& vu = val_uses.var_uses[de];
- if( vu.write == 1 && vu.read == 0 && vu.borrow == 0 ) {
- DEBUG(se->dst << " only written, removing write");
+ // Remove No-op assignments (assignment from a lvalue to itself)
+ if( const auto* src_e = se->src.opt_Use() )
+ {
+ if( se->dst == *src_e )
+ {
+ DEBUG(state << se->dst << " set to itself, removing write");
it = block.statements.erase(it)-1;
+ continue ;
}
+ }
+
+ // Remove assignments of locals that are never read
+ TU_MATCH_DEF( ::MIR::LValue, (se->dst), (de),
+ (
),
- (Temporary,
- const auto& vu = val_uses.tmp_uses[de.idx];
+ (Local,
+ const auto& vu = val_uses.local_uses[de];
if( vu.write == 1 && vu.read == 0 && vu.borrow == 0 ) {
- DEBUG(se->dst << " only written, removing write with " << se->src);
+ DEBUG(state << se->dst << " only written, removing write");
it = block.statements.erase(it)-1;
}
)
@@ -2355,8 +2608,7 @@ bool MIR_Optimise_GarbageCollect_Partial(::MIR::TypeResolve& state, ::MIR::Funct
// --------------------------------------------------------------------
bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
- ::std::vector<bool> used_temps( fcn.temporaries.size() );
- ::std::vector<bool> used_vars( fcn.named_variables.size() );
+ ::std::vector<bool> used_locals( fcn.locals.size() );
::std::vector<bool> used_dfs( fcn.drop_flags.size() );
::std::vector<bool> visited( fcn.blocks.size() );
@@ -2364,10 +2616,8 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
visited[bb] = true;
auto assigned_lval = [&](const ::MIR::LValue& lv) {
- if(const auto* le = lv.opt_Temporary() )
- used_temps[le->idx] = true;
- if(const auto* le = lv.opt_Variable() )
- used_vars[*le] = true;
+ if(const auto* le = lv.opt_Local() )
+ used_locals[*le] = true;
};
for(const auto& stmt : block.statements)
@@ -2404,42 +2654,28 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
{
block_rewrite_table.push_back( visited[i] ? j ++ : ~0u );
}
- ::std::vector<unsigned int> temp_rewrite_table;
- unsigned int n_temp = fcn.temporaries.size();
- for(unsigned int i = 0, j = 0; i < n_temp; i ++)
+ ::std::vector<unsigned int> local_rewrite_table;
+ unsigned int n_locals = fcn.locals.size();
+ for(unsigned int i = 0, j = 0; i < n_locals; i ++)
{
- if( !used_temps[i] )
+ if( !used_locals[i] )
{
- fcn.temporaries.erase(fcn.temporaries.begin() + j);
+ fcn.locals.erase(fcn.locals.begin() + j);
}
else {
- DEBUG("tmp$" << i << " => tmp$" << j);
+ DEBUG("_" << i << " => _" << j);
}
- temp_rewrite_table.push_back( used_temps[i] ? j ++ : ~0u );
+ local_rewrite_table.push_back( used_locals[i] ? j ++ : ~0u );
}
- DEBUG("Deleted Temporaries:" << FMT_CB(ss,
- for(auto run : runs(used_temps))
- if( !used_temps[run.first] )
+ DEBUG("Deleted Locals:" << FMT_CB(ss,
+ for(auto run : runs(used_locals))
+ if( !used_locals[run.first] )
{
ss << " " << run.first;
if(run.second != run.first)
ss << "-" << run.second;
}
));
- ::std::vector<unsigned int> var_rewrite_table;
- unsigned int n_var = fcn.named_variables.size();
- for(unsigned int i = 0, j = 0; i < n_var; i ++)
- {
- if( !used_vars[i] )
- {
- DEBUG("GC Variable(" << i << ")");
- fcn.named_variables.erase(fcn.named_variables.begin() + j);
- }
- else {
- DEBUG("var$" << i << " => var$" << j);
- }
- var_rewrite_table.push_back( used_vars[i] ? j ++ : ~0u );
- }
::std::vector<unsigned int> df_rewrite_table;
unsigned int n_df = fcn.drop_flags.size();
for(unsigned int i = 0, j = 0; i < n_df; i ++)
@@ -2464,17 +2700,11 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
else
{
auto lvalue_cb = [&](auto& lv, auto ) {
- if(auto* e = lv.opt_Temporary() ) {
- MIR_ASSERT(state, e->idx < temp_rewrite_table.size(), "Temporary out of range - " << lv);
- // If the table entry for this temporary is !0, it wasn't marked as used
- MIR_ASSERT(state, temp_rewrite_table.at(e->idx) != ~0u, "LValue " << lv << " incorrectly marked as unused");
- e->idx = temp_rewrite_table.at(e->idx);
- }
- if(auto* e = lv.opt_Variable() ) {
- MIR_ASSERT(state, *e < var_rewrite_table.size(), "Variable out of range - " << lv);
+ if(auto* e = lv.opt_Local() ) {
+ MIR_ASSERT(state, *e < local_rewrite_table.size(), "Variable out of range - " << lv);
// If the table entry for this variable is !0, it wasn't marked as used
- MIR_ASSERT(state, var_rewrite_table.at(*e) != ~0u, "LValue " << lv << " incorrectly marked as unused");
- *e = var_rewrite_table.at(*e);
+ MIR_ASSERT(state, local_rewrite_table.at(*e) != ~0u, "LValue " << lv << " incorrectly marked as unused");
+ *e = local_rewrite_table.at(*e);
}
return false;
};
@@ -2520,28 +2750,18 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
}
else if( auto* se = stmt.opt_ScopeEnd() )
{
- for(auto it = se->vars.begin(); it != se->vars.end(); )
- {
- if( var_rewrite_table.at(*it) == ~0u ) {
- it = se->vars.erase(it);
- }
- else {
- *it = var_rewrite_table.at(*it);
- ++ it;
- }
- }
- for(auto it = se->tmps.begin(); it != se->tmps.end(); )
+ for(auto it = se->slots.begin(); it != se->slots.end(); )
{
- if( temp_rewrite_table.at(*it) == ~0u ) {
- it = se->tmps.erase(it);
+ if( local_rewrite_table.at(*it) == ~0u ) {
+ it = se->slots.erase(it);
}
else {
- *it = temp_rewrite_table.at(*it);
+ *it = local_rewrite_table.at(*it);
++ it;
}
}
- if( se->vars.empty() && se->tmps.empty() ) {
+ if( se->slots.empty() ) {
DEBUG(state << "Delete ScopeEnd (now empty)");
to_remove_statements[stmt_idx] = true;
continue ;
@@ -2572,6 +2792,12 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
for(auto& target : e.targets)
target = block_rewrite_table[target];
),
+ (SwitchValue,
+ visit_mir_lvalue_mut(e.val, ValUsage::Read, lvalue_cb);
+ for(auto& target : e.targets)
+ target = block_rewrite_table[target];
+ e.def_target = block_rewrite_table[e.def_target];
+ ),
(Call,
if( e.fcn.is_Value() ) {
visit_mir_lvalue_mut(e.fcn.as_Value(), ValUsage::Read, lvalue_cb);
@@ -2616,11 +2842,101 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
return false;
}
-void MIR_OptimiseCrate(::HIR::Crate& crate)
+
+/// Sort basic blocks to approximate program flow (helps when reading MIR)
+void MIR_SortBlocks(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn)
{
- ::MIR::OuterVisitor ov { crate, [](const auto& res, const auto& p, auto& expr, const auto& args, const auto& ty)
+ ::std::vector<bool> visited( fcn.blocks.size() );
+ ::std::vector<::std::pair<unsigned,unsigned>> depths( fcn.blocks.size() );
+
+ struct Todo {
+ size_t bb_idx;
+ unsigned branch_count;
+ unsigned level;
+ };
+ unsigned int branches = 0;
+ ::std::vector<Todo> todo;
+ todo.push_back( Todo { 0, 0, 0 } );
+
+ while(!todo.empty())
+ {
+ auto info = todo.back();
+ todo.pop_back();
+ if( visited[info.bb_idx] )
+ continue ;
+
+ visited[info.bb_idx] = true;
+ depths[info.bb_idx] = ::std::make_pair( info.branch_count, info.level );
+ const auto& bb = fcn.blocks[info.bb_idx];
+
+ TU_MATCHA( (bb.terminator), (te),
+ (Incomplete,
+ ),
+ (Return,
+ ),
+ (Diverge,
+ ),
+ (Goto,
+ todo.push_back(Todo { te, info.branch_count, info.level + 1 });
+ ),
+ (Panic,
+ todo.push_back(Todo { te.dst, info.branch_count, info.level + 1 });
+ ),
+ (If,
+ todo.push_back(Todo { te.bb0, ++branches, info.level + 1 });
+ todo.push_back(Todo { te.bb1, ++branches, info.level + 1 });
+ ),
+ (Switch,
+ for(auto dst : te.targets)
+ todo.push_back(Todo { dst, ++branches, info.level + 1 });
+ ),
+ (SwitchValue,
+ for(auto dst : te.targets)
+ todo.push_back(Todo { dst, ++branches, info.level + 1 });
+ todo.push_back(Todo { te.def_target, info.branch_count, info.level + 1 });
+ ),
+ (Call,
+ todo.push_back(Todo { te.ret_block, info.branch_count, info.level + 1 });
+ todo.push_back(Todo { te.panic_block, ++branches, info.level + 1 });
+ )
+ )
+ }
+
+ // Sort a list of block indexes by `depths`
+ ::std::vector<size_t> idxes;
+ idxes.reserve(fcn.blocks.size());
+ for(size_t i = 0; i < fcn.blocks.size(); i++)
+ idxes.push_back(i);
+ ::std::sort( idxes.begin(), idxes.end(), [&](auto a, auto b){
+ return depths.at(a) < depths.at(b);
+ });
+
+ DEBUG(idxes);
+
+ decltype(fcn.blocks) new_block_list;
+ new_block_list.reserve( fcn.blocks.size() );
+ for(auto idx : idxes)
+ {
+ auto fix_bb_idx = [&](auto idx){ return ::std::find(idxes.begin(), idxes.end(), idx) - idxes.begin(); };
+ new_block_list.push_back( mv$(fcn.blocks[idx]) );
+ visit_terminator_target_mut(new_block_list.back().terminator, [&](auto& te){
+ te = fix_bb_idx(te);
+ });
+ }
+ fcn.blocks = mv$(new_block_list);
+}
+
+
+void MIR_OptimiseCrate(::HIR::Crate& crate, bool do_minimal_optimisation)
+{
+ ::MIR::OuterVisitor ov { crate, [do_minimal_optimisation](const auto& res, const auto& p, auto& expr, const auto& args, const auto& ty)
{
- MIR_Optimise(res, p, *expr.m_mir, args, ty);
+ if( do_minimal_optimisation ) {
+ MIR_OptimiseMin(res, p, *expr.m_mir, args, ty);
+ }
+ else {
+ MIR_Optimise(res, p, *expr.m_mir, args, ty);
+ }
}
};
ov.visit_crate(crate);
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp
index 28729b93..547e38e0 100644
--- a/src/parse/expr.cpp
+++ b/src/parse/expr.cpp
@@ -20,7 +20,8 @@
using AST::ExprNode;
using AST::ExprNodeP;
-static inline ExprNodeP mk_exprnodep(const TokenStream& lex, AST::ExprNode* en){en->set_pos(lex.getPosition()); return ExprNodeP(en); }
+// TODO: Use a ProtoSpan
+static inline ExprNodeP mk_exprnodep(const TokenStream& lex, AST::ExprNode* en){en->set_span(lex.point_span()); return ExprNodeP(en); }
#define NEWNODE(type, ...) mk_exprnodep(lex, new type(__VA_ARGS__))
//ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe=false); // common.hpp
@@ -552,7 +553,7 @@ ExprNodeP Parse_Stmt_Let(TokenStream& lex)
{
Token tok;
AST::Pattern pat = Parse_Pattern(lex, false); // irrefutable
- TypeRef type { lex.getPosition() };
+ TypeRef type { lex.point_span() };
if( GET_TOK(tok, lex) == TOK_COLON ) {
type = Parse_Type(lex);
GET_TOK(tok, lex);
@@ -969,7 +970,7 @@ ExprNodeP Parse_ExprVal_StructLiteral(TokenStream& lex, AST::Path path)
GET_CHECK_TOK(tok, lex, TOK_COLON);
ExprNodeP val = Parse_Stmt(lex);
if( ! nodes.insert( ::std::make_pair(ofs, mv$(val)) ).second ) {
- ERROR(lex.getPosition(), E0000, "Duplicate index");
+ ERROR(lex.point_span(), E0000, "Duplicate index");
}
if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE )
@@ -983,7 +984,7 @@ ExprNodeP Parse_ExprVal_StructLiteral(TokenStream& lex, AST::Path path)
for(auto& p : nodes)
{
if( p.first != i ) {
- ERROR(lex.getPosition(), E0000, "Missing index " << i);
+ ERROR(lex.point_span(), E0000, "Missing index " << i);
}
items.push_back( mv$(p.second) );
i ++;
@@ -1041,7 +1042,7 @@ ExprNodeP Parse_ExprVal_Closure(TokenStream& lex, bool is_move)
// Irrefutable pattern
AST::Pattern pat = Parse_Pattern(lex, false);
- TypeRef type { lex.getPosition() };
+ TypeRef type { lex.point_span() };
if( GET_TOK(tok, lex) == TOK_COLON )
type = Parse_Type(lex);
else
@@ -1054,7 +1055,7 @@ ExprNodeP Parse_ExprVal_Closure(TokenStream& lex, bool is_move)
}
CHECK_TOK(tok, TOK_PIPE);
- auto rt = TypeRef(lex.getPosition());
+ auto rt = TypeRef(lex.point_span());
if( GET_TOK(tok, lex) == TOK_THINARROW ) {
if( GET_TOK(tok, lex) == TOK_EXCLAM ) {
@@ -1264,8 +1265,9 @@ ExprNodeP Parse_ExprVal(TokenStream& lex)
}
ExprNodeP Parse_ExprMacro(TokenStream& lex, AST::Path path)
{
+ ASSERT_BUG(lex.point_span(), path.is_trivial(), "TODO: Support path macros - " << path);
+
Token tok;
- ASSERT_BUG(lex.getPosition(), path.is_trivial(), "TODO: Support path macros - " << path);
::std::string name = path.m_class.is_Local() ? path.m_class.as_Local().name : path.nodes()[0].name();
::std::string ident;
if( GET_TOK(tok, lex) == TOK_IDENT ) {
diff --git a/src/parse/lex.cpp b/src/parse/lex.cpp
index 0587e443..9388fca4 100644
--- a/src/parse/lex.cpp
+++ b/src/parse/lex.cpp
@@ -223,8 +223,8 @@ signed int Lexer::getSymbol()
bool issym(Codepoint ch)
{
- if('0' <= ch.v && ch.v <= '9')
- return true;
+ if('0' <= ch.v && ch.v <= '9')
+ return true;
if( ::std::isalpha(ch.v) )
return true;
if( ch == '_' )
@@ -668,7 +668,7 @@ Token Lexer::getTokenInt()
{
return Token(TOK_EOF);
}
- throw "Fell off the end of getTokenInt";
+ throw "Fell off the end of getTokenInt";
}
Token Lexer::getTokenInt_RawString(bool is_byte)
@@ -983,7 +983,7 @@ bool Codepoint::isspace() const {
case ' ':
case 0xC: // ^L
case 0x85:
- case 0x200E: case 0x200F: // LTR / RTL markers
+ case 0x200E: case 0x200F: // LTR / RTL markers
case 0x2028: // Line Separator
case 0x2029: // Paragrah Separator
return true;
diff --git a/src/parse/parseerror.cpp b/src/parse/parseerror.cpp
index 3c5d41fe..1bb30985 100644
--- a/src/parse/parseerror.cpp
+++ b/src/parse/parseerror.cpp
@@ -19,13 +19,13 @@ CompileError::Generic::Generic(::std::string message):
}
CompileError::Generic::Generic(const TokenStream& lex, ::std::string message)
{
- ::std::cout << lex.getPosition() << ": Generic(" << message << ")" << ::std::endl;
+ ::std::cout << lex.point_span() << ": Generic(" << message << ")" << ::std::endl;
}
CompileError::BugCheck::BugCheck(const TokenStream& lex, ::std::string message):
m_message(message)
{
- ::std::cout << lex.getPosition() << "BugCheck(" << message << ")" << ::std::endl;
+ ::std::cout << lex.point_span() << "BugCheck(" << message << ")" << ::std::endl;
}
CompileError::BugCheck::BugCheck(::std::string message):
m_message(message)
@@ -41,7 +41,7 @@ CompileError::Todo::Todo(::std::string message):
CompileError::Todo::Todo(const TokenStream& lex, ::std::string message):
m_message(message)
{
- ::std::cout << lex.getPosition() << ": Todo(" << message << ")" << ::std::endl;
+ ::std::cout << lex.point_span() << ": Todo(" << message << ")" << ::std::endl;
}
CompileError::Todo::~Todo() throw()
{
@@ -49,7 +49,7 @@ CompileError::Todo::~Todo() throw()
ParseError::BadChar::BadChar(const TokenStream& lex, char character)
{
- ::std::cout << lex.getPosition() << ": BadChar(" << character << ")" << ::std::endl;
+ ::std::cout << lex.point_span() << ": BadChar(" << character << ")" << ::std::endl;
}
ParseError::BadChar::~BadChar() throw()
{
@@ -58,24 +58,24 @@ ParseError::BadChar::~BadChar() throw()
ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok)//:
// m_tok( mv$(tok) )
{
- auto pos = tok.get_pos();
+ Span pos = tok.get_pos();
if(pos.filename == "")
- pos = lex.getPosition();
+ pos = lex.point_span();
::std::cout << pos << ": Unexpected(" << tok << ")" << ::std::endl;
}
ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, Token exp)//:
// m_tok( mv$(tok) )
{
- auto pos = tok.get_pos();
+ Span pos = tok.get_pos();
if(pos.filename == "")
- pos = lex.getPosition();
+ pos = lex.point_span();
::std::cout << pos << ": Unexpected(" << tok << ", " << exp << ")" << ::std::endl;
}
ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, ::std::vector<eTokenType> exp)
{
- auto pos = tok.get_pos();
+ Span pos = tok.get_pos();
if(pos.filename == "")
- pos = lex.getPosition();
+ pos = lex.point_span();
::std::cout << pos << ": Unexpected " << tok << ", expected ";
bool f = true;
for(auto v: exp) {
diff --git a/src/parse/pattern.cpp b/src/parse/pattern.cpp
index e9d086f9..974ff5fb 100644
--- a/src/parse/pattern.cpp
+++ b/src/parse/pattern.cpp
@@ -258,7 +258,7 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_Float({n->m_datatype, n->m_value}) );
}
else {
- TODO(lex.getPosition(), "Convert :expr into a pattern value - " << *e);
+ TODO(lex.point_span(), "Convert :expr into a pattern value - " << *e);
}
} break;
@@ -414,7 +414,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
GET_CHECK_TOK(tok, lex, TOK_COLON);
auto val = Parse_Pattern(lex, is_refutable);
if( ! pats.insert( ::std::make_pair(ofs, mv$(val)) ).second ) {
- ERROR(lex.getPosition(), E0000, "Duplicate index");
+ ERROR(lex.point_span(), E0000, "Duplicate index");
}
if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE )
@@ -435,7 +435,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
{
if( p.first != i ) {
if( has_split || !split_allowed ) {
- ERROR(lex.getPosition(), E0000, "Missing index " << i);
+ ERROR(lex.point_span(), E0000, "Missing index " << i);
}
has_split = true;
i = p.first;
diff --git a/src/parse/root.cpp b/src/parse/root.cpp
index 5f8ed0a3..0790f05b 100644
--- a/src/parse/root.cpp
+++ b/src/parse/root.cpp
@@ -196,7 +196,7 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex)
::std::string param_name = mv$(tok.str());
ret.add_ty_param( AST::TypeParam( param_name ) );
- auto param_ty = TypeRef(lex.getPosition(), param_name);
+ auto param_ty = TypeRef(lex.point_span(), param_name);
if( GET_TOK(tok, lex) == TOK_COLON )
{
Parse_TypeBound(lex, ret, mv$(param_ty));
@@ -382,7 +382,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_
GET_TOK(tok, lex);
if( allow_self == false )
throw ParseError::Generic(lex, "Self binding not expected");
- TypeRef ty = TypeRef( lex.getPosition(), "Self", 0xFFFF );
+ TypeRef ty = TypeRef( lex.point_span(), "Self", 0xFFFF );
if( GET_TOK(tok, lex) == TOK_COLON ) {
// Typed mut self
ty = Parse_Type(lex);
@@ -399,7 +399,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_
// By-value method
if( allow_self == false )
throw ParseError::Generic(lex, "Self binding not expected");
- TypeRef ty = TypeRef( lex.getPosition(), "Self", 0xFFFF );
+ TypeRef ty = TypeRef( lex.point_span(), "Self", 0xFFFF );
if( GET_TOK(tok, lex) == TOK_COLON ) {
// Typed mut self
ty = Parse_Type(lex);
@@ -723,14 +723,14 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
if( GET_TOK(tok, lex) == TOK_COLON )
{
// Bounded associated type
- Parse_TypeBound(lex, atype_params, TypeRef(lex.getPosition(), "Self", 0xFFFF));
+ Parse_TypeBound(lex, atype_params, TypeRef(lex.point_span(), "Self", 0xFFFF));
GET_TOK(tok, lex);
}
if( tok.type() == TOK_RWORD_WHERE ) {
throw ParseError::Todo(lex, "Where clause on associated type");
}
- TypeRef default_type = TypeRef( lex.getPosition() );
+ TypeRef default_type = TypeRef( lex.point_span() );
if( tok.type() == TOK_EQUAL ) {
default_type = Parse_Type(lex);
GET_TOK(tok, lex);
@@ -1049,7 +1049,7 @@ AST::MetaItem Parse_MetaItem(TokenStream& lex)
if( GET_TOK(tok, lex) == TOK_DOUBLE_DOT )
{
// Default impl
- impl_type = TypeRef(TypeRef::TagInvalid(), lex.getPosition());
+ impl_type = TypeRef(TypeRef::TagInvalid(), lex.point_span());
}
else
{
@@ -1390,7 +1390,7 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::strin
else
{
PUTBACK(tok, lex);
- ASSERT_BUG(lex.getPosition(), path.nodes().size() > 0, "`use` with no path");
+ ASSERT_BUG(lex.point_span(), path.nodes().size() > 0, "`use` with no path");
name = path.nodes().back().name();
}
@@ -1490,7 +1490,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
Parse_Use(lex, [&](AST::UseStmt p, std::string s) {
DEBUG(mod_path << " - use " << p << " as '" << s << "'");
if( !item_data.is_None() )
- TODO(lex.getPosition(), "Encode multi-item use statements as a single Item");
+ TODO(lex.point_span(), "Encode multi-item use statements as a single Item");
item_data = ::AST::Item(mv$(p));
item_name = mv$(s);
});
@@ -1735,7 +1735,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
bool sub_file_controls_dir = true;
if( mod_fileinfo.path == "-" ) {
if( path_attr.size() ) {
- ERROR(lex.getPosition(), E0000, "Cannot load module from file when reading stdin");
+ ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin");
}
sub_path = "-";
}
@@ -1779,11 +1779,11 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
break;
case TOK_SEMICOLON:
if( sub_path == "-" ) {
- ERROR(lex.getPosition(), E0000, "Cannot load module from file when reading stdin");
+ ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin");
}
else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir )
{
- ERROR(lex.getPosition(), E0000, "Can't load from files outside of mod.rs or crate root");
+ ERROR(lex.point_span(), E0000, "Can't load from files outside of mod.rs or crate root");
}
else if( !H::check_item_cfg(meta_items) ) {
// Ignore - emit Item::None
@@ -1801,7 +1801,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
if( ifs_dir.is_open() && ifs_file.is_open() )
{
// Collision
- ERROR(lex.getPosition(), E0000, "Both modname.rs and modname/mod.rs exist");
+ ERROR(lex.point_span(), E0000, "Both modname.rs and modname/mod.rs exist");
}
else if( ifs_dir.is_open() )
{
@@ -1815,7 +1815,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
else
{
// Can't find file
- ERROR(lex.getPosition(), E0000, "Can't find file for '" << name << "' in '" << mod_fileinfo.path << "'");
+ ERROR(lex.point_span(), E0000, "Can't find file for '" << name << "' in '" << mod_fileinfo.path << "'");
}
DEBUG("- path = " << submod.m_file_info.path);
Lexer sub_lex(submod.m_file_info.path);
diff --git a/src/parse/tokenstream.cpp b/src/parse/tokenstream.cpp
index 8cb9a910..2975a523 100644
--- a/src/parse/tokenstream.cpp
+++ b/src/parse/tokenstream.cpp
@@ -116,11 +116,15 @@ ProtoSpan TokenStream::start_span() const
Span TokenStream::end_span(ProtoSpan ps) const
{
auto p = this->getPosition();
- return Span(
- ps.filename,
- ps.start_line, ps.start_ofs,
- p.line, p.ofs
- );
+ auto rv = Span( ps.filename, ps.start_line, ps.start_ofs, p.line, p.ofs );
+ rv.outer_span = this->outerSpan();
+ return rv;
+}
+Span TokenStream::point_span() const
+{
+ Span rv = this->getPosition();
+ rv.outer_span = this->outerSpan();
+ return rv;
}
Ident TokenStream::get_ident(Token tok) const
{
diff --git a/src/parse/tokenstream.hpp b/src/parse/tokenstream.hpp
index 85fc62e2..5f2e0733 100644
--- a/src/parse/tokenstream.hpp
+++ b/src/parse/tokenstream.hpp
@@ -60,17 +60,19 @@ public:
void putback(Token tok);
eTokenType lookahead(unsigned int count);
- virtual Position getPosition() const = 0;
Ident::Hygiene getHygiene() const;
ParseState& parse_state() { return m_parse_state; }
ProtoSpan start_span() const;
Span end_span(ProtoSpan ps) const;
+ Span point_span() const;
Ident get_ident(Token tok) const;
protected:
+ virtual Position getPosition() const = 0;
+ virtual ::std::shared_ptr<Span> outerSpan() const { return ::std::shared_ptr<Span>(0); }
virtual Token realGetToken() = 0;
virtual Ident::Hygiene realGetHygiene() const = 0;
private:
diff --git a/src/parse/types.cpp b/src/parse/types.cpp
index 905bd935..ff993693 100644
--- a/src/parse/types.cpp
+++ b/src/parse/types.cpp
@@ -218,7 +218,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls)
if( GET_TOK(tok, lex) == TOK_STRING ) {
abi = tok.str();
if( abi == "" )
- ERROR(lex.getPosition(), E0000, "Empty ABI");
+ ERROR(lex.point_span(), E0000, "Empty ABI");
GET_TOK(tok, lex);
}
else {
diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp
index 26a45a1e..1e197769 100644
--- a/src/resolve/absolute.cpp
+++ b/src/resolve/absolute.cpp
@@ -1601,7 +1601,7 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node)
Resolve_Absolute_Pattern(this->context, true, node.m_pattern);
break;
case ::AST::ExprNode_Loop::FOR:
- BUG(node.get_pos(), "`for` should be desugared");
+ BUG(node.span(), "`for` should be desugared");
}
node.m_code->visit( *this );
this->context.pop_block();
@@ -1629,22 +1629,22 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node)
}
void visit(AST::ExprNode_StructLiteral& node) override {
DEBUG("ExprNode_StructLiteral");
- Resolve_Absolute_Path(this->context, Span(node.get_pos()), Context::LookupMode::Type, node.m_path);
+ Resolve_Absolute_Path(this->context, node.span(), Context::LookupMode::Type, node.m_path);
AST::NodeVisitorDef::visit(node);
}
void visit(AST::ExprNode_CallPath& node) override {
DEBUG("ExprNode_CallPath");
- Resolve_Absolute_Path(this->context, Span(node.get_pos()), Context::LookupMode::Variable, node.m_path);
+ Resolve_Absolute_Path(this->context, node.span(), Context::LookupMode::Variable, node.m_path);
AST::NodeVisitorDef::visit(node);
}
void visit(AST::ExprNode_CallMethod& node) override {
DEBUG("ExprNode_CallMethod");
- Resolve_Absolute_PathParams(this->context, Span(node.get_pos()), node.m_method.args());
+ Resolve_Absolute_PathParams(this->context, node.span(), node.m_method.args());
AST::NodeVisitorDef::visit(node);
}
void visit(AST::ExprNode_NamedValue& node) override {
- DEBUG("(" << node.get_pos() << ") ExprNode_NamedValue - " << node.m_path);
- Resolve_Absolute_Path(this->context, Span(node.get_pos()), Context::LookupMode::Variable, node.m_path);
+ DEBUG("(" << node.span() << ") ExprNode_NamedValue - " << node.m_path);
+ Resolve_Absolute_Path(this->context, node.span(), Context::LookupMode::Variable, node.m_path);
}
void visit(AST::ExprNode_Cast& node) override {
DEBUG("ExprNode_Cast");
diff --git a/src/span.cpp b/src/span.cpp
index 29d7201b..8d176671 100644
--- a/src/span.cpp
+++ b/src/span.cpp
@@ -12,6 +12,7 @@
#include <common.hpp>
Span::Span(const Span& x):
+ outer_span(x.outer_span),
filename(x.filename),
start_line(x.start_line),
start_ofs(x.start_ofs),
@@ -20,6 +21,7 @@ Span::Span(const Span& x):
{
}
Span::Span(const Position& pos):
+ outer_span(),
filename(pos.filename),
start_line(pos.line),
start_ofs(pos.ofs),
@@ -28,6 +30,7 @@ Span::Span(const Position& pos):
{
}
Span::Span():
+ outer_span(),
filename("")/*,
start_line(0), start_ofs(0),
end_line(0), end_ofs(0) // */
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index 17bb5ab0..f5c1a61d 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -14,6 +14,7 @@
#include <mir/mir.hpp>
#include <hir_typeck/static.hpp>
#include <mir/helpers.hpp>
+#include "codegen_c.hpp"
namespace {
@@ -31,6 +32,11 @@ namespace {
Msvc, // Use MSVC extensions
};
+ enum class Compiler {
+ Gcc,
+ Msvc
+ };
+
static Span sp;
const ::HIR::Crate& m_crate;
@@ -42,6 +48,8 @@ namespace {
::std::ofstream m_of;
const ::MIR::TypeResolve* m_mir_res;
+ Compiler m_compiler = Compiler::Gcc;
+
::std::map<::HIR::GenericPath, ::std::vector<unsigned>> m_enum_repr_cache;
::std::vector< ::std::pair< ::HIR::GenericPath, const ::HIR::Struct*> > m_box_glue_todo;
@@ -60,10 +68,14 @@ namespace {
<< "#include <stddef.h>\n"
<< "#include <stdint.h>\n"
<< "#include <stdbool.h>\n"
- << "#include <stdatomic.h>\n" // atomic_*
<< "#include <stdlib.h>\n" // abort
<< "#include <string.h>\n" // mem*
<< "#include <math.h>\n" // round, ...
+ ;
+ m_of
+ << "#include <stdatomic.h>\n" // atomic_*
+ ;
+ m_of
<< "typedef uint32_t CHAR;\n"
<< "typedef struct { } tUNIT;\n"
<< "typedef struct { } tBANG;\n"
@@ -87,13 +99,21 @@ namespace {
<< "static inline TRAITOBJ_PTR make_traitobjptr(void* ptr, void* vt) { TRAITOBJ_PTR rv = { ptr, vt }; return rv; }\n"
<< "\n"
<< "static inline size_t max(size_t a, size_t b) { return a < b ? b : a; }\n"
+ << "static inline void noop_drop(void *p) {}\n"
+ << "\n"
+ ;
+ // 64-bit bit ops
+ m_of
<< "static inline uint64_t __builtin_clz64(uint64_t v) {\n"
<< "\treturn (v >> 32 != 0 ? __builtin_clz(v>>32) : 32 + __builtin_clz(v));\n"
<< "}\n"
<< "static inline uint64_t __builtin_ctz64(uint64_t v) {\n"
<< "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n"
<< "}\n"
- << "static inline uint128_t __builtin_bswap128(uint128_t v) {\n"
+ ;
+ // u128/i128 ops
+ m_of
+ << "static inline unsigned __int128 __builtin_bswap128(unsigned __int128 v) {\n"
<< "\tuint64_t lo = __builtin_bswap64((uint64_t)v);\n"
<< "\tuint64_t hi = __builtin_bswap64((uint64_t)(v>>64));\n"
<< "\treturn ((uint128_t)lo << 64) | (uint128_t)hi;\n"
@@ -105,8 +125,6 @@ namespace {
<< "\treturn ((v&0xFFFFFFFFFFFFFFFF) == 0 ? __builtin_ctz64(v>>64) + 64 : __builtin_ctz64(v));\n"
<< "}\n"
<< "\n"
- << "static inline void noop_drop(void *p) {}\n"
- << "\n"
;
}
@@ -141,59 +159,113 @@ namespace {
// Execute $CC with the required libraries
::std::vector<::std::string> tmp;
+ auto cache_str = [&](::std::string s){ tmp.push_back(::std::move(s)); return tmp.back().c_str(); };
::std::vector<const char*> args;
- args.push_back( getenv("CC") ? getenv("CC") : "gcc" );
- args.push_back("-ffunction-sections");
- args.push_back("-pthread");
- switch(opt.opt_level)
- {
- case 0: break;
- case 1:
- args.push_back("-O1");
- break;
- case 2:
- args.push_back("-O2");
- break;
- }
- if( opt.emit_debug_info )
- {
- args.push_back("-g");
- }
- args.push_back("-o");
- args.push_back(m_outfile_path.c_str());
- args.push_back(m_outfile_path_c.c_str());
- if( is_executable )
+ switch( m_compiler )
{
- for( const auto& crate : m_crate.m_ext_crates )
+ case Compiler::Gcc:
+ args.push_back( getenv("CC") ? getenv("CC") : "gcc" );
+ args.push_back("-ffunction-sections");
+ args.push_back("-pthread");
+ switch(opt.opt_level)
{
- tmp.push_back(crate.second.m_filename + ".o");
- args.push_back(tmp.back().c_str());
+ case 0: break;
+ case 1:
+ args.push_back("-O1");
+ break;
+ case 2:
+ args.push_back("-O2");
+ break;
}
- for(const auto& path : opt.library_search_dirs )
+ if( opt.emit_debug_info )
{
- args.push_back("-L"); args.push_back(path.c_str());
+ args.push_back("-g");
}
- for(const auto& lib : m_crate.m_ext_libs) {
- ASSERT_BUG(Span(), lib.name != "", "");
- args.push_back("-l"); args.push_back(lib.name.c_str());
- }
- for( const auto& crate : m_crate.m_ext_crates )
+ args.push_back("-o");
+ args.push_back(m_outfile_path.c_str());
+ args.push_back(m_outfile_path_c.c_str());
+ if( is_executable )
{
- for(const auto& lib : crate.second.m_data->m_ext_libs) {
- ASSERT_BUG(Span(), lib.name != "", "Empty lib from " << crate.first);
+ for( const auto& crate : m_crate.m_ext_crates )
+ {
+ args.push_back(cache_str( crate.second.m_filename + ".o" ));
+ }
+ for(const auto& path : opt.library_search_dirs )
+ {
+ args.push_back("-L"); args.push_back(path.c_str());
+ }
+ for(const auto& lib : m_crate.m_ext_libs) {
+ ASSERT_BUG(Span(), lib.name != "", "");
args.push_back("-l"); args.push_back(lib.name.c_str());
}
+ for( const auto& crate : m_crate.m_ext_crates )
+ {
+ for(const auto& lib : crate.second.m_data->m_ext_libs) {
+ ASSERT_BUG(Span(), lib.name != "", "Empty lib from " << crate.first);
+ args.push_back("-l"); args.push_back(lib.name.c_str());
+ }
+ }
+ for(const auto& path : opt.libraries )
+ {
+ args.push_back("-l"); args.push_back(path.c_str());
+ }
+ args.push_back("-z"); args.push_back("muldefs");
+ args.push_back("-Wl,--gc-sections");
}
- for(const auto& path : opt.libraries )
+ else
{
- args.push_back("-l"); args.push_back(path.c_str());
+ args.push_back("-c");
}
- args.push_back("-z"); args.push_back("muldefs");
- args.push_back("-Wl,--gc-sections");
- }
- else
- {
- args.push_back("-c");
+ break;
+ case Compiler::Msvc:
+ args.push_back( "cl.exe" );
+ args.push_back(m_outfile_path_c.c_str());
+ switch(opt.opt_level)
+ {
+ case 0: break;
+ case 1:
+ args.push_back("/O1");
+ break;
+ case 2:
+ args.push_back("/O2");
+ break;
+ }
+ if(is_executable)
+ {
+ for( const auto& crate : m_crate.m_ext_crates )
+ {
+ args.push_back(cache_str( crate.second.m_filename + ".o" ));
+ }
+ // Command-line specified linker search directories
+ for(const auto& path : opt.library_search_dirs )
+ {
+ args.push_back("/link");
+ args.push_back("/LIBPATH");
+ args.push_back(path.c_str());
+ }
+ // Crate-specified libraries
+ for(const auto& lib : m_crate.m_ext_libs) {
+ ASSERT_BUG(Span(), lib.name != "", "");
+ args.push_back(lib.name.c_str());
+ }
+ for( const auto& crate : m_crate.m_ext_crates )
+ {
+ for(const auto& lib : crate.second.m_data->m_ext_libs) {
+ ASSERT_BUG(Span(), lib.name != "", "Empty lib from " << crate.first);
+ args.push_back(lib.name.c_str());
+ }
+ }
+ for(const auto& path : opt.libraries )
+ {
+ args.push_back(path.c_str());
+ }
+ }
+ else
+ {
+ args.push_back("/c");
+ args.push_back(cache_str( FMT("/Fo" + m_outfile_path) ));
+ }
+ break;
}
::std::stringstream cmd_ss;
@@ -226,13 +298,13 @@ namespace {
::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, args, *(::MIR::Function*)nullptr };
m_mir_res = &mir_res;
- m_of << "void " << Trans_Mangle(drop_glue_path) << "(struct s_" << Trans_Mangle(p) << "* rv) {\n";
+ m_of << "static void " << Trans_Mangle(drop_glue_path) << "(struct s_" << Trans_Mangle(p) << "* rv) {\n";
// Obtain inner pointer
// TODO: This is very specific to the structure of the official liballoc's Box.
m_of << "\t"; emit_ctype(args[0].second, FMT_CB(ss, ss << "arg0"; )); m_of << " = rv->_0._0._0;\n";
// Call destructor of inner data
- emit_destructor_call( ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) }), *ity, true);
+ 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";
@@ -328,12 +400,12 @@ namespace {
auto ty_ptr = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Owned, ty.clone());
::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), ty_ptr, args, *(::MIR::Function*)nullptr };
m_mir_res = &mir_res;
- m_of << "void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(ty); m_of << "* rv) {";
+ 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);
+ emit_destructor_call(fld_lv, ity, /*unsized_valid=*/false, 1);
fld_lv.as_Field().field_index ++;
}
m_of << "}\n";
@@ -440,13 +512,13 @@ namespace {
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 << "void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ");\n";
+ 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, *(::MIR::Function*)nullptr };
m_mir_res = &mir_res;
- m_of << "void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ") {\n";
+ 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 ) {
@@ -464,7 +536,7 @@ namespace {
const auto& fld = e[i];
fld_lv.as_Field().field_index = i;
- emit_destructor_call(fld_lv, monomorph(fld.ent), true);
+ emit_destructor_call(fld_lv, monomorph(fld.ent), true, 1);
}
),
(Named,
@@ -473,7 +545,7 @@ namespace {
const auto& fld = e[i].second;
fld_lv.as_Field().field_index = i;
- emit_destructor_call(fld_lv, monomorph(fld.ent), true);
+ emit_destructor_call(fld_lv, monomorph(fld.ent), true, 1);
}
)
)
@@ -518,7 +590,7 @@ namespace {
m_of << "tUNIT " << Trans_Mangle(drop_impl_path) << "(union u_" << Trans_Mangle(p) << "*rv);\n";
}
- m_of << "void " << Trans_Mangle(drop_glue_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";
@@ -601,6 +673,7 @@ namespace {
}
}
+ m_of << "// enum " << p << "\n";
if( nonzero_path.size() > 0 )
{
MIR_ASSERT(*m_mir_res, nonzero_path[0] == 0, "");
@@ -692,7 +765,7 @@ namespace {
m_of << "tUNIT " << Trans_Mangle(drop_impl_path) << "(struct e_" << Trans_Mangle(p) << "*rv);\n";
}
- m_of << "void " << Trans_Mangle(drop_glue_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 )
@@ -708,7 +781,7 @@ namespace {
m_of << "\tif( ! (*rv)"; emit_nonzero_path(nonzero_path); m_of << " ) {\n";
for(const auto& fld : item.m_variants[1].second.as_Tuple())
{
- emit_destructor_call(fld_lv, monomorph(fld.ent), false);
+ emit_destructor_call(fld_lv, monomorph(fld.ent), false, 2);
fld_lv.as_Field().field_index ++;
}
m_of << "\t}\n";
@@ -739,7 +812,7 @@ namespace {
fld_lv.as_Field().field_index = i;
const auto& fld = e[i];
- emit_destructor_call(fld_lv, monomorph(fld.ent), false);
+ emit_destructor_call(fld_lv, monomorph(fld.ent), false, 2);
}
m_of << "\tbreak;\n";
),
@@ -749,7 +822,7 @@ namespace {
{
fld_lv.as_Field().field_index = i;
const auto& fld = e[i];
- emit_destructor_call(fld_lv, monomorph(fld.second.ent), false);
+ emit_destructor_call(fld_lv, monomorph(fld.second.ent), false, 2);
}
m_of << "\tbreak;\n";
)
@@ -901,6 +974,18 @@ namespace {
m_mir_res = nullptr;
}
+ void emit_float(double v) {
+ if( ::std::isnan(v) ) {
+ m_of << "NAN";
+ }
+ else if( ::std::isinf(v) ) {
+ m_of << (v < 0 ? "-" : "") << "INFINITY";
+ }
+ else {
+ m_of.precision(::std::numeric_limits<double>::max_digits10 + 1);
+ m_of << ::std::scientific << v;
+ }
+ }
void emit_literal(const ::HIR::TypeRef& ty, const ::HIR::Literal& lit, const Trans_Params& params) {
TRACE_FUNCTION_F("ty=" << ty << ", lit=" << lit);
::HIR::TypeRef tmp;
@@ -1072,15 +1157,7 @@ namespace {
}
),
(Float,
- if( ::std::isnan(e) ) {
- m_of << "NAN";
- }
- else if( ::std::isinf(e) ) {
- m_of << "INFINITY";
- }
- else {
- m_of << e;
- }
+ this->emit_float(e);
),
(BorrowOf,
TU_MATCHA( (e.m_data), (pe),
@@ -1306,25 +1383,32 @@ namespace {
m_of << "{\n";
// Variables
m_of << "\t"; emit_ctype(ret_type, FMT_CB(ss, ss << "rv";)); m_of << ";\n";
- for(unsigned int i = 0; i < code->named_variables.size(); i ++) {
- DEBUG("var" << i << " : " << code->named_variables[i]);
- m_of << "\t"; emit_ctype(code->named_variables[i], FMT_CB(ss, ss << "var" << i;)); m_of << ";";
- m_of << "\t// " << code->named_variables[i];
- m_of << "\n";
- }
- for(unsigned int i = 0; i < code->temporaries.size(); i ++) {
- DEBUG("tmp" << i << " : " << code->temporaries[i]);
- m_of << "\t"; emit_ctype(code->temporaries[i], FMT_CB(ss, ss << " tmp" << i;)); m_of << ";";
- m_of << "\t// " << code->temporaries[i];
+ for(unsigned int i = 0; i < code->locals.size(); i ++) {
+ DEBUG("var" << i << " : " << code->locals[i]);
+ m_of << "\t"; emit_ctype(code->locals[i], FMT_CB(ss, ss << "var" << i;)); m_of << ";";
+ m_of << "\t// " << code->locals[i];
m_of << "\n";
}
for(unsigned int i = 0; i < code->drop_flags.size(); i ++) {
m_of << "\tbool df" << i << " = " << code->drop_flags[i] << ";\n";
}
+
+ if( false )
+ {
+ m_of << "#if 0\n";
+ auto nodes = MIR_To_Structured(*code);
+ for(const auto& node : nodes)
+ {
+ emit_fcn_node(mir_res, node, 1);
+ }
+ m_of << "#endif\n";
+ }
+
for(unsigned int i = 0; i < code->blocks.size(); i ++)
{
TRACE_FUNCTION_F(p << " bb" << i);
+ // HACK: Ignore any blocks that only contain `diverge;`
if( code->blocks[i].statements.size() == 0 && code->blocks[i].terminator.is_Diverge() ) {
DEBUG("- Diverge only, omitting");
m_of << "bb" << i << ": _Unwind_Resume(); // Diverge\n";
@@ -1336,454 +1420,7 @@ namespace {
for(const auto& stmt : code->blocks[i].statements)
{
mir_res.set_cur_stmt(i, (&stmt - &code->blocks[i].statements.front()));
- switch( stmt.tag() )
- {
- case ::MIR::Statement::TAGDEAD: throw "";
- case ::MIR::Statement::TAG_ScopeEnd:
- m_of << "// " << stmt << "\n";
- break;
- case ::MIR::Statement::TAG_SetDropFlag: {
- const auto& e = stmt.as_SetDropFlag();
- m_of << "\tdf" << e.idx << " = ";
- if( e.other == ~0u )
- m_of << e.new_val;
- else
- m_of << (e.new_val ? "!" : "") << "df" << e.other;
- m_of << ";\n";
- break; }
- case ::MIR::Statement::TAG_Drop: {
- const auto& e = stmt.as_Drop();
- ::HIR::TypeRef tmp;
- const auto& ty = mir_res.get_lvalue_type(tmp, e.slot);
-
- if( e.flag_idx != ~0u )
- m_of << "\tif( df" << e.flag_idx << " ) {\n";
-
- switch( e.kind )
- {
- case ::MIR::eDropKind::SHALLOW:
- // Shallow drops are only valid on owned_box
- if( const auto* ity = m_resolve.is_type_owned_box(ty) )
- {
- // Emit a call to box_free for the type
- ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { ity->clone() } };
- // TODO: This is specific to the official liballoc's owned_box
- m_of << "\t" << Trans_Mangle(box_free) << "("; emit_lvalue(e.slot); m_of << "._0._0._0);\n";
- }
- else
- {
- MIR_BUG(mir_res, "Shallow drop on non-Box - " << ty);
- }
- break;
- case ::MIR::eDropKind::DEEP:
- emit_destructor_call(e.slot, ty, false);
- break;
- }
- if( e.flag_idx != ~0u )
- m_of << "\t}\n";
- break; }
- case ::MIR::Statement::TAG_Asm: {
- const auto& e = stmt.as_Asm();
-
- struct H {
- static bool has_flag(const ::std::vector<::std::string>& flags, const char* des) {
- return ::std::find_if(flags.begin(), flags.end(), [des](const auto&x){return x==des;}) != flags.end();
- }
- static const char* convert_reg(const char* r) {
- if( ::std::strcmp(r, "{eax}") == 0 || ::std::strcmp(r, "{rax}") == 0 ) {
- return "a";
- }
- else {
- return r;
- }
- }
- };
- bool is_volatile = H::has_flag(e.flags, "volatile");
- bool is_intel = H::has_flag(e.flags, "intel");
-
- m_of << "\t__asm__ ";
- if(is_volatile) m_of << "__volatile__";
- // TODO: Convert format string?
- // TODO: Use a C-specific escaper here.
- m_of << "(\"" << (is_intel ? ".syntax intel; " : "") << FmtEscaped(e.tpl) << (is_intel ? ".syntax att; " : "") << "\"";
- m_of << ": ";
- for(unsigned int i = 0; i < e.outputs.size(); i ++ )
- {
- const auto& v = e.outputs[i];
- if( i != 0 ) m_of << ", ";
- m_of << "\"";
- switch(v.first[0])
- {
- case '=': m_of << "="; break;
- case '+': m_of << "+"; break;
- default: MIR_TODO(mir_res, "Handle asm! output leader '" << v.first[0] << "'");
- }
- m_of << H::convert_reg(v.first.c_str()+1);
- m_of << "\"("; emit_lvalue(v.second); m_of << ")";
- }
- m_of << ": ";
- for(unsigned int i = 0; i < e.inputs.size(); i ++ )
- {
- const auto& v = e.inputs[i];
- if( i != 0 ) m_of << ", ";
- m_of << "\"" << v.first << "\"("; emit_lvalue(v.second); m_of << ")";
- }
- m_of << ": ";
- for(unsigned int i = 0; i < e.clobbers.size(); i ++ )
- {
- if( i != 0 ) m_of << ", ";
- m_of << "\"" << e.clobbers[i] << "\"";
- }
- m_of << ");\n";
- break; }
- case ::MIR::Statement::TAG_Assign: {
- const auto& e = stmt.as_Assign();
- DEBUG("- " << e.dst << " = " << e.src);
- m_of << "\t";
- TU_MATCHA( (e.src), (ve),
- (Use,
- ::HIR::TypeRef tmp;
- const auto& ty = mir_res.get_lvalue_type(tmp, ve);
- if( ty == ::HIR::TypeRef::new_diverge() ) {
- m_of << "abort()";
- break;
- }
- emit_lvalue(e.dst);
- m_of << " = ";
- emit_lvalue(ve);
- ),
- (Constant,
- emit_lvalue(e.dst);
- m_of << " = ";
- emit_constant(ve, &e.dst);
- ),
- (SizedArray,
- if( ve.count == 0 ) {
- }
- else if( ve.count == 1 ) {
- emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val);
- }
- else if( ve.count == 2 ) {
- emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n\t";
- emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val);
- }
- else if( ve.count == 3 ) {
- emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n\t";
- emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); m_of << ";\n\t";
- emit_lvalue(e.dst); m_of << ".DATA[2] = "; emit_param(ve.val);
- }
- else {
- m_of << "for(unsigned int i = 0; i < " << ve.count << "; i ++)\n";
- m_of << "\t\t"; emit_lvalue(e.dst); m_of << ".DATA[i] = "; emit_param(ve.val);
- }
- ),
- (Borrow,
- ::HIR::TypeRef tmp;
- const auto& ty = mir_res.get_lvalue_type(tmp, ve.val);
- bool special = false;
- // If the inner value has type [T] or str, create DST based on inner pointer and existing metadata
- TU_IFLET(::MIR::LValue, ve.val, Deref, le,
- if( metadata_type(ty) != MetadataType::None ) {
- emit_lvalue(e.dst);
- m_of << " = ";
- emit_lvalue(*le.val);
- special = true;
- }
- )
- // Magic for taking a &-ptr to unsized field of a struct.
- // - Needs to get metadata from bottom-level pointer.
- else TU_IFLET(::MIR::LValue, ve.val, Field, le,
- if( metadata_type(ty) != MetadataType::None ) {
- const ::MIR::LValue* base_val = &*le.val;
- while(base_val->is_Field())
- base_val = &*base_val->as_Field().val;
- MIR_ASSERT(mir_res, base_val->is_Deref(), "DST access must be via a deref");
- const ::MIR::LValue& base_ptr = *base_val->as_Deref().val;
-
- // Construct the new DST
- emit_lvalue(e.dst); m_of << ".META = "; emit_lvalue(base_ptr); m_of << ".META;\n\t";
- emit_lvalue(e.dst); m_of << ".PTR = &"; emit_lvalue(ve.val);
- special = true;
- }
- )
- if( !special )
- {
- emit_lvalue(e.dst);
- m_of << " = ";
- m_of << "& "; emit_lvalue(ve.val);
- }
- ),
- (Cast,
- if( m_resolve.is_type_phantom_data(ve.type) ) {
- m_of << "/* PhandomData cast */\n";
- continue ;
- }
-
- emit_lvalue(e.dst);
- m_of << " = ";
- m_of << "("; emit_ctype(ve.type); m_of << ")";
- // TODO: If the source is an unsized borrow, then extract the pointer
- bool special = false;
- ::HIR::TypeRef tmp;
- const auto& ty = mir_res.get_lvalue_type(tmp, ve.val);
- // If the destination is a thin pointer
- if( ve.type.m_data.is_Pointer() && !is_dst( *ve.type.m_data.as_Pointer().inner ) )
- {
- // NOTE: Checks the result of the deref
- if( (ty.m_data.is_Borrow() && is_dst(*ty.m_data.as_Borrow().inner))
- || (ty.m_data.is_Pointer() && is_dst(*ty.m_data.as_Pointer().inner))
- )
- {
- emit_lvalue(ve.val);
- m_of << ".PTR";
- special = true;
- }
- }
- if( ve.type.m_data.is_Primitive() && ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Enum() )
- {
- emit_lvalue(ve.val);
- m_of << ".TAG";
- special = true;
- }
- if( !special )
- {
- emit_lvalue(ve.val);
- }
- ),
- (BinOp,
- emit_lvalue(e.dst);
- m_of << " = ";
- ::HIR::TypeRef tmp;
- const auto& ty = ve.val_l.is_LValue() ? mir_res.get_lvalue_type(tmp, ve.val_l.as_LValue()) : tmp = mir_res.get_const_type(ve.val_l.as_Constant());
- if( ty.m_data.is_Borrow() ) {
- m_of << "(slice_cmp("; emit_param(ve.val_l); m_of << ", "; emit_param(ve.val_r); m_of << ")";
- switch(ve.op)
- {
- case ::MIR::eBinOp::EQ: m_of << " == 0"; break;
- case ::MIR::eBinOp::NE: m_of << " != 0"; break;
- case ::MIR::eBinOp::GT: m_of << " > 0"; break;
- case ::MIR::eBinOp::GE: m_of << " >= 0"; break;
- case ::MIR::eBinOp::LT: m_of << " < 0"; break;
- case ::MIR::eBinOp::LE: m_of << " <= 0"; break;
- default:
- MIR_BUG(mir_res, "Unknown comparison of a &-ptr - " << e.src << " with " << ty);
- }
- m_of << ")";
- break;
- }
- else if( const auto* te = ty.m_data.opt_Pointer() ) {
- if( metadata_type(*te->inner) != MetadataType::None )
- {
- switch(ve.op)
- {
- case ::MIR::eBinOp::EQ:
- emit_param(ve.val_l); m_of << ".PTR == "; emit_param(ve.val_r); m_of << ".PTR && ";
- emit_param(ve.val_l); m_of << ".META == "; emit_param(ve.val_r); m_of << ".META";
- break;
- case ::MIR::eBinOp::NE:
- emit_param(ve.val_l); m_of << ".PTR != "; emit_param(ve.val_r); m_of << ".PTR || ";
- emit_param(ve.val_l); m_of << ".META != "; emit_param(ve.val_r); m_of << ".META";
- break;
- default:
- MIR_BUG(mir_res, "Unknown comparison of a *-ptr - " << e.src << " with " << ty);
- }
- }
- else
- {
- emit_param(ve.val_l);
- switch(ve.op)
- {
- case ::MIR::eBinOp::EQ: m_of << " == "; break;
- case ::MIR::eBinOp::NE: m_of << " != "; break;
- case ::MIR::eBinOp::GT: m_of << " > " ; break;
- case ::MIR::eBinOp::GE: m_of << " >= "; break;
- case ::MIR::eBinOp::LT: m_of << " < " ; break;
- case ::MIR::eBinOp::LE: m_of << " <= "; break;
- default:
- MIR_BUG(mir_res, "Unknown comparison of a *-ptr - " << e.src << " with " << ty);
- }
- emit_param(ve.val_r);
- }
- break;
- }
- else if( ve.op == ::MIR::eBinOp::MOD && (ty == ::HIR::CoreType::F32 || ty == ::HIR::CoreType::F64) ) {
- if( ty == ::HIR::CoreType::F32 )
- m_of << "remainderf";
- else
- m_of << "remainder";
- m_of << "("; emit_param(ve.val_l); m_of << ", "; emit_param(ve.val_r); m_of << ")";
- break;
- }
- else {
- }
-
- emit_param(ve.val_l);
- switch(ve.op)
- {
- case ::MIR::eBinOp::ADD: m_of << " + "; break;
- case ::MIR::eBinOp::SUB: m_of << " - "; break;
- case ::MIR::eBinOp::MUL: m_of << " * "; break;
- case ::MIR::eBinOp::DIV: m_of << " / "; break;
- case ::MIR::eBinOp::MOD: m_of << " % "; break;
-
- case ::MIR::eBinOp::BIT_OR: m_of << " | "; break;
- case ::MIR::eBinOp::BIT_AND: m_of << " & "; break;
- case ::MIR::eBinOp::BIT_XOR: m_of << " ^ "; break;
- case ::MIR::eBinOp::BIT_SHR: m_of << " >> "; break;
- case ::MIR::eBinOp::BIT_SHL: m_of << " << "; break;
- case ::MIR::eBinOp::EQ: m_of << " == "; break;
- case ::MIR::eBinOp::NE: m_of << " != "; break;
- case ::MIR::eBinOp::GT: m_of << " > " ; break;
- case ::MIR::eBinOp::GE: m_of << " >= "; break;
- case ::MIR::eBinOp::LT: m_of << " < " ; break;
- case ::MIR::eBinOp::LE: m_of << " <= "; break;
-
- case ::MIR::eBinOp::ADD_OV:
- case ::MIR::eBinOp::SUB_OV:
- case ::MIR::eBinOp::MUL_OV:
- case ::MIR::eBinOp::DIV_OV:
- MIR_TODO(mir_res, "Overflow");
- break;
- }
- emit_param(ve.val_r);
- ),
- (UniOp,
- ::HIR::TypeRef tmp;
- emit_lvalue(e.dst);
- m_of << " = ";
- switch(ve.op)
- {
- case ::MIR::eUniOp::NEG: m_of << "-"; break;
- case ::MIR::eUniOp::INV:
- if( mir_res.get_lvalue_type(tmp, e.dst) == ::HIR::CoreType::Bool )
- m_of << "!";
- else
- m_of << "~";
- break;
- }
- emit_lvalue(ve.val);
- ),
- (DstMeta,
- emit_lvalue(e.dst);
- m_of << " = ";
- emit_lvalue(ve.val);
- m_of << ".META";
- ),
- (DstPtr,
- emit_lvalue(e.dst);
- m_of << " = ";
- emit_lvalue(ve.val);
- m_of << ".PTR";
- ),
- (MakeDst,
- emit_lvalue(e.dst);
- m_of << ".PTR = ";
- emit_param(ve.ptr_val);
- m_of << ";\n\t";
- emit_lvalue(e.dst);
- m_of << ".META = ";
- emit_param(ve.meta_val);
- ),
- (Tuple,
- for(unsigned int j = 0; j < ve.vals.size(); j ++) {
- if( j != 0 ) m_of << ";\n\t";
- emit_lvalue(e.dst);
- m_of << "._" << j << " = ";
- emit_param(ve.vals[j]);
- }
- ),
- (Array,
- for(unsigned int j = 0; j < ve.vals.size(); j ++) {
- if( j != 0 ) m_of << ";\n\t";
- emit_lvalue(e.dst); m_of << ".DATA[" << j << "] = ";
- emit_param(ve.vals[j]);
- }
- ),
- (Variant,
- const auto& tyi = m_crate.get_typeitem_by_path(sp, ve.path.m_path);
- if( tyi.is_Union() )
- {
- emit_lvalue(e.dst);
- m_of << ".var_" << ve.index << " = "; emit_param(ve.val);
- }
- else if( const auto* enm_p = tyi.opt_Enum() )
- {
- MIR_TODO(mir_res, "Construct enum with RValue::Variant");
- if( enm_p->is_value() )
- {
- emit_lvalue(e.dst); m_of << ".TAG = " << enm_p->get_value(ve.index) << "";
- }
- else
- {
- emit_lvalue(e.dst); m_of << ".TAG = " << ve.index << ";\n\t";
- emit_lvalue(e.dst); m_of << ".DATA";
- m_of << ".var_" << ve.index << " = "; emit_param(ve.val);
- }
- }
- else
- {
- BUG(mir_res.sp, "Unexpected type in Variant");
- }
- ),
- (Struct,
- if(ve.variant_idx != ~0u)
- {
- ::HIR::TypeRef tmp;
- const auto& ty = mir_res.get_lvalue_type(tmp, e.dst);
- const auto* enm_p = ty.m_data.as_Path().binding.as_Enum();
-
- auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic());
- if( it != m_enum_repr_cache.end() )
- {
- if( ve.variant_idx == 0 ) {
- // TODO: Use nonzero_path
- m_of << "memset(&"; emit_lvalue(e.dst); m_of << ", 0, sizeof("; emit_ctype(ty); m_of << "))";
- }
- else if( ve.variant_idx == 1 ) {
- emit_lvalue(e.dst);
- m_of << "._0 = ";
- emit_param(ve.vals[0]);
- }
- else {
- }
- break;
- }
- else if( enm_p->is_value() )
- {
- emit_lvalue(e.dst);
- m_of << ".TAG = " << enm_p->get_value(ve.variant_idx);
- assert(ve.vals.size() == 0);
- }
- else
- {
- emit_lvalue(e.dst);
- m_of << ".TAG = " << ve.variant_idx;
- }
- if(ve.vals.size() > 0)
- m_of << ";\n\t";
- }
-
- for(unsigned int j = 0; j < ve.vals.size(); j ++)
- {
- // HACK: Don't emit assignment of PhantomData
- ::HIR::TypeRef tmp;
- if( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data( mir_res.get_lvalue_type(tmp, ve.vals[j].as_LValue())) )
- continue ;
-
- if( j != 0 ) m_of << ";\n\t";
- emit_lvalue(e.dst);
- if(ve.variant_idx != ~0u)
- m_of << ".DATA.var_" << ve.variant_idx;
- m_of << "._" << j << " = ";
- emit_param(ve.vals[j]);
- }
- )
- )
- m_of << ";";
- m_of << "\t// " << e.dst << " = " << e.src;
- m_of << "\n";
- break; }
- }
+ emit_statement(mir_res, stmt);
}
mir_res.set_cur_stmt_term(i);
@@ -1816,7 +1453,7 @@ namespace {
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(mir_res, e.targets.size() == 2, "");
+ MIR_ASSERT(mir_res, e.targets.size() == 2, "Non-zero optimised type a variant count that isn't 2");
m_of << "\tif("; emit_lvalue(e.val); emit_nonzero_path(it->second); m_of << ")\n";
m_of << "\t\tgoto bb" << e.targets[1] << ";\n";
m_of << "\telse\n";
@@ -1841,85 +1478,683 @@ namespace {
m_of << "\t}\n";
}
),
+ (SwitchValue,
+ MIR_TODO(mir_res, "SwitchValue in C codegen");
+ ),
(Call,
- m_of << "\t";
- if( e.fcn.is_Intrinsic() )
+ emit_term_call(mir_res, e, 1);
+ m_of << "\tgoto bb" << e.ret_block << ";\n";
+ )
+ )
+ m_of << "\t// ^ " << code->blocks[i].terminator << "\n";
+ }
+ m_of << "}\n";
+ m_of.flush();
+ m_mir_res = nullptr;
+ }
+
+ void emit_fcn_node(::MIR::TypeResolve& mir_res, const Node& node, unsigned indent_level)
+ {
+ auto indent = RepeatLitStr { "\t", static_cast<int>(indent_level) };
+ TU_MATCHA( (node), (e),
+ (Block,
+ for(size_t i = 0; i < e.nodes.size(); i ++)
+ {
+ const auto& snr = e.nodes[i];
+ if( snr.node ) {
+ emit_fcn_node(mir_res, *snr.node, indent_level);
+ }
+ else {
+ DEBUG(mir_res << "BB" << snr.bb_idx);
+ m_of << indent << "bb" << snr.bb_idx << ":\n";
+ const auto& bb = mir_res.m_fcn.blocks.at(snr.bb_idx);
+ for(const auto& stmt : bb.statements)
+ {
+ mir_res.set_cur_stmt(snr.bb_idx, (&stmt - &bb.statements.front()));
+ this->emit_statement(mir_res, stmt, indent_level);
+ }
+
+ TU_MATCHA( (bb.terminator), (te),
+ (Incomplete, ),
+ (Return,
+ assert(i == e.nodes.size()-1 && "Return");
+ m_of << indent << "return;\n";
+ ),
+ (Goto,
+ // Ignore (handled by caller)
+ ),
+ (Diverge,
+ ),
+ (Panic,
+ ),
+ (If,
+ //assert(i == e.nodes.size()-1 && "If");
+ ),
+ (Call,
+ // TODO: Emit call
+ emit_term_call(mir_res, te, indent_level);
+ ),
+ (Switch,
+ //assert(i == e.nodes.size()-1 && "Switch");
+ ),
+ (SwitchValue,
+ //assert(i == e.nodes.size()-1 && "Switch");
+ )
+ )
+ }
+ }
+ ),
+ (If,
+ m_of << indent << "if("; emit_lvalue(*e.val); m_of << ") {\n";
+ if( e.arm_true.node ) {
+ emit_fcn_node(mir_res, *e.arm_true.node, indent_level+1);
+ }
+ else {
+ m_of << indent << "\tgoto bb" << e.arm_true.bb_idx << ";\n";
+ }
+ m_of << indent << "}\n";
+ m_of << indent << "else {\n";
+ if( e.arm_false.node ) {
+ emit_fcn_node(mir_res, *e.arm_false.node, indent_level+1);
+ }
+ else {
+ m_of << indent << "\tgoto bb" << e.arm_false.bb_idx << ";\n";
+ }
+ m_of << indent << "}\n";
+ ),
+ (Switch,
+ this->emit_term_switch(mir_res, *e.val, e.arms.size(), indent_level, [&](auto idx) {
+ const auto& arm = e.arms.at(idx);
+ if( arm.node ) {
+ m_of << "{\n";
+ this->emit_fcn_node(mir_res, *arm.node, indent_level+1);
+ m_of << indent << "\t} ";
+ if( arm.has_target() && arm.target() != e.next_bb ) {
+ m_of << "goto bb" << arm.target() << ";";
+ }
+ else {
+ m_of << "break;";
+ }
+ }
+ else {
+ m_of << "goto bb" << arm.bb_idx << ";";
+ }
+ });
+ ),
+ (Loop,
+ m_of << indent << "for(;;) {\n";
+ assert(e.code.node);
+ assert(e.code.node->is_Block());
+ this->emit_fcn_node(mir_res, *e.code.node, indent_level+1);
+ m_of << indent << "}\n";
+ )
+ )
+ }
+
+ void emit_statement(const ::MIR::TypeResolve& mir_res, const ::MIR::Statement& stmt, unsigned indent_level=1)
+ {
+ auto indent = RepeatLitStr { "\t", static_cast<int>(indent_level) };
+ switch( stmt.tag() )
+ {
+ case ::MIR::Statement::TAGDEAD: throw "";
+ case ::MIR::Statement::TAG_ScopeEnd:
+ m_of << indent << "// " << stmt << "\n";
+ break;
+ case ::MIR::Statement::TAG_SetDropFlag: {
+ const auto& e = stmt.as_SetDropFlag();
+ m_of << indent << "df" << e.idx << " = ";
+ if( e.other == ~0u )
+ m_of << e.new_val;
+ else
+ m_of << (e.new_val ? "!" : "") << "df" << e.other;
+ m_of << ";\n";
+ break; }
+ case ::MIR::Statement::TAG_Drop: {
+ const auto& e = stmt.as_Drop();
+ ::HIR::TypeRef tmp;
+ const auto& ty = mir_res.get_lvalue_type(tmp, e.slot);
+
+ if( e.flag_idx != ~0u )
+ m_of << indent << "if( df" << e.flag_idx << " ) {\n";
+
+ switch( e.kind )
+ {
+ case ::MIR::eDropKind::SHALLOW:
+ // Shallow drops are only valid on owned_box
+ if( const auto* ity = m_resolve.is_type_owned_box(ty) )
{
- const auto& name = e.fcn.as_Intrinsic().name;
- const auto& params = e.fcn.as_Intrinsic().params;
- emit_intrinsic_call(name, params, e);
- m_of << "\tgoto bb" << e.ret_block << ";\n";
- break ;
+ // Emit a call to box_free for the type
+ ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { ity->clone() } };
+ // TODO: This is specific to the official liballoc's owned_box
+ m_of << indent << Trans_Mangle(box_free) << "("; emit_lvalue(e.slot); m_of << "._0._0._0);\n";
+ }
+ else
+ {
+ MIR_BUG(mir_res, "Shallow drop on non-Box - " << ty);
}
+ break;
+ case ::MIR::eDropKind::DEEP:
+ emit_destructor_call(e.slot, ty, false, indent_level + (e.flag_idx != ~0u ? 1 : 0));
+ break;
+ }
+ if( e.flag_idx != ~0u )
+ m_of << indent << "}\n";
+ break; }
+ case ::MIR::Statement::TAG_Asm: {
+ const auto& e = stmt.as_Asm();
- TU_MATCHA( (e.fcn), (e2),
- (Value,
+ struct H {
+ static bool has_flag(const ::std::vector<::std::string>& flags, const char* des) {
+ return ::std::find_if(flags.begin(), flags.end(), [des](const auto&x){return x==des;}) != flags.end();
+ }
+ static const char* convert_reg(const char* r) {
+ if( ::std::strcmp(r, "{eax}") == 0 || ::std::strcmp(r, "{rax}") == 0 ) {
+ return "a";
+ }
+ else {
+ return r;
+ }
+ }
+ };
+ bool is_volatile = H::has_flag(e.flags, "volatile");
+ bool is_intel = H::has_flag(e.flags, "intel");
+
+ m_of << indent << "__asm__ ";
+ if(is_volatile) m_of << "__volatile__";
+ // TODO: Convert format string?
+ // TODO: Use a C-specific escaper here.
+ m_of << "(\"" << (is_intel ? ".syntax intel; " : "") << FmtEscaped(e.tpl) << (is_intel ? ".syntax att; " : "") << "\"";
+ m_of << ": ";
+ for(unsigned int i = 0; i < e.outputs.size(); i ++ )
+ {
+ const auto& v = e.outputs[i];
+ if( i != 0 ) m_of << ", ";
+ m_of << "\"";
+ switch(v.first[0])
+ {
+ case '=': m_of << "="; break;
+ case '+': m_of << "+"; break;
+ default: MIR_TODO(mir_res, "Handle asm! output leader '" << v.first[0] << "'");
+ }
+ m_of << H::convert_reg(v.first.c_str()+1);
+ m_of << "\"("; emit_lvalue(v.second); m_of << ")";
+ }
+ m_of << ": ";
+ for(unsigned int i = 0; i < e.inputs.size(); i ++ )
+ {
+ const auto& v = e.inputs[i];
+ if( i != 0 ) m_of << ", ";
+ m_of << "\"" << v.first << "\"("; emit_lvalue(v.second); m_of << ")";
+ }
+ m_of << ": ";
+ for(unsigned int i = 0; i < e.clobbers.size(); i ++ )
+ {
+ if( i != 0 ) m_of << ", ";
+ m_of << "\"" << e.clobbers[i] << "\"";
+ }
+ m_of << ");\n";
+ break; }
+ case ::MIR::Statement::TAG_Assign: {
+ const auto& e = stmt.as_Assign();
+ DEBUG("- " << e.dst << " = " << e.src);
+ m_of << indent;
+ TU_MATCHA( (e.src), (ve),
+ (Use,
+ ::HIR::TypeRef tmp;
+ const auto& ty = mir_res.get_lvalue_type(tmp, ve);
+ if( ty == ::HIR::TypeRef::new_diverge() ) {
+ m_of << "abort()";
+ break;
+ }
+ emit_lvalue(e.dst);
+ m_of << " = ";
+ emit_lvalue(ve);
+ ),
+ (Constant,
+ emit_lvalue(e.dst);
+ m_of << " = ";
+ emit_constant(ve, &e.dst);
+ ),
+ (SizedArray,
+ if( ve.count == 0 ) {
+ }
+ else if( ve.count == 1 ) {
+ emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val);
+ }
+ else if( ve.count == 2 ) {
+ emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n" << indent;
+ emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val);
+ }
+ else if( ve.count == 3 ) {
+ emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n" << indent;
+ emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); m_of << ";\n" << indent;
+ emit_lvalue(e.dst); m_of << ".DATA[2] = "; emit_param(ve.val);
+ }
+ else {
+ m_of << "for(unsigned int i = 0; i < " << ve.count << "; i ++)\n";
+ m_of << indent << "\t"; emit_lvalue(e.dst); m_of << ".DATA[i] = "; emit_param(ve.val);
+ }
+ ),
+ (Borrow,
+ ::HIR::TypeRef tmp;
+ const auto& ty = mir_res.get_lvalue_type(tmp, ve.val);
+ bool special = false;
+ // If the inner value has type [T] or str, create DST based on inner pointer and existing metadata
+ TU_IFLET(::MIR::LValue, ve.val, Deref, le,
+ if( metadata_type(ty) != MetadataType::None ) {
+ emit_lvalue(e.dst);
+ m_of << " = ";
+ emit_lvalue(*le.val);
+ special = true;
+ }
+ )
+ // Magic for taking a &-ptr to unsized field of a struct.
+ // - Needs to get metadata from bottom-level pointer.
+ else TU_IFLET(::MIR::LValue, ve.val, Field, le,
+ if( metadata_type(ty) != MetadataType::None ) {
+ const ::MIR::LValue* base_val = &*le.val;
+ while(base_val->is_Field())
+ base_val = &*base_val->as_Field().val;
+ MIR_ASSERT(mir_res, base_val->is_Deref(), "DST access must be via a deref");
+ const ::MIR::LValue& base_ptr = *base_val->as_Deref().val;
+
+ // Construct the new DST
+ emit_lvalue(e.dst); m_of << ".META = "; emit_lvalue(base_ptr); m_of << ".META;\n" << indent;
+ emit_lvalue(e.dst); m_of << ".PTR = &"; emit_lvalue(ve.val);
+ special = true;
+ }
+ )
+ if( !special )
+ {
+ emit_lvalue(e.dst);
+ m_of << " = ";
+ m_of << "& "; emit_lvalue(ve.val);
+ }
+ ),
+ (Cast,
+ if( m_resolve.is_type_phantom_data(ve.type) ) {
+ m_of << "/* PhandomData cast */\n";
+ return ;
+ }
+
+ emit_lvalue(e.dst);
+ m_of << " = ";
+ m_of << "("; emit_ctype(ve.type); m_of << ")";
+ // TODO: If the source is an unsized borrow, then extract the pointer
+ bool special = false;
+ ::HIR::TypeRef tmp;
+ const auto& ty = mir_res.get_lvalue_type(tmp, ve.val);
+ // If the destination is a thin pointer
+ if( ve.type.m_data.is_Pointer() && !is_dst( *ve.type.m_data.as_Pointer().inner ) )
+ {
+ // NOTE: Checks the result of the deref
+ if( (ty.m_data.is_Borrow() && is_dst(*ty.m_data.as_Borrow().inner))
+ || (ty.m_data.is_Pointer() && is_dst(*ty.m_data.as_Pointer().inner))
+ )
{
- ::HIR::TypeRef tmp;
- const auto& ty = mir_res.get_lvalue_type(tmp, e2);
- MIR_ASSERT(mir_res, ty.m_data.is_Function(), "Call::Value on non-function - " << ty);
- if( !ty.m_data.as_Function().m_rettype->m_data.is_Diverge() )
+ emit_lvalue(ve.val);
+ m_of << ".PTR";
+ special = true;
+ }
+ }
+ if( ve.type.m_data.is_Primitive() && ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Enum() )
+ {
+ emit_lvalue(ve.val);
+ m_of << ".TAG";
+ special = true;
+ }
+ if( !special )
+ {
+ emit_lvalue(ve.val);
+ }
+ ),
+ (BinOp,
+ emit_lvalue(e.dst);
+ m_of << " = ";
+ ::HIR::TypeRef tmp;
+ const auto& ty = ve.val_l.is_LValue() ? mir_res.get_lvalue_type(tmp, ve.val_l.as_LValue()) : tmp = mir_res.get_const_type(ve.val_l.as_Constant());
+ if( ty.m_data.is_Borrow() ) {
+ m_of << "(slice_cmp("; emit_param(ve.val_l); m_of << ", "; emit_param(ve.val_r); m_of << ")";
+ switch(ve.op)
+ {
+ case ::MIR::eBinOp::EQ: m_of << " == 0"; break;
+ case ::MIR::eBinOp::NE: m_of << " != 0"; break;
+ case ::MIR::eBinOp::GT: m_of << " > 0"; break;
+ case ::MIR::eBinOp::GE: m_of << " >= 0"; break;
+ case ::MIR::eBinOp::LT: m_of << " < 0"; break;
+ case ::MIR::eBinOp::LE: m_of << " <= 0"; break;
+ default:
+ MIR_BUG(mir_res, "Unknown comparison of a &-ptr - " << e.src << " with " << ty);
+ }
+ m_of << ")";
+ break;
+ }
+ else if( const auto* te = ty.m_data.opt_Pointer() ) {
+ if( metadata_type(*te->inner) != MetadataType::None )
+ {
+ switch(ve.op)
{
- emit_lvalue(e.ret_val); m_of << " = ";
+ case ::MIR::eBinOp::EQ:
+ emit_param(ve.val_l); m_of << ".PTR == "; emit_param(ve.val_r); m_of << ".PTR && ";
+ emit_param(ve.val_l); m_of << ".META == "; emit_param(ve.val_r); m_of << ".META";
+ break;
+ case ::MIR::eBinOp::NE:
+ emit_param(ve.val_l); m_of << ".PTR != "; emit_param(ve.val_r); m_of << ".PTR || ";
+ emit_param(ve.val_l); m_of << ".META != "; emit_param(ve.val_r); m_of << ".META";
+ break;
+ default:
+ MIR_BUG(mir_res, "Unknown comparison of a *-ptr - " << e.src << " with " << ty);
}
}
- m_of << "("; emit_lvalue(e2); m_of << ")";
- ),
- (Path,
+ else
{
- bool is_diverge = false;
- TU_MATCHA( (e2.m_data), (pe),
- (Generic,
- const auto& fcn = m_crate.get_function_by_path(sp, pe.m_path);
- is_diverge |= fcn.m_return.m_data.is_Diverge();
- // TODO: Monomorph.
- ),
- (UfcsUnknown,
- ),
- (UfcsInherent,
- // TODO: Check if the return type is !
- is_diverge |= m_resolve.m_crate.find_type_impls(*pe.type, [&](const auto& ty)->const auto& { return ty; },
- [&](const auto& impl) {
- // Associated functions
- {
- auto it = impl.m_methods.find(pe.item);
- if( it != impl.m_methods.end() ) {
- return it->second.data.m_return.m_data.is_Diverge();
- }
- }
- // Associated static (undef)
- return false;
- });
- ),
- (UfcsKnown,
- // TODO: Check if the return type is !
- )
- )
- if(!is_diverge)
+ emit_param(ve.val_l);
+ switch(ve.op)
{
- emit_lvalue(e.ret_val); m_of << " = ";
+ case ::MIR::eBinOp::EQ: m_of << " == "; break;
+ case ::MIR::eBinOp::NE: m_of << " != "; break;
+ case ::MIR::eBinOp::GT: m_of << " > " ; break;
+ case ::MIR::eBinOp::GE: m_of << " >= "; break;
+ case ::MIR::eBinOp::LT: m_of << " < " ; break;
+ case ::MIR::eBinOp::LE: m_of << " <= "; break;
+ default:
+ MIR_BUG(mir_res, "Unknown comparison of a *-ptr - " << e.src << " with " << ty);
}
+ emit_param(ve.val_r);
}
- m_of << Trans_Mangle(e2);
+ break;
+ }
+ else if( ve.op == ::MIR::eBinOp::MOD && (ty == ::HIR::CoreType::F32 || ty == ::HIR::CoreType::F64) ) {
+ if( ty == ::HIR::CoreType::F32 )
+ m_of << "remainderf";
+ else
+ m_of << "remainder";
+ m_of << "("; emit_param(ve.val_l); m_of << ", "; emit_param(ve.val_r); m_of << ")";
+ break;
+ }
+ else {
+ }
+
+ emit_param(ve.val_l);
+ switch(ve.op)
+ {
+ case ::MIR::eBinOp::ADD: m_of << " + "; break;
+ case ::MIR::eBinOp::SUB: m_of << " - "; break;
+ case ::MIR::eBinOp::MUL: m_of << " * "; break;
+ case ::MIR::eBinOp::DIV: m_of << " / "; break;
+ case ::MIR::eBinOp::MOD: m_of << " % "; break;
+
+ case ::MIR::eBinOp::BIT_OR: m_of << " | "; break;
+ case ::MIR::eBinOp::BIT_AND: m_of << " & "; break;
+ case ::MIR::eBinOp::BIT_XOR: m_of << " ^ "; break;
+ case ::MIR::eBinOp::BIT_SHR: m_of << " >> "; break;
+ case ::MIR::eBinOp::BIT_SHL: m_of << " << "; break;
+ case ::MIR::eBinOp::EQ: m_of << " == "; break;
+ case ::MIR::eBinOp::NE: m_of << " != "; break;
+ case ::MIR::eBinOp::GT: m_of << " > " ; break;
+ case ::MIR::eBinOp::GE: m_of << " >= "; break;
+ case ::MIR::eBinOp::LT: m_of << " < " ; break;
+ case ::MIR::eBinOp::LE: m_of << " <= "; break;
+
+ case ::MIR::eBinOp::ADD_OV:
+ case ::MIR::eBinOp::SUB_OV:
+ case ::MIR::eBinOp::MUL_OV:
+ case ::MIR::eBinOp::DIV_OV:
+ MIR_TODO(mir_res, "Overflow");
+ break;
+ }
+ emit_param(ve.val_r);
+ ),
+ (UniOp,
+ ::HIR::TypeRef tmp;
+ emit_lvalue(e.dst);
+ m_of << " = ";
+ switch(ve.op)
+ {
+ case ::MIR::eUniOp::NEG: m_of << "-"; break;
+ case ::MIR::eUniOp::INV:
+ if( mir_res.get_lvalue_type(tmp, e.dst) == ::HIR::CoreType::Bool )
+ m_of << "!";
+ else
+ m_of << "~";
+ break;
+ }
+ emit_lvalue(ve.val);
+ ),
+ (DstMeta,
+ emit_lvalue(e.dst);
+ m_of << " = ";
+ emit_lvalue(ve.val);
+ m_of << ".META";
+ ),
+ (DstPtr,
+ emit_lvalue(e.dst);
+ m_of << " = ";
+ emit_lvalue(ve.val);
+ m_of << ".PTR";
+ ),
+ (MakeDst,
+ emit_lvalue(e.dst); m_of << ".PTR = "; emit_param(ve.ptr_val); m_of << ";\n" << indent;
+ emit_lvalue(e.dst); m_of << ".META = "; emit_param(ve.meta_val);
+ ),
+ (Tuple,
+ for(unsigned int j = 0; j < ve.vals.size(); j ++) {
+ if( j != 0 ) m_of << ";\n" << indent;
+ emit_lvalue(e.dst);
+ m_of << "._" << j << " = ";
+ emit_param(ve.vals[j]);
+ }
+ ),
+ (Array,
+ for(unsigned int j = 0; j < ve.vals.size(); j ++) {
+ if( j != 0 ) m_of << ";\n" << indent;
+ emit_lvalue(e.dst); m_of << ".DATA[" << j << "] = ";
+ emit_param(ve.vals[j]);
+ }
+ ),
+ (Variant,
+ const auto& tyi = m_crate.get_typeitem_by_path(sp, ve.path.m_path);
+ if( tyi.is_Union() )
+ {
+ emit_lvalue(e.dst);
+ m_of << ".var_" << ve.index << " = "; emit_param(ve.val);
+ }
+ else if( const auto* enm_p = tyi.opt_Enum() )
+ {
+ MIR_TODO(mir_res, "Construct enum with RValue::Variant");
+ if( enm_p->is_value() )
+ {
+ emit_lvalue(e.dst); m_of << ".TAG = " << enm_p->get_value(ve.index) << "";
+ }
+ else
+ {
+ emit_lvalue(e.dst); m_of << ".TAG = " << ve.index << ";\n\t";
+ emit_lvalue(e.dst); m_of << ".DATA";
+ m_of << ".var_" << ve.index << " = "; emit_param(ve.val);
+ }
+ }
+ else
+ {
+ BUG(mir_res.sp, "Unexpected type in Variant");
+ }
+ ),
+ (Struct,
+ if(ve.variant_idx != ~0u)
+ {
+ ::HIR::TypeRef tmp;
+ const auto& ty = mir_res.get_lvalue_type(tmp, e.dst);
+ const auto* enm_p = ty.m_data.as_Path().binding.as_Enum();
+
+ auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic());
+ if( it != m_enum_repr_cache.end() )
+ {
+ if( ve.variant_idx == 0 ) {
+ // TODO: Use nonzero_path
+ m_of << "memset(&"; emit_lvalue(e.dst); m_of << ", 0, sizeof("; emit_ctype(ty); m_of << "))";
+ }
+ else if( ve.variant_idx == 1 ) {
+ emit_lvalue(e.dst);
+ m_of << "._0 = ";
+ emit_param(ve.vals[0]);
+ }
+ else {
+ }
+ break;
+ }
+ else if( enm_p->is_value() )
+ {
+ emit_lvalue(e.dst);
+ m_of << ".TAG = " << enm_p->get_value(ve.variant_idx);
+ assert(ve.vals.size() == 0);
+ }
+ else
+ {
+ emit_lvalue(e.dst);
+ m_of << ".TAG = " << ve.variant_idx;
+ }
+ if(ve.vals.size() > 0)
+ m_of << ";\n" << indent;
+ }
+
+ for(unsigned int j = 0; j < ve.vals.size(); j ++)
+ {
+ // HACK: Don't emit assignment of PhantomData
+ ::HIR::TypeRef tmp;
+ if( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data( mir_res.get_lvalue_type(tmp, ve.vals[j].as_LValue())) )
+ continue ;
+
+ if( j != 0 ) m_of << ";\n" << indent;
+ emit_lvalue(e.dst);
+ if(ve.variant_idx != ~0u)
+ m_of << ".DATA.var_" << ve.variant_idx;
+ m_of << "._" << j << " = ";
+ emit_param(ve.vals[j]);
+ }
+ )
+ )
+ m_of << ";";
+ m_of << "\t// " << e.dst << " = " << e.src;
+ m_of << "\n";
+ break; }
+ }
+ }
+ void emit_term_switch(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& val, size_t n_arms, unsigned indent_level, ::std::function<void(size_t)> cb)
+ {
+ auto indent = RepeatLitStr { "\t", static_cast<int>(indent_level) };
+
+ ::HIR::TypeRef tmp;
+ 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();
+
+ 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(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); emit_nonzero_path(it->second); m_of << ")\n";
+ m_of << indent;
+ cb(1);
+ m_of << "\n";
+ m_of << indent << "else\n";
+ m_of << indent;
+ cb(0);
+ m_of << "\n";
+ }
+ else if( enm->is_value() )
+ {
+ 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) << ": ";
+ cb(j);
+ m_of << "\n";
+ }
+ m_of << indent << "default: abort();\n";
+ m_of << indent << "}\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";
+ }
+ }
+ void emit_term_call(const ::MIR::TypeResolve& mir_res, const ::MIR::Terminator::Data_Call& e, unsigned indent_level)
+ {
+ auto indent = RepeatLitStr { "\t", static_cast<int>(indent_level) };
+ m_of << indent;
+
+ TU_MATCHA( (e.fcn), (e2),
+ (Value,
+ {
+ ::HIR::TypeRef tmp;
+ const auto& ty = mir_res.get_lvalue_type(tmp, e2);
+ MIR_ASSERT(mir_res, ty.m_data.is_Function(), "Call::Value on non-function - " << ty);
+ if( !ty.m_data.as_Function().m_rettype->m_data.is_Diverge() )
+ {
+ emit_lvalue(e.ret_val); m_of << " = ";
+ }
+ }
+ m_of << "("; emit_lvalue(e2); m_of << ")";
+ ),
+ (Path,
+ {
+ bool is_diverge = false;
+ TU_MATCHA( (e2.m_data), (pe),
+ (Generic,
+ const auto& fcn = m_crate.get_function_by_path(sp, pe.m_path);
+ is_diverge |= fcn.m_return.m_data.is_Diverge();
+ // TODO: Monomorph.
+ ),
+ (UfcsUnknown,
),
- (Intrinsic,
- MIR_BUG(mir_res, "Intrinsic not expected, should be handled above");
+ (UfcsInherent,
+ // TODO: Check if the return type is !
+ is_diverge |= m_resolve.m_crate.find_type_impls(*pe.type, [&](const auto& ty)->const auto& { return ty; },
+ [&](const auto& impl) {
+ // Associated functions
+ {
+ auto it = impl.m_methods.find(pe.item);
+ if( it != impl.m_methods.end() ) {
+ return it->second.data.m_return.m_data.is_Diverge();
+ }
+ }
+ // Associated static (undef)
+ return false;
+ });
+ ),
+ (UfcsKnown,
+ // TODO: Check if the return type is !
)
)
- m_of << "(";
- for(unsigned int j = 0; j < e.args.size(); j ++) {
- if(j != 0) m_of << ",";
- m_of << " "; emit_param(e.args[j]);
+ if(!is_diverge)
+ {
+ emit_lvalue(e.ret_val); m_of << " = ";
}
- m_of << " );\n";
- m_of << "\tgoto bb" << e.ret_block << ";\n";
- )
+ }
+ m_of << Trans_Mangle(e2);
+ ),
+ (Intrinsic,
+ const auto& name = e.fcn.as_Intrinsic().name;
+ const auto& params = e.fcn.as_Intrinsic().params;
+ emit_intrinsic_call(name, params, e);
+ return ;
)
- m_of << "\t// ^ " << code->blocks[i].terminator << "\n";
+ )
+ m_of << "(";
+ for(unsigned int j = 0; j < e.args.size(); j ++) {
+ if(j != 0) m_of << ",";
+ m_of << " "; emit_param(e.args[j]);
}
- m_of << "}\n";
- m_of.flush();
- m_mir_res = nullptr;
+ m_of << " );\n";
}
private:
const ::HIR::TypeRef& monomorphise_fcn_return(::HIR::TypeRef& tmp, const ::HIR::Function& item, const Trans_Params& params)
@@ -2168,7 +2403,7 @@ namespace {
// Nothing needs to be done, this just stops the destructor from running.
}
else if( name == "drop_in_place" ) {
- emit_destructor_call( ::MIR::LValue::make_Deref({ box$(e.args.at(0).as_LValue().clone()) }), params.m_types.at(0), true );
+ emit_destructor_call( ::MIR::LValue::make_Deref({ box$(e.args.at(0).as_LValue().clone()) }), params.m_types.at(0), true, 1 /* TODO: get from caller */ );
}
else if( name == "needs_drop" ) {
// Returns `true` if the actual type given as `T` requires drop glue;
@@ -2508,8 +2743,9 @@ namespace {
m_of << ";\n";
}
- void emit_destructor_call(const ::MIR::LValue& slot, const ::HIR::TypeRef& ty, bool unsized_valid)
+ void emit_destructor_call(const ::MIR::LValue& slot, const ::HIR::TypeRef& ty, bool unsized_valid, unsigned indent_level)
{
+ auto indent = RepeatLitStr { "\t", static_cast<int>(indent_level) };
TU_MATCHA( (ty.m_data), (te),
// Impossible
(Diverge, ),
@@ -2530,7 +2766,7 @@ namespace {
if( te.type == ::HIR::BorrowType::Owned )
{
// Call drop glue on inner.
- emit_destructor_call( ::MIR::LValue::make_Deref({ box$(slot.clone()) }), *te.inner, true );
+ emit_destructor_call( ::MIR::LValue::make_Deref({ box$(slot.clone()) }), *te.inner, true, indent_level );
}
),
(Path,
@@ -2541,13 +2777,13 @@ namespace {
switch( metadata_type(ty) )
{
case MetadataType::None:
- m_of << "\t" << Trans_Mangle(p) << "(&"; emit_lvalue(slot); m_of << ");\n";
+ m_of << indent << Trans_Mangle(p) << "(&"; emit_lvalue(slot); m_of << ");\n";
break;
case MetadataType::Slice:
make_fcn = "make_sliceptr"; if(0)
case MetadataType::TraitObject:
make_fcn = "make_traitobjptr";
- m_of << "\t" << Trans_Mangle(p) << "( " << make_fcn << "(";
+ m_of << indent << Trans_Mangle(p) << "( " << make_fcn << "(";
if( slot.is_Deref() )
{
emit_lvalue(*slot.as_Deref().val);
@@ -2570,12 +2806,9 @@ namespace {
// Emit destructors for all entries
if( te.size_val > 0 )
{
- ::MIR::LValue lv = ::MIR::LValue::make_Field({ box$(slot.clone()), 0 });
- for(unsigned int i = 0; i < te.size_val; i ++)
- {
- lv.as_Field().field_index = i;
- emit_destructor_call(lv, *te.inner, false);
- }
+ m_of << indent << "for(unsigned i = 0; i < " << te.size_val << "; i++) {\n";
+ emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Local(~0u)) }), *te.inner, false, indent_level+1);
+ m_of << "\n" << indent << "}";
}
),
(Tuple,
@@ -2586,7 +2819,7 @@ namespace {
for(unsigned int i = 0; i < te.size(); i ++)
{
lv.as_Field().field_index = i;
- emit_destructor_call(lv, te[i], unsized_valid && (i == te.size()-1));
+ emit_destructor_call(lv, te[i], unsized_valid && (i == te.size()-1), indent_level);
}
}
),
@@ -2596,7 +2829,7 @@ namespace {
const auto* lvp = &slot;
while(const auto* le = lvp->opt_Field()) lvp = &*le->val;
MIR_ASSERT(*m_mir_res, lvp->is_Deref(), "Access to unized type without a deref - " << *lvp << " (part of " << slot << ")");
- m_of << "((VTABLE_HDR*)"; emit_lvalue(*lvp->as_Deref().val); m_of << ".META)->drop(";
+ m_of << indent << "((VTABLE_HDR*)"; emit_lvalue(*lvp->as_Deref().val); m_of << ".META)->drop(";
if( const auto* ve = slot.opt_Deref() )
{
emit_lvalue(*ve->val); m_of << ".PTR";
@@ -2613,10 +2846,9 @@ namespace {
while(const auto* le = lvp->opt_Field()) lvp = &*le->val;
MIR_ASSERT(*m_mir_res, lvp->is_Deref(), "Access to unized type without a deref - " << *lvp << " (part of " << slot << ")");
// Call destructor on all entries
- m_of << "for(unsigned i = 0; i < "; emit_lvalue(*lvp->as_Deref().val); m_of << ".META; i++) {";
- m_of << "\t\t";
- emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Temporary({~0u})) }), *te.inner, false);
- m_of << "\n\t}";
+ m_of << indent << "for(unsigned i = 0; i < "; emit_lvalue(*lvp->as_Deref().val); m_of << ".META; i++) {\n";
+ emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Local(~0u)) }), *te.inner, false, indent_level+1);
+ m_of << "\n" << indent << "}";
)
)
}
@@ -2817,20 +3049,17 @@ namespace {
void emit_lvalue(const ::MIR::LValue& val) {
TU_MATCHA( (val), (e),
- (Variable,
- m_of << "var" << e;
- ),
- (Temporary,
- if( e.idx == ~0u )
- m_of << "i";
- else
- m_of << "tmp" << e.idx;
+ (Return,
+ m_of << "rv";
),
(Argument,
m_of << "arg" << e.idx;
),
- (Return,
- m_of << "rv";
+ (Local,
+ if( e == ~0u )
+ m_of << "i";
+ else
+ m_of << "var" << e;
),
(Static,
m_of << Trans_Mangle(e);
@@ -2991,15 +3220,7 @@ namespace {
}
),
(Float,
- if( ::std::isnan(c.v) ) {
- m_of << "NAN";
- }
- else if( ::std::isinf(c.v) ) {
- m_of << "INFINITY";
- }
- else {
- m_of << c.v;
- }
+ this->emit_float(c.v);
),
(Bool,
m_of << (c.v ? "true" : "false");
diff --git a/src/trans/codegen_c.hpp b/src/trans/codegen_c.hpp
new file mode 100644
index 00000000..72d0c796
--- /dev/null
+++ b/src/trans/codegen_c.hpp
@@ -0,0 +1,47 @@
+/*
+ */
+#pragma once
+#include <vector>
+#include <memory>
+
+class Node;
+
+struct NodeRef
+{
+ ::std::unique_ptr<Node> node;
+ size_t bb_idx;
+
+ NodeRef(size_t idx): bb_idx(idx) {}
+ NodeRef(Node node);
+
+ bool has_target() const;
+ size_t target() const;
+
+ bool operator==(size_t idx) const {
+ return !node && bb_idx == idx;
+ }
+};
+
+TAGGED_UNION(Node, Block,
+(Block, struct {
+ size_t next_bb;
+ ::std::vector<NodeRef> nodes;
+ }),
+(If, struct {
+ size_t next_bb;
+ const ::MIR::LValue* val;
+ NodeRef arm_false;
+ NodeRef arm_true;
+ }),
+(Switch, struct {
+ size_t next_bb;
+ const ::MIR::LValue* val;
+ ::std::vector<NodeRef> arms;
+ }),
+(Loop, struct {
+ size_t next_bb;
+ NodeRef code;
+ })
+);
+
+extern ::std::vector<Node> MIR_To_Structured(const ::MIR::Function& fcn);
diff --git a/src/trans/codegen_c_structured.cpp b/src/trans/codegen_c_structured.cpp
new file mode 100644
index 00000000..888f9a26
--- /dev/null
+++ b/src/trans/codegen_c_structured.cpp
@@ -0,0 +1,298 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * trans/codegen_c_structured.cpp
+ * - Converts MIR into a semi-structured form
+ */
+#include <common.hpp>
+#include <mir/mir.hpp>
+#include <algorithm>
+#include "codegen_c.hpp"
+
+NodeRef::NodeRef(Node node_data):
+ node(new Node(mv$(node_data))),
+ bb_idx(SIZE_MAX)
+{
+}
+bool NodeRef::has_target() const
+{
+ if( node ) {
+ TU_MATCHA( (*this->node), (e),
+ (Block,
+ return e.next_bb != SIZE_MAX;
+ ),
+ (If,
+ return e.next_bb != SIZE_MAX;
+ ),
+ (Switch,
+ return e.next_bb != SIZE_MAX;
+ ),
+ (Loop,
+ return e.next_bb != SIZE_MAX;
+ )
+ )
+ throw "";
+ }
+ else {
+ return true;
+ }
+}
+size_t NodeRef::target() const
+{
+ if( node ) {
+ TU_MATCHA( (*this->node), (e),
+ (Block,
+ return e.next_bb;
+ ),
+ (If,
+ return e.next_bb;
+ ),
+ (Switch,
+ return e.next_bb;
+ ),
+ (Loop,
+ return e.next_bb;
+ )
+ )
+ throw "";
+ }
+ else {
+ return bb_idx;
+ }
+}
+
+class Converter
+{
+ const ::MIR::Function& m_fcn;
+public:
+ ::std::vector<unsigned> m_block_ref_count;
+ ::std::vector<bool> m_blocks_used;
+
+ Converter(const ::MIR::Function& fcn):
+ m_fcn(fcn)
+ {
+
+ }
+
+ // Returns true if the passed block is the start of a self-contained sequence of blocks
+ bool bb_is_opening(size_t bb_idx)
+ {
+ if( m_blocks_used[bb_idx] ) {
+ return false;
+ }
+ else if( m_block_ref_count[bb_idx] > 1 ) {
+ // TODO: Determine if these multiple references are from the block looping back on itself
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+ NodeRef process_node_ref(size_t bb_idx)
+ {
+ if( bb_is_opening(bb_idx) ) {
+ return NodeRef( process_node(bb_idx) );
+ }
+ else {
+ return NodeRef(bb_idx);
+ }
+ }
+
+ Node process_node(size_t bb_idx)
+ {
+ TRACE_FUNCTION_F(bb_idx);
+ ::std::vector<NodeRef> refs;
+ for(;;)
+ {
+ DEBUG("bb_idx = " << bb_idx);
+ bool stop = false;
+ assert( !m_blocks_used[bb_idx] );
+ m_blocks_used[bb_idx] = true;
+
+ refs.push_back( NodeRef(bb_idx) );
+
+ const auto& blk = m_fcn.blocks.at(bb_idx);
+ DEBUG("> " << blk.terminator);
+ TU_MATCHA( (blk.terminator), (te),
+ (Incomplete,
+ stop = true;
+ ),
+ (Goto,
+ bb_idx = te;
+ ),
+ (Panic,
+ TODO(Span(), "Panic");
+ ),
+ (Diverge,
+ stop = true;
+ ),
+ (Return,
+ stop = true;
+ ),
+ (If,
+ auto arm0 = process_node_ref(te.bb0);
+ auto arm1 = process_node_ref(te.bb1);
+ if( arm0.has_target() && arm1.has_target() ) {
+ if( arm0.target() == arm1.target() ) {
+ bb_idx = arm0.target();
+ }
+ else {
+ stop = true;
+ }
+ }
+ else if( arm0.has_target() ) {
+ bb_idx = arm0.target();
+ }
+ else if( arm1.has_target() ) {
+ bb_idx = arm1.target();
+ }
+ else {
+ // No target from either arm
+ stop = false;
+ }
+ refs.push_back(Node::make_If({ bb_idx, &te.cond, mv$(arm0), mv$(arm1) }));
+ ),
+ (Switch,
+ ::std::vector<NodeRef> arms;
+ ::std::vector<size_t> next_blocks;
+ for(auto& tgt : te.targets)
+ {
+ arms.push_back( process_node_ref(tgt) );
+ if( arms.back().has_target() )
+ {
+ next_blocks.push_back( arms.back().target() );
+ }
+ }
+ ::std::sort(next_blocks.begin(), next_blocks.end());
+ size_t exit_bb = SIZE_MAX;
+ if(!next_blocks.empty())
+ {
+ size_t cur = next_blocks[0];
+ size_t cur_count = 0;
+ size_t max_count = 0;
+ for(auto b : next_blocks)
+ {
+ if(cur == b) {
+ cur_count ++;
+ }
+ else {
+ if( cur_count > max_count ) {
+ exit_bb = cur;
+ }
+ cur = b;
+ cur_count = 1;
+ }
+ }
+ if( cur_count > max_count ) {
+ exit_bb = cur;
+ }
+ }
+ refs.push_back(Node::make_Switch({ exit_bb, &te.val, mv$(arms) }));
+ stop = true;
+ ),
+ (SwitchValue,
+ TODO(Span(), "SwitchValue");
+ ),
+ (Call,
+ // NOTE: Let the panic arm just be a goto
+ bb_idx = te.ret_block;
+ )
+ )
+
+ if( stop )
+ {
+ break;
+ }
+
+ // If `bb_idx` is in `refs` as a NodeRef
+ auto it = ::std::find(refs.begin(), refs.end(), bb_idx);
+ if( it != refs.end() )
+ {
+ // Wrap ibb_idxms from `it` to `refs.end()` in a `loop` block
+ ::std::vector<NodeRef> loop_blocks;
+ loop_blocks.reserve(refs.end() - it);
+ for(auto it2 = it; it2 != refs.end(); ++it2)
+ loop_blocks.push_back( mv$(*it2) );
+ auto loop_node = NodeRef( Node::make_Block({ SIZE_MAX, mv$(loop_blocks) }) );
+
+ refs.push_back( Node::make_Loop({ SIZE_MAX, mv$(loop_node) }) );
+ // TODO: If there is only one `goto` in the above loop, assume it's the target
+ DEBUG("Loop");
+ break;
+ }
+ else if( bb_is_opening(bb_idx) )
+ {
+ DEBUG("Destination " << bb_idx << " is unreferenced+unvisited");
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return Node::make_Block({ bb_idx, mv$(refs) });
+ }
+};
+
+::std::vector<Node> MIR_To_Structured(const ::MIR::Function& fcn)
+{
+ Converter conv(fcn);
+ conv.m_block_ref_count.resize( fcn.blocks.size() );
+ conv.m_block_ref_count[0] += 1;
+ for(const auto& blk : fcn.blocks)
+ {
+ TU_MATCHA( (blk.terminator), (te),
+ (Incomplete,
+ ),
+ (Goto,
+ conv.m_block_ref_count[te] += 1;
+ ),
+ (Panic,
+ conv.m_block_ref_count[te.dst] += 1;
+ ),
+ (Diverge,
+ ),
+ (Return,
+ ),
+ (If,
+ conv.m_block_ref_count[te.bb0] += 1;
+ conv.m_block_ref_count[te.bb1] += 1;
+ ),
+ (Switch,
+ for(auto tgt : te.targets)
+ conv.m_block_ref_count[tgt] += 1;
+ ),
+ (SwitchValue,
+ for(auto tgt : te.targets)
+ conv.m_block_ref_count[tgt] += 1;
+ conv.m_block_ref_count[te.def_target] += 1;
+ ),
+ (Call,
+ conv.m_block_ref_count[te.ret_block] += 1;
+ conv.m_block_ref_count[te.panic_block] += 1;
+ )
+ )
+ }
+
+ // First Block: Becomes a block in structured output
+ // - Terminator selects what the next block will be
+ // -
+
+ // Find next unvisited block
+ conv.m_blocks_used.resize( fcn.blocks.size() );
+ ::std::vector<Node> nodes;
+ for(size_t bb_idx = 0; bb_idx < fcn.blocks.size(); bb_idx ++)
+ {
+ if( conv.m_blocks_used[bb_idx] )
+ continue;
+
+ nodes.push_back( conv.process_node(bb_idx) );
+ }
+
+
+ // Return.
+ return nodes;
+}
+
+
diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp
index 02116d18..41489e2b 100644
--- a/src/trans/enumerate.cpp
+++ b/src/trans/enumerate.cpp
@@ -623,9 +623,7 @@ void Trans_Enumerate_Types(EnumState& state)
if( fcn.m_code.m_mir )
{
const auto& mir = *fcn.m_code.m_mir;
- for(const auto& ty : mir.named_variables)
- tv.visit_type(monomorph(ty));
- for(const auto& ty : mir.temporaries)
+ for(const auto& ty : mir.locals)
tv.visit_type(monomorph(ty));
// TODO: Find all LValue::Deref instances and get the result type
@@ -646,19 +644,19 @@ void Trans_Enumerate_Types(EnumState& state)
};
// Recurse, if Deref get the type and add it to the visitor
TU_MATCHA( (lv), (e),
- (Variable,
+ (Return,
if( tmp_ty_ptr ) {
- return monomorph_outer(fcn.m_code.m_mir->named_variables[e]);
+ TODO(Span(), "Get return type for MIR type enumeration");
}
),
- (Temporary,
+ (Argument,
if( tmp_ty_ptr ) {
- return monomorph_outer(fcn.m_code.m_mir->temporaries[e.idx]);
+ return monomorph_outer(fcn.m_args[e.idx].second);
}
),
- (Argument,
+ (Local,
if( tmp_ty_ptr ) {
- return monomorph_outer(fcn.m_args[e.idx].second);
+ return monomorph_outer(fcn.m_code.m_mir->locals[e]);
}
),
(Static,
@@ -682,11 +680,6 @@ void Trans_Enumerate_Types(EnumState& state)
)
}
),
- (Return,
- if( tmp_ty_ptr ) {
- TODO(Span(), "Get return type for MIR type enumeration");
- }
- ),
(Field,
const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
if( tmp_ty_ptr )
@@ -942,6 +935,9 @@ void Trans_Enumerate_Types(EnumState& state)
(Switch,
H::visit_lvalue(tv,pp,fcn, te.val);
),
+ (SwitchValue,
+ H::visit_lvalue(tv,pp,fcn, te.val);
+ ),
(Call,
if( te.fcn.is_Value() )
H::visit_lvalue(tv,pp,fcn, te.fcn.as_Value());
@@ -1344,17 +1340,15 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co
void Trans_Enumerate_FillFrom_MIR_LValue(EnumState& state, const ::MIR::LValue& lv, const Trans_Params& pp)
{
TU_MATCHA( (lv), (e),
- (Variable,
- ),
- (Temporary,
+ (Return,
),
(Argument,
),
+ (Local,
+ ),
(Static,
Trans_Enumerate_FillFrom_Path(state, e, pp);
),
- (Return,
- ),
(Field,
Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp);
),
@@ -1485,6 +1479,9 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code,
(Switch,
Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
),
+ (SwitchValue,
+ Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp);
+ ),
(Call,
Trans_Enumerate_FillFrom_MIR_LValue(state, e.ret_val, pp);
TU_MATCHA( (e.fcn), (e2),
diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp
index 3ac2ee09..b752a5bc 100644
--- a/src/trans/monomorphise.cpp
+++ b/src/trans/monomorphise.cpp
@@ -13,10 +13,9 @@ namespace {
::MIR::LValue monomorph_LValue(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::LValue& tpl)
{
TU_MATCHA( (tpl), (e),
- (Variable, return e; ),
- (Temporary, return e; ),
- (Argument, return e; ),
(Return, return e; ),
+ (Argument, return e; ),
+ (Local, return e; ),
(Static,
return params.monomorph(resolve, e);
),
@@ -120,17 +119,11 @@ namespace {
::MIR::Function output;
// 1. Monomorphise locals and temporaries
- output.named_variables.reserve( tpl->named_variables.size() );
- for(const auto& var : tpl->named_variables)
- {
- DEBUG("- var" << output.named_variables.size());
- output.named_variables.push_back( params.monomorph(resolve, var) );
- }
- output.temporaries.reserve( tpl->temporaries.size() );
- for(const auto& ty : tpl->temporaries)
+ output.locals.reserve( tpl->locals.size() );
+ for(const auto& var : tpl->locals)
{
- DEBUG("- tmp" << output.temporaries.size());
- output.temporaries.push_back( params.monomorph(resolve, ty) );
+ DEBUG("- _" << output.locals.size());
+ output.locals.push_back( params.monomorph(resolve, var) );
}
output.drop_flags = tpl->drop_flags;
@@ -302,6 +295,14 @@ namespace {
e.targets
});
),
+ (SwitchValue,
+ terminator = ::MIR::Terminator::make_SwitchValue({
+ monomorph_LValue(resolve, params, e.val),
+ e.def_target,
+ e.targets,
+ e.values.clone()
+ });
+ ),
(Call,
struct H {
static ::MIR::CallTarget monomorph_calltarget(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::CallTarget& ct) {
diff --git a/src/trans/target.cpp b/src/trans/target.cpp
index a85ab12a..d9b3486e 100644
--- a/src/trans/target.cpp
+++ b/src/trans/target.cpp
@@ -7,10 +7,53 @@
*/
#include "target.hpp"
#include <algorithm>
+#include "../expand/cfg.hpp"
// TODO: Replace with target selection
#define POINTER_SIZE_BYTES 8
+TargetSpec g_target = {
+ "unix",
+ "linux",
+ "gnu",
+ CodegenMode::Gnu11,
+ TargetArch {
+ "x86_64",
+ 64, false,
+ { true, false, true, true, true }
+ }
+ };
+
+void Target_SetCfg()
+{
+ if(g_target.m_family == "unix") {
+ Cfg_SetFlag("unix");
+ }
+ else if( g_target.m_family == "windows") {
+ Cfg_SetFlag("windows");
+ }
+ Cfg_SetValue("target_family", g_target.m_family);
+
+ if( g_target.m_os_name == "linux" )
+ {
+ Cfg_SetFlag("linux");
+ }
+ Cfg_SetValue("target_env", g_target.m_env_name);
+
+ Cfg_SetValue("target_os", g_target.m_os_name);
+ Cfg_SetValue("target_pointer_width", FMT(g_target.m_arch.m_pointer_bits));
+ Cfg_SetValue("target_endian", g_target.m_arch.m_big_endian ? "big" : "little");
+ Cfg_SetValue("target_arch", g_target.m_arch.m_name);
+ Cfg_SetValueCb("target_has_atomic", [&](const ::std::string& s) {
+ if(s == "8") return g_target.m_arch.m_atomics.u8; // Has an atomic byte
+ if(s == "ptr") return g_target.m_arch.m_atomics.ptr; // Has an atomic pointer-sized value
+ return false;
+ });
+ Cfg_SetValueCb("target_feature", [](const ::std::string& s) {
+ return false;
+ });
+}
+
bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align)
{
TU_MATCHA( (ty.m_data), (te),
@@ -55,8 +98,8 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t&
return true;
case ::HIR::CoreType::Usize:
case ::HIR::CoreType::Isize:
- out_size = POINTER_SIZE_BYTES;
- out_align = POINTER_SIZE_BYTES;
+ out_size = g_target.m_arch.m_pointer_bits / 8;
+ out_align = g_target.m_arch.m_pointer_bits / 8;
return true;
case ::HIR::CoreType::F32:
out_size = 4;
@@ -104,6 +147,11 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t&
size_t size, align;
if( !Target_GetSizeAndAlignOf(sp, t, size,align) )
return false;
+ if( out_size % align != 0 )
+ {
+ out_size += align;
+ out_size %= align;
+ }
out_size += size;
out_align = ::std::max(out_align, align);
}
@@ -116,6 +164,9 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t&
),
(Function,
// Pointer size
+ out_size = g_target.m_arch.m_pointer_bits / 8;
+ out_align = g_target.m_arch.m_pointer_bits / 8;
+ return true;
),
(Closure,
// TODO.
diff --git a/src/trans/target.hpp b/src/trans/target.hpp
index 1c081b54..80ba0bf2 100644
--- a/src/trans/target.hpp
+++ b/src/trans/target.hpp
@@ -10,6 +10,38 @@
#include <cstddef>
#include <hir/type.hpp>
+enum class CodegenMode
+{
+ Gnu11,
+ Msvc,
+};
+
+struct TargetArch
+{
+ ::std::string m_name;
+ unsigned m_pointer_bits;
+ bool m_big_endian;
+
+ struct {
+ bool u8;
+ bool u16;
+ bool u32;
+ bool u64;
+ bool ptr;
+ } m_atomics;
+};
+struct TargetSpec
+{
+ ::std::string m_family;
+ ::std::string m_os_name;
+ ::std::string m_env_name;
+
+ CodegenMode m_codegen_mode;
+ TargetArch m_arch;
+};
+
+
+extern void Target_SetCfg();
extern bool Target_GetSizeOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_size);
extern bool Target_GetAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_align);