diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 024f6f89a4b7f..cdaabb036c2ae 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -23,6 +23,7 @@ const OPTIONAL_COMPONENTS: &[&str] = &[ "nvptx", "hexagon", "riscv", + "xtensa", "bpf", ]; diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 3fcf3aca8afee..a027ddcc1508a 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -155,6 +155,12 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char* FileName) { #define SUBTARGET_SPARC #endif +#ifdef LLVM_COMPONENT_XTENSA +#define SUBTARGET_XTENSA SUBTARGET(XTENSA) +#else +#define SUBTARGET_XTENSA +#endif + #ifdef LLVM_COMPONENT_HEXAGON #define SUBTARGET_HEXAGON SUBTARGET(Hexagon) #else @@ -180,6 +186,7 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char* FileName) { SUBTARGET_MSP430 \ SUBTARGET_SPARC \ SUBTARGET_HEXAGON \ + SUBTARGET_XTENSA \ SUBTARGET_RISCV \ SUBTARGET_LOONGARCH \ diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 6a570c97c8888..ae1848a73630a 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -188,6 +188,13 @@ pub fn initialize_available_targets() { LLVMInitializeHexagonAsmPrinter, LLVMInitializeHexagonAsmParser ); + init_target!( + llvm_component = "xtensa", + LLVMInitializeXtensaTargetInfo, + LLVMInitializeXtensaTarget, + LLVMInitializeXtensaTargetMC, + LLVMInitializeXtensaAsmParser + ); init_target!( llvm_component = "webassembly", LLVMInitializeWebAssemblyTargetInfo, diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index fc79c9232d1bd..5713542c17d63 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -29,6 +29,7 @@ mod wasm; mod x86; mod x86_64; mod x86_win64; +mod xtensa; #[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum PassMode { @@ -903,6 +904,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { } } "hexagon" => hexagon::compute_abi_info(self), + "xtensa" => xtensa::compute_abi_info(cx, self), "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self), "wasm32" | "wasm64" => { if cx.target_spec().adjust_abi(cx, abi, self.c_variadic) == spec::abi::Abi::Wasm { diff --git a/compiler/rustc_target/src/abi/call/xtensa.rs b/compiler/rustc_target/src/abi/call/xtensa.rs new file mode 100644 index 0000000000000..addbe6989254c --- /dev/null +++ b/compiler/rustc_target/src/abi/call/xtensa.rs @@ -0,0 +1,123 @@ +//! The Xtensa ABI implementation +//! +//! This ABI implementation is based on the following sources: +//! +//! Section 8.1.4 & 8.1.5 of the Xtensa ISA reference manual, as well as snippets from +//! Section 2.3 from the Xtensa programmers guide. + +use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform}; +use crate::abi::{Abi, HasDataLayout, Size, TyAbiInterface}; +use crate::spec::HasTargetSpec; + +const NUM_ARG_GPRS: u64 = 6; +const NUM_RET_GPRS: u64 = 4; +const MAX_ARG_IN_REGS_SIZE: u64 = NUM_ARG_GPRS * 32; +const MAX_RET_IN_REGS_SIZE: u64 = NUM_RET_GPRS * 32; + +fn classify_ret_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ + if arg.is_ignore() { + return; + } + + // The rules for return and argument types are the same, + // so defer to `classify_arg_ty`. + let mut arg_gprs_left = NUM_RET_GPRS; + classify_arg_ty(arg, &mut arg_gprs_left, MAX_RET_IN_REGS_SIZE); + // Ret args cannot be passed via stack, we lower to indirect and let the backend handle the invisble reference + match arg.mode { + super::PassMode::Indirect { attrs: _, meta_attrs: _, ref mut on_stack } => { + *on_stack = false; + } + _ => {} + } +} + +fn classify_arg_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>, arg_gprs_left: &mut u64, max_size: u64) +where + Ty: TyAbiInterface<'a, C> + Copy, +{ + assert!(*arg_gprs_left <= NUM_ARG_GPRS, "Arg GPR tracking underflow"); + + // Ignore empty structs/unions. + if arg.layout.is_zst() { + return; + } + + let size = arg.layout.size.bits(); + let needed_align = arg.layout.align.abi.bits(); + let mut must_use_stack = false; + + // Determine the number of GPRs needed to pass the current argument + // according to the ABI. 2*XLen-aligned varargs are passed in "aligned" + // register pairs, so may consume 3 registers. + let mut needed_arg_gprs = (size + 32 - 1) / 32; + if needed_align == 64 { + needed_arg_gprs += *arg_gprs_left % 2; + } + + if needed_arg_gprs > *arg_gprs_left + || needed_align > 128 + || (*arg_gprs_left < (max_size / 32) && needed_align == 128) + { + must_use_stack = true; + needed_arg_gprs = *arg_gprs_left; + } + *arg_gprs_left -= needed_arg_gprs; + + if must_use_stack { + arg.make_indirect_byval(None); + } else { + if is_xtensa_aggregate(arg) { + // Aggregates which are <= max_size will be passed in + // registers if possible, so coerce to integers. + + // Use a single `xlen` int if possible, 2 * `xlen` if 2 * `xlen` alignment + // is required, and a 2-element `xlen` array if only `xlen` alignment is + // required. + if size <= 32 { + arg.cast_to(Reg::i32()); + } else { + let reg = if needed_align == 2 * 32 { Reg::i64() } else { Reg::i32() }; + let total = Size::from_bits(((size + 32 - 1) / 32) * 32); + arg.cast_to(Uniform::new(reg, total)); + } + } else { + // All integral types are promoted to `xlen` + // width. + // + // We let the LLVM backend handle integral types >= xlen. + if size < 32 { + arg.extend_integer_width_to(32); + } + } + } +} + +pub fn compute_abi_info<'a, Ty, C>(_cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + if !fn_abi.ret.is_ignore() { + classify_ret_ty(&mut fn_abi.ret); + } + + let mut arg_gprs_left = NUM_ARG_GPRS; + + for arg in fn_abi.args.iter_mut() { + if arg.is_ignore() { + continue; + } + classify_arg_ty(arg, &mut arg_gprs_left, MAX_ARG_IN_REGS_SIZE); + } +} + +fn is_xtensa_aggregate<'a, Ty>(arg: &ArgAbi<'a, Ty>) -> bool { + match arg.layout.abi { + Abi::Vector { .. } => true, + _ => arg.layout.is_aggregate(), + } +} diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs index d137aaa535858..28d10dcf2ff3a 100644 --- a/compiler/rustc_target/src/spec/base/mod.rs +++ b/compiler/rustc_target/src/spec/base/mod.rs @@ -35,3 +35,4 @@ pub(crate) mod windows_gnullvm; pub(crate) mod windows_msvc; pub(crate) mod windows_uwp_gnu; pub(crate) mod windows_uwp_msvc; +pub(crate) mod xtensa; diff --git a/compiler/rustc_target/src/spec/base/xtensa.rs b/compiler/rustc_target/src/spec/base/xtensa.rs new file mode 100644 index 0000000000000..31ad09c52e4fd --- /dev/null +++ b/compiler/rustc_target/src/spec/base/xtensa.rs @@ -0,0 +1,17 @@ +use crate::abi::Endian; +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, TargetOptions}; + +pub fn opts() -> TargetOptions { + TargetOptions { + os: "none".into(), + endian: Endian::Little, + c_int_width: "32".into(), + linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No), + executables: true, + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + atomic_cas: false, + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 83ee63e2cf286..da1da0c52bf42 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1766,6 +1766,10 @@ supported_targets! { ("nvptx64-nvidia-cuda", nvptx64_nvidia_cuda), + ("xtensa-esp32-none-elf", xtensa_esp32_none_elf), + ("xtensa-esp32s2-none-elf", xtensa_esp32s2_none_elf), + ("xtensa-esp32s3-none-elf", xtensa_esp32s3_none_elf), + ("i686-wrs-vxworks", i686_wrs_vxworks), ("x86_64-wrs-vxworks", x86_64_wrs_vxworks), ("armv7-wrs-vxworks-eabihf", armv7_wrs_vxworks_eabihf), diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs new file mode 100644 index 0000000000000..bf5237163139f --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs @@ -0,0 +1,24 @@ +use crate::spec::{base::xtensa, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "xtensa-none-elf".into(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(), + arch: "xtensa".into(), + metadata: crate::spec::TargetMetadata { + description: Some("Xtensa ESP32".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + + options: TargetOptions { + cpu: "esp32".into(), + linker: Some("xtensa-esp32-elf-gcc".into()), + max_atomic_width: Some(32), + atomic_cas: true, + ..xtensa::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs new file mode 100644 index 0000000000000..219b2aa48c1fb --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs @@ -0,0 +1,23 @@ +use crate::spec::{base::xtensa, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "xtensa-none-elf".into(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(), + arch: "xtensa".into(), + metadata: crate::spec::TargetMetadata { + description: Some("Xtensa ESP32-S2".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + + options: TargetOptions { + cpu: "esp32-s2".into(), + linker: Some("xtensa-esp32s2-elf-gcc".into()), + max_atomic_width: Some(32), + ..xtensa::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs new file mode 100644 index 0000000000000..632eef3a5842c --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs @@ -0,0 +1,24 @@ +use crate::spec::{base::xtensa, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "xtensa-none-elf".into(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(), + arch: "xtensa".into(), + metadata: crate::spec::TargetMetadata { + description: Some("Xtensa ESP32-S3".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + + options: TargetOptions { + cpu: "esp32-s3".into(), + linker: Some("xtensa-esp32s3-elf-gcc".into()), + max_atomic_width: Some(32), + atomic_cas: true, + ..xtensa::opts() + }, + } +} diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index bd1f9699c3c82..e4dbd3a13fee6 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/120761 +Last change is for: https://github.com/rust-lang/rust/pull/125141 diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 8ca7af2febee4..ebac27cd92c27 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -330,7 +330,7 @@ impl Step for Llvm { let llvm_exp_targets = match builder.config.llvm_experimental_targets { Some(ref s) => s, - None => "AVR;M68k;CSKY", + None => "AVR;M68k;CSKY;Xtensa", }; let assertions = if builder.config.llvm_assertions { "ON" } else { "OFF" }; diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 77859956c95fa..30fe0206cd5e1 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -383,5 +383,8 @@ target | std | host | notes `x86_64-wrs-vxworks` | ? | | [`x86_64h-apple-darwin`](platform-support/x86_64h-apple-darwin.md) | ✓ | ✓ | macOS with late-gen Intel (at least Haswell) [`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * | | 64-bit Linux with no libc +`xtensa-esp32-none-elf` | | | Xtensa ESP32 +`xtensa-esp32s2-none-elf` | | | Xtensa ESP32-S2 +`xtensa-esp32s3-none-elf` | | | Xtensa ESP32-S3 [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets diff --git a/src/doc/rustc/src/platform-support/xtensa.md b/src/doc/rustc/src/platform-support/xtensa.md new file mode 100644 index 0000000000000..7785977466e4b --- /dev/null +++ b/src/doc/rustc/src/platform-support/xtensa.md @@ -0,0 +1,25 @@ +# `xtensa-*` + +**Tier: 3** + +Targets for Xtensa CPUs. + +## Target maintainers + +- Scott Mabin [@MabezDev](https://github.com/MabezDev) +- Sergio Gasquez [@SergioGasquez](https://github.com/SergioGasquez) + +## Requirements + +The target names follow this format: `xtensa-$CPU`, where `$CPU` specifies the target chip. The following targets are currently defined: + +| Target name | Target CPU(s) | +| ------------------------- | --------------------------------------------------------------- | +| `xtensa-esp32-none-elf` | [ESP32](https://www.espressif.com/en/products/socs/esp32) | +| `xtensa-esp32s2-none-elf` | [ESP32-S2](https://www.espressif.com/en/products/socs/esp32-s2) | +| `xtensa-esp32s3-none-elf` | [ESP32-S3](https://www.espressif.com/en/products/socs/esp32-s3) | + + +## Building the target + +The targets can be built by installing the [Xtensa enabled Rust channel](https://github.com/esp-rs/rust/). See instructions in the [RISC-V and Xtensa Targets section of the The Rust on ESP Book](https://docs.esp-rs.org/book/installation/riscv-and-xtensa.html). diff --git a/src/tools/tidy/src/target_policy.rs b/src/tools/tidy/src/target_policy.rs index 382488e572111..06210c8cdb20f 100644 --- a/src/tools/tidy/src/target_policy.rs +++ b/src/tools/tidy/src/target_policy.rs @@ -12,6 +12,10 @@ const EXCEPTIONS: &[&str] = &[ // FIXME: disabled since it fails on CI saying the csky component is missing "csky_unknown_linux_gnuabiv2", "csky_unknown_linux_gnuabiv2hf", + // FIXME: disabled since it requires a custom LLVM until the upstream LLVM adds support for the target (https://github.com/espressif/llvm-project/issues/4) + "xtensa_esp32_none_elf", + "xtensa_esp32s2_none_elf", + "xtensa_esp32s3_none_elf", ]; pub fn check(root_path: &Path, bad: &mut bool) { diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 0db2a35800269..4c54fe639e3e6 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -573,7 +573,18 @@ //@ revisions: x86_64_wrs_vxworks //@ [x86_64_wrs_vxworks] compile-flags: --target x86_64-wrs-vxworks //@ [x86_64_wrs_vxworks] needs-llvm-components: x86 - +// FIXME: disabled since it requires a custom LLVM until the upstream LLVM adds support for the target (https://github.com/espressif/llvm-project/issues/4) +/* + revisions: xtensa_esp32_none_elf + [xtensa_esp32_none_elf] compile-flags: --target xtensa-esp32-none-elf + [xtensa_esp32_none_elf] needs-llvm-components: xtensa + revisions: xtensa_esp32s2_none_elf + [xtensa_esp32s2_none_elf] compile-flags: --target xtensa-esp32s2-none-elf + [xtensa_esp32s2_none_elf] needs-llvm-components: xtensa + revisions: xtensa_esp32s3_none_elf + [xtensa_esp32s3_none_elf] compile-flags: --target xtensa-esp32s3-none-elf + [xtensa_esp32s3_none_elf] needs-llvm-components: xtensa +*/ // Sanity-check that each target can produce assembly code. #![feature(no_core, lang_items)] diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 0c50ec1abba99..3796dca172739 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -129,7 +129,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_arch = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_arch` are: `aarch64`, `arm`, `arm64ec`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, and `x86_64` + = note: expected values for `target_arch` are: `aarch64`, `arm`, `arm64ec`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64`, and `xtensa` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`