diff --git a/mk/crates.mk b/mk/crates.mk index 0437e08de28b6..ec37c07922128 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -51,12 +51,13 @@ TARGET_CRATES := libc std green rustuv native flate arena glob term semver \ uuid serialize sync getopts collections num test time rand \ - workcache url log regex graphviz core + workcache url log regex graphviz core rlibc HOST_CRATES := syntax rustc rustdoc fourcc hexfloat regex_macros fmt_macros CRATES := $(TARGET_CRATES) $(HOST_CRATES) TOOLS := compiletest rustdoc rustc DEPS_core := +DEPS_rlibc := DEPS_std := core libc native:rustrt native:compiler-rt native:backtrace native:jemalloc DEPS_green := std rand native:context_switch DEPS_rustuv := std native:uv native:uv_support @@ -98,6 +99,7 @@ TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs TOOL_SOURCE_rustc := $(S)src/driver/driver.rs ONLY_RLIB_core := 1 +ONLY_RLIB_rlibc := 1 ################################################################################ # You should not need to edit below this line diff --git a/src/doc/rust.md b/src/doc/rust.md index f242a89784ce9..838ddca042dfc 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -1799,6 +1799,8 @@ type int8_t = i8; - `no_start` - disable linking to the `native` crate, which specifies the "start" language item. - `no_std` - disable linking to the `std` crate. +- `no_builtins` - disable optimizing certain code patterns to invocations of + library functions that are assumed to exist ### Module-only attributes diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9e3a92981e532..4102c72d8b64b 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -18,6 +18,9 @@ //! * `memcpy`, `memcmp`, `memset` - These are core memory routines which are //! often generated by LLVM. Additionally, this library can make explicit //! calls to these funcitons. Their signatures are the same as found in C. +//! These functions are often provided by the system libc, but can also be +//! provided by `librlibc` which is distributed with the standard rust +//! distribution. //! //! * `rust_begin_unwind` - This function takes three arguments, a //! `&fmt::Arguments`, a `&str`, and a `uint. These three arguments dictate diff --git a/src/librlibc/lib.rs b/src/librlibc/lib.rs new file mode 100644 index 0000000000000..f483688829f42 --- /dev/null +++ b/src/librlibc/lib.rs @@ -0,0 +1,96 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A bare-metal library supplying functions rustc may lower code to +//! +//! This library is not intended for general use, and is superseded by a system +//! libc if one is available. In a freestanding context, however, common +//! functions such as memset, memcpy, etc are not implemented. This library +//! provides an implementation of these functions which are either required by +//! libcore or called by rustc implicitly. +//! +//! This library is never included by default, and must be manually included if +//! necessary. It is an error to include this library when also linking with +//! the system libc library. + +#![crate_id = "rlibc#0.11.0-pre"] +#![license = "MIT/ASL2"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://static.rust-lang.org/doc/master")] + +#![no_std] +#![experimental] + +// This library is definining the builtin functions, so it would be a shame for +// LLVM to optimize these function calls to themselves! +#![no_builtins] + +#[cfg(test)] extern crate std; +#[cfg(test)] extern crate native; + +// Require the offset intrinsics for LLVM to properly optimize the +// implementations below. If pointer arithmetic is done through integers the +// optimizations start to break down. +extern "rust-intrinsic" { + fn offset(dst: *T, offset: int) -> *T; +} + +#[no_mangle] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *u8, n: uint) { + let mut i = 0; + while i < n { + *(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int); + i += 1; + } +} + +#[no_mangle] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *u8, n: uint) { + if src < dest as *u8 { // copy from end + let mut i = n; + while i != 0 { + i -= 1; + *(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int); + } + } else { // copy from beginning + let mut i = 0; + while i < n { + *(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int); + i += 1; + } + } +} + +#[no_mangle] +pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: uint) { + let mut i = 0; + while i < n { + *(offset(s as *u8, i as int) as *mut u8) = c as u8; + i += 1; + } +} + +#[no_mangle] +pub unsafe extern "C" fn memcmp(s1: *u8, s2: *u8, n: uint) -> i32 { + let mut i = 0; + while i < n { + let a = *offset(s1, i as int); + let b = *offset(s2, i as int); + if a != b { + return (a - b) as i32 + } + i += 1; + } + return 0; +} + +#[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index de6b5925edbde..9b844e0dab38e 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -212,7 +212,8 @@ pub mod write { if !sess.opts.cg.no_prepopulate_passes { llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod); llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod); - populate_llvm_passes(fpm, mpm, llmod, opt_level); + populate_llvm_passes(fpm, mpm, llmod, opt_level, + trans.no_builtins); } for pass in sess.opts.cg.passes.iter() { @@ -264,11 +265,11 @@ pub mod write { // escape the closure itself, and the manager should only be // used once. fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef, - f: |PassManagerRef|) { + no_builtins: bool, f: |PassManagerRef|) { unsafe { let cpm = llvm::LLVMCreatePassManager(); llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod); - llvm::LLVMRustAddLibraryInfo(cpm, llmod); + llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); f(cpm); llvm::LLVMDisposePassManager(cpm); } @@ -286,7 +287,7 @@ pub mod write { } OutputTypeLlvmAssembly => { path.with_c_str(|output| { - with_codegen(tm, llmod, |cpm| { + with_codegen(tm, llmod, trans.no_builtins, |cpm| { llvm::LLVMRustPrintModule(cpm, llmod, output); }) }) @@ -303,7 +304,7 @@ pub mod write { needs_metadata = true; output.temp_path(OutputTypeAssembly) }; - with_codegen(tm, llmod, |cpm| { + with_codegen(tm, llmod, trans.no_builtins, |cpm| { WriteOutputFile(sess, tm, cpm, llmod, &path, lib::llvm::AssemblyFile); }); @@ -321,7 +322,7 @@ pub mod write { time(sess.time_passes(), "codegen passes", (), |()| { match object_file { Some(ref path) => { - with_codegen(tm, llmod, |cpm| { + with_codegen(tm, llmod, trans.no_builtins, |cpm| { WriteOutputFile(sess, tm, cpm, llmod, path, lib::llvm::ObjectFile); }); @@ -329,7 +330,8 @@ pub mod write { None => {} } if needs_metadata { - with_codegen(tm, trans.metadata_module, |cpm| { + with_codegen(tm, trans.metadata_module, + trans.no_builtins, |cpm| { let out = output.temp_path(OutputTypeObject) .with_extension("metadata.o"); WriteOutputFile(sess, tm, cpm, @@ -441,7 +443,8 @@ pub mod write { unsafe fn populate_llvm_passes(fpm: lib::llvm::PassManagerRef, mpm: lib::llvm::PassManagerRef, llmod: ModuleRef, - opt: lib::llvm::CodeGenOptLevel) { + opt: lib::llvm::CodeGenOptLevel, + no_builtins: bool) { // Create the PassManagerBuilder for LLVM. We configure it with // reasonable defaults and prepare it to actually populate the pass // manager. @@ -465,7 +468,7 @@ pub mod write { } } llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint); - llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod); + llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, no_builtins); // Use the builder to populate the function/module pass managers. llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm); diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 51bdf9ef9edd5..0b731e18f5574 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -356,6 +356,7 @@ pub struct CrateTranslation { pub metadata: Vec, pub reachable: Vec, pub crate_formats: dependency_format::Dependencies, + pub no_builtins: bool, } /// Run the translation phase to LLVM, after which the AST and analysis can diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 0c874bd776ed1..711081f46d666 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -1755,8 +1755,10 @@ pub mod llvm { PM: PassManagerRef, M: ModuleRef); pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef, - M: ModuleRef); - pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef); + M: ModuleRef, + DisableSimplifyLibCalls: bool); + pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef, + DisableSimplifyLibCalls: bool); pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef); pub fn LLVMRustWriteOutputFile(T: TargetMachineRef, PM: PassManagerRef, diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 062a7418287e3..1c24d609551ab 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -1050,6 +1050,7 @@ fn check_raw_ptr_deriving(cx: &mut Context, item: &ast::Item) { static crate_attrs: &'static [&'static str] = &[ "crate_type", "feature", "no_start", "no_main", "no_std", "crate_id", "desc", "comment", "license", "copyright", // not used in rustc now + "no_builtins", ]; diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 17aa0664d4794..92e3b95abadc1 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2226,6 +2226,7 @@ pub fn trans_crate(krate: ast::Crate, let metadata_module = ccx.metadata_llmod; let formats = ccx.tcx.dependency_formats.borrow().clone(); + let no_builtins = attr::contains_name(krate.attrs.as_slice(), "no_builtins"); (ccx.tcx, CrateTranslation { context: llcx, @@ -2235,5 +2236,6 @@ pub fn trans_crate(krate: ast::Crate, metadata: metadata, reachable: reachable, crate_formats: formats, + no_builtins: no_builtins, }) } diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 1031f3c1570e9..64776421fa145 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -128,17 +128,27 @@ LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM, // Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo` // field of a PassManagerBuilder, we expose our own method of doing so. extern "C" void -LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB, LLVMModuleRef M) { +LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB, + LLVMModuleRef M, + bool DisableSimplifyLibCalls) { Triple TargetTriple(unwrap(M)->getTargetTriple()); - unwrap(PMB)->LibraryInfo = new TargetLibraryInfo(TargetTriple); + TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple); + if (DisableSimplifyLibCalls) + TLI->disableAllFunctions(); + unwrap(PMB)->LibraryInfo = TLI; } // Unfortunately, the LLVM C API doesn't provide a way to create the // TargetLibraryInfo pass, so we use this method to do so. extern "C" void -LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, LLVMModuleRef M) { +LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, + LLVMModuleRef M, + bool DisableSimplifyLibCalls) { Triple TargetTriple(unwrap(M)->getTargetTriple()); - unwrap(PMB)->add(new TargetLibraryInfo(TargetTriple)); + TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple); + if (DisableSimplifyLibCalls) + TLI->disableAllFunctions(); + unwrap(PMB)->add(TLI); } // Unfortunately, the LLVM C API doesn't provide an easy way of iterating over