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