From f8643b8765bb69f721094d5677531e2d36e688a4 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Sun, 13 Oct 2024 14:58:44 +0200 Subject: [PATCH] Create a generic AVR target: avr-unknown-unknown This commit removes the `avr-unknown-gnu-atmega328` target and replaces it with a more generic `avr-unknown-unknown` variant that can be specialized using `-C target-cpu` (e.g. `-C target-cpu=atmega328p`). I've decided to go with the `-unknown` tag (i.e. `avr-unknown-unknown` instead of `avr-unknown-gnu`), because that's the name LLVM already uses - I see no reason to diverge here. Seizing the day, I'm adding myself as the maintainer of this target - I've been already fixing the bugs anyway, might as well make it official. Related discussion: https://github.com/rust-lang/rust/pull/131171 --- compiler/rustc_codegen_ssa/src/back/link.rs | 14 +++- .../src/spec/base/{avr_gnu.rs => avr.rs} | 39 ---------- compiler/rustc_target/src/spec/base/mod.rs | 2 +- compiler/rustc_target/src/spec/mod.rs | 4 +- .../spec/targets/avr_unknown_gnu_atmega328.rs | 5 -- .../src/spec/targets/avr_unknown_unknown.rs | 30 +++++++ .../rustc_target/src/spec/tests/tests_impl.rs | 2 +- src/doc/rustc/src/platform-support.md | 2 +- .../platform-support/avr-unknown-unknown.md | 78 +++++++++++++++++++ src/tools/compiletest/src/header/tests.rs | 3 + tests/assembly/asm/avr-modifiers.rs | 2 +- tests/assembly/asm/avr-types.rs | 2 +- tests/assembly/targets/targets-pe.rs | 6 +- tests/codegen/avr/avr-func-addrspace.rs | 2 +- .../feature-gate-abi-avr-interrupt.rs | 2 +- tests/ui/repr/16-bit-repr-c-enum.rs | 2 +- 16 files changed, 136 insertions(+), 59 deletions(-) rename compiler/rustc_target/src/spec/base/{avr_gnu.rs => avr.rs} (91%) delete mode 100644 compiler/rustc_target/src/spec/targets/avr_unknown_gnu_atmega328.rs create mode 100644 compiler/rustc_target/src/spec/targets/avr_unknown_unknown.rs create mode 100644 src/doc/rustc/src/platform-support/avr-unknown-unknown.md diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 34dc599e4fddd..253df76b0cb35 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1920,10 +1920,20 @@ fn add_post_link_objects( /// Add arbitrary "pre-link" args defined by the target spec or from command line. /// FIXME: Determine where exactly these args need to be inserted. -fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { +fn add_pre_link_args( + cmd: &mut dyn Linker, + sess: &Session, + flavor: LinkerFlavor, + codegen_results: &CodegenResults, +) { if let Some(args) = sess.target.pre_link_args.get(&flavor) { cmd.verbatim_args(args.iter().map(Deref::deref)); } + + if sess.target.arch == "avr" { + cmd.verbatim_arg(format!("-mmcu={}", codegen_results.crate_info.target_cpu)); + } + cmd.verbatim_args(&sess.opts.unstable_opts.pre_link_args); } @@ -2215,7 +2225,7 @@ fn linker_with_args( // FIXME: In practice built-in target specs use this for arbitrary order-independent options, // introduce a target spec option for order-independent linker options and migrate built-in // specs to it. - add_pre_link_args(cmd, sess, flavor); + add_pre_link_args(cmd, sess, flavor, codegen_results); // ------------ Object code and libraries, order-dependent ------------ diff --git a/compiler/rustc_target/src/spec/base/avr_gnu.rs b/compiler/rustc_target/src/spec/base/avr.rs similarity index 91% rename from compiler/rustc_target/src/spec/base/avr_gnu.rs rename to compiler/rustc_target/src/spec/base/avr.rs index 4f348af21ad99..85b73e61e52cd 100644 --- a/compiler/rustc_target/src/spec/base/avr_gnu.rs +++ b/compiler/rustc_target/src/spec/base/avr.rs @@ -1,44 +1,5 @@ use object::elf; -use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions}; - -/// A base target for AVR devices using the GNU toolchain. -/// -/// Requires GNU avr-gcc and avr-binutils on the host system. -/// FIXME: Remove the second parameter when const string concatenation is possible. -pub(crate) fn target(target_cpu: &'static str, mmcu: &'static str) -> Target { - Target { - arch: "avr".into(), - metadata: crate::spec::TargetMetadata { - description: None, - tier: None, - host_tools: None, - std: None, - }, - data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(), - llvm_target: "avr-unknown-unknown".into(), - pointer_width: 16, - options: TargetOptions { - env: "gnu".into(), - - c_int_width: "16".into(), - cpu: target_cpu.into(), - exe_suffix: ".elf".into(), - - linker: Some("avr-gcc".into()), - eh_frame_header: false, - pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[mmcu]), - late_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[ - "-lgcc", - ]), - max_atomic_width: Some(16), - atomic_cas: false, - relocation_model: RelocModel::Static, - ..TargetOptions::default() - }, - } -} - /// Resolve the value of the EF_AVR_ARCH field for AVR ELF files, given the /// name of the target CPU / MCU. /// diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs index 28d10dcf2ff3a..762a82e0c20ca 100644 --- a/compiler/rustc_target/src/spec/base/mod.rs +++ b/compiler/rustc_target/src/spec/base/mod.rs @@ -1,7 +1,7 @@ pub(crate) mod aix; pub(crate) mod android; pub(crate) mod apple; -pub(crate) mod avr_gnu; +pub(crate) mod avr; pub(crate) mod bpf; pub(crate) mod dragonfly; pub(crate) mod freebsd; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f4b45a0819525..285c35fe13980 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -63,7 +63,7 @@ pub use base::apple::{ deployment_target_for_target as current_apple_deployment_target, platform as current_apple_platform, }; -pub use base::avr_gnu::ef_avr_arch; +pub use base::avr::ef_avr_arch; /// Linker is called through a C/C++ compiler. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -1734,7 +1734,7 @@ supported_targets! { ("riscv64gc-unknown-fuchsia", riscv64gc_unknown_fuchsia), ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia), - ("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328), + ("avr-unknown-unknown", avr_unknown_unknown), ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc), diff --git a/compiler/rustc_target/src/spec/targets/avr_unknown_gnu_atmega328.rs b/compiler/rustc_target/src/spec/targets/avr_unknown_gnu_atmega328.rs deleted file mode 100644 index c3d6fb722733d..0000000000000 --- a/compiler/rustc_target/src/spec/targets/avr_unknown_gnu_atmega328.rs +++ /dev/null @@ -1,5 +0,0 @@ -use crate::spec::{Target, base}; - -pub(crate) fn target() -> Target { - base::avr_gnu::target("atmega328", "-mmcu=atmega328") -} diff --git a/compiler/rustc_target/src/spec/targets/avr_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/avr_unknown_unknown.rs new file mode 100644 index 0000000000000..c65dfad829ceb --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/avr_unknown_unknown.rs @@ -0,0 +1,30 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, RelocModel, Target, TargetOptions}; + +pub(crate) fn target() -> Target { + Target { + arch: "avr".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(), + llvm_target: "avr-unknown-unknown".into(), + pointer_width: 16, + options: TargetOptions { + c_int_width: "16".into(), + exe_suffix: ".elf".into(), + linker: Some("avr-gcc".into()), + eh_frame_header: false, + pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[]), + late_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[ + "-lgcc", + ]), + max_atomic_width: Some(16), + atomic_cas: false, + relocation_model: RelocModel::Static, + ..TargetOptions::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index fc5bd846e0241..6b8b012ae4780 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -39,7 +39,7 @@ impl Target { &self.post_link_args, ] { for (&flavor, flavor_args) in args { - assert!(!flavor_args.is_empty()); + assert!(!flavor_args.is_empty() || self.arch == "avr"); // Check that flavors mentioned in link args are compatible with the default flavor. match self.linker_flavor { LinkerFlavor::Gnu(..) => { diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 022fc9da7e03a..0b102d59a15ee 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -293,7 +293,7 @@ target | std | host | notes [`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | Armv7-A Apple WatchOS [`armv7s-apple-ios`](platform-support/apple-ios.md) | ✓ | | Armv7-A Apple-A6 Apple iOS [`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Bare Armv8-R, hardfloat -`avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` +`avr-unknown-unknown` | * | | AVR `bpfeb-unknown-none` | * | | BPF (big endian) `bpfel-unknown-none` | * | | BPF (little endian) `csky-unknown-linux-gnuabiv2` | ✓ | | C-SKY abiv2 Linux (little endian) diff --git a/src/doc/rustc/src/platform-support/avr-unknown-unknown.md b/src/doc/rustc/src/platform-support/avr-unknown-unknown.md new file mode 100644 index 0000000000000..0499f2f045e6d --- /dev/null +++ b/src/doc/rustc/src/platform-support/avr-unknown-unknown.md @@ -0,0 +1,78 @@ +# `avr-unknown-unknown` + +Series of microcontrollers from Atmel: ATmega8, ATmega328p etc. + +**Tier: 3** + +## Target maintainers + +-[Patryk Wychowaniec](https://github.com/Patryk27) + +## Requirements + +This target is only cross-compiled; x86\_64 Linux, x86\_64 MacOS and aarch64 +MacOS hosts are confirmed to work, but in principle any machine able to run +rustc and avr-gcc should be good. + +Compiling for this target requires `avr-gcc`, because a couple of intrinsics +(like 32-bit multiplication) rely on [`libgcc`](https://github.com/gcc-mirror/gcc/blob/3269a722b7a03613e9c4e2862bc5088c4a17cc11/libgcc/config/avr/lib1funcs.S) +and can't be provided through `compiler-builtins` yet. This is a limitation that +[we hope to lift in the future](https://github.com/rust-lang/compiler-builtins/issues/711). + +## Building the target + +Rust comes with AVR support enabled, you don't have to rebuild the compiler. + +## Building Rust programs + +Install `avr-gcc`: + +```console +# Ubuntu: +$ sudo apt-get install gcc-avr + +# Mac: +$ brew tap osx-cross/avr && brew install avr-gcc + +# NixOS (takes a couple of minutes, since Hydra doesn't build it): +$ nix shell nixpkgs#pkgsCross.avr.buildPackages.gcc11 +``` + +... setup `.cargo/config` for your project: + +```toml +[build] +target = "avr-unknown-unknown" +rustflags = ["-C", "target-cpu=atmega328p"] + +[unstable] +build-std = ["core"] +``` + +... and then simply run: + +```console +$ cargo build --release +``` + +The final binary will be placed into +`./target/avr-unknown-unknown/release/your-project.elf`. + +Note that since AVRs have rather small amounts of registers, ROM and RAM, it's +recommended to always use `--release` to avoid running out of space. + +### Supported microcontrollers (target-cpu) + +https://github.com/llvm/llvm-project/blob/093d4db2f3c874d4683fb01194b00dbb20e5c713/clang/lib/Basic/Targets/AVR.cpp#L32 + +## Testing + +You can use [`simavr`](https://github.com/buserror/simavr) to emulate the +resulting firmware on your machine: + +```console +$ simavr -m atmega328p ./target/avr-unknown-unknown/release/your-project.elf +``` + +Alternatively, if you want to write a couple of actual `#[test]`s, you can use +[`avr-tester`](https://github.com/Patryk27/avr-tester). diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index c3c9496c4d2d9..61f3aa2814771 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -380,7 +380,10 @@ fn profiler_runtime() { #[test] fn asm_support() { let asms = [ + #[cfg(bootstrap)] ("avr-unknown-gnu-atmega328", false), + #[cfg(not(bootstrap))] + ("avr-unknown-unknown", false), ("i686-unknown-netbsd", true), ("riscv32gc-unknown-linux-gnu", true), ("riscv64imac-unknown-none-elf", true), diff --git a/tests/assembly/asm/avr-modifiers.rs b/tests/assembly/asm/avr-modifiers.rs index e94375f959692..2e0e1704685da 100644 --- a/tests/assembly/asm/avr-modifiers.rs +++ b/tests/assembly/asm/avr-modifiers.rs @@ -1,5 +1,5 @@ //@ assembly-output: emit-asm -//@ compile-flags: --target avr-unknown-gnu-atmega328 +//@ compile-flags: --target avr-unknown-unknown -C target-cpu=atmega328p //@ needs-llvm-components: avr #![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)] diff --git a/tests/assembly/asm/avr-types.rs b/tests/assembly/asm/avr-types.rs index 88b16895e8dc0..baaa2081c044d 100644 --- a/tests/assembly/asm/avr-types.rs +++ b/tests/assembly/asm/avr-types.rs @@ -1,5 +1,5 @@ //@ assembly-output: emit-asm -//@ compile-flags: --target avr-unknown-gnu-atmega328 +//@ compile-flags: --target avr-unknown-unknown -C target-cpu=atmega328p //@ needs-llvm-components: avr #![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)] diff --git a/tests/assembly/targets/targets-pe.rs b/tests/assembly/targets/targets-pe.rs index 6415aee6fae90..fc38d80bfb62a 100644 --- a/tests/assembly/targets/targets-pe.rs +++ b/tests/assembly/targets/targets-pe.rs @@ -15,9 +15,9 @@ //@ revisions: arm64ec_pc_windows_msvc //@ [arm64ec_pc_windows_msvc] compile-flags: --target arm64ec-pc-windows-msvc //@ [arm64ec_pc_windows_msvc] needs-llvm-components: aarch64 -//@ revisions: avr_unknown_gnu_atmega328 -//@ [avr_unknown_gnu_atmega328] compile-flags: --target avr-unknown-gnu-atmega328 -//@ [avr_unknown_gnu_atmega328] needs-llvm-components: avr +//@ revisions: avr_unknown_unknown +//@ [avr_unknown_unknown] compile-flags: --target avr-unknown-unknown -C target-cpu=atmega328p +//@ [avr_unknown_unknown] needs-llvm-components: avr //@ revisions: bpfeb_unknown_none //@ [bpfeb_unknown_none] compile-flags: --target bpfeb-unknown-none //@ [bpfeb_unknown_none] needs-llvm-components: bpf diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs index 7f9a7e6e81103..235f31ae8e2a3 100644 --- a/tests/codegen/avr/avr-func-addrspace.rs +++ b/tests/codegen/avr/avr-func-addrspace.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -O --target=avr-unknown-gnu-atmega328 --crate-type=rlib -C panic=abort +//@ compile-flags: -O --target=avr-unknown-unknown -C target-cpu=atmega328p --crate-type=rlib -C panic=abort //@ needs-llvm-components: avr // This test validates that function pointers can be stored in global variables diff --git a/tests/ui/feature-gates/feature-gate-abi-avr-interrupt.rs b/tests/ui/feature-gates/feature-gate-abi-avr-interrupt.rs index f37c5335deb04..8ed132d9183d8 100644 --- a/tests/ui/feature-gates/feature-gate-abi-avr-interrupt.rs +++ b/tests/ui/feature-gates/feature-gate-abi-avr-interrupt.rs @@ -1,5 +1,5 @@ //@ needs-llvm-components: avr -//@ compile-flags: --target=avr-unknown-gnu-atmega328 --crate-type=rlib +//@ compile-flags: --target=avr-unknown-unknown -C target-cpu=atmega328p --crate-type=rlib #![no_core] #![feature(no_core, lang_items)] #[lang="sized"] diff --git a/tests/ui/repr/16-bit-repr-c-enum.rs b/tests/ui/repr/16-bit-repr-c-enum.rs index 2509416ad87d4..da6e1e04241cf 100644 --- a/tests/ui/repr/16-bit-repr-c-enum.rs +++ b/tests/ui/repr/16-bit-repr-c-enum.rs @@ -2,7 +2,7 @@ //@ revisions: avr msp430 // //@ [avr] needs-llvm-components: avr -//@ [avr] compile-flags: --target=avr-unknown-gnu-atmega328 --crate-type=rlib +//@ [avr] compile-flags: --target=avr-unknown-unknown -C target-cpu=atmega328p --crate-type=rlib //@ [msp430] needs-llvm-components: msp430 //@ [msp430] compile-flags: --target=msp430-none-elf --crate-type=rlib #![feature(no_core, lang_items, intrinsics, staged_api, rustc_attrs)]