From cf3cd43d5ac56ae73679f0bb8b76807aaaf868dd Mon Sep 17 00:00:00 2001 From: Chung-Ju Wu Date: Sat, 2 Jun 2018 14:22:12 +0000 Subject: [PATCH] [NDS32] Support Linux target for nds32. gcc/ * config.gcc (nds32*): Use nds32-linux.opt and nds32-elf.opt. (nds32le-*-*, nds32be-*-*): Integrate checking process. (nds32*-*-*): Add glibc and uclibc conditions. * common/config/nds32/nds32-common.c (nds32_except_unwind_info): New. (TARGET_EXCEPT_UNWIND_INFO): Define. * config/nds32/elf.h: New file. * config/nds32/linux.h: New file. * config/nds32/nds32-elf.opt: New file. * config/nds32/nds32-linux.opt: New file. * config/nds32/nds32-fp-as-gp.c (pass_nds32_fp_as_gp::gate): Consider TARGET_LINUX_ABI. * config/nds32/nds32.c (nds32_conditional_register_usage): Consider TARGET_LINUX_ABI. (nds32_asm_file_end): Ditto. (nds32_print_operand): Ditto. (nds32_insert_attributes): Ditto. (nds32_init_libfuncs): New function. (TARGET_HAVE_TLS): Define. (TARGET_INIT_LIBFUNCS): Define. * config/nds32/nds32.h (TARGET_DEFAULT_RELAX): Apply different relax spec content. (TARGET_ELF): Apply different mcmodel setting. (LINK_SPEC, LIB_SPEC, STARTFILE_SPEC, ENDFILE_SPEC): The content has been migrated into elf.h and linux.h files. * config/nds32/nds32.md (add_pc): Consider TARGET_LINUX_ABI. * config/nds32/nds32.opt (mvh): Consider TARGET_LINUX_ABI. (mcmodel): The content has been migrated into nds32-elf.opt and nds32-linux.opt files. * config/nds32/t-elf: New file. * config/nds32/t-linux: New file. libgcc/ * config.host (nds32*-linux*): New. * config/nds32/linux-atomic.c: New file. * config/nds32/linux-unwind.h: New file. Co-Authored-By: Kito Cheng Co-Authored-By: Monk Chiang From-SVN: r261116 --- gcc/ChangeLog | 34 +++ gcc/common/config/nds32/nds32-common.c | 15 +- gcc/config.gcc | 59 +++++- gcc/config/nds32/elf.h | 81 +++++++ gcc/config/nds32/linux.h | 77 +++++++ gcc/config/nds32/nds32-elf.opt | 16 ++ gcc/config/nds32/nds32-fp-as-gp.c | 3 +- gcc/config/nds32/nds32-linux.opt | 16 ++ gcc/config/nds32/nds32.c | 52 ++++- gcc/config/nds32/nds32.h | 44 ++-- gcc/config/nds32/nds32.md | 2 +- gcc/config/nds32/nds32.opt | 19 +- gcc/config/nds32/t-elf | 42 ++++ gcc/config/nds32/t-linux | 26 +++ libgcc/ChangeLog | 7 + libgcc/config.host | 17 ++ libgcc/config/nds32/linux-atomic.c | 282 +++++++++++++++++++++++++ libgcc/config/nds32/linux-unwind.h | 156 ++++++++++++++ 18 files changed, 876 insertions(+), 72 deletions(-) create mode 100644 gcc/config/nds32/elf.h create mode 100644 gcc/config/nds32/linux.h create mode 100644 gcc/config/nds32/nds32-elf.opt create mode 100644 gcc/config/nds32/nds32-linux.opt create mode 100644 gcc/config/nds32/t-elf create mode 100644 gcc/config/nds32/t-linux create mode 100644 libgcc/config/nds32/linux-atomic.c create mode 100644 libgcc/config/nds32/linux-unwind.h diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8f1bd35b71e..0e6eef70fbb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,37 @@ +2018-06-02 Chung-Ju Wu + Kito Cheng + + * config.gcc (nds32*): Use nds32-linux.opt and nds32-elf.opt. + (nds32le-*-*, nds32be-*-*): Integrate checking process. + (nds32*-*-*): Add glibc and uclibc conditions. + * common/config/nds32/nds32-common.c (nds32_except_unwind_info): New. + (TARGET_EXCEPT_UNWIND_INFO): Define. + * config/nds32/elf.h: New file. + * config/nds32/linux.h: New file. + * config/nds32/nds32-elf.opt: New file. + * config/nds32/nds32-linux.opt: New file. + * config/nds32/nds32-fp-as-gp.c + (pass_nds32_fp_as_gp::gate): Consider TARGET_LINUX_ABI. + * config/nds32/nds32.c (nds32_conditional_register_usage): Consider + TARGET_LINUX_ABI. + (nds32_asm_file_end): Ditto. + (nds32_print_operand): Ditto. + (nds32_insert_attributes): Ditto. + (nds32_init_libfuncs): New function. + (TARGET_HAVE_TLS): Define. + (TARGET_INIT_LIBFUNCS): Define. + * config/nds32/nds32.h (TARGET_DEFAULT_RELAX): Apply different relax + spec content. + (TARGET_ELF): Apply different mcmodel setting. + (LINK_SPEC, LIB_SPEC, STARTFILE_SPEC, ENDFILE_SPEC): The content has + been migrated into elf.h and linux.h files. + * config/nds32/nds32.md (add_pc): Consider TARGET_LINUX_ABI. + * config/nds32/nds32.opt (mvh): Consider TARGET_LINUX_ABI. + (mcmodel): The content has been migrated into nds32-elf.opt and + nds32-linux.opt files. + * config/nds32/t-elf: New file. + * config/nds32/t-linux: New file. + 2018-06-02 Chung-Ju Wu Shiva Chen diff --git a/gcc/common/config/nds32/nds32-common.c b/gcc/common/config/nds32/nds32-common.c index 04dc8646ffb..e4478f166c5 100644 --- a/gcc/common/config/nds32/nds32-common.c +++ b/gcc/common/config/nds32/nds32-common.c @@ -87,6 +87,19 @@ static const struct default_options nds32_option_optimization_table[] = }; /* ------------------------------------------------------------------------ */ + +/* Implement TARGET_EXCEPT_UNWIND_INFO. */ +static enum unwind_info_type +nds32_except_unwind_info (struct gcc_options *opts ATTRIBUTE_UNUSED) +{ + if (TARGET_LINUX_ABI) + return UI_DWARF2; + + return UI_SJLJ; +} + +/* ------------------------------------------------------------------------ */ + /* Run-time Target Specification. */ @@ -127,7 +140,7 @@ static const struct default_options nds32_option_optimization_table[] = /* Defining the Output Assembler Language. */ #undef TARGET_EXCEPT_UNWIND_INFO -#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info +#define TARGET_EXCEPT_UNWIND_INFO nds32_except_unwind_info /* ------------------------------------------------------------------------ */ diff --git a/gcc/config.gcc b/gcc/config.gcc index 4d9f9c6ea29..c3aecbfe764 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -448,6 +448,16 @@ mips*-*-*) nds32*) cpu_type=nds32 extra_headers="nds32_intrinsic.h" + case ${target} in + nds32*-*-linux*) + extra_options="${extra_options} nds32/nds32-linux.opt" + ;; + nds32*-*-elf*) + extra_options="${extra_options} nds32/nds32-elf.opt" + ;; + *) + ;; + esac extra_objs="nds32-cost.o nds32-intrinsic.o nds32-isr.o nds32-md-auxiliary.o nds32-pipelines-auxiliary.o nds32-predicates.o nds32-memory-manipulation.o nds32-fp-as-gp.o nds32-relax-opt.o nds32-utils.o" ;; nios2-*-*) @@ -2335,18 +2345,32 @@ msp430*-*-*) tmake_file="${tmake_file} msp430/t-msp430" extra_gcc_objs="driver-msp430.o" ;; -nds32le-*-*) +nds32*-*-*) target_cpu_default="0" tm_defines="${tm_defines}" - tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file} nds32/nds32_intrinsic.h" - tmake_file="nds32/t-nds32 nds32/t-mlibs" - ;; -nds32be-*-*) - target_cpu_default="0|MASK_BIG_ENDIAN" - tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" - tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file} nds32/nds32_intrinsic.h" - tmake_file="nds32/t-nds32 nds32/t-mlibs" + case ${target} in + nds32le*-*-*) + ;; + nds32be-*-*) + target_cpu_default="${target_cpu_default}|MASK_BIG_ENDIAN" + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" + ;; + esac + case ${target} in + nds32*-*-elf*) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file} nds32/elf.h nds32/nds32_intrinsic.h" + tmake_file="nds32/t-nds32 nds32/t-elf" + ;; + nds32*-*-linux*) + tm_file="dbxelf.h elfos.h ${tm_file} gnu-user.h linux.h glibc-stdint.h nds32/linux.h nds32/nds32_intrinsic.h" + tmake_file="${tmake_file} nds32/t-nds32 nds32/t-linux" + ;; + esac + # Handle --enable-default-relax setting. + if test x${enable_default_relax} = xyes; then + tm_defines="${tm_defines} TARGET_DEFAULT_RELAX=1" + fi # Handle --with-ext-dsp if test x${with_ext_dsp} = xyes; then tm_defines="${tm_defines} TARGET_DEFAULT_EXT_DSP=1" @@ -4383,15 +4407,30 @@ case "${target}" in "") # the default library is newlib with_nds32_lib=newlib + tm_defines="${tm_defines} TARGET_DEFAULT_CTOR_DTOR=1" ;; newlib) # OK + tm_defines="${tm_defines} TARGET_DEFAULT_CTOR_DTOR=1" ;; mculib) # OK + # for the arch=v3f or arch=v3s under mculib toolchain, + # we would like to set -fno-math-errno as default + case "${with_arch}" in + v3f | v3s) + tm_defines="${tm_defines} TARGET_DEFAULT_NO_MATH_ERRNO=1" + ;; + esac + ;; + glibc) + # OK + tm_defines="${tm_defines} TARGET_DEFAULT_TLSDESC_TRAMPOLINE=1" + ;; + uclibc) ;; *) - echo "Cannot accept --with-nds32-lib=$with_nds32_lib, available values are: newlib mculib" 1>&2 + echo "Cannot accept --with-nds32-lib=$with_nds32_lib, available values are: newlib mculib glibc uclibc" 1>&2 exit 1 ;; esac diff --git a/gcc/config/nds32/elf.h b/gcc/config/nds32/elf.h new file mode 100644 index 00000000000..66397ac2e30 --- /dev/null +++ b/gcc/config/nds32/elf.h @@ -0,0 +1,81 @@ +/* Definitions of target machine of Andes NDS32 cpu for GNU compiler + Copyright (C) 2012-2014 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + + +/* ------------------------------------------------------------------------ */ + +#define TARGET_LINUX_ABI 0 + +/* In the configure stage we may use options --enable-default-relax, + --enable-Os-default-ifc and --enable-Os-default-ex9. They effect + the default spec of passing --relax, --mifc, and --mex9 to linker. + We use NDS32_RELAX_SPEC, NDS32_IFC_SPEC, and NDS32_EX9_SPEC + so that we can customize them conveniently. */ +#define LINK_SPEC \ + " %{G*}" \ + " %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + " %{shared:-shared}" \ + NDS32_RELAX_SPEC + +#define LIB_SPEC \ + " -lc -lgloss" + +#define LIBGCC_SPEC \ + " -lgcc" + +/* The option -mno-ctor-dtor can disable constructor/destructor feature + by applying different crt stuff. In the convention, crt0.o is the + startup file without constructor/destructor; + crt1.o, crti.o, crtbegin.o, crtend.o, and crtn.o are the + startup files with constructor/destructor. + Note that crt0.o, crt1.o, crti.o, and crtn.o are provided + by newlib/mculib/glibc/ublic, while crtbegin.o and crtend.o are + currently provided by GCC for nds32 target. + + For nds32 target so far: + If -mno-ctor-dtor, we are going to link + "crt0.o [user objects]". + If -mctor-dtor, we are going to link + "crt1.o crtbegin1.o [user objects] crtend1.o". + + Note that the TARGET_DEFAULT_CTOR_DTOR would effect the + default behavior. Check gcc/config.gcc for more information. */ +#ifdef TARGET_DEFAULT_CTOR_DTOR + #define STARTFILE_SPEC \ + " %{!mno-ctor-dtor:crt1.o%s;:crt0.o%s}" \ + " %{!mno-ctor-dtor:crtbegin1.o%s}" \ + " %{mcrt-arg:crtarg.o%s}" + #define ENDFILE_SPEC \ + " %{!mno-ctor-dtor:crtend1.o%s}" +#else + #define STARTFILE_SPEC \ + " %{mctor-dtor|coverage:crt1.o%s;:crt0.o%s}" \ + " %{mctor-dtor|coverage:crtbegin1.o%s}" \ + " %{mcrt-arg:crtarg.o%s}" + #define ENDFILE_SPEC \ + " %{mctor-dtor|coverage:crtend1.o%s}" +#endif + +#define STARTFILE_CXX_SPEC \ + " %{!mno-ctor-dtor:crt1.o%s;:crt0.o%s}" \ + " %{!mno-ctor-dtor:crtbegin1.o%s}" \ + " %{mcrt-arg:crtarg.o%s}" +#define ENDFILE_CXX_SPEC \ + " %{!mno-ctor-dtor:crtend1.o%s}" diff --git a/gcc/config/nds32/linux.h b/gcc/config/nds32/linux.h new file mode 100644 index 00000000000..a0ec1b2bfd4 --- /dev/null +++ b/gcc/config/nds32/linux.h @@ -0,0 +1,77 @@ +/* Definitions of target machine of Andes NDS32 cpu for GNU compiler + Copyright (C) 2012-2014 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + + +/* ------------------------------------------------------------------------ */ + +#define TARGET_LINUX_ABI 1 + +#undef SIZE_TYPE +#define SIZE_TYPE "unsigned int" + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "int" + +#ifdef TARGET_DEFAULT_TLSDESC_TRAMPOLINE + #define NDS32_TLSDESC_TRAMPOLINE_SPEC \ + " %{!mno-tlsdesc-trampoline:--mtlsdesc-trampoline}" +#else + #define NDS32_TLSDESC_TRAMPOLINE_SPEC "" +#endif + +#define TARGET_OS_CPP_BUILTINS() \ + do \ + { \ + GNU_USER_TARGET_OS_CPP_BUILTINS(); \ + } \ + while (0) + +#define GLIBC_DYNAMIC_LINKER "/lib/ld.so.1" + +/* In the configure stage we may use options --enable-default-relax, + --enable-Os-default-ifc and --enable-Os-default-ex9. They effect + the default spec of passing --relax, --mifc, and --mex9 to linker. + We use NDS32_RELAX_SPEC, NDS32_IFC_SPEC, and NDS32_EX9_SPEC + so that we can customize them conveniently. */ +#define LINK_SPEC \ + " %{G*}" \ + " %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + " %{shared:-shared} \ + %{!shared: \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + -dynamic-linker " GNU_USER_DYNAMIC_LINKER "} \ + %{static:-static}}" \ + NDS32_RELAX_SPEC \ + NDS32_TLSDESC_TRAMPOLINE_SPEC + +#define LINK_PIE_SPEC "%{pie:%{!fno-pie:%{!fno-PIE:%{!static:-pie}}}} " + +#define CPP_SPEC "%{pthread:-D_REENTRANT}" + +/* The SYNC operations are implemented as library functions, not + INSN patterns. As a result, the HAVE defines for the patterns are + not defined. We need to define them to generate the corresponding + __GCC_HAVE_SYNC_COMPARE_AND_SWAP_* and __GCC_ATOMIC_*_LOCK_FREE + defines. + Ref: https://sourceware.org/ml/libc-alpha/2014-09/msg00322.html */ +#define HAVE_sync_compare_and_swapqi 1 +#define HAVE_sync_compare_and_swaphi 1 +#define HAVE_sync_compare_and_swapsi 1 diff --git a/gcc/config/nds32/nds32-elf.opt b/gcc/config/nds32/nds32-elf.opt new file mode 100644 index 00000000000..afe6aadd089 --- /dev/null +++ b/gcc/config/nds32/nds32-elf.opt @@ -0,0 +1,16 @@ +mcmodel= +Target RejectNegative Joined Enum(nds32_cmodel_type) Var(nds32_cmodel_option) Init(CMODEL_MEDIUM) +Specify the address generation strategy for code model. + +Enum +Name(nds32_cmodel_type) Type(enum nds32_cmodel_type) +Known cmodel types (for use with the -mcmodel= option): + +EnumValue +Enum(nds32_cmodel_type) String(small) Value(CMODEL_SMALL) + +EnumValue +Enum(nds32_cmodel_type) String(medium) Value(CMODEL_MEDIUM) + +EnumValue +Enum(nds32_cmodel_type) String(large) Value(CMODEL_LARGE) diff --git a/gcc/config/nds32/nds32-fp-as-gp.c b/gcc/config/nds32/nds32-fp-as-gp.c index 1abad1dc24a..26d2865d450 100644 --- a/gcc/config/nds32/nds32-fp-as-gp.c +++ b/gcc/config/nds32/nds32-fp-as-gp.c @@ -265,7 +265,8 @@ public: /* opt_pass methods: */ bool gate (function *) { - return TARGET_16_BIT + return !TARGET_LINUX_ABI + && TARGET_16_BIT && optimize_size; } unsigned int execute (function *) { return nds32_fp_as_gp (); } diff --git a/gcc/config/nds32/nds32-linux.opt b/gcc/config/nds32/nds32-linux.opt new file mode 100644 index 00000000000..75ccd7625a2 --- /dev/null +++ b/gcc/config/nds32/nds32-linux.opt @@ -0,0 +1,16 @@ +mcmodel= +Target RejectNegative Joined Enum(nds32_cmodel_type) Var(nds32_cmodel_option) Init(CMODEL_LARGE) +Specify the address generation strategy for code model. + +Enum +Name(nds32_cmodel_type) Type(enum nds32_cmodel_type) +Known cmodel types (for use with the -mcmodel= option): + +EnumValue +Enum(nds32_cmodel_type) String(small) Value(CMODEL_SMALL) + +EnumValue +Enum(nds32_cmodel_type) String(medium) Value(CMODEL_MEDIUM) + +EnumValue +Enum(nds32_cmodel_type) String(large) Value(CMODEL_LARGE) diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c index 1afd8a10156..a0b6443e5d2 100644 --- a/gcc/config/nds32/nds32.c +++ b/gcc/config/nds32/nds32.c @@ -1698,6 +1698,9 @@ nds32_conditional_register_usage (void) { int regno; + if (TARGET_LINUX_ABI) + fixed_regs[TP_REGNUM] = 1; + if (TARGET_HARD_FLOAT) { for (regno = NDS32_FIRST_FPR_REGNUM; @@ -3120,21 +3123,30 @@ nds32_asm_file_start (void) fprintf (asm_out_file, "\t! This asm file is generated by compiler\n"); fprintf (asm_out_file, "\t.flag\tverbatim\n"); - if (TARGET_ICT_MODEL_LARGE) - fprintf (asm_out_file, "\t.ict_model\tlarge\n"); - else - fprintf (asm_out_file, "\t.ict_model\tsmall\n"); - /* Give assembler the size of each vector for interrupt handler. */ - fprintf (asm_out_file, "\t! This vector size directive is required " - "for checking inconsistency on interrupt handler\n"); - fprintf (asm_out_file, "\t.vec_size\t%d\n", nds32_isr_vector_size); + /* Insert directive for linker to distinguish object's ict flag. */ + if (!TARGET_LINUX_ABI) + { + if (TARGET_ICT_MODEL_LARGE) + fprintf (asm_out_file, "\t.ict_model\tlarge\n"); + else + fprintf (asm_out_file, "\t.ict_model\tsmall\n"); + } + + /* We need to provide the size of each vector for interrupt handler + under elf toolchain. */ + if (!TARGET_LINUX_ABI) + { + fprintf (asm_out_file, "\t! This vector size directive is required " + "for checking inconsistency on interrupt handler\n"); + fprintf (asm_out_file, "\t.vec_size\t%d\n", nds32_isr_vector_size); + } /* If user enables '-mforce-fp-as-gp' or compiles programs with -Os, the compiler may produce 'la $fp,_FP_BASE_' instruction at prologue for fp-as-gp optimization. We should emit weak reference of _FP_BASE_ to avoid undefined reference in case user does not pass '--relax' option to linker. */ - if (TARGET_FORCE_FP_AS_GP || optimize_size) + if (!TARGET_LINUX_ABI && (TARGET_FORCE_FP_AS_GP || optimize_size)) { fprintf (asm_out_file, "\t! This weak reference is required to do " "fp-as-gp link time optimization\n"); @@ -3270,6 +3282,11 @@ nds32_asm_file_end (void) { nds32_asm_file_end_for_isr (); + /* The NDS32 Linux stack is mapped non-executable by default, so add a + .note.GNU-stack section. */ + if (TARGET_LINUX_ABI) + file_end_indicate_exec_stack (); + fprintf (asm_out_file, "\t! ------------------------------------\n"); } @@ -3497,7 +3514,7 @@ nds32_print_operand (FILE *stream, rtx x, int code) case SYMBOL_REF: output_addr_const (stream, x); - if (nds32_indirect_call_referenced_p (x)) + if (!TARGET_LINUX_ABI && nds32_indirect_call_referenced_p (x)) fprintf (stream, "@ICT"); break; @@ -3912,6 +3929,9 @@ nds32_insert_attributes (tree decl, tree *attributes) { tree new_attrs = *attributes; + if (TARGET_LINUX_ABI) + error("cannot use indirect_call attribute under linux toolchain"); + if (lookup_attribute ("noinline", new_attrs) == NULL) new_attrs = tree_cons (get_identifier ("noinline"), NULL, new_attrs); if (lookup_attribute ("noclone", new_attrs) == NULL) @@ -4166,6 +4186,13 @@ nds32_expand_builtin (tree exp, return nds32_expand_builtin_impl (exp, target, subtarget, mode, ignore); } +/* Implement TARGET_INIT_LIBFUNCS. */ +static void +nds32_init_libfuncs (void) +{ + if (TARGET_LINUX_ABI) + init_sync_libfuncs (UNITS_PER_WORD); +} /* ------------------------------------------------------------------------ */ @@ -5758,6 +5785,9 @@ nds32_use_blocks_for_constant_p (machine_mode mode, /* Emulating TLS. */ +#undef TARGET_HAVE_TLS +#define TARGET_HAVE_TLS TARGET_LINUX_ABI + /* Defining coprocessor specifics for MIPS targets. */ @@ -5785,6 +5815,8 @@ nds32_use_blocks_for_constant_p (machine_mode mode, #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN nds32_expand_builtin +#undef TARGET_INIT_LIBFUNCS +#define TARGET_INIT_LIBFUNCS nds32_init_libfuncs #undef TARGET_USE_BLOCKS_FOR_CONSTANT_P #define TARGET_USE_BLOCKS_FOR_CONSTANT_P nds32_use_blocks_for_constant_p diff --git a/gcc/config/nds32/nds32.h b/gcc/config/nds32/nds32.h index 523492fea17..84fae7d09df 100644 --- a/gcc/config/nds32/nds32.h +++ b/gcc/config/nds32/nds32.h @@ -922,6 +922,14 @@ enum nds32_builtins #define TARGET_CONFIG_FPU_DEFAULT NDS32_CONFIG_FPU_2 +/* ------------------------------------------------------------------------ */ + +#ifdef TARGET_DEFAULT_RELAX +# define NDS32_RELAX_SPEC " %{!mno-relax:--relax}" +#else +# define NDS32_RELAX_SPEC " %{mrelax:--relax}" +#endif + #ifdef TARGET_DEFAULT_EXT_DSP # define NDS32_EXT_DSP_SPEC " %{!mno-ext-dsp:-mext-dsp}" #else @@ -963,34 +971,6 @@ enum nds32_builtins " %{mext-dsp:-mdsp-ext}" \ " %{O|O1|O2|O3|Ofast:-O1;:-Os}" -/* If user issues -mrelax, we need to pass '--relax' to linker. */ -#define LINK_SPEC \ - " %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ - " %{mrelax:--relax}" - -#define LIB_SPEC \ - " -lc -lgloss" - -/* The option -mno-ctor-dtor can disable constructor/destructor feature - by applying different crt stuff. In the convention, crt0.o is the - startup file without constructor/destructor; - crt1.o, crti.o, crtbegin.o, crtend.o, and crtn.o are the - startup files with constructor/destructor. - Note that crt0.o, crt1.o, crti.o, and crtn.o are provided - by newlib/mculib/glibc/ublic, while crtbegin.o and crtend.o are - currently provided by GCC for nds32 target. - - For nds32 target so far: - If -mno-ctor-dtor, we are going to link - "crt0.o [user objects]". - If general cases, we are going to link - "crt1.o crtbegin1.o [user objects] crtend1.o". */ -#define STARTFILE_SPEC \ - " %{!mno-ctor-dtor:crt1.o%s;:crt0.o%s}" \ - " %{!mno-ctor-dtor:crtbegin1.o%s}" -#define ENDFILE_SPEC \ - " %{!mno-ctor-dtor:crtend1.o%s}" - /* The TARGET_BIG_ENDIAN_DEFAULT is defined if we configure gcc with --target=nds32be-* setting. Check gcc/config.gcc for more information. */ @@ -1000,9 +980,11 @@ enum nds32_builtins # define NDS32_ENDIAN_DEFAULT "mlittle-endian" #endif -/* Currently we only have elf toolchain, - where -mcmodel=medium is always the default. */ -#define NDS32_CMODEL_DEFAULT "mcmodel=medium" +#if TARGET_ELF +# define NDS32_CMODEL_DEFAULT "mcmodel=medium" +#else +# define NDS32_CMODEL_DEFAULT "mcmodel=large" +#endif #define MULTILIB_DEFAULTS \ { NDS32_ENDIAN_DEFAULT, NDS32_CMODEL_DEFAULT } diff --git a/gcc/config/nds32/nds32.md b/gcc/config/nds32/nds32.md index cf1ad9bd1b0..92e90dda1af 100644 --- a/gcc/config/nds32/nds32.md +++ b/gcc/config/nds32/nds32.md @@ -2221,7 +2221,7 @@ [(set (match_operand:SI 0 "register_operand" "=r") (plus:SI (match_operand:SI 1 "register_operand" "0") (pc)))] - "flag_pic" + "TARGET_LINUX_ABI || flag_pic" "add5.pc\t%0" [(set_attr "type" "alu") (set_attr "length" "4")] diff --git a/gcc/config/nds32/nds32.opt b/gcc/config/nds32/nds32.opt index 6f73f897e5d..871ae1e07ca 100644 --- a/gcc/config/nds32/nds32.opt +++ b/gcc/config/nds32/nds32.opt @@ -151,7 +151,7 @@ Target Report Mask(RELAX_HINT) Insert relax hint for linker to do relaxation. mvh -Target Report Mask(VH) +Target Report Mask(VH) Condition(!TARGET_LINUX_ABI) Enable Virtual Hosting support. misr-vector-size= @@ -185,23 +185,6 @@ Enum(nds32_arch_type) String(v3f) Value(ARCH_V3F) EnumValue Enum(nds32_arch_type) String(v3s) Value(ARCH_V3S) -mcmodel= -Target RejectNegative Joined Enum(nds32_cmodel_type) Var(nds32_cmodel_option) Init(CMODEL_LARGE) -Specify the address generation strategy for code model. - -Enum -Name(nds32_cmodel_type) Type(enum nds32_cmodel_type) -Known cmodel types (for use with the -mcmodel= option): - -EnumValue -Enum(nds32_cmodel_type) String(small) Value(CMODEL_SMALL) - -EnumValue -Enum(nds32_cmodel_type) String(medium) Value(CMODEL_MEDIUM) - -EnumValue -Enum(nds32_cmodel_type) String(large) Value(CMODEL_LARGE) - mcpu= Target RejectNegative Joined Enum(nds32_cpu_type) Var(nds32_cpu_option) Init(CPU_N9) Specify the cpu for pipeline model. diff --git a/gcc/config/nds32/t-elf b/gcc/config/nds32/t-elf new file mode 100644 index 00000000000..3401dae4881 --- /dev/null +++ b/gcc/config/nds32/t-elf @@ -0,0 +1,42 @@ +# The multilib settings of Andes NDS32 cpu for GNU compiler +# Copyright (C) 2012-2018 Free Software Foundation, Inc. +# Contributed by Andes Technology Corporation. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 3, or (at your +# option) any later version. +# +# GCC is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# We also define a macro MULTILIB_DEFAULTS in nds32.h that tells the +# driver program which options are defaults for this target and thus +# do not need to be handled specially. +MULTILIB_OPTIONS += mcmodel=small/mcmodel=medium/mcmodel=large mvh + +ifneq ($(filter graywolf,$(TM_MULTILIB_CONFIG)),) +MULTILIB_OPTIONS += mcpu=graywolf +endif + +ifneq ($(filter dsp,$(TM_MULTILIB_CONFIG)),) +MULTILIB_OPTIONS += mext-dsp +endif + +ifneq ($(filter zol,$(TM_MULTILIB_CONFIG)),) +MULTILIB_OPTIONS += mext-zol +endif + +ifneq ($(filter v3m+,$(TM_MULTILIB_CONFIG)),) +MULTILIB_OPTIONS += march=v3m+ +endif + +# ------------------------------------------------------------------------ diff --git a/gcc/config/nds32/t-linux b/gcc/config/nds32/t-linux new file mode 100644 index 00000000000..33328f65e7b --- /dev/null +++ b/gcc/config/nds32/t-linux @@ -0,0 +1,26 @@ +# The multilib settings of Andes NDS32 cpu for GNU compiler +# Copyright (C) 2012-2018 Free Software Foundation, Inc. +# Contributed by Andes Technology Corporation. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 3, or (at your +# option) any later version. +# +# GCC is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# We also define a macro MULTILIB_DEFAULTS in nds32.h that tells the +# driver program which options are defaults for this target and thus +# do not need to be handled specially. +MULTILIB_OPTIONS += + +# ------------------------------------------------------------------------ diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 9a94e8333ab..d75d9340a08 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,10 @@ +2018-06-02 Chung-Ju Wu + Monk Chiang + + * config.host (nds32*-linux*): New. + * config/nds32/linux-atomic.c: New file. + * config/nds32/linux-unwind.h: New file. + 2018-05-31 Uros Bizjak PR target/85591 diff --git a/libgcc/config.host b/libgcc/config.host index f8fd78279d3..18cabaf24f6 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -979,6 +979,23 @@ msp430*-*-elf) tmake_file="$tm_file t-crtstuff t-fdpbit msp430/t-msp430" extra_parts="$extra_parts libmul_none.a libmul_16.a libmul_32.a libmul_f5.a" ;; +nds32*-linux*) + # Basic makefile fragment and extra_parts for crt stuff. + # We also append c-isr library implementation. + tmake_file="${tmake_file} t-slibgcc-libgcc" + tmake_file="${tmake_file} nds32/t-nds32-glibc nds32/t-crtstuff t-softfp-sfdf t-softfp" + # The header file of defining MD_FALLBACK_FRAME_STATE_FOR. + md_unwind_header=nds32/linux-unwind.h + # Append library definition makefile fragment according to --with-nds32-lib=X setting. + case "${with_nds32_lib}" in + "" | glibc | uclibc ) + ;; + *) + echo "Cannot accept --with-nds32-lib=$with_nds32_lib, available values are: glibc uclibc" 1>&2 + exit 1 + ;; + esac + ;; nds32*-elf*) # Basic makefile fragment and extra_parts for crt stuff. # We also append c-isr library implementation. diff --git a/libgcc/config/nds32/linux-atomic.c b/libgcc/config/nds32/linux-atomic.c new file mode 100644 index 00000000000..6da7be9a653 --- /dev/null +++ b/libgcc/config/nds32/linux-atomic.c @@ -0,0 +1,282 @@ +/* Linux-specific atomic operations for NDS32 Linux. + Copyright (C) 2012-2018 Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3, or (at your option) any +later version. + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +/* We implement byte, short and int versions of each atomic operation + using the kernel helper defined below. There is no support for + 64-bit operations yet. */ + +/* This function copy form NDS32 Linux-kernal. */ +static inline int +__kernel_cmpxchg (int oldval, int newval, int *mem) +{ + int temp1, temp2, temp3, offset; + + asm volatile ("msync\tall\n" + "movi\t%0, #0\n" + "1:\n" + "\tllw\t%1, [%4+%0]\n" + "\tsub\t%3, %1, %6\n" + "\tcmovz\t%2, %5, %3\n" + "\tcmovn\t%2, %1, %3\n" + "\tscw\t%2, [%4+%0]\n" + "\tbeqz\t%2, 1b\n" + : "=&r" (offset), "=&r" (temp3), "=&r" (temp2), "=&r" (temp1) + : "r" (mem), "r" (newval), "r" (oldval) : "memory"); + + return temp1; +} + +#define HIDDEN __attribute__ ((visibility ("hidden"))) + +#ifdef __NDS32_EL__ +#define INVERT_MASK_1 0 +#define INVERT_MASK_2 0 +#else +#define INVERT_MASK_1 24 +#define INVERT_MASK_2 16 +#endif + +#define MASK_1 0xffu +#define MASK_2 0xffffu + +#define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP) \ + int HIDDEN \ + __sync_fetch_and_##OP##_4 (int *ptr, int val) \ + { \ + int failure, tmp; \ + \ + do { \ + tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ + failure = __kernel_cmpxchg (tmp, PFX_OP (tmp INF_OP val), ptr); \ + } while (failure != 0); \ + \ + return tmp; \ + } + +FETCH_AND_OP_WORD (add, , +) +FETCH_AND_OP_WORD (sub, , -) +FETCH_AND_OP_WORD (or, , |) +FETCH_AND_OP_WORD (and, , &) +FETCH_AND_OP_WORD (xor, , ^) +FETCH_AND_OP_WORD (nand, ~, &) + +#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH +#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH + +/* Implement both __sync__and_fetch and __sync_fetch_and_ for + subword-sized quantities. */ + +#define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN) \ + TYPE HIDDEN \ + NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val) \ + { \ + int *wordptr = (int *) ((unsigned long) ptr & ~3); \ + unsigned int mask, shift, oldval, newval; \ + int failure; \ + \ + shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ + mask = MASK_##WIDTH << shift; \ + \ + do { \ + oldval = __atomic_load_n (wordptr, __ATOMIC_SEQ_CST); \ + newval = ((PFX_OP (((oldval & mask) >> shift) \ + INF_OP (unsigned int) val)) << shift) & mask; \ + newval |= oldval & ~mask; \ + failure = __kernel_cmpxchg (oldval, newval, wordptr); \ + } while (failure != 0); \ + \ + return (RETURN & mask) >> shift; \ + } + + +SUBWORD_SYNC_OP (add, , +, unsigned short, 2, oldval) +SUBWORD_SYNC_OP (sub, , -, unsigned short, 2, oldval) +SUBWORD_SYNC_OP (or, , |, unsigned short, 2, oldval) +SUBWORD_SYNC_OP (and, , &, unsigned short, 2, oldval) +SUBWORD_SYNC_OP (xor, , ^, unsigned short, 2, oldval) +SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, oldval) + +SUBWORD_SYNC_OP (add, , +, unsigned char, 1, oldval) +SUBWORD_SYNC_OP (sub, , -, unsigned char, 1, oldval) +SUBWORD_SYNC_OP (or, , |, unsigned char, 1, oldval) +SUBWORD_SYNC_OP (and, , &, unsigned char, 1, oldval) +SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, oldval) +SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, oldval) + +#define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP) \ + int HIDDEN \ + __sync_##OP##_and_fetch_4 (int *ptr, int val) \ + { \ + int tmp, failure; \ + \ + do { \ + tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ + failure = __kernel_cmpxchg (tmp, PFX_OP (tmp INF_OP val), ptr); \ + } while (failure != 0); \ + \ + return PFX_OP (tmp INF_OP val); \ + } + +OP_AND_FETCH_WORD (add, , +) +OP_AND_FETCH_WORD (sub, , -) +OP_AND_FETCH_WORD (or, , |) +OP_AND_FETCH_WORD (and, , &) +OP_AND_FETCH_WORD (xor, , ^) +OP_AND_FETCH_WORD (nand, ~, &) + +SUBWORD_SYNC_OP (add, , +, unsigned short, 2, newval) +SUBWORD_SYNC_OP (sub, , -, unsigned short, 2, newval) +SUBWORD_SYNC_OP (or, , |, unsigned short, 2, newval) +SUBWORD_SYNC_OP (and, , &, unsigned short, 2, newval) +SUBWORD_SYNC_OP (xor, , ^, unsigned short, 2, newval) +SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, newval) + +SUBWORD_SYNC_OP (add, , +, unsigned char, 1, newval) +SUBWORD_SYNC_OP (sub, , -, unsigned char, 1, newval) +SUBWORD_SYNC_OP (or, , |, unsigned char, 1, newval) +SUBWORD_SYNC_OP (and, , &, unsigned char, 1, newval) +SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, newval) +SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, newval) + +int HIDDEN +__sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval) +{ + int actual_oldval, fail; + + while (1) + { + actual_oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); + + if (oldval != actual_oldval) + return actual_oldval; + + fail = __kernel_cmpxchg (actual_oldval, newval, ptr); + + if (!fail) + return oldval; + } +} + +#define SUBWORD_VAL_CAS(TYPE, WIDTH) \ + TYPE HIDDEN \ + __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ + TYPE newval) \ + { \ + int *wordptr = (int *)((unsigned long) ptr & ~3), fail; \ + unsigned int mask, shift, actual_oldval, actual_newval; \ + \ + shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ + mask = MASK_##WIDTH << shift; \ + \ + while (1) \ + { \ + actual_oldval = __atomic_load_n (wordptr, __ATOMIC_SEQ_CST); \ + \ + if (((actual_oldval & mask) >> shift) != (unsigned int) oldval) \ + return (actual_oldval & mask) >> shift; \ + \ + actual_newval = (actual_oldval & ~mask) \ + | (((unsigned int) newval << shift) & mask); \ + \ + fail = __kernel_cmpxchg (actual_oldval, actual_newval, \ + wordptr); \ + \ + if (!fail) \ + return oldval; \ + } \ + } + +SUBWORD_VAL_CAS (unsigned short, 2) +SUBWORD_VAL_CAS (unsigned char, 1) + +typedef unsigned char bool; + +bool HIDDEN +__sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval) +{ + int failure = __kernel_cmpxchg (oldval, newval, ptr); + return (failure == 0); +} + +#define SUBWORD_BOOL_CAS(TYPE, WIDTH) \ + bool HIDDEN \ + __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ + TYPE newval) \ + { \ + TYPE actual_oldval \ + = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval); \ + return (oldval == actual_oldval); \ + } + +SUBWORD_BOOL_CAS (unsigned short, 2) +SUBWORD_BOOL_CAS (unsigned char, 1) + +int HIDDEN +__sync_lock_test_and_set_4 (int *ptr, int val) +{ + int failure, oldval; + + do { + oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); + failure = __kernel_cmpxchg (oldval, val, ptr); + } while (failure != 0); + + return oldval; +} + +#define SUBWORD_TEST_AND_SET(TYPE, WIDTH) \ + TYPE HIDDEN \ + __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \ + { \ + int failure; \ + unsigned int oldval, newval, shift, mask; \ + int *wordptr = (int *) ((unsigned long) ptr & ~3); \ + \ + shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ + mask = MASK_##WIDTH << shift; \ + \ + do { \ + oldval = __atomic_load_n (wordptr, __ATOMIC_SEQ_CST); \ + newval = (oldval & ~mask) \ + | (((unsigned int) val << shift) & mask); \ + failure = __kernel_cmpxchg (oldval, newval, wordptr); \ + } while (failure != 0); \ + \ + return (oldval & mask) >> shift; \ + } + +SUBWORD_TEST_AND_SET (unsigned short, 2) +SUBWORD_TEST_AND_SET (unsigned char, 1) + +#define SYNC_LOCK_RELEASE(TYPE, WIDTH) \ + void HIDDEN \ + __sync_lock_release_##WIDTH (TYPE *ptr) \ + { \ + /* All writes before this point must be seen before we release \ + the lock itself. */ \ + __builtin_nds32_msync_all (); \ + *ptr = 0; \ + } + +SYNC_LOCK_RELEASE (int, 4) +SYNC_LOCK_RELEASE (short, 2) +SYNC_LOCK_RELEASE (char, 1) diff --git a/libgcc/config/nds32/linux-unwind.h b/libgcc/config/nds32/linux-unwind.h new file mode 100644 index 00000000000..921edf906ea --- /dev/null +++ b/libgcc/config/nds32/linux-unwind.h @@ -0,0 +1,156 @@ +/* DWARF2 EH unwinding support for NDS32 Linux signal frame. + Copyright (C) 2014-2015 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef inhibit_libc + +/* Do code reading to identify a signal frame, and set the frame + state data appropriately. See unwind-dw2.c for the structs. + The corresponding bits in the Linux kernel are in + arch/nds32/kernel/signal.c. */ + +#include +#include + +/* Exactly the same layout as the kernel structures, unique names. */ + +/* arch/nds32/kernel/signal.c */ +struct _sigframe { + struct ucontext uc; + unsigned long retcode; +}; + +struct _rt_sigframe { + siginfo_t info; + struct _sigframe sig; +}; +#define SIGRETURN 0xeb0e0a64 +#define RT_SIGRETURN 0xab150a64 + +#define MD_FALLBACK_FRAME_STATE_FOR nds32_fallback_frame_state + +/* This function is supposed to be invoked by uw_frame_state_for() + when there is no unwind data available. + + Generally, given the _Unwind_Context CONTEXT for a stack frame, + we need to look up its caller and decode information into FS. + However, if the exception handling happens within a signal handler, + the return address of signal handler is a special module, which + contains signal return syscall and has no FDE in the .eh_frame section. + We need to implement MD_FALLBACK_FRAME_STATE_FOR so that we can + unwind through signal frames. */ +static _Unwind_Reason_Code +nds32_fallback_frame_state (struct _Unwind_Context *context, + _Unwind_FrameState *fs) +{ + u_int32_t *pc = (u_int32_t *) context->ra; + struct sigcontext *sc_; + _Unwind_Ptr new_cfa; + +#ifdef __NDS32_EB__ +#error "Signal handler is not supported for force unwind." +#endif + + if ((_Unwind_Ptr) pc & 3) + return _URC_END_OF_STACK; + + /* Check if we are going through a signal handler. + See arch/nds32/kernel/signal.c implementation. + SWI_SYS_SIGRETURN -> (0xeb0e0a64) + SWI_SYS_RT_SIGRETURN -> (0xab150a64) + FIXME: Currently we only handle little endian (EL) case. */ + if (pc[0] == SIGRETURN) + { + /* Using '_sigfame' memory address to locate kernal's sigcontext. + The sigcontext structures in arch/nds32/include/asm/sigcontext.h. */ + struct _sigframe *rt_; + rt_ = context->cfa; + sc_ = &rt_->uc.uc_mcontext; + } + else if (pc[0] == RT_SIGRETURN) + { + /* Using '_sigfame' memory address to locate kernal's sigcontext. */ + struct _rt_sigframe *rt_; + rt_ = context->cfa; + sc_ = &rt_->sig.uc.uc_mcontext; + } + else + return _URC_END_OF_STACK; + + /* Update cfa from sigcontext. */ + new_cfa = (_Unwind_Ptr) sc_; + fs->regs.cfa_how = CFA_REG_OFFSET; + fs->regs.cfa_reg = STACK_POINTER_REGNUM; + fs->regs.cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa; + +#define NDS32_PUT_FS_REG(NUM, NAME) \ + (fs->regs.reg[NUM].how = REG_SAVED_OFFSET, \ + fs->regs.reg[NUM].loc.offset = (_Unwind_Ptr) &(sc_->NAME) - new_cfa) + + /* Restore all registers value. */ + NDS32_PUT_FS_REG (0, nds32_r0); + NDS32_PUT_FS_REG (1, nds32_r1); + NDS32_PUT_FS_REG (2, nds32_r2); + NDS32_PUT_FS_REG (3, nds32_r3); + NDS32_PUT_FS_REG (4, nds32_r4); + NDS32_PUT_FS_REG (5, nds32_r5); + NDS32_PUT_FS_REG (6, nds32_r6); + NDS32_PUT_FS_REG (7, nds32_r7); + NDS32_PUT_FS_REG (8, nds32_r8); + NDS32_PUT_FS_REG (9, nds32_r9); + NDS32_PUT_FS_REG (10, nds32_r10); + NDS32_PUT_FS_REG (11, nds32_r11); + NDS32_PUT_FS_REG (12, nds32_r12); + NDS32_PUT_FS_REG (13, nds32_r13); + NDS32_PUT_FS_REG (14, nds32_r14); + NDS32_PUT_FS_REG (15, nds32_r15); + NDS32_PUT_FS_REG (16, nds32_r16); + NDS32_PUT_FS_REG (17, nds32_r17); + NDS32_PUT_FS_REG (18, nds32_r18); + NDS32_PUT_FS_REG (19, nds32_r19); + NDS32_PUT_FS_REG (20, nds32_r20); + NDS32_PUT_FS_REG (21, nds32_r21); + NDS32_PUT_FS_REG (22, nds32_r22); + NDS32_PUT_FS_REG (23, nds32_r23); + NDS32_PUT_FS_REG (24, nds32_r24); + NDS32_PUT_FS_REG (25, nds32_r25); + + NDS32_PUT_FS_REG (28, nds32_fp); + NDS32_PUT_FS_REG (29, nds32_gp); + NDS32_PUT_FS_REG (30, nds32_lp); + NDS32_PUT_FS_REG (31, nds32_sp); + + /* Restore PC, point to trigger signal instruction. */ + NDS32_PUT_FS_REG (32, nds32_ipc); + +#undef NDS32_PUT_FS_REG + + /* The retaddr is PC, use PC to find FDE. */ + fs->retaddr_column = 32; + fs->signal_frame = 1; + + return _URC_NO_REASON; +} + +#endif