Skip to content

Commit b7e5148

Browse files
committed
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](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
2 parents f536d90 + 3ae912a commit b7e5148

File tree

7 files changed

+121
-3
lines changed

7 files changed

+121
-3
lines changed

src/bootstrap/native.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub fn llvm(build: &Build, target: &str) {
8181
.profile(profile)
8282
.define("LLVM_ENABLE_ASSERTIONS", assertions)
8383
.define("LLVM_TARGETS_TO_BUILD",
84-
"X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430")
84+
"X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc")
8585
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
8686
.define("LLVM_INCLUDE_TESTS", "OFF")
8787
.define("LLVM_INCLUDE_DOCS", "OFF")

src/librustc_llvm/build.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ fn main() {
9595
let is_crossed = target != host;
9696

9797
let optional_components =
98-
["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430"];
98+
["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430",
99+
"sparc"];
99100

100101
// FIXME: surely we don't need all these components, right? Stuff like mcjit
101102
// or interpreter the compiler itself never uses.

src/librustc_llvm/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,12 @@ pub fn initialize_available_targets() {
371371
LLVMInitializeMSP430Target,
372372
LLVMInitializeMSP430TargetMC,
373373
LLVMInitializeMSP430AsmPrinter);
374+
init_target!(llvm_component = "sparc",
375+
LLVMInitializeSparcTargetInfo,
376+
LLVMInitializeSparcTarget,
377+
LLVMInitializeSparcTargetMC,
378+
LLVMInitializeSparcAsmPrinter,
379+
LLVMInitializeSparcAsmParser);
374380
}
375381

376382
pub fn last_error() -> Option<String> {

src/librustc_trans/abi.rs

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use cabi_mips;
2424
use cabi_mips64;
2525
use cabi_asmjs;
2626
use cabi_msp430;
27+
use cabi_sparc;
2728
use machine::{llalign_of_min, llsize_of, llsize_of_alloc};
2829
use type_::Type;
2930
use type_of;
@@ -606,6 +607,7 @@ impl FnType {
606607
"asmjs" => cabi_asmjs::compute_abi_info(ccx, self),
607608
"wasm32" => cabi_asmjs::compute_abi_info(ccx, self),
608609
"msp430" => cabi_msp430::compute_abi_info(ccx, self),
610+
"sparc" => cabi_sparc::compute_abi_info(ccx, self),
609611
a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
610612
}
611613

src/librustc_trans/cabi_sparc.rs

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(non_upper_case_globals)]
12+
13+
use libc::c_uint;
14+
use std::cmp;
15+
use llvm;
16+
use llvm::{Integer, Pointer, Float, Double, Vector};
17+
use abi::{self, align_up_to, ArgType, FnType};
18+
use context::CrateContext;
19+
use type_::Type;
20+
21+
fn ty_align(ty: Type) -> usize {
22+
abi::ty_align(ty, 4)
23+
}
24+
25+
fn ty_size(ty: Type) -> usize {
26+
abi::ty_size(ty, 4)
27+
}
28+
29+
fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
30+
if is_reg_ty(ret.ty) {
31+
ret.extend_integer_width_to(32);
32+
} else {
33+
ret.make_indirect(ccx);
34+
}
35+
}
36+
37+
fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
38+
let orig_offset = *offset;
39+
let size = ty_size(arg.ty) * 8;
40+
let mut align = ty_align(arg.ty);
41+
42+
align = cmp::min(cmp::max(align, 4), 8);
43+
*offset = align_up_to(*offset, align);
44+
*offset += align_up_to(size, align * 8) / 8;
45+
46+
if !is_reg_ty(arg.ty) {
47+
arg.cast = Some(struct_ty(ccx, arg.ty));
48+
arg.pad = padding_ty(ccx, align, orig_offset);
49+
} else {
50+
arg.extend_integer_width_to(32);
51+
}
52+
}
53+
54+
fn is_reg_ty(ty: Type) -> bool {
55+
return match ty.kind() {
56+
Integer
57+
| Pointer
58+
| Float
59+
| Double
60+
| Vector => true,
61+
_ => false
62+
};
63+
}
64+
65+
fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
66+
if ((align - 1 ) & offset) > 0 {
67+
Some(Type::i32(ccx))
68+
} else {
69+
None
70+
}
71+
}
72+
73+
fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
74+
let int_ty = Type::i32(ccx);
75+
let mut args = Vec::new();
76+
77+
let mut n = size / 32;
78+
while n > 0 {
79+
args.push(int_ty);
80+
n -= 1;
81+
}
82+
83+
let r = size % 32;
84+
if r > 0 {
85+
unsafe {
86+
args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
87+
}
88+
}
89+
90+
args
91+
}
92+
93+
fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
94+
let size = ty_size(ty) * 8;
95+
Type::struct_(ccx, &coerce_to_int(ccx, size), false)
96+
}
97+
98+
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
99+
if !fty.ret.is_ignore() {
100+
classify_ret_ty(ccx, &mut fty.ret);
101+
}
102+
103+
let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
104+
for arg in &mut fty.args {
105+
if arg.is_ignore() { continue; }
106+
classify_arg_ty(ccx, arg, &mut offset);
107+
}
108+
}

src/librustc_trans/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ mod cabi_msp430;
106106
mod cabi_powerpc;
107107
mod cabi_powerpc64;
108108
mod cabi_s390x;
109+
mod cabi_sparc;
109110
mod cabi_x86;
110111
mod cabi_x86_64;
111112
mod cabi_x86_win64;

src/rustllvm/llvm-auto-clean-trigger

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

0 commit comments

Comments
 (0)