about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-05-14 11:24:12 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-05-15 13:50:37 -0700
commita7bee7b05d59467bc6304b32eb14e617c2efbfc9 (patch)
tree99c06196f44ecfcebfaace1827cea6e6befa119f
parente043644cea119ea701a293a01b6d4c5c0f13f450 (diff)
downloadrust-a7bee7b05d59467bc6304b32eb14e617c2efbfc9.tar.gz
rust-a7bee7b05d59467bc6304b32eb14e617c2efbfc9.zip
Add a crate for missing stubs from libcore
The core library in theory has 0 dependencies, but in practice it has some in
order for it to be efficient. These dependencies are in the form of the basic
memory operations provided by libc traditionally, such as memset, memcmp, etc.
These functions are trivial to implement and themselves have 0 dependencies.

This commit adds a new crate, librlibc, which will serve the purpose of
providing these dependencies. The crate is never linked to by default, but is
available to be linked to by downstream consumers. Normally these functions are
provided by the system libc, but in other freestanding contexts a libc may not
be available. In these cases, librlibc will suffice for enabling execution with
libcore.

cc #10116
-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