diff --git a/.gitmodules b/.gitmodules index 038237aa179a9..01265d4f25cd7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -64,4 +64,7 @@ path = src/tools/clang url = https://github.com/rust-lang-nursery/clang.git branch = rust-release-80-v1 - \ No newline at end of file +[submodule "src/polly"] + path = src/polly + url = https://github.com/llvm-mirror/polly.git + branch = master diff --git a/config.toml.example b/config.toml.example index 1c851999130a0..34016a4f17681 100644 --- a/config.toml.example +++ b/config.toml.example @@ -337,6 +337,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. # Also see the target's llvm-filecheck option. @@ -395,6 +399,10 @@ # Whether to verify generated LLVM IR #verify-llvm-ir = false +# Use Polly on the rust compiler itself. If optimize is false, this will be +# false as well. +#polly-self = false + # Map all debuginfo paths for libstd and crates to `/rust/$sha/$crate/...`, # generally only set for releases #remap-debuginfo = false diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index b6764c1aaeab6..fabd2bc9b00cb 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)); @@ -159,7 +160,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"); } @@ -287,6 +288,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"); + } + if env::var_os("RUSTC_DENY_WARNINGS").is_some() && env::var_os("RUSTC_EXTERNAL_TOOL").is_none() { cmd.arg("-Dwarnings"); diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index aa4e44df2ef94..dc945d2812f81 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1116,6 +1116,18 @@ impl<'a> Builder<'a> { cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1"); } + let use_polly = match cmd { + "test" | "bench" => { + self.config.rust_polly_tests + }, + _ => self.config.rust_polly_self + }; + if use_polly && stage > 1 { + cargo.env("RUSTC_USE_POLLY", "1"); + } else { + cargo.env("RUSTC_USE_POLLY", "0"); + } + for _ in 1..self.verbosity { cargo.arg("-v"); } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index a5ed096a73581..702bbec605ba5 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -104,12 +104,14 @@ 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_verify_llvm_ir: bool, pub rust_remap_debuginfo: bool, + pub rust_polly_self: bool, pub build: Interned, pub hosts: Vec>, @@ -309,6 +311,7 @@ struct Rust { rpath: Option, optimize_tests: Option, debuginfo_tests: Option, + polly_tests: Option, codegen_tests: Option, ignore_git: Option, debug: Option, @@ -327,6 +330,7 @@ struct Rust { backtrace_on_ice: Option, verify_llvm_ir: Option, remap_debuginfo: Option, + polly_self: Option, } /// TOML representation of how each build target is configured. @@ -541,6 +545,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); @@ -580,6 +588,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 { @@ -644,6 +656,10 @@ impl Config { config.rust_debuginfo = debuginfo.unwrap_or(default); config.rust_debug_assertions = debug_assertions.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/native.rs b/src/bootstrap/native.rs index 424264647f0be..e40a08a808a35 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -148,13 +148,17 @@ impl Step for Llvm { .define("LLVM_INCLUDE_DOCS", "OFF") .define("LLVM_INCLUDE_BENCHMARKS", "OFF") .define("LLVM_ENABLE_ZLIB", "OFF") - .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string()) .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); + if !self.emscripten { + let polly_src = builder.src.join("src/polly"); + cfg.define("LLVM_EXTERNAL_POLLY_SOURCE_DIR", polly_src); + } + if builder.config.llvm_thin_lto && !emscripten { cfg.define("LLVM_ENABLE_LTO", "Thin") .define("LLVM_ENABLE_LLD", "ON"); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 80c89b9ff3826..61e1a3c3c8d29 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1045,6 +1045,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/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index 8a84e47468744..97d6735520e73 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -86,6 +86,10 @@ RUN ./build-headers.sh COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +# Polly needs `PATH_MAX` +ENV CFLAGS="-DPATH_MAX=4096 ${CFLAGS}" +ENV CXXFLAGS="-DPATH_MAX=4096 ${CXXFLAGS}" + ENV HOSTS=i686-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index 7e3cc10b0c10c..01f2fe6de684d 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -86,6 +86,10 @@ RUN ./build-headers.sh COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +# Polly needs `PATH_MAX` +ENV CFLAGS="-DPATH_MAX=4096 ${CFLAGS}" +ENV CXXFLAGS="-DPATH_MAX=4096 ${CXXFLAGS}" + ENV HOSTS=x86_64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 569e7a24d2353..1d7adb0276727 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1382,6 +1382,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "run the self profiler"), profile_json: bool = (false, parse_bool, [UNTRACKED], "output a json file with profiler results"), + polly: bool = (false, parse_bool, [UNTRACKED], "Run the Polly polyhedral \ + model optimization passes."), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emits a section containing stack size metadata"), plt: Option = (None, parse_opt_bool, [TRACKED], diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 3ac22f4eaef65..36ec2902dec5d 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -569,7 +569,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); if config.verify_llvm_ir { let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 95281e2445a1c..c2f50c09e6f6c 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -265,6 +265,7 @@ pub struct ModuleConfig { no_integrated_as: bool, embed_bitcode: bool, embed_bitcode_marker: bool, + pub polly: bool, } impl ModuleConfig { @@ -297,7 +298,8 @@ impl ModuleConfig { vectorize_loop: false, vectorize_slp: false, merge_functions: false, - inline_threshold: None + inline_threshold: None, + polly: false, } } @@ -336,6 +338,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; } } @@ -568,8 +572,8 @@ unsafe fn optimize(cgcx: &CodegenContext, || config.obj_is_bitcode || config.emit_bc_compressed || config.embed_bitcode); let mut have_name_anon_globals_pass = false; 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); let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal || (cgcx.lto != Lto::Fat && cgcx.opts.debugging_opts.cross_lang_lto.enabled()); @@ -702,11 +706,12 @@ unsafe fn codegen(cgcx: &CodegenContext, unsafe fn with_codegen<'ll, F, R>(tm: &'ll llvm::TargetMachine, llmod: &'ll llvm::Module, no_builtins: bool, + polly: bool, f: F) -> R where F: FnOnce(&'ll mut PassManager<'ll>) -> R, { let cpm = llvm::LLVMCreatePassManager(); - llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod); + llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod, polly); llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); f(cpm) } @@ -801,7 +806,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); }); @@ -819,7 +825,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) })?; @@ -827,7 +834,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) })?; @@ -2221,7 +2229,8 @@ pub unsafe fn with_llvm_pmb(llmod: &llvm::Module, llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1); } - llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins); + llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins, + config.polly); // Here we match what clang does (kinda). For O0 we only inline // always-inline functions (but don't add lifetime intrinsics), at O1 we diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 0b98fa4eaf551..a2ae8fe933fbb 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -1470,10 +1470,12 @@ extern "C" { EmitStackSizeSection: bool) -> Option<&'static mut TargetMachine>; pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine); - pub fn LLVMRustAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>, M: &'a Module); + pub fn LLVMRustAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>, M: &'a Module, + Polly: bool); pub fn LLVMRustAddBuilderLibraryInfo(PMB: &'a PassManagerBuilder, M: &'a Module, - DisableSimplifyLibCalls: bool); + DisableSimplifyLibCalls: bool, + Polly: bool); pub fn LLVMRustConfigurePassManagerBuilder(PMB: &PassManagerBuilder, OptLevel: CodeGenOptLevel, MergeFunctions: bool, diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 7d01ed556c8dd..b4ecdd810673c 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -161,11 +161,54 @@ 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 = !cfg!(feature = "emscripten") && + (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"); @@ -218,6 +261,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/polly b/src/polly new file mode 160000 index 0000000000000..d3b94f9cfab9e --- /dev/null +++ b/src/polly @@ -0,0 +1 @@ +Subproject commit d3b94f9cfab9ee0710cd624388181ed7bd067c00 diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 06f75d981e3d6..486d3f17f2c90 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 { @@ -434,10 +445,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/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index c4bd0bbd03ca3..fd6a2290f791a 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -78,6 +78,7 @@ fn filter_dirs(path: &Path) -> bool { "src/tools/lldb", "src/target", "src/stdsimd", + "src/polly", ]; skip.iter().any(|p| path.ends_with(p)) }