summaryrefslogtreecommitdiff
path: root/tools/mir_opt_test/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/mir_opt_test/main.cpp')
-rw-r--r--tools/mir_opt_test/main.cpp246
1 files changed, 246 insertions, 0 deletions
diff --git a/tools/mir_opt_test/main.cpp b/tools/mir_opt_test/main.cpp
new file mode 100644
index 00000000..80a627f3
--- /dev/null
+++ b/tools/mir_opt_test/main.cpp
@@ -0,0 +1,246 @@
+/*
+ */
+#include <path.h>
+#include <target_version.hpp>
+#include "test_desc.h"
+#include <hir_conv/main_bindings.hpp>
+#include <mir/operations.hpp>
+#include <mir/main_bindings.hpp>
+#include <mir/mir.hpp>
+#include <trans/monomorphise.hpp> // used as a MIR clone
+#include <debug_inner.hpp>
+
+#ifdef _WIN32
+# define NOGDI // Don't include GDI functions (defines some macros that collide with mrustc ones)
+# include <Windows.h>
+#else
+# include <dirent.h>
+# include <sys/stat.h>
+#endif
+
+TargetVersion gTargetVersion = TargetVersion::Rustc1_29;
+
+struct Options
+{
+ helpers::path test_dir;
+
+ bool parse(int argc, char* argv[]);
+ void print_usage() const;
+ void print_help() const;
+};
+
+namespace {
+ MIR::FunctionPointer clone_mir(const StaticTraitResolve& resolve, const MIR::FunctionPointer& fcn);
+ bool compare_mir(const MIR::Function& exp, const MIR::Function& have, const HIR::SimplePath& path);
+}
+
+int main(int argc, char* argv[])
+{
+ debug_init_phases("MIRTEST_DEBUG", {
+ "Parse",
+ "Cleanup",
+ "Validate",
+ "Run Tests",
+ });
+
+ Options opts;
+ if( !opts.parse(argc, argv) )
+ {
+ return 1;
+ }
+
+ ::std::vector<MirOptTestFile> test_files;
+ {
+ auto ph = DebugTimedPhase("Parse");
+#ifdef _WIN32
+ WIN32_FIND_DATA find_data;
+ auto mask = opts.test_dir / "*.rs";
+ HANDLE find_handle = FindFirstFile( mask.str().c_str(), &find_data );
+ if( find_handle == INVALID_HANDLE_VALUE ) {
+ ::std::cerr << "Unable to find files matching " << mask << ::std::endl;
+ return 1;
+ }
+ do
+ {
+ auto test_file_path = opts.test_dir / find_data.cFileName;
+#else
+ auto* dp = opendir(opts.test_dir.str().c_str());
+ if( dp == nullptr ) {
+ ::std::cerr << "Unable to open directory " << opts.test_dir << ::std::endl;
+ }
+ while( const auto* dent = readdir(dp) )
+ {
+ if( dent->d_name[0] == '.' )
+ continue ;
+ auto test_file_path = opts.test_dir / dent->d_name;
+ struct stat sb;
+ stat(test_file_path.str().c_str(), &sb);
+ if( (sb.st_mode & S_IFMT) != S_IFREG) {
+ continue ;
+ }
+#endif
+ try
+ {
+ test_files.push_back( MirOptTestFile::load_from_file(test_file_path) );
+ }
+ catch(const ::std::exception& e)
+ {
+ ::std::cerr << "Exception: " << e.what() << " when loading test " << test_file_path << ::std::endl;
+ }
+#ifndef _WIN32
+ }
+ closedir(dp);
+#else
+ } while( FindNextFile(find_handle, &find_data) );
+ FindClose(find_handle);
+#endif
+ }
+
+ {
+ auto ph = DebugTimedPhase("Cleanup");
+ for(auto& f : test_files)
+ {
+ ConvertHIR_Bind(*f.m_crate);
+ }
+ }
+
+ {
+ auto ph = DebugTimedPhase("Validate");
+ for(auto& f : test_files)
+ {
+ MIR_CheckCrate(*f.m_crate);
+ }
+ }
+
+ for(auto& f : test_files)
+ {
+ auto ph = DebugTimedPhase("Run Tests");
+ 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);
+
+ 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);
+ }
+ }
+
+ return 0;
+}
+
+bool Options::parse(int argc, char* argv[])
+{
+ for(int i = 1; i < argc; i ++)
+ {
+ auto arg = helpers::string_view(argv[i], strlen(argv[i]));
+ if( arg[0] != '-' )
+ {
+ if( !this->test_dir.is_valid() )
+ {
+ this->test_dir = static_cast<std::string>(arg);
+ }
+ else
+ {
+ this->print_usage();
+ return false;
+ }
+ }
+ else if( arg[1] != '-' )
+ {
+ switch(arg[1])
+ {
+ case 'h':
+ this->print_help();
+ exit(0);
+ default:
+ this->print_usage();
+ return false;
+ }
+ }
+ else
+ {
+ if( arg == "--help" )
+ {
+ this->print_help();
+ exit(0);
+ }
+ else
+ {
+ this->print_usage();
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void Options::print_usage() const
+{
+}
+void Options::print_help() const
+{
+}
+
+namespace {
+ MIR::FunctionPointer clone_mir(const StaticTraitResolve& resolve, const MIR::FunctionPointer& fcn)
+ {
+ return Trans_Monomorphise(resolve, {}, fcn);
+ }
+ bool compare_mir(const MIR::Function& exp, const MIR::Function& have, const HIR::SimplePath& path)
+ {
+ if( exp.locals.size() != have.locals.size() ) {
+ std::cerr << path << " Mismatch in local count: exp " << exp.locals.size() << " != " << have.locals.size() << std::endl;
+ return false;
+ }
+ for(size_t i = 0; i < exp.locals.size(); i ++)
+ {
+ if( exp.locals[i] != have.locals[i] )
+ {
+ std::cerr << path << " Local " << i << " mismatch: exp " << exp.locals[i] << " != " << have.locals[i] << std::endl;
+ return false;
+ }
+ }
+
+ if( exp.drop_flags != have.drop_flags ) {
+ std::cerr << path << " Mismatch in drop flags" << std::endl;
+ return false;
+ }
+
+ if( exp.blocks.size() != have.blocks.size() ) {
+ std::cerr << path << " Mismatch in block count: exp " << exp.blocks.size() << " != " << have.blocks.size() << std::endl;
+ return false;
+ }
+ for(size_t bb_idx = 0; bb_idx < exp.blocks.size(); bb_idx ++)
+ {
+ const auto& bb_e = exp.blocks[bb_idx];
+ const auto& bb_h = have.blocks[bb_idx];
+
+ if( bb_e.statements.size() != bb_h.statements.size() ) {
+ std::cerr << path << " BB" << bb_idx << " Mismatch in statement count: exp " << bb_e.statements.size() << " != " << bb_h.statements.size() << std::endl;
+ return false;
+ }
+ for(size_t stmt_idx = 0; stmt_idx < bb_e.statements.size(); stmt_idx ++)
+ {
+ const auto& stmt_e = bb_e.statements[stmt_idx];
+ const auto& stmt_h = bb_h.statements[stmt_idx];
+ if( stmt_e != stmt_h ) {
+ std::cerr << path << " BB" << bb_idx << "/" << stmt_idx << " Mismatched statements: exp " << stmt_e << " != " << stmt_h << std::endl;
+ return false;
+ }
+ }
+
+ if( bb_e.terminator != bb_h.terminator )
+ {
+ std::cerr << path << " BB" << bb_idx << "/TERM Mismatched terminator: exp " << bb_e.terminator << " != " << bb_h.terminator << std::endl;
+ return false;
+ }
+ }
+ std::cerr << path << " EQUAL" << std::endl;
+ return true;
+ }
+} \ No newline at end of file