From e863e3dd378c9ba3d5774f9491189e5a991474b0 Mon Sep 17 00:00:00 2001 From: chao an Date: Thu, 18 Apr 2024 14:01:18 +0800 Subject: [PATCH] arch/risc-v: add LLVM clang support Verified on LLVM-Metal: $ riscv64-unknown-elf-clang --version (LLVM-Metal 15.9.0-2023.03.0) clang version 15.9.0 Target: riscv64-unknown-unknown-elf Thread model: posix Signed-off-by: chao an --- arch/arm/src/cmake/Toolchain.cmake | 4 +- arch/risc-v/Kconfig | 4 + arch/risc-v/src/Makefile | 6 +- arch/risc-v/src/cmake/Toolchain.cmake | 98 ++++++++++++++++-------- arch/risc-v/src/common/Toolchain.defs | 105 ++++++++++++++++++++------ 5 files changed, 155 insertions(+), 62 deletions(-) diff --git a/arch/arm/src/cmake/Toolchain.cmake b/arch/arm/src/cmake/Toolchain.cmake index 0ba3fdf239..41d2c89dd6 100644 --- a/arch/arm/src/cmake/Toolchain.cmake +++ b/arch/arm/src/cmake/Toolchain.cmake @@ -67,8 +67,8 @@ else() set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN_PREFIX}) set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN_PREFIX}) - set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) - set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) + set(CMAKE_ASM_COMPILER ${TOOLCHAIN_PREFIX}-gcc) + set(CMAKE_C_COMPILER ${CMAKE_ASM_COMPILER}) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-strip --strip-unneeded) set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}-objcopy) diff --git a/arch/risc-v/Kconfig b/arch/risc-v/Kconfig index 6a6d3f9a39..cf97f0c306 100644 --- a/arch/risc-v/Kconfig +++ b/arch/risc-v/Kconfig @@ -498,6 +498,10 @@ config RISCV_TOOLCHAIN_GNU_RV32 This option should work for any modern GNU toolchain (GCC 5.2 or newer) configured for riscv32-unknown-elf. +config RISCV_TOOLCHAIN_CLANG + bool "LLVM Clang toolchain" + select ARCH_TOOLCHAIN_CLANG + endchoice # Toolchain Selection config RISCV_SEMIHOSTING_HOSTFS diff --git a/arch/risc-v/src/Makefile b/arch/risc-v/src/Makefile index 2333c44cbf..41df61e21c 100644 --- a/arch/risc-v/src/Makefile +++ b/arch/risc-v/src/Makefile @@ -107,11 +107,13 @@ ifeq ($(LD),$(CC)) # -fstack-protector-explicit STRIPCFLAGS = $(filter -fstack-protector%,$(CFLAGS)) endif + LDENTRY ?= -Wl,--entry=__start LDSTARTGROUP ?= -Wl,--start-group LDENDGROUP ?= -Wl,--end-group LDFLAGS := $(addprefix -Xlinker ,$(LDFLAGS)) LDFLAGS += $(filter-out $(STRIPCFLAGS),$(CFLAGS)) else + LDENTRY ?= --entry=__start LDSTARTGROUP ?= --start-group LDENDGROUP ?= --end-group endif @@ -180,7 +182,7 @@ define LINK_ALLSYMS_KASAN $(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp $(Q) $(call COMPILE, kasan_globals.tmp, kasan_globals$(OBJEXT) -fno-sanitize=kernel-address, -x c) $(Q) $(call DELFILE, kasan_globals.tmp)) - $(Q) $(LD) --entry=__start $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \ + $(Q) $(LD) $(LDENTRY) $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \ -o $(NUTTX) $(HEAD_OBJ) $(EXTRA_OBJS) \ $(LDSTARTGROUP) $(LDLIBS) $(EXTRA_LIBS) $(LDENDGROUP) endef @@ -191,7 +193,7 @@ $(addsuffix .tmp,$(ARCHSCRIPT)): $(ARCHSCRIPT) nuttx$(EXEEXT): $(HEAD_OBJ) board/libboard$(LIBEXT) $(addsuffix .tmp,$(ARCHSCRIPT)) $(Q) echo "LD: nuttx" ifeq ($(CONFIG_ALLSYMS)$(CONFIG_MM_KASAN_GLOBAL),) - $(Q) $(LD) --entry=__start $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \ + $(Q) $(LD) $(LDENTRY) $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \ -o $(NUTTX) $(HEAD_OBJ) $(EXTRA_OBJS) \ $(LDSTARTGROUP) $(LDLIBS) $(EXTRA_LIBS) $(LDENDGROUP) else diff --git a/arch/risc-v/src/cmake/Toolchain.cmake b/arch/risc-v/src/cmake/Toolchain.cmake index f25efc04a7..e475238d53 100644 --- a/arch/risc-v/src/cmake/Toolchain.cmake +++ b/arch/risc-v/src/cmake/Toolchain.cmake @@ -24,21 +24,28 @@ set(CMAKE_SYSTEM_VERSION 1) set(CMAKE_C_COMPILER_FORCED TRUE) set(CMAKE_CXX_COMPILER_FORCED TRUE) -if(CONFIG_RISCV_TOOLCHAIN_GNU_RV32 OR CONFIG_RISCV_TOOLCHAIN_GNU_RV64) +if(CONFIG_RISCV_TOOLCHAIN_GNU_RV32 + OR CONFIG_RISCV_TOOLCHAIN_GNU_RV64 + OR CONFIG_RISCV_TOOLCHAIN_CLANG) if(NOT CONFIG_RISCV_TOOLCHAIN) set(CONFIG_RISCV_TOOLCHAIN GNU_RVG) endif() endif() # Default toolchain -find_program(RV_COMPILER riscv-none-elf-gcc) -if(RV_COMPILER) - set(TOOLCHAIN_PREFIX riscv-none-elf) + +if(CONFIG_ARCH_TOOLCHAIN_CLANG) + set(TOOLCHAIN_PREFIX riscv64-unknown-elf) else() - if(CONFIG_RISCV_TOOLCHAIN_GNU_RV32) - set(TOOLCHAIN_PREFIX riscv32-unknown-elf) + find_program(RV_COMPILER riscv-none-elf-gcc) + if(RV_COMPILER) + set(TOOLCHAIN_PREFIX riscv-none-elf) else() - set(TOOLCHAIN_PREFIX riscv64-unknown-elf) + if(CONFIG_RISCV_TOOLCHAIN_GNU_RV32) + set(TOOLCHAIN_PREFIX riscv32-unknown-elf) + else() + set(TOOLCHAIN_PREFIX riscv64-unknown-elf) + endif() endif() endif() @@ -46,26 +53,56 @@ set(CMAKE_LIBRARY_ARCHITECTURE ${TOOLCHAIN_PREFIX}) set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN_PREFIX}) set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN_PREFIX}) -set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) -set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) -set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) -set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-strip --strip-unneeded) -set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}-objcopy) -set(CMAKE_OBJDUMP ${TOOLCHAIN_PREFIX}-objdump) -set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}-gcc) -set(CMAKE_LD ${TOOLCHAIN_PREFIX}-ld) -set(CMAKE_AR ${TOOLCHAIN_PREFIX}-ar) -set(CMAKE_NM ${TOOLCHAIN_PREFIX}-nm) -set(CMAKE_RANLIB ${TOOLCHAIN_PREFIX}-gcc-ranlib) +if(CONFIG_ARCH_TOOLCHAIN_CLANG) + set(CMAKE_ASM_COMPILER ${TOOLCHAIN_PREFIX}-clang) + set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-clang) + set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-clang++) + set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-llvm-strip --strip-unneeded) + set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}-llvm-objcopy) + set(CMAKE_OBJDUMP ${TOOLCHAIN_PREFIX}-llvm-objdump) + set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}-ld) + set(CMAKE_LD ${TOOLCHAIN_PREFIX}-ld) + set(CMAKE_AR ${TOOLCHAIN_PREFIX}-llvm-ar) + set(CMAKE_NM ${TOOLCHAIN_PREFIX}-llvm-nm) + set(CMAKE_RANLIB ${TOOLCHAIN_PREFIX}-llvm-ranlib) -if(CONFIG_LTO_FULL) - add_compile_options(-flto) - if(${CONFIG_RISCV_TOOLCHAIN} STREQUAL "GNU_RVG") + # Since the no_builtin attribute is not fully supported on Clang disable the + # built-in functions, refer: + # https://github.com/apache/incubator-nuttx/pull/5971 + + add_compile_options(-fno-builtin) +else() + set(CMAKE_ASM_COMPILER ${TOOLCHAIN_PREFIX}-gcc) + set(CMAKE_C_COMPILER ${CMAKE_ASM_COMPILER}) + set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) + set(CMAKE_STRIP ${TOOLCHAIN_PREFIX}-strip --strip-unneeded) + set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}-objcopy) + set(CMAKE_OBJDUMP ${TOOLCHAIN_PREFIX}-objdump) + + if(CONFIG_LTO_FULL AND CONFIG_ARCH_TOOLCHAIN_GNU) + set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}-gcc) set(CMAKE_LD ${TOOLCHAIN_PREFIX}-gcc) set(CMAKE_AR ${TOOLCHAIN_PREFIX}-gcc-ar) set(CMAKE_NM ${TOOLCHAIN_PREFIX}-gcc-nm) - add_compile_options(-fuse-linker-plugin) + set(CMAKE_RANLIB ${TOOLCHAIN_PREFIX}-gcc-ranlib) + else() + set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}-ld) + set(CMAKE_LD ${TOOLCHAIN_PREFIX}-ld) + set(CMAKE_AR ${TOOLCHAIN_PREFIX}-ar) + set(CMAKE_NM ${TOOLCHAIN_PREFIX}-nm) + set(CMAKE_RANLIB ${TOOLCHAIN_PREFIX}-ranlib) + endif() +endif() + +# Link Time Optimization + +if(CONFIG_LTO_THIN) + add_compile_options(-flto=thin) +elseif(CONFIG_LTO_FULL) + add_compile_options(-flto) + if(CONFIG_ARCH_TOOLCHAIN_GNU) add_compile_options(-fno-builtin) + add_compile_options(-fuse-linker-plugin) endif() endif() @@ -78,7 +115,11 @@ set(CMAKE_ASM_ARCHIVE_CREATE " rcs ") if(CONFIG_DEBUG_CUSTOMOPT) add_compile_options(${CONFIG_DEBUG_OPTLEVEL}) elseif(CONFIG_DEBUG_FULLOPT) - add_compile_options(-Os) + if(CONFIG_ARCH_TOOLCHAIN_CLANG) + add_compile_options(-Oz) + else() + add_compile_options(-Os) + endif() endif() if(NOT CONFIG_DEBUG_NOOPT) @@ -180,15 +221,6 @@ endif() # Generic GNU RVG toolchain if(${CONFIG_RISCV_TOOLCHAIN} STREQUAL GNU_RVG) - execute_process(COMMAND ${TOOLCHAIN_PREFIX}-gcc --version - OUTPUT_VARIABLE GCC_VERSION_OUTPUT) - string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" GCC_VERSION - ${GCC_VERSION_OUTPUT}) - string(REGEX MATCH "^[0-9]+" GCC_VERSION_MAJOR ${GCC_VERSION}) - if(GCC_VERSION GREATER_EQUAL 12) - set(ARCHRVISAZ "_zicsr_zifencei") - endif() - set(ARCHCPUEXTFLAGS i) if(CONFIG_ARCH_RV_ISA_M) @@ -227,7 +259,7 @@ if(${CONFIG_RISCV_TOOLCHAIN} STREQUAL GNU_RVG) "${GCC_VERSION_OUTPUT}") set(GCCVER ${CMAKE_MATCH_1}) endif() - if(GCCVER GREATER_EQUAL 12) + if(GCCVER GREATER_EQUAL 12 OR CONFIG_ARCH_TOOLCHAIN_CLANG) set(ARCHCPUEXTFLAGS ${ARCHCPUEXTFLAGS}_zicsr_zifencei) endif() endif() diff --git a/arch/risc-v/src/common/Toolchain.defs b/arch/risc-v/src/common/Toolchain.defs index 66d2a7805b..27d3c0c678 100644 --- a/arch/risc-v/src/common/Toolchain.defs +++ b/arch/risc-v/src/common/Toolchain.defs @@ -31,6 +31,8 @@ ifeq ($(filter y, $(CONFIG_RISCV_TOOLCHAIN_GNU_RV64)),y) CONFIG_RISCV_TOOLCHAIN ?= GNU_RVG else ifeq ($(filter y, $(CONFIG_RISCV_TOOLCHAIN_GNU_RV32)),y) CONFIG_RISCV_TOOLCHAIN ?= GNU_RVG +else ifeq ($(filter y, $(CONFIG_RISCV_TOOLCHAIN_CLANG)),y) + CONFIG_RISCV_TOOLCHAIN ?= GNU_RVG endif # @@ -48,7 +50,11 @@ endif ifeq ($(CONFIG_DEBUG_CUSTOMOPT),y) ARCHOPTIMIZATION += $(CONFIG_DEBUG_OPTLEVEL) else ifeq ($(CONFIG_DEBUG_FULLOPT),y) - ARCHOPTIMIZATION += -Os + ifeq ($(CONFIG_ARCH_TOOLCHAIN_CLANG),y) + ARCHOPTIMIZATION += -Oz + else + ARCHOPTIMIZATION += -Os + endif endif ifneq ($(CONFIG_DEBUG_NOOPT),y) @@ -123,7 +129,8 @@ ifeq ($(CONFIG_DEBUG_OPT_UNUSED_SECTIONS),y) ARCHOPTIMIZATION += -ffunction-sections -fdata-sections endif -LDFLAGS += -nostdlib +LDFLAGS += -nostdlib +ARCHOPTIMIZATION += -nostdlib # Debug link map @@ -142,13 +149,17 @@ ifeq ($(CONFIG_RISCV_TOOLCHAIN),GNU_RVG) # Generic GNU RVG toolchain, prefer to use riscv-none-elf-gcc from xPack # if CROSSDEV is not defined. - ifeq ($(shell riscv-none-elf-gcc --version > /dev/null 2>&1; echo $$?), 0) - CROSSDEV ?= riscv-none-elf- + ifeq ($(CONFIG_ARCH_TOOLCHAIN_CLANG),y) + CROSSDEV ?= riscv64-unknown-elf- else - ifeq ($(CONFIG_RISCV_TOOLCHAIN_GNU_RV32),y) - CROSSDEV ?= riscv32-unknown-elf- + ifeq ($(shell riscv-none-elf-gcc --version > /dev/null 2>&1; echo $$?), 0) + CROSSDEV ?= riscv-none-elf- else - CROSSDEV ?= riscv64-unknown-elf- + ifeq ($(CONFIG_RISCV_TOOLCHAIN_GNU_RV32),y) + CROSSDEV ?= riscv32-unknown-elf- + else + CROSSDEV ?= riscv64-unknown-elf- + endif endif endif @@ -292,34 +303,78 @@ ifeq ($(CONFIG_ARCH_INSTRUMENT_ALL),y) ARCHOPTIMIZATION += -finstrument-functions endif +# Link Time Optimization + +ifeq ($(CONFIG_LTO_THIN),y) + ARCHOPTIMIZATION += -flto=thin +else ifeq ($(CONFIG_LTO_FULL),y) + ARCHOPTIMIZATION += -flto + ifeq ($(CONFIG_ARM_TOOLCHAIN_GNU_EABI),y) + ARCHOPTIMIZATION += -fuse-linker-plugin + endif +endif + +# Clang toolchain + +ifeq ($(CONFIG_ARCH_TOOLCHAIN_CLANG),y) + + CC = $(CROSSDEV)clang + CXX = $(CROSSDEV)clang++ + CPP = $(CROSSDEV)clang -E -P -x c + LD = $(CROSSDEV)clang + STRIP = $(CROSSDEV)llvm-strip --strip-unneeded + AR = $(CROSSDEV)llvm-ar rcs + NM = $(CROSSDEV)llvm-nm + OBJCOPY = $(CROSSDEV)llvm-objcopy + OBJDUMP = $(CROSSDEV)llvm-objdump + + # Since the no_builtin attribute is not fully supported on Clang + # disable the built-in functions, refer: + # https://github.com/apache/nuttx/pull/5971 + + ARCHOPTIMIZATION += -fno-builtin + + ARCHOPTIMIZATION += -fshort-enums + # Default toolchain -CC = $(CROSSDEV)gcc -CXX = $(CROSSDEV)g++ -CPP = $(CROSSDEV)gcc -E -P -x c -STRIP = $(CROSSDEV)strip --strip-unneeded -OBJCOPY = $(CROSSDEV)objcopy -OBJDUMP = $(CROSSDEV)objdump -LD = $(CROSSDEV)ld -AR = $(CROSSDEV)ar rcs -NM = $(CROSSDEV)nm +else + + CC = $(CROSSDEV)gcc + CXX = $(CROSSDEV)g++ + CPP = $(CROSSDEV)gcc -E -P -x c + STRIP = $(CROSSDEV)strip --strip-unneeded + OBJCOPY = $(CROSSDEV)objcopy + OBJDUMP = $(CROSSDEV)objdump + LD = $(CROSSDEV)ld + AR = $(CROSSDEV)ar rcs + NM = $(CROSSDEV)nm # Link Time Optimization -ifeq ($(CONFIG_LTO_FULL),y) - ARCHOPTIMIZATION += -flto - ifeq ($(CONFIG_RISCV_TOOLCHAIN),GNU_RVG) - LD := $(CROSSDEV)gcc - AR := $(CROSSDEV)gcc-ar rcs - NM := $(CROSSDEV)gcc-nm - ARCHOPTIMIZATION += -fuse-linker-plugin - ARCHOPTIMIZATION += -fno-builtin + ifeq ($(CONFIG_LTO_FULL),y) + ifeq ($(CONFIG_RISCV_TOOLCHAIN),GNU_RVG) + LD := $(CROSSDEV)gcc + AR := $(CROSSDEV)gcc-ar rcs + NM := $(CROSSDEV)gcc-nm + ARCHOPTIMIZATION += -fno-builtin + endif endif + endif # Add the builtin library -EXTRA_LIBS += $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-libgcc-file-name)) +COMPILER_RT_LIB = $(shell $(CC) $(ARCHCPUFLAGS) --print-libgcc-file-name) +ifeq ($(CONFIG_ARCH_TOOLCHAIN_CLANG),y) + ifeq ($(wildcard $(COMPILER_RT_LIB)),) + # if "--print-libgcc-file-name" unable to find the correct libgcc PATH + # then go ahead and try "--print-file-name" + COMPILER_RT_LIB := $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name $(notdir $(COMPILER_RT_LIB)))) + endif +endif + +EXTRA_LIBS += $(COMPILER_RT_LIB) ifeq ($(CONFIG_LIBM_TOOLCHAIN),y) EXTRA_LIBS += $(wildcard $(shell $(CC) $(ARCHCPUFLAGS) --print-file-name=libm.a))