Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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 compiler/rustc_llvm/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const OPTIONAL_COMPONENTS: &[&str] = &[
"nvptx",
"hexagon",
"riscv",
"xtensa",
"bpf",
];

Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -180,6 +186,7 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char* FileName) {
SUBTARGET_MSP430 \
SUBTARGET_SPARC \
SUBTARGET_HEXAGON \
SUBTARGET_XTENSA \
SUBTARGET_RISCV \
SUBTARGET_LOONGARCH \

Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_target/src/abi/call/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
123 changes: 123 additions & 0 deletions compiler/rustc_target/src/abi/call/xtensa.rs
Original file line number Diff line number Diff line change
@@ -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(),
}
}
1 change: 1 addition & 0 deletions compiler/rustc_target/src/spec/base/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
17 changes: 17 additions & 0 deletions compiler/rustc_target/src/spec/base/xtensa.rs
Original file line number Diff line number Diff line change
@@ -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()
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
24 changes: 24 additions & 0 deletions compiler/rustc_target/src/spec/targets/xtensa_esp32_none_elf.rs
Original file line number Diff line number Diff line change
@@ -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(),
Copy link
Member

Choose a reason for hiding this comment

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

This seem to be wrong? I got the following error when building for this target:

  error: data-layout for target `xtensa-esp32-none-elf`, `e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32`, differs from LLVM target's `xtensa-none-elf` default layout, `e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32`

https://github.com/taiki-e/portable-atomic/actions/runs/9492602960/job/26160155007#step:6:1583

Copy link
Contributor

Choose a reason for hiding this comment

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

Rust is not currently using a new enough LLVM to include the patches to generate code (discussed here: #125141 (comment)), so for now, you still need the esp toolchain in your CI. I think by switching to LLVM 18, or latest LLVM 19 we should be able to build some basic binaries.

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()
},
}
}
23 changes: 23 additions & 0 deletions compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs
Original file line number Diff line number Diff line change
@@ -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()
},
}
}
24 changes: 24 additions & 0 deletions compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs
Original file line number Diff line number Diff line change
@@ -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()
},
}
}
2 changes: 1 addition & 1 deletion src/bootstrap/src/core/build_steps/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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" };
Expand Down
3 changes: 3 additions & 0 deletions src/doc/rustc/src/platform-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
25 changes: 25 additions & 0 deletions src/doc/rustc/src/platform-support/xtensa.md
Original file line number Diff line number Diff line change
@@ -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).
4 changes: 4 additions & 0 deletions src/tools/tidy/src/target_policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
13 changes: 12 additions & 1 deletion tests/assembly/targets/targets-elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/check-cfg/well-known-values.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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 <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration

warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
Expand Down