Auto merge of #38314 - japaric:do-not-delete-enable-llvm-backend, r=alexcrichton

initial SPARC support

### UPDATE

Can now compile `no_std` executables with:

```
$ cargo new --bin app && cd $_

$ edit Cargo.toml && tail -n2 $_
[dependencies]
core = { path = "/path/to/rust/src/libcore" }

$ edit src/main.rs && cat $_
#![feature(lang_items)]
#![no_std]
#![no_main]

#[no_mangle]
pub fn _start() -> ! {
    loop {}
}

#[lang = "panic_fmt"]
fn panic_fmt() -> ! {
    loop {}
}

$ edit sparc-none-elf.json && cat $_
{
  "arch": "sparc",
  "data-layout": "E-m:e-p:32:32-i64:64-f128:64-n32-S64",
  "executables": true,
  "llvm-target": "sparc",
  "os": "none",
  "panic-strategy": "abort",
  "target-endian": "big",
  "target-pointer-width": "32"
}

$ cargo rustc --target sparc-none-elf -- -C linker=sparc-unknown-elf-gcc -C link-args=-nostartfiles

$ file target/sparc-none-elf/debug/app
app: ELF 32-bit MSB executable, SPARC, version 1 (SYSV), statically linked, not stripped

$ sparc-unknown-elf-readelf -h target/sparc-none-elf/debug/app
ELF Header:
  Magic:   7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, big endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Sparc
  Version:                           0x1
  Entry point address:               0x10074
  Start of program headers:          52 (bytes into file)
  Start of section headers:          1188 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         14
  Section header string table index: 11

$ sparc-unknown-elf-objdump -Cd target/sparc-none-elf/debug/app

target/sparc-none-elf/debug/app:     file format elf32-sparc

Disassembly of section .text:

00010074 <_start>:
   10074:       9d e3 bf 98     save  %sp, -104, %sp
   10078:       10 80 00 02     b  10080 <_start+0xc>
   1007c:       01 00 00 00     nop
   10080:       10 80 00 02     b  10088 <_start+0x14>
   10084:       01 00 00 00     nop
   10088:       10 80 00 00     b  10088 <_start+0x14>
   1008c:       01 00 00 00     nop
```

---

