Skip to content

Commit f9d4149

Browse files
committed
rustc: Update LLVM
This commit updates the LLVM submodule in use to the current HEAD of the LLVM repository. This is primarily being done to start picking up unwinding support for MSVC, which is currently unimplemented in the revision of LLVM we are using. Along the way a few changes had to be made: * As usual, lots of C++ debuginfo bindings in LLVM changed, so there were some significant changes to our RustWrapper.cpp * As usual, some pass management changed in LLVM, so clang was re-scrutinized to ensure that we're doing the same thing as clang. * Some optimization options are now passed directly into the `PassManagerBuilder` instead of through CLI switches to LLVM. * The `NoFramePointerElim` option was removed from LLVM, favoring instead the `no-frame-pointer-elim` function attribute instead. Additionally, LLVM has picked up some new optimizations which required fixing an existing soundness hole in the IR we generate. It appears that the current LLVM we use does not expose this hole. When an enum is moved, the previous slot in memory is overwritten with a bit pattern corresponding to "dropped". When the drop glue for this slot is run, however, the switch on the discriminant can often start executing the `unreachable` block of the switch due to the discriminant now being outside the normal range. This was patched over locally for now by having the `unreachable` block just change to a `ret void`.
1 parent 71a8d31 commit f9d4149

17 files changed

+302
-109
lines changed

src/librustc_llvm/lib.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,9 @@ extern {
976976
pub fn LLVMAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: uint64_t);
977977
pub fn LLVMAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: uint64_t);
978978
pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char);
979+
pub fn LLVMAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint,
980+
Name: *const c_char,
981+
Value: *const c_char);
979982
pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char);
980983
pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong;
981984
pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_ulonglong);
@@ -1920,6 +1923,7 @@ extern {
19201923
VarInfo: DIVariable,
19211924
AddrOps: *const i64,
19221925
AddrOpsCount: c_uint,
1926+
DL: ValueRef,
19231927
InsertAtEnd: BasicBlockRef)
19241928
-> ValueRef;
19251929

@@ -1928,6 +1932,7 @@ extern {
19281932
VarInfo: DIVariable,
19291933
AddrOps: *const i64,
19301934
AddrOpsCount: c_uint,
1935+
DL: ValueRef,
19311936
InsertBefore: ValueRef)
19321937
-> ValueRef;
19331938

@@ -2035,7 +2040,6 @@ extern {
20352040
Level: CodeGenOptLevel,
20362041
EnableSegstk: bool,
20372042
UseSoftFP: bool,
2038-
NoFramePointerElim: bool,
20392043
PositionIndependentExecutable: bool,
20402044
FunctionSections: bool,
20412045
DataSections: bool) -> TargetMachineRef;
@@ -2046,6 +2050,11 @@ extern {
20462050
pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef,
20472051
M: ModuleRef,
20482052
DisableSimplifyLibCalls: bool);
2053+
pub fn LLVMRustConfigurePassManagerBuilder(PMB: PassManagerBuilderRef,
2054+
OptLevel: CodeGenOptLevel,
2055+
MergeFunctions: bool,
2056+
SLPVectorize: bool,
2057+
LoopVectorize: bool);
20492058
pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef,
20502059
DisableSimplifyLibCalls: bool);
20512060
pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef);
@@ -2116,6 +2125,12 @@ extern {
21162125
pub fn LLVMWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef);
21172126
}
21182127

