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<String>,
     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<Interned<String>>,
     pub rust_codegen_backends_dir: String,
+    pub rust_polly_self: bool,
 
     pub build: Interned<String>,
     pub hosts: Vec<Interned<String>>,
@@ -294,6 +296,7 @@ struct Rust {
     rpath: Option<bool>,
     optimize_tests: Option<bool>,
     debuginfo_tests: Option<bool>,
+    polly_tests: Option<bool>,
     codegen_tests: Option<bool>,
     ignore_git: Option<bool>,
     debug: Option<bool>,
@@ -306,6 +309,7 @@ struct Rust {
     wasm_syscall: Option<bool>,
     lld: Option<bool>,
     deny_warnings: Option<bool>,
+    polly_self: Option<bool>,
 }
 
 /// 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<F, R>(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