Skip to content

Commit b90aa66

Browse files
committed
Fix emitting asm and object file output at the same time
The LLVM function to output file types that involve codegen can invalidate the IR while lowering. That means that the second time the IR is fed to those passes, it's invalid and the LLVM verifier complains. To workaround this, we can tell the function to skip the codegen passes the second time around. To do this, we tell it to start adding passes only after it has seen a pass that doesn't exist at all. Quite the hack, I know... Fixes rust-lang#24876
1 parent bf7eec0 commit b90aa66

File tree

5 files changed

+48
-5
lines changed

5 files changed

+48
-5
lines changed

src/librustc_llvm/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2066,6 +2066,7 @@ extern {
20662066
PM: PassManagerRef,
20672067
M: ModuleRef,
20682068
Output: *const c_char,
2069+
skip_codegen: bool,
20692070
FileType: FileType) -> bool;
20702071
pub fn LLVMRustPrintModule(PM: PassManagerRef,
20712072
M: ModuleRef,

src/librustc_trans/back/write.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,12 @@ pub fn write_output_file(
5656
pm: llvm::PassManagerRef,
5757
m: ModuleRef,
5858
output: &Path,
59+
skip_codegen: bool,
5960
file_type: llvm::FileType) {
6061
unsafe {
6162
let output_c = path2cstr(output);
6263
let result = llvm::LLVMRustWriteOutputFile(
63-
target, pm, m, output_c.as_ptr(), file_type);
64+
target, pm, m, output_c.as_ptr(), skip_codegen, file_type);
6465
if !result {
6566
llvm_err(handler, format!("could not write output to {}", output.display()));
6667
}
@@ -543,15 +544,19 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
543544
if config.emit_asm {
544545
let path = output_names.with_extension(&format!("{}.s", name_extra));
545546
with_codegen(tm, llmod, config.no_builtins, |cpm| {
546-
write_output_file(cgcx.handler, tm, cpm, llmod, &path,
547+
write_output_file(cgcx.handler, tm, cpm, llmod, &path, false,
547548
llvm::AssemblyFileType);
548549
});
549550
}
550551

551552
if config.emit_obj {
553+
// If we already emitted asm code, the codegen has already been done for this module,
554+
// so don't do it again. See LLVMRustWriteOutputFile for details.
555+
let skip_codegen = config.emit_asm;
552556
let path = output_names.with_extension(&format!("{}.o", name_extra));
553557
with_codegen(tm, llmod, config.no_builtins, |cpm| {
554-
write_output_file(cgcx.handler, tm, cpm, llmod, &path, llvm::ObjectFileType);
558+
write_output_file(cgcx.handler, tm, cpm, llmod, &path, skip_codegen,
559+
llvm::ObjectFileType);
555560
});
556561
}
557562
});

src/rustllvm/PassWrapper.cpp

+13-2
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target,
227227
LLVMPassManagerRef PMR,
228228
LLVMModuleRef M,
229229
const char *path,
230+
bool skipCodegen,
230231
TargetMachine::CodeGenFileType FileType) {
231232
PassManager *PM = unwrap<PassManager>(PMR);
232233

@@ -244,11 +245,21 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target,
244245
return false;
245246
}
246247

248+
// HACK: addPassesToEmitFile() also adds some codegen passes which are
249+
// MachinePasses that may modify IR in a way that it becomes invalid (we've
250+
// seen this with stack coloring). So the IR verifier would abort. Therefore,
251+
// when we want to emit more than one filetype in a single run, we want to
252+
// run the codegen passes and the verifier only for the first filetype.
253+
// Telling LLVM to only start adding passes after it has seen a pass that
254+
// doesn't exist allows us to achieve that.
255+
char notAPass;
256+
AnalysisID startBefore = skipCodegen ? (AnalysisID)&notAPass : nullptr;
257+
247258
#if LLVM_VERSION_MINOR >= 7
248-
unwrap(Target)->addPassesToEmitFile(*PM, OS, FileType, false);
259+
unwrap(Target)->addPassesToEmitFile(*PM, OS, FileType, false, startBefore);
249260
#else
250261
formatted_raw_ostream FOS(OS);
251-
unwrap(Target)->addPassesToEmitFile(*PM, FOS, FileType, false);
262+
unwrap(Target)->addPassesToEmitFile(*PM, FOS, FileType, false, startBefore);
252263
#endif
253264
PM->run(*unwrap(M));
254265

src/test/run-make/emit/Makefile

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-include ../tools.mk
2+
3+
all:
4+
$(RUSTC) -Copt-level=0 --emit=llvm-bc,llvm-ir,asm,obj,link test.rs
5+
$(RUSTC) -Copt-level=1 --emit=llvm-bc,llvm-ir,asm,obj,link test.rs
6+
$(RUSTC) -Copt-level=2 --emit=llvm-bc,llvm-ir,asm,obj,link test.rs
7+
$(RUSTC) -Copt-level=3 --emit=llvm-bc,llvm-ir,asm,obj,link test.rs

src/test/run-make/emit/test.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Checks for issue #24876
12+
13+
fn main() {
14+
let mut v = 0;
15+
for i in 0..0 {
16+
v += i;
17+
}
18+
println!("{}", v)
19+
}

0 commit comments

Comments
 (0)