From e14cd392a4278223d858451a7b5cae327f76707c Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Sat, 6 Jul 2013 00:44:40 -0700 Subject: [PATCH] initial sketch of codegen mode for compiletest; doesn't measure / compare / ratchet the disassembly yet --- src/compiletest/common.rs | 7 ++ src/compiletest/compiletest.rs | 61 ++++++++++++----- src/compiletest/runtest.rs | 118 ++++++++++++++++++++++++++++++++- 3 files changed, 169 insertions(+), 17 deletions(-) diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs index 38289f62741..df00286c87f 100644 --- a/src/compiletest/common.rs +++ b/src/compiletest/common.rs @@ -15,6 +15,7 @@ pub enum mode { mode_run_pass, mode_pretty, mode_debug_info, + mode_codegen } pub struct config { @@ -27,6 +28,12 @@ pub struct config { // The rustc executable rustc_path: Path, + // The clang executable + clang_path: Option, + + // The llvm binaries path + llvm_bin_path: Option, + // The directory containing the tests to run src_base: Path, diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 7d9a7c3ea75..5d3f81fd884 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -19,6 +19,7 @@ extern mod extra; use std::os; use extra::getopts; +use extra::getopts::groups::{optopt, optflag, reqopt}; use extra::test; use common::config; @@ -27,6 +28,7 @@ use common::mode_run_fail; use common::mode_compile_fail; use common::mode_pretty; use common::mode_debug_info; +use common::mode_codegen; use common::mode; use util::logv; @@ -45,31 +47,54 @@ pub fn main() { } pub fn parse_config(args: ~[~str]) -> config { - let opts = - ~[getopts::reqopt("compile-lib-path"), - getopts::reqopt("run-lib-path"), - getopts::reqopt("rustc-path"), getopts::reqopt("src-base"), - getopts::reqopt("build-base"), getopts::reqopt("aux-base"), - getopts::reqopt("stage-id"), - getopts::reqopt("mode"), getopts::optflag("ignored"), - getopts::optopt("runtool"), getopts::optopt("rustcflags"), - getopts::optflag("verbose"), - getopts::optopt("logfile"), - getopts::optflag("jit"), - getopts::optflag("newrt"), - getopts::optopt("target"), - getopts::optopt("adb-path"), - getopts::optopt("adb-test-dir") + + let groups : ~[getopts::groups::OptGroup] = + ~[reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"), + reqopt("", "run-lib-path", "path to target shared libraries", "PATH"), + reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"), + optopt("", "clang-path", "path to executable for codegen tests", "PATH"), + optopt("", "llvm-bin-path", "path to directory holding llvm binaries", "DIR"), + reqopt("", "src-base", "directory to scan for test files", "PATH"), + reqopt("", "build-base", "directory to deposit test outputs", "PATH"), + reqopt("", "aux-base", "directory to find auxiliary test files", "PATH"), + reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"), + reqopt("", "mode", "which sort of compile tests to run", + "(compile-fail|run-fail|run-pass|pretty|debug-info)"), + optflag("", "ignored", "run tests marked as ignored / xfailed"), + optopt("", "runtool", "supervisor program to run tests under \ + (eg. emulator, valgrind)", "PROGRAM"), + optopt("", "rustcflags", "flags to pass to rustc", "FLAGS"), + optflag("", "verbose", "run tests verbosely, showing all output"), + optopt("", "logfile", "file to log test execution to", "FILE"), + optflag("", "jit", "run tests under the JIT"), + optflag("", "newrt", "run tests on the new runtime / scheduler"), + optopt("", "target", "the target to build for", "TARGET"), + optopt("", "adb-path", "path to the android debugger", "PATH"), + optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"), + optflag("h", "help", "show this message"), ]; assert!(!args.is_empty()); + let argv0 = copy args[0]; let args_ = args.tail(); + if args[1] == ~"-h" || args[1] == ~"--help" { + let message = fmt!("Usage: %s [OPTIONS] [TESTNAME...]", argv0); + io::println(getopts::groups::usage(message, groups)); + fail!() + } + let matches = - &match getopts::getopts(args_, opts) { + &match getopts::groups::getopts(args_, groups) { Ok(m) => m, Err(f) => fail!(getopts::fail_str(f)) }; + if getopts::opt_present(matches, "h") || getopts::opt_present(matches, "help") { + let message = fmt!("Usage: %s [OPTIONS] [TESTNAME...]", argv0); + io::println(getopts::groups::usage(message, groups)); + fail!() + } + fn opt_path(m: &getopts::Matches, nm: &str) -> Path { Path(getopts::opt_str(m, nm)) } @@ -78,6 +103,8 @@ pub fn parse_config(args: ~[~str]) -> config { compile_lib_path: getopts::opt_str(matches, "compile-lib-path"), run_lib_path: getopts::opt_str(matches, "run-lib-path"), rustc_path: opt_path(matches, "rustc-path"), + clang_path: getopts::opt_maybe_str(matches, "clang-path").map(|s| Path(*s)), + llvm_bin_path: getopts::opt_maybe_str(matches, "llvm-bin-path").map(|s| Path(*s)), src_base: opt_path(matches, "src-base"), build_base: opt_path(matches, "build-base"), aux_base: opt_path(matches, "aux-base"), @@ -159,6 +186,7 @@ pub fn str_mode(s: ~str) -> mode { ~"run-pass" => mode_run_pass, ~"pretty" => mode_pretty, ~"debug-info" => mode_debug_info, + ~"codegen" => mode_codegen, _ => fail!("invalid mode") } } @@ -170,6 +198,7 @@ pub fn mode_str(mode: mode) -> ~str { mode_run_pass => ~"run-pass", mode_pretty => ~"pretty", mode_debug_info => ~"debug-info", + mode_codegen => ~"codegen", } } diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 91016ba91fa..dee07c6de49 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -39,7 +39,8 @@ pub fn run(config: config, testfile: ~str) { mode_run_fail => run_rfail_test(&config, &props, &testfile), mode_run_pass => run_rpass_test(&config, &props, &testfile), mode_pretty => run_pretty_test(&config, &props, &testfile), - mode_debug_info => run_debuginfo_test(&config, &props, &testfile) + mode_debug_info => run_debuginfo_test(&config, &props, &testfile), + mode_codegen => run_codegen_test(&config, &props, &testfile) } } @@ -835,3 +836,118 @@ fn _arm_push_aux_shared_library(config: &config, testfile: &Path) { } } } + +// codegen tests (vs. clang) + +fn make_o_name(config: &config, testfile: &Path) -> Path { + output_base_name(config, testfile).with_filetype("o") +} + +fn append_suffix_to_stem(p: &Path, suffix: &str) -> Path { + if suffix.len() == 0 { + copy *p + } else { + let stem = p.filestem().get(); + p.with_filestem(stem + "-" + suffix) + } +} + +fn compile_test_and_save_bitcode(config: &config, props: &TestProps, + testfile: &Path) -> ProcRes { + let link_args = ~[~"-L", aux_output_dir_name(config, testfile).to_str()]; + let llvm_args = ~[~"-c", ~"--lib", ~"--save-temps"]; + let args = make_compile_args(config, props, + link_args + llvm_args, + make_o_name, testfile); + compose_and_run_compiler(config, props, testfile, args, None) +} + +fn compile_cc_with_clang_and_save_bitcode(config: &config, _props: &TestProps, + testfile: &Path) -> ProcRes { + let bitcodefile = output_base_name(config, testfile).with_filetype("bc"); + let bitcodefile = append_suffix_to_stem(&bitcodefile, "clang"); + let ProcArgs = ProcArgs { + prog: config.clang_path.get_ref().to_str(), + args: ~[~"-c", + ~"-emit-llvm", + ~"-o", bitcodefile.to_str(), + testfile.with_filetype("cc").to_str() ] + }; + compose_and_run(config, testfile, ProcArgs, ~[], "", None) +} + +fn extract_function_from_bitcode(config: &config, _props: &TestProps, + fname: &str, testfile: &Path, + suffix: &str) -> ProcRes { + let bitcodefile = output_base_name(config, testfile).with_filetype("bc"); + let bitcodefile = append_suffix_to_stem(&bitcodefile, suffix); + let extracted_bc = append_suffix_to_stem(&bitcodefile, "extract"); + let ProcArgs = ProcArgs { + prog: config.llvm_bin_path.get_ref().push("llvm-extract").to_str(), + args: ~[~"-func=" + fname, + ~"-o=" + extracted_bc.to_str(), + bitcodefile.to_str() ] + }; + compose_and_run(config, testfile, ProcArgs, ~[], "", None) +} + +fn disassemble_extract(config: &config, _props: &TestProps, + testfile: &Path, suffix: &str) -> ProcRes { + let bitcodefile = output_base_name(config, testfile).with_filetype("bc"); + let bitcodefile = append_suffix_to_stem(&bitcodefile, suffix); + let extracted_bc = append_suffix_to_stem(&bitcodefile, "extract"); + let extracted_ll = extracted_bc.with_filetype("ll"); + let ProcArgs = ProcArgs { + prog: config.llvm_bin_path.get_ref().push("llvm-dis").to_str(), + args: ~[~"-o=" + extracted_ll.to_str(), + extracted_bc.to_str() ] + }; + compose_and_run(config, testfile, ProcArgs, ~[], "", None) +} + + +fn run_codegen_test(config: &config, props: &TestProps, testfile: &Path) { + + if config.llvm_bin_path.is_none() { + fatal(~"missing --llvm-bin-path"); + } + + if config.clang_path.is_none() { + fatal(~"missing --clang-path"); + } + + let mut ProcRes = compile_test_and_save_bitcode(config, props, testfile); + if ProcRes.status != 0 { + fatal_ProcRes(~"compilation failed!", &ProcRes); + } + + ProcRes = extract_function_from_bitcode(config, props, "test", testfile, ""); + if ProcRes.status != 0 { + fatal_ProcRes(~"extracting 'test' function failed", &ProcRes); + } + + ProcRes = disassemble_extract(config, props, testfile, ""); + if ProcRes.status != 0 { + fatal_ProcRes(~"disassembling extract failed", &ProcRes); + } + + + let mut ProcRes = compile_cc_with_clang_and_save_bitcode(config, props, testfile); + if ProcRes.status != 0 { + fatal_ProcRes(~"compilation failed!", &ProcRes); + } + + ProcRes = extract_function_from_bitcode(config, props, "test", testfile, "clang"); + if ProcRes.status != 0 { + fatal_ProcRes(~"extracting 'test' function failed", &ProcRes); + } + + ProcRes = disassemble_extract(config, props, testfile, "clang"); + if ProcRes.status != 0 { + fatal_ProcRes(~"disassembling extract failed", &ProcRes); + } + + + +} +