about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--mk/crates.mk4
-rw-r--r--src/doc/rust.md2
-rw-r--r--src/libcore/lib.rs3
-rw-r--r--src/librlibc/lib.rs99
-rw-r--r--src/librustc/back/link.rs21
-rw-r--r--src/librustc/driver/driver.rs1
-rw-r--r--src/librustc/lib/llvm.rs6
-rw-r--r--src/librustc/middle/lint.rs1
-rw-r--r--src/librustc/middle/trans/base.rs2
-rw-r--r--src/rustllvm/PassWrapper.cpp18
10 files changed, 141 insertions, 16 deletions
diff --git a/mk/crates.mk b/mk/crates.mk
index 0b923cca7a2..b43accf6104 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 f242a89784c..838ddca042d 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 9e3a92981e5..4102c72d8b6 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 00000000000..904fbe9be9b
--- /dev/null
+++ b/src/librlibc/lib.rs
@@ -0,0 +1,99 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T>(dst: *T, offset: int) -> *T;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *u8, n: uint) -> *mut u8 {
+    let mut i = 0;
+    while i < n {
+        *(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int);
+        i += 1;
+    }
+    return dest;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memmove(dest: *mut u8, src: *u8, n: uint) -> *mut u8 {
+    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;
+        }
+    }
+    return dest;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: uint) -> *mut u8 {
+    let mut i = 0;
+    while i < n {
+        *(offset(s as *u8, i as int) as *mut u8) = c as u8;
+        i += 1;
+    }
+    return s;
+}
+
+#[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 4d70ecb888f..429a8f5be5e 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,
@@ -437,7 +439,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.
@@ -461,7 +464,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 51bdf9ef9ed..0b731e18f55 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -356,6 +356,7 @@ pub struct CrateTranslation {
     pub metadata: Vec<u8>,
     pub reachable: Vec<StrBuf>,
     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 0c874bd776e..711081f46d6 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 062a7418287..1c24d609551 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 17aa0664d47..92e3b95abad 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 1031f3c1570..64776421fa1 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