Skip to content

Commit

Permalink
Auto merge of #38314 - japaric:do-not-delete-enable-llvm-backend, r=a…
Browse files Browse the repository at this point in the history
…lexcrichton

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](https://github.com/rust-lang/llvm/blob/ac1c94226e9fa17005ce7e2dd52dd6d1875f3137/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
  • Loading branch information
bors committed Dec 26, 2016
2 parents f536d90 + 3ae912a commit b7e5148
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/bootstrap/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_llvm/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 6 additions & 0 deletions src/librustc_llvm/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
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_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;
Expand Down Expand Up @@ -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))
}

Expand Down
108 changes: 108 additions & 0 deletions src/librustc_trans/cabi_sparc.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
1 change: 1 addition & 0 deletions src/librustc_trans/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/rustllvm/llvm-auto-clean-trigger
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit b7e5148

Please sign in to comment.