[NDS32] Support Linux target for nds32.
authorChung-Ju Wu <jasonwucj@gmail.com>
Sat, 2 Jun 2018 14:22:12 +0000 (14:22 +0000)
committerChung-Ju Wu <jasonwucj@gcc.gnu.org>
Sat, 2 Jun 2018 14:22:12 +0000 (14:22 +0000)
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 <kito.cheng@gmail.com>
Co-Authored-By: Monk Chiang <sh.chiang04@gmail.com>
From-SVN: r261116

18 files changed:
gcc/ChangeLog
gcc/common/config/nds32/nds32-common.c
gcc/config.gcc
gcc/config/nds32/elf.h [new file with mode: 0644]
gcc/config/nds32/linux.h [new file with mode: 0644]
gcc/config/nds32/nds32-elf.opt [new file with mode: 0644]
gcc/config/nds32/nds32-fp-as-gp.c
gcc/config/nds32/nds32-linux.opt [new file with mode: 0644]
gcc/config/nds32/nds32.c
gcc/config/nds32/nds32.h
gcc/config/nds32/nds32.md
gcc/config/nds32/nds32.opt
gcc/config/nds32/t-elf [new file with mode: 0644]
gcc/config/nds32/t-linux [new file with mode: 0644]
libgcc/ChangeLog
libgcc/config.host
libgcc/config/nds32/linux-atomic.c [new file with mode: 0644]
libgcc/config/nds32/linux-unwind.h [new file with mode: 0644]

index 8f1bd35b71eb6d4166b5883b7e2054fcb96a4c69..0e6eef70fbb6e32bd692e5edd803b00e40043c12 100644 (file)
@@ -1,3 +1,37 @@
+2018-06-02  Chung-Ju Wu  <jasonwucj@gmail.com>
+           Kito Cheng  <kito.cheng@gmail.com>
+
+       * 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  <jasonwucj@gmail.com>
            Shiva Chen  <shiva0217@gmail.com>
 
index 04dc8646ffbe0831fa74425a4a4a1573e3f7b1cb..e4478f166c51ec9a724dd75684fab4b171762dad 100644 (file)
@@ -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;
+}
+
+/* ------------------------------------------------------------------------ */
+
 \f
 /* 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
 
 /* ------------------------------------------------------------------------ */
 
index 4d9f9c6ea294b0b7c13d1c1bb311223ca9d0102a..c3aecbfe764e62a945ddf6db3529a56625d70bf3 100644 (file)
@@ -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 (file)
index 0000000..66397ac
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+
+/* ------------------------------------------------------------------------ */
+
+#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 (file)
index 0000000..a0ec1b2
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+
+/* ------------------------------------------------------------------------ */
+
+#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 (file)
index 0000000..afe6aad
--- /dev/null
@@ -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)
index 1abad1dc24a14183ccd93ecdee9593ccca07aba6..26d2865d450b1d6caae227f5212040deb192fd6d 100644 (file)
@@ -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 (file)
index 0000000..75ccd76
--- /dev/null
@@ -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)
index 1afd8a10156e35df5688daca87db803b203b7d98..a0b6443e5d21930874fd69f64511bce3a07b28eb 100644 (file)
@@ -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,
 \f
 /* Emulating TLS.  */
 
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS TARGET_LINUX_ABI
+
 \f
 /* 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
index 523492fea175348e76f1c24ee4e73c4eacda46fd..84fae7d09dfaf82f86741fa0d800abfb5c188796 100644 (file)
@@ -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 }
index cf1ad9bd1b078fc2f50eb4befde80736286c6c49..92e90dda1afe8e338b651c185a79f16e1225d350 100644 (file)
   [(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")]
index 6f73f897e5d684d68ec24ddda27b72354b107b6b..871ae1e07ca84c6e991aae63eae71cccb3032686 100644 (file)
@@ -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 (file)
index 0000000..3401dae
--- /dev/null
@@ -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
+# <http://www.gnu.org/licenses/>.
+
+# 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 (file)
index 0000000..33328f6
--- /dev/null
@@ -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
+# <http://www.gnu.org/licenses/>.
+
+# 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 +=
+
+# ------------------------------------------------------------------------
index 9a94e8333ab893da5338419b9de818cefcecc27e..d75d9340a089a83145cf403891da5c7869b96066 100644 (file)
@@ -1,3 +1,10 @@
+2018-06-02  Chung-Ju Wu  <jasonwucj@gmail.com>
+           Monk Chiang  <sh.chiang04@gmail.com>
+
+       * config.host (nds32*-linux*): New.
+       * config/nds32/linux-atomic.c: New file.
+       * config/nds32/linux-unwind.h: New file.
+
 2018-05-31  Uros Bizjak  <ubizjak@gmail.com>
 
        PR target/85591
index f8fd78279d353f6959e75ac25571c1b7b2dec110..18cabaf24f6c9c038b149737271d02a8ffbcde7b 100644 (file)
@@ -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 (file)
index 0000000..6da7be9
--- /dev/null
@@ -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
+<http://www.gnu.org/licenses/>.  */
+
+/* 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_<op>_and_fetch and __sync_fetch_and_<op> 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 (file)
index 0000000..921edf9
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#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 <signal.h>
+#include <asm/unistd.h>
+
+/* 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