From 4bcf25a8920a334b88206f9b4f86e9256efbf5c3 Mon Sep 17 00:00:00 2001 From: Richard Diamond Date: Sat, 24 Feb 2018 13:14:57 -0600 Subject: [PATCH] Add Polly support. Use can be triggered via `-Z polly`, when `rustc` uses an LLVM which includes polly. Force LLVM rebuild on buildbots. --- config.toml.example | 8 +++++ src/bootstrap/bin/rustc.rs | 11 +++++- src/bootstrap/bootstrap.py | 4 +++ src/bootstrap/compile.rs | 14 +++++++- src/bootstrap/config.rs | 16 +++++++++ src/bootstrap/test.rs | 3 ++ src/librustc/session/config.rs | 2 ++ src/librustc_llvm/build.rs | 56 +++++++++++++++++++++++++++++++ src/librustc_llvm/ffi.rs | 3 +- src/librustc_trans/back/lto.rs | 2 +- src/librustc_trans/back/write.rs | 22 ++++++++---- src/rustllvm/PassWrapper.cpp | 22 +++++++++++- src/rustllvm/llvm-rebuild-trigger | 2 +- 13 files changed, 152 insertions(+), 13 deletions(-) diff --git a/config.toml.example b/config.toml.example index effe00843810d..020301d1b58d7 100644 --- a/config.toml.example +++ b/config.toml.example @@ -303,6 +303,10 @@ #optimize-tests = true #debuginfo-tests = true +# Flag indicating whether tests are optimized with Polly. If optimize-tests is false, +# polly-tests will be false regardless of its value here. +#polly-tests = false + # Flag indicating whether codegen tests will be run or not. If you get an error # saying that the FileCheck executable is missing, you may want to disable this. #codegen-tests = true @@ -346,6 +350,10 @@ # Whether to deny warnings in crates #deny-warnings = true +# Use Polly on the rust compiler itself. If optimize is false, this will be +# false as well. +#polly-self = false + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index b6ae824c37601..5e2d065bbcfe1 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -91,6 +91,7 @@ fn main() { ("RUSTC_REAL", "RUSTC_LIBDIR") }; let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set"); + let stage = usize::from_str(stage.as_str()).expect("RUSTC_STAGE not a usize"); let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); let on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of)); @@ -152,7 +153,7 @@ fn main() { // workaround undefined references to `rust_eh_unwind_resume` generated // otherwise, see issue https://github.com/rust-lang/rust/issues/43095. if crate_name == "panic_abort" || - crate_name == "compiler_builtins" && stage != "0" { + crate_name == "compiler_builtins" && stage != 0 { cmd.arg("-C").arg("panic=abort"); } @@ -267,6 +268,14 @@ fn main() { cmd.arg("--cfg").arg("parallel_queries"); } + let use_polly = match env::var("RUSTC_USE_POLLY") { + Ok(v) => v != "0", + Err(_) => false, + }; + if use_polly && stage >= 1 { + cmd.arg("-Z").arg("polly"); + } + let color = match env::var("RUSTC_COLOR") { Ok(s) => usize::from_str(&s).expect("RUSTC_COLOR should be an integer"), Err(_) => 0, diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 487440becf630..f5ba263cd1258 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -690,6 +690,10 @@ def update_submodules(self): recorded_submodules[data[3]] = data[2] for module in filtered_submodules: self.update_submodule(module[0], module[1], recorded_submodules) + polly_path = "src/llvm/tools/polly" + if not os.path.exists(os.path.join(self.rust_root, polly_path)): + run(["git", "clone", "https://github.com/llvm-mirror/polly.git", + "src/llvm/tools/polly", "-b", "release_60"]) print("Submodules updated in %.2f seconds" % (time() - start_time)) def set_dev_environment(self): diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 1248c2b50be5e..19b56920f76ba 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -36,7 +36,7 @@ use native; use tool; use cache::{INTERNER, Interned}; -use builder::{Step, RunConfig, ShouldRun, Builder}; +use builder::{Step, RunConfig, ShouldRun, Builder, Kind}; #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] pub struct Std { @@ -553,6 +553,18 @@ pub fn rustc_cargo_env(builder: &Builder, cargo: &mut Command) { if builder.config.rustc_parallel_queries { cargo.env("RUSTC_PARALLEL_QUERIES", "1"); } + + let use_polly = match builder.kind { + Kind::Test | Kind::Check => { + builder.config.rust_polly_tests + }, + _ => builder.config.rust_polly_self + }; + if use_polly { + cargo.env("RUSTC_USE_POLLY", "1"); + } else { + cargo.env("RUSTC_USE_POLLY", "0"); + } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 7175f6a67642b..a1b1ab70b5d2f 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -99,10 +99,12 @@ pub struct Config { pub rustc_parallel_queries: bool, pub rustc_default_linker: Option, pub rust_optimize_tests: bool, + pub rust_polly_tests: bool, pub rust_debuginfo_tests: bool, pub rust_dist_src: bool, pub rust_codegen_backends: Vec>, pub rust_codegen_backends_dir: String, + pub rust_polly_self: bool, pub build: Interned, pub hosts: Vec>, @@ -294,6 +296,7 @@ struct Rust { rpath: Option, optimize_tests: Option, debuginfo_tests: Option, + polly_tests: Option, codegen_tests: Option, ignore_git: Option, debug: Option, @@ -306,6 +309,7 @@ struct Rust { wasm_syscall: Option, lld: Option, deny_warnings: Option, + polly_self: Option, } /// TOML representation of how each build target is configured. @@ -515,6 +519,10 @@ impl Config { ignore_git = rust.ignore_git; debug_jemalloc = rust.debug_jemalloc; set(&mut config.rust_optimize_tests, rust.optimize_tests); + set(&mut config.rust_polly_tests, rust.polly_tests); + if !config.rust_optimize_tests { + config.rust_polly_tests = false; + } set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests); set(&mut config.codegen_tests, rust.codegen_tests); set(&mut config.rust_rpath, rust.rpath); @@ -545,6 +553,10 @@ impl Config { Some(n) => config.rust_codegen_units = Some(n), None => {} } + + config.rust_polly_self = rust + .polly_self + .unwrap_or(false); } if let Some(ref t) = toml.target { @@ -602,6 +614,10 @@ impl Config { config.rust_debug_assertions = debug_assertions.unwrap_or(default); config.rust_optimize = optimize.unwrap_or(!default); + if !config.rust_optimize { + config.rust_polly_self = false; + } + let default = config.channel == "dev"; config.ignore_git = ignore_git.unwrap_or(default); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index e8c40dfdb0ad2..a53f14cf40da7 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -960,6 +960,9 @@ impl Step for Compiletest { } flags.push("-Zunstable-options".to_string()); flags.push(builder.config.cmd.rustc_args().join(" ")); + if builder.config.rust_polly_self { + flags.push("-Zpolly".into()); + } if let Some(linker) = builder.linker(target) { cmd.arg("--linker").arg(linker); diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 59b40e9e2dc56..2a5a4c67a4e80 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1293,6 +1293,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "make the current crate share its generic instantiations"), chalk: bool = (false, parse_bool, [TRACKED], "enable the experimental Chalk-based trait solving engine"), + polly: bool = (false, parse_bool, [UNTRACKED], "Run the Polly polyhedral \ + model optimization passes."), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 1619637b827df..d68b5eb5c9815 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -157,11 +157,53 @@ fn main() { cfg.define("LLVM_RUSTLLVM", None); } + let (enable_polly, polly_link_kind, polly_link_isl) = { + let mut cmd = Command::new(&llvm_config); + cmd.arg("--libdir"); + let libdir = output(&mut cmd); + let libdir = libdir.lines().next().unwrap(); + let libdir = Path::new(&libdir); + assert!(libdir.exists()); + + // We can't specify the full libname to rust, so the linker will always expect (on unix) + // LLVMPolly to be libLLVMPolly, which won't be present. I didn't realize this fact until + // after I wrote the following, but maybe this issue will be resolved in the future. + let allow_shared = false; + let mut found_static = false; + let mut found_shared = false; + for entry in libdir.read_dir().unwrap() { + if let Ok(entry) = entry { + if let Some(name) = entry.path().file_name() { + let name = name.to_str().unwrap(); + if name.contains("Polly") { + if !found_static { + found_static = !name.contains("LLVM"); + } + if !found_shared { + found_shared = name.contains("LLVM"); + } + } + } + } + } + + let found_static = found_static; + let found_shared = allow_shared && found_shared; + let enabled = found_static || found_shared; + let (kind, isl) = match (found_static, found_shared) { + (false, false) => ("", false), + (true, _) => ("static", true), + (false, true) => ("dylib", false), + }; + (enabled, kind, isl) + }; + build_helper::rerun_if_changed_anything_in_dir(Path::new("../rustllvm")); cfg.file("../rustllvm/PassWrapper.cpp") .file("../rustllvm/RustWrapper.cpp") .file("../rustllvm/ArchiveWrapper.cpp") .file("../rustllvm/Linker.cpp") + .define("ENABLE_POLLY", if enable_polly { "1" } else { "0" }) .cpp(true) .cpp_link_stdlib(None) // we handle this below .compile("rustllvm"); @@ -214,6 +256,20 @@ fn main() { println!("cargo:rustc-link-lib={}={}", kind, name); } + if enable_polly { + match polly_link_kind { + "dylib" => { + panic!("dynamically linking polly is not possible :("); + //println!("cargo:rustc-flags=-l:LLVMPolly") + }, + _ => println!("cargo:rustc-link-lib={}=Polly", polly_link_kind), + } + + if polly_link_isl { + println!("cargo:rustc-link-lib={}=PollyISL", polly_link_kind); + } + } + // LLVM ldflags // // If we're a cross-compile of LLVM then unfortunately we can't trust these diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index dba2e918f6f3a..dcbfe52eee1aa 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1642,7 +1642,8 @@ extern "C" { Singlethread: bool) -> TargetMachineRef; pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef); - pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef, PM: PassManagerRef, M: ModuleRef); + pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef, PM: PassManagerRef, M: ModuleRef, + Polly: bool); pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef, M: ModuleRef, DisableSimplifyLibCalls: bool); diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 2a473f1ecbcc5..bbf2fc74a0ac0 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -460,7 +460,7 @@ fn run_pass_manager(cgcx: &CodegenContext, debug!("running the pass manager"); unsafe { let pm = llvm::LLVMCreatePassManager(); - llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod); + llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod, config.polly); let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); assert!(!pass.is_null()); llvm::LLVMRustAddPass(pm, pass); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 148e3d0025c83..c5f2b277bbbc0 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -250,6 +250,7 @@ pub struct ModuleConfig { no_integrated_as: bool, embed_bitcode: bool, embed_bitcode_marker: bool, + pub polly: bool, } impl ModuleConfig { @@ -281,7 +282,8 @@ impl ModuleConfig { vectorize_loop: false, vectorize_slp: false, merge_functions: false, - inline_threshold: None + inline_threshold: None, + polly: false, } } @@ -319,6 +321,8 @@ impl ModuleConfig { self.merge_functions = sess.opts.optimize == config::OptLevel::Default || sess.opts.optimize == config::OptLevel::Aggressive; + self.polly = sess.opts.debugging_opts.polly && !self.no_prepopulate_passes && + !sess.target.target.options.is_like_emscripten; } } @@ -546,8 +550,8 @@ unsafe fn optimize(cgcx: &CodegenContext, if !config.no_verify { assert!(addpass("verify")); } if !config.no_prepopulate_passes { - llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod); - llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod); + llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod, config.polly); + llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod, config.polly); let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); with_llvm_pmb(llmod, &config, opt_level, &mut |b| { llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm); @@ -645,11 +649,12 @@ unsafe fn codegen(cgcx: &CodegenContext, unsafe fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef, no_builtins: bool, + polly: bool, f: F) -> R where F: FnOnce(PassManagerRef) -> R, { let cpm = llvm::LLVMCreatePassManager(); - llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod); + llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod, polly); llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); f(cpm) } @@ -744,7 +749,8 @@ unsafe fn codegen(cgcx: &CodegenContext, cursor.position() as size_t } - with_codegen(tm, llmod, config.no_builtins, |cpm| { + with_codegen(tm, llmod, config.no_builtins, config.polly, + |cpm| { llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback); llvm::LLVMDisposePassManager(cpm); }); @@ -762,7 +768,8 @@ unsafe fn codegen(cgcx: &CodegenContext, } else { llmod }; - with_codegen(tm, llmod, config.no_builtins, |cpm| { + with_codegen(tm, llmod, config.no_builtins, config.polly, + |cpm| { write_output_file(diag_handler, tm, cpm, llmod, &path, llvm::FileType::AssemblyFile) })?; @@ -773,7 +780,8 @@ unsafe fn codegen(cgcx: &CodegenContext, } if write_obj { - with_codegen(tm, llmod, config.no_builtins, |cpm| { + with_codegen(tm, llmod, config.no_builtins, config.polly, + |cpm| { write_output_file(diag_handler, tm, cpm, llmod, &obj_out, llvm::FileType::ObjectFile) })?; diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 382ef2cc407dd..52a16087737d9 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -61,6 +61,13 @@ DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder, LLVMPassManagerBuilderRef) +#if ENABLE_POLLY +namespace polly { +void initializePollyPasses(llvm::PassRegistry &Registry); +void registerPollyPasses(llvm::legacy::PassManagerBase &PM); +} +#endif + extern "C" void LLVMInitializePasses() { PassRegistry &Registry = *PassRegistry::getPassRegistry(); initializeCore(Registry); @@ -73,6 +80,10 @@ extern "C" void LLVMInitializePasses() { initializeInstCombine(Registry); initializeInstrumentation(Registry); initializeTarget(Registry); + +#if ENABLE_POLLY + polly::initializePollyPasses(Registry); +#endif } enum class LLVMRustPassKind { @@ -420,10 +431,19 @@ extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) { // this function. extern "C" void LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM, LLVMPassManagerRef PMR, - LLVMModuleRef M) { + LLVMModuleRef M, + bool Polly) { PassManagerBase *PM = unwrap(PMR); PM->add( createTargetTransformInfoWrapperPass(unwrap(TM)->getTargetIRAnalysis())); + +#if ENABLE_POLLY + if(Polly) { + polly::registerPollyPasses(*PM); + } +#else + (void)Polly; +#endif } extern "C" void LLVMRustConfigurePassManagerBuilder( diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index c3fc3e5452c4f..15ba34c3da429 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2018-04-05 +2018-04-18