From ffa4d7e87f7565177693eefb4650bb32c3498968 Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Wed, 7 Aug 2019 09:30:16 -0700 Subject: [PATCH 1/4] Sort the fat LTO modules to produce deterministic output. --- src/librustc_codegen_ssa/back/write.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index c9e4663fdbddf..2bd46b9f6efee 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -755,6 +755,15 @@ pub enum FatLTOInput { InMemory(ModuleCodegen), } +impl FatLTOInput { + fn name(&'a self) -> &'a String { + match self { + FatLTOInput::Serialized { name, buffer: _ } => &name, + FatLTOInput::InMemory(module) => &module.name, + } + } +} + fn execute_work_item( cgcx: &CodegenContext, work_item: WorkItem, @@ -1345,10 +1354,15 @@ fn start_executing_work( assert!(!started_lto); started_lto = true; - let needs_fat_lto = mem::take(&mut needs_fat_lto); + let mut needs_fat_lto: Vec> = mem::take(&mut needs_fat_lto); let needs_thin_lto = mem::take(&mut needs_thin_lto); let import_only_modules = mem::take(&mut lto_import_only_modules); + // Regardless of what order these modules completed in, report them to + // the backend in the same order every time to ensure that we're handing + // out deterministic results. + needs_fat_lto.sort_by(|m1, m2| m1.name().cmp(m2.name())); + for (work, cost) in generate_lto_work(&cgcx, needs_fat_lto, needs_thin_lto, import_only_modules) { let insertion_index = work_items From 5b2c5e181ac321f04621ef0b7dc78354bf3397d3 Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Thu, 8 Aug 2019 07:54:27 -0700 Subject: [PATCH 2/4] Sort fat LTO modules later and add a test. --- src/librustc_codegen_llvm/back/lto.rs | 6 ++++-- src/librustc_codegen_ssa/back/write.rs | 16 +--------------- .../reproducible-build/Makefile | 11 ++++++++++- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 5d3cc0c0a255f..33b4c8eec54ce 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -265,7 +265,7 @@ fn fat_lto(cgcx: &CodegenContext, // and we want to move everything to the same LLVM context. Currently the // way we know of to do that is to serialize them to a string and them parse // them later. Not great but hey, that's why it's "fat" LTO, right? - serialized_modules.extend(modules.into_iter().map(|module| { + let mut new_modules = modules.into_iter().map(|module| { match module { FatLTOInput::InMemory(module) => { let buffer = ModuleBuffer::new(module.module_llvm.llmod()); @@ -277,7 +277,9 @@ fn fat_lto(cgcx: &CodegenContext, (SerializedModule::Local(buffer), llmod_id) } } - })); + }).collect::>(); + new_modules.sort_by(|module1, module2| module1.1.partial_cmp(&module2.1).unwrap()); + serialized_modules.extend(new_modules); serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| { (buffer, CString::new(wp.cgu_name).unwrap()) })); diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 2bd46b9f6efee..c9e4663fdbddf 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -755,15 +755,6 @@ pub enum FatLTOInput { InMemory(ModuleCodegen), } -impl FatLTOInput { - fn name(&'a self) -> &'a String { - match self { - FatLTOInput::Serialized { name, buffer: _ } => &name, - FatLTOInput::InMemory(module) => &module.name, - } - } -} - fn execute_work_item( cgcx: &CodegenContext, work_item: WorkItem, @@ -1354,15 +1345,10 @@ fn start_executing_work( assert!(!started_lto); started_lto = true; - let mut needs_fat_lto: Vec> = mem::take(&mut needs_fat_lto); + let needs_fat_lto = mem::take(&mut needs_fat_lto); let needs_thin_lto = mem::take(&mut needs_thin_lto); let import_only_modules = mem::take(&mut lto_import_only_modules); - // Regardless of what order these modules completed in, report them to - // the backend in the same order every time to ensure that we're handing - // out deterministic results. - needs_fat_lto.sort_by(|m1, m2| m1.name().cmp(m2.name())); - for (work, cost) in generate_lto_work(&cgcx, needs_fat_lto, needs_thin_lto, import_only_modules) { let insertion_index = work_items diff --git a/src/test/run-make-fulldeps/reproducible-build/Makefile b/src/test/run-make-fulldeps/reproducible-build/Makefile index a17ec212cfd58..5b9c9d3d03521 100644 --- a/src/test/run-make-fulldeps/reproducible-build/Makefile +++ b/src/test/run-make-fulldeps/reproducible-build/Makefile @@ -10,7 +10,8 @@ all: \ link_paths \ remap_paths \ different_source_dirs \ - extern_flags + extern_flags \ + fat_lto smoke: rm -rf $(TMPDIR) && mkdir $(TMPDIR) @@ -76,3 +77,11 @@ extern_flags: --extern reproducible_build_aux=$(TMPDIR)/libbar.rlib \ --crate-type rlib cmp "$(TMPDIR)/libreproducible_build.rlib" "$(TMPDIR)/libfoo.rlib" || exit 1 + +fat_lto: + rm -rf $(TMPDIR) && mkdir $(TMPDIR) + $(RUSTC) reproducible-build-aux.rs + $(RUSTC) reproducible-build.rs -C lto=fat + cp $(TMPDIR)/reproducible-build $(TMPDIR)/reproducible-build-a + $(RUSTC) reproducible-build.rs -C lto=fat + cmp "$(TMPDIR)/reproducible-build-a" "$(TMPDIR)/reproducible-build" || exit 1 From a46e36f9df68f9c59157ccc3c1519413802993b5 Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Thu, 8 Aug 2019 09:05:32 -0700 Subject: [PATCH 3/4] Fix fat LTO determinism test so it fails without the fix. --- src/test/run-make-fulldeps/reproducible-build/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/run-make-fulldeps/reproducible-build/Makefile b/src/test/run-make-fulldeps/reproducible-build/Makefile index 5b9c9d3d03521..addbf9928bf4a 100644 --- a/src/test/run-make-fulldeps/reproducible-build/Makefile +++ b/src/test/run-make-fulldeps/reproducible-build/Makefile @@ -81,7 +81,7 @@ extern_flags: fat_lto: rm -rf $(TMPDIR) && mkdir $(TMPDIR) $(RUSTC) reproducible-build-aux.rs - $(RUSTC) reproducible-build.rs -C lto=fat + $(RUSTC) reproducible-build.rs -C lto=fat -C opt-level=1 cp $(TMPDIR)/reproducible-build $(TMPDIR)/reproducible-build-a - $(RUSTC) reproducible-build.rs -C lto=fat + $(RUSTC) reproducible-build.rs -C lto=fat -C opt-level=1 cmp "$(TMPDIR)/reproducible-build-a" "$(TMPDIR)/reproducible-build" || exit 1 From 3e6a9273057aec611b9f22025bb28355060af265 Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Thu, 8 Aug 2019 10:51:52 -0700 Subject: [PATCH 4/4] Explain why we're sorting the modules. --- src/librustc_codegen_llvm/back/lto.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 33b4c8eec54ce..5ed08943fe6fd 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -278,6 +278,7 @@ fn fat_lto(cgcx: &CodegenContext, } } }).collect::>(); + // Sort the modules to ensure we produce deterministic results. new_modules.sort_by(|module1, module2| module1.1.partial_cmp(&module2.1).unwrap()); serialized_modules.extend(new_modules); serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| {