2128+
// LLVM requires symbols from this library, but apparently they're not printed
2129+
// during llvm-config?
2130+
#[cfg(windows)]
2131+
#[link(name = "ole32")]
2132+
extern {}
2133+
21192134
pub fn SetInstructionCallConv(instr: ValueRef, cc: CallConv) {
21202135
unsafe {
21212136
LLVMSetInstructionCallConv(instr, cc as c_uint);

src/librustc_trans/back/write.rs

+47-44
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use back::lto;
1212
use back::link::{get_cc_prog, remove};
13-
use session::config::{OutputFilenames, NoDebugInfo, Passes, SomePasses, AllPasses};
13+
use session::config::{OutputFilenames, Passes, SomePasses, AllPasses};
1414
use session::Session;
1515
use session::config;
1616
use llvm;
@@ -188,10 +188,6 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef {
188188
let opt_level = get_llvm_opt_level(sess.opts.optimize);
189189
let use_softfp = sess.opts.cg.soft_float;
190190

191-
// FIXME: #11906: Omitting frame pointers breaks retrieving the value of a parameter.
192-
let no_fp_elim = (sess.opts.debuginfo != NoDebugInfo) ||
193-
!sess.target.target.options.eliminate_frame_pointer;
194-
195191
let any_library = sess.crate_types.borrow().iter().any(|ty| {
196192
*ty != config::CrateTypeExecutable
197193
});
@@ -237,7 +233,6 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef {
237233
opt_level,
238234
true /* EnableSegstk */,
239235
use_softfp,
240-
no_fp_elim,
241236
!any_library && reloc_model == llvm::RelocPIC,
242237
ffunction_sections,
243238
fdata_sections,
@@ -279,6 +274,9 @@ struct ModuleConfig {
279274
no_prepopulate_passes: bool,
280275
no_builtins: bool,
281276
time_passes: bool,
277+
vectorize_loop: bool,
278+
vectorize_slp: bool,
279+
merge_functions: bool,
282280
}
283281

284282
unsafe impl Send for ModuleConfig { }
@@ -301,6 +299,9 @@ impl ModuleConfig {
301299
no_prepopulate_passes: false,
302300
no_builtins: false,
303301
time_passes: false,
302+
vectorize_loop: false,
303+
vectorize_slp: false,
304+
merge_functions: false,
304305
}
305306
}
306307

@@ -309,6 +310,18 @@ impl ModuleConfig {
309310
self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes;
310311
self.no_builtins = trans.no_builtins;
311312
self.time_passes = sess.time_passes();
313+
314+
// Copy what clang does by turning on loop vectorization at O2 and
315+
// slp vectorization at O3. Otherwise configure other optimization aspects
316+
// of this pass manager builder.
317+
self.vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
318+
(sess.opts.optimize == config::Default ||
319+
sess.opts.optimize == config::Aggressive);
320+
self.vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
321+
sess.opts.optimize == config::Aggressive;
322+
323+
self.merge_functions = sess.opts.optimize == config::Default ||
324+
sess.opts.optimize == config::Aggressive;
312325
}
313326
}
314327

@@ -448,27 +461,26 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
448461
let pass = CString::new(pass).unwrap();
449462
llvm::LLVMRustAddPass(fpm, pass.as_ptr())
450463
};
451-
if !config.no_verify { assert!(addpass("verify")); }
452464

465+
if !config.no_verify { assert!(addpass("verify")); }
453466
if !config.no_prepopulate_passes {
454467
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
455468
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
456-
populate_llvm_passes(fpm, mpm, llmod, opt_level,
457-
config.no_builtins);
469+
populate_llvm_passes(fpm, mpm, llmod, opt_level, &config);
458470
}
459471

460472
for pass in &config.passes {
461-
let pass = CString::new(pass.clone()).unwrap();
462-
if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) {
463-
cgcx.handler.warn(&format!("unknown pass {:?}, ignoring", pass));
473+
if !addpass(pass) {
474+
cgcx.handler.warn(&format!("unknown pass `{}`, ignoring",
475+
pass));
464476
}
465477
}
466478

467479
for pass in &cgcx.plugin_passes {
468-
let pass = CString::new(pass.clone()).unwrap();
469-
if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) {
470-
cgcx.handler.err(&format!("a plugin asked for LLVM pass {:?} but LLVM \
471-
does not recognize it", pass));
480+
if !addpass(pass) {
481+
cgcx.handler.err(&format!("a plugin asked for LLVM pass \
482+
`{}` but LLVM does not \
483+
recognize it", pass));
472484
}
473485
}
474486

@@ -520,7 +532,6 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
520532
llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
521533
llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
522534
f(cpm);
523-
llvm::LLVMDisposePassManager(cpm);
524535
}
525536

526537
if config.emit_bc {
@@ -537,13 +548,15 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
537548
let out = path2cstr(&out);
538549
with_codegen(tm, llmod, config.no_builtins, |cpm| {
539550
llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr());
551+
llvm::LLVMDisposePassManager(cpm);
540552
})
541553
}
542554

543555
if config.emit_asm {
544556
let path = output_names.with_extension(&format!("{}.s", name_extra));
545557
with_codegen(tm, llmod, config.no_builtins, |cpm| {
546-
write_output_file(cgcx.handler, tm, cpm, llmod, &path, llvm::AssemblyFileType);
558+
write_output_file(cgcx.handler, tm, cpm, llmod, &path,
559+
llvm::AssemblyFileType);
547560
});
548561
}
549562

@@ -1008,25 +1021,16 @@ unsafe fn configure_llvm(sess: &Session) {
10081021
use std::sync::Once;
10091022
static INIT: Once = Once::new();
10101023

1011-
// Copy what clang does by turning on loop vectorization at O2 and
1012-
// slp vectorization at O3
1013-
let vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
1014-
(sess.opts.optimize == config::Default ||
1015-
sess.opts.optimize == config::Aggressive);
1016-
let vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
1017-
sess.opts.optimize == config::Aggressive;
1018-
10191024
let mut llvm_c_strs = Vec::new();
10201025
let mut llvm_args = Vec::new();
1026+
10211027
{
10221028
let mut add = |arg: &str| {
10231029
let s = CString::new(arg).unwrap();
10241030
llvm_args.push(s.as_ptr());
10251031
llvm_c_strs.push(s);
10261032
};
10271033
add("rustc"); // fake program name
1028-
if vectorize_loop { add("-vectorize-loops"); }
1029-
if vectorize_slp { add("-vectorize-slp"); }
10301034
if sess.time_llvm_passes() { add("-time-passes"); }
10311035
if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
10321036

@@ -1084,41 +1088,40 @@ unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef,
10841088
mpm: llvm::PassManagerRef,
10851089
llmod: ModuleRef,
10861090
opt: llvm::CodeGenOptLevel,
1087-
no_builtins: bool) {
1091+
config: &ModuleConfig) {
10881092
// Create the PassManagerBuilder for LLVM. We configure it with
10891093
// reasonable defaults and prepare it to actually populate the pass
10901094
// manager.
10911095
let builder = llvm::LLVMPassManagerBuilderCreate();
1096+
1097+
llvm::LLVMRustConfigurePassManagerBuilder(builder, opt,
1098+
config.merge_functions,
1099+
config.vectorize_slp,
1100+
config.vectorize_loop);
1101+
1102+
llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins);
1103+
1104+
// Here we match what clang does (kinda). For O0 we only inline
1105+
// always-inline functions (but don't add lifetime intrinsics), at O1 we
1106+
// inline with lifetime intrinsics, and O2+ we add an inliner with a
1107+
// thresholds copied from clang.
10921108
match opt {
10931109
llvm::CodeGenLevelNone => {
1094-
// Don't add lifetime intrinsics at O0
10951110
llvm::LLVMRustAddAlwaysInlinePass(builder, false);
10961111
}
10971112
llvm::CodeGenLevelLess => {
10981113
llvm::LLVMRustAddAlwaysInlinePass(builder, true);
10991114
}
1100-
// numeric values copied from clang
11011115
llvm::CodeGenLevelDefault => {
1102-
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
1103-
225);
1116+
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
11041117
}
11051118
llvm::CodeGenLevelAggressive => {
1106-
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
1107-
275);
1119+
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
11081120
}
11091121
}
1110-
llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint);
1111-
llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, no_builtins);
11121122

