Skip to content

Commit

Permalink
Auto merge of rust-lang#37672 - japaric:msp430, r=alexcrichton
Browse files Browse the repository at this point in the history
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~~
  • Loading branch information
bors authored Nov 15, 2016
2 parents 0ed9519 + 80ca1e1 commit c8867f8
Show file tree
Hide file tree
Showing 12 changed files with 106 additions and 6 deletions.
2 changes: 1 addition & 1 deletion configure
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
2 changes: 1 addition & 1 deletion mk/main.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 2 additions & 1 deletion src/bootstrap/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
8 changes: 8 additions & 0 deletions src/librustc_back/target/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,

Expand Down Expand Up @@ -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![],
Expand Down Expand Up @@ -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));

Expand Down Expand Up @@ -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);

Expand Down
17 changes: 16 additions & 1 deletion src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1056,14 +1056,29 @@ 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",
|| write::run_passes(sess, trans, &output_types, outputs));

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();
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_llvm/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_llvm/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_trans/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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))
}

Expand Down
59 changes: 59 additions & 0 deletions src/librustc_trans/cabi_msp430.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
1 change: 1 addition & 0 deletions src/librustc_trans/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_trans/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
9 changes: 8 additions & 1 deletion src/rustllvm/PassWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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[]; \
Expand Down

0 comments on commit c8867f8

Please sign in to comment.