diff options
author | John Hodge <tpg@mutabah.net> | 2019-11-24 19:28:53 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2019-11-24 20:11:41 +0800 |
commit | 80fc5138c0d8e8755b61ad37a4107a02b5a074e3 (patch) | |
tree | 7de575ac780242332229cc4ce3e86b82c726a0ad | |
parent | 0c09aba4b978d5886f67d8745742aa2c8b545313 (diff) | |
download | mrust-80fc5138c0d8e8755b61ad37a4107a02b5a074e3.tar.gz |
mir_opt_test - All terminators implemented, more simple test cases
-rw-r--r-- | tools/mir_opt_test/main.cpp | 28 | ||||
-rw-r--r-- | tools/mir_opt_test/parser.cpp | 193 | ||||
-rw-r--r-- | tools/mir_opt_test/tests/trivial.rs | 54 | ||||
-rw-r--r-- | vsproject/mir_opt_test/mir_opt_test.vcxproj | 4 |
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> |