11131123
// Use the builder to populate the function/module pass managers.
11141124
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
11151125
llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
11161126
llvm::LLVMPassManagerBuilderDispose(builder);
1117-
1118-
match opt {
1119-
llvm::CodeGenLevelDefault | llvm::CodeGenLevelAggressive => {
1120-
llvm::LLVMRustAddPass(mpm, "mergefunc\0".as_ptr() as *const _);
1121-
}
1122-
_ => {}
1123-
};
11241127
}

src/librustc_trans/trans/adt.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -1029,11 +1029,26 @@ pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
10291029
}
10301030
General(ity, ref cases, _) => {
10311031
let ccx = bcx.ccx();
1032-
let unr_cx = fcx.new_temp_block("enum-variant-iter-unr");
1033-
Unreachable(unr_cx);
1032+
1033+
// See the comments in trans/base.rs for more information (inside
1034+
// iter_structural_ty), but the gist here is that if the enum's
1035+
// discriminant is *not* in the range that we're expecting (in which
1036+
// case we'll take the fall-through branch on the switch
1037+
// instruction) then we can't just optimize this to an Unreachable
1038+
// block.
1039+
//
1040+
// Currently we still have filling drop, so this means that the drop
1041+
// glue for enums may be called when the enum has been paved over
1042+
// with the "I've been dropped" value. In this case the default
1043+
// branch of the switch instruction will actually be taken at
1044+
// runtime, so the basic block isn't actually unreachable, so we
1045+
// need to make it do something with defined behavior. In this case
1046+
// we just return early from the function.
1047+
let ret_void_cx = fcx.new_temp_block("enum-variant-iter-ret-void");
1048+
RetVoid(ret_void_cx, DebugLoc::None);
10341049

10351050
let discr_val = trans_get_discr(bcx, r, value, None);
1036-
let llswitch = Switch(bcx, discr_val, unr_cx.llbb, cases.len());
1051+
let llswitch = Switch(bcx, discr_val, ret_void_cx.llbb, cases.len());
10371052
let bcx_next = fcx.new_temp_block("enum-variant-iter-next");
10381053

10391054
for (discr, case) in cases.iter().enumerate() {

src/librustc_trans/trans/attributes.rs

+15
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use libc::{c_uint, c_ulonglong};
1313
use llvm::{self, ValueRef, AttrHelper};
1414
use middle::ty::{self, ClosureTyper};
15+
use session::config::NoDebugInfo;
1516
use syntax::abi;
1617
use syntax::ast;
1718
pub use syntax::attr::InlineAttr;
@@ -106,6 +107,20 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
106107
use syntax::attr::*;
107108
inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs));
108109

