about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-11-15 01:27:47 -0800
committerGitHub <noreply@github.com>2016-11-15 01:27:47 -0800
commitc8867f8b46d804b463acc25e1ce31717ae5a4103 (patch)
tree5dc1f06b0f6b9ce44c67ff6e6fd2ce56518c2835
parent0ed951993fb5721a303ca5fa743543dd9f3f6b10 (diff)
parent80ca1e1251b634b8b9831aa999f3f7435ccfdd16 (diff)
downloadrust-c8867f8b46d804b463acc25e1ce31717ae5a4103.tar.gz
rust-c8867f8b46d804b463acc25e1ce31717ae5a4103.zip
Auto merge of #37672 - japaric:msp430, r=alexcrichton
enable the MSP430 LLVM backend

to let people experiment with this target out of tree.

The MSP430 architecture is used in 16-bit microcontrollers commonly used
in Digital Signal Processing applications.

---

How this was tested:

Declaring a custom target with the following specification:

``` json
{
  "arch": "msp430",
  "data-layout": "e-m:e-p:16:16-i32:16:32-a:16-n8:16",
  "executables": true,
  "linker": "msp430-gcc",
  "llvm-target": "msp430",
  "max-atomic-width": 0,
  "no-integrated-as": true,
  "os": "none",
  "panic-strategy": "abort",
  "relocation-model": "static",
  "target-endian": "little",
  "target-pointer-width": "16"
}
```

And this minimal file:

``` rust

pub fn start() -> ! {
    loop {}
}

trait Copy {}

trait Sized {}
```

Produces the following object files:

```
$ rustc --target=msp430 --emit=obj foo.rs

$ msp430-objdump -Cd foo.o

foo.o:     file format elf32-msp430

Disassembly of section .text.start:

00000000 <start>:
   0:   21 83           decd    r1
   2:   00 3c           jmp     $+2             ;abs 0x4
   4:   00 3c           jmp     $+2             ;abs 0x6
   6:   ff 3f           jmp     $+0             ;abs 0x6

$ rustc --target=msp430 --emit=obj foo.rs -O

$ msp430-objdump -Cd foo.o

foo.o:     file format elf32-msp430

Disassembly of section .text.start:

00000000 <start>:
   0:   ff 3f           jmp     $+0             ;abs 0x0
```

---

r? @alexcrichton
~~TODO get this working with Makefiles so nightly releases include this backend~~
~~TODO measure the increase in binary size~~ +187KiB (+0.47%)
~~FIXME --emit=obj produces empty object files~~
-rwxr-xr-xconfigure2
-rw-r--r--mk/main.mk2
-rw-r--r--src/bootstrap/native.rs3
-rw-r--r--src/librustc_back/target/mod.rs8
-rw-r--r--src/librustc_driver/driver.rs17
-rw-r--r--src/librustc_llvm/build.rs2
-rw-r--r--src/librustc_llvm/lib.rs5
-rw-r--r--src/librustc_trans/abi.rs2
-rw-r--r--src/librustc_trans/cabi_msp430.rs59
-rw-r--r--src/librustc_trans/lib.rs1
-rw-r--r--src/librustc_trans/mir/rvalue.rs2
-rw-r--r--src/rustllvm/PassWrapper.cpp9
12 files changed, 106 insertions, 6 deletions
diff --git a/configure b/configure
index 9c055e7217a..16d6a90bf39 100755
--- a/configure
+++ b/configure
@@ -1782,7 +1782,7 @@ do
         CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON"
     fi
 
-    CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend'"
+    CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430'"
     CMAKE_ARGS="$CMAKE_ARGS -G '$CFG_CMAKE_GENERATOR'"
     CMAKE_ARGS="$CMAKE_ARGS $CFG_LLVM_SRC_DIR"
 
diff --git a/mk/main.mk b/mk/main.mk
index 07b52593781..9936c5b59be 100644
--- a/mk/main.mk
+++ b/mk/main.mk
@@ -285,7 +285,7 @@ endif
 # LLVM macros
 ######################################################################
 
-LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend
+LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend msp430
 LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \
                 interpreter instrumentation
 
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 358cfac7427..96d1b695dd7 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -79,7 +79,8 @@ pub fn llvm(build: &Build, target: &str) {
        .out_dir(&dst)
        .profile(profile)
        .define("LLVM_ENABLE_ASSERTIONS", assertions)
-       .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend")
+       .define("LLVM_TARGETS_TO_BUILD",
+               "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430")
        .define("LLVM_INCLUDE_EXAMPLES", "OFF")
        .define("LLVM_INCLUDE_TESTS", "OFF")
        .define("LLVM_INCLUDE_DOCS", "OFF")
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index 14fe02269d1..cc04582b19e 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -359,6 +359,11 @@ pub struct TargetOptions {
     // will 'just work'.
     pub obj_is_bitcode: bool,
 
+    // LLVM can't produce object files for this target. Instead, we'll make LLVM
+    // emit assembly and then use `gcc` to turn that assembly into an object
+    // file
+    pub no_integrated_as: bool,
+
     /// Don't use this field; instead use the `.max_atomic_width()` method.
     pub max_atomic_width: Option<u64>,
 
@@ -416,6 +421,7 @@ impl Default for TargetOptions {
             allow_asm: true,
             has_elf_tls: false,
             obj_is_bitcode: false,
+            no_integrated_as: false,
             max_atomic_width: None,
             panic_strategy: PanicStrategy::Unwind,
             abi_blacklist: vec![],
@@ -576,6 +582,7 @@ impl Target {
         key!(exe_allocation_crate);
         key!(has_elf_tls, bool);
         key!(obj_is_bitcode, bool);
+        key!(no_integrated_as, bool);
         key!(max_atomic_width, Option<u64>);
         try!(key!(panic_strategy, PanicStrategy));
 
@@ -735,6 +742,7 @@ impl ToJson for Target {
         target_option_val!(exe_allocation_crate);
         target_option_val!(has_elf_tls);
         target_option_val!(obj_is_bitcode);
+        target_option_val!(no_integrated_as);
         target_option_val!(max_atomic_width);
         target_option_val!(panic_strategy);
 
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index d8391849567..2dd83f70823 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -1056,7 +1056,11 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 pub fn phase_5_run_llvm_passes(sess: &Session,
                                trans: &trans::CrateTranslation,
                                outputs: &OutputFilenames) -> CompileResult {
-    if sess.opts.cg.no_integrated_as {
+    if sess.opts.cg.no_integrated_as ||
+        (sess.target.target.options.no_integrated_as &&
+         (outputs.outputs.contains_key(&OutputType::Object) ||
+          outputs.outputs.contains_key(&OutputType::Exe)))
+    {
         let output_types = OutputTypes::new(&[(OutputType::Assembly, None)]);
         time(sess.time_passes(),
              "LLVM passes",
@@ -1064,6 +1068,17 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
 
         write::run_assembler(sess, outputs);
 
+        // HACK the linker expects the object file to be named foo.0.o but
+        // `run_assembler` produces an object named just foo.o. Rename it if we
+        // are going to build an executable
+        if sess.opts.output_types.contains_key(&OutputType::Exe) {
+            let f = outputs.path(OutputType::Object);
+            fs::copy(&f,
+                     f.with_file_name(format!("{}.0.o",
+                                              f.file_stem().unwrap().to_string_lossy()))).unwrap();
+            fs::remove_file(f).unwrap();
+        }
+
         // Remove assembly source, unless --save-temps was specified
         if !sess.opts.cg.save_temps {
             fs::remove_file(&outputs.temp_path(OutputType::Assembly, None)).unwrap();
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index 8656bb8bf00..ca80a5269c9 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -66,7 +66,7 @@ fn main() {
     let is_crossed = target != host;
 
     let optional_components =
-        ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend"];
+        ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430"];
 
     // FIXME: surely we don't need all these components, right? Stuff like mcjit
     //        or interpreter the compiler itself never uses.
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 07b87072c43..65e0dbcad3a 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -413,6 +413,11 @@ pub fn initialize_available_targets() {
                  LLVMInitializeJSBackendTargetInfo,
                  LLVMInitializeJSBackendTarget,
                  LLVMInitializeJSBackendTargetMC);
+    init_target!(llvm_component = "msp430",
+                 LLVMInitializeMSP430TargetInfo,
+                 LLVMInitializeMSP430Target,
+                 LLVMInitializeMSP430TargetMC,
+                 LLVMInitializeMSP430AsmPrinter);
 }
 
 pub fn last_error() -> Option<String> {
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 0a5b013c79a..f2e15a8973c 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -24,6 +24,7 @@ use cabi_s390x;
 use cabi_mips;
 use cabi_mips64;
 use cabi_asmjs;
+use cabi_msp430;
 use machine::{llalign_of_min, llsize_of, llsize_of_alloc};
 use type_::Type;
 use type_of;
@@ -520,6 +521,7 @@ impl FnType {
             "s390x" => cabi_s390x::compute_abi_info(ccx, self),
             "asmjs" => cabi_asmjs::compute_abi_info(ccx, self),
             "wasm32" => cabi_asmjs::compute_abi_info(ccx, self),
+            "msp430" => cabi_msp430::compute_abi_info(ccx, self),
             a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
         }
 
diff --git a/src/librustc_trans/cabi_msp430.rs b/src/librustc_trans/cabi_msp430.rs
new file mode 100644
index 00000000000..aa90bb7ab75
--- /dev/null
+++ b/src/librustc_trans/cabi_msp430.rs
@@ -0,0 +1,59 @@
+// Copyright 2012-2013 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.
+
+// Reference: MSP430 Embedded Application Binary Interface
+// http://www.ti.com/lit/an/slaa534/slaa534.pdf
+
+#![allow(non_upper_case_globals)]
+
+use llvm::Struct;
+
+use abi::{self, ArgType, FnType};
+use context::CrateContext;
+use type_::Type;
+
+fn ty_size(ty: Type) -> usize {
+    abi::ty_size(ty, 2)
+}
+
+// 3.5 Structures or Unions Passed and Returned by Reference
+//
+// "Structures (including classes) and unions larger than 32 bits are passed and
+// returned by reference. To pass a structure or union by reference, the caller
+// places its address in the appropriate location: either in a register or on
+// the stack, according to its position in the argument list. (..)"
+fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+    if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 {
+        ret.make_indirect(ccx);
+    } else {
+        ret.extend_integer_width_to(16);
+    }
+}
+
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
+    if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 {
+        arg.make_indirect(ccx);
+    } else {
+        arg.extend_integer_width_to(16);
+    }
+}
+
+pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(ccx, &mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg_ty(ccx, arg);
+    }
+}
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 0757343a8af..611b93d2de1 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -101,6 +101,7 @@ mod cabi_arm;
 mod cabi_asmjs;
 mod cabi_mips;
 mod cabi_mips64;
+mod cabi_msp430;
 mod cabi_powerpc;
 mod cabi_powerpc64;
 mod cabi_s390x;
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index bf01db0ffd3..15cbbc720d6 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -720,11 +720,13 @@ fn get_overflow_intrinsic(oop: OverflowOp, bcx: &BlockAndBuilder, ty: Ty) -> Val
 
     let new_sty = match ty.sty {
         TyInt(Is) => match &tcx.sess.target.target.target_pointer_width[..] {
+            "16" => TyInt(I16),
             "32" => TyInt(I32),
             "64" => TyInt(I64),
             _ => panic!("unsupported target word size")
         },
         TyUint(Us) => match &tcx.sess.target.target.target_pointer_width[..] {
+            "16" => TyUint(U16),
             "32" => TyUint(U32),
             "64" => TyUint(U64),
             _ => panic!("unsupported target word size")
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 60093e9bd37..a5ba1d219c3 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -137,13 +137,20 @@ LLVMRustAddPass(LLVMPassManagerRef PM, LLVMPassRef rust_pass) {
 #define SUBTARGET_SYSTEMZ
 #endif
 
+#ifdef LLVM_COMPONENT_MSP430
+#define SUBTARGET_MSP430 SUBTARGET(MSP430)
+#else
+#define SUBTARGET_MSP430
+#endif
+
 #define GEN_SUBTARGETS    \
         SUBTARGET_X86     \
         SUBTARGET_ARM     \
         SUBTARGET_AARCH64 \
         SUBTARGET_MIPS    \
         SUBTARGET_PPC     \
-        SUBTARGET_SYSTEMZ
+        SUBTARGET_SYSTEMZ \
+        SUBTARGET_MSP430
 
 #define SUBTARGET(x) namespace llvm {                \
     extern const SubtargetFeatureKV x##FeatureKV[];  \