From e1a13e433f1eed40524776d1c0b8965a72d77d17 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 30 Jul 2024 22:10:39 +0200 Subject: [PATCH] Experimental xtensa support --- lib/std/core/env.c3 | 1 + releasenotes.md | 1 + src/build/build.h | 1 + src/build/build_options.c | 1 + src/compiler/abi/c_abi.c | 52 +++++++++++++++++++++++++++++----- src/compiler/asm_target.c | 2 ++ src/compiler/c_abi_internal.h | 2 +- src/compiler/codegen_general.c | 2 ++ src/compiler/compiler.c | 3 ++ src/compiler/target.c | 37 ++++++++++++++++++++---- src/compiler/target.h | 4 ++- 11 files changed, 92 insertions(+), 14 deletions(-) diff --git a/lib/std/core/env.c3 b/lib/std/core/env.c3 index e9e9c8fa1..cdacc7d25 100644 --- a/lib/std/core/env.c3 +++ b/lib/std/core/env.c3 @@ -112,6 +112,7 @@ enum ArchType WASM64, // WebAssembly with 64-bit pointers RSCRIPT32, // 32-bit RenderScript RSCRIPT64, // 64-bit RenderScript + XTENSA, // Xtensa } const OsType OS_TYPE = (OsType)$$OS_TYPE; diff --git a/releasenotes.md b/releasenotes.md index e38f7d73c..85c0a0ed5 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -16,6 +16,7 @@ - c3c init-lib does not create the directory with the .c3l suffix #1253 - Permit foreach values to be optional. - Add `--show-backtrace` option to disable backtrace for even smaller binary. +- Untested Xtensa support. ### Fixes diff --git a/src/build/build.h b/src/build/build.h index 62c8e0ff3..6b0907e28 100644 --- a/src/build/build.h +++ b/src/build/build.h @@ -317,6 +317,7 @@ typedef enum ELF_RISCV64, ELF_X86, ELF_X64, + ELF_XTENSA, FREEBSD_X86, FREEBSD_X64, LINUX_AARCH64, diff --git a/src/build/build_options.c b/src/build/build_options.c index 1c50727b9..c20baf31f 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -20,6 +20,7 @@ char *arch_os_target[ARCH_OS_TARGET_LAST + 1] = { [ELF_RISCV64] = "elf-riscv64", [ELF_X86] = "elf-x86", [ELF_X64] = "elf-x64", + [ELF_XTENSA] = "elf-xtensa", [FREEBSD_X86] = "freebsd-x86", [FREEBSD_X64] = "freebsd-x64", [LINUX_AARCH64] = "linux-aarch64", diff --git a/src/compiler/abi/c_abi.c b/src/compiler/abi/c_abi.c index ba1795dc4..44568ccab 100644 --- a/src/compiler/abi/c_abi.c +++ b/src/compiler/abi/c_abi.c @@ -197,25 +197,32 @@ void c_abi_func_create(FunctionPrototype *proto) { case ABI_X64: c_abi_func_create_x64(proto); - break; + return; case ABI_X86: c_abi_func_create_x86(proto); - break; + return; case ABI_WIN64: c_abi_func_create_win64(proto); - break; + return; case ABI_AARCH64: c_abi_func_create_aarch64(proto); - break; + return; case ABI_RISCV: c_abi_func_create_riscv(proto); - break; + return; case ABI_WASM: c_abi_func_create_wasm(proto); + return; + case ABI_XTENSA: + c_abi_func_create_default(proto); + return; + case ABI_UNKNOWN: + case ABI_ARM: + case ABI_PPC32: + case ABI_PPC64_SVR4: break; - default: - FATAL_ERROR("Unsupported ABI"); } + FATAL_ERROR("Unsupported ABI"); } @@ -242,3 +249,34 @@ ABIArgInfo *c_abi_classify_argument_type_default(Type *type) return abi_arg_new_direct(); } +void c_abi_func_create_default(FunctionPrototype *prototype) +{ + prototype->ret_abi_info = c_abi_classify_return_type_default(prototype->abi_ret_type); + if (prototype->ret_by_ref) + { + prototype->ret_by_ref_abi_info = c_abi_classify_return_type_default(type_get_ptr(type_flatten(prototype->ret_by_ref_type))); + } + + Type **params = prototype->param_types; + unsigned param_count = vec_size(prototype->param_types); + if (param_count) + { + ABIArgInfo **args = MALLOC(sizeof(ABIArgInfo) * param_count); + for (unsigned i = 0; i < param_count; i++) + { + args[i] = c_abi_classify_argument_type_default(params[i]); + } + prototype->abi_args = args; + } + Type **va_params = prototype->varargs; + unsigned va_param_count = vec_size(va_params); + if (va_param_count) + { + ABIArgInfo **args = MALLOC(sizeof(ABIArgInfo) * va_param_count); + for (unsigned i = 0; i < va_param_count; i++) + { + args[i] = c_abi_classify_argument_type_default(va_params[i]); + } + prototype->abi_varargs = args; + } +} \ No newline at end of file diff --git a/src/compiler/asm_target.c b/src/compiler/asm_target.c index db7f52f13..112339b8f 100644 --- a/src/compiler/asm_target.c +++ b/src/compiler/asm_target.c @@ -459,6 +459,8 @@ void init_asm(void) case ARCH_TYPE_WASM32: init_asm_wasm(); return; + case ARCH_TYPE_XTENSA: + error_exit("Xtensa asm support not yet available."); case ARCH_TYPE_UNKNOWN: error_exit("Unknown arch does not support asm."); UNREACHABLE diff --git a/src/compiler/c_abi_internal.h b/src/compiler/c_abi_internal.h index 6172d47a1..9291cb2b6 100644 --- a/src/compiler/c_abi_internal.h +++ b/src/compiler/c_abi_internal.h @@ -53,7 +53,7 @@ void c_abi_func_create_x64(FunctionPrototype *prototype); void c_abi_func_create_aarch64(FunctionPrototype *prototype); void c_abi_func_create_riscv(FunctionPrototype *prototype); void c_abi_func_create_wasm(FunctionPrototype *prototype); - +void c_abi_func_create_default(FunctionPrototype *prototype); static inline AbiType abi_type_get(Type *type) { diff --git a/src/compiler/codegen_general.c b/src/compiler/codegen_general.c index 159d13acb..bd72e073b 100644 --- a/src/compiler/codegen_general.c +++ b/src/compiler/codegen_general.c @@ -125,6 +125,7 @@ bool type_is_homogenous_base_type(Type *type) case ABI_WASM: case ABI_PPC32: case ABI_RISCV: + case ABI_XTENSA: return false; } UNREACHABLE @@ -150,6 +151,7 @@ bool type_homogenous_aggregate_small_enough(Type *type, unsigned members) case ABI_WASM: case ABI_PPC32: case ABI_RISCV: + case ABI_XTENSA: return false; } UNREACHABLE diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index fddb73bff..f5a5d8374 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -990,6 +990,9 @@ static int jump_buffer_size() case LINUX_RISCV32: // Godbolt test return 76; + case ELF_XTENSA: + // Godbolt 68 => 17 with 32 bit pointers + return 17; case ELF_RISCV64: case LINUX_RISCV64: // Godbolt test diff --git a/src/compiler/target.c b/src/compiler/target.c index 48db7a678..27336e03b 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -1028,6 +1028,8 @@ const char *arch_to_linker_arch(ArchType arch) return "wasm32"; case ARCH_TYPE_WASM64: return "wasm64"; + case ARCH_TYPE_XTENSA: + return "xtensa"; } UNREACHABLE; } @@ -1055,6 +1057,7 @@ static char *arch_to_target_triple[ARCH_OS_TARGET_LAST + 1] = { [ELF_RISCV32] = "riscv32-unknown-elf", [LINUX_RISCV64] = "riscv64-unknown-linux", [ELF_RISCV64] = "riscv64-unknown-elf", + [ELF_XTENSA] = "xtensa-unknown-elf", [WASM32] = "wasm32-unknown-unknown", [WASM64] = "wasm64-unknown-unknown", }; @@ -1144,6 +1147,7 @@ static ArchType arch_from_llvm_string(StringSlice slice) STRCASE("amd64", ARCH_TYPE_X86_64) STRCASE("x86_64h", ARCH_TYPE_X86_64) STRCASE("xcore", ARCH_TYPE_XCORE) + STRCASE("xtensa", ARCH_TYPE_XTENSA) STRCASE("nvptx", ARCH_TYPE_NVPTX) STRCASE("nvptx64", ARCH_TYPE_NVPTX64) STRCASE("le32", ARCH_TYPE_LE32) @@ -1297,6 +1301,7 @@ static unsigned arch_pointer_bit_width(OsType os, ArchType arch) case ARCH_TYPE_THUMBEB: case ARCH_TYPE_X86: case ARCH_TYPE_WASM32: + case ARCH_TYPE_XTENSA: return 32; case ARCH_TYPE_WASM64: case ARCH_TYPE_AARCH64: @@ -1310,9 +1315,8 @@ static unsigned arch_pointer_bit_width(OsType os, ArchType arch) case ARCH_TYPE_X86_64: if (os == OS_TYPE_NACL) return 32; return 64; - default: - UNREACHABLE } + UNREACHABLE } static unsigned arch_int_register_bit_width(OsType os, ArchType arch) @@ -1330,6 +1334,7 @@ static unsigned arch_int_register_bit_width(OsType os, ArchType arch) case ARCH_TYPE_THUMBEB: case ARCH_TYPE_X86: case ARCH_TYPE_WASM32: + case ARCH_TYPE_XTENSA: return 32; case ARCH_TYPE_WASM64: case ARCH_TYPE_AARCH64: @@ -1343,9 +1348,8 @@ static unsigned arch_int_register_bit_width(OsType os, ArchType arch) case ARCH_TYPE_X86_64: if (os == OS_TYPE_NACL) return 32; return 64; - default: - UNREACHABLE } + UNREACHABLE } static unsigned os_target_supports_float16(OsType os, ArchType arch) @@ -1443,6 +1447,7 @@ static unsigned os_target_supports_int128(OsType os, ArchType arch) case ARCH_TYPE_WASM64: return true; case ARCH_TYPE_PPC: + case ARCH_TYPE_XTENSA: default: return false; } @@ -1547,6 +1552,7 @@ static AlignData os_target_alignment_of_int(OsType os, ArchType arch, uint32_t b case ARCH_TYPE_WASM64: case ARCH_TYPE_RISCV32: case ARCH_TYPE_WASM32: + case ARCH_TYPE_XTENSA: return (AlignData) { MIN(64u, bits), MIN(64u, bits) }; case ARCH_TYPE_RISCV64: return (AlignData) { bits, bits }; @@ -1578,6 +1584,7 @@ static unsigned arch_big_endian(ArchType arch) case ARCH_TYPE_RISCV64: case ARCH_TYPE_WASM32: case ARCH_TYPE_WASM64: + case ARCH_TYPE_XTENSA: return false; case ARCH_TYPE_ARMB: case ARCH_TYPE_THUMBEB: @@ -1615,6 +1622,7 @@ static AlignData os_target_alignment_of_float(OsType os, ArchType arch, uint32_t case ARCH_TYPE_RISCV64: case ARCH_TYPE_WASM32: case ARCH_TYPE_WASM64: + case ARCH_TYPE_XTENSA: return (AlignData) { bits , bits }; case ARCH_TYPE_ARM: case ARCH_TYPE_THUMB: @@ -1752,6 +1760,13 @@ INLINE const char *llvm_macos_target_triple(const char *triple) scratch_buffer_printf("%d.%d.0", mac_sdk->macos_min_deploy_target.major, mac_sdk->macos_min_deploy_target.minor); return scratch_buffer_to_string(); } + +#if LLVM_VERSION_MAJOR > 19 +#define XTENSA_AVAILABLE 1 +#else +#define XTENSA_AVAILABLE 0 +#endif + void *llvm_target_machine_create(void) { static bool llvm_initialized = false; @@ -1759,6 +1774,9 @@ void *llvm_target_machine_create(void) if (!llvm_initialized) { llvm_initialized = true; +#if XTENSA_AVAILABLE + INITIALIZE_TARGET(Xtensa); +#endif INITIALIZE_TARGET(ARM); INITIALIZE_TARGET(AArch64); INITIALIZE_TARGET(RISCV); @@ -1821,7 +1839,13 @@ void target_setup(BuildTarget *target) error_exit("Unable to detect the default target, please set an explicit --target value."); } + if (target->arch_os_target == ELF_XTENSA && !XTENSA_AVAILABLE) + { + error_exit("Xtensa support is not available with this LLVM version."); + } + platform_target.target_triple = arch_to_target_triple[target->arch_os_target]; + assert(platform_target.target_triple); platform_target.alloca_address_space = 0; @@ -1856,7 +1880,7 @@ void target_setup(BuildTarget *target) platform_target.arch = arch_from_llvm_string(slice_next_token(&target_triple_string, '-')); if (!arch_is_supported(platform_target.arch)) { - printf("WARNING! This architecture is not supported.\n"); + printf("WARNING! This architecture is unsupported.\n"); } platform_target.vendor = vendor_from_llvm_string(slice_next_token(&target_triple_string, '-')); platform_target.os = os_from_llvm_string(slice_next_token(&target_triple_string, '-')); @@ -1924,6 +1948,9 @@ void target_setup(BuildTarget *target) platform_target.aarch.is_win32 = platform_target.os == OS_TYPE_WIN32; platform_target.abi = ABI_AARCH64; break; + case ARCH_TYPE_XTENSA: + platform_target.abi = ABI_XTENSA; + break; case ARCH_TYPE_WASM32: case ARCH_TYPE_WASM64: platform_target.abi = ABI_WASM; diff --git a/src/compiler/target.h b/src/compiler/target.h index b18f925d1..d67221c35 100644 --- a/src/compiler/target.h +++ b/src/compiler/target.h @@ -59,7 +59,8 @@ typedef enum ARCH_TYPE_WASM64, // WebAssembly with 64-bit pointers ARCH_TYPE_RSCRIPT32, // 32-bit RenderScript ARCH_TYPE_RSCRIPT64, // 64-bit RenderScript - ARCH_TYPE_LAST = ARCH_TYPE_RSCRIPT64 + ARCH_TYPE_XTENSA, // Xtensa + ARCH_TYPE_LAST = ARCH_TYPE_XTENSA } ArchType; @@ -201,6 +202,7 @@ typedef enum ABI_PPC32, ABI_PPC64_SVR4, ABI_RISCV, + ABI_XTENSA, } ABI;