Someone wants to attempt launching some Rust [into space](https://www.reddit.com/r/rust/comments/5h76oa/c_interop/) but their platform is based on the SPARCv8 architecture. Let's not block them by enabling LLVM's SPARC backend.

Something very important that they'll also need is the "cabi" stuff as they'll be embedding some Rust code into a bigger C application (i.e. heavy use of `extern "C"`). The question there is what name(s) should we use for "target_arch" as the "cabi" implementation [varies according to that parameter](https://github.com/rust-lang/rust/blob/1.13.0/src/librustc_trans/abi.rs#L498-L523).

AFAICT, SPARCv8 is a 32-bit architecture and SPARCv9 is a 64-bit architecture. And, LLVM uses `sparc`, `sparcv9` and `sparcel` for [the architecture triple](ac1c94226e/include/llvm/ADT/Triple.h (L67-L69)) so perhaps we should use `target_arch = "sparc"` (32-bit) and `target_arch = "sparcv9"` (64-bit) as well.

r? @alexcrichton This PR only enables this LLVM backend when rustbuild is used. Do I also need to implement this for the old Makefile-based build system? Or are all our nightlies now being generated using rustbuild?

cc @brson
This commit is contained in:
bors 2016-12-26 20:48:43 +00:00
commit b7e5148bbd
7 changed files with 121 additions and 3 deletions

View File

@ -81,7 +81,7 @@ pub fn llvm(build: &Build, target: &str) {
.profile(profile)
.define("LLVM_ENABLE_ASSERTIONS", assertions)
.define("LLVM_TARGETS_TO_BUILD",
"X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430")
"X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc")
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
.define("LLVM_INCLUDE_TESTS", "OFF")
.define("LLVM_INCLUDE_DOCS", "OFF")

View File

@ -95,7 +95,8 @@ fn main() {
let is_crossed = target != host;
let optional_components =
["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430"];
["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430",
"sparc"];
// FIXME: surely we don't need all these components, right? Stuff like mcjit
// or interpreter the compiler itself never uses.

View File

@ -371,6 +371,12 @@ pub fn initialize_available_targets() {
LLVMInitializeMSP430Target,
LLVMInitializeMSP430TargetMC,
LLVMInitializeMSP430AsmPrinter);
init_target!(llvm_component = "sparc",
LLVMInitializeSparcTargetInfo,
LLVMInitializeSparcTarget,
LLVMInitializeSparcTargetMC,
LLVMInitializeSparcAsmPrinter,
LLVMInitializeSparcAsmParser);
}
pub fn last_error() -> Option<String> {

View File

@ -24,6 +24,7 @@ use cabi_mips;
use cabi_mips64;
use cabi_asmjs;
use cabi_msp430;
use cabi_sparc;
use machine::{llalign_of_min, llsize_of, llsize_of_alloc};
use type_::Type;
use type_of;
@ -606,6 +607,7 @@ impl FnType {
"asmjs" => cabi_asmjs::compute_abi_info(ccx, self),
"wasm32" => cabi_asmjs::compute_abi_info(ccx, self),
"msp430" => cabi_msp430::compute_abi_info(ccx, self),
"sparc" => cabi_sparc::compute_abi_info(ccx, self),
a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
}

View File

@ -0,0 +1,108 @@
// 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.
#![allow(non_upper_case_globals)]
use libc::c_uint;
use std::cmp;
use llvm;
use llvm::{Integer, Pointer, Float, Double, Vector};
use abi::{self, align_up_to, ArgType, FnType};
use context::CrateContext;
use type_::Type;
fn ty_align(ty: Type) -> usize {
abi::ty_align(ty, 4)
}
fn ty_size(ty: Type) -> usize {
abi::ty_size(ty, 4)
}
fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
if is_reg_ty(ret.ty) {
ret.extend_integer_width_to(32);
} else {
ret.make_indirect(ccx);
}
}
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
let orig_offset = *offset;
let size = ty_size(arg.ty) * 8;
let mut align = ty_align(arg.ty);
align = cmp::min(cmp::max(align, 4), 8);
*offset = align_up_to(*offset, align);
*offset += align_up_to(size, align * 8) / 8;
if !is_reg_ty(arg.ty) {
arg.cast = Some(struct_ty(ccx, arg.ty));
arg.pad = padding_ty(ccx, align, orig_offset);
} else {
arg.extend_integer_width_to(32);
}
}
fn is_reg_ty(ty: Type) -> bool {
return match ty.kind() {
Integer
| Pointer
| Float
| Double
| Vector => true,
_ => false
};
}
fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
if ((align - 1 ) & offset) > 0 {
Some(Type::i32(ccx))
} else {
None
}
}
fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
let int_ty = Type::i32(ccx);
let mut args = Vec::new();
let mut n = size / 32;
while n > 0 {
args.push(int_ty);
n -= 1;
}
let r = size % 32;
if r > 0 {
unsafe {
args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
}
}
args
}
fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
let size = ty_size(ty) * 8;
Type::struct_(ccx, &coerce_to_int(ccx, size), false)
}
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
if !fty.ret.is_ignore() {
classify_ret_ty(ccx, &mut fty.ret);
}
let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
for arg in &mut fty.args {
if arg.is_ignore() { continue; }
classify_arg_ty(ccx, arg, &mut offset);
}
}

View File

@ -106,6 +106,7 @@ mod cabi_msp430;
mod cabi_powerpc;
mod cabi_powerpc64;
mod cabi_s390x;
mod cabi_sparc;
mod cabi_x86;
mod cabi_x86_64;
mod cabi_x86_win64;

View File

@ -1,4 +1,4 @@
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
2016-12-16
2016-12-19