Skip to content

Commit 4d9271c

Browse files
authored
Merge pull request #12 from chocol4te/xtensa_1.39
Update to 1.39.0
2 parents 4560ea7 + dd8b6ad commit 4d9271c

File tree

10 files changed

+328
-2
lines changed

10 files changed

+328
-2
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
# The Rust Programming Language
1+
# The Rust Programming Language For Xtensa processors
2+
3+
This fork enables projects to be built for the ESP32 and ESP8266 using [espressif's llvm fork](https://github.com/espressif/llvm-xtensa). The [esp-rs](https://github.com/esp-rs) organization has been formed to develop runtime, pac and hal crates for the esp32 and eventually esp8266.
4+
5+
## Using this fork
6+
7+
The [quickstart repo](https://github.com/MabezDev/xtensa-rust-quickstart) has more information on how to build this fork and use it to build xtensa compatible code.
28

39
This is the main source code repository for [Rust]. It contains the compiler,
410
standard library, and documentation.

src/librustc_llvm/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ fn main() {
7272
let mut optional_components =
7373
vec!["x86", "arm", "aarch64", "amdgpu", "mips", "powerpc",
7474
"systemz", "jsbackend", "webassembly", "msp430", "sparc", "nvptx",
75-
"hexagon"];
75+
"hexagon", "xtensa"];
7676

7777
let mut version_cmd = Command::new(&llvm_config);
7878
version_cmd.arg("--version");

src/librustc_llvm/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,11 @@ pub fn initialize_available_targets() {
105105
LLVMInitializeWebAssemblyTarget,
106106
LLVMInitializeWebAssemblyTargetMC,
107107
LLVMInitializeWebAssemblyAsmPrinter);
108+
init_target!(llvm_component = "xtensa",
109+
LLVMInitializeXtensaTargetInfo,
110+
LLVMInitializeXtensaTarget,
111+
LLVMInitializeXtensaTargetMC,
112+
LLVMInitializeXtensaAsmPrinter,
113+
LLVMInitializeXtensaAsmParser);
114+
108115
}

src/librustc_target/abi/call/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ mod x86;
2222
mod x86_64;
2323
mod x86_win64;
2424
mod wasm32;
25+
mod xtensa;
2526

2627
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2728
pub enum IgnoreMode {
@@ -581,6 +582,7 @@ impl<'a, Ty> FnType<'a, Ty> {
581582
"hexagon" => hexagon::compute_abi_info(self),
582583
"riscv32" => riscv::compute_abi_info(self, 32),
583584
"riscv64" => riscv::compute_abi_info(self, 64),
585+
"xtensa" => xtensa::compute_abi_info(self, 32),
584586
a => return Err(format!("unrecognized arch \"{}\" in target specification", a))
585587
}
586588

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// reference: https://github.com/espressif/clang-xtensa/commit/6fb488d2553f06029e6611cf81c6efbd45b56e47#diff-aa74ae1e1ab6b7149789237edb78e688R8450
2+
3+
use crate::abi::call::{ArgType, FnType, Reg, Uniform};
4+
5+
const NUM_ARG_GPR: u64 = 6;
6+
const MAX_ARG_IN_REGS_SIZE: u64 = 4 * 32;
7+
// const MAX_ARG_DIRECT_SIZE: u64 = MAX_ARG_IN_REGS_SIZE;
8+
const MAX_RET_IN_REGS_SIZE: u64 = 2 * 32;
9+
10+
fn classify_ret_ty<Ty>(arg: &mut ArgType<'_, Ty>, xlen: u64) {
11+
// The rules for return and argument types are the same, so defer to
12+
// classifyArgumentType.
13+
classify_arg_ty(arg, xlen, &mut 2); // two as max return size
14+
}
15+
16+
fn classify_arg_ty<Ty>(arg: &mut ArgType<'_, Ty>, xlen: u64, remaining_gpr: &mut u64) {
17+
// Determine the number of GPRs needed to pass the current argument
18+
// according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
19+
// register pairs, so may consume 3 registers.
20+
21+
let arg_size = arg.layout.size;
22+
if arg_size.bits() > MAX_ARG_IN_REGS_SIZE {
23+
arg.make_indirect();
24+
return;
25+
}
26+
27+
let alignment = arg.layout.details.align.abi;
28+
let mut required_gpr = 1u64; // at least one per arg
29+
30+
if alignment.bits() == 2 * xlen {
31+
required_gpr = 2 + (*remaining_gpr % 2);
32+
} else if arg_size.bits() > xlen && arg_size.bits() <= MAX_ARG_IN_REGS_SIZE {
33+
required_gpr = (arg_size.bits() + (xlen - 1)) / xlen;
34+
}
35+
36+
let mut stack_required = false;
37+
if required_gpr > *remaining_gpr {
38+
stack_required = true;
39+
required_gpr = *remaining_gpr;
40+
}
41+
*remaining_gpr -= required_gpr;
42+
43+
// if a value can fit in a reg and the
44+
// stack is not required, extend
45+
if !arg.layout.is_aggregate() {
46+
// non-aggregate types
47+
if arg_size.bits() < xlen && !stack_required {
48+
arg.extend_integer_width_to(xlen);
49+
}
50+
} else if arg_size.bits() as u64 <= MAX_ARG_IN_REGS_SIZE {
51+
// aggregate types
52+
// Aggregates which are <= 4*32 will be passed in registers if possible,
53+
// so coerce to integers.
54+
55+
// Use a single XLen int if possible, 2*XLen if 2*XLen alignment is
56+
// required, and a 2-element XLen array if only XLen alignment is
57+
// required.
58+
// if alignment == 2 * xlen {
59+
// arg.extend_integer_width_to(xlen * 2);
60+
// } else {
61+
// arg.extend_integer_width_to(arg_size + (xlen - 1) / xlen);
62+
// }
63+
if alignment.bits() == 2 * xlen {
64+
arg.cast_to(Uniform { unit: Reg::i64(), total: arg_size });
65+
} else {
66+
//FIXME array type - this should be a homogenous array type
67+
// arg.extend_integer_width_to(arg_size + (xlen - 1) / xlen);
68+
}
69+
} else {
70+
// if we get here the stack is required
71+
assert!(stack_required);
72+
arg.make_indirect();
73+
}
74+
75+
// if arg_size as u64 <= MAX_ARG_IN_REGS_SIZE {
76+
// let align = arg.layout.align.abi.bytes();
77+
// let total = arg.layout.size;
78+
// arg.cast_to(Uniform {
79+
// unit: if align <= 4 { Reg::i32() } else { Reg::i64() },
80+
// total
81+
// });
82+
// return;
83+
// }
84+
}
85+
86+
pub fn compute_abi_info<Ty>(fty: &mut FnType<'_, Ty>, xlen: u64) {
87+
if !fty.ret.is_ignore() {
88+
classify_ret_ty(&mut fty.ret, xlen);
89+
}
90+
91+
let return_indirect =
92+
fty.ret.layout.size.bits() > MAX_RET_IN_REGS_SIZE || fty.ret.is_indirect();
93+
94+
let mut remaining_gpr = if return_indirect { NUM_ARG_GPR - 1 } else { NUM_ARG_GPR };
95+
96+
for arg in &mut fty.args {
97+
if arg.is_ignore() {
98+
continue;
99+
}
100+
classify_arg_ty(arg, xlen, &mut remaining_gpr);
101+
}
102+
}

src/librustc_target/spec/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,8 @@ supported_targets! {
473473
("thumbv8m.main-none-eabihf", thumbv8m_main_none_eabihf),
474474

475475
("msp430-none-elf", msp430_none_elf),
476+
("xtensa-esp32-none-elf", xtensa_esp32_none_elf),
477+
("xtensa-esp8266-none-elf", xtensa_esp8266_none_elf),
476478

477479
("aarch64-unknown-cloudabi", aarch64_unknown_cloudabi),
478480
("armv7-unknown-cloudabi-eabihf", armv7_unknown_cloudabi_eabihf),
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use crate::spec::{abi::Abi, LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
2+
// use crate::spec::abi::Abi;
3+
4+
pub fn target() -> TargetResult {
5+
Ok(Target {
6+
llvm_target: "xtensa-none-elf".to_string(),
7+
target_endian: "little".to_string(),
8+
target_pointer_width: "32".to_string(),
9+
target_c_int_width: "32".to_string(),
10+
data_layout: "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-f64:64-a:0:32-n32".to_string(),
11+
arch: "xtensa".to_string(),
12+
target_os: "none".to_string(),
13+
target_env: String::new(),
14+
target_vendor: String::new(),
15+
linker_flavor: LinkerFlavor::Gcc,
16+
17+
options: TargetOptions {
18+
executables: true,
19+
cpu: "esp32".to_string(),
20+
// The LLVM backend currently can't generate object files. To
21+
// workaround this LLVM generates assembly files which then we feed
22+
// to gcc to get object files. For this reason we have a hard
23+
// dependency on this specific gcc.
24+
// asm_args: vec!["-mcpu=esp32".to_string()],
25+
linker: Some("xtensa-esp32-elf-gcc".to_string()),
26+
no_integrated_as: true,
27+
28+
max_atomic_width: Some(32),
29+
atomic_cas: true,
30+
31+
// Because these devices have very little resources having an
32+
// unwinder is too onerous so we default to "abort" because the
33+
// "unwind" strategy is very rare.
34+
panic_strategy: PanicStrategy::Abort,
35+
36+
// Similarly, one almost always never wants to use relocatable
37+
// code because of the extra costs it involves.
38+
relocation_model: "static".to_string(),
39+
40+
// Right now we invoke an external assembler and this isn't
41+
// compatible with multiple codegen units, and plus we probably
42+
// don't want to invoke that many gcc instances.
43+
default_codegen_units: Some(1),
44+
45+
// Since MSP430 doesn't meaningfully support faulting on illegal
46+
// instructions, LLVM generates a call to abort() function instead
47+
// of a trap instruction. Such calls are 4 bytes long, and that is
48+
// too much overhead for such small target.
49+
trap_unreachable: false,
50+
51+
// See the thumb_base.rs file for an explanation of this value
52+
emit_debug_gdb_scripts: false,
53+
54+
abi_blacklist: vec![
55+
Abi::Stdcall,
56+
Abi::Fastcall,
57+
Abi::Vectorcall,
58+
Abi::Thiscall,
59+
Abi::Win64,
60+
Abi::SysV64,
61+
],
62+
63+
..Default::default()
64+
},
65+
})
66+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use crate::spec::{abi::Abi, LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
2+
// use crate::spec::abi::Abi;
3+
4+
pub fn target() -> TargetResult {
5+
Ok(Target {
6+
llvm_target: "xtensa-none-elf".to_string(),
7+
target_endian: "little".to_string(),
8+
target_pointer_width: "32".to_string(),
9+
target_c_int_width: "32".to_string(),
10+
data_layout: "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-f64:64-a:0:32-n32".to_string(),
11+
arch: "xtensa".to_string(),
12+
target_os: "none".to_string(),
13+
target_env: String::new(),
14+
target_vendor: String::new(),
15+
linker_flavor: LinkerFlavor::Gcc,
16+
17+
options: TargetOptions {
18+
executables: true,
19+
cpu: "esp8266".to_string(),
20+
// The LLVM backend currently can't generate object files. To
21+
// workaround this LLVM generates assembly files which then we feed
22+
// to gcc to get object files. For this reason we have a hard
23+
// dependency on this specific gcc.
24+
// asm_args: vec!["-mcpu=esp8266".to_string()],
25+
linker: Some("xtensa-esp32-elf-gcc".to_string()),
26+
no_integrated_as: true,
27+
28+
max_atomic_width: Some(32),
29+
atomic_cas: true,
30+
31+
// Because these devices have very little resources having an
32+
// unwinder is too onerous so we default to "abort" because the
33+
// "unwind" strategy is very rare.
34+
panic_strategy: PanicStrategy::Abort,
35+
36+
// Similarly, one almost always never wants to use relocatable
37+
// code because of the extra costs it involves.
38+
relocation_model: "static".to_string(),
39+
40+
// Right now we invoke an external assembler and this isn't
41+
// compatible with multiple codegen units, and plus we probably
42+
// don't want to invoke that many gcc instances.
43+
default_codegen_units: Some(1),
44+
45+
// Since MSP430 doesn't meaningfully support faulting on illegal
46+
// instructions, LLVM generates a call to abort() function instead
47+
// of a trap instruction. Such calls are 4 bytes long, and that is
48+
// too much overhead for such small target.
49+
trap_unreachable: false,
50+
51+
// See the thumb_base.rs file for an explanation of this value
52+
emit_debug_gdb_scripts: false,
53+
54+
abi_blacklist: vec![
55+
Abi::Stdcall,
56+
Abi::Fastcall,
57+
Abi::Vectorcall,
58+
Abi::Thiscall,
59+
Abi::Win64,
60+
Abi::SysV64,
61+
],
62+
63+
..Default::default()
64+
},
65+
})
66+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use crate::spec::{abi::Abi, LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
2+
// use crate::spec::abi::Abi;
3+
4+
pub fn target() -> TargetResult {
5+
Ok(Target {
6+
llvm_target: "xtensa-none-elf".to_string(),
7+
target_endian: "little".to_string(),
8+
target_pointer_width: "32".to_string(),
9+
target_c_int_width: "32".to_string(),
10+
data_layout: "e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-f64:64-a:0:32-n32".to_string(),
11+
arch: "xtensa".to_string(),
12+
target_os: "none".to_string(),
13+
target_env: String::new(),
14+
target_vendor: String::new(),
15+
linker_flavor: LinkerFlavor::Gcc,
16+
17+
options: TargetOptions {
18+
executables: true,
19+
20+
// The LLVM backend currently can't generate object files. To
21+
// workaround this LLVM generates assembly files which then we feed
22+
// to gcc to get object files. For this reason we have a hard
23+
// dependency on this specific gcc.
24+
// asm_args: vec!["-mcpu=generic".to_string()],
25+
linker: Some("xtensa-esp32-elf-gcc".to_string()),
26+
no_integrated_as: true,
27+
28+
max_atomic_width: Some(32),
29+
atomic_cas: true,
30+
31+
// Because these devices have very little resources having an
32+
// unwinder is too onerous so we default to "abort" because the
33+
// "unwind" strategy is very rare.
34+
panic_strategy: PanicStrategy::Abort,
35+
36+
// Similarly, one almost always never wants to use relocatable
37+
// code because of the extra costs it involves.
38+
relocation_model: "static".to_string(),
39+
40+
// Right now we invoke an external assembler and this isn't
41+
// compatible with multiple codegen units, and plus we probably
42+
// don't want to invoke that many gcc instances.
43+
default_codegen_units: Some(1),
44+
45+
// Since MSP430 doesn't meaningfully support faulting on illegal
46+
// instructions, LLVM generates a call to abort() function instead
47+
// of a trap instruction. Such calls are 4 bytes long, and that is
48+
// too much overhead for such small target.
49+
trap_unreachable: false,
50+
51+
// See the thumb_base.rs file for an explanation of this value
52+
emit_debug_gdb_scripts: false,
53+
54+
abi_blacklist: vec![
55+
Abi::Stdcall,
56+
Abi::Fastcall,
57+
Abi::Vectorcall,
58+
Abi::Thiscall,
59+
Abi::Win64,
60+
Abi::SysV64,
61+
],
62+
63+
..Default::default()
64+
},
65+
})
66+
}

src/rustllvm/PassWrapper.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,14 @@ void LLVMRustAddLastExtensionPasses(
174174
#define SUBTARGET_HEXAGON
175175
#endif
176176

177+
#ifdef LLVM_COMPONENT_XTENSA
178+
#define SUBTARGET_XTENSA SUBTARGET(XTENSA)
179+
#else
180+
#define SUBTARGET_XTENSA
181+
#endif
182+
183+
184+
177185
#define GEN_SUBTARGETS \
178186
SUBTARGET_X86 \
179187
SUBTARGET_ARM \
@@ -185,6 +193,7 @@ void LLVMRustAddLastExtensionPasses(
185193
SUBTARGET_SPARC \
186194
SUBTARGET_HEXAGON \
187195
SUBTARGET_RISCV \
196+
SUBTARGET_XTENSA \
188197

189198
#define SUBTARGET(x) \
190199
namespace llvm { \

0 commit comments

Comments
 (0)