summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2019-11-24 19:28:53 +0800
committerJohn Hodge <tpg@mutabah.net>2019-11-24 20:11:41 +0800
commit80fc5138c0d8e8755b61ad37a4107a02b5a074e3 (patch)
tree7de575ac780242332229cc4ce3e86b82c726a0ad
parent0c09aba4b978d5886f67d8745742aa2c8b545313 (diff)
downloadmrust-80fc5138c0d8e8755b61ad37a4107a02b5a074e3.tar.gz
mir_opt_test - All terminators implemented, more simple test cases
-rw-r--r--tools/mir_opt_test/main.cpp28
-rw-r--r--tools/mir_opt_test/parser.cpp193
-rw-r--r--tools/mir_opt_test/tests/trivial.rs54
-rw-r--r--vsproject/mir_opt_test/mir_opt_test.vcxproj4
4 files changed, 247 insertions, 32 deletions
diff --git a/tools/mir_opt_test/main.cpp b/tools/mir_opt_test/main.cpp
index 80a627f3..daa6afe5 100644
--- a/tools/mir_opt_test/main.cpp
+++ b/tools/mir_opt_test/main.cpp
@@ -24,6 +24,8 @@ struct Options
{
helpers::path test_dir;
+ // TODO: List of test globs
+
bool parse(int argc, char* argv[]);
void print_usage() const;
void print_help() const;
@@ -96,6 +98,7 @@ int main(int argc, char* argv[])
#endif
}
+ // Run HIR bind on the loaded code (makes sure that it's ready for use)
{
auto ph = DebugTimedPhase("Cleanup");
for(auto& f : test_files)
@@ -104,6 +107,7 @@ int main(int argc, char* argv[])
}
}
+ // Run MIR validation BEFORE attempting optimisaion
{
auto ph = DebugTimedPhase("Validate");
for(auto& f : test_files)
@@ -112,21 +116,27 @@ int main(int argc, char* argv[])
}
}
- for(auto& f : test_files)
+ // Funally run the tests
{
auto ph = DebugTimedPhase("Run Tests");
- for(const auto& test : f.m_tests)
+ for(auto& f : test_files)
{
- const auto& in_fcn = f.m_crate->get_function_by_path(Span(), test.input_function);
- const auto& exp_mir = *f.m_crate->get_function_by_path(Span(), test.output_template_function).m_code.m_mir;
+ for(const auto& test : f.m_tests)
+ {
+ const auto& in_fcn = f.m_crate->get_function_by_path(Span(), test.input_function);
+ const auto& exp_mir = *f.m_crate->get_function_by_path(Span(), test.output_template_function).m_code.m_mir;
- StaticTraitResolve resolve(*f.m_crate);
- // TODO: Generics?
- auto cloned_mir = clone_mir(resolve, in_fcn.m_code.m_mir);
+ StaticTraitResolve resolve(*f.m_crate);
+ // TODO: Generics?
+ auto cloned_mir = clone_mir(resolve, in_fcn.m_code.m_mir);
- MIR_Optimise(resolve, test.input_function, *cloned_mir, in_fcn.m_args, in_fcn.m_return);
+ MIR_Optimise(resolve, test.input_function, *cloned_mir, in_fcn.m_args, in_fcn.m_return);
- compare_mir(exp_mir, *cloned_mir, test.input_function);
+ if( !compare_mir(exp_mir, *cloned_mir, test.input_function) )
+ {
+ MIR_Dump_Fcn(std::cout, *cloned_mir);
+ }
+ }
}
}
diff --git a/tools/mir_opt_test/parser.cpp b/tools/mir_opt_test/parser.cpp
index 70de7f9b..d86d124b 100644
--- a/tools/mir_opt_test/parser.cpp
+++ b/tools/mir_opt_test/parser.cpp
@@ -10,6 +10,8 @@
namespace {
HIR::Function parse_function(TokenStream& lex, RcString& out_name);
+ HIR::PathParams parse_params(TokenStream& lex);
+ HIR::Path parse_path(TokenStream& lex);
HIR::TypeRef parse_type(TokenStream& lex);
MIR::LValue parse_lvalue(TokenStream& lex, const ::std::map<RcString, MIR::LValue::Storage>& name_map);
@@ -96,8 +98,10 @@ namespace {
Token tok;
::std::map<RcString, MIR::LValue::Storage> val_name_map;
val_name_map.insert(::std::make_pair("retval", MIR::LValue::Storage::new_Return()));
+ ::std::map<RcString, unsigned> dropflag_names;
::std::map<RcString, unsigned> real_bb_name_map;
- ::std::map<unsigned, RcString> lookup_bb_name_map;
+ ::std::map<RcString, unsigned> lookup_bb_name_map;
+ ::std::vector<RcString> lookup_bb_names;
::HIR::Function fcn_decl;
fcn_decl.m_code.m_mir = ::MIR::FunctionPointer(new ::MIR::Function());
@@ -145,13 +149,25 @@ namespace {
{
GET_CHECK_TOK(tok, lex, TOK_IDENT);
auto name = tok.istr();
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- auto var_ty = parse_type(lex);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ if( consume_if(lex, TOK_EQUAL) ) {
+ GET_TOK(tok, lex);
+ bool v = tok.type() == TOK_RWORD_TRUE ? true
+ : tok.type() == TOK_RWORD_FALSE ? false
+ : throw ParseError::Unexpected(lex, tok, { TOK_RWORD_TRUE, TOK_RWORD_FALSE });
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- auto var_idx = static_cast<unsigned>(mir_fcn.locals.size());
- val_name_map.insert( ::std::make_pair(name, ::MIR::LValue::Storage::new_Local(var_idx)) );
- mir_fcn.locals.push_back( mv$(var_ty) );
+ dropflag_names.insert(::std::make_pair( name, static_cast<unsigned>(mir_fcn.drop_flags.size()) ));
+ mir_fcn.drop_flags.push_back(v);
+ }
+ else {
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ auto var_ty = parse_type(lex);
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+
+ auto var_idx = static_cast<unsigned>(mir_fcn.locals.size());
+ val_name_map.insert( ::std::make_pair(name, ::MIR::LValue::Storage::new_Local(var_idx)) );
+ mir_fcn.locals.push_back( mv$(var_ty) );
+ }
}
// 2. List of BBs arranged with 'ident: { STMTS; TERM }'
while( lex.lookahead(0) != TOK_BRACE_CLOSE )
@@ -188,12 +204,28 @@ namespace {
GET_TOK(tok, lex);
switch(tok.type())
{
+ // Cnstant boolean
case TOK_RWORD_TRUE: src = MIR::Constant::make_Bool({true }); break;
case TOK_RWORD_FALSE: src = MIR::Constant::make_Bool({false}); break;
+
+ // Operator (e.g. `ADD(...)`) or an lvalue
case TOK_IDENT:
- TODO(lex.point_span(), "MIR assign - " << tok);
+ if( consume_if(lex, TOK_PAREN_OPEN) )
+ {
+ TODO(lex.point_span(), "MIR assign operator - " << tok.istr());
+ }
+ else
+ {
+ lex.putback(mv$(tok));
+ src = parse_lvalue(lex, val_name_map);
+ }
break;
- // Tuple literal
+ // Start of a path (lvalue)
+ case TOK_DOUBLE_COLON:
+ lex.putback(mv$(tok));
+ src = parse_lvalue(lex, val_name_map);
+ break;
+ // Tuple literal
case TOK_PAREN_OPEN: {
src = MIR::RValue::make_Tuple({});
auto& vals = src.as_Tuple().vals;
@@ -204,7 +236,7 @@ namespace {
break;
}
GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE);
- } break;
+ } break;
default:
TODO(lex.point_span(), "MIR assign - " << tok);
}
@@ -219,25 +251,116 @@ namespace {
}
GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
+ auto parse_bb_name = [&](TokenStream& lex) {
+ Token tok;
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto& bb_name = tok.istr();
+ if( lookup_bb_name_map.count(bb_name) ) {
+ return lookup_bb_name_map[bb_name];
+ }
+ else {
+ unsigned idx = static_cast<unsigned>(lookup_bb_names.size());
+ lookup_bb_names.push_back(bb_name);
+ lookup_bb_name_map[bb_name] = idx;
+ return idx;
+ }
+ };
+
GET_CHECK_TOK(tok, lex, TOK_IDENT);
if( tok.istr() == "RETURN" )
{
bb.terminator = ::MIR::Terminator::make_Return({});
}
+ else if( tok.istr() == "DIVERGE" )
+ {
+ bb.terminator = ::MIR::Terminator::make_Diverge({});
+ }
+ else if( tok.istr() == "GOTO" )
+ {
+ bb.terminator = ::MIR::Terminator::make_Goto(parse_bb_name(lex));
+ }
+ else if( tok.istr() == "PANIC" )
+ {
+ bb.terminator = ::MIR::Terminator::make_Panic({ parse_bb_name(lex) });
+ }
+ else if( tok.istr() == "CALL" )
+ {
+ auto dst = parse_lvalue(lex, val_name_map);
+ GET_CHECK_TOK(tok, lex, TOK_EQUAL);
+ MIR::CallTarget target;
+ if( lex.lookahead(0) == TOK_PAREN_OPEN )
+ {
+ GET_TOK(tok, lex);
+ target = ::MIR::CallTarget::make_Value(parse_lvalue(lex, val_name_map));
+ }
+ else if( lex.lookahead(0) == TOK_STRING )
+ {
+ GET_TOK(tok, lex);
+ auto int_name = RcString(tok.str());
+ auto params = parse_params(lex);
+ target = ::MIR::CallTarget::make_Intrinsic({ int_name, mv$(params) });
+ }
+ else
+ {
+ target = ::MIR::CallTarget::make_Path( parse_path(lex) );
+ }
+
+ ::std::vector<MIR::Param> args;
+ GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
+ while( lex.lookahead(0) != TOK_PAREN_CLOSE )
+ {
+ args.push_back(parse_lvalue(lex, val_name_map));
+ if( !consume_if(lex, TOK_COMMA) )
+ break;
+ }
+ GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE);
+ GET_CHECK_TOK(tok, lex, TOK_FATARROW);
+ auto ret_bb = parse_bb_name(lex);
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_ELSE);
+ auto panic_bb = parse_bb_name(lex);
+
+ bb.terminator = ::MIR::Terminator::make_Call({ ret_bb, panic_bb, mv$(dst), mv$(target), mv$(args) });
+ }
else
{
- TODO(lex.point_span(), "MIR terminator - " << tok);
+ TODO(lex.point_span(), "MIR terminator - " << tok.istr());
}
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
}
GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- // 3. Convert BB names over
+ // 3. Convert BB indexes into correct numbering
for(auto& blk : mir_fcn.blocks)
{
TU_MATCH_HDRA( (blk.terminator), {)
- TU_ARMA(Goto, e) {
- e = real_bb_name_map.at( lookup_bb_name_map[e] );
- }
+ TU_ARMA(Diverge, e) {
+ }
+ TU_ARMA(Return, e) {
+ }
+ TU_ARMA(Incomplete, e) {
+ }
+ TU_ARMA(Goto, e) {
+ e = real_bb_name_map.at( lookup_bb_names[e] );
+ }
+ TU_ARMA(Panic, e) {
+ e.dst = real_bb_name_map.at( lookup_bb_names[e.dst] );
+ }
+ TU_ARMA(Call, e) {
+ e.ret_block = real_bb_name_map.at( lookup_bb_names[e.ret_block] );
+ e.panic_block = real_bb_name_map.at( lookup_bb_names[e.panic_block] );
+ }
+ TU_ARMA(If, e) {
+ e.bb0 = real_bb_name_map.at( lookup_bb_names[e.bb0] );
+ e.bb1 = real_bb_name_map.at( lookup_bb_names[e.bb1] );
+ }
+ TU_ARMA(Switch, e) {
+ for(auto& tgt : e.targets)
+ tgt = real_bb_name_map.at( lookup_bb_names[tgt] );
+ }
+ TU_ARMA(SwitchValue, e) {
+ for(auto& tgt : e.targets)
+ tgt = real_bb_name_map.at( lookup_bb_names[tgt] );
+ }
}
}
@@ -245,10 +368,48 @@ namespace {
out_name = mv$(fcn_name);
return fcn_decl;
}
+ HIR::PathParams parse_params(TokenStream& lex)
+ {
+ HIR::PathParams rv;
+ if( lex.lookahead(0) == TOK_LT || lex.lookahead(0) == TOK_DOUBLE_LT )
+ {
+ TODO(lex.point_span(), "parse_params");
+ }
+ return rv;
+ }
+ HIR::SimplePath parse_simplepath(TokenStream& lex)
+ {
+ Token tok;
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
+ GET_CHECK_TOK(tok, lex, TOK_STRING);
+ auto rv = ::HIR::SimplePath(RcString::new_interned(tok.str()));
+
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
+ lex.putback(mv$(tok));
+
+ while( consume_if(lex, TOK_DOUBLE_COLON) )
+ {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ rv.m_components.push_back( tok.istr() );
+ }
+ return rv;
+ }
+ HIR::GenericPath parse_genericpath(TokenStream& lex)
+ {
+ auto sp = parse_simplepath(lex);
+ return ::HIR::GenericPath(mv$(sp), parse_params(lex));
+ }
HIR::Path parse_path(TokenStream& lex)
{
- TODO(lex.point_span(), "parse_path");
+ if( lex.lookahead(0) == TOK_LT || lex.lookahead(0) == TOK_DOUBLE_LT )
+ {
+ TODO(lex.point_span(), "parse_path - ufcs");
+ }
+ else
+ {
+ return parse_genericpath(lex);
+ }
}
HIR::TypeRef parse_type(TokenStream& lex)
{
diff --git a/tools/mir_opt_test/tests/trivial.rs b/tools/mir_opt_test/tests/trivial.rs
index eb818bfb..f2f125b8 100644
--- a/tools/mir_opt_test/tests/trivial.rs
+++ b/tools/mir_opt_test/tests/trivial.rs
@@ -3,21 +3,61 @@ fn test_trivial()
{
bb0: {
ASSIGN retval = ();
- } RETURN
+ } RETURN;
}
-#[test="dce_local_exp"]
-fn dce_local()
+// Dead code elimination, should remove any useless code
+// - Unused assignments
+// - Unused locals
+// - Unused drop flags
+// - Unused blocks
+#[test="dce_exp"]
+fn dce()
{
+ let df0 = false;
let useless: ();
bb0: {
ASSIGN useless = ();
+ ASSIGN useless = useless; // Never read, so will be removed
ASSIGN retval = ();
- } RETURN
+ //ASSIGN retval = (); // Note: won't be de-duplicated (TODO)
+ } RETURN;
+ // Never referenced, will be removed
+ bb_unused: {
+ } GOTO bb_unused_indir;
+ // Indirectly unused, will still be removed
+ bb_unused_indir: {
+ } DIVERGE;
+ // References itself without other reference, will be removed
+ bb_unused_self: {
+ } GOTO bb_unused_self;
}
-fn dce_local_exp()
+fn dce_exp()
{
bb0: {
ASSIGN retval = ();
- } RETURN
-} \ No newline at end of file
+ } RETURN;
+}
+
+#[test="inlining_exp"]
+fn inlining()
+{
+ bb0: {
+ } CALL retval = ::""::inlining_target() => bb1 else bb2;
+ bb1: {
+ } RETURN;
+ bb2: {
+ } DIVERGE;
+}
+fn inlining_target()
+{
+ bb0: {
+ ASSIGN retval = ();
+ } RETURN;
+}
+fn inlining_exp()
+{
+ bb0: {
+ ASSIGN retval = ();
+ } RETURN;
+}
diff --git a/vsproject/mir_opt_test/mir_opt_test.vcxproj b/vsproject/mir_opt_test/mir_opt_test.vcxproj
index f7429dc9..4f8cc28f 100644
--- a/vsproject/mir_opt_test/mir_opt_test.vcxproj
+++ b/vsproject/mir_opt_test/mir_opt_test.vcxproj
@@ -79,6 +79,7 @@
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)..\src;$(SolutionDir)..\src\include;$(SolutionDir)..\tools\mir_opt_test;$(SolutionDir)..\tools\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <TreatSpecificWarningsAsErrors>4062;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -95,6 +96,7 @@
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)..\src;$(SolutionDir)..\src\include;$(SolutionDir)..\tools\mir_opt_test;$(SolutionDir)..\tools\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <TreatSpecificWarningsAsErrors>4062;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -109,6 +111,7 @@
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)..\src;$(SolutionDir)..\src\include;$(SolutionDir)..\tools\mir_opt_test;$(SolutionDir)..\tools\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <TreatSpecificWarningsAsErrors>4062;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -125,6 +128,7 @@
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)..\src;$(SolutionDir)..\src\include;$(SolutionDir)..\tools\mir_opt_test;$(SolutionDir)..\tools\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <TreatSpecificWarningsAsErrors>4062;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>