Skip to content

[DoNotMerge][WIP] add support for thumb* (Cortex-M) targets #36526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mk/cfg/thumbv6m-none-eabi.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# rustbuild-only target
1 change: 1 addition & 0 deletions mk/cfg/thumbv7em-none-eabi.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# rustbuild-only target
1 change: 1 addition & 0 deletions mk/cfg/thumbv7em-none-eabihf.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# rustbuild-only target
1 change: 1 addition & 0 deletions mk/cfg/thumbv7m-none-eabi.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# rustbuild-only target
2 changes: 1 addition & 1 deletion src/bootstrap/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ pub fn krate(build: &Build,
target: &str,
mode: Mode) {
let (name, path, features) = match mode {
Mode::Libstd => ("libstd", "src/rustc/std_shim", build.std_features()),
Mode::Libstd => ("libstd", "src/rustc/std_shim", build.std_features(target)),
Mode::Libtest => ("libtest", "src/rustc/test_shim", String::new()),
Mode::Librustc => ("librustc", "src/rustc", build.rustc_features()),
_ => panic!("can only test libraries"),
Expand Down
2 changes: 1 addition & 1 deletion src/bootstrap/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
build.clear_if_dirty(&out_dir, &build.compiler_path(compiler));
let mut cargo = build.cargo(compiler, Mode::Libstd, target, "build");
cargo.arg("--features").arg(build.std_features())
cargo.arg("--features").arg(build.std_features(target))
.arg("--manifest-path")
.arg(build.src.join("src/rustc/std_shim/Cargo.toml"));

Expand Down
2 changes: 1 addition & 1 deletion src/bootstrap/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ pub fn std(build: &Build, stage: u32, target: &str, out: &Path) {
let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc");
cargo.arg("--manifest-path")
.arg(build.src.join("src/rustc/std_shim/Cargo.toml"))
.arg("--features").arg(build.std_features());
.arg("--features").arg(build.std_features(target));
build.run(&mut cargo);
cp_r(&out_dir, out)
}
Expand Down
28 changes: 19 additions & 9 deletions src/bootstrap/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -712,17 +712,27 @@ impl Build {

/// Get the space-separated set of activated features for the standard
/// library.
fn std_features(&self) -> String {
fn std_features(&self, target: &str) -> String {
let mut features = String::new();
if self.config.debug_jemalloc {
features.push_str(" debug-jemalloc");
}
if self.config.use_jemalloc {
features.push_str(" jemalloc");
}
if self.config.backtrace {
features.push_str(" backtrace");

if target.starts_with("thumbv6m") {
features.push_str(" thumb_no_atomics");
} else if target.starts_with("thumb") {
features.push_str(" thumb");
} else {
features.push_str("full");

if self.config.debug_jemalloc {
features.push_str(" debug-jemalloc");
}
if self.config.use_jemalloc {
features.push_str(" jemalloc");
}
if self.config.backtrace {
features.push_str(" backtrace");
}
}

return features
}

Expand Down
1 change: 1 addition & 0 deletions src/libcompiler_builtins/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ core = { path = "../libcore" }

[build-dependencies]
gcc = "0.3.27"
rustc-cfg = { git = "https://github.com/japaric/rustc-cfg", branch = "llvm-target" }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this may be something that should be in gcc-rs, but maybe I'm missing something? Couldn't we just look at $TARGET like we do for other platforms?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is from #36512. Check that PR for context.

153 changes: 104 additions & 49 deletions src/libcompiler_builtins/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@
//! far far less than working with compiler-rt's build system over time.

extern crate gcc;
extern crate rustc_cfg;

use std::collections::BTreeMap;
use std::env;
use std::path::Path;

use rustc_cfg::Cfg;

struct Sources {
// SYMBOL -> PATH TO SOURCE
map: BTreeMap<&'static str, &'static str>,
Expand Down Expand Up @@ -69,13 +72,33 @@ impl Sources {
}
}
}

fn remove(&mut self, symbols: &[&str]) {
for symbol in symbols {
self.map.remove(*symbol).unwrap();
}
}
}

fn main() {
let target = env::var("TARGET").unwrap();
let Cfg {
ref llvm_target,
ref target_arch,
ref target_os,
ref target_env,
ref target_vendor,
..
} = Cfg::new(&target).unwrap();
// TODO(stage0) use `unwrap` instead of `unwrap_or`
// NOTE in the latest stable/beta release, `rustc --print cfg` doesn't include `llvm_target` in
// its output. In those cases simply fallback to the target triple, which is usually similar to
// llvm-target, as a workaround.
let llvm_target = llvm_target.as_ref().unwrap_or(&target).split('-').collect::<Vec<_>>();
let target_vendor = target_vendor.as_ref().unwrap();
let cfg = &mut gcc::Config::new();

if target.contains("msvc") {
if target_env == "msvc" {
// Don't pull in extra libraries on MSVC
cfg.flag("/Zl");

Expand All @@ -90,6 +113,25 @@ fn main() {
cfg.flag("-ffreestanding");
}

// NOTE Most of the ARM intrinsics are written in assembly. Tell gcc which arch we are going to
// target to make sure that the assembly implementations really work for the target. If the
// implementation is not valid for the arch, then gcc will error when compiling it.
if llvm_target[0].starts_with("thumb") {
cfg.flag("-mthumb");
}

if llvm_target[0] == "thumbv6m" {
cfg.flag("-march=armv6-m");
}

if llvm_target[0] == "thumbv7m" {
cfg.flag("-march=armv7-m");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic should end up in gcc-rs, right?

}

if llvm_target[0] == "thumbv7em" {
cfg.flag("-march=armv7e-m");
}

let mut sources = Sources::new();
sources.extend(&["absvdi2.c",
"absvsi2.c",
Expand Down Expand Up @@ -183,7 +225,7 @@ fn main() {
"umoddi3.c",
"umodsi3.c"]);

if !target.contains("ios") {
if target_os != "ios" {
sources.extend(&["absvti2.c",
"addtf3.c",
"addvti3.c",
Expand Down Expand Up @@ -226,7 +268,7 @@ fn main() {
"umodti3.c"]);
}

if target.contains("apple") {
if target_vendor == "apple" {
sources.extend(&["atomic_flag_clear.c",
"atomic_flag_clear_explicit.c",
"atomic_flag_test_and_set.c",
Expand All @@ -235,20 +277,20 @@ fn main() {
"atomic_thread_fence.c"]);
}

if !target.contains("windows") {
if target_os != "windows" && target_os != "none" {
sources.extend(&["emutls.c"]);
}

if target.contains("msvc") {
if target.contains("x86_64") {
if target_env == "msvc" {
if llvm_target[0] == "x86_64" {
sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]);
}
} else {
if !target.contains("freebsd") {
if target_os != "freebsd" {
sources.extend(&["gcc_personality_v0.c"]);
}

if target.contains("x86_64") {
if target_arch == "x86_64" {
sources.extend(&["x86_64/chkstk.S",
"x86_64/chkstk2.S",
"x86_64/floatdidf.c",
Expand All @@ -259,7 +301,7 @@ fn main() {
"x86_64/floatundixf.S"]);
}

if target.contains("i386") || target.contains("i586") || target.contains("i686") {
if llvm_target[0] == "i386" || llvm_target[0] == "i586" || llvm_target[0] == "i686" {
sources.extend(&["i386/ashldi3.S",
"i386/ashrdi3.S",
"i386/chkstk.S",
Expand All @@ -279,7 +321,7 @@ fn main() {
}
}

if target.contains("arm") && !target.contains("ios") {
if target_arch == "arm" && target_os != "ios" {
sources.extend(&["arm/aeabi_cdcmp.S",
"arm/aeabi_cdcmpeq_check_nan.c",
"arm/aeabi_cfcmp.S",
Expand Down Expand Up @@ -315,7 +357,7 @@ fn main() {
"arm/umodsi3.S"]);
}

if target.contains("armv7") {
if llvm_target[0] == "armv7" {
sources.extend(&["arm/sync_fetch_and_add_4.S",
"arm/sync_fetch_and_add_8.S",
"arm/sync_fetch_and_and_4.S",
Expand All @@ -338,46 +380,47 @@ fn main() {
"arm/sync_fetch_and_xor_8.S"]);
}

if target.contains("eabihf") {
sources.extend(&["arm/adddf3vfp.S",
"arm/addsf3vfp.S",
"arm/divdf3vfp.S",
"arm/divsf3vfp.S",
"arm/eqdf2vfp.S",
"arm/eqsf2vfp.S",
"arm/extendsfdf2vfp.S",
"arm/fixdfsivfp.S",
"arm/fixsfsivfp.S",
"arm/fixunsdfsivfp.S",
"arm/fixunssfsivfp.S",
"arm/floatsidfvfp.S",
"arm/floatsisfvfp.S",
"arm/floatunssidfvfp.S",
"arm/floatunssisfvfp.S",
"arm/gedf2vfp.S",
"arm/gesf2vfp.S",
"arm/gtdf2vfp.S",
"arm/gtsf2vfp.S",
"arm/ledf2vfp.S",
"arm/lesf2vfp.S",
"arm/ltdf2vfp.S",
"arm/ltsf2vfp.S",
"arm/muldf3vfp.S",
"arm/mulsf3vfp.S",
"arm/negdf2vfp.S",
"arm/negsf2vfp.S",
"arm/nedf2vfp.S",
"arm/nesf2vfp.S",
"arm/restore_vfp_d8_d15_regs.S",
"arm/save_vfp_d8_d15_regs.S",
"arm/subdf3vfp.S",
"arm/subsf3vfp.S",
"arm/truncdfsf2vfp.S",
"arm/unorddf2vfp.S",
"arm/unordsf2vfp.S"]);
if llvm_target.last().unwrap().ends_with("eabihf") {
if !llvm_target[0].starts_with("thumbv7em") {
sources.extend(&["arm/adddf3vfp.S",
"arm/addsf3vfp.S",
"arm/divdf3vfp.S",
"arm/divsf3vfp.S",
"arm/eqdf2vfp.S",
"arm/eqsf2vfp.S",
"arm/extendsfdf2vfp.S",
"arm/fixdfsivfp.S",
"arm/fixsfsivfp.S",
"arm/fixunsdfsivfp.S",
"arm/fixunssfsivfp.S",
"arm/floatsidfvfp.S",
"arm/floatsisfvfp.S",
"arm/floatunssidfvfp.S",
"arm/floatunssisfvfp.S",
"arm/gedf2vfp.S",
"arm/gesf2vfp.S",
"arm/gtdf2vfp.S",
"arm/gtsf2vfp.S",
"arm/ledf2vfp.S",
"arm/lesf2vfp.S",
"arm/ltdf2vfp.S",
"arm/ltsf2vfp.S",
"arm/muldf3vfp.S",
"arm/mulsf3vfp.S",
"arm/nedf2vfp.S",
"arm/nesf2vfp.S",
"arm/restore_vfp_d8_d15_regs.S",
"arm/save_vfp_d8_d15_regs.S",
"arm/subdf3vfp.S",
"arm/subsf3vfp.S",
]);
}

sources.extend(&["arm/negdf2vfp.S", "arm/negsf2vfp.S"]);

}

if target.contains("aarch64") {
if target_arch == "aarch64" {
sources.extend(&["comparetf2.c",
"extenddftf2.c",
"extendsftf2.c",
Expand All @@ -396,6 +439,18 @@ fn main() {
"trunctfsf2.c"]);
}

// Remove the assembly implementations that won't compile for the target
if llvm_target[0] == "thumbv6m" {
sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp", "aeabi_dcmp", "aeabi_fcmp", "aeabi_ldivmod",
"aeabi_memset", "aeabi_uldivmod", "clzdi2", "clzsi2", "comparesf2",
"divmodsi4", "divsi3", "modsi3", "switch16", "switch32", "switch8",
"switchu8", "udivmodsi4", "udivsi3", "umodsi3"]);
}

if llvm_target[0] == "thumbv7m" || llvm_target[0] == "thumbv7em" {
sources.remove(&["aeabi_cdcmp", "aeabi_cfcmp"]);
}

for src in sources.map.values() {
cfg.file(Path::new("../compiler-rt/lib/builtins").join(src));
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
let os = &sess.target.target.target_os;
let env = &sess.target.target.target_env;
let vendor = &sess.target.target.target_vendor;
let llvm_target = &sess.target.target.llvm_target;
let max_atomic_width = sess.target.target.options.max_atomic_width;

let fam = if let Some(ref fam) = sess.target.target.options.target_family {
Expand All @@ -949,6 +950,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
mk(InternedString::new("target_pointer_width"), intern(wordsz)),
mk(InternedString::new("target_env"), intern(env)),
mk(InternedString::new("target_vendor"), intern(vendor)),
mk(InternedString::new("llvm_target"), intern(llvm_target)),
];
match &fam[..] {
"windows" | "unix" => ret.push(attr::mk_word_item(fam)),
Expand Down
18 changes: 15 additions & 3 deletions src/librustc_back/target/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,12 @@ mod netbsd_base;
mod solaris_base;
mod windows_base;
mod windows_msvc_base;
mod thumb_base;

pub type TargetResult = Result<Target, String>;

macro_rules! supported_targets {
( $(($triple:expr, $module:ident)),+ ) => (
( $(($triple:expr, $module:ident)),+, ) => (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can actually move the comma inside the parens to require a trailing comma like:

( $(($triple:expr, $module:ident),)+ )

$(mod $module;)*

/// List of supported targets
Expand Down Expand Up @@ -184,7 +185,12 @@ supported_targets! {
("i586-pc-windows-msvc", i586_pc_windows_msvc),

("le32-unknown-nacl", le32_unknown_nacl),
("asmjs-unknown-emscripten", asmjs_unknown_emscripten)
("asmjs-unknown-emscripten", asmjs_unknown_emscripten),

("thumbv6m-none-eabi", thumbv6m_none_eabi),
("thumbv7m-none-eabi", thumbv7m_none_eabi),
("thumbv7em-none-eabi", thumbv7em_none_eabi),
("thumbv7em-none-eabihf", thumbv7em_none_eabihf),
}

/// Everything `rustc` knows about how to compile for a specific target.
Expand Down Expand Up @@ -391,7 +397,13 @@ impl Default for TargetOptions {
allow_asm: true,
has_elf_tls: false,
obj_is_bitcode: false,
max_atomic_width: 0,
// NOTE this is *not* the real default value. The default value of max_atomic_width is
// actually the pointer width of the target. This default is injected in the
// Target::from_json function. Still, we have to pick some value to put here. We'll pick
// an impossible value: u64::max_value() because using a valid value like 0 or 8 as the
// default would cause the max-atomic-width field to be "lost" (it would get replaced
// by target_pointer_width) during the Target <-> JSON round trip
max_atomic_width: u64::max_value(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm I'm not sure I quite understand why this is necessary, could you elaborate what you mean by "lost" in the comment?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! Let me ellaborate here, first, what happens today without this change:

  • All targets go through a round trip from TargetOptions to JSON and back to TargetOptions.
  • Let's say you set max_atomic_width to the Default value, which is 0 today, for a target specification, when this specification is converted to JSON the max_atomic_width field is not present in that JSON representation.
  • When that JSON representation is converted back to TargetOptions, the current logic sets max_atomic_width to target_pointer_witdh, i.e. 32 or 64, because the max_atomic_width field is not present in the JSON representation.

TL;DR You set max_atomic_witdth to 0 but the compiler is actually using 32 or 64 for the target.

The bug is subtle and the proposed fix is sort of magical. Perhaps we could solve it in a better way.

}
}
}
Expand Down
Loading