110+
// FIXME: #11906: Omitting frame pointers breaks retrieving the value of a
111+
// parameter.
112+
let no_fp_elim = (ccx.sess().opts.debuginfo != NoDebugInfo) ||
113+
!ccx.sess().target.target.options.eliminate_frame_pointer;
114+
if no_fp_elim {
115+
unsafe {
116+
let attr = "no-frame-pointer-elim\0".as_ptr() as *const _;
117+
let val = "true\0".as_ptr() as *const _;
118+
llvm::LLVMAddFunctionAttrStringValue(llfn,
119+
llvm::FunctionIndex as c_uint,
120+
attr, val);
121+
}
122+
}
123+
109124
for attr in attrs {
110125
if attr.check_name("no_stack_check") {
111126
split_stack(llfn, false);

src/librustc_trans/trans/base.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -480,9 +480,23 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
480480
}
481481
(_match::Switch, Some(lldiscrim_a)) => {
482482
cx = f(cx, lldiscrim_a, cx.tcx().types.isize);
483-
let unr_cx = fcx.new_temp_block("enum-iter-unr");
484-
Unreachable(unr_cx);
485-
let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb,
483+
484+
// Create a fall-through basic block for the "else" case of
485+
// the switch instruction we're about to generate. Note that
486+
// we do **not** use an Unreachable instruction here, even
487+
// though most of the time this basic block will never be hit.
488+
//
489+
// When an enum is dropped it's contents are currently
490+
// overwritten to DTOR_DONE, which means the discriminant
491+
// could have changed value to something not within the actual
492+
// range of the discriminant. Currently this function is only
493+
// used for drop glue so in this case we just return quickly
494+
// from the outer function, and any other use case will only
495+
// call this for an already-valid enum in which case the `ret
496+
// void` will never be hit.
497+
let ret_void_cx = fcx.new_temp_block("enum-iter-ret-void");
498+
RetVoid(ret_void_cx, DebugLoc::None);
499+
let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb,
486500
n_variants);
487501
let next_cx = fcx.new_temp_block("enum-iter-next");
488502

src/librustc_trans/trans/debuginfo/metadata.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1673,7 +1673,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
16731673
DIB(cx),
16741674
containing_scope,
16751675
enum_name.as_ptr(),
1676-
UNKNOWN_FILE_METADATA,
1676+
file_metadata,
16771677
UNKNOWN_LINE_NUMBER,
16781678
bytes_to_bits(enum_type_size),
16791679
bytes_to_bits(enum_type_align),

0 commit comments

Comments
 (0)