From f9d4149c29e8b989fa3624993be379f380e48dcf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 14 May 2015 12:10:43 -0700 Subject: [PATCH] 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`. --- src/librustc_llvm/lib.rs | 17 +- src/librustc_trans/back/write.rs | 91 +++++------ src/librustc_trans/trans/adt.rs | 21 ++- src/librustc_trans/trans/attributes.rs | 15 ++ src/librustc_trans/trans/base.rs | 20 ++- .../trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/trans/debuginfo/mod.rs | 10 +- src/llvm | 2 +- src/rustllvm/ExecutionEngineWrapper.cpp | 3 - src/rustllvm/PassWrapper.cpp | 58 ++++++- src/rustllvm/RustWrapper.cpp | 146 ++++++++++++++---- src/rustllvm/llvm-auto-clean-trigger | 2 +- src/rustllvm/rustllvm.h | 7 +- src/test/auxiliary/llvm_pass_plugin.rs | 2 +- src/test/codegen/loads.rs | 8 +- src/test/codegen/stores.rs | 4 +- src/test/run-pass/asm-in-out-operand.rs | 3 +- 17 files changed, 302 insertions(+), 109 deletions(-) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 4d7f00e95230a..bf331705b32c9 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -976,6 +976,9 @@ extern { pub fn LLVMAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: uint64_t); pub fn LLVMAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: uint64_t); pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); + pub fn LLVMAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint, + Name: *const c_char, + Value: *const c_char); pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong; pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_ulonglong); @@ -1920,6 +1923,7 @@ extern { VarInfo: DIVariable, AddrOps: *const i64, AddrOpsCount: c_uint, + DL: ValueRef, InsertAtEnd: BasicBlockRef) -> ValueRef; @@ -1928,6 +1932,7 @@ extern { VarInfo: DIVariable, AddrOps: *const i64, AddrOpsCount: c_uint, + DL: ValueRef, InsertBefore: ValueRef) -> ValueRef; @@ -2035,7 +2040,6 @@ extern { Level: CodeGenOptLevel, EnableSegstk: bool, UseSoftFP: bool, - NoFramePointerElim: bool, PositionIndependentExecutable: bool, FunctionSections: bool, DataSections: bool) -> TargetMachineRef; @@ -2046,6 +2050,11 @@ extern { pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef, M: ModuleRef, DisableSimplifyLibCalls: bool); + pub fn LLVMRustConfigurePassManagerBuilder(PMB: PassManagerBuilderRef, + OptLevel: CodeGenOptLevel, + MergeFunctions: bool, + SLPVectorize: bool, + LoopVectorize: bool); pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef, DisableSimplifyLibCalls: bool); pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef); @@ -2116,6 +2125,12 @@ extern { pub fn LLVMWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef); } +// LLVM requires symbols from this library, but apparently they're not printed +// during llvm-config? +#[cfg(windows)] +#[link(name = "ole32")] +extern {} + pub fn SetInstructionCallConv(instr: ValueRef, cc: CallConv) { unsafe { LLVMSetInstructionCallConv(instr, cc as c_uint); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 5352c61d8c0ad..1b8f049972f21 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -10,7 +10,7 @@ use back::lto; use back::link::{get_cc_prog, remove}; -use session::config::{OutputFilenames, NoDebugInfo, Passes, SomePasses, AllPasses}; +use session::config::{OutputFilenames, Passes, SomePasses, AllPasses}; use session::Session; use session::config; use llvm; @@ -188,10 +188,6 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef { let opt_level = get_llvm_opt_level(sess.opts.optimize); let use_softfp = sess.opts.cg.soft_float; - // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a parameter. - let no_fp_elim = (sess.opts.debuginfo != NoDebugInfo) || - !sess.target.target.options.eliminate_frame_pointer; - let any_library = sess.crate_types.borrow().iter().any(|ty| { *ty != config::CrateTypeExecutable }); @@ -237,7 +233,6 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef { opt_level, true /* EnableSegstk */, use_softfp, - no_fp_elim, !any_library && reloc_model == llvm::RelocPIC, ffunction_sections, fdata_sections, @@ -279,6 +274,9 @@ struct ModuleConfig { no_prepopulate_passes: bool, no_builtins: bool, time_passes: bool, + vectorize_loop: bool, + vectorize_slp: bool, + merge_functions: bool, } unsafe impl Send for ModuleConfig { } @@ -301,6 +299,9 @@ impl ModuleConfig { no_prepopulate_passes: false, no_builtins: false, time_passes: false, + vectorize_loop: false, + vectorize_slp: false, + merge_functions: false, } } @@ -309,6 +310,18 @@ impl ModuleConfig { self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes; self.no_builtins = trans.no_builtins; self.time_passes = sess.time_passes(); + + // Copy what clang does by turning on loop vectorization at O2 and + // slp vectorization at O3. Otherwise configure other optimization aspects + // of this pass manager builder. + self.vectorize_loop = !sess.opts.cg.no_vectorize_loops && + (sess.opts.optimize == config::Default || + sess.opts.optimize == config::Aggressive); + self.vectorize_slp = !sess.opts.cg.no_vectorize_slp && + sess.opts.optimize == config::Aggressive; + + self.merge_functions = sess.opts.optimize == config::Default || + sess.opts.optimize == config::Aggressive; } } @@ -448,27 +461,26 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, let pass = CString::new(pass).unwrap(); llvm::LLVMRustAddPass(fpm, pass.as_ptr()) }; - if !config.no_verify { assert!(addpass("verify")); } + if !config.no_verify { assert!(addpass("verify")); } if !config.no_prepopulate_passes { llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod); llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod); - populate_llvm_passes(fpm, mpm, llmod, opt_level, - config.no_builtins); + populate_llvm_passes(fpm, mpm, llmod, opt_level, &config); } for pass in &config.passes { - let pass = CString::new(pass.clone()).unwrap(); - if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) { - cgcx.handler.warn(&format!("unknown pass {:?}, ignoring", pass)); + if !addpass(pass) { + cgcx.handler.warn(&format!("unknown pass `{}`, ignoring", + pass)); } } for pass in &cgcx.plugin_passes { - let pass = CString::new(pass.clone()).unwrap(); - if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) { - cgcx.handler.err(&format!("a plugin asked for LLVM pass {:?} but LLVM \ - does not recognize it", pass)); + if !addpass(pass) { + cgcx.handler.err(&format!("a plugin asked for LLVM pass \ + `{}` but LLVM does not \ + recognize it", pass)); } } @@ -520,7 +532,6 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod); llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); f(cpm); - llvm::LLVMDisposePassManager(cpm); } if config.emit_bc { @@ -537,13 +548,15 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, let out = path2cstr(&out); with_codegen(tm, llmod, config.no_builtins, |cpm| { llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr()); + llvm::LLVMDisposePassManager(cpm); }) } if config.emit_asm { let path = output_names.with_extension(&format!("{}.s", name_extra)); with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(cgcx.handler, tm, cpm, llmod, &path, llvm::AssemblyFileType); + write_output_file(cgcx.handler, tm, cpm, llmod, &path, + llvm::AssemblyFileType); }); } @@ -1008,16 +1021,9 @@ unsafe fn configure_llvm(sess: &Session) { use std::sync::Once; static INIT: Once = Once::new(); - // Copy what clang does by turning on loop vectorization at O2 and - // slp vectorization at O3 - let vectorize_loop = !sess.opts.cg.no_vectorize_loops && - (sess.opts.optimize == config::Default || - sess.opts.optimize == config::Aggressive); - let vectorize_slp = !sess.opts.cg.no_vectorize_slp && - sess.opts.optimize == config::Aggressive; - let mut llvm_c_strs = Vec::new(); let mut llvm_args = Vec::new(); + { let mut add = |arg: &str| { let s = CString::new(arg).unwrap(); @@ -1025,8 +1031,6 @@ unsafe fn configure_llvm(sess: &Session) { llvm_c_strs.push(s); }; add("rustc"); // fake program name - if vectorize_loop { add("-vectorize-loops"); } - if vectorize_slp { add("-vectorize-slp"); } if sess.time_llvm_passes() { add("-time-passes"); } if sess.print_llvm_passes() { add("-debug-pass=Structure"); } @@ -1084,41 +1088,40 @@ unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef, mpm: llvm::PassManagerRef, llmod: ModuleRef, opt: llvm::CodeGenOptLevel, - no_builtins: bool) { + config: &ModuleConfig) { // Create the PassManagerBuilder for LLVM. We configure it with // reasonable defaults and prepare it to actually populate the pass // manager. let builder = llvm::LLVMPassManagerBuilderCreate(); + + llvm::LLVMRustConfigurePassManagerBuilder(builder, opt, + config.merge_functions, + config.vectorize_slp, + config.vectorize_loop); + + llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins); + + // Here we match what clang does (kinda). For O0 we only inline + // always-inline functions (but don't add lifetime intrinsics), at O1 we + // inline with lifetime intrinsics, and O2+ we add an inliner with a + // thresholds copied from clang. match opt { llvm::CodeGenLevelNone => { - // Don't add lifetime intrinsics at O0 llvm::LLVMRustAddAlwaysInlinePass(builder, false); } llvm::CodeGenLevelLess => { llvm::LLVMRustAddAlwaysInlinePass(builder, true); } - // numeric values copied from clang llvm::CodeGenLevelDefault => { - llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, - 225); + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225); } llvm::CodeGenLevelAggressive => { - llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, - 275); + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275); } } - llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint); - llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, no_builtins); // Use the builder to populate the function/module pass managers. llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm); llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm); llvm::LLVMPassManagerBuilderDispose(builder); - - match opt { - llvm::CodeGenLevelDefault | llvm::CodeGenLevelAggressive => { - llvm::LLVMRustAddPass(mpm, "mergefunc\0".as_ptr() as *const _); - } - _ => {} - }; } diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 6d4c72c132a59..61dce5648f807 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -1029,11 +1029,26 @@ pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } General(ity, ref cases, _) => { let ccx = bcx.ccx(); - let unr_cx = fcx.new_temp_block("enum-variant-iter-unr"); - Unreachable(unr_cx); + + // See the comments in trans/base.rs for more information (inside + // iter_structural_ty), but the gist here is that if the enum's + // discriminant is *not* in the range that we're expecting (in which + // case we'll take the fall-through branch on the switch + // instruction) then we can't just optimize this to an Unreachable + // block. + // + // Currently we still have filling drop, so this means that the drop + // glue for enums may be called when the enum has been paved over + // with the "I've been dropped" value. In this case the default + // branch of the switch instruction will actually be taken at + // runtime, so the basic block isn't actually unreachable, so we + // need to make it do something with defined behavior. In this case + // we just return early from the function. + let ret_void_cx = fcx.new_temp_block("enum-variant-iter-ret-void"); + RetVoid(ret_void_cx, DebugLoc::None); let discr_val = trans_get_discr(bcx, r, value, None); - let llswitch = Switch(bcx, discr_val, unr_cx.llbb, cases.len()); + let llswitch = Switch(bcx, discr_val, ret_void_cx.llbb, cases.len()); let bcx_next = fcx.new_temp_block("enum-variant-iter-next"); for (discr, case) in cases.iter().enumerate() { diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index 132947e34d795..f7e9bd4d3d071 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -12,6 +12,7 @@ use libc::{c_uint, c_ulonglong}; use llvm::{self, ValueRef, AttrHelper}; use middle::ty::{self, ClosureTyper}; +use session::config::NoDebugInfo; use syntax::abi; use syntax::ast; pub use syntax::attr::InlineAttr; @@ -106,6 +107,20 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe use syntax::attr::*; inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs)); + // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a + // parameter. + let no_fp_elim = (ccx.sess().opts.debuginfo != NoDebugInfo) || + !ccx.sess().target.target.options.eliminate_frame_pointer; + if no_fp_elim { + unsafe { + let attr = "no-frame-pointer-elim\0".as_ptr() as *const _; + let val = "true\0".as_ptr() as *const _; + llvm::LLVMAddFunctionAttrStringValue(llfn, + llvm::FunctionIndex as c_uint, + attr, val); + } + } + for attr in attrs { if attr.check_name("no_stack_check") { split_stack(llfn, false); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 390c0b035fdd5..91eacca0b8a11 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -480,9 +480,23 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, } (_match::Switch, Some(lldiscrim_a)) => { cx = f(cx, lldiscrim_a, cx.tcx().types.isize); - let unr_cx = fcx.new_temp_block("enum-iter-unr"); - Unreachable(unr_cx); - let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb, + + // Create a fall-through basic block for the "else" case of + // the switch instruction we're about to generate. Note that + // we do **not** use an Unreachable instruction here, even + // though most of the time this basic block will never be hit. + // + // When an enum is dropped it's contents are currently + // overwritten to DTOR_DONE, which means the discriminant + // could have changed value to something not within the actual + // range of the discriminant. Currently this function is only + // used for drop glue so in this case we just return quickly + // from the outer function, and any other use case will only + // call this for an already-valid enum in which case the `ret + // void` will never be hit. + let ret_void_cx = fcx.new_temp_block("enum-iter-ret-void"); + RetVoid(ret_void_cx, DebugLoc::None); + let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants); let next_cx = fcx.new_temp_block("enum-iter-next"); diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index ab86cd7cdde59..406c8b98bd55e 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -1673,7 +1673,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, DIB(cx), containing_scope, enum_name.as_ptr(), - UNKNOWN_FILE_METADATA, + file_metadata, UNKNOWN_LINE_NUMBER, bytes_to_bits(enum_type_size), bytes_to_bits(enum_type_align), diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index 71312bb60a2a5..a5da5501fa2f1 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -484,10 +484,10 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let param_metadata = unsafe { llvm::LLVMDIBuilderCreateTemplateTypeParameter( DIB(cx), - file_metadata, + ptr::null_mut(), name.as_ptr(), actual_self_type_metadata, - ptr::null_mut(), + file_metadata, 0, 0) }; @@ -518,10 +518,10 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let param_metadata = unsafe { llvm::LLVMDIBuilderCreateTemplateTypeParameter( DIB(cx), - file_metadata, + ptr::null_mut(), name.as_ptr(), actual_type_metadata, - ptr::null_mut(), + file_metadata, 0, 0) }; @@ -580,12 +580,14 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, loc.line, loc.col.to_usize())); unsafe { + let debug_loc = llvm::LLVMGetCurrentDebugLocation(cx.raw_builder()); let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( DIB(cx), alloca, metadata, address_operations.as_ptr(), address_operations.len() as c_uint, + debug_loc, bcx.llbb); llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr); diff --git a/src/llvm b/src/llvm index bff6907697564..8cbcdf1b72e1b 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit bff69076975642c64e76dbeaa53476bfa7212086 +Subproject commit 8cbcdf1b72e1b23679646f6faca265f76b20d379 diff --git a/src/rustllvm/ExecutionEngineWrapper.cpp b/src/rustllvm/ExecutionEngineWrapper.cpp index e37ede82bb560..105472cf4f426 100644 --- a/src/rustllvm/ExecutionEngineWrapper.cpp +++ b/src/rustllvm/ExecutionEngineWrapper.cpp @@ -103,9 +103,6 @@ extern "C" LLVMExecutionEngineRef LLVMBuildExecutionEngine(LLVMModuleRef mod) std::string error_str; TargetOptions options; - options.JITEmitDebugInfo = true; - options.NoFramePointerElim = true; - RustJITMemoryManager *mm = new RustJITMemoryManager; ExecutionEngine *ee = diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index a2ab8040198ff..2c0240eb8f92b 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -15,12 +15,19 @@ #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" +#if LLVM_VERSION_MINOR >= 7 +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#else #include "llvm/Target/TargetLibraryInfo.h" +#endif #include "llvm/Transforms/IPO/PassManagerBuilder.h" + #include "llvm-c/Transforms/PassManagerBuilder.h" using namespace llvm; +using namespace llvm::legacy; extern cl::opt EnableARMEHABI; @@ -71,7 +78,6 @@ LLVMRustCreateTargetMachine(const char *triple, CodeGenOpt::Level OptLevel, bool EnableSegmentedStacks, bool UseSoftFloat, - bool NoFramePointerElim, bool PositionIndependentExecutable, bool FunctionSections, bool DataSections) { @@ -91,12 +97,12 @@ LLVMRustCreateTargetMachine(const char *triple, TargetOptions Options; Options.PositionIndependentExecutable = PositionIndependentExecutable; - Options.NoFramePointerElim = NoFramePointerElim; Options.FloatABIType = FloatABI::Default; - Options.UseSoftFloat = UseSoftFloat; if (UseSoftFloat) { Options.FloatABIType = FloatABI::Soft; } + Options.DataSections = DataSections; + Options.FunctionSections = FunctionSections; TargetMachine *TM = TheTarget->createTargetMachine(Trip.getTriple(), real_cpu, @@ -105,8 +111,6 @@ LLVMRustCreateTargetMachine(const char *triple, RM, CM, OptLevel); - TM->setDataSections(DataSections); - TM->setFunctionSections(FunctionSections); return wrap(TM); } @@ -123,12 +127,32 @@ LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM, LLVMPassManagerRef PMR, LLVMModuleRef M) { PassManagerBase *PM = unwrap(PMR); -#if LLVM_VERSION_MINOR >= 6 +#if LLVM_VERSION_MINOR >= 7 + PM->add(createTargetTransformInfoWrapperPass( + unwrap(TM)->getTargetIRAnalysis())); +#else +#if LLVM_VERSION_MINOR == 6 PM->add(new DataLayoutPass()); #else PM->add(new DataLayoutPass(unwrap(M))); #endif unwrap(TM)->addAnalysisPasses(*PM); +#endif +} + +extern "C" void +LLVMRustConfigurePassManagerBuilder(LLVMPassManagerBuilderRef PMB, + CodeGenOpt::Level OptLevel, + bool MergeFunctions, + bool SLPVectorize, + bool LoopVectorize) { +#if LLVM_VERSION_MINOR >= 6 + // Ignore mergefunc for now as enabling it causes crashes. + //unwrap(PMB)->MergeFunctions = MergeFunctions; +#endif + unwrap(PMB)->SLPVectorize = SLPVectorize; + unwrap(PMB)->OptLevel = OptLevel; + unwrap(PMB)->LoopVectorize = LoopVectorize; } // Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo` @@ -138,7 +162,11 @@ LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB, LLVMModuleRef M, bool DisableSimplifyLibCalls) { Triple TargetTriple(unwrap(M)->getTargetTriple()); +#if LLVM_VERSION_MINOR >= 7 + TargetLibraryInfoImpl *TLI = new TargetLibraryInfoImpl(TargetTriple); +#else TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple); +#endif if (DisableSimplifyLibCalls) TLI->disableAllFunctions(); unwrap(PMB)->LibraryInfo = TLI; @@ -151,10 +179,17 @@ LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, LLVMModuleRef M, bool DisableSimplifyLibCalls) { Triple TargetTriple(unwrap(M)->getTargetTriple()); +#if LLVM_VERSION_MINOR >= 7 + TargetLibraryInfoImpl TLII(TargetTriple); + if (DisableSimplifyLibCalls) + TLII.disableAllFunctions(); + unwrap(PMB)->add(new TargetLibraryInfoWrapperPass(TLII)); +#else TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple); if (DisableSimplifyLibCalls) TLI->disableAllFunctions(); unwrap(PMB)->add(TLI); +#endif } // Unfortunately, the LLVM C API doesn't provide an easy way of iterating over @@ -204,10 +239,19 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMRustSetLastError(ErrorInfo.c_str()); return false; } - formatted_raw_ostream FOS(OS); +#if LLVM_VERSION_MINOR >= 7 + unwrap(Target)->addPassesToEmitFile(*PM, OS, FileType, false); +#else + formatted_raw_ostream FOS(OS); unwrap(Target)->addPassesToEmitFile(*PM, FOS, FileType, false); +#endif PM->run(*unwrap(M)); + + // Apparently `addPassesToEmitFile` adds an pointer to our on-the-stack output + // stream (OS), so the only real safe place to delete this is here? Don't we + // wish this was written in Rust? + delete PM; return true; } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index ad6533e5480b1..70ef64afc4336 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -141,6 +141,15 @@ extern "C" void LLVMAddFunctionAttrString(LLVMValueRef Fn, unsigned index, const F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); } +extern "C" void LLVMAddFunctionAttrStringValue(LLVMValueRef Fn, unsigned index, + const char *Name, + const char *Value) { + Function *F = unwrap(Fn); + AttrBuilder B; + B.addAttribute(Name, Value); + F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); +} + extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, unsigned index, const char *Name) { Function *f = unwrap(fn); LLVMContext &C = f->getContext(); @@ -228,10 +237,25 @@ inline Metadata **unwrap(LLVMMetadataRef *Vals) { typedef LLVMValueRef LLVMMetadataRef; #endif +template +DIT* unwrapDIptr(LLVMMetadataRef ref) { + return (DIT*) (ref ? unwrap(ref) : NULL); +} + +#if LLVM_VERSION_MINOR <= 6 template DIT unwrapDI(LLVMMetadataRef ref) { return DIT(ref ? unwrap(ref) : NULL); } +#else +#define DIDescriptor DIScope +#define DIArray DINodeArray +#define unwrapDI unwrapDIptr +#endif + +#if LLVM_VERSION_MINOR <= 5 +#define DISubroutineType DICompositeType +#endif extern "C" uint32_t LLVMRustDebugMetadataVersion() { return DEBUG_METADATA_VERSION; @@ -296,7 +320,9 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateSubroutineType( LLVMMetadataRef ParameterTypes) { return wrap(Builder->createSubroutineType( unwrapDI(File), -#if LLVM_VERSION_MINOR >= 6 +#if LLVM_VERSION_MINOR >= 7 + DITypeRefArray(unwrap(ParameterTypes)))); +#elif LLVM_VERSION_MINOR >= 6 unwrapDI(ParameterTypes))); #else unwrapDI(ParameterTypes))); @@ -322,11 +348,11 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateFunction( return wrap(Builder->createFunction( unwrapDI(Scope), Name, LinkageName, unwrapDI(File), LineNo, - unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, + unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, Flags, isOptimized, unwrap(Fn), - unwrapDI(TParam), - unwrapDI(Decl))); + unwrapDIptr(TParam), + unwrapDIptr(Decl))); } extern "C" LLVMMetadataRef LLVMDIBuilderCreateBasicType( @@ -373,7 +399,11 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateStructType( AlignInBits, Flags, unwrapDI(DerivedFrom), +#if LLVM_VERSION_MINOR >= 7 + DINodeArray(unwrapDI(Elements)), +#else unwrapDI(Elements), +#endif RunTimeLang, unwrapDI(VTableHolder), UniqueId @@ -436,7 +466,7 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateStaticVariable( unwrapDI(Ty), isLocalToUnit, cast(unwrap(Val)), - unwrapDI(Decl))); + unwrapDIptr(Decl))); } extern "C" LLVMMetadataRef LLVMDIBuilderCreateVariable( @@ -486,7 +516,12 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateArrayType( LLVMMetadataRef Subscripts) { return wrap(Builder->createArrayType(Size, AlignInBits, unwrapDI(Ty), - unwrapDI(Subscripts))); +#if LLVM_VERSION_MINOR >= 7 + DINodeArray(unwrapDI(Subscripts)) +#else + unwrapDI(Subscripts) +#endif + )); } extern "C" LLVMMetadataRef LLVMDIBuilderCreateVectorType( @@ -497,7 +532,12 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateVectorType( LLVMMetadataRef Subscripts) { return wrap(Builder->createVectorType(Size, AlignInBits, unwrapDI(Ty), - unwrapDI(Subscripts))); +#if LLVM_VERSION_MINOR >= 7 + DINodeArray(unwrapDI(Subscripts)) +#else + unwrapDI(Subscripts) +#endif + )); } extern "C" LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange( @@ -511,12 +551,18 @@ extern "C" LLVMMetadataRef LLVMDIBuilderGetOrCreateArray( DIBuilderRef Builder, LLVMMetadataRef* Ptr, unsigned Count) { +#if LLVM_VERSION_MINOR >= 7 + Metadata **DataValue = unwrap(Ptr); + return wrap(Builder->getOrCreateArray( + ArrayRef(DataValue, Count)).get()); +#else return wrap(Builder->getOrCreateArray( #if LLVM_VERSION_MINOR >= 6 ArrayRef(unwrap(Ptr), Count))); #else ArrayRef(reinterpret_cast(Ptr), Count))); #endif +#endif } extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( @@ -525,21 +571,21 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( LLVMMetadataRef VarInfo, int64_t* AddrOps, unsigned AddrOpsCount, + LLVMValueRef DL, LLVMBasicBlockRef InsertAtEnd) { -#if LLVM_VERSION_MINOR >= 6 - DIExpression Expr; - if (AddrOpsCount == 0) { - Expr = Builder->createExpression(); - } else { - llvm::ArrayRef addr_ops(AddrOps, AddrOpsCount); - Expr = Builder->createExpression(addr_ops); - } -#endif return wrap(Builder->insertDeclare( unwrap(Val), +#if LLVM_VERSION_MINOR >= 7 + unwrap(VarInfo), +#else unwrapDI(VarInfo), +#endif #if LLVM_VERSION_MINOR >= 6 - Expr, + Builder->createExpression( + llvm::ArrayRef(AddrOps, AddrOpsCount)), +#endif +#if LLVM_VERSION_MINOR >= 7 + DebugLoc(cast(unwrap(DL)->getMetadata())), #endif unwrap(InsertAtEnd))); } @@ -550,21 +596,23 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore( LLVMMetadataRef VarInfo, int64_t* AddrOps, unsigned AddrOpsCount, + LLVMValueRef DL, LLVMValueRef InsertBefore) { #if LLVM_VERSION_MINOR >= 6 - DIExpression Expr; - if (AddrOpsCount == 0) { - Expr = Builder->createExpression(); - } else { - llvm::ArrayRef addr_ops(AddrOps, AddrOpsCount); - Expr = Builder->createExpression(addr_ops); - } #endif return wrap(Builder->insertDeclare( unwrap(Val), +#if LLVM_VERSION_MINOR >= 7 + unwrap(VarInfo), +#else unwrapDI(VarInfo), +#endif #if LLVM_VERSION_MINOR >= 6 - Expr, + Builder->createExpression( + llvm::ArrayRef(AddrOps, AddrOpsCount)), +#endif +#if LLVM_VERSION_MINOR >= 7 + DebugLoc(cast(unwrap(DL)->getMetadata())), #endif unwrap(InsertBefore))); } @@ -595,7 +643,11 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateEnumerationType( LineNumber, SizeInBits, AlignInBits, +#if LLVM_VERSION_MINOR >= 7 + DINodeArray(unwrapDI(Elements)), +#else unwrapDI(Elements), +#endif unwrapDI(ClassType))); } @@ -620,7 +672,11 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateUnionType( SizeInBits, AlignInBits, Flags, +#if LLVM_VERSION_MINOR >= 7 + DINodeArray(unwrapDI(Elements)), +#else unwrapDI(Elements), +#endif RunTimeLang, UniqueId )); @@ -638,10 +694,14 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateTemplateTypeParameter( return wrap(Builder->createTemplateTypeParameter( unwrapDI(Scope), Name, - unwrapDI(Ty), + unwrapDI(Ty) +#if LLVM_VERSION_MINOR <= 6 + , unwrapDI(File), LineNo, - ColumnNo)); + ColumnNo +#endif + )); } extern "C" int64_t LLVMDIBuilderCreateOpDeref() @@ -673,7 +733,10 @@ extern "C" void LLVMDICompositeTypeSetTypeArray( LLVMMetadataRef CompositeType, LLVMMetadataRef TypeArray) { -#if LLVM_VERSION_MINOR >= 6 +#if LLVM_VERSION_MINOR >= 7 + DICompositeType *tmp = unwrapDI(CompositeType); + Builder->replaceArrays(tmp, DINodeArray(unwrap(TypeArray))); +#elif LLVM_VERSION_MINOR >= 6 DICompositeType tmp = unwrapDI(CompositeType); Builder->replaceArrays(tmp, unwrapDI(TypeArray)); #else @@ -692,11 +755,15 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateDebugLocation( DebugLoc debug_loc = DebugLoc::get(Line, Column, - unwrapDI(Scope), - unwrapDI(InlinedAt)); + unwrapDIptr(Scope), + unwrapDIptr(InlinedAt)); #if LLVM_VERSION_MINOR >= 6 - return wrap(MetadataAsValue::get(context, debug_loc.getAsMDNode(context))); + return wrap(MetadataAsValue::get(context, debug_loc.getAsMDNode( +#if LLVM_VERSION_MINOR <= 6 + context +#endif + ))); #else return wrap(debug_loc.getAsMDNode(context)); #endif @@ -721,7 +788,12 @@ LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { Module *Dst = unwrap(dst); #if LLVM_VERSION_MINOR >= 6 std::unique_ptr buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len)); +#if LLVM_VERSION_MINOR >= 7 + ErrorOr> Src = + llvm::getLazyBitcodeModule(std::move(buf), Dst->getContext()); +#else ErrorOr Src = llvm::getLazyBitcodeModule(std::move(buf), Dst->getContext()); +#endif #else MemoryBuffer* buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len)); ErrorOr Src = llvm::getLazyBitcodeModule(buf, Dst->getContext()); @@ -739,7 +811,11 @@ LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { #if LLVM_VERSION_MINOR >= 6 raw_string_ostream Stream(Err); DiagnosticPrinterRawOStream DP(Stream); +#if LLVM_VERSION_MINOR >= 7 + if (Linker::LinkModules(Dst, Src->get(), [&](const DiagnosticInfo &DI) { DI.print(DP); })) { +#else if (Linker::LinkModules(Dst, *Src, [&](const DiagnosticInfo &DI) { DI.print(DP); })) { +#endif #else if (Linker::LinkModules(Dst, *Src, Linker::DestroySource, &Err)) { #endif @@ -813,8 +889,12 @@ extern "C" const Archive::Child* LLVMRustArchiveIteratorCurrent(RustArchiveIterator *rai) { if (rai->cur == rai->end) return NULL; +#if LLVM_VERSION_MINOR >= 6 const Archive::Child &ret = *rai->cur; return &ret; +#else + return rai->cur.operator->(); +#endif } extern "C" void @@ -942,7 +1022,11 @@ extern "C" void LLVMWriteDebugLocToString( RustStringRef str) { raw_rust_string_ostream os(str); +#if LLVM_VERSION_MINOR >= 7 + unwrap(dl)->print(os); +#else unwrap(dl)->print(*unwrap(C), os); +#endif } DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 1ea40fc46a521..38b7b49a3443e 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly 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. -2015-03-04 +2015-06-16 diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index bb82c0c818677..2a47e8b089549 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -12,7 +12,6 @@ #include "llvm/IR/InlineAsm.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" -#include "llvm/PassManager.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Analysis/Passes.h" @@ -46,6 +45,12 @@ #include "llvm-c/ExecutionEngine.h" #include "llvm-c/Object.h" +#if LLVM_VERSION_MINOR >= 7 +#include "llvm/IR/LegacyPassManager.h" +#else +#include "llvm/PassManager.h" +#endif + #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DIBuilder.h" diff --git a/src/test/auxiliary/llvm_pass_plugin.rs b/src/test/auxiliary/llvm_pass_plugin.rs index d61f47fd7ef27..bacc1acd3c4c3 100644 --- a/src/test/auxiliary/llvm_pass_plugin.rs +++ b/src/test/auxiliary/llvm_pass_plugin.rs @@ -24,5 +24,5 @@ pub fn plugin_registrar(reg: &mut Registry) { // Normally, we would name a pass that was registered through // C++ static object constructors in the same .so file as the // plugin registrar. - reg.register_llvm_pass("inline"); + reg.register_llvm_pass("gvn"); } diff --git a/src/test/codegen/loads.rs b/src/test/codegen/loads.rs index 20a55740bb776..45b8731c3b149 100644 --- a/src/test/codegen/loads.rs +++ b/src/test/codegen/loads.rs @@ -20,14 +20,14 @@ pub struct Bytes { // CHECK-LABEL: @borrow #[no_mangle] pub fn borrow(x: &i32) -> &i32 { -// CHECK: load i32** %x{{.*}}, !nonnull +// CHECK: load i32*, i32** %x{{.*}}, !nonnull x } // CHECK-LABEL: @_box #[no_mangle] pub fn _box(x: Box) -> i32 { -// CHECK: load i32** %x{{.*}}, !nonnull +// CHECK: load i32*, i32** %x{{.*}}, !nonnull *x } @@ -36,7 +36,7 @@ pub fn _box(x: Box) -> i32 { // dependent alignment #[no_mangle] pub fn small_array_alignment(x: [i8; 4]) -> [i8; 4] { -// CHECK: [[VAR:%[0-9]+]] = load i32* %{{.*}}, align 1 +// CHECK: [[VAR:%[0-9]+]] = load i32, i32* %{{.*}}, align 1 // CHECK: ret i32 [[VAR]] x } @@ -46,7 +46,7 @@ pub fn small_array_alignment(x: [i8; 4]) -> [i8; 4] { // dependent alignment #[no_mangle] pub fn small_struct_alignment(x: Bytes) -> Bytes { -// CHECK: [[VAR:%[0-9]+]] = load i32* %{{.*}}, align 1 +// CHECK: [[VAR:%[0-9]+]] = load i32, i32* %{{.*}}, align 1 // CHECK: ret i32 [[VAR]] x } diff --git a/src/test/codegen/stores.rs b/src/test/codegen/stores.rs index 32337b085cd27..15cf76b2ab1de 100644 --- a/src/test/codegen/stores.rs +++ b/src/test/codegen/stores.rs @@ -22,7 +22,7 @@ pub struct Bytes { // dependent alignment #[no_mangle] pub fn small_array_alignment(x: &mut [i8; 4]) { -// CHECK: [[VAR:%[0-9]+]] = load [4 x i8]** %x +// CHECK: [[VAR:%[0-9]+]] = load [4 x i8]*, [4 x i8]** %x // CHECK: [[VAR2:%[0-9]+]] = bitcast [4 x i8]* [[VAR]] to i32* // CHECK: store i32 %{{.*}}, i32* [[VAR2]], align 1 *x = [0; 4]; @@ -33,7 +33,7 @@ pub fn small_array_alignment(x: &mut [i8; 4]) { // dependent alignment #[no_mangle] pub fn small_struct_alignment(x: &mut Bytes) { -// CHECK: [[VAR:%[0-9]+]] = load %Bytes** %x +// CHECK: [[VAR:%[0-9]+]] = load %Bytes*, %Bytes** %x // CHECK: [[VAR2:%[0-9]+]] = bitcast %Bytes* [[VAR]] to i32* // CHECK: store i32 %{{.*}}, i32* [[VAR2]], align 1 *x = Bytes { diff --git a/src/test/run-pass/asm-in-out-operand.rs b/src/test/run-pass/asm-in-out-operand.rs index 3eebc7acb0fd5..243ecf86e9c46 100644 --- a/src/test/run-pass/asm-in-out-operand.rs +++ b/src/test/run-pass/asm-in-out-operand.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - #![feature(asm)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] unsafe fn next_power_of_2(n: u32) -> u32 { let mut tmp = n; asm!("dec $0" : "+rm"(tmp) :: "cc"); - let mut shift = 1_usize; + let mut shift = 1_u32; while shift <= 16 { asm!( "shr %cl, $2