diff --git a/util/crossgcc/buildgcc b/util/crossgcc/buildgcc
index dcfb9a6b45..9cbdfc6001 100755
--- a/util/crossgcc/buildgcc
+++ b/util/crossgcc/buildgcc
@@ -18,8 +18,8 @@
cd $(dirname $0)
-CROSSGCC_DATE="July 27th, 2017"
-CROSSGCC_VERSION="1.46"
+CROSSGCC_DATE="August 16th, 2017"
+CROSSGCC_VERSION="1.47"
CROSSGCC_COMMIT=$( git describe )
# default settings
diff --git a/util/crossgcc/patches/gcc-6.3.0_nds32.patch b/util/crossgcc/patches/gcc-6.3.0_nds32.patch
deleted file mode 100644
index cdfb02f351..0000000000
--- a/util/crossgcc/patches/gcc-6.3.0_nds32.patch
+++ /dev/null
@@ -1,17 +0,0 @@
-diff -urN gcc-6.1.0.orig/gcc/config/nds32/nds32.md gcc-6.1.0/gcc/config/nds32/nds32.md
---- gcc-6.1.0.orig/gcc/config/nds32/nds32.md 2015-01-15 22:45:09.000000000 -0800
-+++ gcc-6.1.0/gcc/config/nds32/nds32.md 2016-04-14 22:09:09.000000000 -0700
-@@ -2289,11 +2289,11 @@
- emit_jump_insn (gen_cbranchsi4 (test, operands[0], operands[2],
- operands[4]));
-
-- operands[5] = gen_reg_rtx (SImode);
-+ rtx tmp = gen_reg_rtx (SImode);
- /* Step C, D, E, and F, using another temporary register operands[5]. */
- emit_jump_insn (gen_casesi_internal (operands[0],
- operands[3],
-- operands[5]));
-+ tmp));
- DONE;
- })
-
diff --git a/util/crossgcc/patches/gcc-6.3.0_nds32_ite.patch b/util/crossgcc/patches/gcc-6.3.0_nds32_ite.patch
new file mode 100644
index 0000000000..50e39691b6
--- /dev/null
+++ b/util/crossgcc/patches/gcc-6.3.0_nds32_ite.patch
@@ -0,0 +1,73397 @@
+diff --git a/gcc/common.opt b/gcc/common.opt
+index 67048db..e6f8fd3 100644
+--- a/gcc/common.opt
++++ b/gcc/common.opt
+@@ -1281,7 +1281,7 @@ ffast-math
+ Common
+
+ ffat-lto-objects
+-Common Var(flag_fat_lto_objects)
++Common Var(flag_fat_lto_objects) Init(1)
+ Output lto objects containing both the intermediate language and binary output.
+
+ ffinite-math-only
+diff --git a/gcc/common/config/nds32/nds32-common.c b/gcc/common/config/nds32/nds32-common.c
+index fb75956..66ea95c 100644
+--- a/gcc/common/config/nds32/nds32-common.c
++++ b/gcc/common/config/nds32/nds32-common.c
+@@ -53,6 +53,16 @@ nds32_handle_option (struct gcc_options *opts ATTRIBUTE_UNUSED,
+
+ return true;
+
++ case OPT_misr_secure_:
++ /* Check the valid security level: 0 1 2 3. */
++ if (value < 0 || value > 3)
++ {
++ error_at (loc, "for the option -misr-secure=X, the valid X "
++ "must be: 0, 1, 2, or 3");
++ return false;
++ }
++ return true;
++
+ case OPT_mcache_block_size_:
+ /* Check valid value: 4 8 16 32 64 128 256 512. */
+ if (exact_log2 (value) < 2 || exact_log2 (value) > 9)
+@@ -74,15 +84,69 @@ nds32_handle_option (struct gcc_options *opts ATTRIBUTE_UNUSED,
+ /* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
+ static const struct default_options nds32_option_optimization_table[] =
+ {
+- /* Enable -fomit-frame-pointer by default at -O1 or higher. */
+- { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
++#ifdef TARGET_DEFAULT_NO_MATH_ERRNO
++ /* Under some configuration, we would like to use -fno-math-errno by default
++ at all optimization levels for performance and code size consideration.
++ Please check gcc/config.gcc for more implementation details. */
++ { OPT_LEVELS_ALL, OPT_fmath_errno, NULL, 0 },
++#endif
++#if TARGET_LINUX_ABI == 0
++ /* Disable -fdelete-null-pointer-checks by default in ELF toolchain. */
++ { OPT_LEVELS_ALL, OPT_fdelete_null_pointer_checks,
++ NULL, 0 },
++#endif
++ /* Enable -fsched-pressure by default at -O1 and above. */
++ { OPT_LEVELS_1_PLUS, OPT_fsched_pressure, NULL, 1 },
++ /* Enable -fomit-frame-pointer by default at all optimization levels. */
++ { OPT_LEVELS_ALL, OPT_fomit_frame_pointer, NULL, 1 },
++ /* Enable -mrelax-hint by default at all optimization levels. */
++ { OPT_LEVELS_ALL, OPT_mrelax_hint, NULL, 1 },
++ /* Enable -mabi-compatible by default at all optimization levels. */
++ { OPT_LEVELS_ALL, OPT_mabi_compatible, NULL, 1 },
++ /* Enalbe -malways-align by default at -O1 and above, but not -Os or -Og. */
++ { OPT_LEVELS_1_PLUS_SPEED_ONLY, OPT_malways_align, NULL, 1 },
+ /* Enable -mv3push by default at -Os, but it is useless under V2 ISA. */
+- { OPT_LEVELS_SIZE, OPT_mv3push, NULL, 1 },
+-
+- { OPT_LEVELS_NONE, 0, NULL, 0 }
++ { OPT_LEVELS_SIZE, OPT_mv3push, NULL, 1 },
++ /* Enable -mload-store-opt by default at -Os. */
++ { OPT_LEVELS_SIZE, OPT_mload_store_opt, NULL, 1 },
++ /* Enable -mregrename by default at -O1 and above. */
++ { OPT_LEVELS_1_PLUS, OPT_mregrename, NULL, 1 },
++ /* Enable -mgcse by default at -O1 and above. */
++ { OPT_LEVELS_1_PLUS, OPT_mgcse, NULL, 1 },
++ /* Enable -msign-conversion by default at -O1 and above. */
++ { OPT_LEVELS_1_PLUS, OPT_msign_conversion, NULL, 1 },
++ /* Enable -mscalbn-transform by default at -O1 and above. */
++ { OPT_LEVELS_1_PLUS, OPT_mscalbn_transform, NULL, 1 },
++ /* Enable -mconst_remeterialization by default at -O1 and above. */
++ { OPT_LEVELS_1_PLUS, OPT_mconst_remater, NULL, 1 },
++ /* Enable -mcprop-acc by default at -O1 and above. */
++ { OPT_LEVELS_1_PLUS, OPT_mcprop_acc, NULL, 1 },
++#ifdef TARGET_OS_DEFAULT_IFC
++ /* Enable -mifc by default at -Os, but it is useless under V2/V3M ISA. */
++ { OPT_LEVELS_SIZE, OPT_mifc, NULL, 1 },
++#endif
++#ifdef TARGET_OS_DEFAULT_EX9
++ /* Enable -mex9 by default at -Os, but it is useless under V2/V3M ISA. */
++ { OPT_LEVELS_SIZE, OPT_mex9, NULL, 1 },
++#endif
++
++ { OPT_LEVELS_NONE, 0, NULL, 0 }
+ };
+
+ /* ------------------------------------------------------------------------ */
++
++/* 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. */
+
+@@ -95,14 +159,22 @@ static const struct default_options nds32_option_optimization_table[] =
+
+ Other MASK_XXX flags are set individually.
+ By default we enable
+- TARGET_16_BIT : Generate 16/32 bit mixed length instruction.
+- TARGET_PERF_EXT : Generate performance extention instrcution.
+- TARGET_CMOV : Generate conditional move instruction. */
++ TARGET_16_BIT : Generate 16/32 bit mixed length instruction.
++ TARGET_EXT_PERF : Generate performance extention instrcution.
++ TARGET_EXT_PERF2 : Generate performance extention version 2 instrcution.
++ TARGET_EXT_STRING : Generate string extention instrcution.
++ TARGET_HW_ABS : Generate hardware abs instruction.
++ TARGET_CMOV : Generate conditional move instruction. */
+ #undef TARGET_DEFAULT_TARGET_FLAGS
+ #define TARGET_DEFAULT_TARGET_FLAGS \
+ (TARGET_CPU_DEFAULT \
++ | TARGET_DEFAULT_FPU_ISA \
++ | TARGET_DEFAULT_FPU_FMA \
+ | MASK_16_BIT \
+- | MASK_PERF_EXT \
++ | MASK_EXT_PERF \
++ | MASK_EXT_PERF2 \
++ | MASK_EXT_STRING \
++ | MASK_HW_ABS \
+ | MASK_CMOV)
+
+ #undef TARGET_HANDLE_OPTION
+@@ -115,7 +187,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 1d5b23f..367a821 100644
+--- a/gcc/config.gcc
++++ b/gcc/config.gcc
+@@ -433,8 +433,28 @@ mips*-*-*)
+ ;;
+ nds32*)
+ cpu_type=nds32
+- extra_headers="nds32_intrinsic.h"
+- 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"
++ extra_headers="nds32_intrinsic.h nds32_isr.h nds32_init.inc"
++ 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_options="${extra_options} g.opt"
++ extra_objs="nds32-cost.o nds32-intrinsic.o nds32-md-auxiliary.o \
++ nds32-pipelines-auxiliary.o nds32-predicates.o \
++ nds32-memory-manipulation.o nds32-fp-as-gp.o \
++ nds32-load-store-opt.o nds32-soft-fp-comm.o nds32-isr.o \
++ nds32-regrename.o nds32-gcse.o nds32-relax-opt.o \
++ nds32-sign-conversion.o \
++ nds32-scalbn-transform.o nds32-lmwsmw.o \
++ nds32-reg-utils.o nds32-const-remater.o \
++ nds32-utils.o nds32-abi-compatible.o \
++ nds32-cprop-acc.o"
+ ;;
+ nios2-*-*)
+ cpu_type=nios2
+@@ -2265,17 +2285,67 @@ 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}"
+- 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}"
+- 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
++ nds32_multilibs="${with_multilib_list}"
++ if test "$nds32_multilibs" = "default"; then
++ nds32_multilibs=""
++ fi
++ nds32_multilibs=`echo $nds32_multilibs | sed -e 's/,/ /g'`
++ for nds32_multilib in ${nds32_multilibs}; do
++ case ${nds32_multilib} in
++ dsp | zol | v3m+ | graywolf )
++ TM_MULTILIB_CONFIG="${TM_MULTILIB_CONFIG} ${nds32_multilib}"
++ ;;
++ *)
++ echo "--with-multilib-list=${nds32_multilib} not supported."
++ exit 1
++ esac
++ done
++
++ # Handle --enable-default-relax setting.
++ if test x${enable_default_relax} = xyes; then
++ tm_defines="${tm_defines} TARGET_DEFAULT_RELAX=1"
++ fi
++ # Handle --enable-Os-default-ifc setting.
++ if test x${enable_Os_default_ifc} = xyes; then
++ tm_defines="${tm_defines} TARGET_OS_DEFAULT_IFC=1"
++ fi
++ # Handle --enable-Os-default-ex9 setting.
++ if test x${enable_Os_default_ex9} = xyes; then
++ tm_defines="${tm_defines} TARGET_OS_DEFAULT_EX9=1"
++ fi
++ # Handle --with-ext-dsp
++ if test x${with_ext_dsp} = xyes; then
++ tm_defines="${tm_defines} TARGET_DEFAULT_EXT_DSP=1"
++ fi
++ if test x${with_ext_zol} = xyes; then
++ tm_defines="${tm_defines} TARGET_DEFAULT_HWLOOP=1"
++ fi
++ # Handle --with-16bit-ext, and default is on
++ if test x${with_ext_16bit} != xno; then
++ tm_defines="${tm_defines} TARGET_DEFAULT_16BIT=1"
++ fi
++
+ ;;
+ nios2-*-*)
+ tm_file="elfos.h ${tm_file}"
+@@ -4097,15 +4167,51 @@ case "${target}" in
+ ;;
+
+ nds32*-*-*)
+- supported_defaults="arch nds32_lib"
++ supported_defaults="arch cpu nds32_lib float fpu_config memory_model"
+
+ # process --with-arch
+ case "${with_arch}" in
+- "" | v2 | v3 | v3m)
++ "" | v3 | v3j)
++ # OK
++ tm_defines="${tm_defines} TARGET_ARCH_DEFAULT=0"
++ tm_defines="${tm_defines} TARGET_DEFAULT_ISR_VECTOR_SIZE=4"
++ ;;
++ v2 | v2j | v3m)
++ # OK
++ tm_defines="${tm_defines} TARGET_ARCH_DEFAULT=0"
++ tm_defines="${tm_defines} TARGET_DEFAULT_ISR_VECTOR_SIZE=16"
++ ;;
++ v3f)
++ tm_defines="${tm_defines} TARGET_ARCH_DEFAULT=1"
++ tm_defines="${tm_defines} TARGET_DEFAULT_ISR_VECTOR_SIZE=4"
++ ;;
++ v3s)
++ tm_defines="${tm_defines} TARGET_ARCH_DEFAULT=2"
++ tm_defines="${tm_defines} TARGET_DEFAULT_ISR_VECTOR_SIZE=4"
++ ;;
++ *)
++ echo "Cannot accept --with-arch=$with_arch, available values are: v2 v2j v3 v3j v3m v3f v3s" 1>&2
++ exit 1
++ ;;
++ esac
++
++ # process --with-memory-model
++ case "${with_memory_model}" in
++ "" | fast | slow)
++ ;;
++ *)
++ echo "Cannot accept --with-memory-model=$with_memory_model, available values are: fast slow" 1>&2
++ exit 1
++ ;;
++ esac
++
++ # process --with-cpu
++ case "${with_cpu}" in
++ "" | n7 | n8 | e8 | s8 | n9 | n10 | d10 | graywolf | n12 | n13 | panther)
+ # OK
+ ;;
+ *)
+- echo "Cannot accept --with-arch=$with_arch, available values are: v2 v3 v3m" 1>&2
++ echo "Cannot accept --with-cpu=$with_cpu, available values are: n7 n8 e8 s8 n9 n10 d10 graywolf n12 n13 panther" 1>&2
+ exit 1
+ ;;
+ esac
+@@ -4115,31 +4221,56 @@ 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
++
++ # process --with-float
++ case "${with_float}" in
++ "" | soft | hard)
++ # OK
++ ;;
++ *)
++ echo "Cannot accept --with-float=$with_float, available values are: soft hard" 1>&2
++ exit 1
++ ;;
++ esac
++
++ # process --with-config-fpu
++ case "${with_config_fpu}" in
++ "" | 0 | 1 | 2 | 3)
++ # OK
++ ;;
++ *)
++ echo "Cannot accept --with-config-fpu=$with_config_fpu, available values from 0 to 7" 1>&2
+ exit 1
+ ;;
+ esac
+- ;;
+
+- nios2*-*-*)
+- supported_defaults="arch"
+- case "$with_arch" in
+- "" | r1 | r2)
+- # OK
+- ;;
+- *)
+- echo "Unknown arch used in --with-arch=$with_arch" 1>&2
+- exit 1
+- ;;
+- esac
+ ;;
+
+ powerpc*-*-* | rs6000-*-*)
+@@ -4527,7 +4658,7 @@ case ${target} in
+ esac
+
+ t=
+-all_defaults="abi cpu cpu_32 cpu_64 arch arch_32 arch_64 tune tune_32 tune_64 schedule float mode fpu nan fp_32 odd_spreg_32 divide llsc mips-plt synci tls"
++all_defaults="abi cpu cpu_32 cpu_64 arch arch_32 arch_64 tune tune_32 tune_64 schedule float mode fpu nan fp_32 odd_spreg_32 divide llsc mips-plt synci tls memory_model"
+ for option in $all_defaults
+ do
+ eval "val=\$with_"`echo $option | sed s/-/_/g`
+diff --git a/gcc/config/nds32/constants.md b/gcc/config/nds32/constants.md
+index bea42ee..6c92412 100644
+--- a/gcc/config/nds32/constants.md
++++ b/gcc/config/nds32/constants.md
+@@ -23,25 +23,176 @@
+ (define_constants
+ [(R8_REGNUM 8)
+ (TA_REGNUM 15)
++ (TP_REGNUM 25)
+ (FP_REGNUM 28)
+ (GP_REGNUM 29)
+ (LP_REGNUM 30)
+ (SP_REGNUM 31)
++ (LB_REGNUM 98)
++ (LE_REGNUM 99)
++ (LC_REGNUM 100)
+ ])
+
+
++;; The unpec operation index.
++(define_c_enum "unspec_element" [
++ UNSPEC_COPYSIGN
++ UNSPEC_FCPYNSD
++ UNSPEC_FCPYNSS
++ UNSPEC_FCPYSD
++ UNSPEC_FCPYSS
++ UNSPEC_CLIP
++ UNSPEC_CLIPS
++ UNSPEC_CLO
++ UNSPEC_PBSAD
++ UNSPEC_PBSADA
++ UNSPEC_BSE
++ UNSPEC_BSE_2
++ UNSPEC_BSP
++ UNSPEC_BSP_2
++ UNSPEC_FFB
++ UNSPEC_FFMISM
++ UNSPEC_FLMISM
++ UNSPEC_KDMBB
++ UNSPEC_KDMBT
++ UNSPEC_KDMTB
++ UNSPEC_KDMTT
++ UNSPEC_KHMBB
++ UNSPEC_KHMBT
++ UNSPEC_KHMTB
++ UNSPEC_KHMTT
++ UNSPEC_KSLRAW
++ UNSPEC_KSLRAWU
++ UNSPEC_SVA
++ UNSPEC_SVS
++ UNSPEC_WSBH
++ UNSPEC_LWUP
++ UNSPEC_LBUP
++ UNSPEC_SWUP
++ UNSPEC_SBUP
++ UNSPEC_LMWZB
++ UNSPEC_SMWZB
++ UNSPEC_UALOAD_HW
++ UNSPEC_UALOAD_W
++ UNSPEC_UALOAD_DW
++ UNSPEC_UASTORE_HW
++ UNSPEC_UASTORE_W
++ UNSPEC_UASTORE_DW
++ UNSPEC_GOTINIT
++ UNSPEC_GOT
++ UNSPEC_GOTOFF
++ UNSPEC_PLT
++ UNSPEC_TLSGD
++ UNSPEC_TLSLD
++ UNSPEC_TLSIE
++ UNSPEC_TLSLE
++ UNSPEC_ROUND
++ UNSPEC_VEC_COMPARE
++ UNSPEC_KHM
++ UNSPEC_KHMX
++ UNSPEC_CLIP_OV
++ UNSPEC_CLIPS_OV
++ UNSPEC_BITREV
++ UNSPEC_KABS
++ UNSPEC_LOOP_END
++ UNSPEC_TLS_DESC
++ UNSPEC_TLS_IE
++ UNSPEC_ADD32
++ UNSPEC_ICT
++])
++
++
+ ;; The unspec_volatile operation index.
+ (define_c_enum "unspec_volatile_element" [
+- UNSPEC_VOLATILE_FUNC_RETURN
++ UNSPEC_VOLATILE_EH_RETURN
+ UNSPEC_VOLATILE_ISYNC
+ UNSPEC_VOLATILE_ISB
++ UNSPEC_VOLATILE_DSB
++ UNSPEC_VOLATILE_MSYNC
++ UNSPEC_VOLATILE_MSYNC_ALL
++ UNSPEC_VOLATILE_MSYNC_STORE
+ UNSPEC_VOLATILE_MFSR
+ UNSPEC_VOLATILE_MFUSR
+ UNSPEC_VOLATILE_MTSR
+ UNSPEC_VOLATILE_MTUSR
+ UNSPEC_VOLATILE_SETGIE_EN
+ UNSPEC_VOLATILE_SETGIE_DIS
++ UNSPEC_VOLATILE_FMFCSR
++ UNSPEC_VOLATILE_FMTCSR
++ UNSPEC_VOLATILE_FMFCFG
++ UNSPEC_VOLATILE_JR_ITOFF
++ UNSPEC_VOLATILE_JR_TOFF
++ UNSPEC_VOLATILE_JRAL_ITON
++ UNSPEC_VOLATILE_JRAL_TON
++ UNSPEC_VOLATILE_RET_ITOFF
++ UNSPEC_VOLATILE_RET_TOFF
++ UNSPEC_VOLATILE_STANDBY_NO_WAKE_GRANT
++ UNSPEC_VOLATILE_STANDBY_WAKE_GRANT
++ UNSPEC_VOLATILE_STANDBY_WAKE_DONE
++ UNSPEC_VOLATILE_TEQZ
++ UNSPEC_VOLATILE_TNEZ
++ UNSPEC_VOLATILE_TRAP
++ UNSPEC_VOLATILE_SETEND_BIG
++ UNSPEC_VOLATILE_SETEND_LITTLE
++ UNSPEC_VOLATILE_BREAK
++ UNSPEC_VOLATILE_SYSCALL
++ UNSPEC_VOLATILE_NOP
++ UNSPEC_VOLATILE_RES_DEP
++ UNSPEC_VOLATILE_DATA_DEP
++ UNSPEC_VOLATILE_LLW
++ UNSPEC_VOLATILE_SCW
++ UNSPEC_VOLATILE_CCTL_L1D_INVALALL
++ UNSPEC_VOLATILE_CCTL_L1D_WBALL_ALVL
++ UNSPEC_VOLATILE_CCTL_L1D_WBALL_ONE_LVL
++ UNSPEC_VOLATILE_CCTL_IDX_WRITE
++ UNSPEC_VOLATILE_CCTL_IDX_READ
++ UNSPEC_VOLATILE_CCTL_VA_WBINVAL_L1
++ UNSPEC_VOLATILE_CCTL_VA_WBINVAL_LA
++ UNSPEC_VOLATILE_CCTL_IDX_WBINVAL
++ UNSPEC_VOLATILE_CCTL_VA_LCK
++ UNSPEC_VOLATILE_DPREF_QW
++ UNSPEC_VOLATILE_DPREF_HW
++ UNSPEC_VOLATILE_DPREF_W
++ UNSPEC_VOLATILE_DPREF_DW
++ UNSPEC_VOLATILE_TLBOP_TRD
++ UNSPEC_VOLATILE_TLBOP_TWR
++ UNSPEC_VOLATILE_TLBOP_RWR
++ UNSPEC_VOLATILE_TLBOP_RWLK
++ UNSPEC_VOLATILE_TLBOP_UNLK
++ UNSPEC_VOLATILE_TLBOP_PB
++ UNSPEC_VOLATILE_TLBOP_INV
++ UNSPEC_VOLATILE_TLBOP_FLUA
++ UNSPEC_VOLATILE_ENABLE_INT
++ UNSPEC_VOLATILE_DISABLE_INT
++ UNSPEC_VOLATILE_SET_PENDING_SWINT
++ UNSPEC_VOLATILE_CLR_PENDING_SWINT
++ UNSPEC_VOLATILE_CLR_PENDING_HWINT
++ UNSPEC_VOLATILE_GET_ALL_PENDING_INT
++ UNSPEC_VOLATILE_GET_PENDING_INT
++ UNSPEC_VOLATILE_SET_INT_PRIORITY
++ UNSPEC_VOLATILE_GET_INT_PRIORITY
++ UNSPEC_VOLATILE_SET_TRIG_LEVEL
++ UNSPEC_VOLATILE_SET_TRIG_EDGE
++ UNSPEC_VOLATILE_GET_TRIG_TYPE
++ UNSPEC_VOLATILE_RELAX_GROUP
++ UNSPEC_VOLATILE_INNERMOST_LOOP_BEGIN
++ UNSPEC_VOLATILE_INNERMOST_LOOP_END
++ UNSPEC_VOLATILE_OMIT_FP_BEGIN
++ UNSPEC_VOLATILE_OMIT_FP_END
+ UNSPEC_VOLATILE_POP25_RETURN
++ UNSPEC_VOLATILE_SIGNATURE_BEGIN
++ UNSPEC_VOLATILE_SIGNATURE_END
++ UNSPEC_VOLATILE_NO_HWLOOP
++ UNSPEC_VOLATILE_NO_IFC_BEGIN
++ UNSPEC_VOLATILE_NO_IFC_END
++ UNSPEC_VOLATILE_NO_EX9_BEGIN
++ UNSPEC_VOLATILE_NO_EX9_END
++ UNSPEC_VOLATILE_UNALIGNED_FEATURE
++ UNSPEC_VOLATILE_ENABLE_UNALIGNED
++ UNSPEC_VOLATILE_DISABLE_UNALIGNED
++ UNSPEC_VOLATILE_RDOV
++ UNSPEC_VOLATILE_CLROV
++ UNSPEC_VOLATILE_HWLOOP_LAST_INSN
+ ])
+
+ ;; ------------------------------------------------------------------------
+diff --git a/gcc/config/nds32/constraints.md b/gcc/config/nds32/constraints.md
+index 1f44a1a..8163f46 100644
+--- a/gcc/config/nds32/constraints.md
++++ b/gcc/config/nds32/constraints.md
+@@ -25,9 +25,6 @@
+ ;; Machine-dependent floating: G H
+
+
+-(define_register_constraint "w" "(TARGET_ISA_V3 || TARGET_ISA_V3M) ? LOW_REGS : NO_REGS"
+- "LOW register class $r0 ~ $r7 constraint for V3/V3M ISA")
+-
+ (define_register_constraint "l" "LOW_REGS"
+ "LOW register class $r0 ~ $r7")
+
+@@ -41,9 +38,59 @@
+ (define_register_constraint "t" "R15_TA_REG"
+ "Temporary Assist register $ta (i.e. $r15)")
+
++(define_register_constraint "e" "R8_REG"
++ "Function Entry register $r8)")
++
+ (define_register_constraint "k" "STACK_REG"
+ "Stack register $sp")
+
++(define_register_constraint "v" "R5_REG"
++ "Register $r5")
++
++(define_register_constraint "x" "FRAME_POINTER_REG"
++ "Frame pointer register $fp")
++
++(define_register_constraint "f"
++ "(TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) ? FP_REGS : NO_REGS"
++ "The Floating point registers $fs0 ~ $fs31")
++
++(define_register_constraint "A" "LOOP_REGS"
++ "Loop register class")
++
++(define_constraint "Iv00"
++ "Constant value 0"
++ (and (match_code "const_int")
++ (match_test "ival == 0")))
++
++(define_constraint "Iv01"
++ "Constant value 1"
++ (and (match_code "const_int")
++ (match_test "ival == 1")))
++
++(define_constraint "Iv02"
++ "Constant value 2"
++ (and (match_code "const_int")
++ (match_test "ival == 2")))
++
++(define_constraint "Iv04"
++ "Constant value 4"
++ (and (match_code "const_int")
++ (match_test "ival == 4")))
++
++(define_constraint "Iv08"
++ "Constant value 8"
++ (and (match_code "const_int")
++ (match_test "ival == 8")))
++
++(define_constraint "Iu01"
++ "Unsigned immediate 1-bit value"
++ (and (match_code "const_int")
++ (match_test "ival == 1 || ival == 0")))
++
++(define_constraint "Iu02"
++ "Unsigned immediate 2-bit value"
++ (and (match_code "const_int")
++ (match_test "ival < (1 << 2) && ival >= 0")))
+
+ (define_constraint "Iu03"
+ "Unsigned immediate 3-bit value"
+@@ -65,6 +112,11 @@
+ (and (match_code "const_int")
+ (match_test "ival < (1 << 4) && ival >= -(1 << 4)")))
+
++(define_constraint "Cs05"
++ "Signed immediate 5-bit value"
++ (and (match_code "const_double")
++ (match_test "nds32_const_double_range_ok_p (op, SFmode, -(1 << 4), (1 << 4))")))
++
+ (define_constraint "Iu05"
+ "Unsigned immediate 5-bit value"
+ (and (match_code "const_int")
+@@ -75,6 +127,11 @@
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, -31, 0)")))
+
++(define_constraint "Iu06"
++ "Unsigned immediate 6-bit value"
++ (and (match_code "const_int")
++ (match_test "ival < (1 << 6) && ival >= 0")))
++
+ ;; Ip05 is special and dedicated for v3 movpi45 instruction.
+ ;; movpi45 has imm5u field but the range is 16 ~ 47.
+ (define_constraint "Ip05"
+@@ -84,10 +141,10 @@
+ && ival >= (0 + 16)
+ && (TARGET_ISA_V3 || TARGET_ISA_V3M)")))
+
+-(define_constraint "Iu06"
++(define_constraint "IU06"
+ "Unsigned immediate 6-bit value constraint for addri36.sp instruction"
+ (and (match_code "const_int")
+- (match_test "ival < (1 << 6)
++ (match_test "ival < (1 << 8)
+ && ival >= 0
+ && (ival % 4 == 0)
+ && (TARGET_ISA_V3 || TARGET_ISA_V3M)")))
+@@ -103,6 +160,11 @@
+ (match_test "ival < (1 << 9) && ival >= 0")))
+
+
++(define_constraint "Is08"
++ "Signed immediate 8-bit value"
++ (and (match_code "const_int")
++ (match_test "ival < (1 << 7) && ival >= -(1 << 7)")))
++
+ (define_constraint "Is10"
+ "Signed immediate 10-bit value"
+ (and (match_code "const_int")
+@@ -113,6 +175,10 @@
+ (and (match_code "const_int")
+ (match_test "ival < (1 << 10) && ival >= -(1 << 10)")))
+
++(define_constraint "Is14"
++ "Signed immediate 14-bit value"
++ (and (match_code "const_int")
++ (match_test "ival < (1 << 13) && ival >= -(1 << 13)")))
+
+ (define_constraint "Is15"
+ "Signed immediate 15-bit value"
+@@ -194,12 +260,21 @@
+ (and (match_code "const_int")
+ (match_test "ival < (1 << 19) && ival >= -(1 << 19)")))
+
++(define_constraint "Cs20"
++ "Signed immediate 20-bit value"
++ (and (match_code "const_double")
++ (match_test "nds32_const_double_range_ok_p (op, SFmode, -(1 << 19), (1 << 19))")))
+
+ (define_constraint "Ihig"
+ "The immediate value that can be simply set high 20-bit"
+ (and (match_code "const_int")
+ (match_test "(ival != 0) && ((ival & 0xfff) == 0)")))
+
++(define_constraint "Chig"
++ "The immediate value that can be simply set high 20-bit"
++ (and (match_code "high")
++ (match_test "GET_CODE (XEXP (op, 0)) == CONST_DOUBLE")))
++
+ (define_constraint "Izeb"
+ "The immediate value 0xff"
+ (and (match_code "const_int")
+@@ -213,12 +288,12 @@
+ (define_constraint "Ixls"
+ "The immediate value 0x01"
+ (and (match_code "const_int")
+- (match_test "TARGET_PERF_EXT && (ival == 0x1)")))
++ (match_test "TARGET_EXT_PERF && (ival == 0x1)")))
+
+ (define_constraint "Ix11"
+ "The immediate value 0x7ff"
+ (and (match_code "const_int")
+- (match_test "TARGET_PERF_EXT && (ival == 0x7ff)")))
++ (match_test "TARGET_EXT_PERF && (ival == 0x7ff)")))
+
+ (define_constraint "Ibms"
+ "The immediate value with power of 2"
+@@ -232,23 +307,70 @@
+ (match_test "(TARGET_ISA_V3 || TARGET_ISA_V3M)
+ && (IN_RANGE (exact_log2 (ival + 1), 1, 8))")))
+
++(define_constraint "CVp5"
++ "Unsigned immediate 5-bit value for movpi45 instruction with range 16-47"
++ (and (match_code "const_vector")
++ (match_test "nds32_valid_CVp5_p (op)")))
++
++(define_constraint "CVs5"
++ "Signed immediate 5-bit value"
++ (and (match_code "const_vector")
++ (match_test "nds32_valid_CVs5_p (op)")))
++
++(define_constraint "CVs2"
++ "Signed immediate 20-bit value"
++ (and (match_code "const_vector")
++ (match_test "nds32_valid_CVs2_p (op)")))
++
++(define_constraint "CVhi"
++ "The immediate value that can be simply set high 20-bit"
++ (and (match_code "const_vector")
++ (match_test "nds32_valid_CVhi_p (op)")))
+
+ (define_memory_constraint "U33"
+ "Memory constraint for 333 format"
+ (and (match_code "mem")
+- (match_test "nds32_mem_format (op) == ADDRESS_LO_REG_IMM3U")))
++ (match_test "nds32_mem_format (op) == ADDRESS_POST_INC_LO_REG_IMM3U
++ || nds32_mem_format (op) == ADDRESS_POST_MODIFY_LO_REG_IMM3U
++ || nds32_mem_format (op) == ADDRESS_LO_REG_IMM3U")))
+
+ (define_memory_constraint "U45"
+ "Memory constraint for 45 format"
+ (and (match_code "mem")
+ (match_test "(nds32_mem_format (op) == ADDRESS_REG)
+- && (GET_MODE (op) == SImode)")))
++ && ((GET_MODE (op) == SImode)
++ || (GET_MODE (op) == SFmode))")))
++
++(define_memory_constraint "Ufe"
++ "Memory constraint for fe format"
++ (and (match_code "mem")
++ (match_test "nds32_mem_format (op) == ADDRESS_R8_IMM7U
++ && (GET_MODE (op) == SImode
++ || GET_MODE (op) == SFmode)")))
+
+ (define_memory_constraint "U37"
+ "Memory constraint for 37 format"
+ (and (match_code "mem")
+ (match_test "(nds32_mem_format (op) == ADDRESS_SP_IMM7U
+ || nds32_mem_format (op) == ADDRESS_FP_IMM7U)
+- && (GET_MODE (op) == SImode)")))
++ && (GET_MODE (op) == SImode
++ || GET_MODE (op) == SFmode)")))
++
++(define_memory_constraint "Umw"
++ "Memory constraint for lwm/smw"
++ (and (match_code "mem")
++ (match_test "nds32_valid_smw_lwm_base_p (op)")))
++
++(define_memory_constraint "Da"
++ "Memory constraint for non-offset loads/stores"
++ (and (match_code "mem")
++ (match_test "REG_P (XEXP (op, 0))
++ || (GET_CODE (XEXP (op, 0)) == POST_INC)")))
++
++(define_memory_constraint "Q"
++ "Memory constraint for no symbol_ref and const"
++ (and (match_code "mem")
++ (match_test "(TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE)
++ && nds32_float_mem_operand_p (op)")))
+
+ ;; ------------------------------------------------------------------------
+diff --git a/gcc/config/nds32/elf.h b/gcc/config/nds32/elf.h
+new file mode 100644
+index 0000000..315dcd8
+--- /dev/null
++++ b/gcc/config/nds32/elf.h
+@@ -0,0 +1,83 @@
++/* Definitions of target machine of Andes NDS32 cpu for GNU compiler
++ Copyright (C) 2012-2016 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 \
++ NDS32_IFC_SPEC \
++ NDS32_EX9_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/iterators.md b/gcc/config/nds32/iterators.md
+index ab0f103..6023b9c 100644
+--- a/gcc/config/nds32/iterators.md
++++ b/gcc/config/nds32/iterators.md
+@@ -26,30 +26,99 @@
+ ;; A list of integer modes that are up to one word long.
+ (define_mode_iterator QIHISI [QI HI SI])
+
++;; A list of integer modes for one word and double word.
++(define_mode_iterator SIDI [SI DI])
++
+ ;; A list of integer modes that are up to one half-word long.
+ (define_mode_iterator QIHI [QI HI])
+
+ ;; A list of the modes that are up to double-word long.
+ (define_mode_iterator DIDF [DI DF])
+
++;; A list of the modes that are up to one word long vector.
++(define_mode_iterator VQIHI [V4QI V2HI])
++
++;; A list of the modes that are up to one word long vector and scalar.
++(define_mode_iterator VSQIHI [V4QI V2HI QI HI])
++
++(define_mode_iterator VSQIHIDI [V4QI V2HI QI HI DI])
++
++(define_mode_iterator VQIHIDI [V4QI V2HI DI])
++
++;; A list of the modes that are up to one word long vector
++;; and scalar for HImode.
++(define_mode_iterator VSHI [V2HI HI])
++
++;; A list of the modes that are up to double-word long.
++(define_mode_iterator ANYF [(SF "TARGET_FPU_SINGLE")
++ (DF "TARGET_FPU_DOUBLE")])
+
+ ;;----------------------------------------------------------------------------
+ ;; Mode attributes.
+ ;;----------------------------------------------------------------------------
+
+-(define_mode_attr size [(QI "b") (HI "h") (SI "w")])
++(define_mode_attr size [(QI "b") (HI "h") (SI "w") (SF "s") (DF "d")])
+
+-(define_mode_attr byte [(QI "1") (HI "2") (SI "4")])
++(define_mode_attr byte [(QI "1") (HI "2") (SI "4") (V4QI "4") (V2HI "4")])
+
++(define_mode_attr bits [(V4QI "8") (QI "8") (V2HI "16") (HI "16") (DI "64")])
++
++(define_mode_attr VELT [(V4QI "QI") (V2HI "HI")])
+
+ ;;----------------------------------------------------------------------------
+ ;; Code iterators.
+ ;;----------------------------------------------------------------------------
+
++;; shifts
++(define_code_iterator shift_rotate [ashift ashiftrt lshiftrt rotatert])
++
++(define_code_iterator shifts [ashift ashiftrt lshiftrt])
++
++(define_code_iterator shiftrt [ashiftrt lshiftrt])
++
++(define_code_iterator sat_plus [ss_plus us_plus])
++
++(define_code_iterator all_plus [plus ss_plus us_plus])
++
++(define_code_iterator sat_minus [ss_minus us_minus])
++
++(define_code_iterator all_minus [minus ss_minus us_minus])
++
++(define_code_iterator plus_minus [plus minus])
++
++(define_code_iterator extend [sign_extend zero_extend])
++
++(define_code_iterator sumax [smax umax])
++
++(define_code_iterator sumin [smin umin])
++
++(define_code_iterator sumin_max [smax umax smin umin])
+
+ ;;----------------------------------------------------------------------------
+ ;; Code attributes.
+ ;;----------------------------------------------------------------------------
+
++;; shifts
++(define_code_attr shift
++ [(ashift "ashl") (ashiftrt "ashr") (lshiftrt "lshr") (rotatert "rotr")])
++
++(define_code_attr su
++ [(ashiftrt "") (lshiftrt "u") (sign_extend "s") (zero_extend "u")])
++
++(define_code_attr zs
++ [(sign_extend "s") (zero_extend "z")])
++
++(define_code_attr uk
++ [(plus "") (ss_plus "k") (us_plus "uk")
++ (minus "") (ss_minus "k") (us_minus "uk")])
++
++(define_code_attr opcode
++ [(plus "add") (minus "sub") (smax "smax") (umax "umax") (smin "smin") (umin "umin")])
++
++(define_code_attr add_rsub
++ [(plus "a") (minus "rs")])
++
++(define_code_attr add_sub
++ [(plus "a") (minus "s")])
+
+ ;;----------------------------------------------------------------------------
+diff --git a/gcc/config/nds32/linux.h b/gcc/config/nds32/linux.h
+new file mode 100644
+index 0000000..36ddf2f
+--- /dev/null
++++ b/gcc/config/nds32/linux.h
+@@ -0,0 +1,78 @@
++/* Definitions of target machine of Andes NDS32 cpu for GNU compiler
++ Copyright (C) 2012-2016 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_IFC_SPEC \
++ NDS32_EX9_SPEC \
++ NDS32_TLSDESC_TRAMPOLINE_SPEC
++
++#define LINK_PIE_SPEC "%{pie:%{!fno-pie:%{!fno-PIE:%{!static:-pie}}}} "
++
++
++/* 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-abi-compatible.c b/gcc/config/nds32/nds32-abi-compatible.c
+new file mode 100644
+index 0000000..f2ed006
+--- /dev/null
++++ b/gcc/config/nds32/nds32-abi-compatible.c
+@@ -0,0 +1,315 @@
++/* A Gimple-level pass of Andes NDS32 cpu for GNU compiler.
++ This pass collects the usage of float-point.
++
++ Copyright (C) 2012-2016 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
++. */
++
++
++#include "config.h"
++#include "system.h"
++#include "coretypes.h"
++#include "tm.h"
++#include "hash-set.h"
++#include "machmode.h"
++#include "vec.h"
++#include "double-int.h"
++#include "input.h"
++#include "alias.h"
++#include "symtab.h"
++#include "wide-int.h"
++#include "inchash.h"
++#include "tree.h"
++#include "stor-layout.h"
++#include "varasm.h"
++#include "calls.h"
++#include "rtl.h"
++#include "regs.h"
++#include "hard-reg-set.h"
++#include "insn-config.h" /* Required by recog.h. */
++#include "conditions.h"
++#include "output.h"
++#include "insn-attr.h" /* For DFA state_t. */
++#include "insn-codes.h" /* For CODE_FOR_xxx. */
++#include "reload.h" /* For push_reload (). */
++#include "flags.h"
++#include "input.h"
++#include "function.h"
++#include "expr.h"
++#include "recog.h"
++#include "diagnostic-core.h"
++#include "dominance.h"
++#include "cfg.h"
++#include "cfgrtl.h"
++#include "cfganal.h"
++#include "lcm.h"
++#include "cfgbuild.h"
++#include "cfgcleanup.h"
++#include "predict.h"
++#include "basic-block.h"
++#include "bitmap.h"
++#include "df.h"
++#include "tm_p.h"
++#include "tm-constrs.h"
++#include "optabs.h" /* For GEN_FCN. */
++#include "target.h"
++#include "langhooks.h" /* For add_builtin_function (). */
++#include "ggc.h"
++#include "tree-pass.h"
++#include "tree-ssa-alias.h"
++#include "fold-const.h"
++#include "gimple-expr.h"
++#include "is-a.h"
++#include "gimple.h"
++#include "gimplify.h"
++#include "gimple-iterator.h"
++#include "gimplify-me.h"
++#include "gimple-ssa.h"
++#include "ipa-ref.h"
++#include "lto-streamer.h"
++#include "cgraph.h"
++#include "tree-cfg.h"
++#include "tree-phinodes.h"
++#include "stringpool.h"
++#include "tree-ssanames.h"
++#include "tree-pass.h"
++#include "gimple-pretty-print.h"
++#include "gimple-walk.h"
++
++/* Indicate the translation unit whether including floating-point arithmetic
++ or not. */
++bool nds32_include_fp_arith = false;
++
++/* Return true if the return type and argument types of current function
++ pass the insepction. Furthermore, the global value NDS32_INCLUDE_FP_ARITH
++ is modified. */
++
++static bool
++nds32_acd_func_rtn_args_check (tree fn_decl)
++{
++ tree fn_type = TREE_TYPE (fn_decl);
++ function_args_iterator iter;
++ tree arg_type = NULL_TREE;
++ tree rtn_type = NULL_TREE;
++ unsigned argno = 1;
++
++ gcc_assert (fn_type);
++
++ rtn_type = TREE_TYPE (fn_type);
++ if (dump_file)
++ {
++ fprintf (dump_file,
++ " Check the return & arguments for function %s\n"
++ " Prototype:",
++ fndecl_name (fn_decl));
++ print_generic_decl (dump_file, fn_decl, 0);
++ fprintf (dump_file, "\n");
++ }
++
++ /* Check the return type. */
++ if (FLOAT_TYPE_P (rtn_type)
++ || RECORD_OR_UNION_TYPE_P (rtn_type))
++ {
++ if (dump_file)
++ fprintf (dump_file, " ! Return type is FP or record/union type\n");
++ nds32_include_fp_arith = true;
++
++ return false;
++ }
++
++ /* Check if the function has a variable argument list. */
++ if (stdarg_p (fn_type))
++ {
++ if (dump_file)
++ fprintf (dump_file, " ! Has variable argument list (i.e. ,...)\n");
++ nds32_include_fp_arith = true;
++
++ return false;
++ }
++
++ /* Check the arguments. */
++ FOREACH_FUNCTION_ARGS (fn_type, arg_type, iter)
++ {
++ if (arg_type == void_type_node)
++ break;
++
++ if (FLOAT_TYPE_P (arg_type)
++ || RECORD_OR_UNION_TYPE_P (arg_type))
++ {
++ if (dump_file)
++ fprintf (dump_file,
++ " ! No.%d argument is FP or record/union type\n",
++ argno);
++ nds32_include_fp_arith = true;
++
++ return false;
++ }
++ argno++;
++ }
++
++ if (dump_file)
++ fprintf (dump_file,
++ " >> Pass the inspection of return & arguments type\n");
++
++ return true;
++}
++
++/* Helper for nds32_abi_compatible. Return *TP if it is a floating-point
++ -related operand. */
++
++static tree
++nds32_acd_walk_op_fn (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
++{
++ tree t = *tp;
++
++ if (t && TREE_TYPE (t)
++ && (FLOAT_TYPE_P (TREE_TYPE (t))
++ || TREE_CODE (t) == REAL_CST
++ || TREE_CODE (t) == COMPLEX_CST
++ || TREE_CODE (t) == FLOAT_EXPR
++ || TREE_CODE (t) == REALPART_EXPR))
++ {
++ *walk_subtrees = 0;
++ return t;
++ }
++
++ return NULL_TREE;
++}
++
++/* Helper for nds32_abi_compatible. Return non-NULL tree and set
++ *HANDLED_OPS_P to true if *GSI_P is an ASM stmt. */
++
++static tree
++nds32_acd_walk_stmt_fn (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
++ struct walk_stmt_info *wi ATTRIBUTE_UNUSED)
++{
++ gimple *stmt = gsi_stmt (*gsi_p);
++
++ switch (gimple_code (stmt))
++ {
++ case GIMPLE_DEBUG:
++ *handled_ops_p = true;
++ break;
++
++ case GIMPLE_ASM:
++ *handled_ops_p = true;
++ return (tree) -1;
++ break;
++
++ case GIMPLE_CALL:
++ {
++ tree call_decl = gimple_call_fndecl (stmt);
++ if (!call_decl
++ || !nds32_acd_func_rtn_args_check (call_decl))
++ {
++ *handled_ops_p = true;
++ return call_decl;
++ }
++ }
++ break;
++
++ default:
++ break;
++ }
++
++ return NULL_TREE;
++}
++
++/* This function is the entry of ABI compatible detection pass. */
++
++static int
++nds32_abi_compatible (void)
++{
++ basic_block bb;
++ struct walk_stmt_info wi;
++
++ memset (&wi, 0, sizeof (wi));
++
++ if (!nds32_acd_func_rtn_args_check (current_function_decl))
++ return 0;
++
++ if (dump_file)
++ fprintf (dump_file, "Check function body %s\n",
++ function_name (cfun));
++
++ FOR_EACH_BB_FN (bb, cfun)
++ {
++ gimple *ret;
++ gimple_seq seq = bb_seq (bb);
++
++ ret = walk_gimple_seq (seq,
++ nds32_acd_walk_stmt_fn,
++ nds32_acd_walk_op_fn,
++ &wi);
++ if (ret != NULL)
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, " ! NO PASS: ");
++ print_gimple_stmt (dump_file, ret, 0, TDF_SLIM|TDF_RAW);
++ }
++ nds32_include_fp_arith = true;
++ break;
++ }
++ }
++
++ if (dump_file)
++ if (!nds32_include_fp_arith)
++ fprintf (dump_file,
++ " >> Pass the inspection of FP operand for function body\n");
++
++ return 0;
++}
++
++static bool
++gate_nds32_abi_compatible (void)
++{
++ return flag_nds32_abi_compatible
++ && !nds32_include_fp_arith;
++}
++
++const pass_data pass_data_nds32_abi_compatible =
++{
++ GIMPLE_PASS, /* type */
++ "abi_compatible", /* name */
++ OPTGROUP_NONE, /* optinfo_flags */
++ TV_MACH_DEP, /* tv_id */
++ ( PROP_cfg | PROP_ssa ), /* properties_required */
++ 0, /* properties_provided */
++ 0, /* properties_destroyed */
++ 0, /* todo_flags_start */
++ 0, /* todo_flags_finish */
++};
++
++class pass_nds32_abi_compatible : public gimple_opt_pass
++{
++public:
++ pass_nds32_abi_compatible (gcc::context *ctxt)
++ : gimple_opt_pass (pass_data_nds32_abi_compatible, ctxt)
++ {}
++
++ /* opt_pass methods: */
++ bool gate (function *) { return gate_nds32_abi_compatible (); }
++ unsigned int execute (function *) { return nds32_abi_compatible (); }
++};
++
++gimple_opt_pass *
++make_pass_nds32_abi_compatible (gcc::context *ctxt)
++{
++ return new pass_nds32_abi_compatible (ctxt);
++}
+diff --git a/gcc/config/nds32/nds32-const-remater.c b/gcc/config/nds32/nds32-const-remater.c
+new file mode 100644
+index 0000000..760e567
+--- /dev/null
++++ b/gcc/config/nds32/nds32-const-remater.c
+@@ -0,0 +1,461 @@
++/* Global CSE pass of Andes NDS32 cpu for GNU compiler
++ Copyright (C) 2012-2016 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
++ . */
++
++/* ------------------------------------------------------------------------ */
++
++#include "config.h"
++#include "system.h"
++#include "coretypes.h"
++#include "backend.h"
++#include "tree.h"
++#include "rtl.h"
++#include "df.h"
++#include "alias.h"
++#include "stor-layout.h"
++#include "varasm.h"
++#include "calls.h"
++#include "regs.h"
++#include "insn-config.h" /* Required by recog.h. */
++#include "conditions.h"
++#include "output.h"
++#include "insn-attr.h" /* For DFA state_t. */
++#include "insn-codes.h" /* For CODE_FOR_xxx. */
++#include "reload.h" /* For push_reload(). */
++#include "flags.h"
++#include "insn-config.h"
++#include "expmed.h"
++#include "dojump.h"
++#include "explow.h"
++#include "emit-rtl.h"
++#include "stmt.h"
++#include "expr.h"
++#include "recog.h"
++#include "diagnostic-core.h"
++#include "cfgrtl.h"
++#include "cfganal.h"
++#include "lcm.h"
++#include "cfgbuild.h"
++#include "cfgcleanup.h"
++#include "tm_p.h"
++#include "tm-constrs.h"
++#include "optabs.h" /* For GEN_FCN. */
++#include "target.h"
++#include "langhooks.h" /* For add_builtin_function(). */
++#include "builtins.h"
++#include "cpplib.h"
++#include "params.h"
++#include "tree-pass.h"
++#include "dbgcnt.h"
++#include "df.h"
++#include "tm-constrs.h"
++
++/* ------------------------------------------------------------------------ */
++
++typedef struct reg_avail_info
++{
++ rtx insn;
++ unsigned int uint;
++ unsigned int regno;
++} reg_avail_info_t;
++
++
++static void find_common_const (void);
++static bool try_rematerialize (rtx_insn *, unsigned int,
++ auto_vec *);
++static void clean_reg_avail_info (rtx ,const_rtx, void *);
++static rtx get_const (rtx);
++static bool addsi3_format_p (rtx);
++
++/* Search the register records. */
++static bool
++try_rematerialize (rtx_insn *insn, unsigned int uint_r,
++ auto_vec *reg_avail_infos)
++{
++ unsigned int i, uint_i, cl_i, cl_r, ct_i, ct_r;
++ rtx pat, src, dest, new_insn;
++ bool done = FALSE;
++ df_ref df_rec;
++ df_link *link;
++
++ cl_r = __builtin_clz (uint_r);
++ ct_r = __builtin_ctz (uint_r);
++ for (i = 0; i < reg_avail_infos->length (); ++i)
++ {
++ if ((*reg_avail_infos)[i].uint != uint_r)
++ {
++ uint_i = (*reg_avail_infos)[i].uint;
++ if (dump_file)
++ fprintf (dump_file, "Try rematerialize %08x with const %08x\n",
++ uint_r, uint_i);
++ cl_i = __builtin_clz (uint_i);
++ ct_i = __builtin_ctz (uint_i);
++ src = SET_DEST (PATTERN ((*reg_avail_infos)[i].insn));
++ dest = SET_DEST (PATTERN (insn));
++
++ if (cl_r > cl_i
++ && (uint_i >> (cl_r - cl_i)) == uint_r)
++ {
++ /* Right shift logical. */
++ pat = gen_rtx_LSHIFTRT (SImode, src, GEN_INT (cl_r - cl_i));
++ done = TRUE;
++ if (dump_file)
++ fprintf (dump_file,
++ "Rematerialize %08x with const %08x by l>> %d\n",
++ uint_r, uint_i, (cl_r - cl_i));
++ }
++ else if (ct_i >= ct_r
++ && ((int) uint_i >> (ct_i - ct_r)) == (int) uint_r)
++ {
++ /* Right shift arithmetic. */
++ pat = gen_rtx_ASHIFTRT (SImode, src, GEN_INT (ct_i - ct_r));
++ done = TRUE;
++ if (dump_file)
++ fprintf (dump_file,
++ "Rematerialize %08x with const %08x by a>> %d\n",
++ uint_r, uint_i, (cl_r - cl_i));
++ }
++ else if (ct_r > ct_i
++ && (uint_i << (ct_r - ct_i)) == uint_r)
++ {
++ /* Left shift. */
++ pat = gen_rtx_ASHIFT (SImode, src, GEN_INT (ct_r - ct_i));
++ done = TRUE;
++ if (dump_file)
++ fprintf (dump_file,
++ "Rematerialize %08x with const %08x by << %d\n",
++ uint_r, uint_i, (ct_r - ct_i));
++ }
++ else if (TARGET_EXT_PERF && __builtin_popcount (uint_r ^ uint_i) == 1)
++ {
++ unsigned int val = uint_r ^ uint_i;
++ if ((uint_r & (uint_r ^ uint_i)) != 0)
++ {
++ if (val > (1 << 5))
++ {
++ /* Bit set. */
++ pat = gen_rtx_IOR (SImode, src, GEN_INT (val));
++ done = TRUE;
++ if (dump_file)
++ fprintf (dump_file,
++ "Rematerialize %08x with const %08x by | %08x\n",
++ uint_r, uint_i, uint_r ^ uint_i);
++ }
++ else
++ {
++ /* Transform to plus if immediate can fit addi45. */
++ pat = gen_rtx_PLUS (SImode, src, GEN_INT (val));
++ done = TRUE;
++ if (dump_file)
++ fprintf (dump_file,
++ "Rematerialize %08x with const %08x by | %08x\n",
++ uint_r, uint_i, uint_r ^ uint_i);
++ }
++ }
++ else
++ {
++ if (val > (1 << 5))
++ {
++ /* Bit clear. */
++ pat = gen_rtx_AND (SImode, src, GEN_INT (~(uint_r ^ uint_i)));
++ done = TRUE;
++ if (dump_file)
++ fprintf (dump_file,
++ "Rematerialize %08x with const %08x by & %08x\n",
++ uint_r, uint_i, ~(uint_r ^ uint_i));
++ }
++ else
++ {
++ /* Transform to plus if immediate can fit subi45. */
++ pat = gen_rtx_PLUS (SImode, src, GEN_INT ((int) -val));
++ done = TRUE;
++ if (dump_file)
++ fprintf (dump_file,
++ "Rematerialize %08x with const %08x by | %08x\n",
++ uint_r, uint_i, uint_r ^ uint_i);
++ }
++ }
++ }
++ else if ((uint_r > uint_i ? uint_r - uint_i
++ : uint_i - uint_r) < 0x4000)
++ {
++ /* Check insn_info existence because the instruction
++ maybe be deleted.*/
++ if (DF_INSN_INFO_GET ((*reg_avail_infos)[i].insn))
++ {
++ df_rec = DF_INSN_DEFS ((*reg_avail_infos)[i].insn);
++ link = DF_REF_CHAIN (df_rec);
++
++ /* Do not use the dead instruction. */
++ /* Do not use the original matched sethi. */
++ if (!link)
++ continue;
++ for (link = DF_REF_CHAIN (df_rec); link; link = link->next)
++ {
++ if (DF_REF_REGNO (link->ref) == 0
++ || !DF_REF_INSN_INFO (link->ref)
++ || DF_REF_INSN (link->ref) == insn)
++ break;
++ }
++ if (link)
++ continue;
++ }
++
++ /* Add. */
++ if (uint_r > uint_i)
++ {
++ pat = gen_rtx_PLUS (SImode, src, GEN_INT (uint_r - uint_i));
++ done = TRUE;
++ }
++ else
++ {
++ pat = gen_rtx_PLUS (SImode, src, GEN_INT ((HOST_WIDE_INT)
++ uint_r - uint_i));
++ done = TRUE;
++ }
++ }
++
++ if (done)
++ {
++ /* Emit the new instruction. */
++ new_insn = gen_move_insn (dest, pat);
++ emit_insn_before (new_insn, insn);
++ set_dst_reg_note (new_insn, REG_EQUAL, GEN_INT (uint_r), dest);
++ return TRUE;
++ }
++ }
++ }
++ return FALSE;
++}
++
++/* Clean the reg_avail_info value. */
++static void
++clean_reg_avail_info (rtx dest, const_rtx setter ATTRIBUTE_UNUSED,
++ void *data)
++{
++ unsigned int i;
++ auto_vec *reg_avail_infos =
++ (auto_vec *) data;
++
++ if (GET_CODE (dest) == SUBREG)
++ dest = SUBREG_REG (dest);
++
++ if (REG_P (dest))
++ for (i = 0; i < reg_avail_infos->length (); ++i)
++ if ((*reg_avail_infos)[i].regno == REGNO (dest)
++ || (GET_MODE_SIZE (GET_MODE (dest)) == 8
++ && (*reg_avail_infos)[i].regno == REGNO (dest) + 1))
++ reg_avail_infos->unordered_remove (i--);
++}
++
++/* Return the const if the setting value is a constant integer. */
++static rtx
++get_const (rtx insn)
++{
++ rtx note;
++
++ if (GET_CODE (PATTERN (insn)) != SET
++ || !REG_P (SET_DEST (PATTERN (insn)))
++ || GET_MODE (SET_DEST (PATTERN (insn))) != SImode)
++ return NULL_RTX;
++
++ /* Constant move instruction. */
++ if (CONST_INT_P (XEXP (PATTERN (insn), 1)))
++ return XEXP (PATTERN (insn), 1);
++
++ note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
++ if (!note)
++ note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
++
++ if (note && CONST_INT_P (XEXP (note, 0)))
++ return XEXP (note, 0);
++
++ return NULL_RTX;
++}
++
++/* Return true if the instruction is addi format. */
++static bool
++addsi3_format_p (rtx insn)
++{
++ if (GET_CODE (XEXP (PATTERN (insn), 1)) == PLUS
++ && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 1)) == CONST_INT)
++ return TRUE;
++
++ return FALSE;
++}
++
++/* Return true if the instruction is sethi format. */
++static bool
++sethi_format_p (rtx insn)
++{
++ if (GET_CODE (PATTERN (insn)) == SET
++ && GET_CODE (XEXP (PATTERN (insn), 1)) == CONST_INT
++ && satisfies_constraint_Ihig (XEXP (PATTERN (insn), 1)))
++ return TRUE;
++ return FALSE;
++}
++
++/* Return true if the register definition only be used by insn. */
++static bool
++use_only_p (rtx insn)
++{
++ rtx def_insn;
++ df_ref rec;
++ df_link *link;
++ rec = DF_INSN_USES (insn);
++ link = DF_REF_CHAIN (rec);
++
++ if (!link
++ || DF_REF_REGNO (link->ref) == 0
++ || !DF_REF_INSN_INFO (link->ref))
++ return FALSE;
++
++ def_insn = DF_REF_INSN (link->ref);
++
++ if (!sethi_format_p (def_insn))
++ return FALSE;
++
++ rec = DF_INSN_DEFS (def_insn);
++ link = DF_REF_CHAIN (rec);
++
++ if (!link
++ || link->next
++ || DF_REF_REGNO (link->ref) == 0
++ || !DF_REF_INSN_INFO (link->ref))
++ return FALSE;
++
++ return TRUE;
++}
++
++/* Traverse instructions in each basic block, and save the value of
++ setting constant instructions. */
++static void
++find_common_const (void)
++{
++ basic_block bb;
++ unsigned int i;
++
++ /* Save register constant value. */
++ auto_vec reg_avail_infos;
++ reg_avail_info_t reg_avail_info;
++
++
++ FOR_EACH_BB_FN (bb, cfun)
++ {
++ rtx_insn *insn;
++ rtx dest, cst;
++
++ /* Clear the vector. */
++ while (!reg_avail_infos.is_empty ())
++ reg_avail_infos.pop ();
++
++ FOR_BB_INSNS (bb, insn)
++ {
++ if (!NONDEBUG_INSN_P (insn))
++ continue;
++
++ if (CALL_P (insn))
++ {
++ /* Clean hard register. */
++ for (i = 0; i < reg_avail_infos.length ();)
++ {
++ if (HARD_REGISTER_NUM_P (reg_avail_infos[i].regno)
++ && call_used_regs[reg_avail_infos[i].regno])
++ reg_avail_infos.unordered_remove (i);
++ else
++ ++i;
++ }
++ }
++
++ cst = get_const (insn);
++ if (cst == NULL_RTX)
++ {
++ note_stores (PATTERN (insn), clean_reg_avail_info,
++ ®_avail_infos);
++ continue;
++ }
++
++ dest = SET_DEST (PATTERN (insn));
++
++ if (addsi3_format_p (insn)
++ && use_only_p (insn)
++ && try_rematerialize (insn, XUINT (cst, 0), ®_avail_infos))
++ {
++ delete_insn (insn);
++ df_insn_rescan_all ();
++ }
++
++ note_stores (PATTERN (insn), clean_reg_avail_info, ®_avail_infos);
++ reg_avail_info.insn = insn;
++ reg_avail_info.uint = XUINT (cst, 0);
++ reg_avail_info.regno = REGNO (dest);
++ if (dump_file)
++ fprintf (dump_file, "Find const %08x on %u\n",
++ reg_avail_info.uint, reg_avail_info.regno);
++ reg_avail_infos.safe_push (reg_avail_info);
++ }
++ }
++}
++
++static unsigned int
++nds32_const_remater_opt (void)
++{
++ df_chain_add_problem (DF_DU_CHAIN + DF_UD_CHAIN);
++ df_note_add_problem ();
++ df_insn_rescan_all ();
++ df_analyze ();
++
++ find_common_const ();
++
++ df_insn_rescan_all ();
++ return 0;
++}
++
++const pass_data pass_data_nds32_const_remater_opt =
++{
++ RTL_PASS, /* type */
++ "const_remater_opt", /* name */
++ OPTGROUP_NONE, /* optinfo_flags */
++ TV_MACH_DEP, /* tv_id */
++ 0, /* properties_required */
++ 0, /* properties_provided */
++ 0, /* properties_destroyed */
++ 0, /* todo_flags_start */
++ TODO_df_finish, /* todo_flags_finish */
++};
++
++class pass_nds32_const_remater_opt : public rtl_opt_pass
++{
++public:
++ pass_nds32_const_remater_opt (gcc::context *ctxt)
++ : rtl_opt_pass (pass_data_nds32_const_remater_opt, ctxt)
++ {}
++
++ /* opt_pass methods: */
++ bool gate (function *) { return flag_nds32_const_remater_opt; }
++ unsigned int execute (function *) { return nds32_const_remater_opt (); }
++};
++
++rtl_opt_pass *
++make_pass_nds32_const_remater_opt (gcc::context *ctxt)
++{
++ return new pass_nds32_const_remater_opt (ctxt);
++}
++
++/* ------------------------------------------------------------------------ */
+diff --git a/gcc/config/nds32/nds32-cost.c b/gcc/config/nds32/nds32-cost.c
+index e6a29fc..881d086 100644
+--- a/gcc/config/nds32/nds32-cost.c
++++ b/gcc/config/nds32/nds32-cost.c
+@@ -24,73 +24,447 @@
+ #include "system.h"
+ #include "coretypes.h"
+ #include "backend.h"
+-#include "target.h"
+-#include "rtl.h"
+ #include "tree.h"
+-#include "tm_p.h"
+-#include "optabs.h" /* For GEN_FCN. */
++#include "rtl.h"
++#include "df.h"
++#include "alias.h"
++#include "stor-layout.h"
++#include "varasm.h"
++#include "calls.h"
++#include "regs.h"
++#include "insn-config.h" /* Required by recog.h. */
++#include "conditions.h"
++#include "output.h"
++#include "insn-attr.h" /* For DFA state_t. */
++#include "insn-codes.h" /* For CODE_FOR_xxx. */
++#include "reload.h" /* For push_reload(). */
++#include "flags.h"
++#include "insn-config.h"
++#include "expmed.h"
++#include "dojump.h"
++#include "explow.h"
++#include "emit-rtl.h"
++#include "stmt.h"
++#include "expr.h"
+ #include "recog.h"
++#include "diagnostic-core.h"
++#include "cfgrtl.h"
++#include "cfganal.h"
++#include "lcm.h"
++#include "cfgbuild.h"
++#include "cfgcleanup.h"
++#include "tm_p.h"
+ #include "tm-constrs.h"
++#include "optabs.h" /* For GEN_FCN. */
++#include "target.h"
++#include "langhooks.h" /* For add_builtin_function(). */
++#include "builtins.h"
++#include "tree-pass.h"
+
+ /* ------------------------------------------------------------------------ */
+
+-bool
+-nds32_rtx_costs_impl (rtx x,
+- machine_mode mode ATTRIBUTE_UNUSED,
+- int outer_code,
+- int opno ATTRIBUTE_UNUSED,
+- int *total,
+- bool speed)
+-{
+- int code = GET_CODE (x);
++typedef bool (*rtx_cost_func) (rtx, int, int, int, int*);
+
+- /* According to 'speed', goto suitable cost model section. */
+- if (speed)
+- goto performance_cost;
+- else
+- goto size_cost;
++struct rtx_cost_model_t {
++ rtx_cost_func speed_prefer;
++ rtx_cost_func size_prefer;
++};
+
++static rtx_cost_model_t rtx_cost_model;
+
+-performance_cost:
+- /* This is section for performance cost model. */
++static int insn_size_16bit; /* Initial at nds32_init_rtx_costs. */
++static const int insn_size_32bit = 4;
++
++static bool
++nds32_rtx_costs_speed_prefer (rtx x ATTRIBUTE_UNUSED,
++ int code,
++ int outer_code ATTRIBUTE_UNUSED,
++ int opno ATTRIBUTE_UNUSED,
++ int *total)
++{
++ rtx op0;
++ rtx op1;
++ enum machine_mode mode = GET_MODE (x);
++ /* Scale cost by mode size. */
++ int cost = COSTS_N_INSNS (GET_MODE_SIZE (mode) / GET_MODE_SIZE (SImode));
+
+- /* In gcc/rtl.h, the default value of COSTS_N_INSNS(N) is N*4.
+- We treat it as 4-cycle cost for each instruction
+- under performance consideration. */
+ switch (code)
+ {
+- case SET:
+- /* For 'SET' rtx, we need to return false
+- so that it can recursively calculate costs. */
+- return false;
+-
+ case USE:
+ /* Used in combine.c as a marker. */
+ *total = 0;
+- break;
++ return true;
++
++ case CONST_INT:
++ /* When not optimizing for size, we care more about the cost
++ of hot code, and hot code is often in a loop. If a constant
++ operand needs to be forced into a register, we will often be
++ able to hoist the constant load out of the loop, so the load
++ should not contribute to the cost. */
++ if (outer_code == SET || outer_code == PLUS)
++ *total = satisfies_constraint_Is20 (x) ? 0 : 4;
++ else if (outer_code == AND || outer_code == IOR || outer_code == XOR
++ || outer_code == MINUS)
++ *total = satisfies_constraint_Iu15 (x) ? 0 : 4;
++ else if (outer_code == ASHIFT || outer_code == ASHIFTRT
++ || outer_code == LSHIFTRT)
++ *total = satisfies_constraint_Iu05 (x) ? 0 : 4;
++ else if (GET_RTX_CLASS (outer_code) == RTX_COMPARE
++ || GET_RTX_CLASS (outer_code) == RTX_COMM_COMPARE)
++ *total = satisfies_constraint_Is16 (x) ? 0 : 4;
++ else
++ *total = COSTS_N_INSNS (1);
++ return true;
++
++ case CONST:
++ case LO_SUM:
++ case HIGH:
++ case SYMBOL_REF:
++ *total = COSTS_N_INSNS (1);
++ return true;
++
++ case MEM:
++ *total = COSTS_N_INSNS (1);
++ return true;
++
++ case SET:
++ op0 = SET_DEST (x);
++ op1 = SET_SRC (x);
++ mode = GET_MODE (op0);
++ /* Scale cost by mode size. */
++ cost = COSTS_N_INSNS (GET_MODE_SIZE (mode) / GET_MODE_SIZE (SImode));
++
++ switch (GET_CODE (op1))
++ {
++ case REG:
++ case SUBREG:
++ /* Register move and Store instructions. */
++ if ((REG_P (op0) || MEM_P (op0))
++ && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (DImode))
++ *total = COSTS_N_INSNS (1);
++ else
++ *total = cost;
++ return true;
++
++ case MEM:
++ /* Load instructions. */
++ if (REG_P (op0) && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (DImode))
++ *total = COSTS_N_INSNS (1);
++ else
++ *total = cost;
++ return true;
++
++ case CONST_INT:
++ /* movi instruction. */
++ if (REG_P (op0) && GET_MODE_SIZE (mode) < GET_MODE_SIZE (DImode))
++ {
++ if (satisfies_constraint_Is20 (op1))
++ *total = COSTS_N_INSNS (1) - 1;
++ else
++ *total = COSTS_N_INSNS (2);
++ }
++ else
++ *total = cost;
++ return true;
++
++ case CONST:
++ case SYMBOL_REF:
++ case LABEL_REF:
++ /* la instruction. */
++ if (REG_P (op0) && GET_MODE_SIZE (mode) < GET_MODE_SIZE (DImode))
++ *total = COSTS_N_INSNS (1) - 1;
++ else
++ *total = cost;
++ return true;
++ case VEC_SELECT:
++ *total = cost;
++ return true;
++
++ default:
++ *total = cost;
++ return true;
++ }
++
++ case PLUS:
++ op0 = XEXP (x, 0);
++ op1 = XEXP (x, 1);
++
++ if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
++ *total = cost;
++ else if (GET_CODE (op0) == MULT || GET_CODE (op0) == LSHIFTRT
++ || GET_CODE (op1) == MULT || GET_CODE (op1) == LSHIFTRT)
++ {
++ /* ALU_SHIFT */
++ if (TARGET_PIPELINE_PANTHER)
++ *total = COSTS_N_INSNS (1);
++ else
++ *total = COSTS_N_INSNS (2);
++ }
++ else if ((GET_CODE (op1) == CONST_INT
++ && satisfies_constraint_Is15 (op1))
++ || REG_P (op1))
++ /* ADD instructions */
++ *total = COSTS_N_INSNS (1);
++ else
++ /* ADD instructions: IMM out of range. */
++ *total = COSTS_N_INSNS (2);
++ return true;
++
++ case MINUS:
++ op0 = XEXP (x, 0);
++ op1 = XEXP (x, 1);
++
++ if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
++ *total = cost;
++ else if (GET_CODE (op0) == MULT || GET_CODE (op0) == LSHIFTRT
++ || GET_CODE (op1) == MULT || GET_CODE (op1) == LSHIFTRT)
++ {
++ /* ALU_SHIFT */
++ if (TARGET_PIPELINE_PANTHER)
++ *total = COSTS_N_INSNS (1);
++ else
++ *total = COSTS_N_INSNS (2);
++ }
++ else if ((GET_CODE (op0) == CONST_INT
++ && satisfies_constraint_Is15 (op0))
++ || REG_P (op0))
++ /* SUB instructions */
++ *total = COSTS_N_INSNS (1);
++ else
++ /* SUB instructions: IMM out of range. */
++ *total = COSTS_N_INSNS (2);
++ return true;
++
++ case TRUNCATE:
++ /* TRUNCATE and AND behavior is same. */
++ *total = COSTS_N_INSNS (1);
++ return true;
++
++ case AND:
++ case IOR:
++ case XOR:
++ op0 = XEXP (x, 0);
++ op1 = XEXP (x, 1);
++
++ if (NDS32_EXT_DSP_P ())
++ {
++ /* We prefer (and (ior) (ior)) than (ior (and) (and)) for
++ synthetize pk** and insb instruction. */
++ if (code == AND && GET_CODE (op0) == IOR && GET_CODE (op1) == IOR)
++ return COSTS_N_INSNS (1);
++
++ if (code == IOR && GET_CODE (op0) == AND && GET_CODE (op1) == AND)
++ return COSTS_N_INSNS (10);
++ }
++
++ if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
++ *total = cost;
++ else if (GET_CODE (op0) == ASHIFT || GET_CODE (op0) == LSHIFTRT)
++ {
++ /* ALU_SHIFT */
++ if (TARGET_PIPELINE_PANTHER)
++ *total = COSTS_N_INSNS (1);
++ else
++ *total = COSTS_N_INSNS (2);
++ }
++ else if ((GET_CODE (op1) == CONST_INT
++ && satisfies_constraint_Iu15 (op1))
++ || REG_P (op1))
++ /* AND, OR, XOR instructions */
++ *total = COSTS_N_INSNS (1);
++ else if (code == AND || GET_CODE (op0) == NOT)
++ /* BITC instruction */
++ *total = COSTS_N_INSNS (1);
++ else
++ /* AND, OR, XOR instructions: IMM out of range. */
++ *total = COSTS_N_INSNS (2);
++ return true;
+
+ case MULT:
++ if (GET_MODE (x) == DImode
++ || GET_CODE (XEXP (x, 1)) == SIGN_EXTEND
++ || GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
++ /* MUL instructions */
++ *total = COSTS_N_INSNS (1);
++ else if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
++ *total = cost;
++ else if (outer_code == PLUS || outer_code == MINUS)
++ {
++ /* ALU_SHIFT */
++ if (TARGET_PIPELINE_PANTHER)
++ *total = COSTS_N_INSNS (1);
++ else
++ *total = COSTS_N_INSNS (2);
++ }
++ else if ((GET_CODE (XEXP (x, 1)) == CONST_INT
++ && satisfies_constraint_Iu05 (XEXP (x, 1)))
++ || REG_P (XEXP (x, 1)))
++ /* MUL instructions */
++ *total = COSTS_N_INSNS (1);
++ else
++ /* MUL instructions: IMM out of range. */
++ *total = COSTS_N_INSNS (2);
++
++ if (TARGET_MUL_SLOW)
++ *total += COSTS_N_INSNS (4);
++
++ return true;
++
++ case LSHIFTRT:
++ if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
++ *total = cost;
++ else if (outer_code == PLUS || outer_code == MINUS
++ || outer_code == AND || outer_code == IOR
++ || outer_code == XOR)
++ {
++ /* ALU_SHIFT */
++ if (TARGET_PIPELINE_PANTHER)
++ *total = COSTS_N_INSNS (1);
++ else
++ *total = COSTS_N_INSNS (2);
++ }
++ else if ((GET_CODE (XEXP (x, 1)) == CONST_INT
++ && satisfies_constraint_Iu05 (XEXP (x, 1)))
++ || REG_P (XEXP (x, 1)))
++ /* SRL instructions */
++ *total = COSTS_N_INSNS (1);
++ else
++ /* SRL instructions: IMM out of range. */
++ *total = COSTS_N_INSNS (2);
++ return true;
++
++ case ASHIFT:
++ if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
++ *total = cost;
++ else if (outer_code == AND || outer_code == IOR
++ || outer_code == XOR)
++ {
++ /* ALU_SHIFT */
++ if (TARGET_PIPELINE_PANTHER)
++ *total = COSTS_N_INSNS (1);
++ else
++ *total = COSTS_N_INSNS (2);
++ }
++ else if ((GET_CODE (XEXP (x, 1)) == CONST_INT
++ && satisfies_constraint_Iu05 (XEXP (x, 1)))
++ || REG_P (XEXP (x, 1)))
++ /* SLL instructions */
++ *total = COSTS_N_INSNS (1);
++ else
++ /* SLL instructions: IMM out of range. */
++ *total = COSTS_N_INSNS (2);
++ return true;
++
++ case ASHIFTRT:
++ case ROTATERT:
++ if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (DImode))
++ *total = cost;
++ else if ((GET_CODE (XEXP (x, 1)) == CONST_INT
++ && satisfies_constraint_Iu05 (XEXP (x, 1)))
++ || REG_P (XEXP (x, 1)))
++ /* ROTR, SLL instructions */
++ *total = COSTS_N_INSNS (1);
++ else
++ /* ROTR, SLL instructions: IMM out of range. */
++ *total = COSTS_N_INSNS (2);
++ return true;
++
++ case LT:
++ case LTU:
++ if (outer_code == SET)
++ {
++ if ((GET_CODE (XEXP (x, 1)) == CONST_INT
++ && satisfies_constraint_Iu15 (XEXP (x, 1)))
++ || REG_P (XEXP (x, 1)))
++ /* SLT, SLTI instructions */
++ *total = COSTS_N_INSNS (1);
++ else
++ /* SLT, SLT instructions: IMM out of range. */
++ *total = COSTS_N_INSNS (2);
++ }
++ else
++ /* branch */
++ *total = COSTS_N_INSNS (2);
++ return true;
++
++ case EQ:
++ case NE:
++ case GE:
++ case LE:
++ case GT:
++ /* branch */
++ *total = COSTS_N_INSNS (2);
++ return true;
++
++ case IF_THEN_ELSE:
++ if (GET_CODE (XEXP (x, 1)) == LABEL_REF)
++ /* branch */
++ *total = COSTS_N_INSNS (2);
++ else
++ /* cmovz, cmovn instructions */
++ *total = COSTS_N_INSNS (1);
++ return true;
++
++ case LABEL_REF:
++ if (outer_code == IF_THEN_ELSE)
++ /* branch */
++ *total = COSTS_N_INSNS (2);
++ else
++ *total = COSTS_N_INSNS (1);
++ return true;
++
++ case ZERO_EXTEND:
++ case SIGN_EXTEND:
++ if (MEM_P (XEXP (x, 0)))
++ /* Using memory access. */
++ *total = COSTS_N_INSNS (1);
++ else
++ /* Zero extend and sign extend instructions. */
++ *total = COSTS_N_INSNS (1);
++ return true;
++
++ case NEG:
++ case NOT:
+ *total = COSTS_N_INSNS (1);
+- break;
++ return true;
+
+ case DIV:
+ case UDIV:
+ case MOD:
+ case UMOD:
+- *total = COSTS_N_INSNS (7);
+- break;
++ *total = COSTS_N_INSNS (20);
++ return true;
+
+- default:
++ case CALL:
++ *total = COSTS_N_INSNS (2);
++ return true;
++
++ case CLZ:
++ case SMIN:
++ case SMAX:
++ case ZERO_EXTRACT:
++ if (TARGET_EXT_PERF)
++ *total = COSTS_N_INSNS (1);
++ else
++ *total = COSTS_N_INSNS (3);
++ return true;
++ case VEC_SELECT:
+ *total = COSTS_N_INSNS (1);
+- break;
+- }
+-
+- return true;
+-
++ return true;
+
+-size_cost:
+- /* This is section for size cost model. */
++ default:
++ *total = COSTS_N_INSNS (3);
++ return true;
++ }
++}
+
++static bool
++nds32_rtx_costs_size_prefer (rtx x,
++ int code,
++ int outer_code,
++ int opno ATTRIBUTE_UNUSED,
++ int *total)
++{
+ /* In gcc/rtl.h, the default value of COSTS_N_INSNS(N) is N*4.
+ We treat it as 4-byte cost for each instruction
+ under code size consideration. */
+@@ -98,7 +472,7 @@ size_cost:
+ {
+ case SET:
+ /* For 'SET' rtx, we need to return false
+- so that it can recursively calculate costs. */
++ so that it can recursively calculate costs. */
+ return false;
+
+ case USE:
+@@ -108,92 +482,169 @@ size_cost:
+
+ case CONST_INT:
+ /* All instructions involving constant operation
+- need to be considered for cost evaluation. */
++ need to be considered for cost evaluation. */
+ if (outer_code == SET)
+ {
+ /* (set X imm5s), use movi55, 2-byte cost.
+ (set X imm20s), use movi, 4-byte cost.
+ (set X BIG_INT), use sethi/ori, 8-byte cost. */
+ if (satisfies_constraint_Is05 (x))
+- *total = COSTS_N_INSNS (1) - 2;
++ *total = insn_size_16bit;
+ else if (satisfies_constraint_Is20 (x))
+- *total = COSTS_N_INSNS (1);
++ *total = insn_size_32bit;
+ else
+- *total = COSTS_N_INSNS (2);
++ *total = insn_size_32bit * 2;
+ }
+ else if (outer_code == PLUS || outer_code == MINUS)
+ {
+ /* Possible addi333/subi333 or subi45/addi45, 2-byte cost.
+ General case, cost 1 instruction with 4-byte. */
+ if (satisfies_constraint_Iu05 (x))
+- *total = COSTS_N_INSNS (1) - 2;
++ *total = insn_size_16bit;
+ else
+- *total = COSTS_N_INSNS (1);
++ *total = insn_size_32bit;
+ }
+ else if (outer_code == ASHIFT)
+ {
+ /* Possible slli333, 2-byte cost.
+ General case, cost 1 instruction with 4-byte. */
+ if (satisfies_constraint_Iu03 (x))
+- *total = COSTS_N_INSNS (1) - 2;
++ *total = insn_size_16bit;
+ else
+- *total = COSTS_N_INSNS (1);
++ *total = insn_size_32bit;
+ }
+ else if (outer_code == ASHIFTRT || outer_code == LSHIFTRT)
+ {
+ /* Possible srai45 or srli45, 2-byte cost.
+ General case, cost 1 instruction with 4-byte. */
+ if (satisfies_constraint_Iu05 (x))
+- *total = COSTS_N_INSNS (1) - 2;
++ *total = insn_size_16bit;
+ else
+- *total = COSTS_N_INSNS (1);
++ *total = insn_size_32bit;
+ }
+ else
+ {
+ /* For other cases, simply set it 4-byte cost. */
+- *total = COSTS_N_INSNS (1);
++ *total = insn_size_32bit;
+ }
+ break;
+
+ case CONST_DOUBLE:
+ /* It requires high part and low part processing, set it 8-byte cost. */
+- *total = COSTS_N_INSNS (2);
++ *total = insn_size_32bit * 2;
++ break;
++
++ case CONST:
++ case SYMBOL_REF:
++ *total = insn_size_32bit * 2;
+ break;
+
+ default:
+ /* For other cases, generally we set it 4-byte cost
+- and stop resurively traversing. */
+- *total = COSTS_N_INSNS (1);
++ and stop resurively traversing. */
++ *total = insn_size_32bit;
+ break;
+ }
+
+ return true;
+ }
+
+-int
+-nds32_address_cost_impl (rtx address,
+- machine_mode mode ATTRIBUTE_UNUSED,
+- addr_space_t as ATTRIBUTE_UNUSED,
+- bool speed)
++void
++nds32_init_rtx_costs (void)
++{
++ rtx_cost_model.speed_prefer = nds32_rtx_costs_speed_prefer;
++ rtx_cost_model.size_prefer = nds32_rtx_costs_size_prefer;
++
++ if (TARGET_16_BIT)
++ insn_size_16bit = 2;
++ else
++ insn_size_16bit = 4;
++}
++
++/* This target hook describes the relative costs of RTL expressions.
++ Return 'true' when all subexpressions of x have been processed.
++ Return 'false' to sum the costs of sub-rtx, plus cost of this operation.
++ Refer to gcc/rtlanal.c for more information. */
++bool
++nds32_rtx_costs_impl (rtx x,
++ machine_mode mode ATTRIBUTE_UNUSED,
++ int outer_code,
++ int opno,
++ int *total,
++ bool speed)
++{
++ int code = GET_CODE (x);
++
++ /* According to 'speed', use suitable cost model section. */
++ if (speed)
++ return rtx_cost_model.speed_prefer(x, code, outer_code, opno, total);
++ else
++ return rtx_cost_model.size_prefer(x, code, outer_code, opno, total);
++}
++
++
++int nds32_address_cost_speed_prefer (rtx address)
+ {
+ rtx plus0, plus1;
+ enum rtx_code code;
+
+ code = GET_CODE (address);
+
+- /* According to 'speed', goto suitable cost model section. */
+- if (speed)
+- goto performance_cost;
+- else
+- goto size_cost;
++ switch (code)
++ {
++ case POST_MODIFY:
++ case POST_INC:
++ case POST_DEC:
++ /* We encourage that rtx contains
++ POST_MODIFY/POST_INC/POST_DEC behavior. */
++ return COSTS_N_INSNS (1) - 2;
++
++ case SYMBOL_REF:
++ /* We can have gp-relative load/store for symbol_ref.
++ Have it 4-byte cost. */
++ return COSTS_N_INSNS (2);
++
++ case CONST:
++ /* It is supposed to be the pattern (const (plus symbol_ref const_int)).
++ Have it 4-byte cost. */
++ return COSTS_N_INSNS (2);
++
++ case REG:
++ /* Simply return 4-byte costs. */
++ return COSTS_N_INSNS (1) - 2;
++
++ case PLUS:
++ /* We do not need to check if the address is a legitimate address,
++ because this hook is never called with an invalid address.
++ But we better check the range of
++ const_int value for cost, if it exists. */
++ plus0 = XEXP (address, 0);
++ plus1 = XEXP (address, 1);
++
++ if (REG_P (plus0) && CONST_INT_P (plus1))
++ return COSTS_N_INSNS (1) - 2;
++ else if (ARITHMETIC_P (plus0) || ARITHMETIC_P (plus1))
++ return COSTS_N_INSNS (1) - 1;
++ else if (REG_P (plus0) && REG_P (plus1))
++ return COSTS_N_INSNS (1);
++
++ /* For other 'plus' situation, make it cost 4-byte. */
++ return COSTS_N_INSNS (1);
+
+-performance_cost:
+- /* This is section for performance cost model. */
++ default:
++ break;
++ }
+
+- /* FALLTHRU, currently we use same cost model as size_cost. */
++ return COSTS_N_INSNS (4);
+
+-size_cost:
+- /* This is section for size cost model. */
++}
++
++int nds32_address_cost_speed_fwprop (rtx address)
++{
++ rtx plus0, plus1;
++ enum rtx_code code;
++
++ code = GET_CODE (address);
+
+ switch (code)
+ {
+@@ -201,18 +652,18 @@ size_cost:
+ case POST_INC:
+ case POST_DEC:
+ /* We encourage that rtx contains
+- POST_MODIFY/POST_INC/POST_DEC behavior. */
++ POST_MODIFY/POST_INC/POST_DEC behavior. */
+ return 0;
+
+ case SYMBOL_REF:
+ /* We can have gp-relative load/store for symbol_ref.
+- Have it 4-byte cost. */
+- return COSTS_N_INSNS (1);
++ Have it 4-byte cost. */
++ return COSTS_N_INSNS (2);
+
+ case CONST:
+ /* It is supposed to be the pattern (const (plus symbol_ref const_int)).
+- Have it 4-byte cost. */
+- return COSTS_N_INSNS (1);
++ Have it 4-byte cost. */
++ return COSTS_N_INSNS (2);
+
+ case REG:
+ /* Simply return 4-byte costs. */
+@@ -220,21 +671,25 @@ size_cost:
+
+ case PLUS:
+ /* We do not need to check if the address is a legitimate address,
+- because this hook is never called with an invalid address.
+- But we better check the range of
+- const_int value for cost, if it exists. */
++ because this hook is never called with an invalid address.
++ But we better check the range of
++ const_int value for cost, if it exists. */
+ plus0 = XEXP (address, 0);
+ plus1 = XEXP (address, 1);
+
+ if (REG_P (plus0) && CONST_INT_P (plus1))
+- {
++ {
+ /* If it is possible to be lwi333/swi333 form,
+ make it 2-byte cost. */
+- if (satisfies_constraint_Iu05 (plus1))
++ if (satisfies_constraint_Iu03 (plus1))
+ return (COSTS_N_INSNS (1) - 2);
+ else
+ return COSTS_N_INSNS (1);
+ }
++ if (ARITHMETIC_P (plus0) || ARITHMETIC_P (plus1))
++ return COSTS_N_INSNS (1) - 2;
++ else if (REG_P (plus0) && REG_P (plus1))
++ return COSTS_N_INSNS (1);
+
+ /* For other 'plus' situation, make it cost 4-byte. */
+ return COSTS_N_INSNS (1);
+@@ -246,4 +701,84 @@ size_cost:
+ return COSTS_N_INSNS (4);
+ }
+
++
++int nds32_address_cost_size_prefer (rtx address)
++{
++ rtx plus0, plus1;
++ enum rtx_code code;
++
++ code = GET_CODE (address);
++
++ switch (code)
++ {
++ case POST_MODIFY:
++ case POST_INC:
++ case POST_DEC:
++ /* We encourage that rtx contains
++ POST_MODIFY/POST_INC/POST_DEC behavior. */
++ return 0;
++
++ case SYMBOL_REF:
++ /* We can have gp-relative load/store for symbol_ref.
++ Have it 4-byte cost. */
++ return COSTS_N_INSNS (2);
++
++ case CONST:
++ /* It is supposed to be the pattern (const (plus symbol_ref const_int)).
++ Have it 4-byte cost. */
++ return COSTS_N_INSNS (2);
++
++ case REG:
++ /* Simply return 4-byte costs. */
++ return COSTS_N_INSNS (1) - 1;
++
++ case PLUS:
++ /* We do not need to check if the address is a legitimate address,
++ because this hook is never called with an invalid address.
++ But we better check the range of
++ const_int value for cost, if it exists. */
++ plus0 = XEXP (address, 0);
++ plus1 = XEXP (address, 1);
++
++ if (REG_P (plus0) && CONST_INT_P (plus1))
++ {
++ /* If it is possible to be lwi333/swi333 form,
++ make it 2-byte cost. */
++ if (satisfies_constraint_Iu03 (plus1))
++ return (COSTS_N_INSNS (1) - 2);
++ else
++ return COSTS_N_INSNS (1) - 1;
++ }
++
++ /* (plus (reg) (mult (reg) (const))) */
++ if (ARITHMETIC_P (plus0) || ARITHMETIC_P (plus1))
++ return (COSTS_N_INSNS (1) - 1);
++
++ /* For other 'plus' situation, make it cost 4-byte. */
++ return COSTS_N_INSNS (1);
++
++ default:
++ break;
++ }
++
++ return COSTS_N_INSNS (4);
++
++}
++
++int nds32_address_cost_impl (rtx address,
++ enum machine_mode mode ATTRIBUTE_UNUSED,
++ addr_space_t as ATTRIBUTE_UNUSED,
++ bool speed_p)
++{
++ if (speed_p)
++ {
++ if (current_pass->tv_id == TV_FWPROP)
++ return nds32_address_cost_speed_fwprop (address);
++ else
++ return nds32_address_cost_speed_prefer (address);
++ }
++ else
++ return nds32_address_cost_size_prefer (address);
++}
++
+ /* ------------------------------------------------------------------------ */
+diff --git a/gcc/config/nds32/nds32-cprop-acc.c b/gcc/config/nds32/nds32-cprop-acc.c
+new file mode 100644
+index 0000000..0852095
+--- /dev/null
++++ b/gcc/config/nds32/nds32-cprop-acc.c
+@@ -0,0 +1,845 @@
++/* Copy propagation on hard registers for accumulate style instruction.
++ Copyright (C) 2000-2014 Free Software Foundation, Inc.
++
++ 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
++ . */
++
++#include "config.h"
++#include "system.h"
++#include "coretypes.h"
++#include "tm.h"
++#include "rtl.h"
++#include "tm_p.h"
++#include "insn-config.h"
++#include "regs.h"
++#include "addresses.h"
++#include "predict.h"
++#include "basic-block.h"
++#include "reload.h"
++#include "hash-set.h"
++#include "dominance.h"
++#include "cfg.h"
++#include "function.h"
++#include "recog.h"
++#include "cfgrtl.h"
++#include "flags.h"
++#include "diagnostic-core.h"
++#include "obstack.h"
++#include "tree-pass.h"
++#include "bitmap.h"
++#include "df.h"
++#include "output.h"
++#include "emit-rtl.h"
++#include
++
++/* For each move instruction, we have a two-dimensional vector that record
++ what insns need to replace the operands when the move instruction is
++ propagated. */
++
++typedef std::vector insn_list;
++
++/* Function called by note_uses to replace used subexpressions. */
++
++struct replace_src_operands_data
++{
++ rtx dst_reg;
++ rtx src_reg;
++ unsigned int old_regno;
++ unsigned int new_regno;
++ rtx_insn *insn;
++};
++
++/* Return true if a mode change from ORIG to NEW is allowed for REGNO.
++ Adapted from mode_change_ok in regcprop. */
++
++static bool
++nds32_mode_change_ok (enum machine_mode orig_mode, enum machine_mode new_mode,
++ unsigned int regno ATTRIBUTE_UNUSED)
++{
++ if (GET_MODE_SIZE (orig_mode) < GET_MODE_SIZE (new_mode))
++ return false;
++
++#ifdef CANNOT_CHANGE_MODE_CLASS
++ return !REG_CANNOT_CHANGE_MODE_P (regno, orig_mode, new_mode);
++#endif
++
++ return true;
++}
++
++/* Register REGNO was originally set in ORIG_MODE. It - or a copy of it -
++ was copied in COPY_MODE to COPY_REGNO, and then COPY_REGNO was accessed
++ in NEW_MODE.
++ Return a NEW_MODE rtx for REGNO if that's OK, otherwise return NULL_RTX.
++ Adapted from maybe_mode_change in regcprop. */
++
++static rtx
++nds32_mode_change_reg (enum machine_mode orig_mode, enum machine_mode copy_mode,
++ enum machine_mode new_mode, unsigned int regno,
++ unsigned int copy_regno ATTRIBUTE_UNUSED)
++{
++ if (GET_MODE_SIZE (copy_mode) < GET_MODE_SIZE (orig_mode)
++ && GET_MODE_SIZE (copy_mode) < GET_MODE_SIZE (new_mode))
++ return NULL_RTX;
++
++ if (orig_mode == new_mode)
++ return gen_raw_REG (new_mode, regno);
++ else if (nds32_mode_change_ok (orig_mode, new_mode, regno))
++ {
++ int copy_nregs = hard_regno_nregs[copy_regno][copy_mode];
++ int use_nregs = hard_regno_nregs[copy_regno][new_mode];
++ int copy_offset
++ = GET_MODE_SIZE (copy_mode) / copy_nregs * (copy_nregs - use_nregs);
++ int offset
++ = GET_MODE_SIZE (orig_mode) - GET_MODE_SIZE (new_mode) - copy_offset;
++ int byteoffset = offset % UNITS_PER_WORD;
++ int wordoffset = offset - byteoffset;
++
++ offset = ((WORDS_BIG_ENDIAN ? wordoffset : 0)
++ + (BYTES_BIG_ENDIAN ? byteoffset : 0));
++ regno += subreg_regno_offset (regno, orig_mode, offset, new_mode);
++ if (HARD_REGNO_MODE_OK (regno, new_mode))
++ return gen_raw_REG (new_mode, regno);
++ }
++ return NULL_RTX;
++}
++
++/* Return true if INSN is a register-based move instruction, false
++ otherwise. */
++
++static bool
++nds32_is_reg_mov_p (rtx_insn *insn)
++{
++ rtx pat = PATTERN (insn);
++
++ if (GET_CODE (pat) != SET)
++ return false;
++
++ rtx src_reg = SET_SRC (pat);
++ rtx dst_reg = SET_DEST (pat);
++
++ if (REG_P (dst_reg) && REG_P (src_reg) && can_copy_p (GET_MODE (dst_reg)))
++ return true;
++ else
++ return false;
++}
++
++
++/* Return accumulated register if INSN is an accumulate style instruction,
++ otherwise return NULL_RTX. */
++
++static rtx
++nds32_is_acc_insn_p (rtx_insn *insn)
++{
++ int i;
++ const operand_alternative *op_alt;
++ rtx pat;
++
++ if (get_attr_length (insn) != 4)
++ return NULL_RTX;
++
++ pat = PATTERN (insn);
++ if (GET_CODE (pat) != SET)
++ return NULL_RTX;
++
++ /* Try to get the insn data from recog_data. */
++ recog_memoized (insn);
++ extract_constrain_insn (insn);
++ /* Transform the constraint strings into a more usable form,
++ recog_op_alt. */
++ preprocess_constraints (insn);
++ op_alt = which_op_alt ();
++
++ /* Check all operands whether the output operand is identical to
++ another input operand */
++ for (i = 0; i < recog_data.n_operands; ++i)
++ {
++ int matches = op_alt[i].matches;
++ int matched = op_alt[i].matched;
++ if ((matches >= 0
++ && (recog_data.operand_type[i] != OP_IN
++ || recog_data.operand_type[matches] != OP_IN))
++ || (matched >= 0
++ && (recog_data.operand_type[i] != OP_IN
++ || recog_data.operand_type[matched] != OP_IN)))
++ return recog_data.operand[i];
++ }
++
++ return NULL_RTX;
++}
++
++/* Finds the reference corresponding to the definition of register whose
++ register number is REGNO in INSN. DF is the dataflow object.
++ Adapted from df_find_def in df-core. */
++
++static df_ref
++nds32_df_find_regno_def (rtx_insn *insn, unsigned int regno)
++{
++ df_ref def;
++
++ FOR_EACH_INSN_DEF (def, insn)
++ if (DF_REF_REGNO (def) == regno)
++ return def;
++
++ return NULL;
++ }
++
++/* Return true if the REG in INSN is only defined by one insn whose uid
++ is DEF_UID, otherwise return false. */
++
++static bool
++nds32_is_single_def_p (rtx_insn *insn, rtx reg, unsigned int def_uid)
++{
++ df_ref use;
++
++ FOR_EACH_INSN_USE (use, insn)
++ {
++ df_link *link;
++ unsigned int uid;
++
++ if (DF_REF_REGNO (use) >= REGNO (reg)
++ && DF_REF_REGNO (use) < END_REGNO (reg))
++ {
++ link = DF_REF_CHAIN (use);
++ if (link->next
++ || DF_REF_IS_ARTIFICIAL (link->ref))
++ return false;
++
++ uid = DF_REF_INSN_UID (link->ref);
++ if (uid != def_uid)
++ return false;
++ }
++ }
++
++ return true;
++}
++
++/* Return true if there is no definition of REG on any path from the insn
++ whose uid is FROM_UID (called FROM) to insn TO, otherwise return false.
++ This function collects the reaching definitions bitmap at insn TO, and
++ check if all uses of REG in insn FROM can reach insn TO. */
++
++static bool
++nds32_no_define_reg_p (rtx to, rtx reg, unsigned int from_uid)
++{
++ basic_block bb = BLOCK_FOR_INSN (to);
++ struct df_rd_bb_info *bb_info = DF_RD_BB_INFO (bb);
++ bitmap_head rd_local;
++ bool result = true;
++ rtx_insn *insn;
++ df_ref use;
++ df_insn_info *insn_info;
++
++ bitmap_initialize (&rd_local, &bitmap_default_obstack);
++ bitmap_copy (&rd_local, &bb_info->in);
++ df_rd_simulate_artificial_defs_at_top (bb, &rd_local);
++
++ for (insn = BB_HEAD (bb); insn != to; insn = NEXT_INSN (insn))
++ if (INSN_P (insn))
++ df_rd_simulate_one_insn (bb, insn, &rd_local);
++
++ if (dump_file)
++ {
++ fprintf (dump_file, "scan reach define:");
++ print_rtl_single (dump_file, to);
++
++ fprintf (dump_file, "bb rd in:\n");
++ dump_bitmap (dump_file, &bb_info->in);
++
++ fprintf (dump_file, "reach def:\n");
++ dump_bitmap (dump_file, &rd_local);
++ }
++
++ insn_info = DF_INSN_UID_GET (from_uid);
++ FOR_EACH_INSN_INFO_USE (use, insn_info)
++ {
++ df_link *link;
++
++ if (DF_REF_REGNO (use) >= REGNO (reg)
++ && DF_REF_REGNO (use) < END_REGNO (reg))
++ for (link = DF_REF_CHAIN (use); link; link = link->next)
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, "use ID %d\n", DF_REF_ID (link->ref));
++ if (DF_REF_IS_ARTIFICIAL (link->ref))
++ fprintf (dump_file, "use ref is artificial\n");
++ else
++ {
++ fprintf (dump_file, "use from insn:");
++ print_rtl_single (dump_file, DF_REF_INSN (link->ref));
++ }
++ }
++ result &=
++ (bitmap_bit_p (&rd_local, DF_REF_ID (link->ref)))
++ ? true
++ : false;
++ }
++ }
++
++ bitmap_clear (&rd_local);
++ return result;
++}
++
++/* Return true if the value held by REG is no longer needed before INSN
++ (i.e. REG is dead before INSN), otherwise return false. */
++
++static bool
++nds32_is_dead_reg_p (rtx_insn *insn, rtx reg)
++{
++ basic_block bb = BLOCK_FOR_INSN (insn);
++ bitmap live = BITMAP_ALLOC (®_obstack);
++ bool result = true;
++ rtx_insn *i;
++ unsigned int rn;
++
++ bitmap_copy (live, DF_LR_IN (bb));
++ df_simulate_initialize_forwards (bb, live);
++
++ for (i = BB_HEAD (bb); i != insn; i = NEXT_INSN (i))
++ df_simulate_one_insn_forwards (bb, i, live);
++
++ if (dump_file)
++ {
++ fprintf (dump_file, "scan live regs:");
++ print_rtl_single (dump_file, insn);
++
++ fprintf (dump_file, "bb lr in:\n");
++ dump_bitmap (dump_file, DF_LR_IN (bb));
++
++ fprintf (dump_file, "live:\n");
++ dump_bitmap (dump_file, live);
++ }
++
++ for (rn = REGNO (reg); rn < END_REGNO (reg); ++rn)
++ result &= (bitmap_bit_p (live, rn)) ? false : true;
++
++ BITMAP_FREE (live);
++ return result;
++}
++
++/* Return true if START can do propagation. Notice START maybe a move
++ instruction or an accumulate style instruction.
++ MOV_UID is the uid of beginning move instruction that is only used by
++ function nds32_no_define_reg_p.
++ DST_REG & SRC_REG is the SET_DEST and SET_SRC of a move instruction that
++ maybe real or unreal, respectively.
++ INDEX indicates what number sequence is currently considered rank as
++ consecutive hard registers. Simultaneously, INDEX is the index of row in
++ INSN_LISTS. */
++
++static bool
++nds32_can_cprop_acc_1 (rtx_insn *start, unsigned int mov_uid,
++ rtx dst_reg, rtx src_reg,
++ unsigned int index,
++ std::vector &insn_lists)
++{
++ unsigned int lead_regno = REGNO (dst_reg) + index;
++ unsigned int new_regno = REGNO (src_reg) + index;
++ df_ref def_rec;
++ df_link *link;
++
++ def_rec = nds32_df_find_regno_def (start, lead_regno);
++ gcc_assert (def_rec);
++
++ for (link = DF_REF_CHAIN (def_rec); link; link = link->next)
++ {
++ rtx *use_loc;
++ unsigned int use_regno;
++ enum machine_mode use_mode;
++ rtx_insn *use_insn;
++ rtx acc_reg, new_src;
++
++ if (DF_REF_IS_ARTIFICIAL (link->ref))
++ return false;
++
++ use_loc = DF_REF_LOC (link->ref);
++ gcc_assert (use_loc && REG_P (*use_loc));
++
++ use_regno = REGNO (*use_loc);
++ /* Do not propagate when any insns use register that regno is
++ smaller than DST_REG. */
++ if (use_regno < REGNO (dst_reg))
++ return false;
++
++ /* This status should be handled by previous call. */
++ if (use_regno < lead_regno)
++ continue;
++
++ /* Do not propagate because not all of the pieces of the copy came
++ from DST_REG. */
++ if (END_REGNO (*use_loc) > END_REGNO (dst_reg))
++ return false;
++
++ use_insn = DF_REF_INSN (link->ref);
++ /* Do not propagate since call-used registers can't be replaced. */
++ if (CALL_P (use_insn))
++ return false;
++
++ /* Do not replace in asms intentionally referencing hard registers. */
++ if (asm_noperands (PATTERN (use_insn)) >= 0
++ && use_regno == ORIGINAL_REGNO (*use_loc))
++ return false;
++
++ /* Do not propagate when the register is defined by more than one
++ instruction. */
++ if (!nds32_is_single_def_p (use_insn, *use_loc, INSN_UID (start)))
++ return false;
++
++ use_mode = GET_MODE (*use_loc);
++ new_src = nds32_mode_change_reg (GET_MODE (src_reg),
++ GET_MODE (dst_reg),
++ use_mode,
++ new_regno,
++ use_regno);
++ /* Do not propagate if we can't generate a new register with new mode. */
++ if (!new_src)
++ return false;
++
++ /* Can not replace DST_REG with SRC_REG when SRC_REG is redefined between
++ START and use insn of START. */
++ if (!nds32_no_define_reg_p (use_insn, new_src, mov_uid))
++ return false;
++
++ acc_reg = nds32_is_acc_insn_p (use_insn);
++ /* Handle the accumulate style instruction that accumulate register
++ may be replaced.
++ Also handle the AUTO_INC register that is another form of accumulated
++ register. */
++ if ((acc_reg && rtx_equal_p (acc_reg, *use_loc))
++ || FIND_REG_INC_NOTE (use_insn, *use_loc))
++ {
++ unsigned int i, use_nregs;
++
++ /* ACC_REG can't be replaced since the SRC_REG can't be
++ overwritten. */
++ if (!nds32_is_dead_reg_p (use_insn, new_src))
++ return false;
++
++ /* Once we confirm that ACC_REG can be replaced, the unreal move
++ instruction is generated. For example:
++ mov r0, r1 mov r0, r1
++ cmovn r0, r2, r3 -> cmovn r1, r2, r3
++ mov r0, r1
++ If the unreal move instruction can do propagation, the ACC_REG
++ can be replaced. We check it in a recursive way. */
++ use_nregs = hard_regno_nregs [use_regno][(int) use_mode];
++ for (i = 0; i < use_nregs; ++i)
++ if (!nds32_can_cprop_acc_1 (use_insn, mov_uid,
++ *use_loc, new_src,
++ i, insn_lists))
++ return false;
++ }
++ insn_lists[index].push_back (use_insn);
++ }
++
++ return true;
++}
++
++/* Return true if MOV can do propagation, otherwise return false.
++ INSN_LISTS is used to record what insns need to replace the operands. */
++
++static bool
++nds32_can_cprop_acc (rtx_insn *mov, std::vector &insn_lists)
++{
++ rtx dst_reg = SET_DEST (PATTERN (mov));
++ rtx src_reg = SET_SRC (PATTERN (mov));
++ unsigned int dst_regno = REGNO (dst_reg);
++ enum machine_mode dst_mode = GET_MODE (dst_reg);
++ unsigned int dst_nregs = hard_regno_nregs[dst_regno][(int) dst_mode];
++ unsigned int index;
++
++ insn_lists.resize (dst_nregs);
++ for (index = 0; index < dst_nregs; ++index)
++ if (!nds32_can_cprop_acc_1 (mov, INSN_UID (mov),
++ dst_reg, src_reg,
++ index, insn_lists))
++ return false;
++
++ return true;
++}
++
++/* Replace every occurrence of OLD_REGNO in LOC with NEW_REGNO. LOC maybe a
++ part of INSN.
++ DST_REG & SRC_REG are used by function nds32_mode_change_reg.
++ Mark each change with validate_change passing INSN. */
++
++static void
++nds32_replace_partial_operands (rtx *loc, rtx dst_reg, rtx src_reg,
++ unsigned int old_regno, unsigned int new_regno,
++ rtx_insn *insn)
++{
++ int i, j;
++ rtx x = *loc;
++ enum rtx_code code;
++ const char *fmt;
++
++ if (!x)
++ return;
++
++ code = GET_CODE (x);
++ fmt = GET_RTX_FORMAT (code);
++
++ if (REG_P (x) && REGNO (x) == old_regno)
++ {
++ rtx new_reg = nds32_mode_change_reg (GET_MODE (src_reg),
++ GET_MODE (dst_reg),
++ GET_MODE (x),
++ new_regno,
++ old_regno);
++
++ gcc_assert (new_reg);
++
++ ORIGINAL_REGNO (new_reg) = ORIGINAL_REGNO (x);
++ REG_ATTRS (new_reg) = REG_ATTRS (x);
++ REG_POINTER (new_reg) = REG_POINTER (x);
++
++ /* ??? unshare or not? */
++ validate_change (insn, loc, new_reg, 1);
++ return;
++ }
++
++ /* Call ourself recursively to perform the replacements. */
++ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
++ {
++ if (fmt[i] == 'e')
++ nds32_replace_partial_operands (&XEXP (x, i), dst_reg, src_reg,
++ old_regno, new_regno, insn);
++ else if (fmt[i] == 'E') /* ??? how about V? */
++ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
++ nds32_replace_partial_operands (&XVECEXP (x, i, j), dst_reg, src_reg,
++ old_regno, new_regno, insn);
++ }
++}
++
++/* Try replacing every occurrence of OLD_REGNO in INSN with NEW_REGNO. */
++
++static void
++nds32_replace_all_operands (rtx dst_reg, rtx src_reg,
++ unsigned int old_regno, unsigned int new_regno,
++ rtx_insn *insn)
++{
++ nds32_replace_partial_operands (&PATTERN (insn), dst_reg, src_reg,
++ old_regno, new_regno, insn);
++}
++
++/* Called via note_uses in function nds32_replace_src_operands, for all used
++ rtx do replacement. */
++
++static void
++nds32_replace_src_operands_1 (rtx *loc, void *data)
++{
++ struct replace_src_operands_data *d
++ = (struct replace_src_operands_data *) data;
++
++ nds32_replace_partial_operands (loc, d->dst_reg, d->src_reg,
++ d->old_regno, d->new_regno, d->insn);
++}
++
++/* Try replacing every occurrence of OLD_REGNO in INSN with NEW_REGNO,
++ avoiding SET_DESTs. */
++
++static void
++nds32_replace_src_operands (rtx dst_reg, rtx src_reg,
++ unsigned int old_regno, unsigned int new_regno,
++ rtx_insn *insn)
++{
++ struct replace_src_operands_data d
++ = {dst_reg, src_reg, old_regno, new_regno, insn};
++
++ note_uses (&PATTERN (insn), nds32_replace_src_operands_1, &d);
++}
++
++/* Try replacing every occurrence of SRC_REG (include its consecutive hard
++ registers) in each insn of INSN_LISTS with DST_REG. */
++
++static bool
++nds32_try_replace_operands (rtx dst_reg, rtx src_reg,
++ std::vector &insn_lists)
++{
++ unsigned int i;
++ std::vector::iterator ritr;
++ unsigned int old_regno, new_regno;
++
++ old_regno = REGNO (dst_reg);
++ new_regno = REGNO (src_reg);
++
++ for (i = 0; i < insn_lists.size (); ++i, ++old_regno, ++new_regno)
++ for (ritr = insn_lists[i].begin (); ritr != insn_lists[i].end (); ++ritr)
++ {
++ rtx_insn *insn = *ritr;
++ rtx acc_reg;
++
++ acc_reg = nds32_is_acc_insn_p (insn);
++ if (acc_reg && REGNO (acc_reg) == old_regno)
++ {
++ /* Replace OP_OUT & OP_INOUT */
++ nds32_replace_all_operands (dst_reg, src_reg,
++ old_regno, new_regno, insn);
++
++ }
++ else
++ {
++ /* Replace OP_IN */
++ nds32_replace_src_operands (dst_reg, src_reg,
++ old_regno, new_regno, insn);
++ }
++ }
++
++ if (!apply_change_group ())
++ return false;
++ else
++ {
++ df_analyze ();
++ return true;
++ }
++}
++
++/* Check if each move instruction in WORK_LIST can do propagation, and
++ then try to replace operands if necessary. */
++
++static int
++nds32_do_cprop_acc (auto_vec &work_list)
++{
++ int n_replace = 0;
++ int i;
++ rtx_insn *mov;
++ std::vector insn_lists;
++
++ FOR_EACH_VEC_ELT (work_list, i, mov)
++ {
++ if (nds32_can_cprop_acc (mov, insn_lists))
++ {
++ if (dump_file)
++ fprintf (dump_file, "\n [CPROP_ACC] insn %d will be cprop. \n",
++ INSN_UID (mov));
++
++ if (nds32_try_replace_operands (SET_DEST (PATTERN (mov)),
++ SET_SRC (PATTERN (mov)),
++ insn_lists))
++ n_replace++;
++ }
++ insn_lists.clear ();
++ }
++
++ return n_replace;
++}
++
++/* Return true if MOV meets the conditions of propagation about move
++ instruction, otherwise return false. */
++
++static bool
++nds32_is_target_mov_p (rtx mov)
++{
++ rtx dst = SET_DEST (PATTERN (mov));
++ rtx src = SET_SRC (PATTERN (mov));
++ unsigned int dst_regno, src_regno;
++ unsigned int dst_nregs, src_nregs;
++ bool dst_is_general, src_is_general;
++
++ gcc_assert (REG_P (dst) && REG_P (src));
++
++ dst_regno = REGNO (dst);
++ src_regno = REGNO (src);
++ dst_nregs = hard_regno_nregs[dst_regno][GET_MODE (dst)];
++ src_nregs = hard_regno_nregs[src_regno][GET_MODE (src)];
++
++ /* Do not propagate to the stack pointer, as that can leave memory accesses
++ with no scheduling dependency on the stack update.
++ Adapted from regcprop. */
++ if (dst_regno == STACK_POINTER_REGNUM)
++ return false;
++
++ /* Likewise with the frame pointer, if we're using one.
++ Adapted from regcprop. */
++ if (frame_pointer_needed && dst_regno == HARD_FRAME_POINTER_REGNUM)
++ return false;
++
++ /* Do not propagate to fixed or global registers, patterns can be relying
++ to see particular fixed register or users can expect the chosen global
++ register in asm.
++ Adapted from regcprop. */
++ if (fixed_regs[dst_regno] || global_regs[dst_regno])
++ return false;
++
++ /* Make sure the all consecutive registers of SET_DEST are only defined by
++ SET_SRC. */
++ if (dst_nregs > src_nregs)
++ return false;
++
++ /* Narrowing on big endian will result in the invalid transformation. */
++ if (dst_nregs < src_nregs
++ && (GET_MODE_SIZE (GET_MODE (src)) > UNITS_PER_WORD
++ ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN))
++ return false;
++
++ dst_is_general = in_hard_reg_set_p (reg_class_contents[GENERAL_REGS],
++ GET_MODE (dst), REGNO (dst));
++ src_is_general = in_hard_reg_set_p (reg_class_contents[GENERAL_REGS],
++ GET_MODE (src), REGNO (src));
++ /* Make sure the register class of SET_DEST & SET_SRC are the same. */
++ if (dst_is_general ^ src_is_general)
++ return false;
++
++ return true;
++}
++
++/* Collect the move instructions that are the uses of accumulated register
++ in WORK_LIST */
++
++static void
++nds32_cprop_acc_find_target_mov (auto_vec &work_list)
++{
++ basic_block bb;
++ rtx_insn *insn;
++ rtx acc_reg;
++
++ FOR_EACH_BB_FN (bb, cfun)
++ FOR_BB_INSNS (bb, insn)
++ if (INSN_P (insn))
++ {
++ acc_reg = nds32_is_acc_insn_p (insn);
++ if (acc_reg)
++ {
++ unsigned int acc_regno;
++ enum machine_mode acc_mode;
++ df_ref use;
++ df_link *link;
++ rtx_insn *def_insn;
++
++ if (!single_set (insn) || !REG_P (acc_reg))
++ continue;
++
++ acc_regno = REGNO (acc_reg);
++ /* Don't replace in asms intentionally referencing hard regs. */
++ if (asm_noperands (PATTERN (insn)) >= 0
++ && acc_regno == ORIGINAL_REGNO (acc_reg))
++ continue;
++
++ if (dump_file)
++ fprintf (dump_file,
++ "\n [CPROP_ACC] "
++ "RTL_UID %d is an exchangeable ACC insn. \n",
++ INSN_UID (insn));
++
++ use = df_find_use (insn, acc_reg);
++ gcc_assert (use);
++ link = DF_REF_CHAIN (use);
++
++ if (link->next
++ || DF_REF_IS_ARTIFICIAL (link->ref))
++ continue;
++
++ acc_mode = GET_MODE (acc_reg);
++ def_insn = DF_REF_INSN (link->ref);
++ if (nds32_is_reg_mov_p (def_insn))
++ {
++ rtx *loc = DF_REF_LOC (link->ref);
++ enum machine_mode loc_mode = GET_MODE (*loc);
++
++ /* If the move instruction can't define whole accumulated
++ register, the replacement is invalid. */
++ if (loc_mode != acc_mode)
++ if (hard_regno_nregs[acc_regno][acc_mode]
++ > hard_regno_nregs[acc_regno][loc_mode])
++ continue;
++
++ if (nds32_is_target_mov_p (def_insn))
++ work_list.safe_push (def_insn);
++ }
++ }
++ }
++}
++
++/* Main entry point for the forward copy propagation optimization for
++ accumulate style instruction. */
++
++static int
++nds32_cprop_acc_opt (void)
++{
++ df_chain_add_problem (DF_DU_CHAIN + DF_UD_CHAIN);
++ df_note_add_problem ();
++ df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
++ df_insn_rescan_all ();
++ df_analyze ();
++
++ auto_vec work_list;
++
++ nds32_cprop_acc_find_target_mov (work_list);
++ if (work_list.is_empty())
++ {
++ if (dump_file)
++ fprintf (dump_file, "\n [CPROP_ACC] The work_list is empty. \n");
++ return 0;
++ }
++
++ if (dump_file)
++ {
++ int i;
++ rtx_insn *mov;
++
++ fprintf (dump_file, "\n [CPROP_ACC] The content of work_list:");
++ FOR_EACH_VEC_ELT (work_list, i, mov)
++ fprintf (dump_file, " %d", INSN_UID (mov));
++ fprintf (dump_file, "\n");
++ }
++
++ compute_bb_for_insn ();
++
++ int n_replace = nds32_do_cprop_acc (work_list);
++
++ if (dump_file)
++ {
++ fprintf (dump_file, "\n [CPROP_ACC] Result: ");
++ if (n_replace == 0)
++ fprintf (dump_file, "No move can do cprop. \n");
++ else
++ fprintf (dump_file, "Do cprop for %d move. \n", n_replace);
++ }
++
++ work_list.release ();
++ return 1;
++}
++
++const pass_data pass_data_nds32_cprop_acc_opt =
++{
++ RTL_PASS, /* type */
++ "cprop_acc", /* name */
++ OPTGROUP_NONE, /* optinfo_flags */
++ TV_MACH_DEP, /* tv_id */
++ 0, /* properties_required */
++ 0, /* properties_provided */
++ 0, /* properties_destroyed */
++ 0, /* todo_flags_start */
++ TODO_df_finish, /* todo_flags_finish */
++};
++
++class pass_nds32_cprop_acc_opt : public rtl_opt_pass
++{
++public:
++ pass_nds32_cprop_acc_opt (gcc::context *ctxt)
++ : rtl_opt_pass (pass_data_nds32_cprop_acc_opt, ctxt)
++ {}
++
++ /* opt_pass methods: */
++ bool gate (function *) { return optimize > 0 && flag_nds32_cprop_acc; }
++ unsigned int execute (function *) { return nds32_cprop_acc_opt (); }
++};
++
++rtl_opt_pass *
++make_pass_nds32_cprop_acc_opt (gcc::context *ctxt)
++{
++ return new pass_nds32_cprop_acc_opt (ctxt);
++}
+diff --git a/gcc/config/nds32/nds32-doubleword.md b/gcc/config/nds32/nds32-doubleword.md
+index 23a9f25..7c9dfb9 100644
+--- a/gcc/config/nds32/nds32-doubleword.md
++++ b/gcc/config/nds32/nds32-doubleword.md
+@@ -23,7 +23,8 @@
+ ;; Move DImode/DFmode instructions.
+ ;; -------------------------------------------------------------
+
+-
++;; Do *NOT* try to split DI/DFmode before reload since LRA seem
++;; still buggy for such behavior at least at gcc 4.8.2...
+ (define_expand "movdi"
+ [(set (match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+@@ -46,149 +47,100 @@
+
+
+ (define_insn "move_"
+- [(set (match_operand:DIDF 0 "nonimmediate_operand" "=r, r, r, m")
+- (match_operand:DIDF 1 "general_operand" " r, i, m, r"))]
+- ""
++ [(set (match_operand:DIDF 0 "nonimmediate_operand" "=r, r, r, r, Da, m, f, Q, f, *r, *f")
++ (match_operand:DIDF 1 "general_operand" " r, i, Da, m, r, r, Q, f, f, *f, *r"))]
++ "register_operand(operands[0], mode)
++ || register_operand(operands[1], mode)"
+ {
+- rtx addr;
+- rtx otherops[5];
+-
+ switch (which_alternative)
+ {
+ case 0:
+ return "movd44\t%0, %1";
+-
+ case 1:
+ /* reg <- const_int, we ask gcc to split instruction. */
+ return "#";
+-
+ case 2:
+- /* Refer to nds32_legitimate_address_p() in nds32.c,
+- we only allow "reg", "symbol_ref", "const", and "reg + const_int"
+- as address rtx for DImode/DFmode memory access. */
+- addr = XEXP (operands[1], 0);
+-
+- otherops[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
+- otherops[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
+- otherops[2] = addr;
+-
+- if (REG_P (addr))
+- {
+- /* (reg) <- (mem (reg)) */
+- output_asm_insn ("lmw.bi\t%0, [%2], %1, 0", otherops);
+- }
+- else if (GET_CODE (addr) == PLUS)
+- {
+- /* (reg) <- (mem (plus (reg) (const_int))) */
+- rtx op0 = XEXP (addr, 0);
+- rtx op1 = XEXP (addr, 1);
+-
+- if (REG_P (op0))
+- {
+- otherops[2] = op0;
+- otherops[3] = op1;
+- otherops[4] = gen_int_mode (INTVAL (op1) + 4, SImode);
+- }
+- else
+- {
+- otherops[2] = op1;
+- otherops[3] = op0;
+- otherops[4] = gen_int_mode (INTVAL (op0) + 4, SImode);
+- }
+-
+- /* To avoid base overwrite when REGNO(%0) == REGNO(%2). */
+- if (REGNO (otherops[0]) != REGNO (otherops[2]))
+- {
+- output_asm_insn ("lwi\t%0, [%2 + (%3)]", otherops);
+- output_asm_insn ("lwi\t%1, [%2 + (%4)]", otherops);
+- }
+- else
+- {
+- output_asm_insn ("lwi\t%1, [%2 + (%4)]", otherops);
+- output_asm_insn ("lwi\t%0,[ %2 + (%3)]", otherops);
+- }
+- }
+- else
+- {
+- /* (reg) <- (mem (symbol_ref ...))
+- (reg) <- (mem (const ...)) */
+- output_asm_insn ("lwi.gp\t%0, [ + %2]", otherops);
+- output_asm_insn ("lwi.gp\t%1, [ + %2 + 4]", otherops);
+- }
+-
+- /* We have already used output_asm_insn() by ourself,
+- so return an empty string. */
+- return "";
+-
++ /* The memory format is (mem (reg)),
++ we can generate 'lmw.bi' instruction. */
++ return nds32_output_double (operands, true);
+ case 3:
+- /* Refer to nds32_legitimate_address_p() in nds32.c,
+- we only allow "reg", "symbol_ref", "const", and "reg + const_int"
+- as address rtx for DImode/DFmode memory access. */
+- addr = XEXP (operands[0], 0);
+-
+- otherops[0] = gen_rtx_REG (SImode, REGNO (operands[1]));
+- otherops[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
+- otherops[2] = addr;
+-
+- if (REG_P (addr))
+- {
+- /* (mem (reg)) <- (reg) */
+- output_asm_insn ("smw.bi\t%0, [%2], %1, 0", otherops);
+- }
+- else if (GET_CODE (addr) == PLUS)
+- {
+- /* (mem (plus (reg) (const_int))) <- (reg) */
+- rtx op0 = XEXP (addr, 0);
+- rtx op1 = XEXP (addr, 1);
+-
+- if (REG_P (op0))
+- {
+- otherops[2] = op0;
+- otherops[3] = op1;
+- otherops[4] = gen_int_mode (INTVAL (op1) + 4, SImode);
+- }
+- else
+- {
+- otherops[2] = op1;
+- otherops[3] = op0;
+- otherops[4] = gen_int_mode (INTVAL (op0) + 4, SImode);
+- }
+-
+- /* To avoid base overwrite when REGNO(%0) == REGNO(%2). */
+- if (REGNO (otherops[0]) != REGNO (otherops[2]))
+- {
+- output_asm_insn ("swi\t%0, [%2 + (%3)]", otherops);
+- output_asm_insn ("swi\t%1, [%2 + (%4)]", otherops);
+- }
+- else
+- {
+- output_asm_insn ("swi\t%1, [%2 + (%4)]", otherops);
+- output_asm_insn ("swi\t%0, [%2 + (%3)]", otherops);
+- }
+- }
+- else
+- {
+- /* (mem (symbol_ref ...)) <- (reg)
+- (mem (const ...)) <- (reg) */
+- output_asm_insn ("swi.gp\t%0, [ + %2]", otherops);
+- output_asm_insn ("swi.gp\t%1, [ + %2 + 4]", otherops);
+- }
+-
+- /* We have already used output_asm_insn() by ourself,
+- so return an empty string. */
+- return "";
+-
++ /* We haven't 64-bit load instruction,
++ we split this pattern to two SImode pattern. */
++ return "#";
++ case 4:
++ /* The memory format is (mem (reg)),
++ we can generate 'smw.bi' instruction. */
++ return nds32_output_double (operands, false);
++ case 5:
++ /* We haven't 64-bit store instruction,
++ we split this pattern to two SImode pattern. */
++ return "#";
++ case 6:
++ return nds32_output_float_load (operands);
++ case 7:
++ return nds32_output_float_store (operands);
++ case 8:
++ return "fcpysd\t%0, %1, %1";
++ case 9:
++ return "fmfdr\t%0, %1";
++ case 10:
++ return "fmtdr\t%1, %0";
+ default:
+ gcc_unreachable ();
+ }
+ }
+- [(set_attr "type" "move,move,move,move")
+- (set_attr "length" " 4, 16, 8, 8")])
++ [(set_attr "type" "alu,alu,load,load,store,store,fload,fstore,fcpy,fmfdr,fmtdr")
++ (set_attr_alternative "length"
++ [
++ ;; Alternative 0
++ (if_then_else (match_test "!TARGET_16_BIT")
++ (const_int 4)
++ (const_int 2))
++ ;; Alternative 1
++ (const_int 16)
++ ;; Alternative 2
++ (const_int 4)
++ ;; Alternative 3
++ (const_int 8)
++ ;; Alternative 4
++ (const_int 4)
++ ;; Alternative 5
++ (const_int 8)
++ ;; Alternative 6
++ (const_int 4)
++ ;; Alternative 7
++ (const_int 4)
++ ;; Alternative 8
++ (const_int 4)
++ ;; Alternative 9
++ (const_int 4)
++ ;; Alternative 10
++ (const_int 4)
++ ])
++ (set_attr "feature" " v1, v1, v1, v1, v1, v1, fpu, fpu, fpu, fpu, fpu")])
++
++;; Split move_di pattern when the hard register is odd.
++(define_split
++ [(set (match_operand:DIDF 0 "register_operand" "")
++ (match_operand:DIDF 1 "register_operand" ""))]
++ "(NDS32_IS_GPR_REGNUM (REGNO (operands[0]))
++ && ((REGNO (operands[0]) & 0x1) == 1))
++ || (NDS32_IS_GPR_REGNUM (REGNO (operands[1]))
++ && ((REGNO (operands[1]) & 0x1) == 1))"
++ [(set (match_dup 2) (match_dup 3))
++ (set (match_dup 4) (match_dup 5))]
++ {
++ operands[2] = gen_lowpart (SImode, operands[0]);
++ operands[4] = gen_highpart (SImode, operands[0]);
++ operands[3] = gen_lowpart (SImode, operands[1]);
++ operands[5] = gen_highpart (SImode, operands[1]);
++ }
++)
+
+ (define_split
+ [(set (match_operand:DIDF 0 "register_operand" "")
+ (match_operand:DIDF 1 "const_double_operand" ""))]
+- "reload_completed"
++ "flag_pic || reload_completed"
+ [(set (match_dup 2) (match_dup 3))
+ (set (match_dup 4) (match_dup 5))]
+ {
+@@ -207,7 +159,12 @@
+ /* Actually we would like to create move behavior by ourself.
+ So that movsi expander could have chance to split large constant. */
+ emit_move_insn (operands[2], operands[3]);
+- emit_move_insn (operands[4], operands[5]);
++
++ unsigned HOST_WIDE_INT mask = GET_MODE_MASK (SImode);
++ if ((UINTVAL (operands[3]) & mask) == (UINTVAL (operands[5]) & mask))
++ emit_move_insn (operands[4], operands[2]);
++ else
++ emit_move_insn (operands[4], operands[5]);
+ DONE;
+ })
+
+@@ -217,7 +174,9 @@
+ [(set (match_operand:DIDF 0 "register_operand" "")
+ (match_operand:DIDF 1 "register_operand" ""))]
+ "reload_completed
+- && (TARGET_ISA_V2 || !TARGET_16_BIT)"
++ && (TARGET_ISA_V2 || !TARGET_16_BIT)
++ && NDS32_IS_GPR_REGNUM (REGNO (operands[0]))
++ && NDS32_IS_GPR_REGNUM (REGNO (operands[1]))"
+ [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 2) (match_dup 3))]
+ {
+@@ -239,6 +198,28 @@
+ }
+ })
+
++(define_split
++ [(set (match_operand:DIDF 0 "nds32_general_register_operand" "")
++ (match_operand:DIDF 1 "memory_operand" ""))]
++ "reload_completed
++ && nds32_split_double_word_load_store_p (operands, true)"
++ [(set (match_dup 2) (match_dup 3))
++ (set (match_dup 4) (match_dup 5))]
++{
++ nds32_spilt_doubleword (operands, true);
++})
++
++(define_split
++ [(set (match_operand:DIDF 0 "memory_operand" "")
++ (match_operand:DIDF 1 "nds32_general_register_operand" ""))]
++ "reload_completed
++ && nds32_split_double_word_load_store_p (operands, false)"
++ [(set (match_dup 2) (match_dup 3))
++ (set (match_dup 4) (match_dup 5))]
++{
++ nds32_spilt_doubleword (operands, false);
++})
++
+ ;; -------------------------------------------------------------
+ ;; Boolean DImode instructions.
+ ;; -------------------------------------------------------------
+diff --git a/gcc/config/nds32/nds32-dspext.md b/gcc/config/nds32/nds32-dspext.md
+new file mode 100644
+index 0000000..6ec2137
+--- /dev/null
++++ b/gcc/config/nds32/nds32-dspext.md
+@@ -0,0 +1,5280 @@
++;; Machine description of Andes NDS32 cpu for GNU compiler
++;; Copyright (C) 2012-2016 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_expand "mov"
++ [(set (match_operand:VQIHI 0 "general_operand" "")
++ (match_operand:VQIHI 1 "general_operand" ""))]
++ "NDS32_EXT_DSP_P ()"
++{
++ /* Need to force register if mem <- !reg. */
++ if (MEM_P (operands[0]) && !REG_P (operands[1]))
++ operands[1] = force_reg (mode, operands[1]);
++
++ /* If operands[1] is a large constant and cannot be performed
++ by a single instruction, we need to split it. */
++ if (GET_CODE (operands[1]) == CONST_VECTOR
++ && !satisfies_constraint_CVs2 (operands[1])
++ && !satisfies_constraint_CVhi (operands[1]))
++ {
++ HOST_WIDE_INT ival = const_vector_to_hwint (operands[1]);
++ rtx tmp_rtx;
++
++ tmp_rtx = can_create_pseudo_p ()
++ ? gen_reg_rtx (SImode)
++ : simplify_gen_subreg (SImode, operands[0], mode, 0);
++
++ emit_move_insn (tmp_rtx, gen_int_mode (ival, SImode));
++ convert_move (operands[0], tmp_rtx, false);
++ DONE;
++ }
++
++ if (REG_P (operands[0]) && SYMBOLIC_CONST_P (operands[1]))
++ {
++ if (nds32_tls_referenced_p (operands [1]))
++ {
++ nds32_expand_tls_move (operands);
++ DONE;
++ }
++ else if (flag_pic)
++ {
++ nds32_expand_pic_move (operands);
++ DONE;
++ }
++ }
++})
++
++(define_insn "*mov"
++ [(set (match_operand:VQIHI 0 "nonimmediate_operand" "=r, r,$U45,$U33,$U37,$U45, m,$ l,$ l,$ l,$ d, d, r,$ d, r, r, r, *f, *f, r, *f, Q, A")
++ (match_operand:VQIHI 1 "nds32_vmove_operand" " r, r, l, l, l, d, r, U45, U33, U37, U45,Ufe, m, CVp5, CVs5, CVs2, CVhi, *f, r, *f, Q, *f, r"))]
++ "NDS32_EXT_DSP_P ()
++ && (register_operand(operands[0], mode)
++ || register_operand(operands[1], mode))"
++{
++ switch (which_alternative)
++ {
++ case 0:
++ return "mov55\t%0, %1";
++ case 1:
++ return "ori\t%0, %1, 0";
++ case 2:
++ case 3:
++ case 4:
++ case 5:
++ return nds32_output_16bit_store (operands, );
++ case 6:
++ return nds32_output_32bit_store (operands, );
++ case 7:
++ case 8:
++ case 9:
++ case 10:
++ case 11:
++ return nds32_output_16bit_load (operands, );
++ case 12:
++ return nds32_output_32bit_load (operands, );
++ case 13:
++ return "movpi45\t%0, %1";
++ case 14:
++ return "movi55\t%0, %1";
++ case 15:
++ return "movi\t%0, %1";
++ case 16:
++ return "sethi\t%0, hi20(%1)";
++ case 17:
++ if (TARGET_FPU_SINGLE)
++ return "fcpyss\t%0, %1, %1";
++ else
++ return "#";
++ case 18:
++ return "fmtsr\t%1, %0";
++ case 19:
++ return "fmfsr\t%0, %1";
++ case 20:
++ return nds32_output_float_load (operands);
++ case 21:
++ return nds32_output_float_store (operands);
++ case 22:
++ return "mtusr\t%1, %0";
++ default:
++ gcc_unreachable ();
++ }
++}
++ [(set_attr "type" "alu,alu,store,store,store,store,store,load,load,load,load,load,load,alu,alu,alu,alu,fcpy,fmtsr,fmfsr,fload,fstore,alu")
++ (set_attr "length" " 2, 4, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 4, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4")
++ (set_attr "feature" " v1, v1, v1, v1, v1, v1, v1, v1, v1, v1, v1, v3m, v1, v1, v1, v1, v1, fpu, fpu, fpu, fpu, fpu, v1")])
++
++(define_expand "movv2si"
++ [(set (match_operand:V2SI 0 "general_operand" "")
++ (match_operand:V2SI 1 "general_operand" ""))]
++ "NDS32_EXT_DSP_P ()"
++{
++ /* Need to force register if mem <- !reg. */
++ if (MEM_P (operands[0]) && !REG_P (operands[1]))
++ operands[1] = force_reg (V2SImode, operands[1]);
++})
++
++(define_insn "*movv2si"
++ [(set (match_operand:V2SI 0 "nonimmediate_operand" "=r, r, r, r, Da, m, f, Q, f, r, f")
++ (match_operand:V2SI 1 "general_operand" " r, i, Da, m, r, r, Q, f, f, f, r"))]
++ "NDS32_EXT_DSP_P ()
++ && (register_operand(operands[0], V2SImode)
++ || register_operand(operands[1], V2SImode))"
++{
++ switch (which_alternative)
++ {
++ case 0:
++ return "movd44\t%0, %1";
++ case 1:
++ /* reg <- const_int, we ask gcc to split instruction. */
++ return "#";
++ case 2:
++ /* The memory format is (mem (reg)),
++ we can generate 'lmw.bi' instruction. */
++ return nds32_output_double (operands, true);
++ case 3:
++ /* We haven't 64-bit load instruction,
++ we split this pattern to two SImode pattern. */
++ return "#";
++ case 4:
++ /* The memory format is (mem (reg)),
++ we can generate 'smw.bi' instruction. */
++ return nds32_output_double (operands, false);
++ case 5:
++ /* We haven't 64-bit store instruction,
++ we split this pattern to two SImode pattern. */
++ return "#";
++ case 6:
++ return nds32_output_float_load (operands);
++ case 7:
++ return nds32_output_float_store (operands);
++ case 8:
++ return "fcpysd\t%0, %1, %1";
++ case 9:
++ return "fmfdr\t%0, %1";
++ case 10:
++ return "fmtdr\t%1, %0";
++ default:
++ gcc_unreachable ();
++ }
++}
++ [(set_attr "type" "alu,alu,load,load,store,store,unknown,unknown,unknown,unknown,unknown")
++ (set_attr_alternative "length"
++ [
++ ;; Alternative 0
++ (if_then_else (match_test "!TARGET_16_BIT")
++ (const_int 4)
++ (const_int 2))
++ ;; Alternative 1
++ (const_int 16)
++ ;; Alternative 2
++ (const_int 4)
++ ;; Alternative 3
++ (const_int 8)
++ ;; Alternative 4
++ (const_int 4)
++ ;; Alternative 5
++ (const_int 8)
++ ;; Alternative 6
++ (const_int 4)
++ ;; Alternative 7
++ (const_int 4)
++ ;; Alternative 8
++ (const_int 4)
++ ;; Alternative 9
++ (const_int 4)
++ ;; Alternative 10
++ (const_int 4)
++ ])
++ (set_attr "feature" " v1, v1, v1, v1, v1, v1, fpu, fpu, fpu, fpu, fpu")])
++
++(define_expand "movmisalign"
++ [(set (match_operand:VQIHI 0 "general_operand" "")
++ (match_operand:VQIHI 1 "general_operand" ""))]
++ "NDS32_EXT_DSP_P ()"
++{
++ rtx addr;
++ if (MEM_P (operands[0]) && !REG_P (operands[1]))
++ operands[1] = force_reg (mode, operands[1]);
++
++ if (MEM_P (operands[0]))
++ {
++ addr = force_reg (Pmode, XEXP (operands[0], 0));
++ emit_insn (gen_unaligned_store (addr, operands[1]));
++ }
++ else
++ {
++ addr = force_reg (Pmode, XEXP (operands[1], 0));
++ emit_insn (gen_unaligned_load (operands[0], addr));
++ }
++ DONE;
++})
++
++(define_expand "unaligned_load"
++ [(set (match_operand:VQIHI 0 "register_operand" "=r")
++ (unspec:VQIHI [(mem:VQIHI (match_operand:SI 1 "register_operand" "r"))] UNSPEC_UALOAD_W))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_ISA_V3M)
++ nds32_expand_unaligned_load (operands, mode);
++ else
++ emit_insn (gen_unaligned_load_w (operands[0], gen_rtx_MEM (mode, operands[1])));
++ DONE;
++})
++
++(define_insn "unaligned_load_w"
++ [(set (match_operand:VQIHI 0 "register_operand" "= r")
++ (unspec:VQIHI [(match_operand:VQIHI 1 "nds32_lmw_smw_base_operand" " Umw")] UNSPEC_UALOAD_W))]
++ "NDS32_EXT_DSP_P ()"
++{
++ return nds32_output_lmw_single_word (operands);
++}
++ [(set_attr "type" "load")
++ (set_attr "length" "4")]
++)
++
++(define_expand "unaligned_store"
++ [(set (mem:VQIHI (match_operand:SI 0 "register_operand" "r"))
++ (unspec:VQIHI [(match_operand:VQIHI 1 "register_operand" "r")] UNSPEC_UASTORE_W))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_ISA_V3M)
++ nds32_expand_unaligned_store (operands, mode);
++ else
++ emit_insn (gen_unaligned_store_w (gen_rtx_MEM (mode, operands[0]), operands[1]));
++ DONE;
++})
++
++(define_insn "unaligned_store_w"
++ [(set (match_operand:VQIHI 0 "nds32_lmw_smw_base_operand" "=Umw")
++ (unspec:VQIHI [(match_operand:VQIHI 1 "register_operand" " r")] UNSPEC_UASTORE_W))]
++ "NDS32_EXT_DSP_P ()"
++{
++ return nds32_output_smw_single_word (operands);
++}
++ [(set_attr "type" "store")
++ (set_attr "length" "4")]
++)
++
++(define_insn "add3"
++ [(set (match_operand:VQIHI 0 "register_operand" "=r")
++ (all_plus:VQIHI (match_operand:VQIHI 1 "register_operand" " r")
++ (match_operand:VQIHI 2 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "add %0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")
++ (set_attr "feature" "v1")])
++
++(define_insn "adddi3"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (all_plus:DI (match_operand:DI 1 "register_operand" " r")
++ (match_operand:DI 2 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "add64 %0, %1, %2"
++ [(set_attr "type" "dalu64")
++ (set_attr "length" "4")
++ (set_attr "feature" "v1")])
++
++(define_insn "raddv4qi3"
++ [(set (match_operand:V4QI 0 "register_operand" "=r")
++ (truncate:V4QI
++ (ashiftrt:V4HI
++ (plus:V4HI (sign_extend:V4HI (match_operand:V4QI 1 "register_operand" " r"))
++ (sign_extend:V4HI (match_operand:V4QI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "radd8\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")
++ (set_attr "feature" "v1")])
++
++
++(define_insn "uraddv4qi3"
++ [(set (match_operand:V4QI 0 "register_operand" "=r")
++ (truncate:V4QI
++ (lshiftrt:V4HI
++ (plus:V4HI (zero_extend:V4HI (match_operand:V4QI 1 "register_operand" " r"))
++ (zero_extend:V4HI (match_operand:V4QI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "uradd8\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")
++ (set_attr "feature" "v1")])
++
++(define_insn "raddv2hi3"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (truncate:V2HI
++ (ashiftrt:V2SI
++ (plus:V2SI (sign_extend:V2SI (match_operand:V2HI 1 "register_operand" " r"))
++ (sign_extend:V2SI (match_operand:V2HI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "radd16\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")
++ (set_attr "feature" "v1")])
++
++(define_insn "uraddv2hi3"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (truncate:V2HI
++ (lshiftrt:V2SI
++ (plus:V2SI (zero_extend:V2SI (match_operand:V2HI 1 "register_operand" " r"))
++ (zero_extend:V2SI (match_operand:V2HI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "uradd16\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")
++ (set_attr "feature" "v1")])
++
++(define_insn "radddi3"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (truncate:DI
++ (ashiftrt:TI
++ (plus:TI (sign_extend:TI (match_operand:DI 1 "register_operand" " r"))
++ (sign_extend:TI (match_operand:DI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "radd64\t%0, %1, %2"
++ [(set_attr "type" "dalu64")
++ (set_attr "length" "4")
++ (set_attr "feature" "v1")])
++
++
++(define_insn "uradddi3"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (truncate:DI
++ (lshiftrt:TI
++ (plus:TI (zero_extend:TI (match_operand:DI 1 "register_operand" " r"))
++ (zero_extend:TI (match_operand:DI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "uradd64\t%0, %1, %2"
++ [(set_attr "type" "dalu64")
++ (set_attr "length" "4")
++ (set_attr "feature" "v1")])
++
++(define_insn "sub3"
++ [(set (match_operand:VQIHI 0 "register_operand" "=r")
++ (all_minus:VQIHI (match_operand:VQIHI 1 "register_operand" " r")
++ (match_operand:VQIHI 2 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "sub %0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")
++ (set_attr "feature" "v1")])
++
++(define_insn "subdi3"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (all_minus:DI (match_operand:DI 1 "register_operand" " r")
++ (match_operand:DI 2 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "sub64 %0, %1, %2"
++ [(set_attr "type" "dalu64")
++ (set_attr "length" "4")
++ (set_attr "feature" "v1")])
++
++(define_insn "rsubv4qi3"
++ [(set (match_operand:V4QI 0 "register_operand" "=r")
++ (truncate:V4QI
++ (ashiftrt:V4HI
++ (minus:V4HI (sign_extend:V4HI (match_operand:V4QI 1 "register_operand" " r"))
++ (sign_extend:V4HI (match_operand:V4QI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "rsub8\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_insn "ursubv4qi3"
++ [(set (match_operand:V4QI 0 "register_operand" "=r")
++ (truncate:V4QI
++ (lshiftrt:V4HI
++ (minus:V4HI (zero_extend:V4HI (match_operand:V4QI 1 "register_operand" " r"))
++ (zero_extend:V4HI (match_operand:V4QI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "ursub8\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_insn "rsubv2hi3"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (truncate:V2HI
++ (ashiftrt:V2SI
++ (minus:V2SI (sign_extend:V2SI (match_operand:V2HI 1 "register_operand" " r"))
++ (sign_extend:V2SI (match_operand:V2HI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "rsub16\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_insn "ursubv2hi3"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (truncate:V2HI
++ (lshiftrt:V2SI
++ (minus:V2SI (zero_extend:V2SI (match_operand:V2HI 1 "register_operand" " r"))
++ (zero_extend:V2SI (match_operand:V2HI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "ursub16\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_insn "rsubdi3"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (truncate:DI
++ (ashiftrt:TI
++ (minus:TI (sign_extend:TI (match_operand:DI 1 "register_operand" " r"))
++ (sign_extend:TI (match_operand:DI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "rsub64\t%0, %1, %2"
++ [(set_attr "type" "dalu64")
++ (set_attr "length" "4")])
++
++
++(define_insn "ursubdi3"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (truncate:DI
++ (lshiftrt:TI
++ (minus:TI (zero_extend:TI (match_operand:DI 1 "register_operand" " r"))
++ (zero_extend:TI (match_operand:DI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "ursub64\t%0, %1, %2"
++ [(set_attr "type" "dalu64")
++ (set_attr "length" "4")])
++
++(define_expand "cras16_1"
++ [(match_operand:V2HI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_cras16_1_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_cras16_1_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_insn "cras16_1_le"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (minus:HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (vec_duplicate:V2HI
++ (plus:HI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "cras16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_insn "cras16_1_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (minus:HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (vec_duplicate:V2HI
++ (plus:HI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "cras16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_expand "kcras16_1"
++ [(match_operand:V2HI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_kcras16_1_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_kcras16_1_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_insn "kcras16_1_le"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (ss_minus:HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (vec_duplicate:V2HI
++ (ss_plus:HI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "kcras16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_insn "kcras16_1_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (ss_minus:HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (vec_duplicate:V2HI
++ (ss_plus:HI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "kcras16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_expand "ukcras16_1"
++ [(match_operand:V2HI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_ukcras16_1_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_ukcras16_1_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_insn "ukcras16_1_le"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (us_minus:HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (vec_duplicate:V2HI
++ (us_plus:HI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "ukcras16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_insn "ukcras16_1_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (us_minus:HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (vec_duplicate:V2HI
++ (us_plus:HI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "ukcras16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_expand "crsa16_1"
++ [(match_operand:V2HI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_crsa16_1_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_crsa16_1_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_insn "crsa16_1_le"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (minus:HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (vec_duplicate:V2HI
++ (plus:HI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "crsa16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_insn "crsa16_1_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (minus:HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (vec_duplicate:V2HI
++ (plus:HI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "crsa16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_expand "kcrsa16_1"
++ [(match_operand:V2HI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_kcrsa16_1_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_kcrsa16_1_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_insn "kcrsa16_1_le"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (ss_minus:HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (vec_duplicate:V2HI
++ (ss_plus:HI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "kcrsa16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_insn "kcrsa16_1_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (ss_minus:HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (vec_duplicate:V2HI
++ (ss_plus:HI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "kcrsa16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_expand "ukcrsa16_1"
++ [(match_operand:V2HI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_ukcrsa16_1_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_ukcrsa16_1_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_insn "ukcrsa16_1_le"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (us_minus:HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (vec_duplicate:V2HI
++ (us_plus:HI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "ukcrsa16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_insn "ukcrsa16_1_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (us_minus:HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (vec_duplicate:V2HI
++ (us_plus:HI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "ukcrsa16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_expand "rcras16_1"
++ [(match_operand:V2HI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_rcras16_1_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_rcras16_1_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_insn "rcras16_1_le"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (ashiftrt:SI
++ (minus:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (const_int 1))))
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (ashiftrt:SI
++ (plus:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)]))))
++ (const_int 1))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "rcras16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_insn "rcras16_1_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (ashiftrt:SI
++ (minus:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (const_int 1))))
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (ashiftrt:SI
++ (plus:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)]))))
++ (const_int 1))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "rcras16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_expand "urcras16_1"
++ [(match_operand:V2HI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_urcras16_1_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_urcras16_1_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_insn "urcras16_1_le"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (lshiftrt:SI
++ (minus:SI
++ (zero_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (zero_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (const_int 1))))
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (lshiftrt:SI
++ (plus:SI
++ (zero_extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (zero_extend:SI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)]))))
++ (const_int 1))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "urcras16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_insn "urcras16_1_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (lshiftrt:SI
++ (minus:SI
++ (zero_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (zero_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (const_int 1))))
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (lshiftrt:SI
++ (plus:SI
++ (zero_extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)])))
++ (zero_extend:SI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)]))))
++ (const_int 1))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "urcras16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_expand "rcrsa16_1"
++ [(match_operand:V2HI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_rcrsa16_1_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_rcrsa16_1_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_insn "rcrsa16_1_le"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (ashiftrt:SI
++ (minus:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (const_int 1))))
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (ashiftrt:SI
++ (plus:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))))
++ (const_int 1))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "rcrsa16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_insn "rcrsa16_1_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (ashiftrt:SI
++ (minus:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (const_int 1))))
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (ashiftrt:SI
++ (plus:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))))
++ (const_int 1))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "rcrsa16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_expand "urcrsa16_1"
++ [(match_operand:V2HI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_urcrsa16_1_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_urcrsa16_1_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_insn "urcrsa16_1_le"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (lshiftrt:SI
++ (minus:SI
++ (zero_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (zero_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (const_int 1))))
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (lshiftrt:SI
++ (plus:SI
++ (zero_extend:SI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)])))
++ (zero_extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))))
++ (const_int 1))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "urcrsa16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_insn "urcrsa16_1_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (lshiftrt:SI
++ (minus:SI
++ (zero_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (zero_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (const_int 1))))
++ (vec_duplicate:V2HI
++ (truncate:HI
++ (lshiftrt:SI
++ (plus:SI
++ (zero_extend:SI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)])))
++ (zero_extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))))
++ (const_int 1))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "urcrsa16\t%0, %1, %2"
++ [(set_attr "type" "dalu")]
++)
++
++(define_expand "v2hi3"
++ [(set (match_operand:V2HI 0 "register_operand" "")
++ (shifts:V2HI (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:SI 2 "nds32_rimm4u_operand" "")))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (operands[2] == const0_rtx)
++ {
++ emit_move_insn (operands[0], operands[1]);
++ DONE;
++ }
++})
++
++(define_insn "*ashlv2hi3"
++ [(set (match_operand:V2HI 0 "register_operand" "= r, r")
++ (ashift:V2HI (match_operand:V2HI 1 "register_operand" " r, r")
++ (match_operand:SI 2 "nds32_rimm4u_operand" " Iu04, r")))]
++ "NDS32_EXT_DSP_P ()"
++ "@
++ slli16\t%0, %1, %2
++ sll16\t%0, %1, %2"
++ [(set_attr "type" "dalu,dalu")
++ (set_attr "length" " 4, 4")])
++
++(define_insn "kslli16"
++ [(set (match_operand:V2HI 0 "register_operand" "= r, r")
++ (ss_ashift:V2HI (match_operand:V2HI 1 "register_operand" " r, r")
++ (match_operand:SI 2 "nds32_rimm4u_operand" " Iu04, r")))]
++ "NDS32_EXT_DSP_P ()"
++ "@
++ kslli16\t%0, %1, %2
++ ksll16\t%0, %1, %2"
++ [(set_attr "type" "dalu,dalu")
++ (set_attr "length" " 4, 4")])
++
++(define_insn "*ashrv2hi3"
++ [(set (match_operand:V2HI 0 "register_operand" "= r, r")
++ (ashiftrt:V2HI (match_operand:V2HI 1 "register_operand" " r, r")
++ (match_operand:SI 2 "nds32_rimm4u_operand" " Iu04, r")))]
++ "NDS32_EXT_DSP_P ()"
++ "@
++ srai16\t%0, %1, %2
++ sra16\t%0, %1, %2"
++ [(set_attr "type" "dalu,dalu")
++ (set_attr "length" " 4, 4")])
++
++(define_insn "sra16_round"
++ [(set (match_operand:V2HI 0 "register_operand" "= r, r")
++ (unspec:V2HI [(ashiftrt:V2HI (match_operand:V2HI 1 "register_operand" " r, r")
++ (match_operand:SI 2 "nds32_rimm4u_operand" " Iu04, r"))]
++ UNSPEC_ROUND))]
++ "NDS32_EXT_DSP_P ()"
++ "@
++ srai16.u\t%0, %1, %2
++ sra16.u\t%0, %1, %2"
++ [(set_attr "type" "daluround,daluround")
++ (set_attr "length" " 4, 4")])
++
++(define_insn "*lshrv2hi3"
++ [(set (match_operand:V2HI 0 "register_operand" "= r, r")
++ (lshiftrt:V2HI (match_operand:V2HI 1 "register_operand" " r, r")
++ (match_operand:SI 2 "nds32_rimm4u_operand" " Iu04, r")))]
++ "NDS32_EXT_DSP_P ()"
++ "@
++ srli16\t%0, %1, %2
++ srl16\t%0, %1, %2"
++ [(set_attr "type" "dalu,dalu")
++ (set_attr "length" " 4, 4")])
++
++(define_insn "srl16_round"
++ [(set (match_operand:V2HI 0 "register_operand" "= r, r")
++ (unspec:V2HI [(lshiftrt:V2HI (match_operand:V2HI 1 "register_operand" " r, r")
++ (match_operand:SI 2 "nds32_rimm4u_operand" " Iu04, r"))]
++ UNSPEC_ROUND))]
++ "NDS32_EXT_DSP_P ()"
++ "@
++ srli16.u\t%0, %1, %2
++ srl16.u\t%0, %1, %2"
++ [(set_attr "type" "daluround,daluround")
++ (set_attr "length" " 4, 4")])
++
++(define_insn "kslra16"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (if_then_else:V2HI
++ (lt:SI (match_operand:SI 2 "register_operand" " r")
++ (const_int 0))
++ (ashiftrt:V2HI (match_operand:V2HI 1 "register_operand" " r")
++ (neg:SI (match_dup 2)))
++ (ashift:V2HI (match_dup 1)
++ (match_dup 2))))]
++ "NDS32_EXT_DSP_P ()"
++ "kslra16\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_insn "kslra16_round"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (if_then_else:V2HI
++ (lt:SI (match_operand:SI 2 "register_operand" " r")
++ (const_int 0))
++ (unspec:V2HI [(ashiftrt:V2HI (match_operand:V2HI 1 "register_operand" " r")
++ (neg:SI (match_dup 2)))]
++ UNSPEC_ROUND)
++ (ashift:V2HI (match_dup 1)
++ (match_dup 2))))]
++ "NDS32_EXT_DSP_P ()"
++ "kslra16.u\t%0, %1, %2"
++ [(set_attr "type" "daluround")
++ (set_attr "length" "4")])
++
++(define_insn "cmpeq"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(eq:SI (match_operand:VQIHI 1 "register_operand" " r")
++ (match_operand:VQIHI 2 "register_operand" " r"))]
++ UNSPEC_VEC_COMPARE))]
++ "NDS32_EXT_DSP_P ()"
++ "cmpeq\t%0, %1, %2"
++ [(set_attr "type" "dcmp")
++ (set_attr "length" "4")])
++
++(define_insn "scmplt"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(lt:SI (match_operand:VQIHI 1 "register_operand" " r")
++ (match_operand:VQIHI 2 "register_operand" " r"))]
++ UNSPEC_VEC_COMPARE))]
++ "NDS32_EXT_DSP_P ()"
++ "scmplt\t%0, %1, %2"
++ [(set_attr "type" "dcmp")
++ (set_attr "length" "4")])
++
++(define_insn "scmple"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(le:SI (match_operand:VQIHI 1 "register_operand" " r")
++ (match_operand:VQIHI 2 "register_operand" " r"))]
++ UNSPEC_VEC_COMPARE))]
++ "NDS32_EXT_DSP_P ()"
++ "scmple\t%0, %1, %2"
++ [(set_attr "type" "dcmp")
++ (set_attr "length" "4")])
++
++(define_insn "ucmplt"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(ltu:SI (match_operand:VQIHI 1 "register_operand" " r")
++ (match_operand:VQIHI 2 "register_operand" " r"))]
++ UNSPEC_VEC_COMPARE))]
++ "NDS32_EXT_DSP_P ()"
++ "ucmplt\t%0, %1, %2"
++ [(set_attr "type" "dcmp")
++ (set_attr "length" "4")])
++
++(define_insn "ucmple"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(leu:SI (match_operand:VQIHI 1 "register_operand" " r")
++ (match_operand:VQIHI 2 "register_operand" " r"))]
++ UNSPEC_VEC_COMPARE))]
++ "NDS32_EXT_DSP_P ()"
++ "ucmple\t%0, %1, %2"
++ [(set_attr "type" "dcmp")
++ (set_attr "length" "4")])
++
++(define_insn "sclip16"
++ [(set (match_operand:V2HI 0 "register_operand" "= r")
++ (unspec:V2HI [(match_operand:V2HI 1 "register_operand" " r")
++ (match_operand:SI 2 "nds32_imm4u_operand" " Iu04")]
++ UNSPEC_CLIPS))]
++ "NDS32_EXT_DSP_P ()"
++ "sclip16\t%0, %1, %2"
++ [(set_attr "type" "dclip")
++ (set_attr "length" "4")])
++
++(define_insn "uclip16"
++ [(set (match_operand:V2HI 0 "register_operand" "= r")
++ (unspec:V2HI [(match_operand:V2HI 1 "register_operand" " r")
++ (match_operand:SI 2 "nds32_imm4u_operand" " Iu04")]
++ UNSPEC_CLIP))]
++ "NDS32_EXT_DSP_P ()"
++ "uclip16\t%0, %1, %2"
++ [(set_attr "type" "dclip")
++ (set_attr "length" "4")])
++
++(define_insn "khm16"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (unspec:V2HI [(match_operand:V2HI 1 "register_operand" " r")
++ (match_operand:V2HI 2 "register_operand" " r")]
++ UNSPEC_KHM))]
++ "NDS32_EXT_DSP_P ()"
++ "khm16\t%0, %1, %2"
++ [(set_attr "type" "dmul")
++ (set_attr "length" "4")])
++
++(define_insn "khmx16"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (unspec:V2HI [(match_operand:V2HI 1 "register_operand" " r")
++ (match_operand:V2HI 2 "register_operand" " r")]
++ UNSPEC_KHMX))]
++ "NDS32_EXT_DSP_P ()"
++ "khmx16\t%0, %1, %2"
++ [(set_attr "type" "dmul")
++ (set_attr "length" "4")])
++
++(define_expand "vec_setv4qi"
++ [(match_operand:V4QI 0 "register_operand" "")
++ (match_operand:QI 1 "register_operand" "")
++ (match_operand:SI 2 "immediate_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ HOST_WIDE_INT pos = INTVAL (operands[2]);
++ if (pos > 4)
++ gcc_unreachable ();
++ HOST_WIDE_INT elem = (HOST_WIDE_INT) 1 << pos;
++ emit_insn (gen_vec_setv4qi_internal (operands[0], operands[1],
++ operands[0], GEN_INT (elem)));
++ DONE;
++})
++
++(define_expand "insb"
++ [(match_operand:V4QI 0 "register_operand" "")
++ (match_operand:V4QI 1 "register_operand" "")
++ (match_operand:SI 2 "register_operand" "")
++ (match_operand:SI 3 "const_int_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (INTVAL (operands[3]) > 3 || INTVAL (operands[3]) < 0)
++ gcc_unreachable ();
++
++ rtx src = gen_reg_rtx (QImode);
++
++ convert_move (src, operands[2], false);
++
++ HOST_WIDE_INT selector_index;
++ /* Big endian need reverse index. */
++ if (TARGET_BIG_ENDIAN)
++ selector_index = 4 - INTVAL (operands[3]) - 1;
++ else
++ selector_index = INTVAL (operands[3]);
++ rtx selector = gen_int_mode (1 << selector_index, SImode);
++ emit_insn (gen_vec_setv4qi_internal (operands[0], src,
++ operands[1], selector));
++ DONE;
++})
++
++(define_expand "insvsi"
++ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "const_int_operand" "")
++ (match_operand:SI 2 "nds32_insv_operand" ""))
++ (match_operand:SI 3 "register_operand" ""))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (INTVAL (operands[1]) != 8)
++ FAIL;
++}
++ [(set_attr "type" "dinsb")
++ (set_attr "length" "4")])
++
++
++(define_insn "insvsi_internal"
++ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
++ (const_int 8)
++ (match_operand:SI 1 "nds32_insv_operand" "i"))
++ (match_operand:SI 2 "register_operand" "r"))]
++ "NDS32_EXT_DSP_P ()"
++ "insb\t%0, %2, %v1"
++ [(set_attr "type" "dinsb")
++ (set_attr "length" "4")])
++
++(define_insn "insvsiqi_internal"
++ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
++ (const_int 8)
++ (match_operand:SI 1 "nds32_insv_operand" "i"))
++ (zero_extend:SI (match_operand:QI 2 "register_operand" "r")))]
++ "NDS32_EXT_DSP_P ()"
++ "insb\t%0, %2, %v1"
++ [(set_attr "type" "dinsb")
++ (set_attr "length" "4")])
++
++;; Intermedium pattern for synthetize insvsiqi_internal
++;; v0 = ((v1 & 0xff) << 8)
++(define_insn_and_split "and0xff_s8"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "r")
++ (const_int 8))
++ (const_int 65280)))]
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 1)]
++{
++ rtx tmp = gen_reg_rtx (SImode);
++ emit_insn (gen_ashlsi3 (tmp, operands[1], gen_int_mode (8, SImode)));
++ emit_insn (gen_andsi3 (operands[0], tmp, gen_int_mode (0xffff, SImode)));
++ DONE;
++})
++
++;; v0 = (v1 & 0xff00ffff) | ((v2 << 16) | 0xff0000)
++(define_insn_and_split "insbsi2"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI (and:SI (match_operand:SI 1 "register_operand" "0")
++ (const_int -16711681))
++ (and:SI (ashift:SI (match_operand:SI 2 "register_operand" "r")
++ (const_int 16))
++ (const_int 16711680))))]
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 1)]
++{
++ rtx tmp = gen_reg_rtx (SImode);
++ emit_move_insn (tmp, operands[1]);
++ emit_insn (gen_insvsi_internal (tmp, gen_int_mode(16, SImode), operands[2]));
++ emit_move_insn (operands[0], tmp);
++ DONE;
++})
++
++;; v0 = (v1 & 0xff00ffff) | v2
++(define_insn_and_split "ior_and0xff00ffff_reg"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI (and:SI (match_operand:SI 1 "register_operand" "r")
++ (const_int -16711681))
++ (match_operand:SI 2 "register_operand" "r")))]
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 1)]
++{
++ rtx tmp = gen_reg_rtx (SImode);
++ emit_insn (gen_andsi3 (tmp, operands[1], gen_int_mode (0xff00ffff, SImode)));
++ emit_insn (gen_iorsi3 (operands[0], tmp, operands[2]));
++ DONE;
++})
++
++(define_insn "vec_setv4qi_internal"
++ [(set (match_operand:V4QI 0 "register_operand" "= r, r, r, r")
++ (vec_merge:V4QI
++ (vec_duplicate:V4QI
++ (match_operand:QI 1 "register_operand" " r, r, r, r"))
++ (match_operand:V4QI 2 "register_operand" " 0, 0, 0, 0")
++ (match_operand:SI 3 "nds32_imm_1_2_4_8_operand" " Iv01, Iv02, Iv04, Iv08")))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "insb\t%0, %1, 3",
++ "insb\t%0, %1, 2",
++ "insb\t%0, %1, 1",
++ "insb\t%0, %1, 0" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "insb\t%0, %1, 0",
++ "insb\t%0, %1, 1",
++ "insb\t%0, %1, 2",
++ "insb\t%0, %1, 3" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dinsb")
++ (set_attr "length" "4")])
++
++(define_insn "vec_setv4qi_internal_vec"
++ [(set (match_operand:V4QI 0 "register_operand" "= r, r, r, r")
++ (vec_merge:V4QI
++ (vec_duplicate:V4QI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r, r, r, r")
++ (parallel [(const_int 0)])))
++ (match_operand:V4QI 2 "register_operand" " 0, 0, 0, 0")
++ (match_operand:SI 3 "nds32_imm_1_2_4_8_operand" " Iv01, Iv02, Iv04, Iv08")))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ insb\t%0, %1, 0
++ insb\t%0, %1, 1
++ insb\t%0, %1, 2
++ insb\t%0, %1, 3"
++ [(set_attr "type" "dinsb")
++ (set_attr "length" "4")])
++
++(define_insn "vec_mergev4qi_and_cv0_1"
++ [(set (match_operand:V4QI 0 "register_operand" "=$l,r")
++ (vec_merge:V4QI
++ (vec_duplicate:V4QI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " l,r")
++ (parallel [(const_int 0)])))
++ (const_vector:V4QI [
++ (const_int 0)
++ (const_int 0)
++ (const_int 0)
++ (const_int 0)])
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ zeb33\t%0, %1
++ zeb\t%0, %1"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_insn "vec_mergev4qi_and_cv0_2"
++ [(set (match_operand:V4QI 0 "register_operand" "=$l,r")
++ (vec_merge:V4QI
++ (const_vector:V4QI [
++ (const_int 0)
++ (const_int 0)
++ (const_int 0)
++ (const_int 0)])
++ (vec_duplicate:V4QI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " l,r")
++ (parallel [(const_int 0)])))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ zeb33\t%0, %1
++ zeb\t%0, %1"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_insn "vec_mergeqi_and_cv0_1"
++ [(set (match_operand:V4QI 0 "register_operand" "=$l,r")
++ (vec_merge:V4QI
++ (vec_duplicate:V4QI (match_operand:QI 1 "register_operand" " l,r"))
++ (const_vector:V4QI [
++ (const_int 0)
++ (const_int 0)
++ (const_int 0)
++ (const_int 0)])
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ zeb33\t%0, %1
++ zeb\t%0, %1"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_insn "vec_mergeqi_and_cv0_2"
++ [(set (match_operand:V4QI 0 "register_operand" "=$l,r")
++ (vec_merge:V4QI
++ (const_vector:V4QI [
++ (const_int 0)
++ (const_int 0)
++ (const_int 0)
++ (const_int 0)])
++ (vec_duplicate:V4QI (match_operand:QI 1 "register_operand" " l,r"))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ zeb33\t%0, %1
++ zeb\t%0, %1"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_expand "vec_setv2hi"
++ [(match_operand:V2HI 0 "register_operand" "")
++ (match_operand:HI 1 "register_operand" "")
++ (match_operand:SI 2 "immediate_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ HOST_WIDE_INT pos = INTVAL (operands[2]);
++ if (pos > 2)
++ gcc_unreachable ();
++ HOST_WIDE_INT elem = (HOST_WIDE_INT) 1 << pos;
++ emit_insn (gen_vec_setv2hi_internal (operands[0], operands[1],
++ operands[0], GEN_INT (elem)));
++ DONE;
++})
++
++(define_insn "vec_setv2hi_internal"
++ [(set (match_operand:V2HI 0 "register_operand" "= r, r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (match_operand:HI 1 "register_operand" " r, r"))
++ (match_operand:V2HI 2 "register_operand" " r, r")
++ (match_operand:SI 3 "nds32_imm_1_2_operand" " Iv01, Iv02")))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "pkbb16\t%0, %1, %2",
++ "pktb16\t%0, %2, %1" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "pktb16\t%0, %2, %1",
++ "pkbb16\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "vec_mergev2hi_and_cv0_1"
++ [(set (match_operand:V2HI 0 "register_operand" "=$l,r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " l,r")
++ (parallel [(const_int 0)])))
++ (const_vector:V2HI [
++ (const_int 0)
++ (const_int 0)])
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ zeh33\t%0, %1
++ zeh\t%0, %1"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_insn "vec_mergev2hi_and_cv0_2"
++ [(set (match_operand:V2HI 0 "register_operand" "=$l,r")
++ (vec_merge:V2HI
++ (const_vector:V2HI [
++ (const_int 0)
++ (const_int 0)])
++ (vec_duplicate:V2HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " l,r")
++ (parallel [(const_int 0)])))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ zeh33\t%0, %1
++ zeh\t%0, %1"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_insn "vec_mergehi_and_cv0_1"
++ [(set (match_operand:V2HI 0 "register_operand" "=$l,r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI (match_operand:HI 1 "register_operand" " l,r"))
++ (const_vector:V2HI [
++ (const_int 0)
++ (const_int 0)])
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ zeh33\t%0, %1
++ zeh\t%0, %1"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_insn "vec_mergehi_and_cv0_2"
++ [(set (match_operand:V2HI 0 "register_operand" "=$l,r")
++ (vec_merge:V2HI
++ (const_vector:V2HI [
++ (const_int 0)
++ (const_int 0)])
++ (vec_duplicate:V2HI (match_operand:HI 1 "register_operand" " l,r"))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ zeh33\t%0, %1
++ zeh\t%0, %1"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_expand "pkbb"
++ [(match_operand:V2HI 0 "register_operand")
++ (match_operand:V2HI 1 "register_operand")
++ (match_operand:V2HI 2 "register_operand")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ emit_insn (gen_vec_mergevv (operands[0], operands[1], operands[2],
++ GEN_INT (1), GEN_INT (1), GEN_INT (1)));
++ }
++ else
++ {
++ emit_insn (gen_vec_mergevv (operands[0], operands[1], operands[2],
++ GEN_INT (2), GEN_INT (0), GEN_INT (0)));
++ }
++ DONE;
++})
++
++(define_insn "pkbbsi_1"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI (and:SI (match_operand:SI 1 "register_operand" "r")
++ (const_int 65535))
++ (ashift:SI (match_operand:SI 2 "register_operand" "r")
++ (const_int 16))))]
++ "NDS32_EXT_DSP_P ()"
++ "pkbb16\t%0, %2, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "pkbbsi_2"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI (ashift:SI (match_operand:SI 2 "register_operand" "r")
++ (const_int 16))
++ (and:SI (match_operand:SI 1 "register_operand" "r")
++ (const_int 65535))))]
++ "NDS32_EXT_DSP_P ()"
++ "pkbb16\t%0, %2, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "pkbbsi_3"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "r"))
++ (ashift:SI (match_operand:SI 2 "register_operand" "r")
++ (const_int 16))))]
++ "NDS32_EXT_DSP_P ()"
++ "pkbb16\t%0, %2, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "pkbbsi_4"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI (ashift:SI (match_operand:SI 2 "register_operand" "r")
++ (const_int 16))
++ (zero_extend:SI (match_operand:HI 1 "register_operand" "r"))))]
++ "NDS32_EXT_DSP_P ()"
++ "pkbb16\t%0, %2, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++;; v0 = (v1 & 0xffff0000) | (v2 & 0xffff)
++(define_insn "pktbsi_1"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI (and:SI (match_operand:SI 1 "register_operand" "r")
++ (const_int -65536))
++ (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
++ "NDS32_EXT_DSP_P ()"
++ "pktb16\t%0, %1, %2"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "pktbsi_2"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI (and:SI (match_operand:SI 1 "register_operand" "r")
++ (const_int -65536))
++ (and:SI (match_operand:SI 2 "register_operand" "r")
++ (const_int 65535))))]
++ "NDS32_EXT_DSP_P ()"
++ "pktb16\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "pktbsi_3"
++ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
++ (const_int 16 )
++ (const_int 0))
++ (match_operand:SI 1 "register_operand" " r"))]
++ "NDS32_EXT_DSP_P ()"
++ "pktb16\t%0, %0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "pktbsi_4"
++ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
++ (const_int 16 )
++ (const_int 0))
++ (zero_extend:SI (match_operand:HI 1 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "pktb16\t%0, %0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "pkttsi"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI (and:SI (match_operand:SI 1 "register_operand" " r")
++ (const_int -65536))
++ (lshiftrt:SI (match_operand:SI 2 "register_operand" " r")
++ (const_int 16))))]
++ "NDS32_EXT_DSP_P ()"
++ "pktt16\t%0, %1, %2"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_expand "pkbt"
++ [(match_operand:V2HI 0 "register_operand")
++ (match_operand:V2HI 1 "register_operand")
++ (match_operand:V2HI 2 "register_operand")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ emit_insn (gen_vec_mergevv (operands[0], operands[1], operands[2],
++ GEN_INT (1), GEN_INT (1), GEN_INT (0)));
++ }
++ else
++ {
++ emit_insn (gen_vec_mergevv (operands[0], operands[1], operands[2],
++ GEN_INT (2), GEN_INT (0), GEN_INT (1)));
++ }
++ DONE;
++})
++
++(define_expand "pktt"
++ [(match_operand:V2HI 0 "register_operand")
++ (match_operand:V2HI 1 "register_operand")
++ (match_operand:V2HI 2 "register_operand")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ emit_insn (gen_vec_mergevv (operands[0], operands[1], operands[2],
++ GEN_INT (1), GEN_INT (0), GEN_INT (0)));
++ }
++ else
++ {
++ emit_insn (gen_vec_mergevv (operands[0], operands[1], operands[2],
++ GEN_INT (2), GEN_INT (1), GEN_INT (1)));
++ }
++ DONE;
++})
++
++(define_expand "pktb"
++ [(match_operand:V2HI 0 "register_operand")
++ (match_operand:V2HI 1 "register_operand")
++ (match_operand:V2HI 2 "register_operand")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ emit_insn (gen_vec_mergevv (operands[0], operands[1], operands[2],
++ GEN_INT (1), GEN_INT (0), GEN_INT (1)));
++ }
++ else
++ {
++ emit_insn (gen_vec_mergevv (operands[0], operands[1], operands[2],
++ GEN_INT (2), GEN_INT (1), GEN_INT (0)));
++ }
++ DONE;
++})
++
++(define_insn "vec_mergerr"
++ [(set (match_operand:V2HI 0 "register_operand" "= r, r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (match_operand:HI 1 "register_operand" " r, r"))
++ (vec_duplicate:V2HI
++ (match_operand:HI 2 "register_operand" " r, r"))
++ (match_operand:SI 3 "nds32_imm_1_2_operand" " Iv01, Iv02")))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ pkbb16\t%0, %2, %1
++ pkbb16\t%0, %1, %2"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++
++(define_insn "vec_merge"
++ [(set (match_operand:V2HI 0 "register_operand" "= r, r")
++ (vec_merge:V2HI
++ (match_operand:V2HI 1 "register_operand" " r, r")
++ (match_operand:V2HI 2 "register_operand" " r, r")
++ (match_operand:SI 3 "nds32_imm_1_2_operand" " Iv01, Iv02")))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "pktb16\t%0, %1, %2",
++ "pktb16\t%0, %2, %1" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "pktb16\t%0, %2, %1",
++ "pktb16\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "vec_mergerv"
++ [(set (match_operand:V2HI 0 "register_operand" "= r, r, r, r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (match_operand:HI 1 "register_operand" " r, r, r, r"))
++ (vec_duplicate:V2HI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r, r, r, r")
++ (parallel [(match_operand:SI 4 "nds32_imm_0_1_operand" " Iv00, Iv01, Iv00, Iv01")])))
++ (match_operand:SI 3 "nds32_imm_1_2_operand" " Iv01, Iv01, Iv02, Iv02")))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ pkbb16\t%0, %2, %1
++ pktb16\t%0, %2, %1
++ pkbb16\t%0, %1, %2
++ pkbt16\t%0, %1, %2"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "vec_mergevr"
++ [(set (match_operand:V2HI 0 "register_operand" "= r, r, r, r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r, r, r, r")
++ (parallel [(match_operand:SI 4 "nds32_imm_0_1_operand" " Iv00, Iv01, Iv00, Iv01")])))
++ (vec_duplicate:V2HI
++ (match_operand:HI 2 "register_operand" " r, r, r, r"))
++ (match_operand:SI 3 "nds32_imm_1_2_operand" " Iv01, Iv01, Iv02, Iv02")))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ pkbb16\t%0, %2, %1
++ pkbt16\t%0, %2, %1
++ pkbb16\t%0, %1, %2
++ pktb16\t%0, %1, %2"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "vec_mergevv"
++ [(set (match_operand:V2HI 0 "register_operand" "= r, r, r, r, r, r, r, r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r, r, r, r, r, r, r, r")
++ (parallel [(match_operand:SI 4 "nds32_imm_0_1_operand" " Iv00, Iv00, Iv01, Iv01, Iv00, Iv00, Iv01, Iv01")])))
++ (vec_duplicate:V2HI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r, r, r, r, r, r, r, r")
++ (parallel [(match_operand:SI 5 "nds32_imm_0_1_operand" " Iv00, Iv01, Iv01, Iv00, Iv00, Iv01, Iv01, Iv00")])))
++ (match_operand:SI 3 "nds32_imm_1_2_operand" " Iv01, Iv01, Iv01, Iv01, Iv02, Iv02, Iv02, Iv02")))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "pktt16\t%0, %1, %2",
++ "pktb16\t%0, %1, %2",
++ "pkbb16\t%0, %1, %2",
++ "pkbt16\t%0, %1, %2",
++ "pktt16\t%0, %2, %1",
++ "pkbt16\t%0, %2, %1",
++ "pkbb16\t%0, %2, %1",
++ "pktb16\t%0, %2, %1" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "pkbb16\t%0, %2, %1",
++ "pktb16\t%0, %2, %1",
++ "pktt16\t%0, %2, %1",
++ "pkbt16\t%0, %2, %1",
++ "pkbb16\t%0, %1, %2",
++ "pkbt16\t%0, %1, %2",
++ "pktt16\t%0, %1, %2",
++ "pktb16\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_expand "vec_extractv4qi"
++ [(set (match_operand:QI 0 "register_operand" "")
++ (vec_select:QI
++ (match_operand:V4QI 1 "nonimmediate_operand" "")
++ (parallel [(match_operand:SI 2 "const_int_operand" "")])))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++{
++ if (INTVAL (operands[2]) != 0
++ && INTVAL (operands[2]) != 1
++ && INTVAL (operands[2]) != 2
++ && INTVAL (operands[2]) != 3)
++ gcc_unreachable ();
++
++ if (INTVAL (operands[2]) != 0 && MEM_P (operands[0]))
++ FAIL;
++})
++
++(define_insn "vec_extractv4qi0"
++ [(set (match_operand:QI 0 "register_operand" "=l,r,r")
++ (vec_select:QI
++ (match_operand:V4QI 1 "nonimmediate_operand" " l,r,m")
++ (parallel [(const_int 0)])))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++{
++ switch (which_alternative)
++ {
++ case 0:
++ return "zeb33\t%0, %1";
++ case 1:
++ return "zeb\t%0, %1";
++ case 2:
++ return nds32_output_32bit_load (operands, 1);
++ default:
++ gcc_unreachable ();
++ }
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "vec_extractv4qi0_ze"
++ [(set (match_operand:SI 0 "register_operand" "=l,r,r")
++ (zero_extend:SI
++ (vec_select:QI
++ (match_operand:V4QI 1 "nonimmediate_operand" " l,r,m")
++ (parallel [(const_int 0)]))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++{
++ switch (which_alternative)
++ {
++ case 0:
++ return "zeb33\t%0, %1";
++ case 1:
++ return "zeb\t%0, %1";
++ case 2:
++ return nds32_output_32bit_load (operands, 1);
++ default:
++ gcc_unreachable ();
++ }
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "vec_extractv4qi0_se"
++ [(set (match_operand:SI 0 "register_operand" "=l,r,r")
++ (sign_extend:SI
++ (vec_select:QI
++ (match_operand:V4QI 1 "nonimmediate_operand" " l,r,m")
++ (parallel [(const_int 0)]))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++{
++ switch (which_alternative)
++ {
++ case 0:
++ return "seb33\t%0, %1";
++ case 1:
++ return "seb\t%0, %1";
++ case 2:
++ return nds32_output_32bit_load_se (operands, 1);
++ default:
++ gcc_unreachable ();
++ }
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "vec_extractv4qi1"
++ [(set (match_operand:QI 0 "register_operand" "=r")
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 1)])))]
++ "NDS32_EXT_DSP_P () && !reload_completed && !TARGET_BIG_ENDIAN"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 1)]
++{
++ rtx tmp = gen_reg_rtx (V4QImode);
++ emit_insn (gen_rotrv4qi_1 (tmp, operands[1]));
++ emit_insn (gen_vec_extractv4qi0 (operands[0], tmp));
++ DONE;
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "vec_extractv4qi2"
++ [(set (match_operand:QI 0 "register_operand" "=r")
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 2)])))]
++ "NDS32_EXT_DSP_P () && !reload_completed && !TARGET_BIG_ENDIAN"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 1)]
++{
++ rtx tmp = gen_reg_rtx (V4QImode);
++ emit_insn (gen_rotrv4qi_2 (tmp, operands[1]));
++ emit_insn (gen_vec_extractv4qi0 (operands[0], tmp));
++ DONE;
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "vec_extractv4qi3"
++ [(set (match_operand:QI 0 "register_operand" "=r")
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 3)])))]
++ "NDS32_EXT_DSP_P () && !reload_completed && !TARGET_BIG_ENDIAN"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 1)]
++{
++ rtx tmp = gen_reg_rtx (V4QImode);
++ emit_insn (gen_rotrv4qi_3 (tmp, operands[1]));
++ emit_insn (gen_vec_extractv4qi0 (operands[0], tmp));
++ DONE;
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "vec_extractv4qi3_se"
++ [(set (match_operand:SI 0 "register_operand" "=$d,r")
++ (sign_extend:SI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " 0,r")
++ (parallel [(const_int 3)]))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ srai45\t%0, 24
++ srai\t%0, %1, 24"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_insn "vec_extractv4qi3_ze"
++ [(set (match_operand:SI 0 "register_operand" "=$d,r")
++ (zero_extend:SI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " 0,r")
++ (parallel [(const_int 3)]))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ srli45\t%0, 24
++ srli\t%0, %1, 24"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_insn_and_split "vec_extractv4qihi0"
++ [(set (match_operand:HI 0 "register_operand" "=r")
++ (sign_extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))))]
++ "NDS32_EXT_DSP_P () && !reload_completed && !TARGET_BIG_ENDIAN"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 1)]
++{
++ rtx tmp = gen_reg_rtx (QImode);
++ emit_insn (gen_vec_extractv4qi0 (tmp, operands[1]));
++ emit_insn (gen_extendqihi2 (operands[0], tmp));
++ DONE;
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "vec_extractv4qihi1"
++ [(set (match_operand:HI 0 "register_operand" "=r")
++ (sign_extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 1)]))))]
++ "NDS32_EXT_DSP_P () && !reload_completed && !TARGET_BIG_ENDIAN"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 1)]
++{
++ rtx tmp = gen_reg_rtx (QImode);
++ emit_insn (gen_vec_extractv4qi1 (tmp, operands[1]));
++ emit_insn (gen_extendqihi2 (operands[0], tmp));
++ DONE;
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "vec_extractv4qihi2"
++ [(set (match_operand:HI 0 "register_operand" "=r")
++ (sign_extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 2)]))))]
++ "NDS32_EXT_DSP_P () && !reload_completed && !TARGET_BIG_ENDIAN"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 1)]
++{
++ rtx tmp = gen_reg_rtx (QImode);
++ emit_insn (gen_vec_extractv4qi2 (tmp, operands[1]));
++ emit_insn (gen_extendqihi2 (operands[0], tmp));
++ DONE;
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "vec_extractv4qihi3"
++ [(set (match_operand:HI 0 "register_operand" "=r")
++ (sign_extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 3)]))))]
++ "NDS32_EXT_DSP_P () && !reload_completed && !TARGET_BIG_ENDIAN"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 1)]
++{
++ rtx tmp = gen_reg_rtx (QImode);
++ emit_insn (gen_vec_extractv4qi3 (tmp, operands[1]));
++ emit_insn (gen_extendqihi2 (operands[0], tmp));
++ DONE;
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_expand "vec_extractv2hi"
++ [(set (match_operand:HI 0 "register_operand" "")
++ (vec_select:HI
++ (match_operand:V2HI 1 "nonimmediate_operand" "")
++ (parallel [(match_operand:SI 2 "const_int_operand" "")])))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (INTVAL (operands[2]) != 0
++ && INTVAL (operands[2]) != 1)
++ gcc_unreachable ();
++
++ if (INTVAL (operands[2]) != 0 && MEM_P (operands[0]))
++ FAIL;
++})
++
++(define_insn "vec_extractv2hi0"
++ [(set (match_operand:HI 0 "register_operand" "=$l,r,r")
++ (vec_select:HI
++ (match_operand:V2HI 1 "nonimmediate_operand" " l,r,m")
++ (parallel [(const_int 0)])))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++{
++ switch (which_alternative)
++ {
++ case 0:
++ return "seh33\t%0, %1";
++ case 1:
++ return "seh\t%0, %1";
++ case 2:
++ return nds32_output_32bit_load_se (operands, 2);
++
++ default:
++ gcc_unreachable ();
++ }
++}
++ [(set_attr "type" "alu,alu,load")
++ (set_attr "length" " 2, 4, 4")])
++
++(define_insn "vec_extractv2hi0_ze"
++ [(set (match_operand:SI 0 "register_operand" "=$l, r,$ l, *r")
++ (zero_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "nonimmediate_operand" " l, r, U33, m")
++ (parallel [(const_int 0)]))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++{
++ switch (which_alternative)
++ {
++ case 0:
++ return "zeh33\t%0, %1";
++ case 1:
++ return "zeh\t%0, %1";
++ case 2:
++ return nds32_output_16bit_load (operands, 2);
++ case 3:
++ return nds32_output_32bit_load (operands, 2);
++
++ default:
++ gcc_unreachable ();
++ }
++}
++ [(set_attr "type" "alu,alu,load,load")
++ (set_attr "length" " 2, 4, 2, 4")])
++
++(define_insn "vec_extractv2hi0_se"
++ [(set (match_operand:SI 0 "register_operand" "=$l, r, r")
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "nonimmediate_operand" " l,r,m")
++ (parallel [(const_int 0)]))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++{
++ switch (which_alternative)
++ {
++ case 0:
++ return "seh33\t%0, %1";
++ case 1:
++ return "seh\t%0, %1";
++ case 2:
++ return nds32_output_32bit_load_se (operands, 2);
++
++ default:
++ gcc_unreachable ();
++ }
++}
++ [(set_attr "type" "alu,alu,load")
++ (set_attr "length" " 2, 4, 4")])
++
++(define_insn "vec_extractv2hi0_be"
++ [(set (match_operand:HI 0 "register_operand" "=$d,r")
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " 0,r")
++ (parallel [(const_int 0)])))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "@
++ srai45\t%0, 16
++ srai\t%0, %1, 16"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_insn "vec_extractv2hi1"
++ [(set (match_operand:HI 0 "register_operand" "=$d,r")
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " 0,r")
++ (parallel [(const_int 1)])))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ srai45\t%0, 16
++ srai\t%0, %1, 16"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_insn "vec_extractv2hi1_se"
++ [(set (match_operand:SI 0 "register_operand" "=$d,r")
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " 0,r")
++ (parallel [(const_int 1)]))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ srai45\t%0, 16
++ srai\t%0, %1, 16"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_insn "vec_extractv2hi1_ze"
++ [(set (match_operand:SI 0 "register_operand" "=$d,r")
++ (zero_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " 0,r")
++ (parallel [(const_int 1)]))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "@
++ srli45\t%0, 16
++ srli\t%0, %1, 16"
++ [(set_attr "type" "alu,alu")
++ (set_attr "length" " 2, 4")])
++
++(define_insn "vec_extractv2hi1_be"
++ [(set (match_operand:HI 0 "register_operand" "=$l,r,r")
++ (vec_select:HI
++ (match_operand:V2HI 1 "nonimmediate_operand" " l,r,m")
++ (parallel [(const_int 1)])))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++{
++ switch (which_alternative)
++ {
++ case 0:
++ return "seh33\t%0, %1";
++ case 1:
++ return "seh\t%0, %1";
++ case 2:
++ return nds32_output_32bit_load_se (operands, 2);
++
++ default:
++ gcc_unreachable ();
++ }
++}
++ [(set_attr "type" "alu,alu,load")
++ (set_attr "length" " 2, 4, 4")])
++
++(define_insn "mul16"
++ [(set (match_operand:V2SI 0 "register_operand" "=r")
++ (mult:V2SI (extend:V2SI (match_operand:V2HI 1 "register_operand" "%r"))
++ (extend:V2SI (match_operand:V2HI 2 "register_operand" " r"))))]
++ "NDS32_EXT_DSP_P ()"
++ "mul16\t%0, %1, %2"
++ [(set_attr "type" "dmul")
++ (set_attr "length" "4")])
++
++(define_insn "mulx16"
++ [(set (match_operand:V2SI 0 "register_operand" "=r")
++ (vec_merge:V2SI
++ (vec_duplicate:V2SI
++ (mult:SI
++ (extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))))
++ (vec_duplicate:V2SI
++ (mult:SI
++ (extend:SI
++ (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)])))
++ (extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P ()"
++ "mulx16\t%0, %1, %2"
++ [(set_attr "type" "dmul")
++ (set_attr "length" "4")])
++
++(define_insn "rotrv2hi_1"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_select:V2HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1) (const_int 0)])))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "rotri\t%0, %1, 16"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "rotrv2hi_1_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_select:V2HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0) (const_int 1)])))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "rotri\t%0, %1, 16"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "rotrv4qi_1"
++ [(set (match_operand:V4QI 0 "register_operand" "=r")
++ (vec_select:V4QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 1) (const_int 2) (const_int 3) (const_int 0)])))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "rotri\t%0, %1, 8"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "rotrv4qi_1_be"
++ [(set (match_operand:V4QI 0 "register_operand" "=r")
++ (vec_select:V4QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 2) (const_int 1) (const_int 0) (const_int 3)])))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "rotri\t%0, %1, 8"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "rotrv4qi_2"
++ [(set (match_operand:V4QI 0 "register_operand" "=r")
++ (vec_select:V4QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 2) (const_int 3) (const_int 0) (const_int 1)])))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "rotri\t%0, %1, 16"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "rotrv4qi_2_be"
++ [(set (match_operand:V4QI 0 "register_operand" "=r")
++ (vec_select:V4QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 1) (const_int 0) (const_int 3) (const_int 2)])))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "rotri\t%0, %1, 16"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "rotrv4qi_3"
++ [(set (match_operand:V4QI 0 "register_operand" "=r")
++ (vec_select:V4QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 3) (const_int 0) (const_int 1) (const_int 2)])))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "rotri\t%0, %1, 24"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "rotrv4qi_3_be"
++ [(set (match_operand:V4QI 0 "register_operand" "=r")
++ (vec_select:V4QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 0) (const_int 3) (const_int 2) (const_int 1)])))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "rotri\t%0, %1, 24"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "v4qi_dup_10"
++ [(set (match_operand:V4QI 0 "register_operand" "=r")
++ (vec_select:V4QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 0) (const_int 1) (const_int 0) (const_int 1)])))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "pkbb\t%0, %1, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "v4qi_dup_32"
++ [(set (match_operand:V4QI 0 "register_operand" "=r")
++ (vec_select:V4QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 2) (const_int 3) (const_int 2) (const_int 3)])))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "pktt\t%0, %1, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_expand "vec_unpacks_lo_v4qi"
++ [(match_operand:V2HI 0 "register_operand" "=r")
++ (match_operand:V4QI 1 "register_operand" " r")]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++{
++ emit_insn (gen_sunpkd810 (operands[0], operands[1]));
++ DONE;
++})
++
++(define_expand "sunpkd810"
++ [(match_operand:V2HI 0 "register_operand")
++ (match_operand:V4QI 1 "register_operand")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_sunpkd810_imp_be (operands[0], operands[1]));
++ else
++ emit_insn (gen_sunpkd810_imp (operands[0], operands[1]));
++ DONE;
++})
++
++(define_insn "unpkd810_imp"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 0)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "unpkd810\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "unpkd810_imp_inv"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 1)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "unpkd810\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "unpkd810_imp_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 2)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 3)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "unpkd810\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "unpkd810_imp_inv_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 3)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 2)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "unpkd810\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_expand "sunpkd820"
++ [(match_operand:V2HI 0 "register_operand")
++ (match_operand:V4QI 1 "register_operand")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_sunpkd820_imp_be (operands[0], operands[1]));
++ else
++ emit_insn (gen_sunpkd820_imp (operands[0], operands[1]));
++ DONE;
++})
++
++(define_insn "unpkd820_imp"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 2)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 0)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "unpkd820\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "unpkd820_imp_inv"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 2)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "unpkd820\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "unpkd820_imp_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 3)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "unpkd820\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "unpkd820_imp_inv_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 3)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 1)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "unpkd820\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_expand "sunpkd830"
++ [(match_operand:V2HI 0 "register_operand")
++ (match_operand:V4QI 1 "register_operand")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_sunpkd830_imp_be (operands[0], operands[1]));
++ else
++ emit_insn (gen_sunpkd830_imp (operands[0], operands[1]));
++ DONE;
++})
++
++(define_insn "unpkd830_imp"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 3)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 0)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "unpkd830\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "unpkd830_imp_inv"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 3)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "unpkd830\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "unpkd830_imp_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 3)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "unpkd830\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "unpkd830_imp_inv_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 3)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 0)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "unpkd830\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_expand "sunpkd831"
++ [(match_operand:V2HI 0 "register_operand")
++ (match_operand:V4QI 1 "register_operand")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_sunpkd831_imp_be (operands[0], operands[1]));
++ else
++ emit_insn (gen_sunpkd831_imp (operands[0], operands[1]));
++ DONE;
++})
++
++(define_insn "unpkd831_imp"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 3)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 1)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "unpkd831\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "unpkd831_imp_inv"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 3)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "unpkd831\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "unpkd831_imp_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 2)]))))
++ (const_int 1)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "unpkd831\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "unpkd831_imp_inv_be"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 2)]))))
++ (vec_duplicate:V2HI
++ (extend:HI
++ (vec_select:QI
++ (match_dup 1)
++ (parallel [(const_int 0)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "unpkd831\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_expand "zunpkd810"
++ [(match_operand:V2HI 0 "register_operand")
++ (match_operand:V4QI 1 "register_operand")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_zunpkd810_imp_be (operands[0], operands[1]));
++ else
++ emit_insn (gen_zunpkd810_imp (operands[0], operands[1]));
++ DONE;
++})
++
++(define_expand "zunpkd820"
++ [(match_operand:V2HI 0 "register_operand")
++ (match_operand:V4QI 1 "register_operand")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_zunpkd820_imp_be (operands[0], operands[1]));
++ else
++ emit_insn (gen_zunpkd820_imp (operands[0], operands[1]));
++ DONE;
++})
++
++(define_expand "zunpkd830"
++ [(match_operand:V2HI 0 "register_operand")
++ (match_operand:V4QI 1 "register_operand")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_zunpkd830_imp_be (operands[0], operands[1]));
++ else
++ emit_insn (gen_zunpkd830_imp (operands[0], operands[1]));
++ DONE;
++})
++
++(define_expand "zunpkd831"
++ [(match_operand:V2HI 0 "register_operand")
++ (match_operand:V4QI 1 "register_operand")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_zunpkd831_imp_be (operands[0], operands[1]));
++ else
++ emit_insn (gen_zunpkd831_imp (operands[0], operands[1]));
++ DONE;
++})
++
++(define_expand "smbb"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_mulhisi3v (operands[0], operands[1], operands[2],
++ GEN_INT (1), GEN_INT (1)));
++ else
++ emit_insn (gen_mulhisi3v (operands[0], operands[1], operands[2],
++ GEN_INT (0), GEN_INT (0)));
++ DONE;
++})
++
++(define_expand "smbt"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_mulhisi3v (operands[0], operands[1], operands[2],
++ GEN_INT (1), GEN_INT (0)));
++ else
++ emit_insn (gen_mulhisi3v (operands[0], operands[1], operands[2],
++ GEN_INT (0), GEN_INT (1)));
++ DONE;
++})
++
++(define_expand "smtt"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_mulhisi3v (operands[0], operands[1], operands[2],
++ GEN_INT (0), GEN_INT (0)));
++ else
++ emit_insn (gen_mulhisi3v (operands[0], operands[1], operands[2],
++ GEN_INT (1), GEN_INT (1)));
++ DONE;
++})
++
++(define_insn "mulhisi3v"
++ [(set (match_operand:SI 0 "register_operand" "= r, r, r, r")
++ (mult:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r, r, r, r")
++ (parallel [(match_operand:SI 3 "nds32_imm_0_1_operand" " Iv00, Iv00, Iv01, Iv01")])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r, r, r, r")
++ (parallel [(match_operand:SI 4 "nds32_imm_0_1_operand" " Iv00, Iv01, Iv01, Iv00")])))))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "smtt\t%0, %1, %2",
++ "smbt\t%0, %2, %1",
++ "smbb\t%0, %1, %2",
++ "smbt\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "smbb\t%0, %1, %2",
++ "smbt\t%0, %1, %2",
++ "smtt\t%0, %1, %2",
++ "smbt\t%0, %2, %1" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dmul")
++ (set_attr "length" "4")])
++
++(define_expand "kmabb"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")
++ (match_operand:V2HI 3 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_kma_internal (operands[0], operands[2], operands[3],
++ GEN_INT (1), GEN_INT (1),
++ operands[1]));
++ else
++ emit_insn (gen_kma_internal (operands[0], operands[2], operands[3],
++ GEN_INT (0), GEN_INT (0),
++ operands[1]));
++ DONE;
++})
++
++(define_expand "kmabt"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")
++ (match_operand:V2HI 3 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_kma_internal (operands[0], operands[2], operands[3],
++ GEN_INT (1), GEN_INT (0),
++ operands[1]));
++ else
++ emit_insn (gen_kma_internal (operands[0], operands[2], operands[3],
++ GEN_INT (0), GEN_INT (1),
++ operands[1]));
++ DONE;
++})
++
++(define_expand "kmatt"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")
++ (match_operand:V2HI 3 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_kma_internal (operands[0], operands[2], operands[3],
++ GEN_INT (0), GEN_INT (0),
++ operands[1]));
++ else
++ emit_insn (gen_kma_internal (operands[0], operands[2], operands[3],
++ GEN_INT (1), GEN_INT (1),
++ operands[1]));
++ DONE;
++})
++
++(define_insn "kma_internal"
++ [(set (match_operand:SI 0 "register_operand" "= r, r, r, r")
++ (ss_plus:SI
++ (mult:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r, r, r, r")
++ (parallel [(match_operand:SI 3 "nds32_imm_0_1_operand" " Iv00, Iv00, Iv01, Iv01")])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r, r, r, r")
++ (parallel [(match_operand:SI 4 "nds32_imm_0_1_operand" " Iv00, Iv01, Iv01, Iv00")]))))
++ (match_operand:SI 5 "register_operand" " 0, 0, 0, 0")))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "kmatt\t%0, %1, %2",
++ "kmabt\t%0, %2, %1",
++ "kmabb\t%0, %1, %2",
++ "kmabt\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "kmabb\t%0, %1, %2",
++ "kmabt\t%0, %1, %2",
++ "kmatt\t%0, %1, %2",
++ "kmabt\t%0, %2, %1" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_expand "smds"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smds_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_smds_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_expand "smds_le"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))))))]
++ "NDS32_EXT_DSP_P ()"
++{
++})
++
++(define_expand "smds_be"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))))))]
++ "NDS32_EXT_DSP_P ()"
++{
++})
++
++(define_expand "smdrs"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smdrs_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_smdrs_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_expand "smdrs_le"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))))))]
++ "NDS32_EXT_DSP_P ()"
++{
++})
++
++(define_expand "smdrs_be"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))))))]
++ "NDS32_EXT_DSP_P ()"
++{
++})
++
++(define_expand "smxdsv"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:V2HI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smxdsv_be (operands[0], operands[1], operands[2]));
++ else
++ emit_insn (gen_smxdsv_le (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++
++(define_expand "smxdsv_le"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))))))]
++ "NDS32_EXT_DSP_P ()"
++{
++})
++
++(define_expand "smxdsv_be"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))))))]
++ "NDS32_EXT_DSP_P ()"
++{
++})
++
++(define_insn "smal1"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI (match_operand:DI 1 "register_operand" " r")
++ (sign_extend:DI
++ (mult:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)])))))))]
++ "NDS32_EXT_DSP_P ()"
++ "smal\t%0, %1, %2"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smal2"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI (match_operand:DI 1 "register_operand" " r")
++ (mult:DI
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:DI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))))))]
++ "NDS32_EXT_DSP_P ()"
++ "smal\t%0, %1, %2"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smal3"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI (match_operand:DI 1 "register_operand" " r")
++ (sign_extend:DI
++ (mult:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))))))]
++ "NDS32_EXT_DSP_P ()"
++ "smal\t%0, %1, %2"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smal4"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI (match_operand:DI 1 "register_operand" " r")
++ (mult:DI
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:DI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))))))]
++ "NDS32_EXT_DSP_P ()"
++ "smal\t%0, %1, %2"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smal5"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (sign_extend:DI
++ (mult:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)])))))
++ (match_operand:DI 1 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "smal\t%0, %1, %2"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smal6"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (mult:DI
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:DI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))))
++ (match_operand:DI 1 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "smal\t%0, %1, %2"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smal7"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (sign_extend:DI
++ (mult:SI
++ (sign_extend:SI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))))
++ (match_operand:DI 1 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "smal\t%0, %1, %2"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smal8"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (mult:DI
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:DI
++ (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))))
++ (match_operand:DI 1 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "smal\t%0, %1, %2"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++;; We need this dummy pattern for smal
++(define_insn_and_split "extendsidi2"
++ [(set (match_operand:DI 0 "register_operand" "")
++ (sign_extend:DI (match_operand:SI 1 "nds32_move_operand" "")))]
++ "NDS32_EXT_DSP_P ()"
++ "#"
++ "NDS32_EXT_DSP_P ()"
++ [(const_int 0)]
++{
++ rtx high_part_dst, low_part_dst;
++
++ low_part_dst = nds32_di_low_part_subreg (operands[0]);
++ high_part_dst = nds32_di_high_part_subreg (operands[0]);
++
++ emit_move_insn (low_part_dst, operands[1]);
++ emit_insn (gen_ashrsi3 (high_part_dst, low_part_dst, GEN_INT (31)));
++ DONE;
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++;; We need this dummy pattern for usmar64/usmsr64
++(define_insn_and_split "zero_extendsidi2"
++ [(set (match_operand:DI 0 "register_operand" "")
++ (zero_extend:DI (match_operand:SI 1 "nds32_move_operand" "")))]
++ "NDS32_EXT_DSP_P ()"
++ "#"
++ "NDS32_EXT_DSP_P ()"
++ [(const_int 0)]
++{
++ rtx high_part_dst, low_part_dst;
++
++ low_part_dst = nds32_di_low_part_subreg (operands[0]);
++ high_part_dst = nds32_di_high_part_subreg (operands[0]);
++
++ emit_move_insn (low_part_dst, operands[1]);
++ emit_move_insn (high_part_dst, const0_rtx);
++ DONE;
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "extendhidi2"
++ [(set (match_operand:DI 0 "register_operand" "")
++ (sign_extend:DI (match_operand:HI 1 "nonimmediate_operand" "")))]
++ "NDS32_EXT_DSP_P ()"
++ "#"
++ "NDS32_EXT_DSP_P ()"
++ [(const_int 0)]
++{
++ rtx high_part_dst, low_part_dst;
++
++ low_part_dst = nds32_di_low_part_subreg (operands[0]);
++ high_part_dst = nds32_di_high_part_subreg (operands[0]);
++
++
++ emit_insn (gen_extendhisi2 (low_part_dst, operands[1]));
++ emit_insn (gen_ashrsi3 (high_part_dst, low_part_dst, GEN_INT (31)));
++ DONE;
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_insn "extendqihi2"
++ [(set (match_operand:HI 0 "register_operand" "=r")
++ (sign_extend:HI (match_operand:QI 1 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "sunpkd820\t%0, %1"
++ [(set_attr "type" "dpack")
++ (set_attr "length" "4")])
++
++(define_insn "smulsi3_highpart"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (truncate:SI
++ (lshiftrt:DI
++ (mult:DI
++ (sign_extend:DI (match_operand:SI 1 "register_operand" " r"))
++ (sign_extend:DI (match_operand:SI 2 "register_operand" " r")))
++ (const_int 32))))]
++ "NDS32_EXT_DSP_P ()"
++ "smmul\t%0, %1, %2"
++ [(set_attr "type" "dmul")
++ (set_attr "length" "4")])
++
++(define_insn "smmul_round"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (truncate:SI
++ (lshiftrt:DI
++ (unspec:DI [(mult:DI
++ (sign_extend:DI (match_operand:SI 1 "register_operand" " r"))
++ (sign_extend:DI (match_operand:SI 2 "register_operand" " r")))]
++ UNSPEC_ROUND)
++ (const_int 32))))]
++ "NDS32_EXT_DSP_P ()"
++ "smmul.u\t%0, %1, %2"
++ [(set_attr "type" "dmul")
++ (set_attr "length" "4")])
++
++(define_insn "kmmac"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_plus:SI (match_operand:SI 1 "register_operand" " 0")
++ (truncate:SI
++ (lshiftrt:DI
++ (mult:DI
++ (sign_extend:DI (match_operand:SI 2 "register_operand" " r"))
++ (sign_extend:DI (match_operand:SI 3 "register_operand" " r")))
++ (const_int 32)))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmmac\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmmac_round"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_plus:SI (match_operand:SI 1 "register_operand" " 0")
++ (truncate:SI
++ (lshiftrt:DI
++ (unspec:DI [(mult:DI
++ (sign_extend:DI (match_operand:SI 2 "register_operand" " r"))
++ (sign_extend:DI (match_operand:SI 3 "register_operand" " r")))]
++ UNSPEC_ROUND)
++ (const_int 32)))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmmac.u\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmmsb"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_minus:SI (match_operand:SI 1 "register_operand" " 0")
++ (truncate:SI
++ (lshiftrt:DI
++ (mult:DI
++ (sign_extend:DI (match_operand:SI 2 "register_operand" " r"))
++ (sign_extend:DI (match_operand:SI 3 "register_operand" " r")))
++ (const_int 32)))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmmsb\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmmsb_round"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_minus:SI (match_operand:SI 1 "register_operand" " 0")
++ (truncate:SI
++ (lshiftrt:DI
++ (unspec:DI [(mult:DI
++ (sign_extend:DI (match_operand:SI 2 "register_operand" " r"))
++ (sign_extend:DI (match_operand:SI 3 "register_operand" " r")))]
++ UNSPEC_ROUND)
++ (const_int 32)))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmmsb.u\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kwmmul"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (truncate:SI
++ (lshiftrt:DI
++ (ss_mult:DI
++ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" " r")) (const_int 2))
++ (mult:DI (sign_extend:DI (match_operand:SI 2 "register_operand" " r")) (const_int 2)))
++ (const_int 32))))]
++ "NDS32_EXT_DSP_P ()"
++ "kwmmul\t%0, %1, %2"
++ [(set_attr "type" "dmul")
++ (set_attr "length" "4")])
++
++(define_insn "kwmmul_round"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (truncate:SI
++ (lshiftrt:DI
++ (unspec:DI [
++ (ss_mult:DI
++ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" " r")) (const_int 2))
++ (mult:DI (sign_extend:DI (match_operand:SI 2 "register_operand" " r")) (const_int 2)))]
++ UNSPEC_ROUND)
++ (const_int 32))))]
++ "NDS32_EXT_DSP_P ()"
++ "kwmmul.u\t%0, %1, %2"
++ [(set_attr "type" "dmul")
++ (set_attr "length" "4")])
++
++(define_expand "smmwb"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smulhisi3_highpart_1 (operands[0], operands[1], operands[2], GEN_INT (1)));
++ else
++ emit_insn (gen_smulhisi3_highpart_1 (operands[0], operands[1], operands[2], GEN_INT (0)));
++ DONE;
++})
++
++(define_expand "smmwt"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smulhisi3_highpart_1 (operands[0], operands[1], operands[2], GEN_INT (0)));
++ else
++ emit_insn (gen_smulhisi3_highpart_1 (operands[0], operands[1], operands[2], GEN_INT (1)));
++ DONE;
++})
++
++(define_insn "smulhisi3_highpart_1"
++ [(set (match_operand:SI 0 "register_operand" "= r, r")
++ (truncate:SI
++ (lshiftrt:DI
++ (mult:DI
++ (sign_extend:DI (match_operand:SI 1 "register_operand" " r, r"))
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r, r")
++ (parallel [(match_operand:SI 3 "nds32_imm_0_1_operand" " Iv00, Iv01")]))))
++ (const_int 16))))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "smmwt\t%0, %1, %2",
++ "smmwb\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "smmwb\t%0, %1, %2",
++ "smmwt\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dmul")
++ (set_attr "length" "4")])
++
++(define_insn "smulhisi3_highpart_2"
++ [(set (match_operand:SI 0 "register_operand" "= r, r")
++ (truncate:SI
++ (lshiftrt:DI
++ (mult:DI
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r, r")
++ (parallel [(match_operand:SI 3 "nds32_imm_0_1_operand" " Iv00, Iv01")])))
++ (sign_extend:DI (match_operand:SI 2 "register_operand" " r, r")))
++ (const_int 16))))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "smmwt\t%0, %1, %2",
++ "smmwb\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "smmwb\t%0, %1, %2",
++ "smmwt\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dmul")
++ (set_attr "length" "4")])
++
++(define_expand "smmwb_round"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smmw_round_internal (operands[0], operands[1], operands[2], GEN_INT (1)));
++ else
++ emit_insn (gen_smmw_round_internal (operands[0], operands[1], operands[2], GEN_INT (0)));
++ DONE;
++})
++
++(define_expand "smmwt_round"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smmw_round_internal (operands[0], operands[1], operands[2], GEN_INT (0)));
++ else
++ emit_insn (gen_smmw_round_internal (operands[0], operands[1], operands[2], GEN_INT (1)));
++ DONE;
++})
++
++(define_insn "smmw_round_internal"
++ [(set (match_operand:SI 0 "register_operand" "= r, r")
++ (truncate:SI
++ (lshiftrt:DI
++ (unspec:DI
++ [(mult:DI
++ (sign_extend:DI (match_operand:SI 1 "register_operand" " r, r"))
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r, r")
++ (parallel [(match_operand:SI 3 "nds32_imm_0_1_operand" " Iv00, Iv01")]))))]
++ UNSPEC_ROUND)
++ (const_int 16))))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "smmwt.u\t%0, %1, %2",
++ "smmwb.u\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "smmwb.u\t%0, %1, %2",
++ "smmwt.u\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dmul")
++ (set_attr "length" "4")])
++
++(define_expand "kmmawb"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:SI 2 "register_operand" "")
++ (match_operand:V2HI 3 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_kmmaw_internal (operands[0], operands[2], operands[3], GEN_INT (1), operands[1]));
++ else
++ emit_insn (gen_kmmaw_internal (operands[0], operands[2], operands[3], GEN_INT (0), operands[1]));
++ DONE;
++})
++
++(define_expand "kmmawt"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:SI 2 "register_operand" "")
++ (match_operand:V2HI 3 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_kmmaw_internal (operands[0], operands[2], operands[3], GEN_INT (0), operands[1]));
++ else
++ emit_insn (gen_kmmaw_internal (operands[0], operands[2], operands[3], GEN_INT (1), operands[1]));
++ DONE;
++})
++
++(define_insn "kmmaw_internal"
++ [(set (match_operand:SI 0 "register_operand" "= r, r")
++ (ss_plus:SI
++ (match_operand:SI 4 "register_operand" " 0, 0")
++ (truncate:SI
++ (lshiftrt:DI
++ (mult:DI
++ (sign_extend:DI (match_operand:SI 1 "register_operand" " r, r"))
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r, r")
++ (parallel [(match_operand:SI 3 "nds32_imm_0_1_operand" " Iv00, Iv01")]))))
++ (const_int 16)))))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "kmmawt\t%0, %1, %2",
++ "kmmawb\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "kmmawb\t%0, %1, %2",
++ "kmmawt\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_expand "kmmawb_round"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:SI 2 "register_operand" "")
++ (match_operand:V2HI 3 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_kmmaw_round_internal (operands[0], operands[2], operands[3], GEN_INT (1), operands[1]));
++ else
++ emit_insn (gen_kmmaw_round_internal (operands[0], operands[2], operands[3], GEN_INT (0), operands[1]));
++ DONE;
++}
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")])
++
++(define_expand "kmmawt_round"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:SI 2 "register_operand" "")
++ (match_operand:V2HI 3 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_kmmaw_round_internal (operands[0], operands[2], operands[3], GEN_INT (0), operands[1]));
++ else
++ emit_insn (gen_kmmaw_round_internal (operands[0], operands[2], operands[3], GEN_INT (1), operands[1]));
++ DONE;
++}
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++
++(define_insn "kmmaw_round_internal"
++ [(set (match_operand:SI 0 "register_operand" "= r, r")
++ (ss_plus:SI
++ (match_operand:SI 4 "register_operand" " 0, 0")
++ (truncate:SI
++ (lshiftrt:DI
++ (unspec:DI
++ [(mult:DI
++ (sign_extend:DI (match_operand:SI 1 "register_operand" " r, r"))
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r, r")
++ (parallel [(match_operand:SI 3 "nds32_imm_0_1_operand" " Iv00, Iv01")]))))]
++ UNSPEC_ROUND)
++ (const_int 16)))))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "kmmawt.u\t%0, %1, %2",
++ "kmmawb.u\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "kmmawb.u\t%0, %1, %2",
++ "kmmawt.u\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_expand "smalbb"
++ [(match_operand:DI 0 "register_operand" "")
++ (match_operand:DI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")
++ (match_operand:V2HI 3 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smaddhidi (operands[0], operands[2],
++ operands[3], operands[1],
++ GEN_INT (1), GEN_INT (1)));
++ else
++ emit_insn (gen_smaddhidi (operands[0], operands[2],
++ operands[3], operands[1],
++ GEN_INT (0), GEN_INT (0)));
++ DONE;
++})
++
++(define_expand "smalbt"
++ [(match_operand:DI 0 "register_operand" "")
++ (match_operand:DI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")
++ (match_operand:V2HI 3 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smaddhidi (operands[0], operands[2],
++ operands[3], operands[1],
++ GEN_INT (1), GEN_INT (0)));
++ else
++ emit_insn (gen_smaddhidi (operands[0], operands[2],
++ operands[3], operands[1],
++ GEN_INT (0), GEN_INT (1)));
++ DONE;
++})
++
++(define_expand "smaltt"
++ [(match_operand:DI 0 "register_operand" "")
++ (match_operand:DI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" "")
++ (match_operand:V2HI 3 "register_operand" "")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smaddhidi (operands[0], operands[2],
++ operands[3], operands[1],
++ GEN_INT (0), GEN_INT (0)));
++ else
++ emit_insn (gen_smaddhidi (operands[0], operands[2],
++ operands[3], operands[1],
++ GEN_INT (1), GEN_INT (1)));
++ DONE;
++})
++
++(define_insn "smaddhidi"
++ [(set (match_operand:DI 0 "register_operand" "= r, r, r, r")
++ (plus:DI
++ (match_operand:DI 3 "register_operand" " 0, 0, 0, 0")
++ (mult:DI
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r, r, r, r")
++ (parallel [(match_operand:SI 4 "nds32_imm_0_1_operand" " Iv00, Iv00, Iv01, Iv01")])))
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r, r, r, r")
++ (parallel [(match_operand:SI 5 "nds32_imm_0_1_operand" " Iv00, Iv01, Iv01, Iv00")]))))))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "smaltt\t%0, %1, %2",
++ "smalbt\t%0, %2, %1",
++ "smalbb\t%0, %1, %2",
++ "smalbt\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "smalbb\t%0, %1, %2",
++ "smalbt\t%0, %1, %2",
++ "smaltt\t%0, %1, %2",
++ "smalbt\t%0, %2, %1" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smaddhidi2"
++ [(set (match_operand:DI 0 "register_operand" "= r, r, r, r")
++ (plus:DI
++ (mult:DI
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r, r, r, r")
++ (parallel [(match_operand:SI 4 "nds32_imm_0_1_operand" " Iv00, Iv00, Iv01, Iv01")])))
++ (sign_extend:DI
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r, r, r, r")
++ (parallel [(match_operand:SI 5 "nds32_imm_0_1_operand" " Iv00, Iv01, Iv01, Iv00")]))))
++ (match_operand:DI 3 "register_operand" " 0, 0, 0, 0")))]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ {
++ const char *pats[] = { "smaltt\t%0, %1, %2",
++ "smalbt\t%0, %2, %1",
++ "smalbb\t%0, %1, %2",
++ "smalbt\t%0, %1, %2" };
++ return pats[which_alternative];
++ }
++ else
++ {
++ const char *pats[] = { "smalbb\t%0, %1, %2",
++ "smalbt\t%0, %1, %2",
++ "smaltt\t%0, %1, %2",
++ "smalbt\t%0, %2, %1" };
++ return pats[which_alternative];
++ }
++}
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_expand "smalda1"
++ [(match_operand:DI 0 "register_operand" "")
++ (match_operand:DI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" " r")
++ (match_operand:V2HI 3 "register_operand" " r")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smalda1_be (operands[0], operands[1], operands[2], operands[3]));
++ else
++ emit_insn (gen_smalda1_le (operands[0], operands[1], operands[2], operands[3]));
++ DONE;
++})
++
++(define_expand "smalds1"
++ [(match_operand:DI 0 "register_operand" "")
++ (match_operand:DI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" " r")
++ (match_operand:V2HI 3 "register_operand" " r")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smalds1_be (operands[0], operands[1], operands[2], operands[3]));
++ else
++ emit_insn (gen_smalds1_le (operands[0], operands[1], operands[2], operands[3]));
++ DONE;
++})
++
++(define_insn "smalda1_le"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (sign_extend:DI
++ (plus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 0)]))))))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "smalda\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smalds1_le"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (sign_extend:DI
++ (minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 0)]))))))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "smalds\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smalda1_be"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (sign_extend:DI
++ (plus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 1)]))))))))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "smalda\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smalds1_be"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (sign_extend:DI
++ (minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 1)]))))))))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "smalds\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_expand "smaldrs3"
++ [(match_operand:DI 0 "register_operand" "")
++ (match_operand:DI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" " r")
++ (match_operand:V2HI 3 "register_operand" " r")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smaldrs3_be (operands[0], operands[1], operands[2], operands[3]));
++ else
++ emit_insn (gen_smaldrs3_le (operands[0], operands[1], operands[2], operands[3]));
++ DONE;
++})
++
++(define_insn "smaldrs3_le"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (sign_extend:DI
++ (minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 1)]))))))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "smaldrs\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smaldrs3_be"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (sign_extend:DI
++ (minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 0)]))))))))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "smaldrs\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_expand "smalxda1"
++ [(match_operand:DI 0 "register_operand" "")
++ (match_operand:DI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" " r")
++ (match_operand:V2HI 3 "register_operand" " r")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smalxda1_be (operands[0], operands[1], operands[2], operands[3]));
++ else
++ emit_insn (gen_smalxda1_le (operands[0], operands[1], operands[2], operands[3]));
++ DONE;
++})
++
++(define_expand "smalxds1"
++ [(match_operand:DI 0 "register_operand" "")
++ (match_operand:DI 1 "register_operand" "")
++ (match_operand:V2HI 2 "register_operand" " r")
++ (match_operand:V2HI 3 "register_operand" " r")]
++ "NDS32_EXT_DSP_P ()"
++{
++ if (TARGET_BIG_ENDIAN)
++ emit_insn (gen_smalxds1_be (operands[0], operands[1], operands[2], operands[3]));
++ else
++ emit_insn (gen_smalxds1_le (operands[0], operands[1], operands[2], operands[3]));
++ DONE;
++})
++
++(define_insn "smalxd1_le"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (sign_extend:DI
++ (plus_minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 1)]))))))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "smalxd\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++
++(define_insn "smalxd1_be"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (sign_extend:DI
++ (plus_minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 0)]))))))))]
++ "NDS32_EXT_DSP_P () && TARGET_BIG_ENDIAN"
++ "smalxd\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smslda1"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (minus:DI
++ (minus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (sign_extend:DI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 1)]))))))
++ (sign_extend:DI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 0)])))))))]
++ "NDS32_EXT_DSP_P ()"
++ "smslda\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "smslxda1"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (minus:DI
++ (minus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (sign_extend:DI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 0)]))))))
++ (sign_extend:DI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 1)])))))))]
++ "NDS32_EXT_DSP_P ()"
++ "smslxda\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++;; mada for synthetize smalda
++(define_insn_and_split "mada1"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (plus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" "r")
++ (parallel [(match_operand:SI 3 "nds32_imm_0_1_operand" " Iu01")])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" "r")
++ (parallel [(match_operand:SI 4 "nds32_imm_0_1_operand" " Iu01")]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 1)
++ (parallel [(match_operand:SI 5 "nds32_imm_0_1_operand" " Iu01")])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(match_operand:SI 6 "nds32_imm_0_1_operand" " Iu01")]))))))]
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 1)]
++{
++ rtx result0 = gen_reg_rtx (SImode);
++ rtx result1 = gen_reg_rtx (SImode);
++ emit_insn (gen_mulhisi3v (result0, operands[1], operands[2],
++ operands[3], operands[4]));
++ emit_insn (gen_mulhisi3v (result1, operands[1], operands[2],
++ operands[5], operands[6]));
++ emit_insn (gen_addsi3 (operands[0], result0, result1));
++ DONE;
++})
++
++(define_insn_and_split "mada2"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (plus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" "r")
++ (parallel [(match_operand:SI 3 "nds32_imm_0_1_operand" " Iu01")])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" "r")
++ (parallel [(match_operand:SI 4 "nds32_imm_0_1_operand" " Iu01")]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(match_operand:SI 5 "nds32_imm_0_1_operand" " Iu01")])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 1)
++ (parallel [(match_operand:SI 6 "nds32_imm_0_1_operand" " Iu01")]))))))]
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 1)]
++{
++ rtx result0 = gen_reg_rtx (SImode);
++ rtx result1 = gen_reg_rtx (SImode);
++ emit_insn (gen_mulhisi3v (result0, operands[1], operands[2],
++ operands[3], operands[4]));
++ emit_insn (gen_mulhisi3v (result1, operands[1], operands[2],
++ operands[6], operands[5]));
++ emit_insn (gen_addsi3 (operands[0], result0, result1));
++ DONE;
++})
++
++;; sms for synthetize smalds
++(define_insn_and_split "sms1"
++ [(set (match_operand:SI 0 "register_operand" "= r")
++ (minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(match_operand:SI 3 "nds32_imm_0_1_operand" " Iu01")])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(match_operand:SI 4 "nds32_imm_0_1_operand" " Iu01")]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 1)
++ (parallel [(match_operand:SI 5 "nds32_imm_0_1_operand" " Iu01")])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(match_operand:SI 6 "nds32_imm_0_1_operand" " Iu01")]))))))]
++ "NDS32_EXT_DSP_P ()
++ && (!reload_completed
++ || !nds32_need_split_sms_p (operands[3], operands[4],
++ operands[5], operands[6]))"
++
++{
++ return nds32_output_sms (operands[3], operands[4],
++ operands[5], operands[6]);
++}
++ "NDS32_EXT_DSP_P ()
++ && !reload_completed
++ && nds32_need_split_sms_p (operands[3], operands[4],
++ operands[5], operands[6])"
++ [(const_int 1)]
++{
++ nds32_split_sms (operands[0], operands[1], operands[2],
++ operands[3], operands[4],
++ operands[5], operands[6]);
++ DONE;
++}
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "sms2"
++ [(set (match_operand:SI 0 "register_operand" "= r")
++ (minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(match_operand:SI 3 "nds32_imm_0_1_operand" " Iu01")])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(match_operand:SI 4 "nds32_imm_0_1_operand" " Iu01")]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(match_operand:SI 5 "nds32_imm_0_1_operand" " Iu01")])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 1)
++ (parallel [(match_operand:SI 6 "nds32_imm_0_1_operand" " Iu01")]))))))]
++ "NDS32_EXT_DSP_P ()
++ && (!reload_completed
++ || !nds32_need_split_sms_p (operands[3], operands[4],
++ operands[6], operands[5]))"
++{
++ return nds32_output_sms (operands[3], operands[4],
++ operands[6], operands[5]);
++}
++ "NDS32_EXT_DSP_P ()
++ && !reload_completed
++ && nds32_need_split_sms_p (operands[3], operands[4],
++ operands[6], operands[5])"
++ [(const_int 1)]
++{
++ nds32_split_sms (operands[0], operands[1], operands[2],
++ operands[3], operands[4],
++ operands[6], operands[5]);
++ DONE;
++}
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmda"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_plus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" "r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" "r")
++ (parallel [(const_int 1)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)]))))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmda\t%0, %1, %2"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmxda"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_plus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" "r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" "r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 1)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)]))))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmxda\t%0, %1, %2"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmada"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_plus:SI
++ (match_operand:SI 1 "register_operand" " 0")
++ (ss_plus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 0)])))))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmada\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmada2"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_plus:SI
++ (match_operand:SI 1 "register_operand" " 0")
++ (ss_plus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 1)])))))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmada\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmaxda"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_plus:SI
++ (match_operand:SI 1 "register_operand" " 0")
++ (ss_plus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 1)])))))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmaxda\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmads"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_plus:SI
++ (match_operand:SI 1 "register_operand" " 0")
++ (ss_minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 0)])))))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmads\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmadrs"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_plus:SI
++ (match_operand:SI 1 "register_operand" " 0")
++ (ss_minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 1)])))))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmadrs\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmaxds"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_plus:SI
++ (match_operand:SI 1 "register_operand" " 0")
++ (ss_minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 1)])))))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmaxds\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmsda"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_minus:SI
++ (match_operand:SI 1 "register_operand" " 0")
++ (ss_minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 0)])))))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmsda\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmsxda"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_minus:SI
++ (match_operand:SI 1 "register_operand" " 0")
++ (ss_minus:SI
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)])))
++ (sign_extend:SI (vec_select:HI
++ (match_operand:V2HI 3 "register_operand" " r")
++ (parallel [(const_int 0)]))))
++ (mult:SI
++ (sign_extend:SI (vec_select:HI
++ (match_dup 2)
++ (parallel [(const_int 0)])))
++ (sign_extend:SI (vec_select:HI
++ (match_dup 3)
++ (parallel [(const_int 1)])))))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmsxda\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++;; smax[8|16] and umax[8|16]
++(define_insn "3"
++ [(set (match_operand:VQIHI 0 "register_operand" "=r")
++ (sumax:VQIHI (match_operand:VQIHI 1 "register_operand" " r")
++ (match_operand:VQIHI 2 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++;; smin[8|16] and umin[8|16]
++(define_insn "3"
++ [(set (match_operand:VQIHI 0 "register_operand" "=r")
++ (sumin:VQIHI (match_operand:VQIHI 1 "register_operand" " r")
++ (match_operand:VQIHI 2 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_insn "3_bb"
++ [(set (match_operand: 0 "register_operand" "=r")
++ (sumin_max: (vec_select:
++ (match_operand:VQIHI 1 "register_operand" " r")
++ (parallel [(const_int 0)]))
++ (vec_select:
++ (match_operand:VQIHI 2 "register_operand" " r")
++ (parallel [(const_int 0)]))))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "3_tt"
++ [(set (match_operand: 0 "register_operand" "=r")
++ (sumin_max: (vec_select:
++ (match_operand:VQIHI 1 "register_operand" " r")
++ (parallel [(const_int 1)]))
++ (vec_select:
++ (match_operand:VQIHI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))]
++ "NDS32_EXT_DSP_P () && !reload_completed && !TARGET_BIG_ENDIAN"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 0)]
++{
++ rtx tmp = gen_reg_rtx (mode);
++ emit_insn (gen_3 (tmp, operands[1], operands[2]));
++ emit_insn (gen_rotr_1 (tmp, tmp));
++ emit_move_insn (operands[0], simplify_gen_subreg (mode, tmp, mode, 0));
++ DONE;
++}
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "v4qi3_22"
++ [(set (match_operand:QI 0 "register_operand" "=r")
++ (sumin_max:QI (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 2)]))
++ (vec_select:QI
++ (match_operand:V4QI 2 "register_operand" " r")
++ (parallel [(const_int 2)]))))]
++ "NDS32_EXT_DSP_P () && !reload_completed && !TARGET_BIG_ENDIAN"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 0)]
++{
++ rtx tmp = gen_reg_rtx (V4QImode);
++ emit_insn (gen_v4qi3 (tmp, operands[1], operands[2]));
++ emit_insn (gen_rotrv4qi_2 (tmp, tmp));
++ emit_move_insn (operands[0], simplify_gen_subreg (QImode, tmp, V4QImode, 0));
++ DONE;
++}
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "v4qi3_33"
++ [(set (match_operand:QI 0 "register_operand" "=r")
++ (sumin_max:QI (vec_select:QI
++ (match_operand:V4QI 1 "register_operand" " r")
++ (parallel [(const_int 3)]))
++ (vec_select:QI
++ (match_operand:V4QI 2 "register_operand" " r")
++ (parallel [(const_int 3)]))))]
++ "NDS32_EXT_DSP_P () && !reload_completed && !TARGET_BIG_ENDIAN"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 0)]
++{
++ rtx tmp = gen_reg_rtx (V4QImode);
++ emit_insn (gen_v4qi3 (tmp, operands[1], operands[2]));
++ emit_insn (gen_rotrv4qi_3 (tmp, tmp));
++ emit_move_insn (operands[0], simplify_gen_subreg (QImode, tmp, V4QImode, 0));
++ DONE;
++}
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "v2hi3_bbtt"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (vec_merge:V2HI
++ (vec_duplicate:V2HI
++ (sumin_max:HI (vec_select:HI
++ (match_operand:V2HI 1 "register_operand" " r")
++ (parallel [(const_int 1)]))
++ (vec_select:HI
++ (match_operand:V2HI 2 "register_operand" " r")
++ (parallel [(const_int 1)]))))
++ (vec_duplicate:V2HI
++ (sumin_max:HI (vec_select:HI
++ (match_dup:V2HI 1)
++ (parallel [(const_int 0)]))
++ (vec_select:HI
++ (match_dup:HI 2)
++ (parallel [(const_int 0)]))))
++ (const_int 2)))]
++ "NDS32_EXT_DSP_P () && !TARGET_BIG_ENDIAN"
++ "#"
++ "NDS32_EXT_DSP_P ()"
++ [(const_int 0)]
++{
++ emit_insn (gen_v2hi3 (operands[0], operands[1], operands[2]));
++ DONE;
++}
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_expand "abs2"
++ [(set (match_operand:VQIHI 0 "register_operand" "=r")
++ (ss_abs:VQIHI (match_operand:VQIHI 1 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P () && TARGET_HW_ABS && !flag_wrapv"
++{
++})
++
++(define_insn "kabs2"
++ [(set (match_operand:VQIHI 0 "register_operand" "=r")
++ (ss_abs:VQIHI (match_operand:VQIHI 1 "register_operand" " r")))]
++ "NDS32_EXT_DSP_P ()"
++ "kabs\t%0, %1"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_insn "mar64_1"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (mult:DI
++ (extend:DI
++ (match_operand:SI 2 "register_operand" " r"))
++ (extend:DI
++ (match_operand:SI 3 "register_operand" " r")))))]
++ "NDS32_EXT_DSP_P ()"
++ "mar64\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "mar64_2"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (mult:DI
++ (extend:DI
++ (match_operand:SI 2 "register_operand" " r"))
++ (extend:DI
++ (match_operand:SI 3 "register_operand" " r")))
++ (match_operand:DI 1 "register_operand" " 0")))]
++ "NDS32_EXT_DSP_P ()"
++ "mar64\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "mar64_3"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (extend:DI
++ (mult:SI
++ (match_operand:SI 2 "register_operand" " r")
++ (match_operand:SI 3 "register_operand" " r")))))]
++ "NDS32_EXT_DSP_P ()"
++ "mar64\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "mar64_4"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI
++ (extend:DI
++ (mult:SI
++ (match_operand:SI 2 "register_operand" " r")
++ (match_operand:SI 3 "register_operand" " r")))
++ (match_operand:DI 1 "register_operand" " 0")))]
++ "NDS32_EXT_DSP_P ()"
++ "mar64\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "msr64"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (minus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (mult:DI
++ (extend:DI
++ (match_operand:SI 2 "register_operand" " r"))
++ (extend:DI
++ (match_operand:SI 3 "register_operand" " r")))))]
++ "NDS32_EXT_DSP_P ()"
++ "msr64\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "msr64_2"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (minus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (extend:DI
++ (mult:SI
++ (match_operand:SI 2 "register_operand" " r")
++ (match_operand:SI 3 "register_operand" " r")))))]
++ "NDS32_EXT_DSP_P ()"
++ "msr64\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++;; kmar64, kmsr64, ukmar64 and ukmsr64
++(define_insn "kmar64_1"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (ss_plus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (mult:DI
++ (sign_extend:DI
++ (match_operand:SI 2 "register_operand" " r"))
++ (sign_extend:DI
++ (match_operand:SI 3 "register_operand" " r")))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmar64\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmar64_2"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (ss_plus:DI
++ (mult:DI
++ (sign_extend:DI
++ (match_operand:SI 2 "register_operand" " r"))
++ (sign_extend:DI
++ (match_operand:SI 3 "register_operand" " r")))
++ (match_operand:DI 1 "register_operand" " 0")))]
++ "NDS32_EXT_DSP_P ()"
++ "kmar64\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "kmsr64"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (ss_minus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (mult:DI
++ (sign_extend:DI
++ (match_operand:SI 2 "register_operand" " r"))
++ (sign_extend:DI
++ (match_operand:SI 3 "register_operand" " r")))))]
++ "NDS32_EXT_DSP_P ()"
++ "kmsr64\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "ukmar64_1"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (us_plus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (mult:DI
++ (zero_extend:DI
++ (match_operand:SI 2 "register_operand" " r"))
++ (zero_extend:DI
++ (match_operand:SI 3 "register_operand" " r")))))]
++ "NDS32_EXT_DSP_P ()"
++ "ukmar64\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "ukmar64_2"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (us_plus:DI
++ (mult:DI
++ (zero_extend:DI
++ (match_operand:SI 2 "register_operand" " r"))
++ (zero_extend:DI
++ (match_operand:SI 3 "register_operand" " r")))
++ (match_operand:DI 1 "register_operand" " 0")))]
++ "NDS32_EXT_DSP_P ()"
++ "ukmar64\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "ukmsr64"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (us_minus:DI
++ (match_operand:DI 1 "register_operand" " 0")
++ (mult:DI
++ (zero_extend:DI
++ (match_operand:SI 2 "register_operand" " r"))
++ (zero_extend:DI
++ (match_operand:SI 3 "register_operand" " r")))))]
++ "NDS32_EXT_DSP_P ()"
++ "ukmsr64\t%0, %2, %3"
++ [(set_attr "type" "dmac")
++ (set_attr "length" "4")])
++
++(define_insn "bpick1"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI
++ (and:SI
++ (match_operand:SI 1 "register_operand" " r")
++ (match_operand:SI 3 "register_operand" " r"))
++ (and:SI
++ (match_operand:SI 2 "register_operand" " r")
++ (not:SI (match_dup 3)))))]
++ "NDS32_EXT_DSP_P ()"
++ "bpick\t%0, %1, %2, %3"
++ [(set_attr "type" "dbpick")
++ (set_attr "length" "4")])
++
++(define_insn "bpick2"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI
++ (and:SI
++ (match_operand:SI 1 "register_operand" " r")
++ (match_operand:SI 2 "register_operand" " r"))
++ (and:SI
++ (not:SI (match_dup 2))
++ (match_operand:SI 3 "register_operand" " r"))))]
++ "NDS32_EXT_DSP_P ()"
++ "bpick\t%0, %1, %3, %2"
++ [(set_attr "type" "dbpick")
++ (set_attr "length" "4")])
++
++(define_insn "bpick3"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI
++ (and:SI
++ (match_operand:SI 1 "register_operand" " r")
++ (match_operand:SI 2 "register_operand" " r"))
++ (and:SI
++ (match_operand:SI 3 "register_operand" " r")
++ (not:SI (match_dup 1)))))]
++ "NDS32_EXT_DSP_P ()"
++ "bpick\t%0, %2, %3, %1"
++ [(set_attr "type" "dbpick")
++ (set_attr "length" "4")])
++
++(define_insn "bpick4"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI
++ (and:SI
++ (match_operand:SI 1 "register_operand" " r")
++ (match_operand:SI 2 "register_operand" " r"))
++ (and:SI
++ (not:SI (match_dup 1))
++ (match_operand:SI 3 "register_operand" " r"))))]
++ "NDS32_EXT_DSP_P ()"
++ "bpick\t%0, %2, %3, %1"
++ [(set_attr "type" "dbpick")
++ (set_attr "length" "4")])
++
++(define_insn "bpick5"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI
++ (and:SI
++ (match_operand:SI 1 "register_operand" " r")
++ (not:SI (match_operand:SI 2 "register_operand" " r")))
++ (and:SI
++ (match_operand:SI 3 "register_operand" " r")
++ (match_dup 2))))]
++ "NDS32_EXT_DSP_P ()"
++ "bpick\t%0, %3, %1, %2"
++ [(set_attr "type" "dbpick")
++ (set_attr "length" "4")])
++
++(define_insn "bpick6"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI
++ (and:SI
++ (not:SI (match_operand:SI 1 "register_operand" " r"))
++ (match_operand:SI 2 "register_operand" " r"))
++ (and:SI
++ (match_operand:SI 3 "register_operand" " r")
++ (match_dup 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "bpick\t%0, %3, %2, %1"
++ [(set_attr "type" "dbpick")
++ (set_attr "length" "4")])
++
++(define_insn "bpick7"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI
++ (and:SI
++ (match_operand:SI 1 "register_operand" " r")
++ (not:SI (match_operand:SI 2 "register_operand" " r")))
++ (and:SI
++ (match_dup 2)
++ (match_operand:SI 3 "register_operand" " r"))))]
++ "NDS32_EXT_DSP_P ()"
++ "bpick\t%0, %3, %1, %2"
++ [(set_attr "type" "dbpick")
++ (set_attr "length" "4")])
++
++(define_insn "bpick8"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ior:SI
++ (and:SI
++ (not:SI (match_operand:SI 1 "register_operand" " r"))
++ (match_operand:SI 2 "register_operand" " r"))
++ (and:SI
++ (match_dup 1)
++ (match_operand:SI 3 "register_operand" " r"))))]
++ "NDS32_EXT_DSP_P ()"
++ "bpick\t%0, %3, %2, %1"
++ [(set_attr "type" "dbpick")
++ (set_attr "length" "4")])
++
++(define_insn "sraiu"
++ [(set (match_operand:SI 0 "register_operand" "= r, r")
++ (unspec:SI [(ashiftrt:SI (match_operand:SI 1 "register_operand" " r, r")
++ (match_operand:SI 2 "nds32_rimm5u_operand" " Iu05, r"))]
++ UNSPEC_ROUND))]
++ "NDS32_EXT_DSP_P ()"
++ "@
++ srai.u\t%0, %1, %2
++ sra.u\t%0, %1, %2"
++ [(set_attr "type" "daluround")
++ (set_attr "length" "4")])
++
++(define_insn "kssl"
++ [(set (match_operand:SI 0 "register_operand" "= r, r")
++ (ss_ashift:SI (match_operand:SI 1 "register_operand" " r, r")
++ (match_operand:SI 2 "nds32_rimm5u_operand" " Iu05, r")))]
++ "NDS32_EXT_DSP_P ()"
++ "@
++ kslli\t%0, %1, %2
++ ksll\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++(define_insn "kslraw_round"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (if_then_else:SI
++ (lt:SI (match_operand:SI 2 "register_operand" " r")
++ (const_int 0))
++ (unspec:SI [(ashiftrt:SI (match_operand:SI 1 "register_operand" " r")
++ (neg:SI (match_dup 2)))]
++ UNSPEC_ROUND)
++ (ss_ashift:SI (match_dup 1)
++ (match_dup 2))))]
++ "NDS32_EXT_DSP_P ()"
++ "kslraw.u\t%0, %1, %2"
++ [(set_attr "type" "daluround")
++ (set_attr "length" "4")])
++
++(define_insn_and_split "di3"
++ [(set (match_operand:DI 0 "register_operand" "")
++ (shift_rotate:DI (match_operand:DI 1 "register_operand" "")
++ (match_operand:SI 2 "nds32_rimm6u_operand" "")))]
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ "#"
++ "NDS32_EXT_DSP_P () && !reload_completed"
++ [(const_int 0)]
++{
++ if (REGNO (operands[0]) == REGNO (operands[1]))
++ {
++ rtx tmp = gen_reg_rtx (DImode);
++ nds32_split_di3 (tmp, operands[1], operands[2]);
++ emit_move_insn (operands[0], tmp);
++ }
++ else
++ nds32_split_di3 (operands[0], operands[1], operands[2]);
++ DONE;
++})
++
++(define_insn "sclip32"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "immediate_operand" "i")] UNSPEC_CLIPS_OV))]
++ "NDS32_EXT_DSP_P ()"
++ "sclip32\t%0, %1, %2"
++ [(set_attr "type" "dclip")
++ (set_attr "length" "4")]
++)
++
++(define_insn "uclip32"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "immediate_operand" "i")] UNSPEC_CLIP_OV))]
++ "NDS32_EXT_DSP_P ()"
++ "uclip32\t%0, %1, %2"
++ [(set_attr "type" "dclip")
++ (set_attr "length" "4")]
++)
++
++(define_insn "bitrev"
++ [(set (match_operand:SI 0 "register_operand" "=r, r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" " r, r")
++ (match_operand:SI 2 "nds32_rimm5u_operand" " r, Iu05")]
++ UNSPEC_BITREV))]
++ ""
++ "@
++ bitrev\t%0, %1, %2
++ bitrevi\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")]
++)
++
++;; wext, wexti
++(define_insn "wext"
++ [(set (match_operand:SI 0 "register_operand" "=r, r")
++ (truncate:SI
++ (shiftrt:DI
++ (match_operand:DI 1 "register_operand" " r, r")
++ (match_operand:SI 2 "nds32_rimm5u_operand" " r,Iu05"))))]
++ "NDS32_EXT_DSP_P ()"
++ "@
++ wext\t%0, %1, %2
++ wexti\t%0, %1, %2"
++ [(set_attr "type" "dwext")
++ (set_attr "length" "4")])
++
++;; 32-bit add/sub instruction: raddw and rsubw.
++(define_insn "rsi3"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (truncate:SI
++ (ashiftrt:DI
++ (plus_minus:DI
++ (sign_extend:DI (match_operand:SI 1 "register_operand" " r"))
++ (sign_extend:DI (match_operand:SI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "rw\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
++
++;; 32-bit add/sub instruction: uraddw and ursubw.
++(define_insn "ursi3"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (truncate:SI
++ (lshiftrt:DI
++ (plus_minus:DI
++ (zero_extend:DI (match_operand:SI 1 "register_operand" " r"))
++ (zero_extend:DI (match_operand:SI 2 "register_operand" " r")))
++ (const_int 1))))]
++ "NDS32_EXT_DSP_P ()"
++ "urw\t%0, %1, %2"
++ [(set_attr "type" "dalu")
++ (set_attr "length" "4")])
+diff --git a/gcc/config/nds32/nds32-e8.md b/gcc/config/nds32/nds32-e8.md
+new file mode 100644
+index 0000000..1f24b5c
+--- /dev/null
++++ b/gcc/config/nds32/nds32-e8.md
+@@ -0,0 +1,329 @@
++;; Pipeline descriptions of Andes NDS32 cpu for GNU compiler
++;; Copyright (C) 2012-2016 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 E8 pipeline settings.
++;; ------------------------------------------------------------------------
++
++(define_automaton "nds32_e8_machine")
++
++;; ------------------------------------------------------------------------
++;; Pipeline Stages
++;; ------------------------------------------------------------------------
++;; IF - Instruction Fetch
++;; II - Instruction Issue / Address Generation
++;; EX - Instruction Execution
++;; EXD - Psuedo Stage / Load Data Completion
++
++(define_cpu_unit "e8_ii" "nds32_e8_machine")
++(define_cpu_unit "e8_ex" "nds32_e8_machine")
++
++(define_insn_reservation "nds_e8_unknown" 1
++ (and (eq_attr "type" "unknown")
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, e8_ex")
++
++(define_insn_reservation "nds_e8_misc" 1
++ (and (eq_attr "type" "misc")
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, e8_ex")
++
++(define_insn_reservation "nds_e8_alu" 1
++ (and (eq_attr "type" "alu")
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, e8_ex")
++
++(define_insn_reservation "nds_e8_load" 1
++ (and (match_test "nds32::load_single_p (insn)")
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, e8_ex")
++
++(define_insn_reservation "nds_e8_store" 1
++ (and (match_test "nds32::store_single_p (insn)")
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, e8_ex")
++
++(define_insn_reservation "nds_e8_load_multiple_1" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "1"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, e8_ex")
++
++(define_insn_reservation "nds_e8_load_multiple_2" 1
++ (and (ior (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "2"))
++ (match_test "nds32::load_double_p (insn)"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, e8_ii+e8_ex, e8_ex")
++
++(define_insn_reservation "nds_e8_load_multiple_3" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "3"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*2, e8_ex")
++
++(define_insn_reservation "nds_e8_load_multiple_4" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "4"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*3, e8_ex")
++
++(define_insn_reservation "nds_e8_load_multiple_5" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "5"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*4, e8_ex")
++
++(define_insn_reservation "nds_e8_load_multiple_6" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "6"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*5, e8_ex")
++
++(define_insn_reservation "nds_e8_load_multiple_7" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "7"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*6, e8_ex")
++
++(define_insn_reservation "nds_e8_load_multiple_8" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "8"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*7, e8_ex")
++
++(define_insn_reservation "nds_e8_load_multiple_12" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "12"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*11, e8_ex")
++
++(define_insn_reservation "nds_e8_store_multiple_1" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "1"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, e8_ex")
++
++(define_insn_reservation "nds_e8_store_multiple_2" 1
++ (and (ior (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "2"))
++ (match_test "nds32::store_double_p (insn)"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, e8_ii+e8_ex, e8_ex")
++
++(define_insn_reservation "nds_e8_store_multiple_3" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "3"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*2, e8_ex")
++
++(define_insn_reservation "nds_e8_store_multiple_4" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "4"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*3, e8_ex")
++
++(define_insn_reservation "nds_e8_store_multiple_5" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "5"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*4, e8_ex")
++
++(define_insn_reservation "nds_e8_store_multiple_6" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "6"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*5, e8_ex")
++
++(define_insn_reservation "nds_e8_store_multiple_7" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "7"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*6, e8_ex")
++
++(define_insn_reservation "nds_e8_store_multiple_8" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "8"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*7, e8_ex")
++
++(define_insn_reservation "nds_e8_store_multiple_12" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "12"))
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*11, e8_ex")
++
++(define_insn_reservation "nds_e8_mul_fast" 1
++ (and (match_test "nds32_mul_config != MUL_TYPE_SLOW")
++ (and (eq_attr "type" "mul")
++ (eq_attr "pipeline_model" "e8")))
++ "e8_ii, e8_ex")
++
++(define_insn_reservation "nds_e8_mul_slow" 1
++ (and (match_test "nds32_mul_config == MUL_TYPE_SLOW")
++ (and (eq_attr "type" "mul")
++ (eq_attr "pipeline_model" "e8")))
++ "e8_ii, e8_ex*16")
++
++(define_insn_reservation "nds_e8_mac_fast" 1
++ (and (match_test "nds32_mul_config != MUL_TYPE_SLOW")
++ (and (eq_attr "type" "mac")
++ (eq_attr "pipeline_model" "e8")))
++ "e8_ii, e8_ii+e8_ex, e8_ex")
++
++(define_insn_reservation "nds_e8_mac_slow" 1
++ (and (match_test "nds32_mul_config == MUL_TYPE_SLOW")
++ (and (eq_attr "type" "mac")
++ (eq_attr "pipeline_model" "e8")))
++ "e8_ii, (e8_ii+e8_ex)*16, e8_ex")
++
++(define_insn_reservation "nds_e8_div" 1
++ (and (eq_attr "type" "div")
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, (e8_ii+e8_ex)*36, e8_ex")
++
++(define_insn_reservation "nds_e8_branch" 1
++ (and (eq_attr "type" "branch")
++ (eq_attr "pipeline_model" "e8"))
++ "e8_ii, e8_ex")
++
++;; ------------------------------------------------------------------------
++;; Comment Notations and Bypass Rules
++;; ------------------------------------------------------------------------
++;; Producers (LHS)
++;; LD
++;; Load data from the memory and produce the loaded data. The result is
++;; ready at EXD.
++;; LMW(N, M)
++;; There are N micro-operations within an instruction that loads multiple
++;; words. The result produced by the M-th micro-operation is sent to
++;; consumers. The result is ready at EXD.
++;; ADDR_OUT
++;; Most load/store instructions can produce an address output if updating
++;; the base register is required. The result is ready at EX, which is
++;; produced by ALU.
++;; ALU, MOVD44, MUL, MAC
++;; The result is ready at EX.
++;; DIV_Rs
++;; A division instruction saves the quotient result to Rt and saves the
++;; remainder result to Rs. The instruction is separated into two micro-
++;; operations. The first micro-operation writes to Rt, and the seconde
++;; one writes to Rs. Each of the results is ready at EX.
++;;
++;; Consumers (RHS)
++;; ALU, MUL, DIV
++;; Require operands at EX.
++;; ADDR_IN_MOP(N)
++;; N denotes the address input is required by the N-th micro-operation.
++;; Such operand is required at II.
++;; ST
++;; A store instruction requires its data at EX.
++;; SMW(N, M)
++;; There are N micro-operations within an instruction that stores multiple
++;; words. Each M-th micro-operation requires its data at EX.
++;; BR_COND
++;; If a branch instruction is conditional, its input data is required at EX.
++
++;; LD -> ADDR_IN_MOP(1)
++(define_bypass 2
++ "nds_e8_load"
++ "nds_e8_branch,\
++ nds_e8_load, nds_e8_store,\
++ nds_e8_load_multiple_1,nds_e8_load_multiple_2, nds_e8_load_multiple_3,\
++ nds_e8_load_multiple_4,nds_e8_load_multiple_5, nds_e8_load_multiple_6,\
++ nds_e8_load_multiple_7,nds_e8_load_multiple_8, nds_e8_load_multiple_12,\
++ nds_e8_store_multiple_1,nds_e8_store_multiple_2, nds_e8_store_multiple_3,\
++ nds_e8_store_multiple_4,nds_e8_store_multiple_5, nds_e8_store_multiple_6,\
++ nds_e8_store_multiple_7,nds_e8_store_multiple_8, nds_e8_store_multiple_12"
++ "nds32_e8_load_to_ii_p"
++)
++
++;; LD -> ALU, MUL, MAC, DIV, BR_COND, ST, SMW(N, 1)
++(define_bypass 2
++ "nds_e8_load"
++ "nds_e8_alu,
++ nds_e8_mul_fast, nds_e8_mul_slow,\
++ nds_e8_mac_fast, nds_e8_mac_slow,\
++ nds_e8_div,\
++ nds_e8_branch,\
++ nds_e8_store,\
++ nds_e8_store_multiple_1,nds_e8_store_multiple_2, nds_e8_store_multiple_3,\
++ nds_e8_store_multiple_4,nds_e8_store_multiple_5, nds_e8_store_multiple_6,\
++ nds_e8_store_multiple_7,nds_e8_store_multiple_8, nds_e8_store_multiple_12"
++ "nds32_e8_load_to_ex_p"
++)
++
++;; ALU, MOVD44, MUL, MAC, DIV_Rs, LD_bi, ADDR_OUT -> ADDR_IN_MOP(1)
++(define_bypass 2
++ "nds_e8_alu,
++ nds_e8_mul_fast, nds_e8_mul_slow,\
++ nds_e8_mac_fast, nds_e8_mac_slow,\
++ nds_e8_div,\
++ nds_e8_load, nds_e8_store,\
++ nds_e8_load_multiple_1,nds_e8_load_multiple_2, nds_e8_load_multiple_3,\
++ nds_e8_load_multiple_4,nds_e8_load_multiple_5, nds_e8_load_multiple_6,\
++ nds_e8_load_multiple_7,nds_e8_load_multiple_8, nds_e8_load_multiple_12,\
++ nds_e8_store_multiple_1,nds_e8_store_multiple_2, nds_e8_store_multiple_3,\
++ nds_e8_store_multiple_4,nds_e8_store_multiple_5, nds_e8_store_multiple_6,\
++ nds_e8_store_multiple_7,nds_e8_store_multiple_8, nds_e8_store_multiple_12"
++ "nds_e8_branch,\
++ nds_e8_load, nds_e8_store,\
++ nds_e8_load_multiple_1,nds_e8_load_multiple_2, nds_e8_load_multiple_3,\
++ nds_e8_load_multiple_4,nds_e8_load_multiple_5, nds_e8_load_multiple_6,\
++ nds_e8_load_multiple_7,nds_e8_load_multiple_8, nds_e8_load_multiple_12,\
++ nds_e8_store_multiple_1,nds_e8_store_multiple_2, nds_e8_store_multiple_3,\
++ nds_e8_store_multiple_4,nds_e8_store_multiple_5, nds_e8_store_multiple_6,\
++ nds_e8_store_multiple_7,nds_e8_store_multiple_8, nds_e8_store_multiple_12"
++ "nds32_e8_ex_to_ii_p"
++)
++
++;; LMW(N, N) -> ADDR_IN_MOP(1)
++(define_bypass 2
++ "nds_e8_load_multiple_1,nds_e8_load_multiple_2, nds_e8_load_multiple_3,\
++ nds_e8_load_multiple_4,nds_e8_load_multiple_5, nds_e8_load_multiple_6,\
++ nds_e8_load_multiple_7,nds_e8_load_multiple_8, nds_e8_load_multiple_12"
++ "nds_e8_branch,\
++ nds_e8_load, nds_e8_store,\
++ nds_e8_load_multiple_1,nds_e8_load_multiple_2, nds_e8_load_multiple_3,\
++ nds_e8_load_multiple_4,nds_e8_load_multiple_5, nds_e8_load_multiple_6,\
++ nds_e8_load_multiple_7,nds_e8_load_multiple_8, nds_e8_load_multiple_12,\
++ nds_e8_store_multiple_1,nds_e8_store_multiple_2, nds_e8_store_multiple_3,\
++ nds_e8_store_multiple_4,nds_e8_store_multiple_5, nds_e8_store_multiple_6,\
++ nds_e8_store_multiple_7,nds_e8_store_multiple_8, nds_e8_store_multiple_12"
++ "nds32_e8_last_load_to_ii_p"
++)
++
++;; LMW(N, N) -> ALU, MUL, MAC, DIV, BR_COND, ST, SMW(N, 1)
++(define_bypass 2
++ "nds_e8_load_multiple_1,nds_e8_load_multiple_2, nds_e8_load_multiple_3,\
++ nds_e8_load_multiple_4,nds_e8_load_multiple_5, nds_e8_load_multiple_6,\
++ nds_e8_load_multiple_7,nds_e8_load_multiple_8, nds_e8_load_multiple_12"
++ "nds_e8_alu,
++ nds_e8_mul_fast, nds_e8_mul_slow,\
++ nds_e8_mac_fast, nds_e8_mac_slow,\
++ nds_e8_div,\
++ nds_e8_branch,\
++ nds_e8_store,\
++ nds_e8_store_multiple_1,nds_e8_store_multiple_2, nds_e8_store_multiple_3,\
++ nds_e8_store_multiple_4,nds_e8_store_multiple_5, nds_e8_store_multiple_6,\
++ nds_e8_store_multiple_7,nds_e8_store_multiple_8, nds_e8_store_multiple_12"
++ "nds32_e8_last_load_to_ex_p"
++)
+diff --git a/gcc/config/nds32/nds32-elf.opt b/gcc/config/nds32/nds32-elf.opt
+new file mode 100644
+index 0000000..afe6aad
+--- /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 f8b2738..6525915 100644
+--- a/gcc/config/nds32/nds32-fp-as-gp.c
++++ b/gcc/config/nds32/nds32-fp-as-gp.c
+@@ -1,4 +1,4 @@
+-/* The fp-as-gp pass of Andes NDS32 cpu for GNU compiler
++/* fp-as-gp pass of Andes NDS32 cpu for GNU compiler
+ Copyright (C) 2012-2016 Free Software Foundation, Inc.
+ Contributed by Andes Technology Corporation.
+
+@@ -24,19 +24,280 @@
+ #include "system.h"
+ #include "coretypes.h"
+ #include "backend.h"
++#include "tree.h"
++#include "rtl.h"
++#include "df.h"
++#include "alias.h"
++#include "stor-layout.h"
++#include "varasm.h"
++#include "calls.h"
++#include "regs.h"
++#include "insn-config.h" /* Required by recog.h. */
++#include "conditions.h"
++#include "output.h"
++#include "insn-attr.h" /* For DFA state_t. */
++#include "insn-codes.h" /* For CODE_FOR_xxx. */
++#include "reload.h" /* For push_reload(). */
++#include "flags.h"
++#include "insn-config.h"
++#include "expmed.h"
++#include "dojump.h"
++#include "explow.h"
++#include "emit-rtl.h"
++#include "stmt.h"
++#include "expr.h"
++#include "recog.h"
++#include "diagnostic-core.h"
++#include "cfgrtl.h"
++#include "cfganal.h"
++#include "lcm.h"
++#include "cfgbuild.h"
++#include "cfgcleanup.h"
++#include "tm_p.h"
++#include "tm-constrs.h"
++#include "optabs.h" /* For GEN_FCN. */
++#include "target.h"
++#include "langhooks.h" /* For add_builtin_function(). */
++#include "builtins.h"
++#include "ira.h"
++#include "ira-int.h"
++#include "tree-pass.h"
+
+ /* ------------------------------------------------------------------------ */
+
++/* A helper function to check if this function should contain prologue. */
++static bool
++nds32_have_prologue_p (void)
++{
++ int i;
++
++ for (i = 0; i < 28; i++)
++ if (NDS32_REQUIRED_CALLEE_SAVED_P (i))
++ return true;
++
++ return (flag_pic
++ || NDS32_REQUIRED_CALLEE_SAVED_P (FP_REGNUM)
++ || NDS32_REQUIRED_CALLEE_SAVED_P (LP_REGNUM));
++}
++
++static int
++nds32_get_symbol_count (void)
++{
++ int symbol_count = 0;
++ rtx_insn *insn;
++ basic_block bb;
++
++ FOR_EACH_BB_FN (bb, cfun)
++ {
++ FOR_BB_INSNS (bb, insn)
++ {
++ /* Counting the insn number which the addressing mode is symbol. */
++ if (single_set (insn) && nds32_symbol_load_store_p (insn))
++ {
++ rtx pattern = PATTERN (insn);
++ rtx mem;
++ gcc_assert (GET_CODE (pattern) == SET);
++ if (GET_CODE (SET_SRC (pattern)) == REG )
++ mem = SET_DEST (pattern);
++ else
++ mem = SET_SRC (pattern);
++
++ /* We have only lwi37 and swi37 for fp-as-gp optimization,
++ so don't count any other than SImode.
++ MEM for QImode and HImode will wrap by ZERO_EXTEND
++ or SIGN_EXTEND */
++ if (GET_CODE (mem) == MEM)
++ symbol_count++;
++ }
++ }
++ }
++
++ return symbol_count;
++}
++
+ /* Function to determine whether it is worth to do fp_as_gp optimization.
+- Return 0: It is NOT worth to do fp_as_gp optimization.
+- Return 1: It is APPROXIMATELY worth to do fp_as_gp optimization.
++ Return false: It is NOT worth to do fp_as_gp optimization.
++ Return true: It is APPROXIMATELY worth to do fp_as_gp optimization.
+ Note that if it is worth to do fp_as_gp optimization,
+ we MUST set FP_REGNUM ever live in this function. */
+-int
++static bool
+ nds32_fp_as_gp_check_available (void)
+ {
+- /* By default we return 0. */
+- return 0;
++ basic_block bb;
++ basic_block exit_bb;
++ edge_iterator ei;
++ edge e;
++ bool first_exit_blocks_p;
++
++ /* If there exists ANY of following conditions,
++ we DO NOT perform fp_as_gp optimization:
++ 1. TARGET_FORBID_FP_AS_GP is set
++ regardless of the TARGET_FORCE_FP_AS_GP.
++ 2. User explicitly uses 'naked'/'no_prologue' attribute.
++ We use nds32_naked_function_p() to help such checking.
++ 3. Not optimize for size.
++ 4. Need frame pointer.
++ 5. If $fp is already required to be saved,
++ it means $fp is already choosen by register allocator.
++ Thus we better not to use it for fp_as_gp optimization.
++ 6. This function is a vararg function.
++ DO NOT apply fp_as_gp optimization on this function
++ because it may change and break stack frame.
++ 7. The epilogue is empty.
++ This happens when the function uses exit()
++ or its attribute is no_return.
++ In that case, compiler will not expand epilogue
++ so that we have no chance to output .omit_fp_end directive. */
++ if (TARGET_FORBID_FP_AS_GP
++ || nds32_naked_function_p (current_function_decl)
++ || !optimize_size
++ || frame_pointer_needed
++ || NDS32_REQUIRED_CALLEE_SAVED_P (FP_REGNUM)
++ || (cfun->stdarg == 1)
++ || (find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) == NULL))
++ return false;
++
++ /* Disable fp_as_gp if there is any infinite loop since the fp may
++ reuse in infinite loops by register rename.
++ For check infinite loops we should make sure exit_bb is post dominate
++ all other basic blocks if there is no infinite loops. */
++ first_exit_blocks_p = true;
++ exit_bb = NULL;
++
++ FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
++ {
++ /* More than one exit block also do not perform fp_as_gp optimization. */
++ if (!first_exit_blocks_p)
++ return false;
++
++ exit_bb = e->src;
++ first_exit_blocks_p = false;
++ }
++
++ /* Not found exit_bb? just abort fp_as_gp! */
++ if (!exit_bb)
++ return false;
++
++ /* Each bb should post dominate by exit_bb if there is no infinite loop! */
++ FOR_EACH_BB_FN (bb, cfun)
++ {
++ if (!dominated_by_p (CDI_POST_DOMINATORS,
++ bb,
++ exit_bb))
++ return false;
++ }
++
++ /* Now we can check the possibility of using fp_as_gp optimization. */
++ if (TARGET_FORCE_FP_AS_GP)
++ {
++ /* User explicitly issues -mforce-fp-as-gp option. */
++ return true;
++ }
++ else
++ {
++ /* In the following we are going to evaluate whether
++ it is worth to do fp_as_gp optimization. */
++ bool good_gain = false;
++ int symbol_count;
++
++ int threshold;
++
++ /* We check if there already requires prologue.
++ Note that $gp will be saved in prologue for PIC code generation.
++ After that, we can set threshold by the existence of prologue.
++ Each fp-implied instruction will gain 2-byte code size
++ from gp-aware instruction, so we have following heuristics. */
++ if (flag_pic
++ || nds32_have_prologue_p ())
++ {
++ /* Have-prologue:
++ Compiler already intends to generate prologue content,
++ so the fp_as_gp optimization will only insert
++ 'la $fp,_FP_BASE_' instruction, which will be
++ converted into 4-byte instruction at link time.
++ The threshold is "3" symbol accesses, 2 + 2 + 2 > 4. */
++ threshold = 3;
++ }
++ else
++ {
++ /* None-prologue:
++ Compiler originally does not generate prologue content,
++ so the fp_as_gp optimization will NOT ONLY insert
++ 'la $fp,_FP_BASE' instruction, but also causes
++ push/pop instructions.
++ If we are using v3push (push25/pop25),
++ the threshold is "5" symbol accesses, 5*2 > 4 + 2 + 2;
++ If we are using normal push (smw/lmw),
++ the threshold is "5+2" symbol accesses 7*2 > 4 + 4 + 4. */
++ threshold = 5 + (TARGET_V3PUSH ? 0 : 2);
++ }
++
++ symbol_count = nds32_get_symbol_count ();
++
++ if (symbol_count >= threshold)
++ good_gain = true;
++
++ /* Enable fp_as_gp optimization when potential gain is good enough. */
++ return good_gain;
++ }
++}
++
++static unsigned int
++nds32_fp_as_gp (void)
++{
++ bool fp_as_gp_p;
++ calculate_dominance_info (CDI_POST_DOMINATORS);
++ fp_as_gp_p = nds32_fp_as_gp_check_available ();
++
++ /* Here is a hack to IRA for enable/disable a hard register per function.
++ We *MUST* review this way after migrate gcc 4.9! */
++ if (fp_as_gp_p) {
++ SET_HARD_REG_BIT(this_target_ira_int->x_no_unit_alloc_regs, FP_REGNUM);
++ df_set_regs_ever_live (FP_REGNUM, 1);
++ } else {
++ CLEAR_HARD_REG_BIT(this_target_ira_int->x_no_unit_alloc_regs, FP_REGNUM);
++ }
++
++ cfun->machine->fp_as_gp_p = fp_as_gp_p;
++
++ free_dominance_info (CDI_POST_DOMINATORS);
++ return 1;
++}
++
++const pass_data pass_data_nds32_fp_as_gp =
++{
++ RTL_PASS, /* type */
++ "fp_as_gp", /* name */
++ OPTGROUP_NONE, /* optinfo_flags */
++ TV_MACH_DEP, /* tv_id */
++ 0, /* properties_required */
++ 0, /* properties_provided */
++ 0, /* properties_destroyed */
++ 0, /* todo_flags_start */
++ 0 /* todo_flags_finish */
++};
++
++class pass_nds32_fp_as_gp : public rtl_opt_pass
++{
++public:
++ pass_nds32_fp_as_gp (gcc::context *ctxt)
++ : rtl_opt_pass (pass_data_nds32_fp_as_gp, ctxt)
++ {}
++
++ /* opt_pass methods: */
++ bool gate (function *)
++ {
++ return !TARGET_LINUX_ABI
++ && TARGET_16_BIT
++ && optimize_size;
++ }
++ unsigned int execute (function *) { return nds32_fp_as_gp (); }
++};
++
++rtl_opt_pass *
++make_pass_nds32_fp_as_gp (gcc::context *ctxt)
++{
++ return new pass_nds32_fp_as_gp (ctxt);
+ }
+
+ /* ------------------------------------------------------------------------ */
+diff --git a/gcc/config/nds32/nds32-fpu.md b/gcc/config/nds32/nds32-fpu.md
+new file mode 100644
+index 0000000..11eabd5
+--- /dev/null
++++ b/gcc/config/nds32/nds32-fpu.md
+@@ -0,0 +1,503 @@
++;; Machine description of Andes NDS32 cpu for GNU compiler
++;; Copyright (C) 2012-2016 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
++;; .
++
++;;SFmode moves
++
++(define_expand "movsf"
++ [(set (match_operand:SF 0 "general_operand" "")
++ (match_operand:SF 1 "general_operand" ""))]
++ ""
++{
++ /* Need to force register if mem <- !reg. */
++ if (MEM_P (operands[0]) && !REG_P (operands[1]))
++ operands[1] = force_reg (SFmode, operands[1]);
++ if (CONST_DOUBLE_P (operands[1])
++ && !satisfies_constraint_Cs20 (operands[1]))
++ {
++ const REAL_VALUE_TYPE *r;
++ unsigned long l;
++
++ r = CONST_DOUBLE_REAL_VALUE (operands[1]);
++ REAL_VALUE_TO_TARGET_SINGLE (*r, l);
++
++ emit_move_insn (operands[0], gen_rtx_HIGH (SFmode, operands[1]));
++
++ if ((l & 0xFFF) != 0)
++ emit_insn (gen_movsf_lo (operands[0], operands[0], operands[1]));
++ DONE;
++ }
++})
++
++(define_insn "movsf_lo"
++ [(set (match_operand:SF 0 "register_operand" "=r")
++ (lo_sum:SF (match_operand:SF 1 "register_operand" "r")
++ (match_operand:SF 2 "immediate_operand" "i")))]
++ ""
++ "ori\t%0, %1, lo12(%2)"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "*movsf"
++ [(set (match_operand:SF 0 "nonimmediate_operand" "=r, r, U45, U33, U37, U45, m, l, l, l, d, r, f, *f, *r, f, Q, r, r, r")
++ (match_operand:SF 1 "general_operand" " r, r, l, l, l, d, r, U45, U33, U37, U45, m, f, *r, *f, Q, f,Cs05,Cs20, Chig"))]
++ "(register_operand(operands[0], SFmode)
++ || register_operand(operands[1], SFmode))"
++{
++ switch (which_alternative)
++ {
++ case 0:
++ return "mov55\t%0, %1";
++ case 1:
++ return "ori\t%0, %1, 0";
++ case 2:
++ case 3:
++ case 4:
++ case 5:
++ return nds32_output_16bit_store (operands, 4);
++ case 6:
++ return nds32_output_32bit_store (operands, 4);
++ case 7:
++ case 8:
++ case 9:
++ case 10:
++ return nds32_output_16bit_load (operands, 4);
++ case 11:
++ return nds32_output_32bit_load (operands, 4);
++ case 12:
++ if (TARGET_FPU_SINGLE)
++ return "fcpyss\t%0, %1, %1";
++ else
++ return "#";
++ case 13:
++ return "fmtsr\t%1, %0";
++ case 14:
++ return "fmfsr\t%0, %1";
++ case 15:
++ return nds32_output_float_load (operands);
++ case 16:
++ return nds32_output_float_store (operands);
++ case 17:
++ return "movi55\t%0, %1";
++ case 18:
++ return "movi\t%0, %1";
++ case 19:
++ return "sethi\t%0, %1";
++ default:
++ gcc_unreachable ();
++ }
++}
++ [(set_attr "type" "alu,alu,store,store,store,store,store,load,load,load,load,load,fcpy,fmtsr,fmfsr,fload,fstore,alu,alu,alu")
++ (set_attr "length" " 2, 4, 2, 2, 2, 2, 4, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 2, 4, 4")
++ (set_attr "feature" " v1, v1, v1, v1, v1, v1, v1, v1, v1, v1, v1, v1, fpu, fpu, fpu, fpu, fpu, v1, v1, v1")])
++
++;; Conditional Move Instructions
++
++(define_expand "movcc"
++ [(set (match_operand:ANYF 0 "register_operand" "")
++ (if_then_else:ANYF (match_operand 1 "nds32_float_comparison_operator" "")
++ (match_operand:ANYF 2 "register_operand" "")
++ (match_operand:ANYF 3 "register_operand" "")))]
++ ""
++{
++ if (nds32_cond_move_p (operands[1]))
++ {
++ /* Operands[1] condition code is UNORDERED or ORDERED, and
++ sub-operands[1] MODE isn't SFmode or SFmode, return FAIL
++ for gcc, because we don't using slt compare instruction
++ to generate UNORDERED and ORDERED condition. */
++ FAIL;
++ }
++ else
++ nds32_expand_float_movcc (operands);
++})
++
++(define_insn "fcmov_eq"
++ [(set (match_operand:ANYF 0 "register_operand" "=f, f")
++ (if_then_else:ANYF (eq (match_operand:SI 1 "register_operand" "f, f")
++ (const_int 0))
++ (match_operand:ANYF 2 "register_operand" "f, 0")
++ (match_operand:ANYF 3 "register_operand" "0, f")))]
++ ""
++ "@
++ fcmovz\t%0,%2,%1
++ fcmovn\t%0,%3,%1"
++ [(set_attr "type" "fcmov")
++ (set_attr "length" "4")]
++)
++
++(define_insn "fcmov_ne"
++ [(set (match_operand:ANYF 0 "register_operand" "=f, f")
++ (if_then_else:ANYF (ne (match_operand:SI 1 "register_operand" "f, f")
++ (const_int 0))
++ (match_operand:ANYF 2 "register_operand" "f, 0")
++ (match_operand:ANYF 3 "register_operand" "0, f")))]
++ ""
++ "@
++ fcmovn\t%0,%2,%1
++ fcmovz\t%0,%3,%1"
++ [(set_attr "type" "fcmov")
++ (set_attr "length" "4")]
++)
++
++;; Arithmetic instructions.
++
++(define_insn "add3"
++ [(set (match_operand:ANYF 0 "register_operand" "=f")
++ (plus:ANYF (match_operand:ANYF 1 "register_operand" "f")
++ (match_operand:ANYF 2 "register_operand" "f")))]
++ ""
++ "fadd\t %0, %1, %2"
++ [(set_attr "type" "falu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "sub3"
++ [(set (match_operand:ANYF 0 "register_operand" "=f")
++ (minus:ANYF (match_operand:ANYF 1 "register_operand" "f")
++ (match_operand:ANYF 2 "register_operand" "f")))]
++ ""
++ "fsub\t %0, %1, %2"
++ [(set_attr "type" "falu")
++ (set_attr "length" "4")]
++)
++
++;; Multiplication insns.
++
++(define_insn "mul3"
++ [(set (match_operand:ANYF 0 "register_operand" "=f")
++ (mult:ANYF (match_operand:ANYF 1 "register_operand" "f")
++ (match_operand:ANYF 2 "register_operand" "f")))]
++ ""
++ "fmul\t %0, %1, %2"
++ [(set_attr "type" "fmul")
++ (set_attr "length" "4")]
++)
++
++(define_insn "fma4"
++ [(set (match_operand:ANYF 0 "register_operand" "=f")
++ (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
++ (match_operand:ANYF 2 "register_operand" "f")
++ (match_operand:ANYF 3 "register_operand" "0")))]
++ "TARGET_EXT_FPU_FMA"
++ "fmadd\t%0, %1, %2"
++ [(set_attr "type" "fmac")
++ (set_attr "length" "4")]
++)
++
++(define_insn "fnma4"
++ [(set (match_operand:ANYF 0 "register_operand" "=f")
++ (fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
++ (match_operand:ANYF 2 "register_operand" "f")
++ (match_operand:ANYF 3 "register_operand" "0")))]
++ "TARGET_EXT_FPU_FMA"
++ "fmsub\t%0, %1, %2"
++ [(set_attr "type" "fmac")
++ (set_attr "length" "4")]
++)
++
++(define_insn "fms4"
++ [(set (match_operand:ANYF 0 "register_operand" "=f")
++ (fma:ANYF (match_operand:ANYF 1 "register_operand" "f")
++ (match_operand:ANYF 2 "register_operand" "f")
++ (neg:ANYF (match_operand:ANYF 3 "register_operand" "0"))))]
++ "TARGET_EXT_FPU_FMA"
++ "fnmsub\t%0, %1, %2"
++ [(set_attr "type" "fmac")
++ (set_attr "length" "4")]
++)
++
++(define_insn "fnms4"
++ [(set (match_operand:ANYF 0 "register_operand" "=f")
++ (fma:ANYF (neg:ANYF (match_operand:ANYF 1 "register_operand" "f"))
++ (match_operand:ANYF 2 "register_operand" "f")
++ (neg:ANYF (match_operand:ANYF 3 "register_operand" "0"))))]
++ "TARGET_EXT_FPU_FMA"
++ "fnmadd\t%0, %1, %2"
++ [(set_attr "type" "fmac")
++ (set_attr "length" "4")]
++)
++
++;; Div Instructions.
++
++(define_insn "div3"
++ [(set (match_operand:ANYF 0 "register_operand" "=f")
++ (div:ANYF (match_operand:ANYF 1 "register_operand" "f")
++ (match_operand:ANYF 2 "register_operand" "f")))]
++ ""
++ "fdiv\t %0, %1, %2"
++ [(set_attr "type" "fdiv")
++ (set_attr "length" "4")]
++)
++
++(define_insn "sqrt2"
++ [(set (match_operand:ANYF 0 "register_operand" "=f")
++ (sqrt:ANYF (match_operand:ANYF 1 "register_operand" "f")))]
++ ""
++ "fsqrt\t %0, %1"
++ [(set_attr "type" "fsqrt")
++ (set_attr "length" "4")]
++)
++
++;; Conditional Branch patterns
++
++(define_expand "cstore4"
++ [(set (match_operand:SI 0 "register_operand" "")
++ (match_operator:SI 1 "nds32_float_comparison_operator"
++ [(match_operand:ANYF 2 "register_operand" "")
++ (match_operand:ANYF 3 "register_operand" "")]))]
++ ""
++{
++ nds32_expand_float_cstore (operands);
++ DONE;
++})
++
++(define_expand "cbranch4"
++ [(set (pc)
++ (if_then_else (match_operator 0 "nds32_float_comparison_operator"
++ [(match_operand:ANYF 1 "register_operand" "")
++ (match_operand:ANYF 2 "register_operand" "")])
++ (label_ref (match_operand 3 "" ""))
++ (pc)))]
++ ""
++{
++ nds32_expand_float_cbranch (operands);
++ DONE;
++})
++
++;; Copysign Instructions.
++
++(define_insn "copysignsf3"
++ [(set (match_operand:SF 0 "register_operand" "=f")
++ (unspec:SF [(match_operand:SF 1 "register_operand" "f")
++ (match_operand:SF 2 "register_operand" "f")]
++ UNSPEC_COPYSIGN))]
++ "TARGET_FPU_SINGLE"
++ "fcpyss\t%0,%1,%2"
++ [(set_attr "type" "fcpy")
++ (set_attr "length" "4")]
++)
++
++(define_insn "copysigndf3"
++ [(set (match_operand:DF 0 "register_operand" "=f")
++ (unspec:DF [(match_operand:DF 1 "register_operand" "f")
++ (match_operand:DF 2 "register_operand" "f")]
++ UNSPEC_COPYSIGN))]
++ "TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE"
++ "fcpysd\t%0,%1,%2"
++ [(set_attr "type" "fcpy")
++ (set_attr "length" "4")]
++)
++
++(define_insn "*ncopysign3"
++ [(set (match_operand:ANYF 0 "register_operand" "=f")
++ (neg:ANYF (unspec:ANYF [(match_operand:ANYF 1 "register_operand" "f")
++ (match_operand:ANYF 2 "register_operand" "f")]
++ UNSPEC_COPYSIGN)))]
++ ""
++ "fcpyns\t%0,%1,%2"
++ [(set_attr "type" "fcpy")
++ (set_attr "length" "4")]
++)
++
++;; Absolute Instructions
++
++(define_insn "abssf2"
++ [(set (match_operand:SF 0 "register_operand" "=f, r")
++ (abs:SF (match_operand:SF 1 "register_operand" "f, r")))]
++ "TARGET_FPU_SINGLE || TARGET_EXT_PERF"
++ "@
++ fabss\t%0, %1
++ bclr\t%0, %1, 31"
++ [(set_attr "type" "fabs,alu")
++ (set_attr "length" "4")
++ (set_attr "feature" "fpu,pe1")]
++)
++
++(define_insn "absdf2"
++ [(set (match_operand:DF 0 "register_operand" "=f")
++ (abs:DF (match_operand:DF 1 "register_operand" "f")))]
++ "TARGET_FPU_DOUBLE"
++ "fabsd\t%0, %1"
++ [(set_attr "type" "fabs")
++ (set_attr "length" "4")]
++)
++
++;; Negation Instructions
++
++(define_insn "*negsf2"
++ [(set (match_operand:SF 0 "register_operand" "=f, r")
++ (neg:SF (match_operand:SF 1 "register_operand" "f, r")))]
++ "TARGET_FPU_SINGLE || TARGET_EXT_PERF"
++ "@
++ fcpynss\t%0, %1, %1
++ btgl\t%0, %1, 31"
++ [(set_attr "type" "fcpy,alu")
++ (set_attr "length" "4")
++ (set_attr "feature" "fpu,pe1")]
++)
++
++(define_insn "*negdf2"
++ [(set (match_operand:DF 0 "register_operand" "=f")
++ (neg:DF (match_operand:DF 1 "register_operand" "f")))]
++ "TARGET_FPU_DOUBLE"
++ "fcpynsd\t%0, %1, %1"
++ [(set_attr "type" "fcpy")
++ (set_attr "length" "4")]
++)
++
++;; Data Format Conversion Instructions
++
++(define_insn "floatunssi2"
++ [(set (match_operand:ANYF 0 "register_operand" "=f")
++ (unsigned_float:ANYF (match_operand:SI 1 "register_operand" "f")))]
++ ""
++ "fui2\t %0, %1"
++ [(set_attr "type" "falu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "floatsi2"
++ [(set (match_operand:ANYF 0 "register_operand" "=f")
++ (float:ANYF (match_operand:SI 1 "register_operand" "f")))]
++ ""
++ "fsi2\t %0, %1"
++ [(set_attr "type" "falu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "fixuns_truncsi2"
++ [(set (match_operand:SI 0 "register_operand" "=f")
++ (unsigned_fix:SI (fix:ANYF (match_operand:ANYF 1 "register_operand" "f"))))]
++ ""
++ "f2ui.z\t %0, %1"
++ [(set_attr "type" "falu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "fix_truncsi2"
++ [(set (match_operand:SI 0 "register_operand" "=f")
++ (fix:SI (fix:ANYF (match_operand:ANYF 1 "register_operand" "f"))))]
++ ""
++ "f2si.z\t %0, %1"
++ [(set_attr "type" "falu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "extendsfdf2"
++ [(set (match_operand:DF 0 "register_operand" "=f")
++ (float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
++ "TARGET_FPU_SINGLE && TARGET_FPU_DOUBLE"
++ "fs2d\t%0, %1"
++ [(set_attr "type" "falu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "truncdfsf2"
++ [(set (match_operand:SF 0 "register_operand" "=f")
++ (float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
++ "TARGET_FPU_SINGLE && TARGET_FPU_DOUBLE"
++ "fd2s\t%0, %1"
++ [(set_attr "type" "falu")
++ (set_attr "length" "4")]
++)
++
++;; Compare Instructions
++
++(define_insn "cmp_eq"
++ [(set (match_operand:SI 0 "register_operand" "=f")
++ (eq:SI (match_operand:ANYF 1 "register_operand" "f")
++ (match_operand:ANYF 2 "register_operand" "f")))]
++ ""
++ {
++ if (NDS32_EXT_FPU_DOT_E)
++ return "fcmpeq.e %0, %1, %2";
++ else
++ return "fcmpeq\t%0, %1, %2";
++ }
++ [(set_attr "type" "fcmp")
++ (set_attr "length" "4")]
++)
++
++(define_insn "cmp_lt"
++ [(set (match_operand:SI 0 "register_operand" "=f")
++ (lt:SI (match_operand:ANYF 1 "register_operand" "f")
++ (match_operand:ANYF 2 "register_operand" "f")))]
++ ""
++{
++ if (NDS32_EXT_FPU_DOT_E)
++ return "fcmplt.e %0, %1, %2";
++ else
++ return "fcmplt\t%0, %1, %2";
++}
++ [(set_attr "type" "fcmp")
++ (set_attr "length" "4")]
++)
++
++(define_insn "cmp_le"
++ [(set (match_operand:SI 0 "register_operand" "=f")
++ (le:SI (match_operand:ANYF 1 "register_operand" "f")
++ (match_operand:ANYF 2 "register_operand" "f")))]
++ ""
++{
++ if (NDS32_EXT_FPU_DOT_E)
++ return "fcmple.e %0, %1, %2";
++ else
++ return "fcmple\t%0, %1, %2";
++}
++ [(set_attr "type" "fcmp")
++ (set_attr "length" "4")]
++)
++
++(define_insn "cmp_un"
++ [(set (match_operand:SI 0 "register_operand" "=f")
++ (unordered:SI (match_operand:ANYF 1 "register_operand" "f")
++ (match_operand:ANYF 2 "register_operand" "f")))]
++ ""
++{
++ if (NDS32_EXT_FPU_DOT_E)
++ return "fcmpun.e %0, %1, %2";
++ else
++ return "fcmpun\t%0, %1, %2";
++}
++ [(set_attr "type" "fcmp")
++ (set_attr "length" "4")]
++)
++
++(define_split
++ [(set (match_operand:SF 0 "register_operand" "")
++ (match_operand:SF 1 "register_operand" ""))]
++ "!TARGET_FPU_SINGLE
++ && NDS32_IS_FPR_REGNUM (REGNO (operands[0]))
++ && NDS32_IS_FPR_REGNUM (REGNO (operands[1]))"
++ [(set (match_dup 2) (match_dup 1))
++ (set (match_dup 0) (match_dup 2))]
++{
++ operands[2] = gen_rtx_REG (SFmode, TA_REGNUM);
++})
++
++(define_split
++ [(set (match_operand:SF 0 "register_operand" "")
++ (match_operand:SF 1 "const_double_operand" ""))]
++ "!satisfies_constraint_Cs20 (operands[1])
++ && !satisfies_constraint_Chig (operands[1])"
++ [(set (match_dup 0) (high:SF (match_dup 1)))
++ (set (match_dup 0) (lo_sum:SF (match_dup 0) (match_dup 1)))])
++;; ----------------------------------------------------------------------------
+diff --git a/gcc/config/nds32/nds32-gcse.c b/gcc/config/nds32/nds32-gcse.c
+new file mode 100644
+index 0000000..301981d
+--- /dev/null
++++ b/gcc/config/nds32/nds32-gcse.c
+@@ -0,0 +1,670 @@
++/* Global CSE pass of Andes NDS32 cpu for GNU compiler
++ Copyright (C) 2012-2016 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
++ . */
++
++/* ------------------------------------------------------------------------ */
++
++#include "config.h"
++#include "system.h"
++#include "coretypes.h"
++#include "backend.h"
++#include "tree.h"
++#include "rtl.h"
++#include "df.h"
++#include "alias.h"
++#include "stor-layout.h"
++#include "varasm.h"
++#include "calls.h"
++#include "regs.h"
++#include "insn-config.h" /* Required by recog.h. */
++#include "conditions.h"
++#include "output.h"
++#include "insn-attr.h" /* For DFA state_t. */
++#include "insn-codes.h" /* For CODE_FOR_xxx. */
++#include "reload.h" /* For push_reload(). */
++#include "flags.h"
++#include "insn-config.h"
++#include "expmed.h"
++#include "dojump.h"
++#include "explow.h"
++#include "emit-rtl.h"
++#include "stmt.h"
++#include "expr.h"
++#include "recog.h"
++#include "diagnostic-core.h"
++#include "cfgrtl.h"
++#include "cfganal.h"
++#include "lcm.h"
++#include "cfgbuild.h"
++#include "cfgcleanup.h"
++#include "tm_p.h"
++#include "tm-constrs.h"
++#include "optabs.h" /* For GEN_FCN. */
++#include "target.h"
++#include "langhooks.h" /* For add_builtin_function(). */
++#include "builtins.h"
++#include "cpplib.h"
++#include "params.h"
++#include "tree-pass.h"
++#include "dbgcnt.h"
++#include "df.h"
++#include "reload.h"
++
++/* ------------------------------------------------------------------------ */
++
++struct expr
++{
++ /* The expression. */
++ rtx expr;
++
++ /* The same hash for this entry. */
++ hashval_t hash;
++
++ struct occr *antic_occr;
++ /* The number of antic_occr. */
++ unsigned int count;
++};
++
++struct occr
++{
++ /* Next occurrence of this expression. */
++ struct occr *next;
++ /* The insn that computes the expression. */
++ rtx_insn *insn;
++ /* Nonzero if this [anticipatable] occurrence has been deleted. */
++ char deleted_p;
++};
++
++struct reg_avail_info
++{
++ basic_block last_bb;
++ int first_set;
++ int first_use;
++};
++
++/* Hashtable helpers. */
++
++struct expr_hasher : nofree_ptr_hash
++{
++ static inline hashval_t hash (const expr *);
++ static inline bool equal (const expr *, const expr *);
++};
++
++/* Callback for hashtab.
++ Return the hash value for expression EXP. We don't actually hash
++ here, we just return the cached hash value. */
++
++inline hashval_t
++expr_hasher::hash (const expr *exp)
++{
++ return exp->hash;
++}
++
++/* Callback for hashtab.
++ Return nonzero if exp1 is equivalent to exp2. */
++
++inline bool
++expr_hasher::equal (const expr *exp1, const expr *exp2)
++{
++ int equiv_p = exp_equiv_p (exp1->expr, exp2->expr, 0, true);
++
++ gcc_assert (!equiv_p || exp1->hash == exp2->hash);
++ return equiv_p;
++}
++
++static hashval_t
++hash_expr (rtx x, int *do_not_record_p)
++{
++ *do_not_record_p = 0;
++ return hash_rtx (x, GET_MODE (x), do_not_record_p,
++ NULL, /*have_reg_qty=*/false);
++}
++
++
++/* Helpers for memory allocation/freeing. */
++static void alloc_mem (void);
++static void free_mem (void);
++static void compute_hash_table (void);
++/* Scan the pattern of INSN and add an entry to the hash TABLE.
++ After reload we are interested in loads/stores only. */
++static void hash_scan_set (rtx_insn *);
++static void insert_expr_in_table (rtx, rtx_insn *);
++static void dump_hash_table (FILE *);
++
++static struct obstack expr_obstack;
++/* The table itself. */
++static hash_table *expr_table;
++static struct reg_avail_info *reg_avail_info;
++static sbitmap *hoist_vbein;
++static sbitmap *hoist_vbeout;
++
++/* Allocate memory for the CUID mapping array and register/memory
++ tracking tables. */
++
++static void
++alloc_mem (void)
++{
++ /* Allocate the available expressions hash table. We don't want to
++ make the hash table too small, but unnecessarily making it too large
++ also doesn't help. The i/4 is a gcse.c relic, and seems like a
++ reasonable choice. */
++ expr_table = new hash_table (MAX (get_max_insn_count () / 4,
++ 13));
++
++ /* We allocate everything on obstacks because we often can roll back
++ the whole obstack to some point. Freeing obstacks is very fast. */
++ gcc_obstack_init (&expr_obstack);
++}
++
++/* Free memory allocated by alloc_mem. */
++
++static void
++free_mem (void)
++{
++ delete expr_table;
++ expr_table = NULL;
++
++ obstack_free (&expr_obstack, NULL);
++}
++
++
++/* Dump all expressions and occurrences that are currently in the
++ expression hash table to FILE. */
++
++/* This helper is called via htab_traverse. */
++int
++nds32_dump_expr_hash_table_entry (expr **slot, FILE *file)
++{
++ struct expr *exprs = *slot;
++ struct occr *occr;
++
++ fprintf (file, "expr: ");
++ print_rtl (file, exprs->expr);
++ fprintf (file,"\nhashcode: %u\n", exprs->hash);
++ fprintf (file,"list of occurrences:\n");
++ occr = exprs->antic_occr;
++ while (occr)
++ {
++ rtx_insn *insn = occr->insn;
++ print_rtl_single (file, insn);
++ fprintf (file, "\n");
++ occr = occr->next;
++ }
++ fprintf (file, "\n");
++ return 1;
++}
++
++static void
++dump_hash_table (FILE *file)
++{
++ fprintf (file, "\n\nexpression hash table\n");
++ fprintf (file, "size %ld, %ld elements, %f collision/search ratio\n",
++ (long) expr_table->size (),
++ (long) expr_table->elements (),
++ expr_table->collisions ());
++ if (expr_table->elements () > 0)
++ {
++ fprintf (file, "\n\ntable entries:\n");
++ expr_table->traverse (file);
++ }
++ fprintf (file, "\n");
++}
++
++/* Insert expression X in INSN in the hash TABLE.
++ If it is already present, record it as the last occurrence in INSN's
++ basic block. */
++
++static void
++insert_expr_in_table (rtx x, rtx_insn *insn)
++{
++ int do_not_record_p;
++ hashval_t hash;
++ struct expr *cur_expr, **slot;
++ struct occr *antic_occr, *last_occr = NULL;
++
++ hash = hash_expr (x, &do_not_record_p);
++
++ /* Do not insert expression in the table if it contains volatile operands,
++ or if hash_expr determines the expression is something we don't want
++ to or can't handle. */
++ if (do_not_record_p)
++ return;
++
++ /* We anticipate that redundant expressions are rare, so for convenience
++ allocate a new hash table element here already and set its fields.
++ If we don't do this, we need a hack with a static struct expr. Anyway,
++ obstack_free is really fast and one more obstack_alloc doesn't hurt if
++ we're going to see more expressions later on. */
++ cur_expr = (struct expr *) obstack_alloc (&expr_obstack,
++ sizeof (struct expr));
++ cur_expr->expr = x;
++ cur_expr->hash = hash;
++ cur_expr->antic_occr = NULL;
++
++ slot = expr_table->find_slot_with_hash (cur_expr, hash, INSERT);
++
++ if (! (*slot))
++ /* The expression isn't found, so insert it. */
++ *slot = cur_expr;
++ else
++ {
++ /* The expression is already in the table, so roll back the
++ obstack and use the existing table entry. */
++ obstack_free (&expr_obstack, cur_expr);
++ cur_expr = *slot;
++ }
++
++ /* Search for another occurrence in the same basic block. */
++ antic_occr = cur_expr->antic_occr;
++ cur_expr->count++;
++ while (antic_occr
++ && BLOCK_FOR_INSN (antic_occr->insn) != BLOCK_FOR_INSN (insn))
++ {
++ /* If an occurrence isn't found, save a pointer to the end of
++ the list. */
++ last_occr = antic_occr;
++ antic_occr = antic_occr->next;
++ }
++
++ if (antic_occr)
++ /* Found another instance of the expression in the same basic block.
++ Prefer this occurrence to the currently recorded one. We want
++ the last one in the block and the block is scanned from start
++ to end. */
++ antic_occr->insn = insn;
++ else
++ {
++ /* First occurrence of this expression in this basic block. */
++ antic_occr = (struct occr *) obstack_alloc (&expr_obstack,
++ sizeof (struct occr));
++
++ /* First occurrence of this expression in any block? */
++ if (cur_expr->antic_occr == NULL)
++ cur_expr->antic_occr = antic_occr;
++ else
++ last_occr->next = antic_occr;
++
++ antic_occr->insn = insn;
++ antic_occr->next = NULL;
++ antic_occr->deleted_p = 0;
++ }
++}
++
++/* Check whether this instruction is supported format. */
++
++static void
++hash_scan_set (rtx_insn *insn)
++{
++ rtx pat = PATTERN (insn);
++ rtx src = SET_SRC (pat);
++ rtx dest = SET_DEST (pat);
++ int regno;
++ struct reg_avail_info *info;
++
++ /* Don't mess with jumps and nops. */
++ if (JUMP_P (insn) || set_noop_p (pat))
++ return;
++
++ /* TODO: support more format. */
++
++ /* Only consider locally anticipatable intructions currently. */
++ if (REG_P (dest) && REGNO (dest) <= SP_REGNUM)
++ {
++ regno = REGNO (dest);
++ info = ®_avail_info[regno];
++
++ if (BLOCK_FOR_INSN (insn) == info->last_bb
++ && info->first_set == DF_INSN_LUID (insn)
++ && info->first_use >= info->first_set)
++ {
++ /* Only support immediate input currently because
++ this is bugzilla case. */
++ if (CONST_INT_P (src) || CONST_DOUBLE_P (src))
++ insert_expr_in_table (PATTERN (insn), insn);
++ }
++ }
++}
++
++/* Record register first use information for REGNO in INSN.
++
++ first_use records the first place in the block where the register
++ is used and is used to compute "anticipatability".
++
++ last_bb records the block for which first_use is valid,
++ as a quick test to invalidate them. */
++
++static void
++record_first_reg_use_info (rtx_insn *insn, int regno)
++{
++ struct reg_avail_info *info = ®_avail_info[regno];
++ int luid = DF_INSN_LUID (insn);
++
++ if (info->last_bb != BLOCK_FOR_INSN (insn))
++ {
++ info->last_bb = BLOCK_FOR_INSN (insn);
++ info->first_use = luid;
++ /* Set the value to record the using is former than setting. */
++ info->first_set = luid + 1;
++ }
++}
++
++/* Called from compute_hash_table via note_stores to handle one
++ SET or CLOBBER in an insn. DATA is really the instruction in which
++ the SET is taking place. */
++
++static void
++record_first_use_info (rtx *dest, void *data)
++{
++ rtx_insn *last_set_insn = static_cast (data);
++ int i, j;
++ enum rtx_code code;
++ const char *fmt;
++ rtx x = *dest;
++
++ if (x == 0)
++ return;
++
++ code = GET_CODE (x);
++ if (REG_P (x) && REGNO (x) <= SP_REGNUM)
++ {
++ record_first_reg_use_info (last_set_insn, REGNO (x));
++ /* DF and DI mode may use two registers. */
++ if (GET_MODE_SIZE (GET_MODE (x)) == 8)
++ record_first_reg_use_info (last_set_insn, REGNO (x) + 1);
++ }
++
++ for (i = GET_RTX_LENGTH (code) - 1, fmt = GET_RTX_FORMAT (code); i >= 0; i--)
++ {
++ if (fmt[i] == 'e')
++ record_first_use_info (&XEXP (x, i), data);
++ else if (fmt[i] == 'E')
++ for (j = 0; j < XVECLEN (x, i); j++)
++ record_first_use_info (&XVECEXP (x, i, j), data);
++ }
++}
++
++/* Record register first/block set information for REGNO in INSN.
++
++ first_set records the first place in the block where the register
++ is set and is used to compute "anticipatability".
++
++ last_bb records the block for which first_set is valid,
++ as a quick test to invalidate them. */
++
++static void
++record_first_reg_set_info (rtx_insn *insn, int regno)
++{
++ struct reg_avail_info *info = ®_avail_info[regno];
++ int luid = DF_INSN_LUID (insn);
++
++ if (info->last_bb != BLOCK_FOR_INSN (insn))
++ {
++ info->last_bb = BLOCK_FOR_INSN (insn);
++ info->first_set = luid;
++ /* Set the value to record the using is later than setting. */
++ info->first_use = luid + 1;
++ }
++}
++
++/* Called from compute_hash_table via note_stores to handle one
++ SET or CLOBBER in an insn. DATA is really the instruction in which
++ the SET is taking place. */
++
++static void
++record_first_set_info (rtx dest, const_rtx setter ATTRIBUTE_UNUSED, void *data)
++{
++ rtx_insn *last_set_insn = static_cast (data);
++
++ if (GET_CODE (dest) == SUBREG)
++ dest = SUBREG_REG (dest);
++
++ if (REG_P (dest) && REGNO (dest) <= SP_REGNUM)
++ {
++ record_first_reg_set_info (last_set_insn, REGNO (dest));
++ if (GET_MODE_SIZE (GET_MODE (dest)) == 8)
++ record_first_reg_set_info (last_set_insn, REGNO (dest) + 1);
++ }
++}
++
++/* Build hash table for supported format instructions.
++ Only consider if the instruction is anticipatable in the basic block here.
++ We postpone the def-use check until hoisting. */
++
++static void
++compute_hash_table (void)
++{
++ basic_block bb;
++ int i;
++
++ /* We only take care hard registers. */
++ reg_avail_info =
++ (struct reg_avail_info *) xmalloc (sizeof (struct reg_avail_info) *
++ (SP_REGNUM + 1));
++
++ for (i = 0; i < 32; i++)
++ reg_avail_info[i].last_bb = NULL;
++
++ FOR_EACH_BB_FN (bb, cfun)
++ {
++ rtx_insn *insn;
++
++ /* Do not hoist instrucion from block which has more
++ than one predecessor. */
++ if (EDGE_COUNT (bb->preds) > 1)
++ continue;
++
++ FOR_BB_INSNS (bb, insn)
++ {
++ if (!NONDEBUG_INSN_P (insn))
++ continue;
++
++ /* Construct a caller save register barrier. We cannot hoist the
++ instruction over a function call which sets caller save
++ registers. */
++ if (CALL_P (insn))
++ {
++ for (i = 0; i <= SP_REGNUM; i++)
++ if (call_used_regs[i])
++ record_first_reg_use_info (insn, i);
++ }
++
++ note_uses (&PATTERN (insn), record_first_use_info, insn);
++ note_stores (PATTERN (insn), record_first_set_info, insn);
++ }
++
++ /* Build the hash table. */
++ FOR_BB_INSNS (bb, insn)
++ if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == SET)
++ hash_scan_set (insn);
++ }
++}
++
++/* Hoist instructions in this slot if possible. */
++int
++nds32_find_gcse_expr_table (expr **slot, void *data ATTRIBUTE_UNUSED)
++{
++ struct expr *exprs = *slot;
++ struct occr *occr;
++ rtx_insn *insn = NULL;
++ rtx_insn *last_insn;
++ basic_block bb;
++ edge e;
++ unsigned ix;
++ unsigned emit_done;
++ unsigned cover, regno;
++ df_ref use;
++ enum machine_mode mode;
++
++ if (exprs->count < 2)
++ return 1;
++
++ bitmap_vector_clear (hoist_vbeout, last_basic_block_for_fn (cfun));
++ bitmap_vector_clear (hoist_vbein, last_basic_block_for_fn (cfun));
++
++ /* Set the bit for this slot. */
++ occr = exprs->antic_occr;
++ while (occr)
++ {
++ insn = occr->insn;
++ bb = BLOCK_FOR_INSN (insn);
++ if (!occr->deleted_p)
++ bitmap_set_bit (hoist_vbein[bb->index], 0);
++ occr = occr->next;
++ }
++
++ /* Try to hoist code for each basic block. */
++ FOR_EACH_BB_REVERSE_FN (bb, cfun)
++ {
++ if (bb->next_bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
++ bitmap_intersection_of_succs (hoist_vbeout[bb->index], hoist_vbein, bb);
++
++ if (bitmap_bit_p (hoist_vbeout[bb->index], 0)
++ && EDGE_COUNT (bb->succs) > 1)
++ {
++ emit_done = 0;
++ cover = FALSE;
++ for (e = NULL, ix = 0; ix < EDGE_COUNT (bb->succs); ix++)
++ {
++ e = EDGE_SUCC (bb, ix);
++ if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
++ continue;
++ occr = exprs->antic_occr;
++ while (occr)
++ {
++ insn = occr->insn;
++ if (!occr->deleted_p && e->dest == BLOCK_FOR_INSN (insn))
++ break;
++ occr = occr->next;
++ }
++
++ gcc_assert (insn != NULL);
++
++ if (!emit_done)
++ {
++ last_insn = BB_END (bb);
++ /* Check the defined register is not used by the last
++ instruction of the previos block.*/
++ regno = REGNO (SET_DEST (PATTERN (insn)));
++ mode = GET_MODE (SET_DEST (PATTERN (insn)));
++ FOR_EACH_INSN_USE (use, last_insn)
++ {
++ if (DF_REF_REGNO (use) == regno
++ || regno_clobbered_p (regno, last_insn, mode, 2))
++ {
++ cover = TRUE;
++ break;
++ }
++ }
++
++ /* TODO: support more format. */
++ if (cover)
++ break;
++ else if (JUMP_P (last_insn))
++ {
++ emit_insn_before_noloc (PATTERN (insn), last_insn, bb);
++ emit_done = TRUE;
++ }
++ else
++ break;
++ }
++
++ if (emit_done)
++ {
++ delete_insn (insn);
++ occr->deleted_p = TRUE;
++ }
++ }
++ }
++ }
++ return 1;
++}
++
++static int
++hoist_code (void)
++{
++ hoist_vbein = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), 1);
++ hoist_vbeout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), 1);
++
++ expr_table->traverse (NULL);
++
++ sbitmap_vector_free (hoist_vbein);
++ sbitmap_vector_free (hoist_vbeout);
++
++ return 0;
++}
++
++
++static unsigned int
++nds32_gcse_opt (void)
++{
++
++ if (n_basic_blocks_for_fn (cfun) <= NUM_FIXED_BLOCKS + 1)
++ return 0;
++ /* Allocate memory for this pass.
++ Also computes and initializes the insns' CUIDs. */
++ alloc_mem ();
++
++ df_chain_add_problem (DF_DU_CHAIN);
++ df_insn_rescan_all ();
++ df_analyze ();
++
++ compute_hash_table ();
++
++ if (dump_file)
++ dump_hash_table (dump_file);
++
++ hoist_code ();
++
++ df_insn_rescan_all ();
++ free_mem ();
++ return 0;
++}
++
++const pass_data pass_data_nds32_gcse_opt =
++{
++ RTL_PASS, /* type */
++ "gcse_opt", /* name */
++ OPTGROUP_NONE, /* optinfo_flags */
++ TV_MACH_DEP, /* tv_id */
++ 0, /* properties_required */
++ 0, /* properties_provided */
++ 0, /* properties_destroyed */
++ 0, /* todo_flags_start */
++ 0, /* todo_flags_finish */
++};
++
++class pass_nds32_gcse_opt : public rtl_opt_pass
++{
++public:
++ pass_nds32_gcse_opt (gcc::context *ctxt)
++ : rtl_opt_pass (pass_data_nds32_gcse_opt, ctxt)
++ {}
++
++ /* opt_pass methods: */
++ bool gate (function *) { return TARGET_GCSE_OPT; }
++ unsigned int execute (function *) { return nds32_gcse_opt (); }
++};
++
++rtl_opt_pass *
++make_pass_nds32_gcse_opt (gcc::context *ctxt)
++{
++ return new pass_nds32_gcse_opt (ctxt);
++}
++
++/* ------------------------------------------------------------------------ */
+diff --git a/gcc/config/nds32/nds32-graywolf.md b/gcc/config/nds32/nds32-graywolf.md
+new file mode 100644
+index 0000000..f9ddbd8
+--- /dev/null
++++ b/gcc/config/nds32/nds32-graywolf.md
+@@ -0,0 +1,471 @@
++;; Pipeline descriptions of Andes NDS32 cpu for GNU compiler
++;; Copyright (C) 2012-2016 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 Graywolf pipeline settings.
++;; ------------------------------------------------------------------------
++
++(define_automaton "nds32_graywolf_machine")
++
++(define_cpu_unit "gw_ii_0" "nds32_graywolf_machine")
++(define_cpu_unit "gw_ii_1" "nds32_graywolf_machine")
++(define_cpu_unit "gw_ex_p0" "nds32_graywolf_machine")
++(define_cpu_unit "gw_mm_p0" "nds32_graywolf_machine")
++(define_cpu_unit "gw_wb_p0" "nds32_graywolf_machine")
++(define_cpu_unit "gw_ex_p1" "nds32_graywolf_machine")
++(define_cpu_unit "gw_mm_p1" "nds32_graywolf_machine")
++(define_cpu_unit "gw_wb_p1" "nds32_graywolf_machine")
++(define_cpu_unit "gw_iq_p2" "nds32_graywolf_machine")
++(define_cpu_unit "gw_rf_p2" "nds32_graywolf_machine")
++(define_cpu_unit "gw_e1_p2" "nds32_graywolf_machine")
++(define_cpu_unit "gw_e2_p2" "nds32_graywolf_machine")
++(define_cpu_unit "gw_e3_p2" "nds32_graywolf_machine")
++(define_cpu_unit "gw_e4_p2" "nds32_graywolf_machine")
++
++(define_reservation "gw_ii" "gw_ii_0 | gw_ii_1")
++(define_reservation "gw_ex" "gw_ex_p0 | gw_ex_p1")
++(define_reservation "gw_mm" "gw_mm_p0 | gw_mm_p1")
++(define_reservation "gw_wb" "gw_wb_p0 | gw_wb_p1")
++
++(define_reservation "gw_ii_all" "gw_ii_0 + gw_ii_1")
++
++(define_insn_reservation "nds_gw_unknown" 1
++ (and (eq_attr "type" "unknown")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_ex, gw_mm, gw_wb")
++
++(define_insn_reservation "nds_gw_misc" 1
++ (and (eq_attr "type" "misc")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_ex, gw_mm, gw_wb")
++
++(define_insn_reservation "nds_gw_mmu" 1
++ (and (eq_attr "type" "mmu")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_ex, gw_mm, gw_wb")
++
++(define_insn_reservation "nds_gw_alu" 1
++ (and (and (eq_attr "type" "alu")
++ (match_test "!nds32::movd44_insn_p (insn)"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_ex, gw_mm, gw_wb")
++
++(define_insn_reservation "nds_gw_movd44" 1
++ (and (and (eq_attr "type" "alu")
++ (match_test "nds32::movd44_insn_p (insn)"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex, gw_mm, gw_wb")
++
++(define_insn_reservation "nds_gw_alu_shift" 1
++ (and (eq_attr "type" "alu_shift")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_ex*2, gw_mm, gw_wb")
++
++(define_insn_reservation "nds_gw_pbsad" 1
++ (and (eq_attr "type" "pbsad")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_ex*3, gw_mm, gw_wb")
++
++(define_insn_reservation "nds_gw_pbsada" 1
++ (and (eq_attr "type" "pbsada")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_ex*3, gw_mm, gw_wb")
++
++(define_insn_reservation "nds_gw_load" 1
++ (and (and (eq_attr "type" "load")
++ (match_test "!nds32::post_update_insn_p (insn)"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_load_2w" 1
++ (and (and (eq_attr "type" "load")
++ (match_test "nds32::post_update_insn_p (insn)"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_all, gw_ex_p1, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_store" 1
++ (and (and (eq_attr "type" "store")
++ (match_test "!nds32::store_offset_reg_p (insn)"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_store_3r" 1
++ (and (and (eq_attr "type" "store")
++ (match_test "nds32::store_offset_reg_p (insn)"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_all, gw_ex_p1, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_load_multiple_1" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "1"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_load_multiple_2" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "2"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*2, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_load_multiple_3" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "3"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*3, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_load_multiple_4" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "4"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*4, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_load_multiple_5" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "5"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*4, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_load_multiple_6" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "6"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*4, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_load_multiple_7" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "7"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*4, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_load_multiple_8" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "8"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*4, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_load_multiple_12" 1
++ (and (and (eq_attr "type" "load_multiple")
++ (eq_attr "combo" "12"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*4, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_store_multiple_1" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "1"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_store_multiple_2" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "2"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*2, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_store_multiple_3" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "3"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*3, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_store_multiple_4" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "4"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*4, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_store_multiple_5" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "5"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*4, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_store_multiple_6" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "6"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*4, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_store_multiple_7" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "7"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*4, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_store_multiple_8" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "8"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*4, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_store_multiple_12" 1
++ (and (and (eq_attr "type" "store_multiple")
++ (eq_attr "combo" "12"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_1, gw_ex_p1*4, gw_mm_p1, gw_wb_p1")
++
++(define_insn_reservation "nds_gw_mul_fast1" 1
++ (and (match_test "nds32_mul_config == MUL_TYPE_FAST_1")
++ (and (eq_attr "type" "mul")
++ (eq_attr "pipeline_model" "graywolf")))
++ "gw_ii_0, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_mul_fast2" 1
++ (and (match_test "nds32_mul_config == MUL_TYPE_FAST_2")
++ (and (eq_attr "type" "mul")
++ (eq_attr "pipeline_model" "graywolf")))
++ "gw_ii_0, gw_ex_p0*2, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_mul_slow" 1
++ (and (match_test "nds32_mul_config == MUL_TYPE_SLOW")
++ (and (eq_attr "type" "mul")
++ (eq_attr "pipeline_model" "graywolf")))
++ "gw_ii_0, gw_ex_p0*4, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_mac_fast1" 1
++ (and (match_test "nds32_mul_config == MUL_TYPE_FAST_1")
++ (and (eq_attr "type" "mac")
++ (eq_attr "pipeline_model" "graywolf")))
++ "gw_ii_all, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_mac_fast2" 1
++ (and (match_test "nds32_mul_config == MUL_TYPE_FAST_2")
++ (and (eq_attr "type" "mac")
++ (eq_attr "pipeline_model" "graywolf")))
++ "gw_ii_all, gw_ex_p0*2, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_mac_slow" 1
++ (and (match_test "nds32_mul_config == MUL_TYPE_SLOW")
++ (and (eq_attr "type" "mac")
++ (eq_attr "pipeline_model" "graywolf")))
++ "gw_ii_all, gw_ex_p0*4, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_div" 1
++ (and (and (eq_attr "type" "div")
++ (match_test "!nds32::divmod_p (insn)"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_0, gw_ex_p0*4, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_div_2w" 1
++ (and (and (eq_attr "type" "div")
++ (match_test "nds32::divmod_p (insn)"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_all, gw_ex_p0*4, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_branch" 1
++ (and (eq_attr "type" "branch")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_0, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_dsp_alu" 1
++ (and (eq_attr "type" "dalu")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_ex, gw_mm, gw_wb")
++
++(define_insn_reservation "nds_gw_dsp_alu64" 1
++ (and (eq_attr "type" "dalu64")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_all, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_dsp_alu_round" 1
++ (and (eq_attr "type" "daluround")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_0, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_dsp_cmp" 1
++ (and (eq_attr "type" "dcmp")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_0, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_dsp_clip" 1
++ (and (eq_attr "type" "dclip")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_0, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_dsp_mul" 1
++ (and (eq_attr "type" "dmul")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_0, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_dsp_mac" 1
++ (and (eq_attr "type" "dmac")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_all, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_dsp_insb" 1
++ (and (eq_attr "type" "dinsb")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_0, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_dsp_pack" 1
++ (and (eq_attr "type" "dpack")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_0, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_dsp_bpick" 1
++ (and (eq_attr "type" "dbpick")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_0, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_dsp_wext" 1
++ (and (eq_attr "type" "dwext")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii_all, gw_ex_p0, gw_mm_p0, gw_wb_p0")
++
++(define_insn_reservation "nds_gw_fpu_alu" 4
++ (and (eq_attr "type" "falu")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_iq_p2, gw_rf_p2, gw_e1_p2, gw_e2_p2, gw_e3_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_muls" 4
++ (and (eq_attr "type" "fmuls")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_iq_p2, gw_rf_p2, gw_e1_p2, gw_e2_p2, gw_e3_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_muld" 4
++ (and (eq_attr "type" "fmuld")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_iq_p2, gw_rf_p2, gw_e1_p2, gw_e2_p2*2, gw_e3_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_macs" 4
++ (and (eq_attr "type" "fmacs")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_iq_p2, gw_rf_p2, gw_e1_p2, gw_e2_p2*3, gw_e3_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_macd" 4
++ (and (eq_attr "type" "fmacd")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_iq_p2, gw_rf_p2, gw_e1_p2, gw_e2_p2*4, gw_e3_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_divs" 4
++ (and (ior (eq_attr "type" "fdivs")
++ (eq_attr "type" "fsqrts"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_iq_p2, gw_rf_p2, gw_e1_p2, gw_e2_p2*14, gw_e3_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_divd" 4
++ (and (ior (eq_attr "type" "fdivd")
++ (eq_attr "type" "fsqrtd"))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_iq_p2, gw_rf_p2, gw_e1_p2, gw_e2_p2*28, gw_e3_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_fast_alu" 2
++ (and (ior (eq_attr "type" "fcmp")
++ (ior (eq_attr "type" "fabs")
++ (ior (eq_attr "type" "fcpy")
++ (eq_attr "type" "fcmov"))))
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_iq_p2, gw_rf_p2, gw_e1_p2, gw_e2_p2, gw_e3_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_fmtsr" 1
++ (and (eq_attr "type" "fmtsr")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_iq_p2, gw_rf_p2, gw_e1_p2, gw_e2_p2, gw_e3_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_fmtdr" 1
++ (and (eq_attr "type" "fmtdr")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_ii+gw_iq_p2, gw_iq_p2+gw_rf_p2, gw_rf_p2+gw_e1_p2, gw_e1_p2+gw_e2_p2, gw_e2_p2+gw_e3_p2, gw_e3_p2+gw_e4_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_fmfsr" 1
++ (and (eq_attr "type" "fmfsr")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_iq_p2, gw_rf_p2, gw_e1_p2, gw_e2_p2, gw_e3_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_fmfdr" 1
++ (and (eq_attr "type" "fmfdr")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_ii+gw_iq_p2, gw_iq_p2+gw_rf_p2, gw_rf_p2+gw_e1_p2, gw_e1_p2+gw_e2_p2, gw_e2_p2+gw_e3_p2, gw_e3_p2+gw_e4_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_load" 3
++ (and (eq_attr "type" "fload")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_iq_p2, gw_rf_p2, gw_e1_p2, gw_e2_p2, gw_e3_p2, gw_e4_p2")
++
++(define_insn_reservation "nds_gw_fpu_store" 1
++ (and (eq_attr "type" "fstore")
++ (eq_attr "pipeline_model" "graywolf"))
++ "gw_ii, gw_iq_p2, gw_rf_p2, gw_e1_p2, gw_e2_p2, gw_e3_p2, gw_e4_p2")
++
++;; FPU_ADDR_OUT -> FPU_ADDR_IN
++;; Main pipeline rules don't need this because those default latency is 1.
++(define_bypass 1
++ "nds_gw_fpu_load, nds_gw_fpu_store"
++ "nds_gw_fpu_load, nds_gw_fpu_store"
++ "nds32_gw_ex_to_ex_p"
++)
++
++;; LD, MUL, MAC, DIV, DALU64, DMUL, DMAC, DALUROUND, DBPICK, DWEXT
++;; -> ALU, ALU_SHIFT_Rb, PBSAD, PBSADA_RaRb, MOVD44, MUL, MAC_RaRb, DIV, ADDR_IN, BR, MMU,
++;; DALU, DALUROUND, DMUL, DMAC_RaRb, DPACK, DINSB, DCMP, DCLIP, WEXT_O, BPICK_RaRb
++(define_bypass 2
++ "nds_gw_load, nds_gw_load_2w,\
++ nds_gw_mul_fast1, nds_gw_mul_fast2, nds_gw_mul_slow,\
++ nds_gw_mac_fast1, nds_gw_mac_fast2, nds_gw_mac_slow,\
++ nds_gw_div, nds_gw_div_2w,\
++ nds_gw_dsp_alu64, nds_gw_dsp_mul, nds_gw_dsp_mac,\
++ nds_gw_dsp_alu_round, nds_gw_dsp_bpick, nds_gw_dsp_wext"
++ "nds_gw_alu, nds_gw_movd44, nds_gw_alu_shift,\
++ nds_gw_pbsad, nds_gw_pbsada,\
++ nds_gw_mul_fast1, nds_gw_mul_fast2, nds_gw_mul_slow,\
++ nds_gw_mac_fast1, nds_gw_mac_fast2, nds_gw_mac_slow,\
++ nds_gw_branch,\
++ nds_gw_div, nds_gw_div_2w,\
++ nds_gw_load, nds_gw_load_2w, nds_gw_store, nds_gw_store_3r,\
++ nds_gw_load_multiple_1,nds_gw_load_multiple_2, nds_gw_load_multiple_3,\
++ nds_gw_load_multiple_4,nds_gw_load_multiple_5, nds_gw_load_multiple_6,\
++ nds_gw_load_multiple_7,nds_gw_load_multiple_8, nds_gw_load_multiple_12,\
++ nds_gw_store_multiple_1,nds_gw_store_multiple_2, nds_gw_store_multiple_3,\
++ nds_gw_store_multiple_4,nds_gw_store_multiple_5, nds_gw_store_multiple_6,\
++ nds_gw_store_multiple_7,nds_gw_store_multiple_8, nds_gw_store_multiple_12,\
++ nds_gw_mmu,\
++ nds_gw_dsp_alu, nds_gw_dsp_alu_round,\
++ nds_gw_dsp_mul, nds_gw_dsp_mac, nds_gw_dsp_pack,\
++ nds_gw_dsp_insb, nds_gw_dsp_cmp, nds_gw_dsp_clip,\
++ nds_gw_dsp_wext, nds_gw_dsp_bpick"
++ "nds32_gw_mm_to_ex_p"
++)
++
++;; LMW(N, N)
++;; -> ALU, ALU_SHIFT_Rb, PBSAD, PBSADA_RaRb, MOVD44, MUL, MAC_RaRb, DIV, ADDR_IN, BR, MMU
++;; DALU, DALUROUND, DMUL, DMAC_RaRb, DPACK, DINSB, DCMP, DCLIP, WEXT_O, BPICK_RaRb
++(define_bypass 2
++ "nds_gw_load_multiple_1,nds_gw_load_multiple_2, nds_gw_load_multiple_3,\
++ nds_gw_load_multiple_4,nds_gw_load_multiple_5, nds_gw_load_multiple_6,\
++ nds_gw_load_multiple_7,nds_gw_load_multiple_8, nds_gw_load_multiple_12"
++ "nds_gw_alu, nds_gw_movd44, nds_gw_alu_shift,\
++ nds_gw_pbsad, nds_gw_pbsada,\
++ nds_gw_mul_fast1, nds_gw_mul_fast2, nds_gw_mul_slow,\
++ nds_gw_mac_fast1, nds_gw_mac_fast2, nds_gw_mac_slow,\
++ nds_gw_branch,\
++ nds_gw_div, nds_gw_div_2w,\
++ nds_gw_load, nds_gw_load_2w, nds_gw_store, nds_gw_store_3r,\
++ nds_gw_load_multiple_1,nds_gw_load_multiple_2, nds_gw_load_multiple_3,\
++ nds_gw_load_multiple_4,nds_gw_load_multiple_5, nds_gw_load_multiple_6,\
++ nds_gw_load_multiple_7,nds_gw_load_multiple_8, nds_gw_load_multiple_12,\
++ nds_gw_store_multiple_1,nds_gw_store_multiple_2, nds_gw_store_multiple_3,\
++ nds_gw_store_multiple_4,nds_gw_store_multiple_5, nds_gw_store_multiple_6,\
++ nds_gw_store_multiple_7,nds_gw_store_multiple_8, nds_gw_store_multiple_12,\
++ nds_gw_mmu,\
++ nds_gw_dsp_alu, nds_gw_dsp_alu_round,\
++ nds_gw_dsp_mul, nds_gw_dsp_mac, nds_gw_dsp_pack,\
++ nds_gw_dsp_insb, nds_gw_dsp_cmp, nds_gw_dsp_clip,\
++ nds_gw_dsp_wext, nds_gw_dsp_bpick"
++ "nds32_gw_last_load_to_ex_p"
++)
+diff --git a/gcc/config/nds32/nds32-intrinsic.c b/gcc/config/nds32/nds32-intrinsic.c
+index fabf262..7547fb1 100644
+--- a/gcc/config/nds32/nds32-intrinsic.c
++++ b/gcc/config/nds32/nds32-intrinsic.c
+@@ -24,210 +24,1867 @@
+ #include "system.h"
+ #include "coretypes.h"
+ #include "backend.h"
+-#include "target.h"
+-#include "rtl.h"
+ #include "tree.h"
+-#include "optabs.h" /* For GEN_FCN. */
+-#include "diagnostic-core.h"
++#include "rtl.h"
++#include "df.h"
++#include "alias.h"
+ #include "stor-layout.h"
++#include "varasm.h"
++#include "calls.h"
++#include "regs.h"
++#include "insn-config.h" /* Required by recog.h. */
++#include "conditions.h"
++#include "output.h"
++#include "insn-attr.h" /* For DFA state_t. */
++#include "insn-codes.h" /* For CODE_FOR_xxx. */
++#include "reload.h" /* For push_reload(). */
++#include "flags.h"
++#include "insn-config.h"
++#include "expmed.h"
++#include "dojump.h"
++#include "explow.h"
++#include "emit-rtl.h"
++#include "stmt.h"
+ #include "expr.h"
++#include "recog.h"
++#include "diagnostic-core.h"
++#include "cfgrtl.h"
++#include "cfganal.h"
++#include "lcm.h"
++#include "cfgbuild.h"
++#include "cfgcleanup.h"
++#include "tm_p.h"
++#include "tm-constrs.h"
++#include "optabs.h" /* For GEN_FCN. */
++#include "target.h"
+ #include "langhooks.h" /* For add_builtin_function(). */
++#include "builtins.h"
+
+ /* ------------------------------------------------------------------------ */
+
+-/* Function to expand builtin function for
+- '[(unspec_volatile [(reg)])]'. */
++/* Read the requested argument from the EXP given by INDEX.
++ Return the value as an rtx. */
++static rtx
++nds32_read_argument (tree exp, unsigned int index)
++{
++ return expand_normal (CALL_EXPR_ARG (exp, index));
++}
++
++/* Return a legitimate rtx for instruction ICODE's return value. Use TARGET
++ if it's not null, has the right mode, and satisfies operand 0's
++ predicate. */
++static rtx
++nds32_legitimize_target (enum insn_code icode, rtx target)
++{
++ enum machine_mode mode = insn_data[icode].operand[0].mode;
++
++ if (! target
++ || GET_MODE (target) != mode
++ || ! (*insn_data[icode].operand[0].predicate) (target, mode))
++ return gen_reg_rtx (mode);
++ else
++ return target;
++}
++
++/* Given that ARG is being passed as operand OPNUM to instruction ICODE,
++ check whether ARG satisfies the operand's constraints. If it doesn't,
++ copy ARG to a temporary register and return that. Otherwise return ARG
++ itself. */
+ static rtx
+-nds32_expand_builtin_null_ftype_reg (enum insn_code icode,
+- tree exp, rtx target)
++nds32_legitimize_argument (enum insn_code icode, int opnum, rtx arg)
++{
++ enum machine_mode mode = insn_data[icode].operand[opnum].mode;
++
++ if ((*insn_data[icode].operand[opnum].predicate) (arg, mode))
++ return arg;
++ else if (VECTOR_MODE_P (mode) && CONST_INT_P (arg))
++ {
++ /* Handle CONST_INT covert to CONST_VECTOR. */
++ int nunits = GET_MODE_NUNITS (mode);
++ int i, shift = 0;
++ rtvec v = rtvec_alloc (nunits);
++ int val = INTVAL (arg);
++ enum machine_mode val_mode = (mode == V4QImode) ? QImode : HImode;
++ int shift_acc = (val_mode == QImode) ? 8 : 16;
++ int mask = (val_mode == QImode) ? 0xff : 0xffff;
++ int tmp_val = val;
++
++ if (TARGET_BIG_ENDIAN)
++ for (i = 0; i < nunits; i++)
++ {
++ tmp_val = (val >> shift) & mask;
++ RTVEC_ELT (v, nunits - i - 1) = gen_int_mode (tmp_val, val_mode);
++ shift += shift_acc;
++ }
++ else
++ for (i = 0; i < nunits; i++)
++ {
++ tmp_val = (val >> shift) & mask;
++ RTVEC_ELT (v, i) = gen_int_mode (tmp_val, val_mode);
++ shift += shift_acc;
++ }
++
++ return copy_to_mode_reg (mode, gen_rtx_CONST_VECTOR (mode, v));
++ }
++ else
++ {
++ rtx tmp_rtx = gen_reg_rtx (mode);
++ convert_move (tmp_rtx, arg, false);
++ return tmp_rtx;
++ }
++}
++
++/* Return true if OPVAL can be used for operand OPNUM of instruction ICODE.
++ The instruction should require a constant operand of some sort. The
++ function prints an error if OPVAL is not valid. */
++static int
++nds32_check_constant_argument (enum insn_code icode, int opnum, rtx opval,
++ const char *name)
+ {
+- /* Mapping:
+- ops[0] <--> value0 <--> arg0 */
+- struct expand_operand ops[1];
+- tree arg0;
+- rtx value0;
++ if (GET_CODE (opval) != CONST_INT)
++ {
++ error ("invalid argument to built-in function %s", name);
++ return false;
++ }
++ if (! (*insn_data[icode].operand[opnum].predicate) (opval, VOIDmode))
++ {
++ error ("constant argument out of range for %s", name);
++
++ return false;
++ }
++ return true;
++}
+
+- /* Grab the incoming arguments and extract its rtx. */
+- arg0 = CALL_EXPR_ARG (exp, 0);
+- value0 = expand_normal (arg0);
++/* Expand builtins that return target. */
++static rtx
++nds32_expand_noarg_builtin (enum insn_code icode, rtx target)
++{
++ rtx pat;
+
+- /* Create operands. */
+- create_input_operand (&ops[0], value0, TYPE_MODE (TREE_TYPE (arg0)));
++ target = nds32_legitimize_target (icode, target);
+
+- /* Emit new instruction. */
+- if (!maybe_expand_insn (icode, 1, ops))
+- error ("invalid argument to built-in function");
++ /* Emit and return the new instruction. */
++ pat = GEN_FCN (icode) (target);
++ if (! pat)
++ return NULL_RTX;
+
++ emit_insn (pat);
+ return target;
+ }
+
+-/* Function to expand builtin function for
+- '[(set (reg) (unspec_volatile [(imm)]))]'. */
++/* Expand builtins that take one operand. */
+ static rtx
+-nds32_expand_builtin_reg_ftype_imm (enum insn_code icode,
+- tree exp, rtx target)
++nds32_expand_unop_builtin (enum insn_code icode, tree exp, rtx target,
++ bool return_p)
+ {
+- /* Mapping:
+- ops[0] <--> target <--> exp
+- ops[1] <--> value0 <--> arg0 */
+- struct expand_operand ops[2];
+- tree arg0;
+- rtx value0;
++ rtx pat;
++ rtx op0 = nds32_read_argument (exp, 0);
++ int op0_num = return_p ? 1 : 0;
++
++ if (return_p)
++ target = nds32_legitimize_target (icode, target);
+
+- /* Grab the incoming arguments and extract its rtx. */
+- arg0 = CALL_EXPR_ARG (exp, 0);
+- value0 = expand_normal (arg0);
++ op0 = nds32_legitimize_argument (icode, op0_num, op0);
+
+- /* Create operands. */
+- create_output_operand (&ops[0], target, TYPE_MODE (TREE_TYPE (exp)));
+- create_input_operand (&ops[1], value0, TYPE_MODE (TREE_TYPE (arg0)));
++ /* Emit and return the new instruction. */
++ if (return_p)
++ pat = GEN_FCN (icode) (target, op0);
++ else
++ pat = GEN_FCN (icode) (op0);
+
+- /* Emit new instruction. */
+- if (!maybe_expand_insn (icode, 2, ops))
+- error ("invalid argument to built-in function");
++ if (! pat)
++ return NULL_RTX;
+
++ emit_insn (pat);
+ return target;
+ }
+
+-/* Function to expand builtin function for
+- '[(unspec_volatile [(reg) (imm)])]' pattern. */
++/* Expand builtins that take one operands and the first is immediate. */
+ static rtx
+-nds32_expand_builtin_null_ftype_reg_imm (enum insn_code icode,
+- tree exp, rtx target)
+-{
+- /* Mapping:
+- ops[0] <--> value0 <--> arg0
+- ops[1] <--> value1 <--> arg1 */
+- struct expand_operand ops[2];
+- tree arg0, arg1;
+- rtx value0, value1;
+-
+- /* Grab the incoming arguments and extract its rtx. */
+- arg0 = CALL_EXPR_ARG (exp, 0);
+- arg1 = CALL_EXPR_ARG (exp, 1);
+- value0 = expand_normal (arg0);
+- value1 = expand_normal (arg1);
+-
+- /* Create operands. */
+- create_input_operand (&ops[0], value0, TYPE_MODE (TREE_TYPE (arg0)));
+- create_input_operand (&ops[1], value1, TYPE_MODE (TREE_TYPE (arg1)));
+-
+- /* Emit new instruction. */
+- if (!maybe_expand_insn (icode, 2, ops))
+- error ("invalid argument to built-in function");
++nds32_expand_unopimm_builtin (enum insn_code icode, tree exp, rtx target,
++ bool return_p, const char *name)
++{
++ rtx pat;
++ rtx op0 = nds32_read_argument (exp, 0);
++ int op0_num = return_p ? 1 : 0;
++
++ if (return_p)
++ target = nds32_legitimize_target (icode, target);
++
++ if (!nds32_check_constant_argument (icode, op0_num, op0, name))
++ return NULL_RTX;
++
++ op0 = nds32_legitimize_argument (icode, op0_num, op0);
+
++ /* Emit and return the new instruction. */
++ if (return_p)
++ pat = GEN_FCN (icode) (target, op0);
++ else
++ pat = GEN_FCN (icode) (op0);
++
++ if (! pat)
++ return NULL_RTX;
++
++ emit_insn (pat);
+ return target;
+ }
+
+-/* ------------------------------------------------------------------------ */
++/* Expand builtins that take two operands. */
++static rtx
++nds32_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
++ bool return_p)
++{
++ rtx pat;
++ rtx op0 = nds32_read_argument (exp, 0);
++ rtx op1 = nds32_read_argument (exp, 1);
++ int op0_num = return_p ? 1 : 0;
++ int op1_num = return_p ? 2 : 1;
+
+-void
+-nds32_init_builtins_impl (void)
++ if (return_p)
++ target = nds32_legitimize_target (icode, target);
++
++ op0 = nds32_legitimize_argument (icode, op0_num, op0);
++ op1 = nds32_legitimize_argument (icode, op1_num, op1);
++
++ /* Emit and return the new instruction. */
++ if (return_p)
++ pat = GEN_FCN (icode) (target, op0, op1);
++ else
++ pat = GEN_FCN (icode) (op0, op1);
++
++ if (! pat)
++ return NULL_RTX;
++
++ emit_insn (pat);
++ return target;
++}
++
++/* Expand builtins that take two operands and the second is immediate. */
++static rtx
++nds32_expand_binopimm_builtin (enum insn_code icode, tree exp, rtx target,
++ bool return_p, const char *name)
+ {
+- tree pointer_type_node = build_pointer_type (integer_type_node);
++ rtx pat;
++ rtx op0 = nds32_read_argument (exp, 0);
++ rtx op1 = nds32_read_argument (exp, 1);
++ int op0_num = return_p ? 1 : 0;
++ int op1_num = return_p ? 2 : 1;
+
+- tree void_ftype_void = build_function_type (void_type_node,
+- void_list_node);
++ if (return_p)
++ target = nds32_legitimize_target (icode, target);
+
+- tree void_ftype_pint = build_function_type_list (void_type_node,
+- pointer_type_node,
+- NULL_TREE);
++ if (!nds32_check_constant_argument (icode, op1_num, op1, name))
++ return NULL_RTX;
+
+- tree int_ftype_int = build_function_type_list (integer_type_node,
+- integer_type_node,
+- NULL_TREE);
++ op0 = nds32_legitimize_argument (icode, op0_num, op0);
++ op1 = nds32_legitimize_argument (icode, op1_num, op1);
+
+- tree void_ftype_int_int = build_function_type_list (void_type_node,
+- integer_type_node,
+- integer_type_node,
+- NULL_TREE);
++ /* Emit and return the new instruction. */
++ if (return_p)
++ pat = GEN_FCN (icode) (target, op0, op1);
++ else
++ pat = GEN_FCN (icode) (op0, op1);
+
+- /* Cache. */
+- add_builtin_function ("__builtin_nds32_isync", void_ftype_pint,
+- NDS32_BUILTIN_ISYNC,
+- BUILT_IN_MD, NULL, NULL_TREE);
+- add_builtin_function ("__builtin_nds32_isb", void_ftype_void,
+- NDS32_BUILTIN_ISB,
+- BUILT_IN_MD, NULL, NULL_TREE);
++ if (! pat)
++ return NULL_RTX;
+
+- /* Register Transfer. */
+- add_builtin_function ("__builtin_nds32_mfsr", int_ftype_int,
+- NDS32_BUILTIN_MFSR,
+- BUILT_IN_MD, NULL, NULL_TREE);
+- add_builtin_function ("__builtin_nds32_mfusr", int_ftype_int,
+- NDS32_BUILTIN_MFUSR,
+- BUILT_IN_MD, NULL, NULL_TREE);
+- add_builtin_function ("__builtin_nds32_mtsr", void_ftype_int_int,
+- NDS32_BUILTIN_MTSR,
+- BUILT_IN_MD, NULL, NULL_TREE);
+- add_builtin_function ("__builtin_nds32_mtusr", void_ftype_int_int,
+- NDS32_BUILTIN_MTUSR,
+- BUILT_IN_MD, NULL, NULL_TREE);
++ emit_insn (pat);
++ return target;
++}
+
+- /* Interrupt. */
+- add_builtin_function ("__builtin_nds32_setgie_en", void_ftype_void,
+- NDS32_BUILTIN_SETGIE_EN,
+- BUILT_IN_MD, NULL, NULL_TREE);
+- add_builtin_function ("__builtin_nds32_setgie_dis", void_ftype_void,
+- NDS32_BUILTIN_SETGIE_DIS,
+- BUILT_IN_MD, NULL, NULL_TREE);
++/* Expand builtins that take three operands. */
++static rtx
++nds32_expand_triop_builtin (enum insn_code icode, tree exp, rtx target,
++ bool return_p)
++{
++ rtx pat;
++ rtx op0 = nds32_read_argument (exp, 0);
++ rtx op1 = nds32_read_argument (exp, 1);
++ rtx op2 = nds32_read_argument (exp, 2);
++ int op0_num = return_p ? 1 : 0;
++ int op1_num = return_p ? 2 : 1;
++ int op2_num = return_p ? 3 : 2;
++
++ if (return_p)
++ target = nds32_legitimize_target (icode, target);
++
++ op0 = nds32_legitimize_argument (icode, op0_num, op0);
++ op1 = nds32_legitimize_argument (icode, op1_num, op1);
++ op2 = nds32_legitimize_argument (icode, op2_num, op2);
++
++ /* Emit and return the new instruction. */
++ if (return_p)
++ pat = GEN_FCN (icode) (target, op0, op1, op2);
++ else
++ pat = GEN_FCN (icode) (op0, op1, op2);
++
++ if (! pat)
++ return NULL_RTX;
++
++ emit_insn (pat);
++ return target;
++}
++
++/* Expand builtins that take three operands and the third is immediate. */
++static rtx
++nds32_expand_triopimm_builtin (enum insn_code icode, tree exp, rtx target,
++ bool return_p, const char *name)
++{
++ rtx pat;
++ rtx op0 = nds32_read_argument (exp, 0);
++ rtx op1 = nds32_read_argument (exp, 1);
++ rtx op2 = nds32_read_argument (exp, 2);
++ int op0_num = return_p ? 1 : 0;
++ int op1_num = return_p ? 2 : 1;
++ int op2_num = return_p ? 3 : 2;
++
++ if (return_p)
++ target = nds32_legitimize_target (icode, target);
++
++ if (!nds32_check_constant_argument (icode, op2_num, op2, name))
++ return NULL_RTX;
++
++ op0 = nds32_legitimize_argument (icode, op0_num, op0);
++ op1 = nds32_legitimize_argument (icode, op1_num, op1);
++ op2 = nds32_legitimize_argument (icode, op2_num, op2);
++
++ /* Emit and return the new instruction. */
++ if (return_p)
++ pat = GEN_FCN (icode) (target, op0, op1, op2);
++ else
++ pat = GEN_FCN (icode) (op0, op1, op2);
++
++ if (! pat)
++ return NULL_RTX;
++
++ emit_insn (pat);
++ return target;
++}
++
++/* Expand builtins for load. */
++static rtx
++nds32_expand_builtin_load (enum insn_code icode, tree exp, rtx target)
++{
++ /* Load address format is [$ra + $rb],
++ but input arguments not enough,
++ so we need another temp register as $rb.
++ Generating assembly code:
++ movi $temp, 0
++ llw $rt, [$ra + $temp] */
++ rtx pat;
++ rtx op0 = nds32_read_argument (exp, 0);
++ rtx addr_helper = gen_reg_rtx (insn_data[icode].operand[1].mode);
++
++ target = nds32_legitimize_target (icode, target);
++ op0 = nds32_legitimize_argument (icode, 1, op0);
++
++ /* Emit and return the new instruction. */
++ pat = GEN_FCN (icode) (target, op0, addr_helper);
++ if (!pat)
++ return NULL_RTX;
++
++ emit_move_insn (addr_helper, GEN_INT (0));
++ emit_insn (pat);
++ return target;
++}
++
++/* Expand builtins for store. */
++static rtx
++nds32_expand_builtin_store (enum insn_code icode, tree exp, rtx target)
++{
++ /* Store address format is [$ra + $rb],
++ but input arguments not enough,
++ so we need another temp register as $rb.
++ Generating assembly code:
++ movi $temp, 0
++ store $rt, [$ra + $temp] */
++ rtx pat;
++ rtx op0 = nds32_read_argument (exp, 0);
++ rtx op1 = nds32_read_argument (exp, 1);
++ rtx addr_helper = gen_reg_rtx (insn_data[icode].operand[1].mode);
++
++ op0 = nds32_legitimize_argument (icode, 0, op0);
++ op1 = nds32_legitimize_argument (icode, 2, op1);
++
++ /* Emit and return the new instruction. */
++ pat = GEN_FCN (icode) (op0, addr_helper, op1);
++ if (! pat)
++ return NULL_RTX;
++
++ emit_move_insn (addr_helper, GEN_INT (0));
++ emit_insn (pat);
++ return target;
++}
++
++/* Expand cctl builtins. */
++static rtx
++nds32_expand_cctl_builtin (enum insn_code icode, tree exp, rtx target,
++ bool return_p, const char *name)
++{
++ rtx pat;
++ rtx op0 = nds32_read_argument (exp, 0);
++ rtx op1 = nds32_read_argument (exp, 1);
++ int op0_num = return_p ? 1 : 0;
++ int op1_num = return_p ? 2 : 1;
++
++ if (return_p)
++ target = nds32_legitimize_target (icode, target);
++
++ if (!nds32_check_constant_argument (icode, op0_num, op0, name))
++ return NULL_RTX;
++
++ op0 = nds32_legitimize_argument (icode, op0_num, op0);
++ op1 = nds32_legitimize_argument (icode, op1_num, op1);
++
++ /* Emit and return the new instruction. */
++ if (icode == CODE_FOR_cctl_idx_write)
++ {
++ /* cctl_idx_write is three argument,
++ so create operand2 for cctl_idx_write pattern. */
++ rtx op2 = nds32_read_argument (exp, 2);
++ op2 = nds32_legitimize_argument (icode, 2, op2);
++ pat = GEN_FCN (icode) (op0, op1, op2);
++ }
++ else if (return_p)
++ pat = GEN_FCN (icode) (target, op0, op1);
++ else
++ pat = GEN_FCN (icode) (op0, op1);
++
++ if (! pat)
++ return NULL_RTX;
++
++ emit_insn (pat);
++ return target;
++}
++
++/* Expand scw builtins. */
++static rtx
++nds32_expand_scw_builtin (enum insn_code icode, tree exp, rtx target)
++{
++ /* SCW address format is [$ra + $rb], but input arguments not enough,
++ so we need another temp register as $rb.
++ Generating assembly code:
++ movi $temp, 0
++ scw $rt, [$ra + $temp] */
++ rtx pat;
++ rtx op0 = nds32_read_argument (exp, 0);
++ rtx op1 = nds32_read_argument (exp, 1);
++ rtx addr_helper = gen_reg_rtx (insn_data[icode].operand[1].mode);
++
++ target = nds32_legitimize_target (icode, target);
++ op0 = nds32_legitimize_argument (icode, 1, op0);
++ op1 = nds32_legitimize_argument (icode, 2, op1);
++
++ /* Emit and return the new instruction. */
++ pat = GEN_FCN (icode) (target, op0, addr_helper, target);
++
++ if (!pat)
++ return NULL_RTX;
++
++ emit_move_insn (addr_helper, GEN_INT (0));
++ emit_move_insn (target, op1);
++ emit_insn (pat);
++ return target;
+ }
+
++/* Expand set int priority builtins. */
++static rtx
++nds32_expand_priority_builtin (enum insn_code icode, tree exp, rtx target,
++ const char *name)
++{
++ rtx pat;
++ rtx op0 = nds32_read_argument (exp, 0);
++ rtx op1 = nds32_read_argument (exp, 1);
++
++ /* set_int_priority intrinsic function that two arguments are immediate,
++ so check whether auguments are immedite. */
++
++ if (!nds32_check_constant_argument (icode, 0, op0, name))
++ return NULL_RTX;
++
++ if (!nds32_check_constant_argument (icode, 1, op1, name))
++ return NULL_RTX;
++
++ op0 = nds32_legitimize_argument (icode, 0, op0);
++ op1 = nds32_legitimize_argument (icode, 1, op1);
++
++ /* Emit and return the new instruction. */
++ pat = GEN_FCN (icode) (op0, op1);
++
++ if (! pat)
++ return NULL_RTX;
++
++ emit_insn (pat);
++ return target;
++}
++
++struct builtin_description
++{
++ const enum insn_code icode;
++ const char *name;
++ enum nds32_builtins code;
++ bool return_p;
++};
++
++#define NDS32_BUILTIN(code, string, builtin) \
++ { CODE_FOR_##code, "__nds32__" string, \
++ NDS32_BUILTIN_##builtin, true },
++
++#define NDS32_NO_TARGET_BUILTIN(code, string, builtin) \
++ { CODE_FOR_##code, "__nds32__" string, \
++ NDS32_BUILTIN_##builtin, false },
++
++/* Intrinsics that no argument, and that return value. */
++static struct builtin_description bdesc_noarg[] =
++{
++ NDS32_BUILTIN(unspec_fmfcfg, "fmfcfg", FMFCFG)
++ NDS32_BUILTIN(unspec_fmfcsr, "fmfcsr", FMFCSR)
++ NDS32_BUILTIN(unspec_volatile_rdov, "rdov", RDOV)
++ NDS32_BUILTIN(unspec_get_current_sp, "get_current_sp", GET_CURRENT_SP)
++ NDS32_BUILTIN(unspec_return_address, "return_address", RETURN_ADDRESS)
++ NDS32_BUILTIN(unspec_get_all_pending_int, "get_all_pending_int",
++ GET_ALL_PENDING_INT)
++ NDS32_BUILTIN(unspec_unaligned_feature, "unaligned_feature",
++ UNALIGNED_FEATURE)
++ NDS32_NO_TARGET_BUILTIN(unspec_enable_unaligned, "enable_unaligned",
++ ENABLE_UNALIGNED)
++ NDS32_NO_TARGET_BUILTIN(unspec_disable_unaligned, "disable_unaligned",
++ DISABLE_UNALIGNED)
++};
++
++/* Intrinsics that take just one argument. */
++static struct builtin_description bdesc_1arg[] =
++{
++ NDS32_BUILTIN(unspec_ssabssi2, "abs", ABS)
++ NDS32_BUILTIN(clzsi2, "clz", CLZ)
++ NDS32_BUILTIN(unspec_clo, "clo", CLO)
++ NDS32_BUILTIN(unspec_wsbh, "wsbh", WSBH)
++ NDS32_BUILTIN(unspec_tlbop_pb, "tlbop_pb",TLBOP_PB)
++ NDS32_BUILTIN(unaligned_load_hw, "unaligned_load_hw", UALOAD_HW)
++ NDS32_BUILTIN(unaligned_loadsi, "unaligned_load_w", UALOAD_W)
++ NDS32_BUILTIN(unaligned_loaddi, "unaligned_load_dw", UALOAD_DW)
++ NDS32_NO_TARGET_BUILTIN(unspec_volatile_isync, "isync", ISYNC)
++ NDS32_NO_TARGET_BUILTIN(unspec_fmtcsr, "fmtcsr", FMTCSR)
++ NDS32_NO_TARGET_BUILTIN(unspec_jr_itoff, "jr_itoff", JR_ITOFF)
++ NDS32_NO_TARGET_BUILTIN(unspec_jr_toff, "jr_toff", JR_TOFF)
++ NDS32_NO_TARGET_BUILTIN(unspec_jral_ton, "jral_ton", JRAL_TON)
++ NDS32_NO_TARGET_BUILTIN(unspec_ret_toff, "ret_toff", RET_TOFF)
++ NDS32_NO_TARGET_BUILTIN(unspec_jral_iton, "jral_iton",JRAL_ITON)
++ NDS32_NO_TARGET_BUILTIN(unspec_tlbop_trd, "tlbop_trd", TLBOP_TRD)
++ NDS32_NO_TARGET_BUILTIN(unspec_tlbop_twr, "tlbop_twr", TLBOP_TWR)
++ NDS32_NO_TARGET_BUILTIN(unspec_tlbop_rwr, "tlbop_rwr", TLBOP_RWR)
++ NDS32_NO_TARGET_BUILTIN(unspec_tlbop_rwlk, "tlbop_rwlk", TLBOP_RWLK)
++ NDS32_NO_TARGET_BUILTIN(unspec_tlbop_unlk, "tlbop_unlk", TLBOP_UNLK)
++ NDS32_NO_TARGET_BUILTIN(unspec_tlbop_inv, "tlbop_inv", TLBOP_INV)
++ NDS32_NO_TARGET_BUILTIN(unspec_ret_itoff, "ret_itoff", RET_ITOFF)
++ NDS32_NO_TARGET_BUILTIN(unspec_set_current_sp,
++ "set_current_sp", SET_CURRENT_SP)
++ NDS32_BUILTIN(kabsv2hi2, "kabs16", KABS16)
++ NDS32_BUILTIN(kabsv2hi2, "v_kabs16", V_KABS16)
++ NDS32_BUILTIN(kabsv4qi2, "kabs8", KABS8)
++ NDS32_BUILTIN(kabsv4qi2, "v_kabs8", V_KABS8)
++ NDS32_BUILTIN(sunpkd810, "sunpkd810", SUNPKD810)
++ NDS32_BUILTIN(sunpkd810, "v_sunpkd810", V_SUNPKD810)
++ NDS32_BUILTIN(sunpkd820, "sunpkd820", SUNPKD820)
++ NDS32_BUILTIN(sunpkd820, "v_sunpkd820", V_SUNPKD820)
++ NDS32_BUILTIN(sunpkd830, "sunpkd830", SUNPKD830)
++ NDS32_BUILTIN(sunpkd830, "v_sunpkd830", V_SUNPKD830)
++ NDS32_BUILTIN(sunpkd831, "sunpkd831", SUNPKD831)
++ NDS32_BUILTIN(sunpkd831, "v_sunpkd831", V_SUNPKD831)
++ NDS32_BUILTIN(zunpkd810, "zunpkd810", ZUNPKD810)
++ NDS32_BUILTIN(zunpkd810, "v_zunpkd810", V_ZUNPKD810)
++ NDS32_BUILTIN(zunpkd820, "zunpkd820", ZUNPKD820)
++ NDS32_BUILTIN(zunpkd820, "v_zunpkd820", V_ZUNPKD820)
++ NDS32_BUILTIN(zunpkd830, "zunpkd830", ZUNPKD830)
++ NDS32_BUILTIN(zunpkd830, "v_zunpkd830", V_ZUNPKD830)
++ NDS32_BUILTIN(zunpkd831, "zunpkd831", ZUNPKD831)
++ NDS32_BUILTIN(zunpkd831, "v_zunpkd831", V_ZUNPKD831)
++ NDS32_BUILTIN(unspec_kabs, "kabs", KABS)
++ NDS32_BUILTIN(unaligned_loadv2hi, "get_unaligned_u16x2", UALOAD_U16)
++ NDS32_BUILTIN(unaligned_loadv2hi, "get_unaligned_s16x2", UALOAD_S16)
++ NDS32_BUILTIN(unaligned_loadv4qi, "get_unaligned_u8x4", UALOAD_U8)
++ NDS32_BUILTIN(unaligned_loadv4qi, "get_unaligned_s8x4", UALOAD_S8)
++};
++
++/* Intrinsics that take just one argument. and the argument is immediate. */
++static struct builtin_description bdesc_1argimm[] =
++{
++ NDS32_BUILTIN(unspec_volatile_mfsr, "mfsr", MFSR)
++ NDS32_BUILTIN(unspec_volatile_mfusr, "mfsr", MFUSR)
++ NDS32_BUILTIN(unspec_get_pending_int, "get_pending_int", GET_PENDING_INT)
++ NDS32_BUILTIN(unspec_get_int_priority, "get_int_priority", GET_INT_PRIORITY)
++ NDS32_NO_TARGET_BUILTIN(unspec_trap, "trap", TRAP)
++ NDS32_NO_TARGET_BUILTIN(unspec_break, "break", BREAK)
++ NDS32_NO_TARGET_BUILTIN(unspec_syscall, "syscall", SYSCALL)
++ NDS32_NO_TARGET_BUILTIN(unspec_enable_int, "enable_int", ENABLE_INT)
++ NDS32_NO_TARGET_BUILTIN(unspec_disable_int, "disable_int", DISABLE_INT)
++ NDS32_NO_TARGET_BUILTIN(unspec_clr_pending_hwint, "clr_pending_hwint",
++ CLR_PENDING_HWINT)
++ NDS32_NO_TARGET_BUILTIN(unspec_set_trig_level, "set_trig_level",
++ SET_TRIG_LEVEL)
++ NDS32_NO_TARGET_BUILTIN(unspec_set_trig_edge, "set_trig_edge",
++ SET_TRIG_EDGE)
++ NDS32_BUILTIN(unspec_get_trig_type, "get_trig_type", GET_TRIG_TYPE)
++};
++
++/* Intrinsics that take two arguments. */
++static struct builtin_description bdesc_2arg[] =
++{
++ NDS32_BUILTIN(unspec_fcpynss, "fcpynss", FCPYNSS)
++ NDS32_BUILTIN(unspec_fcpyss, "fcpyss", FCPYSS)
++ NDS32_BUILTIN(unspec_fcpynsd, "fcpynsd", FCPYNSD)
++ NDS32_BUILTIN(unspec_fcpysd, "fcpysd", FCPYSD)
++ NDS32_BUILTIN(unspec_ave, "ave", AVE)
++ NDS32_BUILTIN(unspec_pbsad, "pbsad", PBSAD)
++ NDS32_BUILTIN(unspec_ffb, "ffb", FFB)
++ NDS32_BUILTIN(unspec_ffmism, "ffmsim", FFMISM)
++ NDS32_BUILTIN(unspec_flmism, "flmism", FLMISM)
++ NDS32_BUILTIN(unspec_kaddw, "kaddw", KADDW)
++ NDS32_BUILTIN(unspec_kaddh, "kaddh", KADDH)
++ NDS32_BUILTIN(unspec_ksubw, "ksubw", KSUBW)
++ NDS32_BUILTIN(unspec_ksubh, "ksubh", KSUBH)
++ NDS32_BUILTIN(unspec_kdmbb, "kdmbb", KDMBB)
++ NDS32_BUILTIN(unspec_kdmbb, "v_kdmbb", V_KDMBB)
++ NDS32_BUILTIN(unspec_kdmbt, "kdmbt", KDMBT)
++ NDS32_BUILTIN(unspec_kdmbt, "v_kdmbt", V_KDMBT)
++ NDS32_BUILTIN(unspec_kdmtb, "kdmtb", KDMTB)
++ NDS32_BUILTIN(unspec_kdmtb, "v_kdmtb", V_KDMTB)
++ NDS32_BUILTIN(unspec_kdmtt, "kdmtt", KDMTT)
++ NDS32_BUILTIN(unspec_kdmtt, "v_kdmtt", V_KDMTT)
++ NDS32_BUILTIN(unspec_khmbb, "khmbb", KHMBB)
++ NDS32_BUILTIN(unspec_khmbb, "v_khmbb", V_KHMBB)
++ NDS32_BUILTIN(unspec_khmbt, "khmbt", KHMBT)
++ NDS32_BUILTIN(unspec_khmbt, "v_khmbt", V_KHMBT)
++ NDS32_BUILTIN(unspec_khmtb, "khmtb", KHMTB)
++ NDS32_BUILTIN(unspec_khmtb, "v_khmtb", V_KHMTB)
++ NDS32_BUILTIN(unspec_khmtt, "khmtt", KHMTT)
++ NDS32_BUILTIN(unspec_khmtt, "v_khmtt", V_KHMTT)
++ NDS32_BUILTIN(unspec_kslraw, "kslraw", KSLRAW)
++ NDS32_BUILTIN(unspec_kslrawu, "kslraw_u", KSLRAW_U)
++ NDS32_BUILTIN(rotrsi3, "rotr", ROTR)
++ NDS32_BUILTIN(unspec_sva, "sva", SVA)
++ NDS32_BUILTIN(unspec_svs, "svs", SVS)
++ NDS32_NO_TARGET_BUILTIN(mtsr_isb, "mtsr_isb", MTSR_ISB)
++ NDS32_NO_TARGET_BUILTIN(mtsr_dsb, "mtsr_dsb", MTSR_DSB)
++ NDS32_NO_TARGET_BUILTIN(unspec_volatile_mtsr, "mtsr", MTSR)
++ NDS32_NO_TARGET_BUILTIN(unspec_volatile_mtusr, "mtusr", MTUSR)
++ NDS32_NO_TARGET_BUILTIN(unaligned_store_hw, "unaligned_store_hw", UASTORE_HW)
++ NDS32_NO_TARGET_BUILTIN(unaligned_storesi, "unaligned_store_hw", UASTORE_W)
++ NDS32_NO_TARGET_BUILTIN(unaligned_storedi, "unaligned_store_hw", UASTORE_DW)
++ NDS32_BUILTIN(addv2hi3, "add16", ADD16)
++ NDS32_BUILTIN(addv2hi3, "v_uadd16", V_UADD16)
++ NDS32_BUILTIN(addv2hi3, "v_sadd16", V_SADD16)
++ NDS32_BUILTIN(raddv2hi3, "radd16", RADD16)
++ NDS32_BUILTIN(raddv2hi3, "v_radd16", V_RADD16)
++ NDS32_BUILTIN(uraddv2hi3, "uradd16", URADD16)
++ NDS32_BUILTIN(uraddv2hi3, "v_uradd16", V_URADD16)
++ NDS32_BUILTIN(kaddv2hi3, "kadd16", KADD16)
++ NDS32_BUILTIN(kaddv2hi3, "v_kadd16", V_KADD16)
++ NDS32_BUILTIN(ukaddv2hi3, "ukadd16", UKADD16)
++ NDS32_BUILTIN(ukaddv2hi3, "v_ukadd16", V_UKADD16)
++ NDS32_BUILTIN(subv2hi3, "sub16", SUB16)
++ NDS32_BUILTIN(subv2hi3, "v_usub16", V_USUB16)
++ NDS32_BUILTIN(subv2hi3, "v_ssub16", V_SSUB16)
++ NDS32_BUILTIN(rsubv2hi3, "rsub16", RSUB16)
++ NDS32_BUILTIN(rsubv2hi3, "v_rsub16", V_RSUB16)
++ NDS32_BUILTIN(ursubv2hi3, "ursub16", URSUB16)
++ NDS32_BUILTIN(ursubv2hi3, "v_ursub16", V_URSUB16)
++ NDS32_BUILTIN(ksubv2hi3, "ksub16", KSUB16)
++ NDS32_BUILTIN(ksubv2hi3, "v_ksub16", V_KSUB16)
++ NDS32_BUILTIN(uksubv2hi3, "uksub16", UKSUB16)
++ NDS32_BUILTIN(uksubv2hi3, "v_uksub16", V_UKSUB16)
++ NDS32_BUILTIN(cras16_1, "cras16", CRAS16)
++ NDS32_BUILTIN(cras16_1, "v_ucras16", V_UCRAS16)
++ NDS32_BUILTIN(cras16_1, "v_scras16", V_SCRAS16)
++ NDS32_BUILTIN(rcras16_1, "rcras16", RCRAS16)
++ NDS32_BUILTIN(rcras16_1, "v_rcras16", V_RCRAS16)
++ NDS32_BUILTIN(urcras16_1, "urcras16", URCRAS16)
++ NDS32_BUILTIN(urcras16_1, "v_urcras16", V_URCRAS16)
++ NDS32_BUILTIN(kcras16_1, "kcras16", KCRAS16)
++ NDS32_BUILTIN(kcras16_1, "v_kcras16", V_KCRAS16)
++ NDS32_BUILTIN(ukcras16_1, "ukcras16", UKCRAS16)
++ NDS32_BUILTIN(ukcras16_1, "v_ukcras16", V_UKCRAS16)
++ NDS32_BUILTIN(crsa16_1, "crsa16", CRSA16)
++ NDS32_BUILTIN(crsa16_1, "v_ucrsa16", V_UCRSA16)
++ NDS32_BUILTIN(crsa16_1, "v_scrsa16", V_SCRSA16)
++ NDS32_BUILTIN(rcrsa16_1, "rcrsa16", RCRSA16)
++ NDS32_BUILTIN(rcrsa16_1, "v_rcrsa16", V_RCRSA16)
++ NDS32_BUILTIN(urcrsa16_1, "urcrsa16", URCRSA16)
++ NDS32_BUILTIN(urcrsa16_1, "v_urcrsa16", V_URCRSA16)
++ NDS32_BUILTIN(kcrsa16_1, "kcrsa16", KCRSA16)
++ NDS32_BUILTIN(kcrsa16_1, "v_kcrsa16", V_KCRSA16)
++ NDS32_BUILTIN(ukcrsa16_1, "ukcrsa16", UKCRSA16)
++ NDS32_BUILTIN(ukcrsa16_1, "v_ukcrsa16", V_UKCRSA16)
++ NDS32_BUILTIN(addv4qi3, "add8", ADD8)
++ NDS32_BUILTIN(addv4qi3, "v_uadd8", V_UADD8)
++ NDS32_BUILTIN(addv4qi3, "v_sadd8", V_SADD8)
++ NDS32_BUILTIN(raddv4qi3, "radd8", RADD8)
++ NDS32_BUILTIN(raddv4qi3, "v_radd8", V_RADD8)
++ NDS32_BUILTIN(uraddv4qi3, "uradd8", URADD8)
++ NDS32_BUILTIN(uraddv4qi3, "v_uradd8", V_URADD8)
++ NDS32_BUILTIN(kaddv4qi3, "kadd8", KADD8)
++ NDS32_BUILTIN(kaddv4qi3, "v_kadd8", V_KADD8)
++ NDS32_BUILTIN(ukaddv4qi3, "ukadd8", UKADD8)
++ NDS32_BUILTIN(ukaddv4qi3, "v_ukadd8", V_UKADD8)
++ NDS32_BUILTIN(subv4qi3, "sub8", SUB8)
++ NDS32_BUILTIN(subv4qi3, "v_usub8", V_USUB8)
++ NDS32_BUILTIN(subv4qi3, "v_ssub8", V_SSUB8)
++ NDS32_BUILTIN(rsubv4qi3, "rsub8", RSUB8)
++ NDS32_BUILTIN(rsubv4qi3, "v_rsub8", V_RSUB8)
++ NDS32_BUILTIN(ursubv4qi3, "ursub8", URSUB8)
++ NDS32_BUILTIN(ursubv4qi3, "v_ursub8", V_URSUB8)
++ NDS32_BUILTIN(ksubv4qi3, "ksub8", KSUB8)
++ NDS32_BUILTIN(ksubv4qi3, "v_ksub8", V_KSUB8)
++ NDS32_BUILTIN(uksubv4qi3, "uksub8", UKSUB8)
++ NDS32_BUILTIN(uksubv4qi3, "v_uksub8", V_UKSUB8)
++ NDS32_BUILTIN(ashrv2hi3, "sra16", SRA16)
++ NDS32_BUILTIN(ashrv2hi3, "v_sra16", V_SRA16)
++ NDS32_BUILTIN(sra16_round, "sra16_u", SRA16_U)
++ NDS32_BUILTIN(sra16_round, "v_sra16_u", V_SRA16_U)
++ NDS32_BUILTIN(lshrv2hi3, "srl16", SRL16)
++ NDS32_BUILTIN(lshrv2hi3, "v_srl16", V_SRL16)
++ NDS32_BUILTIN(srl16_round, "srl16_u", SRL16_U)
++ NDS32_BUILTIN(srl16_round, "v_srl16_u", V_SRL16_U)
++ NDS32_BUILTIN(ashlv2hi3, "sll16", SLL16)
++ NDS32_BUILTIN(ashlv2hi3, "v_sll16", V_SLL16)
++ NDS32_BUILTIN(kslli16, "ksll16", KSLL16)
++ NDS32_BUILTIN(kslli16, "v_ksll16", V_KSLL16)
++ NDS32_BUILTIN(kslra16, "kslra16", KSLRA16)
++ NDS32_BUILTIN(kslra16, "v_kslra16", V_KSLRA16)
++ NDS32_BUILTIN(kslra16_round, "kslra16_u", KSLRA16_U)
++ NDS32_BUILTIN(kslra16_round, "v_kslra16_u", V_KSLRA16_U)
++ NDS32_BUILTIN(cmpeq16, "cmpeq16", CMPEQ16)
++ NDS32_BUILTIN(cmpeq16, "v_scmpeq16", V_SCMPEQ16)
++ NDS32_BUILTIN(cmpeq16, "v_ucmpeq16", V_UCMPEQ16)
++ NDS32_BUILTIN(scmplt16, "scmplt16", SCMPLT16)
++ NDS32_BUILTIN(scmplt16, "v_scmplt16", V_SCMPLT16)
++ NDS32_BUILTIN(scmple16, "scmple16", SCMPLE16)
++ NDS32_BUILTIN(scmple16, "v_scmple16", V_SCMPLE16)
++ NDS32_BUILTIN(ucmplt16, "ucmplt16", UCMPLT16)
++ NDS32_BUILTIN(ucmplt16, "v_ucmplt16", V_UCMPLT16)
++ NDS32_BUILTIN(ucmplt16, "ucmple16", UCMPLE16)
++ NDS32_BUILTIN(ucmplt16, "v_ucmple16", V_UCMPLE16)
++ NDS32_BUILTIN(cmpeq8, "cmpeq8", CMPEQ8)
++ NDS32_BUILTIN(cmpeq8, "v_scmpeq8", V_SCMPEQ8)
++ NDS32_BUILTIN(cmpeq8, "v_ucmpeq8", V_UCMPEQ8)
++ NDS32_BUILTIN(scmplt8, "scmplt8", SCMPLT8)
++ NDS32_BUILTIN(scmplt8, "v_scmplt8", V_SCMPLT8)
++ NDS32_BUILTIN(scmple8, "scmple8", SCMPLE8)
++ NDS32_BUILTIN(scmple8, "v_scmple8", V_SCMPLE8)
++ NDS32_BUILTIN(ucmplt8, "ucmplt8", UCMPLT8)
++ NDS32_BUILTIN(ucmplt8, "v_ucmplt8", V_UCMPLT8)
++ NDS32_BUILTIN(ucmplt8, "ucmple8", UCMPLE8)
++ NDS32_BUILTIN(ucmplt8, "v_ucmple8", V_UCMPLE8)
++ NDS32_BUILTIN(sminv2hi3, "smin16", SMIN16)
++ NDS32_BUILTIN(sminv2hi3, "v_smin16", V_SMIN16)
++ NDS32_BUILTIN(uminv2hi3, "umin16", UMIN16)
++ NDS32_BUILTIN(uminv2hi3, "v_umin16", V_UMIN16)
++ NDS32_BUILTIN(smaxv2hi3, "smax16", SMAX16)
++ NDS32_BUILTIN(smaxv2hi3, "v_smax16", V_SMAX16)
++ NDS32_BUILTIN(umaxv2hi3, "umax16", UMAX16)
++ NDS32_BUILTIN(umaxv2hi3, "v_umax16", V_UMAX16)
++ NDS32_BUILTIN(khm16, "khm16", KHM16)
++ NDS32_BUILTIN(khm16, "v_khm16", V_KHM16)
++ NDS32_BUILTIN(khmx16, "khmx16", KHMX16)
++ NDS32_BUILTIN(khmx16, "v_khmx16", V_KHMX16)
++ NDS32_BUILTIN(sminv4qi3, "smin8", SMIN8)
++ NDS32_BUILTIN(sminv4qi3, "v_smin8", V_SMIN8)
++ NDS32_BUILTIN(uminv4qi3, "umin8", UMIN8)
++ NDS32_BUILTIN(uminv4qi3, "v_umin8", V_UMIN8)
++ NDS32_BUILTIN(smaxv4qi3, "smax8", SMAX8)
++ NDS32_BUILTIN(smaxv4qi3, "v_smax8", V_SMAX8)
++ NDS32_BUILTIN(umaxv4qi3, "umax8", UMAX8)
++ NDS32_BUILTIN(umaxv4qi3, "v_umax8", V_UMAX8)
++ NDS32_BUILTIN(raddsi3, "raddw", RADDW)
++ NDS32_BUILTIN(uraddsi3, "uraddw", URADDW)
++ NDS32_BUILTIN(rsubsi3, "rsubw", RSUBW)
++ NDS32_BUILTIN(ursubsi3, "ursubw", URSUBW)
++ NDS32_BUILTIN(sraiu, "sra_u", SRA_U)
++ NDS32_BUILTIN(kssl, "ksll", KSLL)
++ NDS32_BUILTIN(pkbb, "pkbb16", PKBB16)
++ NDS32_BUILTIN(pkbb, "v_pkbb16", V_PKBB16)
++ NDS32_BUILTIN(pkbt, "pkbt16", PKBT16)
++ NDS32_BUILTIN(pkbt, "v_pkbt16", V_PKBT16)
++ NDS32_BUILTIN(pktb, "pktb16", PKTB16)
++ NDS32_BUILTIN(pktb, "v_pktb16", V_PKTB16)
++ NDS32_BUILTIN(pktt, "pktt16", PKTT16)
++ NDS32_BUILTIN(pktt, "v_pktt16", V_PKTT16)
++ NDS32_BUILTIN(smulsi3_highpart, "smmul", SMMUL)
++ NDS32_BUILTIN(smmul_round, "smmul_u", SMMUL_U)
++ NDS32_BUILTIN(smmwb, "smmwb", SMMWB)
++ NDS32_BUILTIN(smmwb, "v_smmwb", V_SMMWB)
++ NDS32_BUILTIN(smmwb_round, "smmwb_u", SMMWB_U)
++ NDS32_BUILTIN(smmwb_round, "v_smmwb_u", V_SMMWB_U)
++ NDS32_BUILTIN(smmwt, "smmwt", SMMWT)
++ NDS32_BUILTIN(smmwt, "v_smmwt", V_SMMWT)
++ NDS32_BUILTIN(smmwt_round, "smmwt_u", SMMWT_U)
++ NDS32_BUILTIN(smmwt_round, "v_smmwt_u", V_SMMWT_U)
++ NDS32_BUILTIN(smbb, "smbb", SMBB)
++ NDS32_BUILTIN(smbb, "v_smbb", V_SMBB)
++ NDS32_BUILTIN(smbt, "smbt", SMBT)
++ NDS32_BUILTIN(smbt, "v_smbt", V_SMBT)
++ NDS32_BUILTIN(smtt, "smtt", SMTT)
++ NDS32_BUILTIN(smtt, "v_smtt", V_SMTT)
++ NDS32_BUILTIN(kmda, "kmda", KMDA)
++ NDS32_BUILTIN(kmda, "v_kmda", V_KMDA)
++ NDS32_BUILTIN(kmxda, "kmxda", KMXDA)
++ NDS32_BUILTIN(kmxda, "v_kmxda", V_KMXDA)
++ NDS32_BUILTIN(smds, "smds", SMDS)
++ NDS32_BUILTIN(smds, "v_smds", V_SMDS)
++ NDS32_BUILTIN(smdrs, "smdrs", SMDRS)
++ NDS32_BUILTIN(smdrs, "v_smdrs", V_SMDRS)
++ NDS32_BUILTIN(smxdsv, "smxds", SMXDS)
++ NDS32_BUILTIN(smxdsv, "v_smxds", V_SMXDS)
++ NDS32_BUILTIN(smal1, "smal", SMAL)
++ NDS32_BUILTIN(smal1, "v_smal", V_SMAL)
++ NDS32_BUILTIN(bitrev, "bitrev", BITREV)
++ NDS32_BUILTIN(wext, "wext", WEXT)
++ NDS32_BUILTIN(adddi3, "sadd64", SADD64)
++ NDS32_BUILTIN(adddi3, "uadd64", UADD64)
++ NDS32_BUILTIN(radddi3, "radd64", RADD64)
++ NDS32_BUILTIN(uradddi3, "uradd64", URADD64)
++ NDS32_BUILTIN(kadddi3, "kadd64", KADD64)
++ NDS32_BUILTIN(ukadddi3, "ukadd64", UKADD64)
++ NDS32_BUILTIN(subdi3, "ssub64", SSUB64)
++ NDS32_BUILTIN(subdi3, "usub64", USUB64)
++ NDS32_BUILTIN(rsubdi3, "rsub64", RSUB64)
++ NDS32_BUILTIN(ursubdi3, "ursub64", URSUB64)
++ NDS32_BUILTIN(ksubdi3, "ksub64", KSUB64)
++ NDS32_BUILTIN(uksubdi3, "uksub64", UKSUB64)
++ NDS32_BUILTIN(smul16, "smul16", SMUL16)
++ NDS32_BUILTIN(smul16, "v_smul16", V_SMUL16)
++ NDS32_BUILTIN(smulx16, "smulx16", SMULX16)
++ NDS32_BUILTIN(smulx16, "v_smulx16", V_SMULX16)
++ NDS32_BUILTIN(umul16, "umul16", UMUL16)
++ NDS32_BUILTIN(umul16, "v_umul16", V_UMUL16)
++ NDS32_BUILTIN(umulx16, "umulx16", UMULX16)
++ NDS32_BUILTIN(umulx16, "v_umulx16", V_UMULX16)
++ NDS32_BUILTIN(kwmmul, "kwmmul", KWMMUL)
++ NDS32_BUILTIN(kwmmul_round, "kwmmul_u", KWMMUL_U)
++ NDS32_NO_TARGET_BUILTIN(unaligned_storev2hi,
++ "put_unaligned_u16x2", UASTORE_U16)
++ NDS32_NO_TARGET_BUILTIN(unaligned_storev2hi,
++ "put_unaligned_s16x2", UASTORE_S16)
++ NDS32_NO_TARGET_BUILTIN(unaligned_storev4qi, "put_unaligned_u8x4", UASTORE_U8)
++ NDS32_NO_TARGET_BUILTIN(unaligned_storev4qi, "put_unaligned_s8x4", UASTORE_S8)
++};
++
++/* Two-argument intrinsics with an immediate second argument. */
++static struct builtin_description bdesc_2argimm[] =
++{
++ NDS32_BUILTIN(unspec_bclr, "bclr", BCLR)
++ NDS32_BUILTIN(unspec_bset, "bset", BSET)
++ NDS32_BUILTIN(unspec_btgl, "btgl", BTGL)
++ NDS32_BUILTIN(unspec_btst, "btst", BTST)
++ NDS32_BUILTIN(unspec_clip, "clip", CLIP)
++ NDS32_BUILTIN(unspec_clips, "clips", CLIPS)
++ NDS32_NO_TARGET_BUILTIN(unspec_teqz, "teqz", TEQZ)
++ NDS32_NO_TARGET_BUILTIN(unspec_tnez, "tnez", TNEZ)
++ NDS32_BUILTIN(ashrv2hi3, "srl16", SRL16)
++ NDS32_BUILTIN(ashrv2hi3, "v_srl16", V_SRL16)
++ NDS32_BUILTIN(srl16_round, "srl16_u", SRL16_U)
++ NDS32_BUILTIN(srl16_round, "v_srl16_u", V_SRL16_U)
++ NDS32_BUILTIN(kslli16, "ksll16", KSLL16)
++ NDS32_BUILTIN(kslli16, "v_ksll16", V_KSLL16)
++ NDS32_BUILTIN(sclip16, "sclip16", SCLIP16)
++ NDS32_BUILTIN(sclip16, "v_sclip16", V_SCLIP16)
++ NDS32_BUILTIN(uclip16, "uclip16", UCLIP16)
++ NDS32_BUILTIN(uclip16, "v_uclip16", V_UCLIP16)
++ NDS32_BUILTIN(sraiu, "sra_u", SRA_U)
++ NDS32_BUILTIN(kssl, "ksll", KSLL)
++ NDS32_BUILTIN(bitrev, "bitrev", BITREV)
++ NDS32_BUILTIN(wext, "wext", WEXT)
++ NDS32_BUILTIN(uclip32, "uclip32", UCLIP32)
++ NDS32_BUILTIN(sclip32, "sclip32", SCLIP32)
++};
++
++/* Intrinsics that take three arguments. */
++static struct builtin_description bdesc_3arg[] =
++{
++ NDS32_BUILTIN(unspec_pbsada, "pbsada", PBSADA)
++ NDS32_NO_TARGET_BUILTIN(bse, "bse", BSE)
++ NDS32_NO_TARGET_BUILTIN(bsp, "bsp", BSP)
++ NDS32_BUILTIN(kmabb, "kmabb", KMABB)
++ NDS32_BUILTIN(kmabb, "v_kmabb", V_KMABB)
++ NDS32_BUILTIN(kmabt, "kmabt", KMABT)
++ NDS32_BUILTIN(kmabt, "v_kmabt", V_KMABT)
++ NDS32_BUILTIN(kmatt, "kmatt", KMATT)
++ NDS32_BUILTIN(kmatt, "v_kmatt", V_KMATT)
++ NDS32_BUILTIN(kmada, "kmada", KMADA)
++ NDS32_BUILTIN(kmada, "v_kmada", V_KMADA)
++ NDS32_BUILTIN(kmaxda, "kmaxda", KMAXDA)
++ NDS32_BUILTIN(kmaxda, "v_kmaxda", V_KMAXDA)
++ NDS32_BUILTIN(kmads, "kmads", KMADS)
++ NDS32_BUILTIN(kmads, "v_kmads", V_KMADS)
++ NDS32_BUILTIN(kmadrs, "kmadrs", KMADRS)
++ NDS32_BUILTIN(kmadrs, "v_kmadrs", V_KMADRS)
++ NDS32_BUILTIN(kmaxds, "kmaxds", KMAXDS)
++ NDS32_BUILTIN(kmaxds, "v_kmaxds", V_KMAXDS)
++ NDS32_BUILTIN(kmsda, "kmsda", KMSDA)
++ NDS32_BUILTIN(kmsda, "v_kmsda", V_KMSDA)
++ NDS32_BUILTIN(kmsxda, "kmsxda", KMSXDA)
++ NDS32_BUILTIN(kmsxda, "v_kmsxda", V_KMSXDA)
++ NDS32_BUILTIN(bpick1, "bpick", BPICK)
++ NDS32_BUILTIN(smar64_1, "smar64", SMAR64)
++ NDS32_BUILTIN(smsr64, "smsr64", SMSR64)
++ NDS32_BUILTIN(umar64_1, "umar64", UMAR64)
++ NDS32_BUILTIN(umsr64, "umsr64", UMSR64)
++ NDS32_BUILTIN(kmar64_1, "kmar64", KMAR64)
++ NDS32_BUILTIN(kmsr64, "kmsr64", KMSR64)
++ NDS32_BUILTIN(ukmar64_1, "ukmar64", UKMAR64)
++ NDS32_BUILTIN(ukmsr64, "ukmsr64", UKMSR64)
++ NDS32_BUILTIN(smalbb, "smalbb", SMALBB)
++ NDS32_BUILTIN(smalbb, "v_smalbb", V_SMALBB)
++ NDS32_BUILTIN(smalbt, "smalbt", SMALBT)
++ NDS32_BUILTIN(smalbt, "v_smalbt", V_SMALBT)
++ NDS32_BUILTIN(smaltt, "smaltt", SMALTT)
++ NDS32_BUILTIN(smaltt, "v_smaltt", V_SMALTT)
++ NDS32_BUILTIN(smalda1, "smalda", SMALDA)
++ NDS32_BUILTIN(smalda1, "v_smalda", V_SMALDA)
++ NDS32_BUILTIN(smalxda1, "smalxda", SMALXDA)
++ NDS32_BUILTIN(smalxda1, "v_smalxda", V_SMALXDA)
++ NDS32_BUILTIN(smalds1, "smalds", SMALDS)
++ NDS32_BUILTIN(smalds1, "v_smalds", V_SMALDS)
++ NDS32_BUILTIN(smaldrs3, "smaldrs", SMALDRS)
++ NDS32_BUILTIN(smaldrs3, "v_smaldrs", V_SMALDRS)
++ NDS32_BUILTIN(smalxds1, "smalxds", SMALXDS)
++ NDS32_BUILTIN(smalxds1, "v_smalxds", V_SMALXDS)
++ NDS32_BUILTIN(smslda1, "smslda", SMSLDA)
++ NDS32_BUILTIN(smslda1, "v_smslda", V_SMSLDA)
++ NDS32_BUILTIN(smslxda1, "smslxda", SMSLXDA)
++ NDS32_BUILTIN(smslxda1, "v_smslxda", V_SMSLXDA)
++ NDS32_BUILTIN(kmmawb, "kmmawb", KMMAWB)
++ NDS32_BUILTIN(kmmawb, "v_kmmawb", V_KMMAWB)
++ NDS32_BUILTIN(kmmawb_round, "kmmawb_u", KMMAWB_U)
++ NDS32_BUILTIN(kmmawb_round, "v_kmmawb_u", V_KMMAWB_U)
++ NDS32_BUILTIN(kmmawt, "kmmawt", KMMAWT)
++ NDS32_BUILTIN(kmmawt, "v_kmmawt", V_KMMAWT)
++ NDS32_BUILTIN(kmmawt_round, "kmmawt_u", KMMAWT_U)
++ NDS32_BUILTIN(kmmawt_round, "v_kmmawt_u", V_KMMAWT_U)
++ NDS32_BUILTIN(kmmac, "kmmac", KMMAC)
++ NDS32_BUILTIN(kmmac_round, "kmmac_u", KMMAC_U)
++ NDS32_BUILTIN(kmmsb, "kmmsb", KMMSB)
++ NDS32_BUILTIN(kmmsb_round, "kmmsb_u", KMMSB_U)
++};
++
++/* Three-argument intrinsics with an immediate third argument. */
++static struct builtin_description bdesc_3argimm[] =
++{
++ NDS32_NO_TARGET_BUILTIN(prefetch_qw, "prefetch_qw", DPREF_QW)
++ NDS32_NO_TARGET_BUILTIN(prefetch_hw, "prefetch_hw", DPREF_HW)
++ NDS32_NO_TARGET_BUILTIN(prefetch_w, "prefetch_w", DPREF_W)
++ NDS32_NO_TARGET_BUILTIN(prefetch_dw, "prefetch_dw", DPREF_DW)
++ NDS32_BUILTIN(insb, "insb", INSB)
++};
++
++/* Intrinsics that load a value. */
++static struct builtin_description bdesc_load[] =
++{
++ NDS32_BUILTIN(unspec_volatile_llw, "llw", LLW)
++ NDS32_BUILTIN(unspec_lwup, "lwup", LWUP)
++ NDS32_BUILTIN(unspec_lbup, "lbup", LBUP)
++};
++
++/* Intrinsics that store a value. */
++static struct builtin_description bdesc_store[] =
++{
++ NDS32_BUILTIN(unspec_swup, "swup", SWUP)
++ NDS32_BUILTIN(unspec_sbup, "sbup", SBUP)
++};
++
++static struct builtin_description bdesc_cctl[] =
++{
++ NDS32_BUILTIN(cctl_idx_read, "cctl_idx_read", CCTL_IDX_READ)
++ NDS32_NO_TARGET_BUILTIN(cctl_idx_write, "cctl_idx_write", CCTL_IDX_WRITE)
++ NDS32_NO_TARGET_BUILTIN(cctl_va_lck, "cctl_va_lck", CCTL_VA_LCK)
++ NDS32_NO_TARGET_BUILTIN(cctl_idx_wbinval,
++ "cctl_idx_wbinval", CCTL_IDX_WBINVAL)
++ NDS32_NO_TARGET_BUILTIN(cctl_va_wbinval_l1,
++ "cctl_va_wbinval_l1", CCTL_VA_WBINVAL_L1)
++ NDS32_NO_TARGET_BUILTIN(cctl_va_wbinval_la,
++ "cctl_va_wbinval_la", CCTL_VA_WBINVAL_LA)
++};
+
+ rtx
+ nds32_expand_builtin_impl (tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+- machine_mode mode ATTRIBUTE_UNUSED,
++ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+ {
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
++ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
++ unsigned i;
++ struct builtin_description *d;
++
++ if (!NDS32_EXT_DSP_P ()
++ && fcode > NDS32_BUILTIN_DSP_BEGIN
++ && fcode < NDS32_BUILTIN_DSP_END)
++ error ("don't support DSP extension instructions");
++
++ switch (fcode)
++ {
++ /* FPU Register Transfer. */
++ case NDS32_BUILTIN_FMFCFG:
++ case NDS32_BUILTIN_FMFCSR:
++ case NDS32_BUILTIN_FMTCSR:
++ case NDS32_BUILTIN_FCPYNSS:
++ case NDS32_BUILTIN_FCPYSS:
++ /* Both v3s and v3f toolchains define TARGET_FPU_SINGLE. */
++ if (!TARGET_FPU_SINGLE)
++ {
++ error ("this builtin function is only available "
++ "on the v3s or v3f toolchain");
++ return NULL_RTX;
++ }
++ break;
++
++ /* FPU Register Transfer. */
++ case NDS32_BUILTIN_FCPYNSD:
++ case NDS32_BUILTIN_FCPYSD:
++ /* Only v3f toolchain defines TARGET_FPU_DOUBLE. */
++ if (!TARGET_FPU_DOUBLE)
++ {
++ error ("this builtin function is only available "
++ "on the v3f toolchain");
++ return NULL_RTX;
++ }
++ break;
++
++ /* Load and Store */
++ case NDS32_BUILTIN_LLW:
++ case NDS32_BUILTIN_LWUP:
++ case NDS32_BUILTIN_LBUP:
++ case NDS32_BUILTIN_SCW:
++ case NDS32_BUILTIN_SWUP:
++ case NDS32_BUILTIN_SBUP:
++ if (TARGET_ISA_V3M)
++ {
++ error ("this builtin function not support "
++ "on the v3m toolchain");
++ return NULL_RTX;
++ }
++ break;
++
++ /* Performance Extension */
++ case NDS32_BUILTIN_ABS:
++ case NDS32_BUILTIN_AVE:
++ case NDS32_BUILTIN_BCLR:
++ case NDS32_BUILTIN_BSET:
++ case NDS32_BUILTIN_BTGL:
++ case NDS32_BUILTIN_BTST:
++ case NDS32_BUILTIN_CLIP:
++ case NDS32_BUILTIN_CLIPS:
++ case NDS32_BUILTIN_CLZ:
++ case NDS32_BUILTIN_CLO:
++ if (!TARGET_EXT_PERF)
++ {
++ error ("don't support performance extension instructions");
++ return NULL_RTX;
++ }
++ break;
++
++ /* Performance Extension 2 */
++ case NDS32_BUILTIN_PBSAD:
++ case NDS32_BUILTIN_PBSADA:
++ case NDS32_BUILTIN_BSE:
++ case NDS32_BUILTIN_BSP:
++ if (!TARGET_EXT_PERF2)
++ {
++ error ("don't support performance extension "
++ "version 2 instructions");
++ return NULL_RTX;
++ }
++ break;
+
+- int fcode = DECL_FUNCTION_CODE (fndecl);
++ /* String Extension */
++ case NDS32_BUILTIN_FFB:
++ case NDS32_BUILTIN_FFMISM:
++ case NDS32_BUILTIN_FLMISM:
++ if (!TARGET_EXT_STRING)
++ {
++ error ("don't support string extension instructions");
++ return NULL_RTX;
++ }
++ break;
+
++ default:
++ break;
++ }
++
++ /* Since there are no result and operands, we can simply emit this rtx. */
+ switch (fcode)
+ {
+- /* Cache. */
+- case NDS32_BUILTIN_ISYNC:
+- return nds32_expand_builtin_null_ftype_reg
+- (CODE_FOR_unspec_volatile_isync, exp, target);
+ case NDS32_BUILTIN_ISB:
+- /* Since there are no result and operands for isb instruciton,
+- we can simply emit this rtx. */
+ emit_insn (gen_unspec_volatile_isb ());
+ return target;
+-
+- /* Register Transfer. */
+- case NDS32_BUILTIN_MFSR:
+- return nds32_expand_builtin_reg_ftype_imm
+- (CODE_FOR_unspec_volatile_mfsr, exp, target);
+- case NDS32_BUILTIN_MFUSR:
+- return nds32_expand_builtin_reg_ftype_imm
+- (CODE_FOR_unspec_volatile_mfusr, exp, target);
+- case NDS32_BUILTIN_MTSR:
+- return nds32_expand_builtin_null_ftype_reg_imm
+- (CODE_FOR_unspec_volatile_mtsr, exp, target);
+- case NDS32_BUILTIN_MTUSR:
+- return nds32_expand_builtin_null_ftype_reg_imm
+- (CODE_FOR_unspec_volatile_mtusr, exp, target);
+-
+- /* Interrupt. */
++ case NDS32_BUILTIN_DSB:
++ emit_insn (gen_unspec_dsb ());
++ return target;
++ case NDS32_BUILTIN_MSYNC_ALL:
++ emit_insn (gen_unspec_msync_all ());
++ return target;
++ case NDS32_BUILTIN_MSYNC_STORE:
++ emit_insn (gen_unspec_msync_store ());
++ return target;
+ case NDS32_BUILTIN_SETGIE_EN:
+- /* Since there are no result and operands for setgie.e instruciton,
+- we can simply emit this rtx. */
+ emit_insn (gen_unspec_volatile_setgie_en ());
++ emit_insn (gen_unspec_dsb ());
+ return target;
+ case NDS32_BUILTIN_SETGIE_DIS:
+- /* Since there are no result and operands for setgie.d instruciton,
+- we can simply emit this rtx. */
+ emit_insn (gen_unspec_volatile_setgie_dis ());
++ emit_insn (gen_unspec_dsb ());
++ return target;
++ case NDS32_BUILTIN_GIE_DIS:
++ emit_insn (gen_unspec_volatile_setgie_dis ());
++ emit_insn (gen_unspec_dsb ());
++ return target;
++ case NDS32_BUILTIN_GIE_EN:
++ emit_insn (gen_unspec_volatile_setgie_en ());
++ emit_insn (gen_unspec_dsb ());
++ return target;
++ case NDS32_BUILTIN_SET_PENDING_SWINT:
++ emit_insn (gen_unspec_set_pending_swint ());
++ return target;
++ case NDS32_BUILTIN_CLR_PENDING_SWINT:
++ emit_insn (gen_unspec_clr_pending_swint ());
++ return target;
++ case NDS32_BUILTIN_CCTL_L1D_INVALALL:
++ emit_insn (gen_cctl_l1d_invalall());
++ return target;
++ case NDS32_BUILTIN_CCTL_L1D_WBALL_ALVL:
++ emit_insn (gen_cctl_l1d_wball_alvl());
++ return target;
++ case NDS32_BUILTIN_CCTL_L1D_WBALL_ONE_LVL:
++ emit_insn (gen_cctl_l1d_wball_one_lvl());
++ return target;
++ case NDS32_BUILTIN_CLROV:
++ emit_insn (gen_unspec_volatile_clrov ());
++ return target;
++ case NDS32_BUILTIN_STANDBY_NO_WAKE_GRANT:
++ emit_insn (gen_unspec_standby_no_wake_grant ());
++ return target;
++ case NDS32_BUILTIN_STANDBY_WAKE_GRANT:
++ emit_insn (gen_unspec_standby_wake_grant ());
++ return target;
++ case NDS32_BUILTIN_STANDBY_WAKE_DONE:
++ emit_insn (gen_unspec_standby_wait_done ());
++ return target;
++ case NDS32_BUILTIN_SETEND_BIG:
++ emit_insn (gen_unspec_setend_big ());
++ return target;
++ case NDS32_BUILTIN_SETEND_LITTLE:
++ emit_insn (gen_unspec_setend_little ());
++ return target;
++ case NDS32_BUILTIN_NOP:
++ emit_insn (gen_unspec_nop ());
++ return target;
++ case NDS32_BUILTIN_SCHE_BARRIER:
++ emit_insn (gen_blockage ());
++ return target;
++ case NDS32_BUILTIN_TLBOP_FLUA:
++ emit_insn (gen_unspec_tlbop_flua ());
++ return target;
++ /* Instruction sequence protection */
++ case NDS32_BUILTIN_SIGNATURE_BEGIN:
++ emit_insn (gen_unspec_signature_begin ());
++ return target;
++ case NDS32_BUILTIN_SIGNATURE_END:
++ emit_insn (gen_unspec_signature_end ());
++ return target;
++ case NDS32_BUILTIN_SCW:
++ return nds32_expand_scw_builtin (CODE_FOR_unspec_volatile_scw,
++ exp, target);
++ case NDS32_BUILTIN_SET_INT_PRIORITY:
++ return nds32_expand_priority_builtin (CODE_FOR_unspec_set_int_priority,
++ exp, target,
++ "__nds32__set_int_priority");
++ case NDS32_BUILTIN_NO_HWLOOP:
++ emit_insn (gen_no_hwloop ());
+ return target;
+-
+ default:
+- gcc_unreachable ();
++ break;
+ }
+
++ /* Expand groups of builtins. */
++ for (i = 0, d = bdesc_noarg; i < ARRAY_SIZE (bdesc_noarg); i++, d++)
++ if (d->code == fcode)
++ return nds32_expand_noarg_builtin (d->icode, target);
++
++ for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
++ if (d->code == fcode)
++ return nds32_expand_unop_builtin (d->icode, exp, target, d->return_p);
++
++ for (i = 0, d = bdesc_1argimm; i < ARRAY_SIZE (bdesc_1argimm); i++, d++)
++ if (d->code == fcode)
++ return nds32_expand_unopimm_builtin (d->icode, exp, target,
++ d->return_p, d->name);
++
++ for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
++ if (d->code == fcode)
++ return nds32_expand_binop_builtin (d->icode, exp, target, d->return_p);
++
++ for (i = 0, d = bdesc_2argimm; i < ARRAY_SIZE (bdesc_2argimm); i++, d++)
++ if (d->code == fcode)
++ return nds32_expand_binopimm_builtin (d->icode, exp, target,
++ d->return_p, d->name);
++
++ for (i = 0, d = bdesc_3arg; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
++ if (d->code == fcode)
++ return nds32_expand_triop_builtin (d->icode, exp, target, d->return_p);
++
++ for (i = 0, d = bdesc_3argimm; i < ARRAY_SIZE (bdesc_3argimm); i++, d++)
++ if (d->code == fcode)
++ return nds32_expand_triopimm_builtin (d->icode, exp, target,
++ d->return_p, d->name);
++
++ for (i = 0, d = bdesc_load; i < ARRAY_SIZE (bdesc_load); i++, d++)
++ if (d->code == fcode)
++ return nds32_expand_builtin_load (d->icode, exp, target);
++
++ for (i = 0, d = bdesc_store; i < ARRAY_SIZE (bdesc_store); i++, d++)
++ if (d->code == fcode)
++ return nds32_expand_builtin_store (d->icode, exp, target);
++
++ for (i = 0, d = bdesc_cctl; i < ARRAY_SIZE (bdesc_cctl); i++, d++)
++ if (d->code == fcode)
++ return nds32_expand_cctl_builtin (d->icode, exp, target,
++ d->return_p, d->name);
++
+ return NULL_RTX;
+ }
+
++static GTY(()) tree nds32_builtin_decls[NDS32_BUILTIN_COUNT];
++
++/* Return the NDS32 builtin for CODE. */
++tree
++nds32_builtin_decl_impl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
++{
++ if (code >= NDS32_BUILTIN_COUNT)
++ return error_mark_node;
++
++ return nds32_builtin_decls[code];
++}
++
++void
++nds32_init_builtins_impl (void)
++{
++#define ADD_NDS32_BUILTIN0(NAME, RET_TYPE, CODE) \
++ nds32_builtin_decls[NDS32_BUILTIN_ ## CODE] = \
++ add_builtin_function ("__builtin_nds32_" NAME, \
++ build_function_type_list (RET_TYPE##_type_node, \
++ NULL_TREE), \
++ NDS32_BUILTIN_ ## CODE, BUILT_IN_MD, NULL, NULL_TREE)
++
++#define ADD_NDS32_BUILTIN1(NAME, RET_TYPE, ARG_TYPE, CODE) \
++ nds32_builtin_decls[NDS32_BUILTIN_ ## CODE] = \
++ add_builtin_function ("__builtin_nds32_" NAME, \
++ build_function_type_list (RET_TYPE##_type_node, \
++ ARG_TYPE##_type_node, \
++ NULL_TREE), \
++ NDS32_BUILTIN_ ## CODE, BUILT_IN_MD, NULL, NULL_TREE)
++
++#define ADD_NDS32_BUILTIN2(NAME, RET_TYPE, ARG_TYPE1, ARG_TYPE2, CODE) \
++ nds32_builtin_decls[NDS32_BUILTIN_ ## CODE] = \
++ add_builtin_function ("__builtin_nds32_" NAME, \
++ build_function_type_list (RET_TYPE##_type_node, \
++ ARG_TYPE1##_type_node,\
++ ARG_TYPE2##_type_node,\
++ NULL_TREE), \
++ NDS32_BUILTIN_ ## CODE, BUILT_IN_MD, NULL, NULL_TREE)
++
++#define ADD_NDS32_BUILTIN3(NAME, RET_TYPE, ARG_TYPE1, ARG_TYPE2, ARG_TYPE3, CODE) \
++ nds32_builtin_decls[NDS32_BUILTIN_ ## CODE] = \
++ add_builtin_function ("__builtin_nds32_" NAME, \
++ build_function_type_list (RET_TYPE##_type_node, \
++ ARG_TYPE1##_type_node,\
++ ARG_TYPE2##_type_node,\
++ ARG_TYPE3##_type_node,\
++ NULL_TREE), \
++ NDS32_BUILTIN_ ## CODE, BUILT_IN_MD, NULL, NULL_TREE)
++
++ /* Looking for return type and argument can be found in tree.h file. */
++ tree ptr_char_type_node = build_pointer_type (char_type_node);
++ tree ptr_uchar_type_node = build_pointer_type (unsigned_char_type_node);
++ tree ptr_ushort_type_node = build_pointer_type (short_unsigned_type_node);
++ tree ptr_short_type_node = build_pointer_type (short_integer_type_node);
++ tree ptr_uint_type_node = build_pointer_type (unsigned_type_node);
++ tree ptr_ulong_type_node = build_pointer_type (long_long_unsigned_type_node);
++ tree v4qi_type_node = build_vector_type (intQI_type_node, 4);
++ tree u_v4qi_type_node = build_vector_type (unsigned_intQI_type_node, 4);
++ tree v2hi_type_node = build_vector_type (intHI_type_node, 2);
++ tree u_v2hi_type_node = build_vector_type (unsigned_intHI_type_node, 2);
++ tree v2si_type_node = build_vector_type (intSI_type_node, 2);
++ tree u_v2si_type_node = build_vector_type (unsigned_intSI_type_node, 2);
++
++ /* Cache. */
++ ADD_NDS32_BUILTIN1 ("isync", void, ptr_uint, ISYNC);
++ ADD_NDS32_BUILTIN0 ("isb", void, ISB);
++ ADD_NDS32_BUILTIN0 ("dsb", void, DSB);
++ ADD_NDS32_BUILTIN0 ("msync_all", void, MSYNC_ALL);
++ ADD_NDS32_BUILTIN0 ("msync_store", void, MSYNC_STORE);
++
++ /* Register Transfer. */
++ ADD_NDS32_BUILTIN1 ("mfsr", unsigned, integer, MFSR);
++ ADD_NDS32_BUILTIN1 ("mfusr", unsigned, integer, MFUSR);
++ ADD_NDS32_BUILTIN2 ("mtsr", void, unsigned, integer, MTSR);
++ ADD_NDS32_BUILTIN2 ("mtsr_isb", void, unsigned, integer, MTSR_ISB);
++ ADD_NDS32_BUILTIN2 ("mtsr_dsb", void, unsigned, integer, MTSR_DSB);
++ ADD_NDS32_BUILTIN2 ("mtusr", void, unsigned, integer, MTUSR);
++
++ /* FPU Register Transfer. */
++ ADD_NDS32_BUILTIN0 ("fmfcsr", unsigned, FMFCSR);
++ ADD_NDS32_BUILTIN1 ("fmtcsr", void, unsigned, FMTCSR);
++ ADD_NDS32_BUILTIN0 ("fmfcfg", unsigned, FMFCFG);
++ ADD_NDS32_BUILTIN2 ("fcpyss", float, float, float, FCPYSS);
++ ADD_NDS32_BUILTIN2 ("fcpynss", float, float, float, FCPYNSS);
++ ADD_NDS32_BUILTIN2 ("fcpysd", double, double, double, FCPYSD);
++ ADD_NDS32_BUILTIN2 ("fcpynsd", double, double, double, FCPYNSD);
++
++ /* Interrupt. */
++ ADD_NDS32_BUILTIN0 ("setgie_en", void, SETGIE_EN);
++ ADD_NDS32_BUILTIN0 ("setgie_dis", void, SETGIE_DIS);
++ ADD_NDS32_BUILTIN0 ("gie_en", void, GIE_EN);
++ ADD_NDS32_BUILTIN0 ("gie_dis", void, GIE_DIS);
++ ADD_NDS32_BUILTIN1 ("enable_int", void, integer, ENABLE_INT);
++ ADD_NDS32_BUILTIN1 ("disable_int", void, integer, DISABLE_INT);
++ ADD_NDS32_BUILTIN0 ("set_pending_swint", void, SET_PENDING_SWINT);
++ ADD_NDS32_BUILTIN0 ("clr_pending_swint", void, CLR_PENDING_SWINT);
++ ADD_NDS32_BUILTIN0 ("get_all_pending_int", unsigned, GET_ALL_PENDING_INT);
++ ADD_NDS32_BUILTIN1 ("get_pending_int", unsigned, integer, GET_PENDING_INT);
++ ADD_NDS32_BUILTIN1 ("get_int_priority", unsigned, integer, GET_INT_PRIORITY);
++ ADD_NDS32_BUILTIN2 ("set_int_priority", void, integer, integer,
++ SET_INT_PRIORITY);
++ ADD_NDS32_BUILTIN1 ("clr_pending_hwint", void, integer, CLR_PENDING_HWINT);
++ ADD_NDS32_BUILTIN1 ("set_trig_level", void, integer, SET_TRIG_LEVEL);
++ ADD_NDS32_BUILTIN1 ("set_trig_edge", void, integer, SET_TRIG_EDGE);
++ ADD_NDS32_BUILTIN1 ("get_trig_type", unsigned, integer, GET_TRIG_TYPE);
++
++ /* Load and Store */
++ ADD_NDS32_BUILTIN1 ("llw", unsigned, ptr_uint, LLW);
++ ADD_NDS32_BUILTIN1 ("lwup", unsigned, ptr_uint, LWUP);
++ ADD_NDS32_BUILTIN1 ("lbup", char, ptr_uchar, LBUP);
++ ADD_NDS32_BUILTIN2 ("scw", unsigned, ptr_uint, unsigned, SCW);
++ ADD_NDS32_BUILTIN2 ("swup", void, ptr_uint, unsigned, SWUP);
++ ADD_NDS32_BUILTIN2 ("sbup", void, ptr_uchar, char, SBUP);
++
++ /* CCTL */
++ ADD_NDS32_BUILTIN0 ("cctl_l1d_invalall", void, CCTL_L1D_INVALALL);
++ ADD_NDS32_BUILTIN0 ("cctl_l1d_wball_alvl", void, CCTL_L1D_WBALL_ALVL);
++ ADD_NDS32_BUILTIN0 ("cctl_l1d_wball_one_lvl", void, CCTL_L1D_WBALL_ONE_LVL);
++ ADD_NDS32_BUILTIN2 ("cctl_va_lck", void, integer, ptr_uint, CCTL_VA_LCK);
++ ADD_NDS32_BUILTIN2 ("cctl_idx_wbinval", void, integer, unsigned,
++ CCTL_IDX_WBINVAL);
++ ADD_NDS32_BUILTIN2 ("cctl_va_wbinval_l1", void, integer, ptr_uint,
++ CCTL_VA_WBINVAL_L1);
++ ADD_NDS32_BUILTIN2 ("cctl_va_wbinval_la", void, integer, ptr_uint,
++ CCTL_VA_WBINVAL_LA);
++ ADD_NDS32_BUILTIN2 ("cctl_idx_read", unsigned, integer, unsigned,
++ CCTL_IDX_READ);
++ ADD_NDS32_BUILTIN3 ("cctl_idx_write", void, integer, unsigned, unsigned,
++ CCTL_IDX_WRITE);
++
++ /* PREFETCH */
++ ADD_NDS32_BUILTIN3 ("dpref_qw", void, ptr_uchar, unsigned, integer, DPREF_QW);
++ ADD_NDS32_BUILTIN3 ("dpref_hw", void, ptr_ushort, unsigned, integer,
++ DPREF_HW);
++ ADD_NDS32_BUILTIN3 ("dpref_w", void, ptr_uint, unsigned, integer, DPREF_W);
++ ADD_NDS32_BUILTIN3 ("dpref_dw", void, ptr_ulong, unsigned, integer, DPREF_DW);
++
++ /* Performance Extension */
++ ADD_NDS32_BUILTIN1 ("pe_abs", integer, integer, ABS);
++ ADD_NDS32_BUILTIN2 ("pe_ave", integer, integer, integer, AVE);
++ ADD_NDS32_BUILTIN2 ("pe_bclr", unsigned, unsigned, unsigned, BCLR);
++ ADD_NDS32_BUILTIN2 ("pe_bset", unsigned, unsigned, unsigned, BSET);
++ ADD_NDS32_BUILTIN2 ("pe_btgl", unsigned, unsigned, unsigned, BTGL);
++ ADD_NDS32_BUILTIN2 ("pe_btst", unsigned, unsigned, unsigned, BTST);
++ ADD_NDS32_BUILTIN2 ("pe_clip", unsigned, integer, unsigned, CLIP);
++ ADD_NDS32_BUILTIN2 ("pe_clips", integer, integer, unsigned, CLIPS);
++ ADD_NDS32_BUILTIN1 ("pe_clz", unsigned, unsigned, CLZ);
++ ADD_NDS32_BUILTIN1 ("pe_clo", unsigned, unsigned, CLO);
++
++ /* Performance Extension 2 */
++ ADD_NDS32_BUILTIN3 ("pe2_bse", void, ptr_uint, unsigned, ptr_uint, BSE);
++ ADD_NDS32_BUILTIN3 ("pe2_bsp", void, ptr_uint, unsigned, ptr_uint, BSP);
++ ADD_NDS32_BUILTIN2 ("pe2_pbsad", unsigned, unsigned, unsigned, PBSAD);
++ ADD_NDS32_BUILTIN3 ("pe2_pbsada", unsigned, unsigned, unsigned, unsigned,
++ PBSADA);
++
++ /* String Extension */
++ ADD_NDS32_BUILTIN2 ("se_ffb", integer, unsigned, unsigned, FFB);
++ ADD_NDS32_BUILTIN2 ("se_ffmism", integer, unsigned, unsigned, FFMISM);
++ ADD_NDS32_BUILTIN2 ("se_flmism", integer, unsigned, unsigned, FLMISM);
++
++ /* SATURATION */
++ ADD_NDS32_BUILTIN2 ("kaddw", integer, integer, integer, KADDW);
++ ADD_NDS32_BUILTIN2 ("ksubw", integer, integer, integer, KSUBW);
++ ADD_NDS32_BUILTIN2 ("kaddh", integer, integer, integer, KADDH);
++ ADD_NDS32_BUILTIN2 ("ksubh", integer, integer, integer, KSUBH);
++ ADD_NDS32_BUILTIN2 ("kdmbb", integer, unsigned, unsigned, KDMBB);
++ ADD_NDS32_BUILTIN2 ("v_kdmbb", integer, v2hi, v2hi, V_KDMBB);
++ ADD_NDS32_BUILTIN2 ("kdmbt", integer, unsigned, unsigned, KDMBT);
++ ADD_NDS32_BUILTIN2 ("v_kdmbt", integer, v2hi, v2hi, V_KDMBT);
++ ADD_NDS32_BUILTIN2 ("kdmtb", integer, unsigned, unsigned, KDMTB);
++ ADD_NDS32_BUILTIN2 ("v_kdmtb", integer, v2hi, v2hi, V_KDMTB);
++ ADD_NDS32_BUILTIN2 ("kdmtt", integer, unsigned, unsigned, KDMTT);
++ ADD_NDS32_BUILTIN2 ("v_kdmtt", integer, v2hi, v2hi, V_KDMTT);
++ ADD_NDS32_BUILTIN2 ("khmbb", integer, unsigned, unsigned, KHMBB);
++ ADD_NDS32_BUILTIN2 ("v_khmbb", integer, v2hi, v2hi, V_KHMBB);
++ ADD_NDS32_BUILTIN2 ("khmbt", integer, unsigned, unsigned, KHMBT);
++ ADD_NDS32_BUILTIN2 ("v_khmbt", integer, v2hi, v2hi, V_KHMBT);
++ ADD_NDS32_BUILTIN2 ("khmtb", integer, unsigned, unsigned, KHMTB);
++ ADD_NDS32_BUILTIN2 ("v_khmtb", integer, v2hi, v2hi, V_KHMTB);
++ ADD_NDS32_BUILTIN2 ("khmtt", integer, unsigned, unsigned, KHMTT);
++ ADD_NDS32_BUILTIN2 ("v_khmtt", integer, v2hi, v2hi, V_KHMTT);
++ ADD_NDS32_BUILTIN2 ("kslraw", integer, integer, integer, KSLRAW);
++ ADD_NDS32_BUILTIN2 ("kslraw_u", integer, integer, integer, KSLRAW_U);
++ ADD_NDS32_BUILTIN0 ("rdov", unsigned, RDOV);
++ ADD_NDS32_BUILTIN0 ("clrov", void, CLROV);
++
++ /* ROTR */
++ ADD_NDS32_BUILTIN2 ("rotr", unsigned, unsigned, unsigned, ROTR);
++
++ /* Swap */
++ ADD_NDS32_BUILTIN1 ("wsbh", unsigned, unsigned, WSBH);
++
++ /* System */
++ ADD_NDS32_BUILTIN2 ("svs", unsigned, integer, integer, SVS);
++ ADD_NDS32_BUILTIN2 ("sva", unsigned, integer, integer, SVA);
++ ADD_NDS32_BUILTIN1 ("jr_itoff", void, unsigned, JR_ITOFF);
++ ADD_NDS32_BUILTIN1 ("jr_toff", void, unsigned, JR_TOFF);
++ ADD_NDS32_BUILTIN1 ("jral_iton", void, unsigned, JRAL_ITON);
++ ADD_NDS32_BUILTIN1 ("jral_ton", void, unsigned, JRAL_TON);
++ ADD_NDS32_BUILTIN1 ("ret_itoff", void, unsigned, RET_ITOFF);
++ ADD_NDS32_BUILTIN1 ("ret_toff", void, unsigned, RET_TOFF);
++ ADD_NDS32_BUILTIN0 ("standby_no_wake_grant", void, STANDBY_NO_WAKE_GRANT);
++ ADD_NDS32_BUILTIN0 ("standby_wake_grant", void, STANDBY_WAKE_GRANT);
++ ADD_NDS32_BUILTIN0 ("standby_wait_done", void, STANDBY_WAKE_DONE);
++ ADD_NDS32_BUILTIN1 ("break", void, unsigned, BREAK);
++ ADD_NDS32_BUILTIN1 ("syscall", void, unsigned, SYSCALL);
++ ADD_NDS32_BUILTIN0 ("nop", void, NOP);
++ ADD_NDS32_BUILTIN0 ("get_current_sp", unsigned, GET_CURRENT_SP);
++ ADD_NDS32_BUILTIN1 ("set_current_sp", void, unsigned, SET_CURRENT_SP);
++ ADD_NDS32_BUILTIN2 ("teqz", void, unsigned, unsigned, TEQZ);
++ ADD_NDS32_BUILTIN2 ("tnez", void, unsigned, unsigned, TNEZ);
++ ADD_NDS32_BUILTIN1 ("trap", void, unsigned, TRAP);
++ ADD_NDS32_BUILTIN0 ("return_address", unsigned, RETURN_ADDRESS);
++ ADD_NDS32_BUILTIN0 ("setend_big", void, SETEND_BIG);
++ ADD_NDS32_BUILTIN0 ("setend_little", void, SETEND_LITTLE);
++
++ /* Schedule Barrier */
++ ADD_NDS32_BUILTIN0 ("schedule_barrier", void, SCHE_BARRIER);
++
++ /* TLBOP */
++ ADD_NDS32_BUILTIN1 ("tlbop_trd", void, unsigned, TLBOP_TRD);
++ ADD_NDS32_BUILTIN1 ("tlbop_twr", void, unsigned, TLBOP_TWR);
++ ADD_NDS32_BUILTIN1 ("tlbop_rwr", void, unsigned, TLBOP_RWR);
++ ADD_NDS32_BUILTIN1 ("tlbop_rwlk", void, unsigned, TLBOP_RWLK);
++ ADD_NDS32_BUILTIN1 ("tlbop_unlk", void, unsigned, TLBOP_UNLK);
++ ADD_NDS32_BUILTIN1 ("tlbop_pb", unsigned, unsigned, TLBOP_PB);
++ ADD_NDS32_BUILTIN1 ("tlbop_inv", void, unsigned, TLBOP_INV);
++ ADD_NDS32_BUILTIN0 ("tlbop_flua", void, TLBOP_FLUA);
++
++ /* Unaligned Load/Store */
++ ADD_NDS32_BUILTIN1 ("unaligned_load_hw", short_unsigned, ptr_ushort,
++ UALOAD_HW);
++ ADD_NDS32_BUILTIN1 ("unaligned_load_w", unsigned, ptr_uint, UALOAD_W);
++ ADD_NDS32_BUILTIN1 ("unaligned_load_dw", long_long_unsigned, ptr_ulong,
++ UALOAD_DW);
++ ADD_NDS32_BUILTIN2 ("unaligned_store_hw", void, ptr_ushort, short_unsigned,
++ UASTORE_HW);
++ ADD_NDS32_BUILTIN2 ("unaligned_store_w", void, ptr_uint, unsigned, UASTORE_W);
++ ADD_NDS32_BUILTIN2 ("unaligned_store_dw", void, ptr_ulong, long_long_unsigned,
++ UASTORE_DW);
++ ADD_NDS32_BUILTIN0 ("unaligned_feature", unsigned, UNALIGNED_FEATURE);
++ ADD_NDS32_BUILTIN0 ("enable_unaligned", void, ENABLE_UNALIGNED);
++ ADD_NDS32_BUILTIN0 ("disable_unaligned", void, DISABLE_UNALIGNED);
++
++ /* Instruction sequence protection */
++ ADD_NDS32_BUILTIN0 ("signature_begin", void, SIGNATURE_BEGIN);
++ ADD_NDS32_BUILTIN0 ("signature_end", void, SIGNATURE_END);
++
++ /* DSP Extension: SIMD 16bit Add and Subtract. */
++ ADD_NDS32_BUILTIN2 ("add16", unsigned, unsigned, unsigned, ADD16);
++ ADD_NDS32_BUILTIN2 ("v_uadd16", u_v2hi, u_v2hi, u_v2hi, V_UADD16);
++ ADD_NDS32_BUILTIN2 ("v_sadd16", v2hi, v2hi, v2hi, V_SADD16);
++ ADD_NDS32_BUILTIN2 ("radd16", unsigned, unsigned, unsigned, RADD16);
++ ADD_NDS32_BUILTIN2 ("v_radd16", v2hi, v2hi, v2hi, V_RADD16);
++ ADD_NDS32_BUILTIN2 ("uradd16", unsigned, unsigned, unsigned, URADD16);
++ ADD_NDS32_BUILTIN2 ("v_uradd16", u_v2hi, u_v2hi, u_v2hi, V_URADD16);
++ ADD_NDS32_BUILTIN2 ("kadd16", unsigned, unsigned, unsigned, KADD16);
++ ADD_NDS32_BUILTIN2 ("v_kadd16", v2hi, v2hi, v2hi, V_KADD16);
++ ADD_NDS32_BUILTIN2 ("ukadd16", unsigned, unsigned, unsigned, UKADD16);
++ ADD_NDS32_BUILTIN2 ("v_ukadd16", u_v2hi, u_v2hi, u_v2hi, V_UKADD16);
++ ADD_NDS32_BUILTIN2 ("sub16", unsigned, unsigned, unsigned, SUB16);
++ ADD_NDS32_BUILTIN2 ("v_usub16", u_v2hi, u_v2hi, u_v2hi, V_USUB16);
++ ADD_NDS32_BUILTIN2 ("v_ssub16", v2hi, v2hi, v2hi, V_SSUB16);
++ ADD_NDS32_BUILTIN2 ("rsub16", unsigned, unsigned, unsigned, RSUB16);
++ ADD_NDS32_BUILTIN2 ("v_rsub16", v2hi, v2hi, v2hi, V_RSUB16);
++ ADD_NDS32_BUILTIN2 ("ursub16", unsigned, unsigned, unsigned, URSUB16);
++ ADD_NDS32_BUILTIN2 ("v_ursub16", u_v2hi, u_v2hi, u_v2hi, V_URSUB16);
++ ADD_NDS32_BUILTIN2 ("ksub16", unsigned, unsigned, unsigned, KSUB16);
++ ADD_NDS32_BUILTIN2 ("v_ksub16", v2hi, v2hi, v2hi, V_KSUB16);
++ ADD_NDS32_BUILTIN2 ("uksub16", unsigned, unsigned, unsigned, UKSUB16);
++ ADD_NDS32_BUILTIN2 ("v_uksub16", u_v2hi, u_v2hi, u_v2hi, V_UKSUB16);
++ ADD_NDS32_BUILTIN2 ("cras16", unsigned, unsigned, unsigned, CRAS16);
++ ADD_NDS32_BUILTIN2 ("v_ucras16", u_v2hi, u_v2hi, u_v2hi, V_UCRAS16);
++ ADD_NDS32_BUILTIN2 ("v_scras16", v2hi, v2hi, v2hi, V_SCRAS16);
++ ADD_NDS32_BUILTIN2 ("rcras16", unsigned, unsigned, unsigned, RCRAS16);
++ ADD_NDS32_BUILTIN2 ("v_rcras16", v2hi, v2hi, v2hi, V_RCRAS16);
++ ADD_NDS32_BUILTIN2 ("urcras16", unsigned, unsigned, unsigned, URCRAS16);
++ ADD_NDS32_BUILTIN2 ("v_urcras16", u_v2hi, u_v2hi, u_v2hi, V_URCRAS16);
++ ADD_NDS32_BUILTIN2 ("kcras16", unsigned, unsigned, unsigned, KCRAS16);
++ ADD_NDS32_BUILTIN2 ("v_kcras16", v2hi, v2hi, v2hi, V_KCRAS16);
++ ADD_NDS32_BUILTIN2 ("ukcras16", unsigned, unsigned, unsigned, UKCRAS16);
++ ADD_NDS32_BUILTIN2 ("v_ukcras16", u_v2hi, u_v2hi, u_v2hi, V_UKCRAS16);
++ ADD_NDS32_BUILTIN2 ("crsa16", unsigned, unsigned, unsigned, CRSA16);
++ ADD_NDS32_BUILTIN2 ("v_ucrsa16", u_v2hi, u_v2hi, u_v2hi, V_UCRSA16);
++ ADD_NDS32_BUILTIN2 ("v_scrsa16", v2hi, v2hi, v2hi, V_SCRSA16);
++ ADD_NDS32_BUILTIN2 ("rcrsa16", unsigned, unsigned, unsigned, RCRSA16);
++ ADD_NDS32_BUILTIN2 ("v_rcrsa16", v2hi, v2hi, v2hi, V_RCRSA16);
++ ADD_NDS32_BUILTIN2 ("urcrsa16", unsigned, unsigned, unsigned, URCRSA16);
++ ADD_NDS32_BUILTIN2 ("v_urcrsa16", u_v2hi, u_v2hi, u_v2hi, V_URCRSA16);
++ ADD_NDS32_BUILTIN2 ("kcrsa16", unsigned, unsigned, unsigned, KCRSA16);
++ ADD_NDS32_BUILTIN2 ("v_kcrsa16", v2hi, v2hi, v2hi, V_KCRSA16);
++ ADD_NDS32_BUILTIN2 ("ukcrsa16", unsigned, unsigned, unsigned, UKCRSA16);
++ ADD_NDS32_BUILTIN2 ("v_ukcrsa16", u_v2hi, u_v2hi, u_v2hi, V_UKCRSA16);
++
++ /* DSP Extension: SIMD 8bit Add and Subtract. */
++ ADD_NDS32_BUILTIN2 ("add8", integer, integer, integer, ADD8);
++ ADD_NDS32_BUILTIN2 ("v_uadd8", u_v4qi, u_v4qi, u_v4qi, V_UADD8);
++ ADD_NDS32_BUILTIN2 ("v_sadd8", v4qi, v4qi, v4qi, V_SADD8);
++ ADD_NDS32_BUILTIN2 ("radd8", unsigned, unsigned, unsigned, RADD8);
++ ADD_NDS32_BUILTIN2 ("v_radd8", v4qi, v4qi, v4qi, V_RADD8);
++ ADD_NDS32_BUILTIN2 ("uradd8", unsigned, unsigned, unsigned, URADD8);
++ ADD_NDS32_BUILTIN2 ("v_uradd8", u_v4qi, u_v4qi, u_v4qi, V_URADD8);
++ ADD_NDS32_BUILTIN2 ("kadd8", unsigned, unsigned, unsigned, KADD8);
++ ADD_NDS32_BUILTIN2 ("v_kadd8", v4qi, v4qi, v4qi, V_KADD8);
++ ADD_NDS32_BUILTIN2 ("ukadd8", unsigned, unsigned, unsigned, UKADD8);
++ ADD_NDS32_BUILTIN2 ("v_ukadd8", u_v4qi, u_v4qi, u_v4qi, V_UKADD8);
++ ADD_NDS32_BUILTIN2 ("sub8", integer, integer, integer, SUB8);
++ ADD_NDS32_BUILTIN2 ("v_usub8", u_v4qi, u_v4qi, u_v4qi, V_USUB8);
++ ADD_NDS32_BUILTIN2 ("v_ssub8", v4qi, v4qi, v4qi, V_SSUB8);
++ ADD_NDS32_BUILTIN2 ("rsub8", unsigned, unsigned, unsigned, RSUB8);
++ ADD_NDS32_BUILTIN2 ("v_rsub8", v4qi, v4qi, v4qi, V_RSUB8);
++ ADD_NDS32_BUILTIN2 ("ursub8", unsigned, unsigned, unsigned, URSUB8);
++ ADD_NDS32_BUILTIN2 ("v_ursub8", u_v4qi, u_v4qi, u_v4qi, V_URSUB8);
++ ADD_NDS32_BUILTIN2 ("ksub8", unsigned, unsigned, unsigned, KSUB8);
++ ADD_NDS32_BUILTIN2 ("v_ksub8", v4qi, v4qi, v4qi, V_KSUB8);
++ ADD_NDS32_BUILTIN2 ("uksub8", unsigned, unsigned, unsigned, UKSUB8);
++ ADD_NDS32_BUILTIN2 ("v_uksub8", u_v4qi, u_v4qi, u_v4qi, V_UKSUB8);
++
++ /* DSP Extension: SIMD 16bit Shift. */
++ ADD_NDS32_BUILTIN2 ("sra16", unsigned, unsigned, unsigned, SRA16);
++ ADD_NDS32_BUILTIN2 ("v_sra16", v2hi, v2hi, unsigned, V_SRA16);
++ ADD_NDS32_BUILTIN2 ("sra16_u", unsigned, unsigned, unsigned, SRA16_U);
++ ADD_NDS32_BUILTIN2 ("v_sra16_u", v2hi, v2hi, unsigned, V_SRA16_U);
++ ADD_NDS32_BUILTIN2 ("srl16", unsigned, unsigned, unsigned, SRL16);
++ ADD_NDS32_BUILTIN2 ("v_srl16", u_v2hi, u_v2hi, unsigned, V_SRL16);
++ ADD_NDS32_BUILTIN2 ("srl16_u", unsigned, unsigned, unsigned, SRL16_U);
++ ADD_NDS32_BUILTIN2 ("v_srl16_u", u_v2hi, u_v2hi, unsigned, V_SRL16_U);
++ ADD_NDS32_BUILTIN2 ("sll16", unsigned, unsigned, unsigned, SLL16);
++ ADD_NDS32_BUILTIN2 ("v_sll16", u_v2hi, u_v2hi, unsigned, V_SLL16);
++ ADD_NDS32_BUILTIN2 ("ksll16", unsigned, unsigned, unsigned, KSLL16);
++ ADD_NDS32_BUILTIN2 ("v_ksll16", v2hi, v2hi, unsigned, V_KSLL16);
++ ADD_NDS32_BUILTIN2 ("kslra16", unsigned, unsigned, unsigned, KSLRA16);
++ ADD_NDS32_BUILTIN2 ("v_kslra16", v2hi, v2hi, unsigned, V_KSLRA16);
++ ADD_NDS32_BUILTIN2 ("kslra16_u", unsigned, unsigned, unsigned, KSLRA16_U);
++ ADD_NDS32_BUILTIN2 ("v_kslra16_u", v2hi, v2hi, unsigned, V_KSLRA16_U);
++
++ /* DSP Extension: 16bit Compare. */
++ ADD_NDS32_BUILTIN2 ("cmpeq16", unsigned, unsigned, unsigned, CMPEQ16);
++ ADD_NDS32_BUILTIN2 ("v_scmpeq16", u_v2hi, v2hi, v2hi, V_SCMPEQ16);
++ ADD_NDS32_BUILTIN2 ("v_ucmpeq16", u_v2hi, u_v2hi, u_v2hi, V_UCMPEQ16);
++ ADD_NDS32_BUILTIN2 ("scmplt16", unsigned, unsigned, unsigned, SCMPLT16);
++ ADD_NDS32_BUILTIN2 ("v_scmplt16", u_v2hi, v2hi, v2hi, V_SCMPLT16);
++ ADD_NDS32_BUILTIN2 ("scmple16", unsigned, unsigned, unsigned, SCMPLE16);
++ ADD_NDS32_BUILTIN2 ("v_scmple16", u_v2hi, v2hi, v2hi, V_SCMPLE16);
++ ADD_NDS32_BUILTIN2 ("ucmplt16", unsigned, unsigned, unsigned, UCMPLT16);
++ ADD_NDS32_BUILTIN2 ("v_ucmplt16", u_v2hi, u_v2hi, u_v2hi, V_UCMPLT16);
++ ADD_NDS32_BUILTIN2 ("ucmple16", unsigned, unsigned, unsigned, UCMPLE16);
++ ADD_NDS32_BUILTIN2 ("v_ucmple16", u_v2hi, u_v2hi, u_v2hi, V_UCMPLE16);
++
++ /* DSP Extension: 8bit Compare. */
++ ADD_NDS32_BUILTIN2 ("cmpeq8", unsigned, unsigned, unsigned, CMPEQ8);
++ ADD_NDS32_BUILTIN2 ("v_scmpeq8", u_v4qi, v4qi, v4qi, V_SCMPEQ8);
++ ADD_NDS32_BUILTIN2 ("v_ucmpeq8", u_v4qi, u_v4qi, u_v4qi, V_UCMPEQ8);
++ ADD_NDS32_BUILTIN2 ("scmplt8", unsigned, unsigned, unsigned, SCMPLT8);
++ ADD_NDS32_BUILTIN2 ("v_scmplt8", u_v4qi, v4qi, v4qi, V_SCMPLT8);
++ ADD_NDS32_BUILTIN2 ("scmple8", unsigned, unsigned, unsigned, SCMPLE8);
++ ADD_NDS32_BUILTIN2 ("v_scmple8", u_v4qi, v4qi, v4qi, V_SCMPLE8);
++ ADD_NDS32_BUILTIN2 ("ucmplt8", unsigned, unsigned, unsigned, UCMPLT8);
++ ADD_NDS32_BUILTIN2 ("v_ucmplt8", u_v4qi, u_v4qi, u_v4qi, V_UCMPLT8);
++ ADD_NDS32_BUILTIN2 ("ucmple8", unsigned, unsigned, unsigned, UCMPLE8);
++ ADD_NDS32_BUILTIN2 ("v_ucmple8", u_v4qi, u_v4qi, u_v4qi, V_UCMPLE8);
++
++ /* DSP Extension: SIMD 16bit MISC. */
++ ADD_NDS32_BUILTIN2 ("smin16", unsigned, unsigned, unsigned, SMIN16);
++ ADD_NDS32_BUILTIN2 ("v_smin16", v2hi, v2hi, v2hi, V_SMIN16);
++ ADD_NDS32_BUILTIN2 ("umin16", unsigned, unsigned, unsigned, UMIN16);
++ ADD_NDS32_BUILTIN2 ("v_umin16", u_v2hi, u_v2hi, u_v2hi, V_UMIN16);
++ ADD_NDS32_BUILTIN2 ("smax16", unsigned, unsigned, unsigned, SMAX16);
++ ADD_NDS32_BUILTIN2 ("v_smax16", v2hi, v2hi, v2hi, V_SMAX16);
++ ADD_NDS32_BUILTIN2 ("umax16", unsigned, unsigned, unsigned, UMAX16);
++ ADD_NDS32_BUILTIN2 ("v_umax16", u_v2hi, u_v2hi, u_v2hi, V_UMAX16);
++ ADD_NDS32_BUILTIN2 ("sclip16", unsigned, unsigned, unsigned, SCLIP16);
++ ADD_NDS32_BUILTIN2 ("v_sclip16", v2hi, v2hi, unsigned, V_SCLIP16);
++ ADD_NDS32_BUILTIN2 ("uclip16", unsigned, unsigned, unsigned, UCLIP16);
++ ADD_NDS32_BUILTIN2 ("v_uclip16", v2hi, v2hi, unsigned, V_UCLIP16);
++ ADD_NDS32_BUILTIN2 ("khm16", unsigned, unsigned, unsigned, KHM16);
++ ADD_NDS32_BUILTIN2 ("v_khm16", v2hi, v2hi, v2hi, V_KHM16);
++ ADD_NDS32_BUILTIN2 ("khmx16", unsigned, unsigned, unsigned, KHMX16);
++ ADD_NDS32_BUILTIN2 ("v_khmx16", v2hi, v2hi, v2hi, V_KHMX16);
++ ADD_NDS32_BUILTIN1 ("kabs16", unsigned, unsigned, KABS16);
++ ADD_NDS32_BUILTIN1 ("v_kabs16", v2hi, v2hi, V_KABS16);
++ ADD_NDS32_BUILTIN2 ("smul16", long_long_unsigned, unsigned, unsigned, SMUL16);
++ ADD_NDS32_BUILTIN2 ("v_smul16", v2si, v2hi, v2hi, V_SMUL16);
++ ADD_NDS32_BUILTIN2 ("smulx16",
++ long_long_unsigned, unsigned, unsigned, SMULX16);
++ ADD_NDS32_BUILTIN2 ("v_smulx16", v2si, v2hi, v2hi, V_SMULX16);
++ ADD_NDS32_BUILTIN2 ("umul16", long_long_unsigned, unsigned, unsigned, UMUL16);
++ ADD_NDS32_BUILTIN2 ("v_umul16", u_v2si, u_v2hi, u_v2hi, V_UMUL16);
++ ADD_NDS32_BUILTIN2 ("umulx16",
++ long_long_unsigned, unsigned, unsigned, UMULX16);
++ ADD_NDS32_BUILTIN2 ("v_umulx16", u_v2si, u_v2hi, u_v2hi, V_UMULX16);
++
++ /* DSP Extension: SIMD 8bit MISC. */
++ ADD_NDS32_BUILTIN2 ("smin8", unsigned, unsigned, unsigned, SMIN8);
++ ADD_NDS32_BUILTIN2 ("v_smin8", v4qi, v4qi, v4qi, V_SMIN8);
++ ADD_NDS32_BUILTIN2 ("umin8", unsigned, unsigned, unsigned, UMIN8);
++ ADD_NDS32_BUILTIN2 ("v_umin8", u_v4qi, u_v4qi, u_v4qi, V_UMIN8);
++ ADD_NDS32_BUILTIN2 ("smax8", unsigned, unsigned, unsigned, SMAX8);
++ ADD_NDS32_BUILTIN2 ("v_smax8", v4qi, v4qi, v4qi, V_SMAX8);
++ ADD_NDS32_BUILTIN2 ("umax8", unsigned, unsigned, unsigned, UMAX8);
++ ADD_NDS32_BUILTIN2 ("v_umax8", u_v4qi, u_v4qi, u_v4qi, V_UMAX8);
++ ADD_NDS32_BUILTIN1 ("kabs8", unsigned, unsigned, KABS8);
++ ADD_NDS32_BUILTIN1 ("v_kabs8", v4qi, v4qi, V_KABS8);
++
++ /* DSP Extension: 8bit Unpacking. */
++ ADD_NDS32_BUILTIN1 ("sunpkd810", unsigned, unsigned, SUNPKD810);
++ ADD_NDS32_BUILTIN1 ("v_sunpkd810", v2hi, v4qi, V_SUNPKD810);
++ ADD_NDS32_BUILTIN1 ("sunpkd820", unsigned, unsigned, SUNPKD820);
++ ADD_NDS32_BUILTIN1 ("v_sunpkd820", v2hi, v4qi, V_SUNPKD820);
++ ADD_NDS32_BUILTIN1 ("sunpkd830", unsigned, unsigned, SUNPKD830);
++ ADD_NDS32_BUILTIN1 ("v_sunpkd830", v2hi, v4qi, V_SUNPKD830);
++ ADD_NDS32_BUILTIN1 ("sunpkd831", unsigned, unsigned, SUNPKD831);
++ ADD_NDS32_BUILTIN1 ("v_sunpkd831", v2hi, v4qi, V_SUNPKD831);
++ ADD_NDS32_BUILTIN1 ("zunpkd810", unsigned, unsigned, ZUNPKD810);
++ ADD_NDS32_BUILTIN1 ("v_zunpkd810", u_v2hi, u_v4qi, V_ZUNPKD810);
++ ADD_NDS32_BUILTIN1 ("zunpkd820", unsigned, unsigned, ZUNPKD820);
++ ADD_NDS32_BUILTIN1 ("v_zunpkd820", u_v2hi, u_v4qi, V_ZUNPKD820);
++ ADD_NDS32_BUILTIN1 ("zunpkd830", unsigned, unsigned, ZUNPKD830);
++ ADD_NDS32_BUILTIN1 ("v_zunpkd830", u_v2hi, u_v4qi, V_ZUNPKD830);
++ ADD_NDS32_BUILTIN1 ("zunpkd831", unsigned, unsigned, ZUNPKD831);
++ ADD_NDS32_BUILTIN1 ("v_zunpkd831", u_v2hi, u_v4qi, V_ZUNPKD831);
++
++ /* DSP Extension: 32bit Add and Subtract. */
++ ADD_NDS32_BUILTIN2 ("raddw", integer, integer, integer, RADDW);
++ ADD_NDS32_BUILTIN2 ("uraddw", unsigned, unsigned, unsigned, URADDW);
++ ADD_NDS32_BUILTIN2 ("rsubw", integer, integer, integer, RSUBW);
++ ADD_NDS32_BUILTIN2 ("ursubw", unsigned, unsigned, unsigned, URSUBW);
++
++ /* DSP Extension: 32bit Shift. */
++ ADD_NDS32_BUILTIN2 ("sra_u", integer, integer, unsigned, SRA_U);
++ ADD_NDS32_BUILTIN2 ("ksll", integer, integer, unsigned, KSLL);
++
++ /* DSP Extension: 16bit Packing. */
++ ADD_NDS32_BUILTIN2 ("pkbb16", unsigned, unsigned, unsigned, PKBB16);
++ ADD_NDS32_BUILTIN2 ("v_pkbb16", u_v2hi, u_v2hi, u_v2hi, V_PKBB16);
++ ADD_NDS32_BUILTIN2 ("pkbt16", unsigned, unsigned, unsigned, PKBT16);
++ ADD_NDS32_BUILTIN2 ("v_pkbt16", u_v2hi, u_v2hi, u_v2hi, V_PKBT16);
++ ADD_NDS32_BUILTIN2 ("pktb16", unsigned, unsigned, unsigned, PKTB16);
++ ADD_NDS32_BUILTIN2 ("v_pktb16", u_v2hi, u_v2hi, u_v2hi, V_PKTB16);
++ ADD_NDS32_BUILTIN2 ("pktt16", unsigned, unsigned, unsigned, PKTT16);
++ ADD_NDS32_BUILTIN2 ("v_pktt16", u_v2hi, u_v2hi, u_v2hi, V_PKTT16);
++
++ /* DSP Extension: Signed MSW 32x32 Multiply and ADD. */
++ ADD_NDS32_BUILTIN2 ("smmul", integer, integer, integer, SMMUL);
++ ADD_NDS32_BUILTIN2 ("smmul_u", integer, integer, integer, SMMUL_U);
++ ADD_NDS32_BUILTIN3 ("kmmac", integer, integer, integer, integer, KMMAC);
++ ADD_NDS32_BUILTIN3 ("kmmac_u", integer, integer, integer, integer, KMMAC_U);
++ ADD_NDS32_BUILTIN3 ("kmmsb", integer, integer, integer, integer, KMMSB);
++ ADD_NDS32_BUILTIN3 ("kmmsb_u", integer, integer, integer, integer, KMMSB_U);
++ ADD_NDS32_BUILTIN2 ("kwmmul", integer, integer, integer, KWMMUL);
++ ADD_NDS32_BUILTIN2 ("kwmmul_u", integer, integer, integer, KWMMUL_U);
++
++ /* DSP Extension: Most Significant Word 32x16 Multiply and ADD. */
++ ADD_NDS32_BUILTIN2 ("smmwb", integer, integer, unsigned, SMMWB);
++ ADD_NDS32_BUILTIN2 ("v_smmwb", integer, integer, v2hi, V_SMMWB);
++ ADD_NDS32_BUILTIN2 ("smmwb_u", integer, integer, unsigned, SMMWB_U);
++ ADD_NDS32_BUILTIN2 ("v_smmwb_u", integer, integer, v2hi, V_SMMWB_U);
++ ADD_NDS32_BUILTIN2 ("smmwt", integer, integer, unsigned, SMMWT);
++ ADD_NDS32_BUILTIN2 ("v_smmwt", integer, integer, v2hi, V_SMMWT);
++ ADD_NDS32_BUILTIN2 ("smmwt_u", integer, integer, unsigned, SMMWT_U);
++ ADD_NDS32_BUILTIN2 ("v_smmwt_u", integer, integer, v2hi, V_SMMWT_U);
++ ADD_NDS32_BUILTIN3 ("kmmawb", integer, integer, integer, unsigned, KMMAWB);
++ ADD_NDS32_BUILTIN3 ("v_kmmawb", integer, integer, integer, v2hi, V_KMMAWB);
++ ADD_NDS32_BUILTIN3 ("kmmawb_u",
++ integer, integer, integer, unsigned, KMMAWB_U);
++ ADD_NDS32_BUILTIN3 ("v_kmmawb_u",
++ integer, integer, integer, v2hi, V_KMMAWB_U);
++ ADD_NDS32_BUILTIN3 ("kmmawt", integer, integer, integer, unsigned, KMMAWT);
++ ADD_NDS32_BUILTIN3 ("v_kmmawt", integer, integer, integer, v2hi, V_KMMAWT);
++ ADD_NDS32_BUILTIN3 ("kmmawt_u",
++ integer, integer, integer, unsigned, KMMAWT_U);
++ ADD_NDS32_BUILTIN3 ("v_kmmawt_u",
++ integer, integer, integer, v2hi, V_KMMAWT_U);
++
++ /* DSP Extension: Signed 16bit Multiply with ADD/Subtract. */
++ ADD_NDS32_BUILTIN2 ("smbb", integer, unsigned, unsigned, SMBB);
++ ADD_NDS32_BUILTIN2 ("v_smbb", integer, v2hi, v2hi, V_SMBB);
++ ADD_NDS32_BUILTIN2 ("smbt", integer, unsigned, unsigned, SMBT);
++ ADD_NDS32_BUILTIN2 ("v_smbt", integer, v2hi, v2hi, V_SMBT);
++ ADD_NDS32_BUILTIN2 ("smtt", integer, unsigned, unsigned, SMTT);
++ ADD_NDS32_BUILTIN2 ("v_smtt", integer, v2hi, v2hi, V_SMTT);
++ ADD_NDS32_BUILTIN2 ("kmda", integer, unsigned, unsigned, KMDA);
++ ADD_NDS32_BUILTIN2 ("v_kmda", integer, v2hi, v2hi, V_KMDA);
++ ADD_NDS32_BUILTIN2 ("kmxda", integer, unsigned, unsigned, KMXDA);
++ ADD_NDS32_BUILTIN2 ("v_kmxda", integer, v2hi, v2hi, V_KMXDA);
++ ADD_NDS32_BUILTIN2 ("smds", integer, unsigned, unsigned, SMDS);
++ ADD_NDS32_BUILTIN2 ("v_smds", integer, v2hi, v2hi, V_SMDS);
++ ADD_NDS32_BUILTIN2 ("smdrs", integer, unsigned, unsigned, SMDRS);
++ ADD_NDS32_BUILTIN2 ("v_smdrs", integer, v2hi, v2hi, V_SMDRS);
++ ADD_NDS32_BUILTIN2 ("smxds", integer, unsigned, unsigned, SMXDS);
++ ADD_NDS32_BUILTIN2 ("v_smxds", integer, v2hi, v2hi, V_SMXDS);
++ ADD_NDS32_BUILTIN3 ("kmabb", integer, integer, unsigned, unsigned, KMABB);
++ ADD_NDS32_BUILTIN3 ("v_kmabb", integer, integer, v2hi, v2hi, V_KMABB);
++ ADD_NDS32_BUILTIN3 ("kmabt", integer, integer, unsigned, unsigned, KMABT);
++ ADD_NDS32_BUILTIN3 ("v_kmabt", integer, integer, v2hi, v2hi, V_KMABT);
++ ADD_NDS32_BUILTIN3 ("kmatt", integer, integer, unsigned, unsigned, KMATT);
++ ADD_NDS32_BUILTIN3 ("v_kmatt", integer, integer, v2hi, v2hi, V_KMATT);
++ ADD_NDS32_BUILTIN3 ("kmada", integer, integer, unsigned, unsigned, KMADA);
++ ADD_NDS32_BUILTIN3 ("v_kmada", integer, integer, v2hi, v2hi, V_KMADA);
++ ADD_NDS32_BUILTIN3 ("kmaxda", integer, integer, unsigned, unsigned, KMAXDA);
++ ADD_NDS32_BUILTIN3 ("v_kmaxda", integer, integer, v2hi, v2hi, V_KMAXDA);
++ ADD_NDS32_BUILTIN3 ("kmads", integer, integer, unsigned, unsigned, KMADS);
++ ADD_NDS32_BUILTIN3 ("v_kmads", integer, integer, v2hi, v2hi, V_KMADS);
++ ADD_NDS32_BUILTIN3 ("kmadrs", integer, integer, unsigned, unsigned, KMADRS);
++ ADD_NDS32_BUILTIN3 ("v_kmadrs", integer, integer, v2hi, v2hi, V_KMADRS);
++ ADD_NDS32_BUILTIN3 ("kmaxds", integer, integer, unsigned, unsigned, KMAXDS);
++ ADD_NDS32_BUILTIN3 ("v_kmaxds", integer, integer, v2hi, v2hi, V_KMAXDS);
++ ADD_NDS32_BUILTIN3 ("kmsda", integer, integer, unsigned, unsigned, KMSDA);
++ ADD_NDS32_BUILTIN3 ("v_kmsda", integer, integer, v2hi, v2hi, V_KMSDA);
++ ADD_NDS32_BUILTIN3 ("kmsxda", integer, integer, unsigned, unsigned, KMSXDA);
++ ADD_NDS32_BUILTIN3 ("v_kmsxda", integer, integer, v2hi, v2hi, V_KMSXDA);
++
++ /* DSP Extension: Signed 16bit Multiply with 64bit ADD/Subtract. */
++ ADD_NDS32_BUILTIN2 ("smal", long_long_integer,
++ long_long_integer, unsigned, SMAL);
++ ADD_NDS32_BUILTIN2 ("v_smal", long_long_integer,
++ long_long_integer, v2hi, V_SMAL);
++
++ /* DSP Extension: 32bit MISC. */
++ ADD_NDS32_BUILTIN2 ("bitrev", unsigned, unsigned, unsigned, BITREV);
++ ADD_NDS32_BUILTIN2 ("wext", unsigned, long_long_integer, unsigned, WEXT);
++ ADD_NDS32_BUILTIN3 ("bpick", unsigned, unsigned, unsigned, unsigned, BPICK);
++ ADD_NDS32_BUILTIN3 ("insb", unsigned, unsigned, unsigned, unsigned, INSB);
++
++ /* DSP Extension: 64bit Add and Subtract. */
++ ADD_NDS32_BUILTIN2 ("sadd64", long_long_integer,
++ long_long_integer, long_long_integer, SADD64);
++ ADD_NDS32_BUILTIN2 ("uadd64", long_long_unsigned,
++ long_long_unsigned, long_long_unsigned, UADD64);
++ ADD_NDS32_BUILTIN2 ("radd64", long_long_integer,
++ long_long_integer, long_long_integer, RADD64);
++ ADD_NDS32_BUILTIN2 ("uradd64", long_long_unsigned,
++ long_long_unsigned, long_long_unsigned, URADD64);
++ ADD_NDS32_BUILTIN2 ("kadd64", long_long_integer,
++ long_long_integer, long_long_integer, KADD64);
++ ADD_NDS32_BUILTIN2 ("ukadd64", long_long_unsigned,
++ long_long_unsigned, long_long_unsigned, UKADD64);
++ ADD_NDS32_BUILTIN2 ("ssub64", long_long_integer,
++ long_long_integer, long_long_integer, SSUB64);
++ ADD_NDS32_BUILTIN2 ("usub64", long_long_unsigned,
++ long_long_unsigned, long_long_unsigned, USUB64);
++ ADD_NDS32_BUILTIN2 ("rsub64", long_long_integer,
++ long_long_integer, long_long_integer, RSUB64);
++ ADD_NDS32_BUILTIN2 ("ursub64", long_long_unsigned,
++ long_long_unsigned, long_long_unsigned, URSUB64);
++ ADD_NDS32_BUILTIN2 ("ksub64", long_long_integer,
++ long_long_integer, long_long_integer, KSUB64);
++ ADD_NDS32_BUILTIN2 ("uksub64", long_long_unsigned,
++ long_long_unsigned, long_long_unsigned, UKSUB64);
++
++ /* DSP Extension: 32bit Multiply with 64bit Add/Subtract. */
++ ADD_NDS32_BUILTIN3 ("smar64", long_long_integer,
++ long_long_integer, integer, integer, SMAR64);
++ ADD_NDS32_BUILTIN3 ("smsr64", long_long_integer,
++ long_long_integer, integer, integer, SMSR64);
++ ADD_NDS32_BUILTIN3 ("umar64", long_long_unsigned,
++ long_long_unsigned, unsigned, unsigned, UMAR64);
++ ADD_NDS32_BUILTIN3 ("umsr64", long_long_unsigned,
++ long_long_unsigned, unsigned, unsigned, UMSR64);
++ ADD_NDS32_BUILTIN3 ("kmar64", long_long_integer,
++ long_long_integer, integer, integer, KMAR64);
++ ADD_NDS32_BUILTIN3 ("kmsr64", long_long_integer,
++ long_long_integer, integer, integer, KMSR64);
++ ADD_NDS32_BUILTIN3 ("ukmar64", long_long_unsigned,
++ long_long_unsigned, unsigned, unsigned, UKMAR64);
++ ADD_NDS32_BUILTIN3 ("ukmsr64", long_long_unsigned,
++ long_long_unsigned, unsigned, unsigned, UKMSR64);
++
++ /* DSP Extension: Signed 16bit Multiply with 64bit Add/Subtract. */
++ ADD_NDS32_BUILTIN3 ("smalbb", long_long_integer,
++ long_long_integer, unsigned, unsigned, SMALBB);
++ ADD_NDS32_BUILTIN3 ("v_smalbb", long_long_integer,
++ long_long_integer, v2hi, v2hi, V_SMALBB);
++ ADD_NDS32_BUILTIN3 ("smalbt", long_long_integer,
++ long_long_integer, unsigned, unsigned, SMALBT);
++ ADD_NDS32_BUILTIN3 ("v_smalbt", long_long_integer,
++ long_long_integer, v2hi, v2hi, V_SMALBT);
++ ADD_NDS32_BUILTIN3 ("smaltt", long_long_integer,
++ long_long_integer, unsigned, unsigned, SMALTT);
++ ADD_NDS32_BUILTIN3 ("v_smaltt", long_long_integer,
++ long_long_integer, v2hi, v2hi, V_SMALTT);
++ ADD_NDS32_BUILTIN3 ("smalda", long_long_integer,
++ long_long_integer, unsigned, unsigned, SMALDA);
++ ADD_NDS32_BUILTIN3 ("v_smalda", long_long_integer,
++ long_long_integer, v2hi, v2hi, V_SMALDA);
++ ADD_NDS32_BUILTIN3 ("smalxda", long_long_integer,
++ long_long_integer, unsigned, unsigned, SMALXDA);
++ ADD_NDS32_BUILTIN3 ("v_smalxda", long_long_integer,
++ long_long_integer, v2hi, v2hi, V_SMALXDA);
++ ADD_NDS32_BUILTIN3 ("smalds", long_long_integer,
++ long_long_integer, unsigned, unsigned, SMALDS);
++ ADD_NDS32_BUILTIN3 ("v_smalds", long_long_integer,
++ long_long_integer, v2hi, v2hi, V_SMALDS);
++ ADD_NDS32_BUILTIN3 ("smaldrs", long_long_integer,
++ long_long_integer, unsigned, unsigned, SMALDRS);
++ ADD_NDS32_BUILTIN3 ("v_smaldrs", long_long_integer,
++ long_long_integer, v2hi, v2hi, V_SMALDRS);
++ ADD_NDS32_BUILTIN3 ("smalxds", long_long_integer,
++ long_long_integer, unsigned, unsigned, SMALXDS);
++ ADD_NDS32_BUILTIN3 ("v_smalxds", long_long_integer,
++ long_long_integer, v2hi, v2hi, V_SMALXDS);
++ ADD_NDS32_BUILTIN3 ("smslda", long_long_integer,
++ long_long_integer, unsigned, unsigned, SMSLDA);
++ ADD_NDS32_BUILTIN3 ("v_smslda", long_long_integer,
++ long_long_integer, v2hi, v2hi, V_SMSLDA);
++ ADD_NDS32_BUILTIN3 ("smslxda", long_long_integer,
++ long_long_integer, unsigned, unsigned, SMSLXDA);
++ ADD_NDS32_BUILTIN3 ("v_smslxda", long_long_integer,
++ long_long_integer, v2hi, v2hi, V_SMSLXDA);
++
++ /* DSP Extension: augmented baseline. */
++ ADD_NDS32_BUILTIN2 ("uclip32", unsigned, integer, unsigned, UCLIP32);
++ ADD_NDS32_BUILTIN2 ("sclip32", integer, integer, unsigned, SCLIP32);
++ ADD_NDS32_BUILTIN1 ("kabs", integer, integer, KABS);
++
++ /* The builtin turn off hwloop optimization. */
++ ADD_NDS32_BUILTIN0 ("no_ext_zol", void, NO_HWLOOP);
++
++ /* DSP Extension: vector type unaligned Load/Store */
++ ADD_NDS32_BUILTIN1 ("get_unaligned_u16x2", u_v2hi, ptr_ushort, UALOAD_U16);
++ ADD_NDS32_BUILTIN1 ("get_unaligned_s16x2", v2hi, ptr_short, UALOAD_S16);
++ ADD_NDS32_BUILTIN1 ("get_unaligned_u8x4", u_v4qi, ptr_uchar, UALOAD_U8);
++ ADD_NDS32_BUILTIN1 ("get_unaligned_s8x4", v4qi, ptr_char, UALOAD_S8);
++ ADD_NDS32_BUILTIN2 ("put_unaligned_u16x2", void, ptr_ushort,
++ u_v2hi, UASTORE_U16);
++ ADD_NDS32_BUILTIN2 ("put_unaligned_s16x2", void, ptr_short,
++ v2hi, UASTORE_S16);
++ ADD_NDS32_BUILTIN2 ("put_unaligned_u8x4", void, ptr_uchar,
++ u_v4qi, UASTORE_U8);
++ ADD_NDS32_BUILTIN2 ("put_unaligned_s8x4", void, ptr_char,
++ v4qi, UASTORE_S8);
++}
+ /* ------------------------------------------------------------------------ */
+diff --git a/gcc/config/nds32/nds32-intrinsic.md b/gcc/config/nds32/nds32-intrinsic.md
+index 53876c5..6f8b3eb 100644
+--- a/gcc/config/nds32/nds32-intrinsic.md
++++ b/gcc/config/nds32/nds32-intrinsic.md
+@@ -40,6 +40,26 @@
+ (set_attr "length" "4")]
+ )
+
++(define_expand "mtsr_isb"
++ [(set (match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "immediate_operand" ""))]
++ ""
++{
++ emit_insn (gen_unspec_volatile_mtsr (operands[0], operands[1]));
++ emit_insn (gen_unspec_volatile_isb());
++ DONE;
++})
++
++(define_expand "mtsr_dsb"
++ [(set (match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "immediate_operand" ""))]
++ ""
++{
++ emit_insn (gen_unspec_volatile_mtsr (operands[0], operands[1]));
++ emit_insn (gen_unspec_dsb());
++ DONE;
++})
++
+ (define_insn "unspec_volatile_mtsr"
+ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_MTSR)]
+@@ -58,6 +78,74 @@
+ (set_attr "length" "4")]
+ )
+
++;; FPU Register Transfer.
++
++(define_insn "unspec_fcpynsd"
++ [(set (match_operand:DF 0 "register_operand" "=f")
++ (unspec:DF [(match_operand:DF 1 "register_operand" "f")
++ (match_operand:DF 2 "register_operand" "f")] UNSPEC_FCPYNSD))]
++ ""
++ "fcpynsd\t%0, %1, %2"
++ [(set_attr "type" "misc")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_fcpynss"
++ [(set (match_operand:SF 0 "register_operand" "=f")
++ (unspec:SF [(match_operand:SF 1 "register_operand" "f")
++ (match_operand:SF 2 "register_operand" "f")] UNSPEC_FCPYNSS))]
++ ""
++ "fcpynss\t%0, %1, %2"
++ [(set_attr "type" "misc")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_fcpysd"
++ [(set (match_operand:DF 0 "register_operand" "=f")
++ (unspec:DF [(match_operand:DF 1 "register_operand" "f")
++ (match_operand:DF 2 "register_operand" "f")] UNSPEC_FCPYSD))]
++ ""
++ "fcpysd\t%0, %1, %2"
++ [(set_attr "type" "misc")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_fcpyss"
++ [(set (match_operand:SF 0 "register_operand" "=f")
++ (unspec:SF [(match_operand:SF 1 "register_operand" "f")
++ (match_operand:SF 2 "register_operand" "f")] UNSPEC_FCPYSS))]
++ ""
++ "fcpyss\t%0, %1, %2"
++ [(set_attr "type" "misc")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_fmfcsr"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_FMFCSR))]
++ ""
++ "fmfcsr\t%0"
++ [(set_attr "type" "misc")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_fmtcsr"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_FMTCSR)]
++ ""
++ "fmtcsr\t%0"
++ [(set_attr "type" "misc")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_fmfcfg"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_FMFCFG))]
++ ""
++ "fmfcfg\t%0"
++ [(set_attr "type" "misc")
++ (set_attr "length" "4")]
++)
++
+ ;; ------------------------------------------------------------------------
+
+ ;; Interrupt Instructions.
+@@ -76,6 +164,445 @@
+ [(set_attr "type" "misc")]
+ )
+
++(define_expand "unspec_enable_int"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "")] UNSPEC_VOLATILE_ENABLE_INT)]
++ ""
++{
++ rtx system_reg;
++ rtx temp_reg = gen_reg_rtx (SImode);
++
++ /* Set system register form nds32_intrinsic_register_names[]. */
++ if ((INTVAL (operands[0]) >= NDS32_INT_H16)
++ && (INTVAL (operands[0]) <= NDS32_INT_H31))
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_MASK2__);
++ operands[0] = GEN_INT (1 << (INTVAL (operands[0])));
++ }
++ else if ((INTVAL (operands[0]) >= NDS32_INT_H32)
++ && (INTVAL (operands[0]) <= NDS32_INT_H63))
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_MASK3__);
++ operands[0] = GEN_INT (1 << (INTVAL (operands[0]) - 32));
++ }
++ else
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_MASK__);
++
++ if (INTVAL (operands[0]) == NDS32_INT_SWI)
++ operands[0] = GEN_INT (1 << 16);
++ else if ((INTVAL (operands[0]) >= NDS32_INT_ALZ)
++ && (INTVAL (operands[0]) <= NDS32_INT_DSSIM))
++ operands[0] = GEN_INT (1 << (INTVAL (operands[0]) - 4));
++ else
++ operands[0] = GEN_INT (1 << (INTVAL (operands[0])));
++ }
++
++ emit_insn (gen_unspec_volatile_mfsr (temp_reg, system_reg));
++ emit_insn (gen_iorsi3 (temp_reg, temp_reg, operands[0]));
++ emit_insn (gen_unspec_volatile_mtsr (temp_reg, system_reg));
++ emit_insn (gen_unspec_dsb ());
++ DONE;
++})
++
++(define_expand "unspec_disable_int"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "")] UNSPEC_VOLATILE_DISABLE_INT)]
++ ""
++{
++ rtx system_reg;
++ rtx temp_reg = gen_reg_rtx (SImode);
++
++ /* Set system register form nds32_intrinsic_register_names[]. */
++ if ((INTVAL (operands[0]) >= NDS32_INT_H16)
++ && (INTVAL (operands[0]) <= NDS32_INT_H31))
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_MASK2__);
++ operands[0] = GEN_INT (~(1 << INTVAL (operands[0])));
++ }
++ else if ((INTVAL (operands[0]) >= NDS32_INT_H32)
++ && (INTVAL (operands[0]) <= NDS32_INT_H63))
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_MASK3__);
++ operands[0] = GEN_INT (~(1 << (INTVAL (operands[0]) - 32)));
++ }
++ else
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_MASK__);
++
++ if (INTVAL (operands[0]) == NDS32_INT_SWI)
++ operands[0] = GEN_INT (~(1 << 16));
++ else if ((INTVAL (operands[0]) >= NDS32_INT_ALZ)
++ && (INTVAL (operands[0]) <= NDS32_INT_DSSIM))
++ operands[0] = GEN_INT (~(1 << (INTVAL (operands[0]) - 4)));
++ else
++ operands[0] = GEN_INT (~(1 << INTVAL (operands[0])));
++ }
++
++ emit_insn (gen_unspec_volatile_mfsr (temp_reg, system_reg));
++ emit_insn (gen_andsi3 (temp_reg, temp_reg, operands[0]));
++ emit_insn (gen_unspec_volatile_mtsr (temp_reg, system_reg));
++ emit_insn (gen_unspec_dsb ());
++ DONE;
++})
++
++(define_expand "unspec_set_pending_swint"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SET_PENDING_SWINT)]
++ ""
++{
++ /* Get $INT_PEND system register form nds32_intrinsic_register_names[] */
++ rtx system_reg = GEN_INT (__NDS32_REG_INT_PEND__);
++ rtx temp_reg = gen_reg_rtx (SImode);
++
++ emit_insn (gen_unspec_volatile_mfsr (temp_reg, system_reg));
++ emit_insn (gen_iorsi3 (temp_reg, temp_reg, GEN_INT (65536)));
++ emit_insn (gen_unspec_volatile_mtsr (temp_reg, system_reg));
++ emit_insn (gen_unspec_dsb ());
++ DONE;
++})
++
++(define_expand "unspec_clr_pending_swint"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_CLR_PENDING_SWINT)]
++ ""
++{
++ /* Get $INT_PEND system register form nds32_intrinsic_register_names[] */
++ rtx system_reg = GEN_INT (__NDS32_REG_INT_PEND__);
++ rtx temp_reg = gen_reg_rtx (SImode);
++
++ emit_insn (gen_unspec_volatile_mfsr (temp_reg, system_reg));
++ emit_insn (gen_andsi3 (temp_reg, temp_reg, GEN_INT (~(1 << 16))));
++ emit_insn (gen_unspec_volatile_mtsr (temp_reg, system_reg));
++ emit_insn (gen_unspec_dsb ());
++ DONE;
++})
++
++(define_expand "unspec_clr_pending_hwint"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "")] UNSPEC_VOLATILE_CLR_PENDING_HWINT)]
++ ""
++{
++ rtx system_reg = NULL_RTX;
++ rtx temp_reg = gen_reg_rtx (SImode);
++ rtx clr_hwint;
++ unsigned offset = 0;
++
++ /* Set system register form nds32_intrinsic_register_names[]. */
++ if ((INTVAL (operands[0]) >= NDS32_INT_H0)
++ && (INTVAL (operands[0]) <= NDS32_INT_H15))
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PEND__);
++ }
++ else if ((INTVAL (operands[0]) >= NDS32_INT_H16)
++ && (INTVAL (operands[0]) <= NDS32_INT_H31))
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PEND2__);
++ }
++ else if ((INTVAL (operands[0]) >= NDS32_INT_H32)
++ && (INTVAL (operands[0]) <= NDS32_INT_H63))
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PEND3__);
++ offset = 32;
++ }
++ else
++ error ("__nds32__clr_pending_hwint not support NDS32_INT_SWI,"
++ " NDS32_INT_ALZ, NDS32_INT_IDIVZE, NDS32_INT_DSSIM");
++
++ /* $INT_PEND type is write one clear. */
++ clr_hwint = GEN_INT (1 << (INTVAL (operands[0]) - offset));
++
++ if (system_reg != NULL_RTX)
++ {
++ emit_move_insn (temp_reg, clr_hwint);
++ emit_insn (gen_unspec_volatile_mtsr (temp_reg, system_reg));
++ emit_insn (gen_unspec_dsb ());
++ }
++ DONE;
++})
++
++(define_expand "unspec_get_all_pending_int"
++ [(set (match_operand:SI 0 "register_operand" "")
++ (unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_GET_ALL_PENDING_INT))]
++ ""
++{
++ rtx system_reg = GEN_INT (__NDS32_REG_INT_PEND__);
++ emit_insn (gen_unspec_volatile_mfsr (operands[0], system_reg));
++ emit_insn (gen_unspec_dsb ());
++ DONE;
++})
++
++(define_expand "unspec_get_pending_int"
++ [(set (match_operand:SI 0 "register_operand" "")
++ (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "")] UNSPEC_VOLATILE_GET_PENDING_INT))]
++ ""
++{
++ rtx system_reg = NULL_RTX;
++
++ /* Set system register form nds32_intrinsic_register_names[]. */
++ if ((INTVAL (operands[1]) >= NDS32_INT_H0)
++ && (INTVAL (operands[1]) <= NDS32_INT_H15))
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PEND__);
++ operands[2] = GEN_INT (31 - INTVAL (operands[1]));
++ }
++ else if (INTVAL (operands[1]) == NDS32_INT_SWI)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PEND__);
++ operands[2] = GEN_INT (15);
++ }
++ else if ((INTVAL (operands[1]) >= NDS32_INT_H16)
++ && (INTVAL (operands[1]) <= NDS32_INT_H31))
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PEND2__);
++ operands[2] = GEN_INT (31 - INTVAL (operands[1]));
++ }
++ else if ((INTVAL (operands[1]) >= NDS32_INT_H32)
++ && (INTVAL (operands[1]) <= NDS32_INT_H63))
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PEND3__);
++ operands[2] = GEN_INT (31 - (INTVAL (operands[1]) - 32));
++ }
++ else
++ error ("get_pending_int not support NDS32_INT_ALZ,"
++ " NDS32_INT_IDIVZE, NDS32_INT_DSSIM");
++
++ /* mfsr op0, sytem_reg */
++ if (system_reg != NULL_RTX)
++ {
++ emit_insn (gen_unspec_volatile_mfsr (operands[0], system_reg));
++ emit_insn (gen_ashlsi3 (operands[0], operands[0], operands[2]));
++ emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (31)));
++ emit_insn (gen_unspec_dsb ());
++ }
++ DONE;
++})
++
++(define_expand "unspec_set_int_priority"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "")
++ (match_operand:SI 1 "immediate_operand" "")] UNSPEC_VOLATILE_SET_INT_PRIORITY)]
++ ""
++{
++ rtx system_reg = NULL_RTX;
++ rtx priority = NULL_RTX;
++ rtx mask = NULL_RTX;
++ rtx temp_reg = gen_reg_rtx (SImode);
++ rtx mask_reg = gen_reg_rtx (SImode);
++ rtx set_reg = gen_reg_rtx (SImode);
++ unsigned offset = 0;
++
++ /* Get system register form nds32_intrinsic_register_names[]. */
++ if (INTVAL (operands[0]) <= NDS32_INT_H15)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PRI__);
++ offset = 0;
++ }
++ else if (INTVAL (operands[0]) >= NDS32_INT_H16
++ && INTVAL (operands[0]) <= NDS32_INT_H31)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PRI2__);
++ /* The $INT_PRI2 first bit correspond to H16, so need
++ subtract 16. */
++ offset = 16;
++ }
++ else if (INTVAL (operands[0]) >= NDS32_INT_H32
++ && INTVAL (operands[0]) <= NDS32_INT_H47)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PRI3__);
++ /* The $INT_PRI3 first bit correspond to H32, so need
++ subtract 32. */
++ offset = 32;
++ }
++ else if (INTVAL (operands[0]) >= NDS32_INT_H48
++ && INTVAL (operands[0]) <= NDS32_INT_H63)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PRI4__);
++ /* The $INT_PRI3 first bit correspond to H48, so need
++ subtract 48. */
++ offset = 48;
++ }
++ else
++ error ("set_int_priority not support NDS32_INT_SWI,"
++ " NDS32_INT_ALZ, NDS32_INT_IDIVZE, NDS32_INT_DSSIM");
++
++ mask = GEN_INT (~(3 << 2 * (INTVAL (operands[0]) - offset)));
++ priority = GEN_INT ((int) (INTVAL (operands[1])
++ << ((INTVAL (operands[0]) - offset) * 2)));
++
++ if (system_reg != NULL_RTX)
++ {
++ emit_move_insn (mask_reg, mask);
++ emit_move_insn (set_reg, priority);
++ emit_insn (gen_unspec_volatile_mfsr (temp_reg, system_reg));
++ emit_insn (gen_andsi3 (temp_reg, temp_reg, mask_reg));
++ emit_insn (gen_iorsi3 (temp_reg, temp_reg, set_reg));
++ emit_insn (gen_unspec_volatile_mtsr (temp_reg, system_reg));
++ emit_insn (gen_unspec_dsb ());
++ }
++ DONE;
++})
++
++(define_expand "unspec_get_int_priority"
++ [(set (match_operand:SI 0 "register_operand" "")
++ (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "")] UNSPEC_VOLATILE_GET_INT_PRIORITY))]
++ ""
++{
++ rtx system_reg = NULL_RTX;
++ rtx priority = NULL_RTX;
++ unsigned offset = 0;
++
++ /* Get system register form nds32_intrinsic_register_names[] */
++ if (INTVAL (operands[1]) <= NDS32_INT_H15)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PRI__);
++ offset = 0;
++ }
++ else if (INTVAL (operands[1]) >= NDS32_INT_H16
++ && INTVAL (operands[1]) <= NDS32_INT_H31)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PRI2__);
++ /* The $INT_PRI2 first bit correspond to H16, so need
++ subtract 16. */
++ offset = 16;
++ }
++ else if (INTVAL (operands[1]) >= NDS32_INT_H32
++ && INTVAL (operands[1]) <= NDS32_INT_H47)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PRI3__);
++ /* The $INT_PRI3 first bit correspond to H32, so need
++ subtract 32. */
++ offset = 32;
++ }
++ else if (INTVAL (operands[1]) >= NDS32_INT_H48
++ && INTVAL (operands[1]) <= NDS32_INT_H63)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_PRI4__);
++ /* The $INT_PRI4 first bit correspond to H48, so need
++ subtract 48. */
++ offset = 48;
++ }
++ else
++ error ("set_int_priority not support NDS32_INT_SWI,"
++ " NDS32_INT_ALZ, NDS32_INT_IDIVZE, NDS32_INT_DSSIM");
++
++ priority = GEN_INT (31 - 2 * (INTVAL (operands[1]) - offset));
++
++ if (system_reg != NULL_RTX)
++ {
++ emit_insn (gen_unspec_volatile_mfsr (operands[0], system_reg));
++ emit_insn (gen_ashlsi3 (operands[0], operands[0], priority));
++ emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (30)));
++ emit_insn (gen_unspec_dsb ());
++ }
++ DONE;
++})
++
++(define_expand "unspec_set_trig_level"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "")] UNSPEC_VOLATILE_SET_TRIG_LEVEL)]
++ ""
++{
++ rtx system_reg = NULL_RTX;
++ rtx temp_reg = gen_reg_rtx (SImode);
++ rtx set_level;
++ unsigned offset = 0;
++
++ if (INTVAL (operands[0]) >= NDS32_INT_H0
++ && INTVAL (operands[0]) <= NDS32_INT_H31)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_TRIGGER__);
++ offset = 0;
++ }
++ else if (INTVAL (operands[0]) >= NDS32_INT_H32
++ && INTVAL (operands[0]) <= NDS32_INT_H63)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_TRIGGER2__);
++ offset = 32;
++ }
++ else
++ error ("__nds32__set_trig_type_level not support NDS32_INT_SWI,"
++ " NDS32_INT_ALZ, NDS32_INT_IDIVZE, NDS32_INT_DSSIM");
++
++ if (system_reg != NULL_RTX)
++ {
++ /* TRIGGER register, 0 mean level triggered and 1 mean edge triggered. */
++ set_level = GEN_INT (~(1 << (INTVAL (operands[0]) - offset)));
++
++ emit_insn (gen_unspec_volatile_mfsr (temp_reg, system_reg));
++ emit_insn (gen_andsi3 (temp_reg, temp_reg, set_level));
++ emit_insn (gen_unspec_volatile_mtsr (temp_reg, system_reg));
++ }
++ DONE;
++})
++
++(define_expand "unspec_set_trig_edge"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "")] UNSPEC_VOLATILE_SET_TRIG_EDGE)]
++ ""
++{
++ rtx system_reg = NULL_RTX;
++ rtx temp_reg = gen_reg_rtx (SImode);
++ rtx set_level;
++ unsigned offset = 0;
++
++ if (INTVAL (operands[0]) >= NDS32_INT_H0
++ && INTVAL (operands[0]) <= NDS32_INT_H31)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_TRIGGER__);
++ offset = 0;
++ }
++ else if (INTVAL (operands[0]) >= NDS32_INT_H32
++ && INTVAL (operands[0]) <= NDS32_INT_H63)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_TRIGGER2__);
++ offset = 32;
++ }
++ else
++ error ("__nds32__set_trig_type_edge not support NDS32_INT_SWI,"
++ " NDS32_INT_ALZ, NDS32_INT_IDIVZE, NDS32_INT_DSSIM");
++
++ if (system_reg != NULL_RTX)
++ {
++ /* TRIGGER register, 0 mean level triggered and 1 mean edge triggered. */
++ set_level = GEN_INT ((1 << (INTVAL (operands[0]) - offset)));
++
++ emit_insn (gen_unspec_volatile_mfsr (temp_reg, system_reg));
++ emit_insn (gen_iorsi3 (temp_reg, temp_reg, set_level));
++ emit_insn (gen_unspec_volatile_mtsr (temp_reg, system_reg));
++ }
++ DONE;
++})
++
++(define_expand "unspec_get_trig_type"
++ [(set (match_operand:SI 0 "register_operand" "")
++ (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "")] UNSPEC_VOLATILE_GET_TRIG_TYPE))]
++ ""
++{
++ rtx system_reg = NULL_RTX;
++ rtx trig_type;
++ unsigned offset = 0;
++
++ if (INTVAL (operands[1]) >= NDS32_INT_H0
++ && INTVAL (operands[1]) <= NDS32_INT_H31)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_TRIGGER__);
++ offset = 0;
++ }
++ else if (INTVAL (operands[1]) >= NDS32_INT_H32
++ && INTVAL (operands[1]) <= NDS32_INT_H63)
++ {
++ system_reg = GEN_INT (__NDS32_REG_INT_TRIGGER2__);
++ offset = 32;
++ }
++ else
++ error ("__nds32__get_trig_type not support NDS32_INT_SWI,"
++ " NDS32_INT_ALZ, NDS32_INT_IDIVZE, NDS32_INT_DSSIM");
++
++ if (system_reg != NULL_RTX)
++ {
++ trig_type = GEN_INT (31 - (INTVAL (operands[1]) - offset));
++
++ emit_insn (gen_unspec_volatile_mfsr (operands[0], system_reg));
++ emit_insn (gen_ashlsi3 (operands[0], operands[0], trig_type));
++ emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (31)));
++ emit_insn (gen_unspec_dsb ());
++ }
++ DONE;
++})
++
+ ;; ------------------------------------------------------------------------
+
+ ;; Cache Synchronization Instructions
+@@ -84,7 +611,7 @@
+ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_ISYNC)]
+ ""
+ "isync\t%0"
+- [(set_attr "type" "misc")]
++ [(set_attr "type" "mmu")]
+ )
+
+ (define_insn "unspec_volatile_isb"
+@@ -94,4 +621,1077 @@
+ [(set_attr "type" "misc")]
+ )
+
++(define_insn "unspec_dsb"
++ [(unspec_volatile [(const_int 0)] UNSPEC_VOLATILE_DSB)]
++ ""
++ "dsb"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_msync"
++ [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "i")] UNSPEC_VOLATILE_MSYNC)]
++ ""
++ "msync\t%0"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_msync_all"
++ [(unspec_volatile [(const_int 0)] UNSPEC_VOLATILE_MSYNC_ALL)]
++ ""
++ "msync\tall"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_msync_store"
++ [(unspec_volatile [(const_int 0)] UNSPEC_VOLATILE_MSYNC_STORE)]
++ ""
++ "msync\tstore"
++ [(set_attr "type" "misc")]
++)
++
++;; Load and Store
++
++(define_insn "unspec_volatile_llw"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec_volatile:SI [(mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")))] UNSPEC_VOLATILE_LLW))]
++ ""
++ "llw\t%0, [%1 + %2]"
++ [(set_attr "length" "4")]
++)
++
++(define_insn "unspec_lwup"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec_volatile:SI [(mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")))] UNSPEC_LWUP))]
++ ""
++ "lwup\t%0, [%1 + %2]"
++ [(set_attr "length" "4")]
++)
++
++(define_insn "unspec_lbup"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec_volatile:SI [(mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")))] UNSPEC_LBUP))]
++ ""
++ "lbup\t%0, [%1 + %2]"
++ [(set_attr "length" "4")]
++)
++
++(define_insn "unspec_volatile_scw"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec_volatile:SI [(mem:SI (plus:SI (match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")))
++ (match_operand:SI 3 "register_operand" "0")] UNSPEC_VOLATILE_SCW))]
++ ""
++ "scw\t%0, [%1 + %2]"
++ [(set_attr "length" "4")]
++)
++
++(define_insn "unspec_swup"
++ [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "r")
++ (match_operand:SI 1 "register_operand" "r")))
++ (unspec:SI [(match_operand:SI 2 "register_operand" "r")] UNSPEC_SWUP))]
++ ""
++ "swup\t%2, [%0 + %1]"
++ [(set_attr "length" "4")]
++)
++
++(define_insn "unspec_sbup"
++ [(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "r")
++ (match_operand:SI 1 "register_operand" "r")))
++ (unspec:SI [(match_operand:SI 2 "register_operand" "r")] UNSPEC_SBUP))]
++ ""
++ "sbup\t%2, [%0 + %1]"
++ [(set_attr "length" "4")]
++)
++
++;; CCTL
++
++(define_insn "cctl_l1d_invalall"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_CCTL_L1D_INVALALL)]
++ ""
++ "cctl\tL1D_INVALALL"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "cctl_l1d_wball_alvl"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_CCTL_L1D_WBALL_ALVL)]
++ ""
++ "cctl\tL1D_WBALL, alevel"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "cctl_l1d_wball_one_lvl"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_CCTL_L1D_WBALL_ONE_LVL)]
++ ""
++ "cctl\tL1D_WBALL, 1level"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "cctl_idx_read"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec_volatile:SI [(match_operand:SI 1 "immediate_operand" "i")
++ (match_operand:SI 2 "register_operand" "r")] UNSPEC_VOLATILE_CCTL_IDX_READ))]
++ ""
++ "cctl\t%0, %2, %X1"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "cctl_idx_write"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")
++ (match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")] UNSPEC_VOLATILE_CCTL_IDX_WRITE)]
++ ""
++ "cctl\t%1, %2, %W0"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "cctl_va_wbinval_l1"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")
++ (match_operand:SI 1 "register_operand" "r")] UNSPEC_VOLATILE_CCTL_VA_WBINVAL_L1)]
++ ""
++ "cctl\t%1, %U0, 1level"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "cctl_va_wbinval_la"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")
++ (match_operand:SI 1 "register_operand" "r")] UNSPEC_VOLATILE_CCTL_VA_WBINVAL_LA)]
++ ""
++ "cctl\t%1, %U0, alevel"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "cctl_idx_wbinval"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")
++ (match_operand:SI 1 "register_operand" "r")] UNSPEC_VOLATILE_CCTL_IDX_WBINVAL)]
++ ""
++ "cctl\t%1, %T0"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "cctl_va_lck"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")
++ (match_operand:SI 1 "register_operand" "r")] UNSPEC_VOLATILE_CCTL_VA_LCK)]
++ ""
++ "cctl\t%1, %R0"
++ [(set_attr "type" "mmu")]
++)
++
++;;PREFETCH
++
++(define_insn "prefetch_qw"
++ [(unspec_volatile:QI [(match_operand:SI 0 "register_operand" "r")
++ (match_operand:SI 1 "nonmemory_operand" "r")
++ (match_operand:SI 2 "immediate_operand" "i")] UNSPEC_VOLATILE_DPREF_QW)]
++ ""
++ "dpref\t%Z2, [%0 + %1]"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "prefetch_hw"
++ [(unspec_volatile:HI [(match_operand:SI 0 "register_operand" "r")
++ (match_operand:SI 1 "nonmemory_operand" "r")
++ (match_operand:SI 2 "immediate_operand" "i")] UNSPEC_VOLATILE_DPREF_HW)]
++ ""
++ "dpref\t%Z2, [%0 + (%1<<1)]"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "prefetch_w"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" " r, r")
++ (match_operand:SI 1 "nonmemory_operand" "Is15, r")
++ (match_operand:SI 2 "immediate_operand" " i, i")] UNSPEC_VOLATILE_DPREF_W)]
++ ""
++ "@
++ dprefi.w\t%Z2, [%0 + %1]
++ dpref\t%Z2, [%0 + (%1<<2)]"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "prefetch_dw"
++ [(unspec_volatile:DI [(match_operand:SI 0 "register_operand" " r, r")
++ (match_operand:SI 1 "nonmemory_operand" "Is15, r")
++ (match_operand:SI 2 "immediate_operand" " i, i")] UNSPEC_VOLATILE_DPREF_DW)]
++ ""
++ "@
++ dprefi.d\t%Z2, [%0 + %1]
++ dpref\t%Z2, [%0 + (%1<<3)]"
++ [(set_attr "type" "misc")]
++)
++
++;; Performance Extension
++
++(define_expand "unspec_ave"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:SI 2 "register_operand" "")]
++ ""
++{
++ emit_insn (gen_ave (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_expand "unspec_bclr"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:SI 2 "immediate_operand" "")]
++ ""
++{
++ unsigned HOST_WIDE_INT val = ~(1u << UINTVAL (operands[2]));
++ emit_insn (gen_andsi3 (operands[0], operands[1], gen_int_mode (val, SImode)));
++ DONE;
++})
++
++(define_expand "unspec_bset"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:SI 2 "immediate_operand" "")]
++ ""
++{
++ unsigned HOST_WIDE_INT val = 1u << UINTVAL (operands[2]);
++ emit_insn (gen_iorsi3 (operands[0], operands[1], gen_int_mode (val, SImode)));
++ DONE;
++})
++
++(define_expand "unspec_btgl"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:SI 2 "immediate_operand" "")]
++ ""
++{
++ unsigned HOST_WIDE_INT val = 1u << UINTVAL (operands[2]);
++ emit_insn (gen_xorsi3 (operands[0], operands[1], gen_int_mode (val, SImode)));
++ DONE;
++})
++
++(define_expand "unspec_btst"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:SI 2 "immediate_operand" "")]
++ ""
++{
++ emit_insn (gen_btst (operands[0], operands[1], operands[2]));
++ DONE;
++})
++
++(define_insn "unspec_clip"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "immediate_operand" "i")] UNSPEC_CLIP))]
++ ""
++ "clip\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_clips"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "immediate_operand" "i")] UNSPEC_CLIPS))]
++ ""
++ "clips\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_clo"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")] UNSPEC_CLO))]
++ ""
++ "clo\t%0, %1"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_ssabssi2"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_abs:SI (match_operand:SI 1 "register_operand" "r")))]
++ ""
++ "abs\t%0, %1"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++;; Performance extension 2
++
++(define_insn "unspec_pbsad"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")] UNSPEC_PBSAD))]
++ ""
++ "pbsad\t%0, %1, %2"
++ [(set_attr "type" "pbsad")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_pbsada"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "0")
++ (match_operand:SI 2 "register_operand" "r")
++ (match_operand:SI 3 "register_operand" "r")] UNSPEC_PBSADA))]
++ ""
++ "pbsada\t%0, %2, %3"
++ [(set_attr "type" "pbsada")
++ (set_attr "length" "4")]
++)
++
++(define_expand "bse"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:SI 2 "register_operand" "")]
++ ""
++ {
++ rtx temp0 = gen_reg_rtx (SImode);
++ rtx temp2 = gen_reg_rtx (SImode);
++
++ emit_move_insn (temp0, gen_rtx_MEM (Pmode, operands[0]));
++ emit_move_insn (temp2, gen_rtx_MEM (Pmode, operands[2]));
++ emit_insn (gen_unspec_bse (temp0, operands[1], temp2, temp0, temp2));
++ emit_move_insn (gen_rtx_MEM (Pmode, operands[0]), temp0);
++ emit_move_insn (gen_rtx_MEM (Pmode, operands[2]), temp2);
++ DONE;
++ }
++)
++
++(define_insn "unspec_bse"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")
++ (match_operand:SI 3 "register_operand" "0")] UNSPEC_BSE))
++ (set (match_operand:SI 4 "register_operand" "=2")
++ (unspec:SI [(match_dup 1)
++ (match_dup 2)
++ (match_dup 0)] UNSPEC_BSE_2))]
++ ""
++ "bse\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_expand "bsp"
++ [(match_operand:SI 0 "register_operand" "")
++ (match_operand:SI 1 "register_operand" "")
++ (match_operand:SI 2 "register_operand" "")]
++ ""
++ {
++ rtx temp0 = gen_reg_rtx (SImode);
++ rtx temp2 = gen_reg_rtx (SImode);
++
++ emit_move_insn (temp0, gen_rtx_MEM (Pmode, operands[0]));
++ emit_move_insn (temp2, gen_rtx_MEM (Pmode, operands[2]));
++ emit_insn (gen_unspec_bsp (temp0, operands[1], temp2, temp0, temp2));
++ emit_move_insn (gen_rtx_MEM (Pmode, operands[0]), temp0);
++ emit_move_insn (gen_rtx_MEM (Pmode, operands[2]), temp2);
++ DONE;
++ }
++)
++
++(define_insn "unspec_bsp"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")
++ (match_operand:SI 3 "register_operand" "0")] UNSPEC_BSP))
++ (set (match_operand:SI 4 "register_operand" "=2")
++ (unspec:SI [(match_dup 1)
++ (match_dup 2)
++ (match_dup 0)] UNSPEC_BSP_2))]
++ ""
++ "bsp\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++;; String Extension
++
++(define_insn "unspec_ffb"
++ [(set (match_operand:SI 0 "register_operand" "=r, r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r, r")
++ (match_operand:SI 2 "nonmemory_operand" "Iu08, r")] UNSPEC_FFB))]
++ ""
++ "@
++ ffbi\t%0, %1, %2
++ ffb\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_ffmism"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")] UNSPEC_FFMISM))]
++ ""
++ "ffmism\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_flmism"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")] UNSPEC_FLMISM))]
++ ""
++ "flmism\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++;; SATURATION
++
++(define_insn "unspec_kaddw"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_plus:SI (match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")))]
++ ""
++ "kaddw\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_ksubw"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ss_minus:SI (match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")))]
++ ""
++ "ksubw\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_kaddh"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(plus:SI (match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r"))
++ (const_int 15)] UNSPEC_CLIPS))]
++ ""
++ "kaddh\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_ksubh"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(minus:SI (match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r"))
++ (const_int 15)] UNSPEC_CLIPS))]
++ ""
++ "ksubh\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_kdmbb"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (unspec:V2HI [(match_operand:V2HI 1 "register_operand" "r")
++ (match_operand:V2HI 2 "register_operand" "r")] UNSPEC_KDMBB))]
++ ""
++ "kdmbb\t%0, %1, %2"
++ [(set_attr "type" "mul")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_kdmbt"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (unspec:V2HI [(match_operand:V2HI 1 "register_operand" "r")
++ (match_operand:V2HI 2 "register_operand" "r")] UNSPEC_KDMBT))]
++ ""
++ "kdmbt\t%0, %1, %2"
++ [(set_attr "type" "mul")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_kdmtb"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (unspec:V2HI [(match_operand:V2HI 1 "register_operand" "r")
++ (match_operand:V2HI 2 "register_operand" "r")] UNSPEC_KDMTB))]
++ ""
++ "kdmtb\t%0, %1, %2"
++ [(set_attr "type" "mul")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_kdmtt"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (unspec:V2HI [(match_operand:V2HI 1 "register_operand" "r")
++ (match_operand:V2HI 2 "register_operand" "r")] UNSPEC_KDMTT))]
++ ""
++ "kdmtt\t%0, %1, %2"
++ [(set_attr "type" "mul")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_khmbb"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (unspec:V2HI [(match_operand:V2HI 1 "register_operand" "r")
++ (match_operand:V2HI 2 "register_operand" "r")] UNSPEC_KHMBB))]
++ ""
++ "khmbb\t%0, %1, %2"
++ [(set_attr "type" "mul")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_khmbt"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (unspec:V2HI [(match_operand:V2HI 1 "register_operand" "r")
++ (match_operand:V2HI 2 "register_operand" "r")] UNSPEC_KHMBT))]
++ ""
++ "khmbt\t%0, %1, %2"
++ [(set_attr "type" "mul")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_khmtb"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (unspec:V2HI [(match_operand:V2HI 1 "register_operand" "r")
++ (match_operand:V2HI 2 "register_operand" "r")] UNSPEC_KHMTB))]
++ ""
++ "khmtb\t%0, %1, %2"
++ [(set_attr "type" "mul")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_khmtt"
++ [(set (match_operand:V2HI 0 "register_operand" "=r")
++ (unspec:V2HI [(match_operand:V2HI 1 "register_operand" "r")
++ (match_operand:V2HI 2 "register_operand" "r")] UNSPEC_KHMTT))]
++ ""
++ "khmtt\t%0, %1, %2"
++ [(set_attr "type" "mul")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_kslraw"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")] UNSPEC_KSLRAW))]
++ ""
++ "kslraw\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_kslrawu"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")] UNSPEC_KSLRAWU))]
++ ""
++ "kslraw.u\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_volatile_rdov"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_RDOV))]
++ ""
++ "rdov\t%0"
++ [(set_attr "type" "misc")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_volatile_clrov"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_CLROV)]
++ ""
++ "clrov"
++ [(set_attr "type" "misc")
++ (set_attr "length" "4")]
++)
++
++;; System
++
++(define_insn "unspec_sva"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")] UNSPEC_SVA))]
++ ""
++ "sva\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_svs"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")
++ (match_operand:SI 2 "register_operand" "r")] UNSPEC_SVS))]
++ ""
++ "svs\t%0, %1, %2"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_insn "unspec_jr_itoff"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_JR_ITOFF)]
++ ""
++ "jr.itoff\t%0"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_jr_toff"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_JR_TOFF)]
++ ""
++ "jr.toff\t%0"
++ [(set_attr "type" "branch")]
++)
++
++(define_insn "unspec_jral_iton"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_JRAL_ITON)]
++ ""
++ "jral.iton\t%0"
++ [(set_attr "type" "branch")]
++)
++
++(define_insn "unspec_jral_ton"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_JRAL_TON)]
++ ""
++ "jral.ton\t%0"
++ [(set_attr "type" "branch")]
++)
++
++(define_insn "unspec_ret_itoff"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_RET_ITOFF)]
++ ""
++ "ret.itoff\t%0"
++ [(set_attr "type" "branch")]
++)
++
++(define_insn "unspec_ret_toff"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_RET_TOFF)]
++ ""
++ "ret.toff\t%0"
++ [(set_attr "type" "branch")]
++)
++
++(define_insn "unspec_standby_no_wake_grant"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_STANDBY_NO_WAKE_GRANT)]
++ ""
++ "standby\tno_wake_grant"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_standby_wake_grant"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_STANDBY_WAKE_GRANT)]
++ ""
++ "standby\twake_grant"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_standby_wait_done"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_STANDBY_WAKE_DONE)]
++ ""
++ "standby\twait_done"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_teqz"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")
++ (match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_TEQZ)]
++ ""
++ "teqz\t%0, %1"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_tnez"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")
++ (match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_TNEZ)]
++ ""
++ "tnez\t%0, %1"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_trap"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] UNSPEC_VOLATILE_TRAP)]
++ ""
++ "trap\t%0"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_setend_big"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SETEND_BIG)]
++ ""
++ "setend.b"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_setend_little"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SETEND_LITTLE)]
++ ""
++ "setend.l"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_break"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] UNSPEC_VOLATILE_BREAK)]
++ ""
++ "break\t%0"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_syscall"
++ [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] UNSPEC_VOLATILE_SYSCALL)]
++ ""
++ "syscall\t%0"
++ [(set_attr "type" "misc")]
++)
++
++(define_insn "unspec_nop"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_NOP)]
++ ""
++ "nop"
++ [(set_attr "type" "misc")]
++)
++
++(define_expand "unspec_get_current_sp"
++ [(match_operand:SI 0 "register_operand" "")]
++ ""
++{
++ emit_move_insn (operands[0], gen_rtx_REG (SImode, SP_REGNUM));
++ DONE;
++})
++
++(define_expand "unspec_set_current_sp"
++ [(match_operand:SI 0 "register_operand" "")]
++ ""
++{
++ emit_move_insn (gen_rtx_REG (SImode, SP_REGNUM), operands[0]);
++ DONE;
++})
++
++(define_expand "unspec_return_address"
++ [(match_operand:SI 0 "register_operand" "")]
++ ""
++{
++ emit_move_insn (operands[0], gen_rtx_REG (SImode, LP_REGNUM));
++ DONE;
++})
++
++(define_insn "unspec_signature_begin"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SIGNATURE_BEGIN)]
++ ""
++ "isps"
++ [(set_attr "length" "4")]
++)
++
++(define_insn "unspec_signature_end"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_SIGNATURE_END)]
++ ""
++ "! -----\;.signature_end\;j8 2\;! -----"
++ [(set_attr "length" "2")]
++)
++
++;; Swap
++
++(define_insn "unspec_wsbh"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")] UNSPEC_WSBH))]
++ ""
++ "wsbh\t%0, %1"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++;; TLBOP Intrinsic
++
++(define_insn "unspec_tlbop_trd"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_TLBOP_TRD)]
++ ""
++ "tlbop\t%0, TRD"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "unspec_tlbop_twr"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_TLBOP_TWR)]
++ ""
++ "tlbop\t%0, TWR"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "unspec_tlbop_rwr"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_TLBOP_RWR)]
++ ""
++ "tlbop\t%0, RWR"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "unspec_tlbop_rwlk"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_TLBOP_RWLK)]
++ ""
++ "tlbop\t%0, RWLK"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "unspec_tlbop_unlk"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_TLBOP_UNLK)]
++ ""
++ "tlbop\t%0, UNLK"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "unspec_tlbop_pb"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r")] UNSPEC_VOLATILE_TLBOP_PB))]
++ ""
++ "tlbop\t%0, %1, PB"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "unspec_tlbop_inv"
++ [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_TLBOP_INV)]
++ ""
++ "tlbop\t%0, INV"
++ [(set_attr "type" "mmu")]
++)
++
++(define_insn "unspec_tlbop_flua"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_TLBOP_FLUA)]
++ ""
++ "tlbop\tFLUA"
++ [(set_attr "type" "mmu")]
++)
++
++;;Unaligned Load/Store
++
++(define_expand "unaligned_load_hw"
++ [(set (match_operand:HI 0 "register_operand" "")
++ (unspec:HI [(mem:HI (match_operand:SI 1 "register_operand" ""))] UNSPEC_UALOAD_HW))]
++ ""
++{
++ operands[0] = simplify_gen_subreg (SImode, operands[0],
++ GET_MODE (operands[0]), 0);
++ if (TARGET_ISA_V3M)
++ {
++ nds32_expand_unaligned_load (operands, HImode);
++ }
++ else
++ {
++ emit_insn (gen_unaligned_load_w (operands[0],
++ gen_rtx_MEM (SImode, operands[1])));
++
++ if (WORDS_BIG_ENDIAN)
++ emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT(16)));
++ else
++ emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (0xffff)));
++ }
++
++ DONE;
++})
++
++(define_expand "unaligned_loadsi"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(mem:SI (match_operand:SI 1 "register_operand" "r"))] UNSPEC_UALOAD_W))]
++ ""
++{
++ if (flag_unaligned_access)
++ {
++ rtx mem = gen_rtx_MEM (SImode, operands[1]);
++ emit_move_insn (operands[0], mem);
++ }
++ else
++ {
++ if (TARGET_ISA_V3M)
++ nds32_expand_unaligned_load (operands, SImode);
++ else
++ emit_insn (gen_unaligned_load_w (operands[0],
++ gen_rtx_MEM (SImode, (operands[1]))));
++ }
++ DONE;
++})
++
++(define_insn "unaligned_load_w"
++ [(set (match_operand:SI 0 "register_operand" "= r")
++ (unspec:SI [(match_operand:SI 1 "nds32_lmw_smw_base_operand" " Umw")] UNSPEC_UALOAD_W))]
++ ""
++{
++ return nds32_output_lmw_single_word (operands);
++}
++ [(set_attr "type" "load")
++ (set_attr "length" "4")]
++)
++
++(define_expand "unaligned_loaddi"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (unspec:DI [(mem:DI (match_operand:SI 1 "register_operand" "r"))] UNSPEC_UALOAD_DW))]
++ ""
++{
++ if (TARGET_ISA_V3M)
++ {
++ nds32_expand_unaligned_load (operands, DImode);
++ }
++ else
++ emit_insn (gen_unaligned_load_dw (operands[0], operands[1]));
++ DONE;
++})
++
++(define_insn "unaligned_load_dw"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (unspec:DI [(mem:DI (match_operand:SI 1 "register_operand" "r"))] UNSPEC_UALOAD_DW))]
++ ""
++{
++ rtx otherops[3];
++ otherops[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
++ otherops[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
++ otherops[2] = operands[1];
++
++ output_asm_insn ("lmw.bi\t%0, [%2], %1, 0", otherops);
++ return "";
++}
++ [(set_attr "type" "load")
++ (set_attr "length" "4")]
++)
++
++(define_expand "unaligned_store_hw"
++ [(set (mem:SI (match_operand:SI 0 "register_operand" ""))
++ (unspec:HI [(match_operand:HI 1 "register_operand" "")] UNSPEC_UASTORE_HW))]
++ ""
++{
++ operands[1] = simplify_gen_subreg (SImode, operands[1],
++ GET_MODE (operands[1]), 0);
++ nds32_expand_unaligned_store (operands, HImode);
++ DONE;
++})
++
++(define_expand "unaligned_storesi"
++ [(set (mem:SI (match_operand:SI 0 "register_operand" "r"))
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")] UNSPEC_UASTORE_W))]
++ ""
++{
++ if (flag_unaligned_access)
++ {
++ rtx mem = gen_rtx_MEM (SImode, operands[0]);
++ emit_move_insn (mem, operands[1]);
++ }
++ else
++ {
++ if (TARGET_ISA_V3M)
++ nds32_expand_unaligned_store (operands, SImode);
++ else
++ emit_insn (gen_unaligned_store_w (gen_rtx_MEM (SImode, operands[0]),
++ operands[1]));
++ }
++ DONE;
++})
++
++(define_insn "unaligned_store_w"
++ [(set (match_operand:SI 0 "nds32_lmw_smw_base_operand" "=Umw")
++ (unspec:SI [(match_operand:SI 1 "register_operand" " r")] UNSPEC_UASTORE_W))]
++ ""
++{
++ return nds32_output_smw_single_word (operands);
++}
++ [(set_attr "type" "store")
++ (set_attr "length" "4")]
++)
++
++(define_expand "unaligned_storedi"
++ [(set (mem:DI (match_operand:SI 0 "register_operand" "r"))
++ (unspec:DI [(match_operand:DI 1 "register_operand" "r")] UNSPEC_UASTORE_DW))]
++ ""
++{
++ if (TARGET_ISA_V3M)
++ nds32_expand_unaligned_store (operands, DImode);
++ else
++ emit_insn (gen_unaligned_store_dw (gen_rtx_MEM (DImode, operands[0]),
++ operands[1]));
++ DONE;
++})
++
++(define_insn "unaligned_store_dw"
++ [(set (match_operand:DI 0 "nds32_lmw_smw_base_operand" "=Umw")
++ (unspec:DI [(match_operand:DI 1 "register_operand" " r")] UNSPEC_UASTORE_DW))]
++ ""
++{
++ return nds32_output_smw_double_word (operands);
++}
++ [(set_attr "type" "store")
++ (set_attr "length" "4")]
++)
++
++(define_expand "unspec_unaligned_feature"
++ [(set (match_operand:SI 0 "register_operand" "")
++ (unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_UNALIGNED_FEATURE))]
++ ""
++{
++ /* Get $MMU_CTL system register form nds32_intrinsic_register_names[] */
++ rtx system_reg = GEN_INT (__NDS32_REG_MMU_CTL__);
++ rtx temp_reg = gen_reg_rtx (SImode);
++ rtx temp2_reg = gen_reg_rtx (SImode);
++
++ emit_insn (gen_unspec_volatile_mfsr (operands[0], system_reg));
++ emit_move_insn (temp_reg, operands[0]);
++ emit_move_insn (temp2_reg, GEN_INT (0x800 << 12));
++ emit_insn (gen_iorsi3 (operands[0], operands[0], temp2_reg));
++ emit_insn (gen_unspec_volatile_mtsr (operands[0], system_reg));
++ emit_insn (gen_unspec_dsb ());
++
++ emit_insn (gen_unspec_volatile_mfsr (operands[0], system_reg));
++ emit_insn (gen_unspec_volatile_mtsr (temp_reg, system_reg));
++ emit_insn (gen_unspec_dsb ());
++
++ emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (8)));
++ emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (31)));
++ DONE;
++})
++
++(define_expand "unspec_enable_unaligned"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_UNALIGNED_FEATURE)]
++ ""
++{
++ /* Get $MMU_CTL system register form nds32_intrinsic_register_names[] */
++ rtx system_reg = GEN_INT (__NDS32_REG_MMU_CTL__);
++ rtx temp_reg = gen_reg_rtx (SImode);
++ rtx temp2_reg = gen_reg_rtx (SImode);
++ emit_insn (gen_unspec_volatile_mfsr (temp_reg, system_reg));
++ emit_move_insn (temp2_reg, GEN_INT (0x800 << 12));
++ emit_insn (gen_iorsi3 (temp_reg, temp_reg, temp2_reg));
++ emit_insn (gen_unspec_volatile_mtsr (temp_reg, system_reg));
++ emit_insn (gen_unspec_dsb ());
++ DONE;
++})
++
++(define_expand "unspec_disable_unaligned"
++ [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_UNALIGNED_FEATURE)]
++ ""
++{
++ /* Get $MMU_CTL system register form nds32_intrinsic_register_names[] */
++ rtx system_reg = GEN_INT (__NDS32_REG_MMU_CTL__);
++ rtx temp_reg = gen_reg_rtx (SImode);
++ rtx temp2_reg = gen_reg_rtx (SImode);
++ emit_insn (gen_unspec_volatile_mfsr (temp_reg, system_reg));
++ emit_move_insn (temp2_reg, GEN_INT (0x800 << 12));
++ emit_insn (gen_one_cmplsi2 (temp2_reg, temp2_reg));
++ emit_insn (gen_andsi3 (temp_reg, temp_reg, temp2_reg));
++ emit_insn (gen_unspec_volatile_mtsr (temp_reg, system_reg));
++ emit_insn (gen_unspec_dsb ());
++ DONE;
++})
++
++;; abs alias kabs
++
++(define_insn "unspec_kabs"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "r")] UNSPEC_KABS))]
++ ""
++ "kabs\t%0, %1"
++ [(set_attr "type" "alu")
++ (set_attr "length" "4")]
++)
++
++(define_expand "no_hwloop"
++ [(const_int 0)]
++ ""
++{
++ if (NDS32_HW_LOOP_P ())
++ emit_insn (gen_unspec_no_hwloop ());
++ else
++ emit_insn (gen_nop ());
++
++ DONE;
++})
++
++(define_insn "unspec_no_hwloop"
++ [(unspec_volatile [(const_int 0)] UNSPEC_VOLATILE_NO_HWLOOP)]
++ ""
++ ""
++ [(set_attr "type" "misc")]
++)
+ ;; ------------------------------------------------------------------------
+diff --git a/gcc/config/nds32/nds32-isr.c b/gcc/config/nds32/nds32-isr.c
+index 79be27e..be82609 100644
+--- a/gcc/config/nds32/nds32-isr.c
++++ b/gcc/config/nds32/nds32-isr.c
+@@ -24,11 +24,41 @@
+ #include "system.h"
+ #include "coretypes.h"
+ #include "backend.h"
+-#include "target.h"
+-#include "rtl.h"
+ #include "tree.h"
+-#include "diagnostic-core.h"
++#include "rtl.h"
++#include "df.h"
++#include "alias.h"
++#include "stor-layout.h"
++#include "varasm.h"
++#include "calls.h"
++#include "regs.h"
++#include "insn-config.h" /* Required by recog.h. */
++#include "conditions.h"
+ #include "output.h"
++#include "insn-attr.h" /* For DFA state_t. */
++#include "insn-codes.h" /* For CODE_FOR_xxx. */
++#include "reload.h" /* For push_reload(). */
++#include "flags.h"
++#include "insn-config.h"
++#include "expmed.h"
++#include "dojump.h"
++#include "explow.h"
++#include "emit-rtl.h"
++#include "stmt.h"
++#include "expr.h"
++#include "recog.h"
++#include "diagnostic-core.h"
++#include "cfgrtl.h"
++#include "cfganal.h"
++#include "lcm.h"
++#include "cfgbuild.h"
++#include "cfgcleanup.h"
++#include "tm_p.h"
++#include "tm-constrs.h"
++#include "optabs.h" /* For GEN_FCN. */
++#include "target.h"
++#include "langhooks.h" /* For add_builtin_function(). */
++#include "builtins.h"
+
+ /* ------------------------------------------------------------------------ */
+
+@@ -39,7 +69,260 @@
+ We use an array to record essential information for each vector. */
+ static struct nds32_isr_info nds32_isr_vectors[NDS32_N_ISR_VECTORS];
+
+-/* ------------------------------------------------------------------------ */
++/* ------------------------------------------------------------- */
++/* FIXME:
++ FOR BACKWARD COMPATIBILITY, we need to support following patterns:
++
++ __attribute__((interrupt("XXX;YYY;id=ZZZ")))
++ __attribute__((exception("XXX;YYY;id=ZZZ")))
++ __attribute__((reset("vectors=XXX;nmi_func=YYY;warm_func=ZZZ")))
++
++ We provide several functions to parse the strings. */
++
++static void
++nds32_interrupt_attribute_parse_string (const char *original_str,
++ const char *func_name,
++ unsigned int s_level)
++{
++ char target_str[100];
++ enum nds32_isr_save_reg save_reg;
++ enum nds32_isr_nested_type nested_type;
++
++ char *save_all_regs_str, *save_caller_regs_str;
++ char *nested_str, *not_nested_str, *ready_nested_str, *critical_str;
++ char *id_str, *value_str;
++
++ /* Copy original string into a character array so that
++ the string APIs can handle it. */
++ strcpy (target_str, original_str);
++
++ /* 1. Detect 'save_all_regs' : NDS32_SAVE_ALL
++ 'save_caller_regs' : NDS32_PARTIAL_SAVE */
++ save_all_regs_str = strstr (target_str, "save_all_regs");
++ save_caller_regs_str = strstr (target_str, "save_caller_regs");
++
++ /* Note that if no argument is found,
++ use NDS32_PARTIAL_SAVE by default. */
++ if (save_all_regs_str)
++ save_reg = NDS32_SAVE_ALL;
++ else if (save_caller_regs_str)
++ save_reg = NDS32_PARTIAL_SAVE;
++ else
++ save_reg = NDS32_PARTIAL_SAVE;
++
++ /* 2. Detect 'nested' : NDS32_NESTED
++ 'not_nested' : NDS32_NOT_NESTED
++ 'ready_nested' : NDS32_NESTED_READY
++ 'critical' : NDS32_CRITICAL */
++ nested_str = strstr (target_str, "nested");
++ not_nested_str = strstr (target_str, "not_nested");
++ ready_nested_str = strstr (target_str, "ready_nested");
++ critical_str = strstr (target_str, "critical");
++
++ /* Note that if no argument is found,
++ use NDS32_NOT_NESTED by default.
++ Also, since 'not_nested' and 'ready_nested' both contains
++ 'nested' string, we check 'nested' with lowest priority. */
++ if (not_nested_str)
++ nested_type = NDS32_NOT_NESTED;
++ else if (ready_nested_str)
++ nested_type = NDS32_NESTED_READY;
++ else if (nested_str)
++ nested_type = NDS32_NESTED;
++ else if (critical_str)
++ nested_type = NDS32_CRITICAL;
++ else
++ nested_type = NDS32_NOT_NESTED;
++
++ /* 3. Traverse each id value and set corresponding information. */
++ id_str = strstr (target_str, "id=");
++
++ /* If user forgets to assign 'id', issue an error message. */
++ if (id_str == NULL)
++ error ("require id argument in the string");
++ /* Extract the value_str first. */
++ id_str = strtok (id_str, "=");
++ value_str = strtok (NULL, ";");
++
++ /* Pick up the first id value token. */
++ value_str = strtok (value_str, ",");
++ while (value_str != NULL)
++ {
++ int i;
++ i = atoi (value_str);
++
++ /* For interrupt(0..63), the actual vector number is (9..72). */
++ i = i + 9;
++ if (i < 9 || i > 72)
++ error ("invalid id value for interrupt attribute");
++
++ /* Setup nds32_isr_vectors[] array. */
++ nds32_isr_vectors[i].category = NDS32_ISR_INTERRUPT;
++ strcpy (nds32_isr_vectors[i].func_name, func_name);
++ nds32_isr_vectors[i].save_reg = save_reg;
++ nds32_isr_vectors[i].nested_type = nested_type;
++ nds32_isr_vectors[i].security_level = s_level;
++
++ /* Fetch next token. */
++ value_str = strtok (NULL, ",");
++ }
++
++ return;
++}
++
++static void
++nds32_exception_attribute_parse_string (const char *original_str,
++ const char *func_name,
++ unsigned int s_level)
++{
++ char target_str[100];
++ enum nds32_isr_save_reg save_reg;
++ enum nds32_isr_nested_type nested_type;
++
++ char *save_all_regs_str, *save_caller_regs_str;
++ char *nested_str, *not_nested_str, *ready_nested_str, *critical_str;
++ char *id_str, *value_str;
++
++ /* Copy original string into a character array so that
++ the string APIs can handle it. */
++ strcpy (target_str, original_str);
++
++ /* 1. Detect 'save_all_regs' : NDS32_SAVE_ALL
++ 'save_caller_regs' : NDS32_PARTIAL_SAVE */
++ save_all_regs_str = strstr (target_str, "save_all_regs");
++ save_caller_regs_str = strstr (target_str, "save_caller_regs");
++
++ /* Note that if no argument is found,
++ use NDS32_PARTIAL_SAVE by default. */
++ if (save_all_regs_str)
++ save_reg = NDS32_SAVE_ALL;
++ else if (save_caller_regs_str)
++ save_reg = NDS32_PARTIAL_SAVE;
++ else
++ save_reg = NDS32_PARTIAL_SAVE;
++
++ /* 2. Detect 'nested' : NDS32_NESTED
++ 'not_nested' : NDS32_NOT_NESTED
++ 'ready_nested' : NDS32_NESTED_READY
++ 'critical' : NDS32_CRITICAL */
++ nested_str = strstr (target_str, "nested");
++ not_nested_str = strstr (target_str, "not_nested");
++ ready_nested_str = strstr (target_str, "ready_nested");
++ critical_str = strstr (target_str, "critical");
++
++ /* Note that if no argument is found,
++ use NDS32_NOT_NESTED by default.
++ Also, since 'not_nested' and 'ready_nested' both contains
++ 'nested' string, we check 'nested' with lowest priority. */
++ if (not_nested_str)
++ nested_type = NDS32_NOT_NESTED;
++ else if (ready_nested_str)
++ nested_type = NDS32_NESTED_READY;
++ else if (nested_str)
++ nested_type = NDS32_NESTED;
++ else if (critical_str)
++ nested_type = NDS32_CRITICAL;
++ else
++ nested_type = NDS32_NOT_NESTED;
++
++ /* 3. Traverse each id value and set corresponding information. */
++ id_str = strstr (target_str, "id=");
++
++ /* If user forgets to assign 'id', issue an error message. */
++ if (id_str == NULL)
++ error ("require id argument in the string");
++ /* Extract the value_str first. */
++ id_str = strtok (id_str, "=");
++ value_str = strtok (NULL, ";");
++
++ /* Pick up the first id value token. */
++ value_str = strtok (value_str, ",");
++ while (value_str != NULL)
++ {
++ int i;
++ i = atoi (value_str);
++
++ /* For exception(1..8), the actual vector number is (1..8). */
++ if (i < 1 || i > 8)
++ error ("invalid id value for exception attribute");
++
++ /* Setup nds32_isr_vectors[] array. */
++ nds32_isr_vectors[i].category = NDS32_ISR_EXCEPTION;
++ strcpy (nds32_isr_vectors[i].func_name, func_name);
++ nds32_isr_vectors[i].save_reg = save_reg;
++ nds32_isr_vectors[i].nested_type = nested_type;
++ nds32_isr_vectors[i].security_level = s_level;
++
++ /* Fetch next token. */
++ value_str = strtok (NULL, ",");
++ }
++
++ return;
++}
++
++static void
++nds32_reset_attribute_parse_string (const char *original_str,
++ const char *func_name)
++{
++ char target_str[100];
++ char *vectors_str, *nmi_str, *warm_str, *value_str;
++
++ /* Deal with reset attribute. Its vector number is always 0. */
++ nds32_isr_vectors[0].category = NDS32_ISR_RESET;
++
++
++ /* 1. Parse 'vectors=XXXX'. */
++
++ /* Copy original string into a character array so that
++ the string APIs can handle it. */
++ strcpy (target_str, original_str);
++ vectors_str = strstr (target_str, "vectors=");
++ /* The total vectors = interrupt + exception numbers + reset.
++ There are 8 exception and 1 reset in nds32 architecture.
++ If user forgets to assign 'vectors', user default 16 interrupts. */
++ if (vectors_str != NULL)
++ {
++ /* Extract the value_str. */
++ vectors_str = strtok (vectors_str, "=");
++ value_str = strtok (NULL, ";");
++ nds32_isr_vectors[0].total_n_vectors = atoi (value_str) + 8 + 1;
++ }
++ else
++ nds32_isr_vectors[0].total_n_vectors = 16 + 8 + 1;
++ strcpy (nds32_isr_vectors[0].func_name, func_name);
++
++
++ /* 2. Parse 'nmi_func=YYYY'. */
++
++ /* Copy original string into a character array so that
++ the string APIs can handle it. */
++ strcpy (target_str, original_str);
++ nmi_str = strstr (target_str, "nmi_func=");
++ if (nmi_str != NULL)
++ {
++ /* Extract the value_str. */
++ nmi_str = strtok (nmi_str, "=");
++ value_str = strtok (NULL, ";");
++ strcpy (nds32_isr_vectors[0].nmi_name, value_str);
++ }
++
++ /* 3. Parse 'warm_func=ZZZZ'. */
++
++ /* Copy original string into a character array so that
++ the string APIs can handle it. */
++ strcpy (target_str, original_str);
++ warm_str = strstr (target_str, "warm_func=");
++ if (warm_str != NULL)
++ {
++ /* Extract the value_str. */
++ warm_str = strtok (warm_str, "=");
++ value_str = strtok (NULL, ";");
++ strcpy (nds32_isr_vectors[0].warm_name, value_str);
++ }
++
++ return;
++}
++/* ------------------------------------------------------------- */
+
+ /* A helper function to emit section head template. */
+ static void
+@@ -75,6 +358,15 @@ nds32_emit_isr_jmptbl_section (int vector_id)
+ char section_name[100];
+ char symbol_name[100];
+
++ /* A critical isr does not need jump table section because
++ its behavior is not performed by two-level handler. */
++ if (nds32_isr_vectors[vector_id].nested_type == NDS32_CRITICAL)
++ {
++ fprintf (asm_out_file, "\t! The vector %02d is a critical isr !\n",
++ vector_id);
++ return;
++ }
++
+ /* Prepare jmptbl section and symbol name. */
+ snprintf (section_name, sizeof (section_name),
+ ".nds32_jmptbl.%02d", vector_id);
+@@ -95,7 +387,6 @@ nds32_emit_isr_vector_section (int vector_id)
+ const char *c_str = "CATEGORY";
+ const char *sr_str = "SR";
+ const char *nt_str = "NT";
+- const char *vs_str = "VS";
+ char first_level_handler_name[100];
+ char section_name[100];
+ char symbol_name[100];
+@@ -143,46 +434,63 @@ nds32_emit_isr_vector_section (int vector_id)
+ case NDS32_NESTED_READY:
+ nt_str = "nr";
+ break;
++ case NDS32_CRITICAL:
++ /* The critical isr is not performed by two-level handler. */
++ nt_str = "";
++ break;
+ }
+
+- /* Currently we have 4-byte or 16-byte size for each vector.
+- If it is 4-byte, the first level handler name has suffix string "_4b". */
+- vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
+-
+ /* Now we can create first level handler name. */
+- snprintf (first_level_handler_name, sizeof (first_level_handler_name),
+- "_nds32_%s_%s_%s%s", c_str, sr_str, nt_str, vs_str);
++ if (nds32_isr_vectors[vector_id].security_level == 0)
++ {
++ /* For security level 0, use normal first level handler name. */
++ snprintf (first_level_handler_name, sizeof (first_level_handler_name),
++ "_nds32_%s_%s_%s", c_str, sr_str, nt_str);
++ }
++ else
++ {
++ /* For security level 1-3, use corresponding spl_1, spl_2, or spl_3. */
++ snprintf (first_level_handler_name, sizeof (first_level_handler_name),
++ "_nds32_spl_%d", nds32_isr_vectors[vector_id].security_level);
++ }
+
+ /* Prepare vector section and symbol name. */
+ snprintf (section_name, sizeof (section_name),
+ ".nds32_vector.%02d", vector_id);
+ snprintf (symbol_name, sizeof (symbol_name),
+- "_nds32_vector_%02d%s", vector_id, vs_str);
++ "_nds32_vector_%02d", vector_id);
+
+
+ /* Everything is ready. We can start emit vector section content. */
+ nds32_emit_section_head_template (section_name, symbol_name,
+ floor_log2 (nds32_isr_vector_size), false);
+
+- /* According to the vector size, the instructions in the
+- vector section may be different. */
+- if (nds32_isr_vector_size == 4)
++ /* First we check if it is a critical isr.
++ If so, jump to user handler directly; otherwise, the instructions
++ in the vector section may be different according to the vector size. */
++ if (nds32_isr_vectors[vector_id].nested_type == NDS32_CRITICAL)
++ {
++ /* This block is for critical isr. Jump to user handler directly. */
++ fprintf (asm_out_file, "\tj\t%s ! jump to user handler directly\n",
++ nds32_isr_vectors[vector_id].func_name);
++ }
++ else if (nds32_isr_vector_size == 4)
+ {
+ /* This block is for 4-byte vector size.
+- Hardware $VID support is necessary and only one instruction
+- is needed in vector section. */
++ Hardware $VID support is necessary and only one instruction
++ is needed in vector section. */
+ fprintf (asm_out_file, "\tj\t%s ! jump to first level handler\n",
+ first_level_handler_name);
+ }
+ else
+ {
+ /* This block is for 16-byte vector size.
+- There is NO hardware $VID so that we need several instructions
+- such as pushing GPRs and preparing software vid at vector section.
+- For pushing GPRs, there are four variations for
+- 16-byte vector content and we have to handle each combination.
+- For preparing software vid, note that the vid need to
+- be substracted vector_number_offset. */
++ There is NO hardware $VID so that we need several instructions
++ such as pushing GPRs and preparing software vid at vector section.
++ For pushing GPRs, there are four variations for
++ 16-byte vector content and we have to handle each combination.
++ For preparing software vid, note that the vid need to
++ be substracted vector_number_offset. */
+ if (TARGET_REDUCED_REGS)
+ {
+ if (nds32_isr_vectors[vector_id].save_reg == NDS32_SAVE_ALL)
+@@ -235,13 +543,11 @@ nds32_emit_isr_reset_content (void)
+ {
+ unsigned int i;
+ unsigned int total_n_vectors;
+- const char *vs_str;
+ char reset_handler_name[100];
+ char section_name[100];
+ char symbol_name[100];
+
+ total_n_vectors = nds32_isr_vectors[0].total_n_vectors;
+- vs_str = (nds32_isr_vector_size == 4) ? "_4b" : "";
+
+ fprintf (asm_out_file, "\t! RESET HANDLER CONTENT - BEGIN !\n");
+
+@@ -257,7 +563,7 @@ nds32_emit_isr_reset_content (void)
+ /* Emit vector references. */
+ fprintf (asm_out_file, "\t ! references to vector section entries\n");
+ for (i = 0; i < total_n_vectors; i++)
+- fprintf (asm_out_file, "\t.word\t_nds32_vector_%02d%s\n", i, vs_str);
++ fprintf (asm_out_file, "\t.word\t_nds32_vector_%02d\n", i);
+
+ /* Emit jmptbl_00 section. */
+ snprintf (section_name, sizeof (section_name), ".nds32_jmptbl.00");
+@@ -271,9 +577,9 @@ nds32_emit_isr_reset_content (void)
+
+ /* Emit vector_00 section. */
+ snprintf (section_name, sizeof (section_name), ".nds32_vector.00");
+- snprintf (symbol_name, sizeof (symbol_name), "_nds32_vector_00%s", vs_str);
++ snprintf (symbol_name, sizeof (symbol_name), "_nds32_vector_00");
+ snprintf (reset_handler_name, sizeof (reset_handler_name),
+- "_nds32_reset%s", vs_str);
++ "_nds32_reset");
+
+ fprintf (asm_out_file, "\t! ....................................\n");
+ nds32_emit_section_head_template (section_name, symbol_name,
+@@ -319,12 +625,12 @@ void
+ nds32_check_isr_attrs_conflict (tree func_decl, tree func_attrs)
+ {
+ int save_all_p, partial_save_p;
+- int nested_p, not_nested_p, nested_ready_p;
++ int nested_p, not_nested_p, nested_ready_p, critical_p;
+ int intr_p, excp_p, reset_p;
+
+ /* Initialize variables. */
+ save_all_p = partial_save_p = 0;
+- nested_p = not_nested_p = nested_ready_p = 0;
++ nested_p = not_nested_p = nested_ready_p = critical_p = 0;
+ intr_p = excp_p = reset_p = 0;
+
+ /* We must check at MOST one attribute to set save-reg. */
+@@ -343,8 +649,10 @@ nds32_check_isr_attrs_conflict (tree func_decl, tree func_attrs)
+ not_nested_p = 1;
+ if (lookup_attribute ("nested_ready", func_attrs))
+ nested_ready_p = 1;
++ if (lookup_attribute ("critical", func_attrs))
++ critical_p = 1;
+
+- if ((nested_p + not_nested_p + nested_ready_p) > 1)
++ if ((nested_p + not_nested_p + nested_ready_p + critical_p) > 1)
+ error ("multiple nested types attributes to function %qD", func_decl);
+
+ /* We must check at MOST one attribute to
+@@ -358,6 +666,17 @@ nds32_check_isr_attrs_conflict (tree func_decl, tree func_attrs)
+
+ if ((intr_p + excp_p + reset_p) > 1)
+ error ("multiple interrupt attributes to function %qD", func_decl);
++
++ /* Do not allow isr attributes under linux toolchain. */
++ if (TARGET_LINUX_ABI && intr_p)
++ error ("cannot use interrupt attributes to function %qD "
++ "under linux toolchain", func_decl);
++ if (TARGET_LINUX_ABI && excp_p)
++ error ("cannot use exception attributes to function %qD "
++ "under linux toolchain", func_decl);
++ if (TARGET_LINUX_ABI && reset_p)
++ error ("cannot use reset attributes to function %qD "
++ "under linux toolchain", func_decl);
+ }
+
+ /* Function to construct isr vectors information array.
+@@ -369,15 +688,21 @@ nds32_construct_isr_vectors_information (tree func_attrs,
+ const char *func_name)
+ {
+ tree save_all, partial_save;
+- tree nested, not_nested, nested_ready;
++ tree nested, not_nested, nested_ready, critical;
+ tree intr, excp, reset;
+
++ tree secure;
++ tree security_level_list;
++ tree security_level;
++ unsigned int s_level;
++
+ save_all = lookup_attribute ("save_all", func_attrs);
+ partial_save = lookup_attribute ("partial_save", func_attrs);
+
+ nested = lookup_attribute ("nested", func_attrs);
+ not_nested = lookup_attribute ("not_nested", func_attrs);
+ nested_ready = lookup_attribute ("nested_ready", func_attrs);
++ critical = lookup_attribute ("critical", func_attrs);
+
+ intr = lookup_attribute ("interrupt", func_attrs);
+ excp = lookup_attribute ("exception", func_attrs);
+@@ -387,6 +712,63 @@ nds32_construct_isr_vectors_information (tree func_attrs,
+ if (!intr && !excp && !reset)
+ return;
+
++ /* At first, we need to retrieve security level. */
++ secure = lookup_attribute ("secure", func_attrs);
++ if (secure != NULL)
++ {
++ security_level_list = TREE_VALUE (secure);
++ security_level = TREE_VALUE (security_level_list);
++ s_level = TREE_INT_CST_LOW (security_level);
++ }
++ else
++ {
++ /* If there is no secure attribute, the security level is set by
++ nds32_isr_secure_level, which is controlled by -misr-secure=X option.
++ By default nds32_isr_secure_level should be 0. */
++ s_level = nds32_isr_secure_level;
++ }
++
++ /* ------------------------------------------------------------- */
++ /* FIXME:
++ FOR BACKWARD COMPATIBILITY, we need to support following patterns:
++
++ __attribute__((interrupt("XXX;YYY;id=ZZZ")))
++ __attribute__((exception("XXX;YYY;id=ZZZ")))
++ __attribute__((reset("vectors=XXX;nmi_func=YYY;warm_func=ZZZ")))
++
++ If interrupt/exception/reset appears and its argument is a
++ STRING_CST, we will parse string with some auxiliary functions
++ which set necessary isr information in the nds32_isr_vectors[] array.
++ After that, we can return immediately to avoid new-syntax isr
++ information construction. */
++ if (intr != NULL_TREE
++ && TREE_CODE (TREE_VALUE (TREE_VALUE (intr))) == STRING_CST)
++ {
++ tree string_arg = TREE_VALUE (TREE_VALUE (intr));
++ nds32_interrupt_attribute_parse_string (TREE_STRING_POINTER (string_arg),
++ func_name,
++ s_level);
++ return;
++ }
++ if (excp != NULL_TREE
++ && TREE_CODE (TREE_VALUE (TREE_VALUE (excp))) == STRING_CST)
++ {
++ tree string_arg = TREE_VALUE (TREE_VALUE (excp));
++ nds32_exception_attribute_parse_string (TREE_STRING_POINTER (string_arg),
++ func_name,
++ s_level);
++ return;
++ }
++ if (reset != NULL_TREE
++ && TREE_CODE (TREE_VALUE (TREE_VALUE (reset))) == STRING_CST)
++ {
++ tree string_arg = TREE_VALUE (TREE_VALUE (reset));
++ nds32_reset_attribute_parse_string (TREE_STRING_POINTER (string_arg),
++ func_name);
++ return;
++ }
++ /* ------------------------------------------------------------- */
++
+ /* If we are here, either we have interrupt/exception,
+ or reset attribute. */
+ if (intr || excp)
+@@ -413,6 +795,9 @@ nds32_construct_isr_vectors_information (tree func_attrs,
+ /* Add vector_number_offset to get actual vector number. */
+ vector_id = TREE_INT_CST_LOW (id) + vector_number_offset;
+
++ /* Set security level. */
++ nds32_isr_vectors[vector_id].security_level = s_level;
++
+ /* Enable corresponding vector and set function name. */
+ nds32_isr_vectors[vector_id].category = (intr)
+ ? (NDS32_ISR_INTERRUPT)
+@@ -432,6 +817,8 @@ nds32_construct_isr_vectors_information (tree func_attrs,
+ nds32_isr_vectors[vector_id].nested_type = NDS32_NOT_NESTED;
+ else if (nested_ready)
+ nds32_isr_vectors[vector_id].nested_type = NDS32_NESTED_READY;
++ else if (critical)
++ nds32_isr_vectors[vector_id].nested_type = NDS32_CRITICAL;
+
+ /* Advance to next id. */
+ id_list = TREE_CHAIN (id_list);
+@@ -447,12 +834,12 @@ nds32_construct_isr_vectors_information (tree func_attrs,
+ nds32_isr_vectors[0].category = NDS32_ISR_RESET;
+
+ /* Prepare id_list and identify id value so that
+- we can set total number of vectors. */
++ we can set total number of vectors. */
+ id_list = TREE_VALUE (reset);
+ id = TREE_VALUE (id_list);
+
+ /* The total vectors = interrupt + exception numbers + reset.
+- There are 8 exception and 1 reset in nds32 architecture. */
++ There are 8 exception and 1 reset in nds32 architecture. */
+ nds32_isr_vectors[0].total_n_vectors = TREE_INT_CST_LOW (id) + 8 + 1;
+ strcpy (nds32_isr_vectors[0].func_name, func_name);
+
+@@ -488,7 +875,6 @@ nds32_construct_isr_vectors_information (tree func_attrs,
+ }
+ }
+
+-/* A helper function to handle isr stuff at the beginning of asm file. */
+ void
+ nds32_asm_file_start_for_isr (void)
+ {
+@@ -501,15 +887,14 @@ nds32_asm_file_start_for_isr (void)
+ strcpy (nds32_isr_vectors[i].func_name, "");
+ nds32_isr_vectors[i].save_reg = NDS32_PARTIAL_SAVE;
+ nds32_isr_vectors[i].nested_type = NDS32_NOT_NESTED;
++ nds32_isr_vectors[i].security_level = 0;
+ nds32_isr_vectors[i].total_n_vectors = 0;
+ strcpy (nds32_isr_vectors[i].nmi_name, "");
+ strcpy (nds32_isr_vectors[i].warm_name, "");
+ }
+ }
+
+-/* A helper function to handle isr stuff at the end of asm file. */
+-void
+-nds32_asm_file_end_for_isr (void)
++void nds32_asm_file_end_for_isr (void)
+ {
+ int i;
+
+@@ -543,6 +928,8 @@ nds32_asm_file_end_for_isr (void)
+ /* Found one vector which is interupt or exception.
+ Output its jmptbl and vector section content. */
+ fprintf (asm_out_file, "\t! interrupt/exception vector %02d\n", i);
++ fprintf (asm_out_file, "\t! security level: %d\n",
++ nds32_isr_vectors[i].security_level);
+ fprintf (asm_out_file, "\t! ------------------------------------\n");
+ nds32_emit_isr_jmptbl_section (i);
+ fprintf (asm_out_file, "\t! ....................................\n");
+@@ -576,4 +963,65 @@ nds32_isr_function_p (tree func)
+ || (t_reset != NULL_TREE));
+ }
+
+-/* ------------------------------------------------------------------------ */
++/* Return true if FUNC is a isr function with critical attribute. */
++bool
++nds32_isr_function_critical_p (tree func)
++{
++ tree t_intr;
++ tree t_excp;
++ tree t_critical;
++
++ tree attrs;
++
++ if (TREE_CODE (func) != FUNCTION_DECL)
++ abort ();
++
++ attrs = DECL_ATTRIBUTES (func);
++
++ t_intr = lookup_attribute ("interrupt", attrs);
++ t_excp = lookup_attribute ("exception", attrs);
++
++ t_critical = lookup_attribute ("critical", attrs);
++
++ /* If both interrupt and exception attribute does not appear,
++ we can return false immediately. */
++ if ((t_intr == NULL_TREE) && (t_excp == NULL_TREE))
++ return false;
++
++ /* Here we can guarantee either interrupt or ecxception attribute
++ does exist, so further check critical attribute.
++ If it also appears, we can return true. */
++ if (t_critical != NULL_TREE)
++ return true;
++
++ /* ------------------------------------------------------------- */
++ /* FIXME:
++ FOR BACKWARD COMPATIBILITY, we need to handle string type.
++ If the string 'critical' appears in the interrupt/exception
++ string argument, we can return true. */
++ if (t_intr != NULL_TREE || t_excp != NULL_TREE)
++ {
++ char target_str[100];
++ char *critical_str;
++ tree t_check;
++ tree string_arg;
++
++ t_check = t_intr ? t_intr : t_excp;
++ if (TREE_CODE (TREE_VALUE (TREE_VALUE (t_check))) == STRING_CST)
++ {
++ string_arg = TREE_VALUE (TREE_VALUE (t_check));
++ strcpy (target_str, TREE_STRING_POINTER (string_arg));
++ critical_str = strstr (target_str, "critical");
++
++ /* Found 'critical' string, so return true. */
++ if (critical_str)
++ return true;
++ }
++ }
++ /* ------------------------------------------------------------- */
++
++ /* Other cases, this isr function is not critical type. */
++ return false;
++}
++
++/* ------------------------------------------------------------- */
+diff --git a/gcc/config/nds32/nds32-linux.opt b/gcc/config/nds32/nds32-linux.opt
+new file mode 100644
+index 0000000..75ccd76
+--- /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-lmwsmw.c b/gcc/config/nds32/nds32-lmwsmw.c
+new file mode 100644
+index 0000000..e3b66bf
+--- /dev/null
++++ b/gcc/config/nds32/nds32-lmwsmw.c
+@@ -0,0 +1,1998 @@
++
++/* lmwsmw pass of Andes NDS32 cpu for GNU compiler
++ Copyright (C) 2012-2016 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
++ . */
++
++/* ------------------------------------------------------------------------ */
++#include "config.h"
++#include "system.h"
++#include "coretypes.h"
++#include "tm.h"
++#include "hash-set.h"
++#include "machmode.h"
++#include "vec.h"
++#include "double-int.h"
++#include "input.h"
++#include "alias.h"
++#include "symtab.h"
++#include "wide-int.h"
++#include "inchash.h"
++#include "tree.h"
++#include "stor-layout.h"
++#include "varasm.h"
++#include "calls.h"
++#include "rtl.h"
++#include "regs.h"
++#include "hard-reg-set.h"
++#include "insn-config.h" /* Required by recog.h. */
++#include "conditions.h"
++#include "output.h"
++#include "insn-attr.h" /* For DFA state_t. */
++#include "insn-codes.h" /* For CODE_FOR_xxx. */
++#include "reload.h" /* For push_reload(). */
++#include "flags.h"
++#include "input.h"
++#include "function.h"
++#include "expr.h"
++#include "recog.h"
++#include "diagnostic-core.h"
++#include "dominance.h"
++#include "cfg.h"
++#include "cfgrtl.h"
++#include "cfganal.h"
++#include "lcm.h"
++#include "cfgbuild.h"
++#include "cfgcleanup.h"
++#include "predict.h"
++#include "basic-block.h"
++#include "bitmap.h"
++#include "df.h"
++#include "tm_p.h"
++#include "tm-constrs.h"
++#include "optabs.h" /* For GEN_FCN. */
++#include "target.h"
++#include "langhooks.h" /* For add_builtin_function(). */
++#include "ggc.h"
++#include "tree-pass.h"
++#include "target-globals.h"
++#include "ira.h"
++#include "ira-int.h"
++#include "regrename.h"
++#include "nds32-load-store-opt.h"
++#include "nds32-reg-utils.h"
++#include
++#include
++#include
++
++#define NDS32_GPR_NUM 32
++
++static int
++compare_order (const void *a, const void *b)
++{
++ const load_store_info_t *fp1 = (const load_store_info_t *) a;
++ const load_store_info_t *fp2 = (const load_store_info_t *) b;
++ const load_store_info_t f1 = *fp1;
++ const load_store_info_t f2 = *fp2;
++
++ return f1.order < f2.order ? -1 : 1;
++}
++
++static int
++compare_offset (const void *a, const void *b)
++{
++ const load_store_info_t *fp1 = (const load_store_info_t *) a;
++ const load_store_info_t *fp2 = (const load_store_info_t *) b;
++ const load_store_info_t f1 = *fp1;
++ const load_store_info_t f2 = *fp2;
++
++ return f1.offset < f2.offset ? -1 : 1;
++}
++
++static bool
++compare_amount(available_reg_info_t a, available_reg_info_t b)
++{
++ return a.amount > b.amount;
++}
++
++static bool
++nds32_load_store_reg_plus_offset (rtx_insn *insn, load_store_info_t *load_store_info)
++{
++ rtx pattern, mem, reg, base_reg, addr;
++ HOST_WIDE_INT offset;
++ bool load_p;
++ enum nds32_memory_post_type post_type = NDS32_NONE;
++
++ pattern = PATTERN (insn);
++ mem = NULL_RTX;
++ reg = NULL_RTX;
++ base_reg = NULL_RTX;
++ offset = 0;
++ load_p = false;
++
++ if (GET_CODE (pattern) != SET)
++ return false;
++
++ if (MEM_P (SET_SRC (pattern)))
++ {
++ mem = SET_SRC (pattern);
++ reg = SET_DEST (pattern);
++ load_p = true;
++ }
++
++ if (MEM_P (SET_DEST (pattern)))
++ {
++ mem = SET_DEST (pattern);
++ reg = SET_SRC (pattern);
++ load_p = false;
++ }
++
++ if (mem == NULL_RTX || reg == NULL_RTX || !REG_P (reg))
++ return false;
++
++ /* The FPU ISA has not load-store-multiple instruction. */
++ if (!NDS32_IS_GPR_REGNUM (REGNO (reg)))
++ return false;
++
++ if (MEM_VOLATILE_P (mem))
++ return false;
++
++ if (GET_MODE (reg) != SImode)
++ return false;
++
++ gcc_assert (REG_P (reg));
++
++ addr = XEXP (mem, 0);
++
++ /* We only care about [reg] and [reg+const]. */
++ if (REG_P (addr))
++ {
++ base_reg = addr;
++ offset = 0;
++ }
++ else if (GET_CODE (addr) == PLUS
++ && CONST_INT_P (XEXP (addr, 1)))
++ {
++ base_reg = XEXP (addr, 0);
++ offset = INTVAL (XEXP (addr, 1));
++ if (!REG_P (base_reg))
++ return false;
++ }
++ else if (GET_CODE (addr) == POST_INC)
++ {
++ base_reg = XEXP (addr, 0);
++ offset = 0;
++ post_type = NDS32_POST_INC;
++ }
++ else if (GET_CODE (addr) == POST_DEC)
++ {
++ base_reg = XEXP (addr, 0);
++ offset = 0;
++ post_type = NDS32_POST_DEC;
++ }
++ else
++ return false;
++
++ if ((REGNO (base_reg) > NDS32_LAST_GPR_REGNUM)
++ && (REGNO (base_reg) < FIRST_PSEUDO_REGISTER))
++ return false;
++
++ if (load_store_info)
++ {
++ load_store_info->load_p = load_p;
++ load_store_info->offset = offset;
++ load_store_info->reg = reg;
++ load_store_info->base_reg = base_reg;
++ load_store_info->insn = insn;
++ load_store_info->mem = mem;
++ load_store_info->post_type = post_type;
++ }
++
++ return true;
++}
++
++static bool
++nds32_insn_alias_p (rtx memref, rtx x)
++{
++ rtx mem;
++
++ if (GET_CODE (x) == PARALLEL)
++ {
++ int i, j;
++
++ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
++ {
++ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
++ if (nds32_insn_alias_p (memref, XVECEXP (x, i, j)))
++ return true;
++ }
++
++ return false;
++ }
++
++ if (GET_CODE (x) != SET)
++ return true;
++
++ if (MEM_P (SET_SRC (x)))
++ mem = SET_SRC (x);
++ else if (MEM_P (SET_DEST (x)))
++ mem = SET_DEST (x);
++ else
++ return false;
++
++ if (may_alias_p (memref, mem))
++ return true;
++ else
++ return false;
++}
++
++static void
++nds32_emit_multiple_insn (load_store_infos_t *multiple_insn,
++ rtx base_reg, rtx place, bool update_p)
++{
++ unsigned int i;
++ unsigned int num_use_regs = multiple_insn->length ();
++ int par_index = 0;
++ int offset = 0;
++ bool load_p = (*multiple_insn)[0].load_p;
++
++ rtx reg;
++ rtx mem;
++ rtx push_rtx;
++ rtx update_offset;
++ rtx parallel_insn;
++
++ /* In addition to used registers,
++ we need one more space for (set base base-x) rtx. */
++ if (update_p)
++ num_use_regs++;
++
++ parallel_insn = gen_rtx_PARALLEL (VOIDmode,
++ rtvec_alloc (num_use_regs));
++
++ /* Set update insn. */
++ if (update_p)
++ {
++ update_offset = GEN_INT (multiple_insn->length () * 4);
++ push_rtx = gen_addsi3 (base_reg, base_reg, update_offset);
++ XVECEXP (parallel_insn, 0, par_index) = push_rtx;
++ par_index++;
++ }
++
++ /* Create (set mem regX) from start_reg to end_reg. */
++ for (i = 0; i < multiple_insn->length (); ++i)
++ {
++ reg = (*multiple_insn)[i].reg;
++ mem = gen_frame_mem (SImode, plus_constant (Pmode,
++ base_reg,
++ offset));
++ MEM_COPY_ATTRIBUTES (mem, (*multiple_insn)[i].mem);
++
++ if (load_p)
++ push_rtx = gen_rtx_SET (reg, mem);
++ else
++ push_rtx = gen_rtx_SET (mem, reg);
++
++ XVECEXP (parallel_insn, 0, par_index) = push_rtx;
++ offset = offset + 4;
++ par_index++;
++ }
++
++ emit_insn_before (parallel_insn, place);
++
++ if (dump_file)
++ {
++ fprintf (dump_file, "lmw/smw instruction:\n");
++ print_rtl_single (dump_file, parallel_insn);
++ }
++}
++
++static void
++nds32_emit_add_insn (load_store_info_t insn, rtx base_reg,
++ rtx place, bool add_p)
++{
++ rtx add_insn;
++ HOST_WIDE_INT offset = insn.offset;
++ if (!add_p)
++ offset = -offset;
++
++ add_insn = gen_addsi3 (base_reg, insn.base_reg, GEN_INT (offset));
++ emit_insn_before (add_insn, place);
++}
++
++/* Get the instruction of same ID. */
++static void
++nds32_fetch_group_insn (load_store_infos_t *src,
++ load_store_infos_t *dst, int id)
++{
++ unsigned int i = 0;
++
++ while (i < src->length ())
++ {
++ if (id == (*src)[i].group)
++ {
++ dst->safe_push ((*src)[i]);
++ src->ordered_remove (i);
++ i = 0;
++ }
++ else
++ i++;
++ }
++}
++
++/* Check registers are not used and defined. */
++static rtx
++nds32_lmwsmw_insert_place (load_store_infos_t *insn_set)
++{
++ unsigned int i, position;
++ bool combine_p;
++ rtx_insn *insn;
++ auto_vec temp_set;
++
++ for (i = 0; i < insn_set->length (); i++)
++ temp_set.safe_push ((*insn_set)[i]);
++
++ /* Check registers are not used and defined
++ between first instruction and last instruction,
++ and find insert lmw/smw instruction place.
++ example:
++ lwi $r0, [$r2 + 4]
++ lwi $r1, [$r2 + 8]
++
++ Check $r0 and $r1 are not used and defined. */
++ temp_set.qsort (compare_order);
++
++ for (position = 0; position < temp_set.length (); ++position)
++ {
++ combine_p = true;
++
++ /* Check instruction form first instruction to position. */
++ for (i = 0; i < position; i++)
++ {
++ for (insn = NEXT_INSN (temp_set[i].insn);
++ insn != temp_set[position].insn;
++ insn = NEXT_INSN (insn))
++ {
++ if (!NONDEBUG_INSN_P (insn))
++ continue;
++ if (df_reg_used (insn, temp_set[i].reg)
++ || df_reg_defined (insn, temp_set[i].reg))
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, "Fail:register has modify\n");
++ fprintf (dump_file, "insn uid:%d, reg: r%d,\n",
++ INSN_UID (temp_set[position].insn),
++ REGNO (temp_set[position].reg));
++ fprintf (dump_file, "Modify instruction:\n");
++ print_rtl_single (dump_file, insn);
++ }
++ combine_p = false;
++ break;
++ }
++ }
++ }
++
++ /* Check instruction form position to last instruction. */
++ for (i = position + 1; i < temp_set.length (); i++)
++ {
++ for (insn = temp_set[position].insn;
++ insn != temp_set[i].insn;
++ insn = NEXT_INSN (insn))
++ {
++ if (!NONDEBUG_INSN_P (insn))
++ continue;
++ if (df_reg_used (insn, temp_set[i].reg)
++ || df_reg_defined (insn, temp_set[i].reg))
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, "Fail:register has modify\n");
++ fprintf (dump_file, "insn uid:%d, reg: r%d,\n",
++ INSN_UID (temp_set[position].insn),
++ REGNO (temp_set[position].reg));
++ fprintf (dump_file, "Modify instruction:\n");
++ print_rtl_single (dump_file, insn);
++ }
++ combine_p = false;
++ break;
++ }
++ }
++ }
++
++ if (combine_p)
++ return temp_set[position].insn;
++ }
++
++ return NULL_RTX;
++}
++
++/* Check registers are not used and defined. */
++static bool
++nds32_base_reg_safe_p (load_store_infos_t *insn_set)
++{
++ unsigned int i;
++ rtx_insn *insn;
++ auto_vec temp_set;
++
++ /* We will change 'insn_set' element order,
++ to avoid change order using 'temp_set'. */
++ for (i = 0; i < insn_set->length (); i++)
++ temp_set.safe_push ((*insn_set)[i]);
++
++ /* We want to combine load and store instructions,
++ need to check base register is not used and defined
++ between first insn and last insn.
++ example:
++ lwi $r0, [$r3 + 4]
++ ... <- check here
++ lwi $r1, [$r3 + 8]
++ ... <- check here
++ lwi $r2, [$r3 + 12]
++
++ Check $r3 is not used and defined,
++ between first insn and last insn. */
++
++ /* Scan instruction from top to bottom,
++ so need to sort by order. */
++ temp_set.qsort (compare_order);
++
++ for (i = 0; i < temp_set.length () - 1; ++i)
++ {
++ for (insn = NEXT_INSN (temp_set[i].insn);
++ insn != temp_set[i + 1].insn;
++ insn = NEXT_INSN (insn))
++ {
++ if (!NONDEBUG_INSN_P (insn))
++ continue;
++
++ if (nds32_insn_alias_p (temp_set[0].mem, PATTERN (insn)))
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, "Memory alias:\n");
++ print_rtl_single (dump_file, insn);
++ }
++ return false;
++ }
++
++ if (temp_set[0].load_p)
++ {
++ if (df_reg_defined (insn, temp_set[0].base_reg))
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, "Fail: base register has modify\n");
++ fprintf (dump_file, "insn uid:%d, base reg: r%d,\n",
++ INSN_UID (temp_set[i].insn),
++ REGNO (temp_set[i].reg));
++ fprintf (dump_file, "Modify instruction:\n");
++ print_rtl_single (dump_file, insn);
++ }
++ return false;
++ }
++ }
++ else
++ {
++ if (df_reg_used (insn, temp_set[0].base_reg))
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, "Fail: base register has modify\n");
++ fprintf (dump_file, "insn uid:%d, base reg: r%d,\n",
++ INSN_UID (temp_set[i].insn),
++ REGNO (temp_set[i].reg));
++ fprintf (dump_file, "Modify instruction:\n");
++ print_rtl_single (dump_file, insn);
++ }
++ return false;
++ }
++ }
++ }
++ }
++ return true;
++}
++
++static bool
++nds32_gain_size_p (load_store_infos_t *insn, bool new_base_p)
++{
++ unsigned int i, new_cost = 4, old_cost = 0;
++ rtx reg;
++ rtx base_reg = (*insn)[0].base_reg;
++ HOST_WIDE_INT offset;
++
++ for (i = 0; i < insn->length (); ++i)
++ {
++ reg = (*insn)[i].reg;
++ offset = (*insn)[i].offset;
++
++ if (in_reg_class_p (reg, LOW_REGS))
++ {
++ /* lwi37.sp/swi37.sp/lwi37/swi37 */
++ if ((REGNO (base_reg) == SP_REGNUM
++ || REGNO (base_reg) == FP_REGNUM)
++ && (offset >= 0 && offset < 512 && (offset % 4 == 0)))
++ old_cost += 2;
++ /* lwi333/swi333 */
++ else if (in_reg_class_p (base_reg, LOW_REGS)
++ && (offset >= 0 && offset < 32 && (offset % 4 == 0)))
++ old_cost += 2;
++ else
++ old_cost += 4;
++ }
++ else
++ {
++ /* lwi450/swi450 */
++ if (in_reg_class_p (reg, MIDDLE_REGS)
++ && offset == 0)
++ old_cost += 2;
++ else
++ old_cost += 4;
++ }
++ }
++
++ offset = (*insn)[0].offset;
++ if (offset != 0)
++ {
++ /* addi333 */
++ if (in_reg_class_p (base_reg, LOW_REGS)
++ && satisfies_constraint_Iu05 (GEN_INT (offset)))
++ new_cost += 2;
++ /* addi45 */
++ else if (in_reg_class_p (base_reg, MIDDLE_REGS)
++ && satisfies_constraint_Iu05 (GEN_INT (offset)))
++ new_cost += 2;
++ else
++ new_cost += 4;
++
++ /* subri */
++ if (!new_base_p)
++ new_cost += 4;
++ }
++
++ if (dump_file)
++ fprintf (dump_file, "Code size compare: old code size is %d,"
++ " new code size is %d\n", old_cost, new_cost);
++
++ return new_cost < old_cost;
++}
++
++static bool
++nds32_gain_speed_p (load_store_infos_t *insn, bool new_base_p)
++{
++ unsigned int new_cost = 0, old_cost = insn->length ();
++
++ if (TARGET_PIPELINE_GRAYWOLF)
++ {
++ new_cost = insn->length () / 2 + insn->length () % 2;
++
++ if ((*insn)[0].offset != 0)
++ {
++ /* Need addi instruction. */
++ new_cost += 1;
++
++ /* Need subri instruction. */
++ if (!new_base_p)
++ new_cost += 1;
++ }
++ }
++ else
++ {
++ if ((*insn)[0].offset != 0)
++ return false;
++ }
++
++ return new_cost < old_cost;
++}
++
++/* Check instructions can combine into a mulitple-instruction. */
++static bool
++nds32_combine_multiple_p (load_store_infos_t *insn_set, bool new_base_p)
++{
++ unsigned int i;
++ auto_vec temp_set;
++
++ /* We will change 'insn_set' element order,
++ to avoid change order using 'temp_set'. */
++ for (i = 0; i < insn_set->length (); i++)
++ temp_set.safe_push ((*insn_set)[i]);
++
++ /* Check start offset need to sort by offset. */
++ temp_set.qsort (compare_offset);
++
++ /* The lmw/smw pattern, need two or more instructions. */
++ if (temp_set.length () < 2)
++ return false;
++
++ /* The lmw/smw pattern, only allow combine 25 instruction. */
++ if (temp_set.length () > 25)
++ return false;
++
++ if (TARGET_LMWSMW_OPT_SIZE
++ || (TARGET_LMWSMW_OPT_AUTO && optimize_size))
++ {
++ /* Compare original instructions with multiple instruction,
++ when mupltiple instruction is small than original instructions
++ then combine it. */
++ if (!nds32_gain_size_p (&temp_set, new_base_p))
++ return false;
++ }
++ else if (TARGET_LMWSMW_OPT_SPEED
++ || (TARGET_LMWSMW_OPT_AUTO && !optimize_size))
++ {
++ /* The start offset is not zero, we need add a instrucion
++ to handle offset, it is not worth on -O3, -O2 level. */
++ if (!nds32_gain_speed_p (&temp_set, new_base_p))
++ return false;
++ }
++
++ /* Base register is not equal register, when offset is not zero. */
++ if (temp_set[0].offset != 0)
++ for (i = 0; i < temp_set.length (); ++i)
++ {
++ if (REGNO (temp_set[i].reg)
++ == REGNO (temp_set[0].base_reg))
++ return false;
++ }
++
++ /* Don't combine, when start offset is greater then Is15,
++ because need extra register. */
++ if (!satisfies_constraint_Is15 (GEN_INT (temp_set[0].offset)))
++ return false;
++
++ return true;
++}
++
++static bool
++nds32_use_bim_p (load_store_infos_t *insn_set,
++ load_store_infos_t *ref_set)
++{
++ rtx_insn *insn;
++ bool combine_p = true;
++
++ /* Generate .bim form, need offset is continuous. */
++ if (insn_set->last ().offset != ((*ref_set)[0].offset - 4))
++ return false;
++
++ /* Reject 'insn_set' instructions bottom
++ of the 'ref_set' instructions. */
++ if ((*insn_set)[0].group > (*ref_set)[0].group)
++ return false;
++
++ /* Scan instruction from top to bottom,
++ so need to sort by order. */
++ insn_set->qsort (compare_order);
++ ref_set->qsort (compare_order);
++
++ /* We want to combine .bim form instruction,
++ so need to check base register is not used and defined
++ between multiple-insn and next mulitple-insn.
++ example:
++ lmw.bim $r0, [$r2], $r1
++ ... <- check here
++ lmw.bi $r3, [$r2], $r4
++
++ Use .bim form need to check $r2 is not used and defined,
++ between lmw.bim and lmw.bi. */
++ for (insn = NEXT_INSN (insn_set->last ().insn);
++ insn != (*ref_set)[0].insn;
++ insn = NEXT_INSN (insn))
++ {
++ if (!NONDEBUG_INSN_P (insn))
++ continue;
++
++ if (nds32_insn_alias_p ((*insn_set)[0].mem, PATTERN (insn)))
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, "Have memory instruction:\n");
++ print_rtl_single (dump_file, insn);
++ }
++ combine_p = false;
++ break;
++ }
++
++ if (df_reg_used (insn, (*insn_set)[0].base_reg)
++ || df_reg_defined (insn, (*insn_set)[0].base_reg))
++ {
++ if (dump_file)
++ {
++ fprintf (dump_file, "Use .bi form: Base reg is"
++ " used or defined between multiple-insn"
++ " and next multiple-insn\n");
++ fprintf (dump_file, "Base register: r%d,\n",
++ REGNO ((*insn_set)[0].base_reg));
++ fprintf (dump_file, "use or def instruction:\n");
++ print_rtl_single (dump_file, insn);
++ }
++ combine_p = false;
++ break;
++ }
++ }
++
++ /* Restore element order. */
++ insn_set->qsort (compare_offset);
++ ref_set->qsort (compare_offset);
++
++ if (combine_p)
++ return true;
++ else
++ return false;
++}
++
++static void
++nds32_merge_overlapping_regs (HARD_REG_SET *pset, struct du_head *head)
++{
++ bitmap_iterator bi;
++ unsigned i;
++ IOR_HARD_REG_SET (*pset, head->hard_conflicts);
++ EXECUTE_IF_SET_IN_BITMAP (&head->conflicts, 0, i, bi)
++ {
++ du_head_p other = regrename_chain_from_id (i);
++ unsigned j = other->nregs;
++ gcc_assert (other != head);
++ while (j-- > 0)
++ SET_HARD_REG_BIT (*pset, other->regno + j);
++ }
++}
++
++/* Check if NEW_REG can be the candidate register to rename for
++ REG in THIS_HEAD chain. THIS_UNAVAILABLE is a set of unavailable hard
++ registers. */
++static bool
++nds32_check_new_reg_p (int reg ATTRIBUTE_UNUSED, int new_reg,
++ struct du_head *this_head, HARD_REG_SET this_unavailable)
++{
++ enum machine_mode mode = GET_MODE (*this_head->first->loc);
++ int nregs = hard_regno_nregs[new_reg][mode];
++ int i;
++ struct du_chain *tmp;
++
++ for (i = nregs - 1; i >= 0; --i)
++ if (TEST_HARD_REG_BIT (this_unavailable, new_reg + i)
++ || fixed_regs[new_reg + i]
++ || global_regs[new_reg + i]
++ /* Can't use regs which aren't saved by the prologue. */
++ || (! df_regs_ever_live_p (new_reg + i)
++ && ! call_used_regs[new_reg + i])
++#ifdef LEAF_REGISTERS
++ /* We can't use a non-leaf register if we're in a
++ leaf function. */
++ || (crtl->is_leaf
++ && !LEAF_REGISTERS[new_reg + i])
++#endif
++#ifdef HARD_REGNO_RENAME_OK
++ || ! HARD_REGNO_RENAME_OK (reg + i, new_reg + i)
++#endif
++ )
++ return false;
++
++ /* See whether it accepts all modes that occur in
++ definition and uses. */
++ for (tmp = this_head->first; tmp; tmp = tmp->next_use)
++ if ((! HARD_REGNO_MODE_OK (new_reg, GET_MODE (*tmp->loc))
++ && ! DEBUG_INSN_P (tmp->insn))
++ || (this_head->need_caller_save_reg
++ && ! (HARD_REGNO_CALL_PART_CLOBBERED
++ (reg, GET_MODE (*tmp->loc)))
++ && (HARD_REGNO_CALL_PART_CLOBBERED
++ (new_reg, GET_MODE (*tmp->loc)))))
++ return false;
++
++ return true;
++}
++
++static int
++nds32_find_best_rename_reg (du_head_p this_head, int new_reg, int old_reg)
++{
++ HARD_REG_SET unavailable;
++ int best_new_reg = old_reg;
++
++ COMPL_HARD_REG_SET (unavailable, reg_class_contents[GENERAL_REGS]);
++ CLEAR_HARD_REG_BIT (unavailable, this_head->regno);
++
++ /* Further narrow the set of registers we can use for renaming.
++ If the chain needs a call-saved register, mark the call-used
++ registers as unavailable. */
++ if (this_head->need_caller_save_reg)
++ IOR_HARD_REG_SET (unavailable, call_used_reg_set);
++
++ /* Mark registers that overlap this chain's lifetime as unavailable. */
++ nds32_merge_overlapping_regs (&unavailable, this_head);
++
++ if (nds32_check_new_reg_p (old_reg, new_reg, this_head, unavailable))
++ best_new_reg = new_reg;
++
++ return best_new_reg;
++}
++
++static bool
++nds32_try_rename_reg (rtx_insn *insn, unsigned op_pos, unsigned best_reg)
++{
++ insn_rr_info *info;
++ du_head_p op_chain;
++ unsigned oldreg, newreg;
++
++ info = &insn_rr[INSN_UID (insn)];
++
++ if (info->op_info == NULL)
++ return false;
++
++ if (info->op_info[op_pos].n_chains == 0)
++ return false;
++
++ op_chain = regrename_chain_from_id (info->op_info[op_pos].heads[0]->id);
++
++ if (op_chain->cannot_rename)
++ return false;
++
++ oldreg = op_chain->regno;
++ newreg = nds32_find_best_rename_reg (op_chain, best_reg, oldreg);
++
++ if (newreg == oldreg)
++ return false;
++
++ return true;
++}
++
++/* Grouping consecutive registers. */
++static void
++nds32_group_available_reg (HARD_REG_SET *available_regset, enum reg_class clazz,
++ std::vector *available_group)
++{
++ hard_reg_set_iterator hrsi;
++ unsigned regno, pre_regno = 0;
++ unsigned count = 0;
++ available_reg_info_t reg_info;
++ std::vector::iterator it;
++
++ if (!available_group->empty ())
++ available_group->clear ();
++
++ /* Find available register form $r16 to $r31. */
++ EXECUTE_IF_SET_IN_HARD_REG_SET (reg_class_contents[clazz], 2, regno, hrsi)
++ {
++ /* Caller-save register or callee-save register but it's ever live. */
++ if (TEST_HARD_REG_BIT (*available_regset, regno)
++ && (call_used_regs[regno] || df_regs_ever_live_p (regno)))
++ {
++ if (pre_regno == 0
++ || (pre_regno + 1) == regno)
++ count++;
++ }
++ else
++ {
++ if (count >= 2)
++ {
++ reg_info.amount = count;
++ reg_info.end = pre_regno;
++ reg_info.start = pre_regno - count + 1;
++ available_group->push_back (reg_info);
++ }
++ count = 0;
++ }
++ pre_regno = regno;
++ }
++
++ sort (available_group->begin(), available_group->end(), compare_amount);
++
++ if (dump_file)
++ {
++ for (it = available_group->begin();
++ it != available_group->end(); ++it)
++ fprintf (dump_file,
++ "available amount = %d start = %d "
++ "end = %d \n", it->amount, it->start,
++ it->end);
++ }
++}
++
++/* Try to rename insn's register in order. */
++static void
++nds32_find_reg (load_store_infos_t *insn, load_store_infos_t *rename_insn,
++ HARD_REG_SET *available_regset)
++{
++ int can_rename_number;
++ unsigned i, regno, amount;
++ unsigned op_pos = (*insn)[0].load_p ? 0 : 1;
++ auto_vec temp_set;
++ std::vector available_group;
++ std::vector::iterator it;
++ auto_vec down_set, up_set;
++ unsigned int down_num = 0, up_num = 0;
++ long offset;
++ int m;
++
++ /* We will change 'insn' element order,
++ to avoid change order using 'temp_set'. */
++ for (i = 0; i < insn->length (); i++)
++ temp_set.safe_push ((*insn)[i]);
++
++ if (temp_set[0].post_type == NDS32_NONE)
++ temp_set.qsort (compare_offset);
++
++ nds32_group_available_reg (available_regset, GENERAL_REGS, &available_group);
++
++ /* Check rename register form top insn to bottom insn,
++ and avoid using fp, sp, lp, gp registers. */
++ regno = REGNO (temp_set[0].reg);
++ can_rename_number = regno + temp_set.length () - 1;
++ offset = temp_set[0].offset;
++
++ if (can_rename_number < FP_REGNUM)
++ for (i = 1; i < temp_set.length (); ++i)
++ {
++ /* Find this case:
++ lwi $r0, [$r2 + 4]
++ lwi $r3, [$r2 + 8]
++
++ Rename $r3 to $r1. */
++ down_num++;
++ if ((regno + i) != REGNO (temp_set[i].reg))
++ {
++ if (nds32_try_rename_reg (temp_set[i].insn, op_pos, regno + i))
++ {
++ /* Store in temparary set. */
++ down_set.safe_push (temp_set[i]);
++ down_set.last ().new_reg = regno + i;
++ }
++ else
++ /* Stop when the register sequence is broken. */
++ break;
++ }
++ }
++
++ /* Check rename register form bottom insn to top insn,
++ and avoid using fp, sp, lp, gp registers. */
++ regno = REGNO (temp_set.last ().reg);
++ can_rename_number = regno - temp_set.length () + 1;
++
++ if (can_rename_number > 0 && regno < FP_REGNUM)
++ for (i = temp_set.length () - 1; i > 0; --i)
++ {
++ /* Find this case:
++ lwi $r1, [$r2 + 4]
++ lwi $r4, [$r2 + 8]
++
++ Rename $r1 to $r3. */
++ up_num++;
++ if ((regno - i) != REGNO (temp_set[i - 1].reg))
++ {
++ if (nds32_try_rename_reg (temp_set[i - 1].insn, op_pos, regno - i))
++ {
++ /* Store in rename_insn. */
++ up_set.safe_push (temp_set[i - 1]);
++ up_set.last ().new_reg = regno - i;
++ }
++ else
++ /* Stop when the register sequence is broken. */
++ break;
++ }
++ }
++
++ /* Rename for the longest sequence. */
++ /* The overhead of zero offset instruction is lowest, so try it first. */
++ if ((offset == 0 || down_num >= up_num) && !down_set.is_empty ())
++ {
++ for (m = down_set.length () - 1; m >= 0; --m)
++ {
++ regno = REGNO (down_set[m].reg);
++ CLEAR_HARD_REG_BIT (*available_regset, regno);
++ rename_insn->safe_push (down_set[m]);
++ }
++ nds32_group_available_reg (available_regset, GENERAL_REGS,
++ &available_group);
++ return;
++ }
++ else if (up_num >= down_num && !up_set.is_empty ())
++ {
++ for (m = up_set.length () - 1; m >= 0; --m)
++ {
++ regno = REGNO (up_set[m].reg);
++ CLEAR_HARD_REG_BIT (*available_regset, regno);
++ rename_insn->safe_push (up_set[m]);
++ }
++ nds32_group_available_reg (available_regset, GENERAL_REGS,
++ &available_group);
++ return;
++ }
++ /* Check whether it is empty, We will use available table. */
++ else if (available_group.empty ())
++ return;
++
++ amount = available_group.begin ()->amount;
++ /* Using the minimum number, as the rename amount. */
++ if (amount > temp_set.length ())
++ amount = temp_set.length ();
++
++ /* Using most available register number to rename. */
++ regno = available_group.begin ()->start;
++ for (i = 0; i < amount; ++i)
++ {
++ if (nds32_try_rename_reg (temp_set[i].insn, op_pos, regno))
++ {
++ rename_insn->safe_push (temp_set[i]);
++ rename_insn->last ().new_reg = regno;
++ CLEAR_HARD_REG_BIT (*available_regset, regno);
++ regno++;
++ }
++ else
++ /* Stop when the register sequence is broken. */
++ break;
++ }
++
++ /* Check length here because the whole sequence entries
++ have to be renamed. */
++ if (rename_insn->length () > 1)
++ {
++ /* Update available table. */
++ nds32_group_available_reg (available_regset, GENERAL_REGS,
++ &available_group);
++ return;
++ }
++
++ /* Using all available register to rename each insn. */
++ for (i = 0; i < (temp_set.length () - 1); i += 2)
++ {
++ for (it = available_group.begin();
++ it != available_group.end(); ++it)
++ {
++ bool change_p = false;
++ unsigned int j;
++ regno = it->start;
++
++ /* Once replaced two instructions. */
++ for (j = regno; j < (it->end + 1); j += 2)
++ {
++ if (nds32_try_rename_reg (temp_set[i].insn, op_pos, regno)
++ && nds32_try_rename_reg (temp_set[i + 1].insn,
++ op_pos, regno + 1))
++ {
++ rename_insn->safe_push (temp_set[i]);
++ rename_insn->last ().new_reg = regno;
++ CLEAR_HARD_REG_BIT (*available_regset, regno);
++
++ rename_insn->safe_push (temp_set[i + 1]);
++ rename_insn->last ().new_reg = regno + 1;
++ CLEAR_HARD_REG_BIT (*available_regset, regno + 1);
++ change_p = true;
++ break;
++ }
++ }
++
++ if (change_p)
++ {
++ nds32_group_available_reg (available_regset, GENERAL_REGS,
++ &available_group);
++ break;
++ }
++ }
++ }
++}
++
++static void
++nds32_rename_reg (rtx_insn *insn, unsigned op_pos, unsigned newreg)
++{
++ insn_rr_info *info;
++ du_head_p op_chain;
++
++ info = &insn_rr[INSN_UID (insn)];
++ op_chain = regrename_chain_from_id (info->op_info[op_pos].heads[0]->id);
++
++ if (dump_file)
++ {
++ fprintf (dump_file, "Try to rename operand %d to %d:\n",
++ op_pos, newreg);
++ print_rtl_single (dump_file, insn);
++ }
++
++ regrename_do_replace (op_chain, newreg);
++
++ if (dump_file)
++ {
++ print_rtl_single (dump_file, insn);
++ }
++}
++
++/* Combine mutilple load/store insn into a lmw/smw insn. */
++static void
++nds32_combine_bi_insn (load_store_infos_t *load_store_info)
++{
++ auto_vec candidate_set, bi_set;
++ unsigned int i, j, regno;
++
++ bool load_insn_p;
++ enum nds32_memory_post_type post_type;
++
++ for (i = 0; i < load_store_info->length (); ++i)
++ {
++ /* Recording instruction order of priority and initinal place. */
++ (*load_store_info)[i].order = i;
++ (*load_store_info)[i].place = false;
++ candidate_set.safe_push ((*load_store_info)[i]);
++ }
++
++ for (i = 0; i < candidate_set.length (); ++i)
++ {
++ load_insn_p = candidate_set[i].load_p;
++ post_type = candidate_set[i].post_type;
++ regno = REGNO (candidate_set[i].reg);
++
++ for (j = i + 1; j < candidate_set.length (); ++j)
++ {
++ if ((post_type == candidate_set[j].post_type)
++ && (load_insn_p == candidate_set[j].load_p)
++ && ((regno + 1) == REGNO (candidate_set[j].reg)))
++ {
++ bi_set.safe_push (candidate_set[i]);
++ bi_set.safe_push (candidate_set[j]);
++
++ if (nds32_combine_multiple_p (&bi_set, false)
++ && nds32_base_reg_safe_p (&bi_set)
++ && nds32_lmwsmw_insert_place (&bi_set) != NULL_RTX)
++ {
++ rtx place = nds32_lmwsmw_insert_place (&bi_set);
++ rtx base_reg = bi_set[0].base_reg;
++
++ nds32_emit_multiple_insn (&bi_set, base_reg, place, true);
++ delete_insn (bi_set[i].insn);
++ delete_insn (bi_set[j].insn);
++ candidate_set.ordered_remove (j);
++ bi_set.block_remove (0, bi_set.length ());
++ break;
++ }
++
++ bi_set.block_remove (0, bi_set.length ());
++ }
++ }
++ }
++}
++
++/* Combine mutilple load/store insn into a lmw/smw insn. */
++static void
++nds32_combine_load_store_insn (load_store_infos_t *load_store_info,
++ HARD_REG_SET *available_regset)
++{
++ auto_vec candidate_set, main_set, temp_set;
++ auto_vec first_set, second_set;
++ HOST_WIDE_INT current_offset, last_offset = 0, add_offset = 0;
++ unsigned int i, j, regno;
++ int group_num = 0, group_id;
++ bool load_insn_p;
++ bool new_base_p = false;
++ bool prev_bim_p = false;
++ bool inc_p = true, dec_p = true;
++ rtx new_base_reg = NULL_RTX;
++ rtx base_reg = (*load_store_info)[0].base_reg;
++ rtx place;
++ unsigned new_base_regnum;
++
++ /* Get available register to add offset for first instruction. */
++ new_base_regnum = find_available_reg (available_regset, GENERAL_REGS);
++ if (new_base_regnum != INVALID_REGNUM)
++ {
++ CLEAR_HARD_REG_BIT (*available_regset, new_base_regnum);
++ new_base_reg = gen_rtx_REG (Pmode, new_base_regnum);
++ /* Copy attribute form base register to new base register. */
++ ORIGINAL_REGNO (new_base_reg) =
++ ORIGINAL_REGNO ((*load_store_info)[0].base_reg);
++ REG_ATTRS (new_base_reg) = REG_ATTRS ((*load_store_info)[0].base_reg);
++ new_base_p = true;
++
++ if (dump_file)
++ fprintf (dump_file, "Have new base register: %d\n", new_base_regnum);
++ }
++
++ /* Recording instruction order of priority and initinal place. */
++ for (i = 0; i < load_store_info->length (); ++i)
++ {
++ (*load_store_info)[i].order = i;
++ (*load_store_info)[i].place = false;
++ }
++
++ /* Fetch first instruction information from 'load_store_info',
++ we will use first instruction as base, to search next instruction. */
++ candidate_set.safe_push ((*load_store_info)[0]);
++ /* Set offset, regno, load_p state from candidate_set. */
++ current_offset = candidate_set[0].offset;
++ regno = REGNO (candidate_set[0].reg);
++ load_insn_p = candidate_set[0].load_p;
++ /* Set first instruction group ID,
++ the group ID mark instruction for the same group. */
++ candidate_set[0].group = group_num;
++
++ /* Search instructions can be combined to a lmw/smw instruction. */
++ for (i = 1; i < load_store_info->length (); ++i)
++ {
++ /* Collecting register number and offset is increase,
++ for example:
++
++ lwi $r0, [$r22 + 4] <- base instruction
++ lwi $r1, [$r22 + 8] <- collect object
++
++ The collect object (regno + 1), (offset + 4)
++ from base instruction. */
++ if ((current_offset == (*load_store_info)[i].offset - 4)
++ && ((regno + 1) == REGNO ((*load_store_info)[i].reg))
++ && (load_insn_p == (*load_store_info)[i].load_p)
++ && inc_p)
++ {
++ /* Give instruction group ID. */
++ (*load_store_info)[i].group = group_num;
++ /* Save instruction. */
++ candidate_set.safe_push ((*load_store_info)[i]);
++ /* Update state, next register number and offset. */
++ regno = REGNO ((*load_store_info)[i].reg);
++ current_offset += 4;
++ /* Close decrease type, search increase type. */
++ dec_p = false;
++ }
++ /* Collecting register number and offset is decrease,
++ for example:
++
++ lwi $r2, [$r22 + 8] <- base instruction
++ lwi $r1, [$r22 + 4] <- collect object
++
++ The collect object (regno - 1), (offset - 4)
++ from base instruction. */
++ else if ((current_offset == (*load_store_info)[i].offset + 4)
++ && ((regno - 1) == REGNO ((*load_store_info)[i].reg))
++ && (load_insn_p == (*load_store_info)[i].load_p)
++ && dec_p)
++ {
++ /* Give instruction group ID. */
++ (*load_store_info)[i].group = group_num;
++ /* Save instruction. */
++ candidate_set.safe_push ((*load_store_info)[i]);
++
++ /* Update state, next register number and offset. */
++ regno = REGNO ((*load_store_info)[i].reg);
++ current_offset -= 4;
++ /* Close increase type, search decrease type. */
++ inc_p = false;
++ }
++ else
++ {
++ inc_p = true;
++ dec_p = true;
++ }
++
++ /* Instructions collect is complete. */
++ if ((inc_p && dec_p)
++ || (i + 1) == load_store_info->length ())
++ {
++ /* Filter candidate instructions. */
++ if (nds32_combine_multiple_p (&candidate_set, new_base_p)
++ && nds32_base_reg_safe_p (&candidate_set)
++ && nds32_lmwsmw_insert_place (&candidate_set) != NULL_RTX)
++ {
++ /* Store candidate instructions to 'main_set'. */
++ for (j = 0; j < candidate_set.length (); j++)
++ main_set.safe_push (candidate_set[j]);
++ }
++
++ /* Scan to the last instruction, it is complete. */
++ if ((i + 1) == load_store_info->length ())
++ break;
++
++ /* Clean candidate_set sequence. */
++ candidate_set.block_remove (0, candidate_set.length ());
++ /* Reinitialize first instruction infomation
++ to search next instruction. */
++ candidate_set.safe_push ((*load_store_info)[i]);
++ /* Update group number for next sequence. */
++ group_num ++;
++ /* Set offset, regno, load_p state from candidate_set. */
++ current_offset = candidate_set.last ().offset;
++ regno = REGNO (candidate_set.last ().reg);
++ load_insn_p = candidate_set.last ().load_p;
++ candidate_set.last ().group = group_num;
++ }
++ else if (!nds32_base_reg_safe_p (&candidate_set)
++ || nds32_lmwsmw_insert_place (&candidate_set) == NULL_RTX)
++ {
++ /* Check collect instruction for each instruction,
++ we store (n - 1) instructions in group, and
++ last instruction make next group First instruction. */
++ for (j = 0; j < (candidate_set.length () - 1); j++)
++ temp_set.safe_push (candidate_set[j]);
++
++ /* Store candidate instructions to 'main_set'. */
++ if (nds32_combine_multiple_p (&temp_set, new_base_p))
++ {
++ for (j = 0; j < (temp_set.length ()); j++)
++ main_set.safe_push (temp_set[j]);
++ }
++
++ /* Clean temp_set sequence. */
++ temp_set.block_remove (0, temp_set.length ());
++ /* Clean candidate_set sequence. */
++ candidate_set.block_remove (0, (candidate_set.length () - 1));
++ /* Update group number for next sequence. */
++ group_num ++;
++ /* Set offset, regno, load_p state from candidate_set. */
++ current_offset = candidate_set.last ().offset;
++ regno = REGNO (candidate_set.last ().reg);
++ load_insn_p = candidate_set.last ().load_p;
++ candidate_set.last ().group = group_num;
++ /* Reset it for search increase and decrease type. */
++ inc_p = true;
++ dec_p = true;
++ }
++ }
++
++ if (dump_file)
++ {
++ if (!main_set.is_empty ())
++ fprintf (dump_file,"Do lmwsmw instructions:\n");
++ for (i = 0; i < main_set.length (); ++i)
++ {
++ fprintf (dump_file,
++ "regno = %d base_regno = %d "
++ "offset = " HOST_WIDE_INT_PRINT_DEC " "
++ "load_p = %d UID = %u group = %d,"
++ " order = %d, place = %d\n",
++ REGNO (main_set[i].reg),
++ REGNO (main_set[i].base_reg),
++ main_set[i].offset,
++ main_set[i].load_p,
++ INSN_UID (main_set[i].insn),
++ main_set[i].group,
++ main_set[i].order,
++ main_set[i].place);
++ }
++ }
++
++ /* Fetch first group instruction from main_set. */
++ if (!main_set.is_empty ())
++ {
++ /* Sort main_set by offset. */
++ main_set.qsort (compare_offset);
++
++ group_id = main_set[0].group;
++ nds32_fetch_group_insn (&main_set, &first_set, group_id);
++ last_offset = first_set.last ().offset;
++ }
++
++ /* Main loop for emit lmw/smw instrucion. */
++ while (!main_set.is_empty ())
++ {
++ /* Get second group ID. */
++ group_id = main_set[0].group;
++ for (i = 0; i < main_set.length (); ++i)
++ {
++ /* Prefer get consecutive offset form
++ first group to second group */
++ if ((last_offset + 4) == main_set[i].offset)
++ {
++ group_id = main_set[i].group;
++ break;
++ }
++ }
++
++ /* Fetch second instrucion group. */
++ nds32_fetch_group_insn (&main_set, &second_set, group_id);
++ /* Get lmw/smw insert place. */
++ place = nds32_lmwsmw_insert_place (&first_set);
++
++ /* Adjust address offset, because lmw/smw instruction
++ only allow offset is zero.
++ example:
++ lwi $r0, [$r3 + 4]
++ lwi $r1, [$r3 + 8]
++ lwi $r2, [$r3 + 12]
++
++ combine into
++
++ addi $r3, $r3, 4
++ lwm.bi(m) $r0, [$r3], $r2
++
++ Need addi instrucion to handle offset. */
++ if (first_set[0].offset != 0 && !prev_bim_p)
++ {
++ if (dump_file)
++ fprintf (dump_file, "Use addi insn handle offset: "
++ "" HOST_WIDE_INT_PRINT_DEC "\n",
++ first_set[0].offset);
++ /* Use available register to process offset,
++ and don't recovey base register value. */
++ if (new_base_p)
++ {
++ base_reg = new_base_reg;
++ add_offset = 0;
++ CLEAR_HARD_REG_BIT (*available_regset, new_base_regnum);
++ }
++ else
++ add_offset = first_set[0].offset;
++
++ nds32_emit_add_insn (first_set[0], base_reg, place, true);
++ }
++
++ if (nds32_use_bim_p (&first_set, &second_set))
++ {
++ if (dump_file)
++ fprintf (dump_file, "Generate BIM form.\n");
++
++ nds32_emit_multiple_insn (&first_set, base_reg, place, true);
++
++ /* Update status, for next instruction sequence.
++ The add_offset need add 4, because the instruction
++ is post increase. */
++ add_offset = first_set.last ().offset + 4;
++ prev_bim_p = true;
++ }
++ else
++ {
++ if (dump_file)
++ fprintf (dump_file, "Generate BI form.\n");
++
++ nds32_emit_multiple_insn (&first_set, base_reg, place, false);
++
++ if (add_offset != 0)
++ {
++ if (dump_file)
++ fprintf (dump_file, "Use addi insn handle -offset: "
++ "" HOST_WIDE_INT_PRINT_DEC "\n",
++ add_offset);
++
++ nds32_emit_add_insn (first_set[0], base_reg, place, false);
++ add_offset = 0;
++ }
++ prev_bim_p = false;
++
++ /* Recovey base register for next instruction sequence. */
++ if (REGNO (base_reg) != REGNO (first_set[0].base_reg))
++ base_reg = first_set[0].base_reg;
++ }
++
++ /* Delete insn, replace by lmw/smw instruction. */
++ for (i = 0; i < first_set.length (); ++i)
++ delete_insn (first_set[i].insn);
++
++ /* Clean first_set for store next instruction group. */
++ first_set.block_remove (0, first_set.length ());
++ /* Store next instruction group. */
++ for (i = 0; i < second_set.length (); ++i)
++ first_set.safe_insert (i, second_set[i]);
++
++ /* Clean second_set. */
++ second_set.block_remove (0, second_set.length ());
++
++ /* Update last_offset for search next group. */
++ last_offset = first_set.last ().offset;
++ }
++
++ /* Processing the last instruction group. */
++ if (!first_set.is_empty ())
++ {
++ /* Get lmw/smw insert place. */
++ place = nds32_lmwsmw_insert_place (&first_set);
++
++ if (first_set[0].offset != 0 && !prev_bim_p)
++ {
++ if (dump_file)
++ fprintf (dump_file, "Use addi insn handle offset: "
++ "" HOST_WIDE_INT_PRINT_DEC "\n",
++ first_set[0].offset);
++
++ if (new_base_p)
++ {
++ base_reg = new_base_reg;
++ add_offset = 0;
++ }
++ else
++ add_offset = first_set[0].offset;
++
++ nds32_emit_add_insn (first_set[0], base_reg, place, true);
++ }
++
++ if (dump_file)
++ fprintf (dump_file, "Generate BI form.\n");
++
++ nds32_emit_multiple_insn (&first_set, base_reg, place, false);
++
++ if (add_offset != 0)
++ {
++ if (dump_file)
++ fprintf (dump_file, "Use addi insn handle -offset: "
++ "" HOST_WIDE_INT_PRINT_DEC "\n",
++ -add_offset);
++
++ nds32_emit_add_insn (first_set[0], base_reg, place, false);
++ }
++
++ /* Delete insn, replace by lmw/smw instruction. */
++ for (i = 0; i < first_set.length (); ++i)
++ delete_insn (first_set[i].insn);
++ }
++}
++
++/* Combine mutilple load/store insn into a lmw/smw insn. */
++static void
++nds32_rename_bi_insn (load_store_infos_t *load_store_info,
++ HARD_REG_SET *available_regset)
++{
++ auto_vec candidate_set, bi_set, replace_set;
++ unsigned int i, j;
++
++ bool load_insn_p;
++ enum nds32_memory_post_type post_type;
++
++ for (i = 0; i < load_store_info->length (); ++i)
++ {
++ /* Recording instruction order of priority and initinal place. */
++ (*load_store_info)[i].order = i;
++ (*load_store_info)[i].place = false;
++ candidate_set.safe_push ((*load_store_info)[i]);
++ }
++
++ for (i = 0; i < candidate_set.length (); ++i)
++ {
++ load_insn_p = candidate_set[i].load_p;
++ post_type = candidate_set[i].post_type;
++
++ for (j = i + 1; j < candidate_set.length (); ++j)
++ {
++ if ((post_type == candidate_set[j].post_type)
++ && (load_insn_p == candidate_set[j].load_p))
++ {
++ bi_set.safe_push (candidate_set[i]);
++ bi_set.safe_push (candidate_set[j]);
++
++ if (nds32_combine_multiple_p (&bi_set, false)
++ && nds32_base_reg_safe_p (&bi_set)
++ && nds32_lmwsmw_insert_place (&bi_set) != NULL_RTX)
++ {
++ nds32_find_reg (&bi_set, &replace_set, available_regset);
++
++ if (!replace_set.is_empty ())
++ {
++ unsigned k;
++ unsigned op_pos = replace_set[0].load_p ? 0 : 1;
++
++ /* Do rename register. */
++ for (k = 0; k < replace_set.length (); ++k)
++ nds32_rename_reg (replace_set[k].insn, op_pos,
++ replace_set[k].new_reg);
++
++ replace_set.block_remove (0, replace_set.length ());
++ }
++
++ candidate_set.ordered_remove (j);
++ bi_set.block_remove (0, bi_set.length ());
++ break;
++ }
++
++ bi_set.block_remove (0, bi_set.length ());
++ }
++ }
++ }
++}
++
++/* Rename register, can be combined mutilple load/store insn. */
++static void
++nds32_rename_load_store_reg (load_store_infos_t *load_store_info,
++ HARD_REG_SET *available_regset)
++{
++ auto_vec rename_set, temp_set, replace_set;
++ HOST_WIDE_INT current_offset;
++ unsigned int i, j;
++ bool load_insn_p;
++ bool inc_p = true, dec_p = true;
++
++ /* Recording instruction order of priority and initinal place. */
++ for (i = 0; i < load_store_info->length (); ++i)
++ {
++ (*load_store_info)[i].order = i;
++ (*load_store_info)[i].place = false;
++ }
++
++ /* Fetch first instruction information from 'load_store_info',
++ we will use first instruction as base, to search next instruction. */
++ rename_set.safe_push ((*load_store_info)[0]);
++ /* Set offset, load_p state from rename_set. */
++ current_offset = rename_set[0].offset;
++ load_insn_p = rename_set[0].load_p;
++
++ /* Search instructions can be combined to a lmw/smw instruction. */
++ for (i = 1; i < load_store_info->length (); ++i)
++ {
++ /* Collecting offset is increase, for example:
++
++ lwi pseudo_reg, [$r22 + 4] <- base instruction
++ lwi pseudo_reg, [$r22 + 8] <- collect object
++
++ The collect object (offset + 4) from base instruction. */
++ if ((current_offset == (*load_store_info)[i].offset - 4)
++ && (load_insn_p == (*load_store_info)[i].load_p)
++ && inc_p)
++ {
++ /* Save instruction. */
++ rename_set.safe_push ((*load_store_info)[i]);
++ /* Update offset. */
++ current_offset += 4;
++ /* Close decrease type, search increase type. */
++ dec_p = false;
++ }
++ /* Collecting offset is decrease, for example:
++
++ lwi pseudo_reg, [$r22 + 8] <- base instruction
++ lwi pseudo_reg, [$r22 + 4] <- collect object
++
++ The collect object (offset - 4) from base instruction. */
++ else if ((current_offset == (*load_store_info)[i].offset + 4)
++ && (load_insn_p == (*load_store_info)[i].load_p)
++ && dec_p)
++ {
++ /* Save instruction. */
++ rename_set.safe_push ((*load_store_info)[i]);
++
++ /* Update offset. */
++ current_offset -= 4;
++ /* Close increase type, search decrease type. */
++ inc_p = false;
++ }
++ else
++ {
++ inc_p = true;
++ dec_p = true;
++ }
++
++ /* Instructions collect is completed. */
++ if ((inc_p && dec_p)
++ || (i + 1) == load_store_info->length ())
++ {
++ /* Check whether the rename register. */
++ if (nds32_combine_multiple_p (&rename_set, false)
++ && nds32_base_reg_safe_p (&rename_set)
++ && nds32_lmwsmw_insert_place (&rename_set) != NULL_RTX)
++ {
++ /* Find can rename instruction, and store in 'replace_set'. */
++ nds32_find_reg (&rename_set, &replace_set, available_regset);
++
++ if (!replace_set.is_empty ())
++ {
++ unsigned op_pos = replace_set[0].load_p ? 0 : 1;
++
++ /* Do rename register. */
++ for (j = 0; j < replace_set.length (); ++j)
++ nds32_rename_reg (replace_set[j].insn, op_pos,
++ replace_set[j].new_reg);
++
++ replace_set.block_remove (0, replace_set.length ());
++ }
++ }
++
++ /* Scan to the last instruction, it is complete. */
++ if ((i + 1) == load_store_info->length ())
++ break;
++
++ /* Clean rename_set sequence. */
++ rename_set.block_remove (0, rename_set.length ());
++ /* Reinitialize first instruction infomation
++ to search next instruction. */
++ rename_set.safe_push ((*load_store_info)[i]);
++ /* Set offset, load_p state from rename_set. */
++ current_offset = rename_set.last ().offset;
++ load_insn_p = rename_set.last ().load_p;
++ }
++ else if (!nds32_base_reg_safe_p (&rename_set)
++ || nds32_lmwsmw_insert_place (&rename_set) == NULL_RTX)
++ {
++ /* Check collect instruction for each instruction,
++ we store (n - 1) instructions in group, and
++ last instruction as the first instruction of the next group. */
++ for (j = 0; j < (rename_set.length () - 1); j++)
++ temp_set.safe_push (rename_set[j]);
++
++ if (nds32_combine_multiple_p (&temp_set, false))
++ {
++ /* Find can rename instruction, and store in 'replace_set'. */
++ nds32_find_reg (&temp_set, &replace_set, available_regset);
++
++ if (!replace_set.is_empty ())
++ {
++ unsigned op_pos = replace_set[0].load_p ? 0 : 1;
++
++ /* Do rename register. */
++ for (j = 0; j < replace_set.length (); ++j)
++ nds32_rename_reg (replace_set[j].insn, op_pos,
++ replace_set[j].new_reg);
++
++ replace_set.block_remove (0, replace_set.length ());
++ }
++ }
++
++ /* Clean temp_set sequence. */
++ temp_set.block_remove (0, temp_set.length ());
++ /* Clean rename_set sequence. */
++ rename_set.block_remove (0, (rename_set.length () - 1));
++ /* Set offset, regno, load_p state from rename_set. */
++ current_offset = rename_set.last ().offset;
++ load_insn_p = rename_set.last ().load_p;
++ /* Reset it for search increase and decrease type. */
++ inc_p = true;
++ dec_p = true;
++ }
++ }
++}
++
++static void
++nds32_do_lmwsmw_opt (basic_block bb, bool rename_p)
++{
++ rtx_insn *insn;
++ HARD_REG_SET available_regset;
++ load_store_info_t load_store_info;
++ auto_vec load_store_infos[NDS32_GPR_NUM];
++ auto_vec plus_infos[NDS32_GPR_NUM];
++ auto_vec post_infos[NDS32_GPR_NUM];
++ int i;
++ unsigned j;
++ unsigned regno;
++ unsigned polluting;
++ df_ref def;
++ /* Dirty mean a register is define again after
++ first load/store instruction.
++ For example:
++
++ lwi $r2, [$r3 + #0x100]
++ mov $r3, $r4 ! $r3 is dirty after this instruction.
++ lwi $r1, [$r3 + #0x120] ! so this load can't chain with prev load.
++ */
++ bool dirty[NDS32_GPR_NUM];
++
++ if (dump_file)
++ fprintf (dump_file, "scan bb %d\n", bb->index);
++
++ for (i = 0; i < NDS32_GPR_NUM; ++i)
++ dirty[i] = false;
++
++ FOR_BB_INSNS (bb, insn)
++ {
++ if (!INSN_P (insn))
++ continue;
++
++ polluting = INVALID_REGNUM;
++
++ /* Set def reg is dirty if chain is not empty. */
++ FOR_EACH_INSN_USE (def, insn)
++ {
++ regno = DF_REF_REGNO (def);
++
++ if (!NDS32_IS_GPR_REGNUM (regno))
++ continue;
++
++ if (!load_store_infos[regno].is_empty ())
++ {
++ /* Set pulluting here because the source register
++ may be the same one. */
++ if (dirty[regno] == false)
++ polluting = regno;
++
++ dirty[regno] = true;
++ }
++ }
++
++ /* Set all caller-save register is dirty if chain is not empty. */
++ if (CALL_P (insn))
++ {
++ for (i = 0; i < NDS32_GPR_NUM; ++i)
++ {
++ if (call_used_regs[i] && !load_store_infos[i].is_empty ())
++ dirty[i] = true;
++ }
++ }
++
++ if (nds32_load_store_reg_plus_offset (insn, &load_store_info))
++ {
++ regno = REGNO (load_store_info.base_reg);
++ gcc_assert (NDS32_IS_GPR_REGNUM (regno));
++
++ /* Don't add to chain if this reg is dirty. */
++ if (dirty[regno] && polluting != regno)
++ break;
++
++ /* If the register is first time to be used and be polluted
++ right away, we don't push it. */
++ if (regno == REGNO (load_store_info.reg) && load_store_info.load_p
++ && dirty[regno] == false)
++ continue;
++
++ load_store_infos[regno].safe_push (load_store_info);
++ }
++ }
++
++ for (i = 0; i < NDS32_GPR_NUM; ++i)
++ {
++ for (j = 0; j < load_store_infos[i].length (); ++j)
++ {
++ if (load_store_infos[i][j].post_type == NDS32_NONE)
++ plus_infos[i].safe_push (load_store_infos[i][j]);
++ else
++ post_infos[i].safe_push (load_store_infos[i][j]);
++ }
++ }
++
++ for (i = 0; i < NDS32_GPR_NUM; ++i)
++ {
++ if (load_store_infos[i].length () <= 1)
++ {
++ if (dump_file && load_store_infos[i].length () == 1)
++ fprintf (dump_file,
++ "Skip Chain for $r%d since chain size only 1\n",
++ i);
++ continue;
++ }
++
++ if (dump_file)
++ {
++ fprintf (dump_file,
++ "Chain for $r%d: (size = %u)\n",
++ i, load_store_infos[i].length ());
++
++ for (j = 0; j < load_store_infos[i].length (); ++j)
++ {
++ fprintf (dump_file,
++ "regno = %d base_regno = %d "
++ "offset = " HOST_WIDE_INT_PRINT_DEC " "
++ "load_p = %d UID = %u place = %d\n",
++ REGNO (load_store_infos[i][j].reg),
++ REGNO (load_store_infos[i][j].base_reg),
++ load_store_infos[i][j].offset,
++ load_store_infos[i][j].load_p,
++ INSN_UID (load_store_infos[i][j].insn),
++ load_store_infos[i][j].place);
++ }
++ }
++
++ nds32_get_available_reg_set (bb,
++ load_store_infos[i][0].insn,
++ load_store_infos[i].last ().insn,
++ &available_regset);
++ if (dump_file)
++ print_hard_reg_set (dump_file, "", available_regset);
++
++ /* If rename_p is true, then do rename register of load/store
++ instruction. Otherwise combination of a multiple load/sotre
++ a multiple load/store instruction. */
++ if (rename_p)
++ {
++ if (plus_infos[i].length () > 1)
++ nds32_rename_load_store_reg (&plus_infos[i], &available_regset);
++ if (post_infos[i].length () > 1)
++ nds32_rename_bi_insn (&post_infos[i], &available_regset);
++ }
++ else
++ {
++ if (plus_infos[i].length () > 1)
++ nds32_combine_load_store_insn (&plus_infos[i], &available_regset);
++ if (post_infos[i].length () > 1)
++ nds32_combine_bi_insn (&post_infos[i]);
++ }
++ }
++}
++
++static void
++nds32_lmwsmw_opt (bool rename_p)
++{
++ basic_block bb;
++
++ FOR_EACH_BB_FN (bb, cfun)
++ nds32_do_lmwsmw_opt (bb, rename_p);
++}
++
++/* Implement rename register for load and store instruction. */
++static unsigned int
++rest_of_handle_rename_lmwsmw_opt (void)
++{
++ init_alias_analysis ();
++
++ df_set_flags (DF_LR_RUN_DCE);
++ df_note_add_problem ();
++ df_analyze ();
++ df_set_flags (DF_DEFER_INSN_RESCAN);
++
++ regrename_init (true);
++ regrename_analyze (NULL);
++
++ nds32_lmwsmw_opt (true);
++
++ regrename_finish ();
++
++ /* We are finished with alias. */
++ end_alias_analysis ();
++ return 1;
++}
++
++/* Implement generate lmw and smw instruction. */
++static unsigned int
++rest_of_handle_gen_lmwsmw_opt (void)
++{
++ init_alias_analysis ();
++
++ df_note_add_problem ();
++ df_analyze ();
++ nds32_lmwsmw_opt (false);
++
++ /* We are finished with alias. */
++ end_alias_analysis ();
++ return 1;
++}
++
++
++const pass_data pass_data_nds32_rename_lmwsmw_opt =
++{
++ RTL_PASS, /* type */
++ "rename_lmwsmw_opt", /* name */
++ OPTGROUP_NONE, /* optinfo_flags */
++ TV_MACH_DEP, /* tv_id */
++ 0, /* properties_required */
++ 0, /* properties_provided */
++ 0, /* properties_destroyed */
++ 0, /* todo_flags_start */
++ TODO_df_finish, /* todo_flags_finish */
++};
++
++class pass_nds32_rename_lmwsmw_opt : public rtl_opt_pass
++{
++public:
++ pass_nds32_rename_lmwsmw_opt (gcc::context *ctxt)
++ : rtl_opt_pass (pass_data_nds32_rename_lmwsmw_opt, ctxt)
++ {}
++
++ /* opt_pass methods: */
++ bool gate (function *) { return flag_nds32_lmwsmw_opt; }
++ unsigned int execute (function *) { return rest_of_handle_rename_lmwsmw_opt (); }
++};
++
++rtl_opt_pass *
++make_pass_nds32_rename_lmwsmw_opt (gcc::context *ctxt)
++{
++ return new pass_nds32_rename_lmwsmw_opt (ctxt);
++}
++
++const pass_data pass_data_nds32_gen_lmwsmw_opt =
++{
++ RTL_PASS, /* type */
++ "gen_lmwsmw_opt", /* name */
++ OPTGROUP_NONE, /* optinfo_flags */
++ TV_MACH_DEP, /* tv_id */
++ 0, /* properties_required */
++ 0, /* properties_provided */
++ 0, /* properties_destroyed */
++ 0, /* todo_flags_start */
++ TODO_df_finish, /* todo_flags_finish */
++};
++
++class pass_nds32_gen_lmwsmw_opt : public rtl_opt_pass
++{
++public:
++ pass_nds32_gen_lmwsmw_opt (gcc::context *ctxt)
++ : rtl_opt_pass (pass_data_nds32_gen_lmwsmw_opt, ctxt)
++ {}
++
++ /* opt_pass methods: */
++ bool gate (function *) { return flag_nds32_lmwsmw_opt; }
++ unsigned int execute (function *) { return rest_of_handle_gen_lmwsmw_opt (); }
++};
++
++rtl_opt_pass *
++make_pass_nds32_gen_lmwsmw_opt (gcc::context *ctxt)
++{
++ return new pass_nds32_gen_lmwsmw_opt (ctxt);
++}
+diff --git a/gcc/config/nds32/nds32-load-store-opt.c b/gcc/config/nds32/nds32-load-store-opt.c
+new file mode 100644
+index 0000000..9e5161e
+--- /dev/null
++++ b/gcc/config/nds32/nds32-load-store-opt.c
+@@ -0,0 +1,721 @@
++/* load-store-opt pass of Andes NDS32 cpu for GNU compiler
++ Copyright (C) 2012-2016 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
++ . */
++
++
++#include "config.h"
++#include "system.h"
++#include "coretypes.h"
++#include "backend.h"
++#include "tree.h"
++#include "rtl.h"
++#include "df.h"
++#include "alias.h"
++#include "stor-layout.h"
++#include "varasm.h"
++#include "calls.h"
++#include "regs.h"
++#include "insn-config.h" /* Required by recog.h. */
++#include "conditions.h"
++#include "output.h"
++#include "insn-attr.h" /* For DFA state_t. */
++#include "insn-codes.h" /* For CODE_FOR_xxx. */
++#include "reload.h" /* For push_reload(). */
++#include "flags.h"
++#include "insn-config.h"
++#include "expmed.h"
++#include "dojump.h"
++#include "explow.h"
++#include "emit-rtl.h"
++#include "stmt.h"
++#include "expr.h"
++#include "recog.h"
++#include "diagnostic-core.h"
++#include "cfgrtl.h"
++#include "cfganal.h"
++#include "lcm.h"
++#include "cfgbuild.h"
++#include "cfgcleanup.h"
++#include "tm_p.h"
++#include "tm-constrs.h"
++#include "optabs.h" /* For GEN_FCN. */
++#include "target.h"
++#include "langhooks.h" /* For add_builtin_function(). */
++#include "builtins.h"
++#include "cpplib.h"
++#include "params.h"
++#include "tree-pass.h"
++#include "target-globals.h"
++#include "nds32-load-store-opt.h"
++#include "nds32-reg-utils.h"
++#include
++
++#define NDS32_GPR_NUM 32
++
++static new_base_reg_info_t gen_new_base (rtx,
++ offset_info_t,
++ unsigned,
++ HOST_WIDE_INT,
++ HOST_WIDE_INT);
++
++static const load_store_optimize_pass *load_store_optimizes[] =
++{
++ /* allow_regclass, new_base_regclass,
++ offset_lower_bound, offset_upper_bound,
++ load_only_p, name */
++ new load_store_optimize_pass (
++ LOW_REGS, LOW_REGS,
++ 0, (32-4),
++ false, "lswi333"),
++ new load_store_optimize_pass (
++ LOW_REGS, FRAME_POINTER_REG,
++ 0, (512-4),
++ false, "lswi37"),
++ new load_store_optimize_pass (
++ MIDDLE_REGS, GENERAL_REGS,
++ 0, 0,
++ false, "lswi450"),
++ new load_store_optimize_pass (
++ MIDDLE_REGS, R8_REG,
++ -128, -4,
++ true, "lwi45fe")
++};
++
++static const int N_LOAD_STORE_OPT_TYPE = sizeof (load_store_optimizes)
++ / sizeof (load_store_optimize_pass*);
++
++load_store_optimize_pass
++::load_store_optimize_pass (enum reg_class allow_regclass,
++ enum reg_class new_base_regclass,
++ HOST_WIDE_INT offset_lower_bound,
++ HOST_WIDE_INT offset_upper_bound,
++ bool load_only_p,
++ const char *name)
++ : m_allow_regclass (allow_regclass),
++ m_new_base_regclass (new_base_regclass),
++ m_offset_lower_bound (offset_lower_bound),
++ m_offset_upper_bound (offset_upper_bound),
++ m_load_only_p (load_only_p),
++ m_name (name)
++{
++ gcc_assert (offset_lower_bound <= offset_upper_bound);
++}
++
++int
++load_store_optimize_pass::calc_gain (HARD_REG_SET *available_regset,
++ offset_info_t offset_info,
++ load_store_infos_t *load_store_info) const
++{
++ int extra_cost = 0;
++ int gain = 0;
++ unsigned i;
++ unsigned chain_size;
++ unsigned new_base_regnum;
++ HOST_WIDE_INT allow_range = m_offset_upper_bound - m_offset_lower_bound;
++ new_base_regnum = find_available_reg (available_regset, m_new_base_regclass);
++ chain_size = load_store_info->length ();
++
++ if (new_base_regnum == INVALID_REGNUM)
++ {
++ if (dump_file)
++ fprintf (dump_file,
++ "%s have no avariable register, so give up try %s\n",
++ reg_class_names[m_new_base_regclass],
++ m_name);
++ return 0;
++ }
++ else if (dump_file)
++ fprintf (dump_file,
++ "%s is avariable, get %s, try %s, chain size = %u\n",
++ reg_class_names[m_new_base_regclass],
++ reg_names[new_base_regnum],
++ m_name,
++ chain_size);
++
++ HOST_WIDE_INT range = offset_info.max_offset - offset_info.min_offset;
++
++ if (range > allow_range)
++ {
++ /* TODO: We can perform load-store opt for only part of load store. */
++ if (dump_file)
++ fprintf (dump_file,
++ "range is too large for %s"
++ " (range = " HOST_WIDE_INT_PRINT_DEC ", "
++ "allow_range = " HOST_WIDE_INT_PRINT_DEC ")\n",
++ m_name, range, allow_range);
++ return 0;
++ }
++
++ if (offset_info.min_offset >= m_offset_lower_bound
++ && offset_info.max_offset <= m_offset_upper_bound)
++ {
++ /* mov55. */
++ extra_cost = 2;
++ }
++ else
++ {
++ if (satisfies_constraint_Is15 (GEN_INT (offset_info.min_offset
++ - m_offset_lower_bound)))
++ {
++ /* add. */
++ extra_cost = 4;
++ }
++ else
++ {
++ /* TODO: Try m_offset_upper_bound instead of m_offset_lower_bound
++ again. */
++ /* add45 + movi. */
++ if (satisfies_constraint_Is20 (GEN_INT (offset_info.min_offset
++ - m_offset_lower_bound)))
++ extra_cost = 6;
++ else
++ return -1; /* Give up if this constant is too large. */
++ }
++ }
++
++ for (i = 0; i < chain_size; ++i)
++ {
++ if (m_load_only_p && !(*load_store_info)[i].load_p)
++ continue;
++
++ if (in_reg_class_p ((*load_store_info)[i].reg, m_allow_regclass))
++ gain += 2;
++ }
++
++ if (dump_file)
++ fprintf (dump_file,
++ "%s: gain = %d extra_cost = %d\n",
++ m_name, gain, extra_cost);
++
++ return gain - extra_cost;
++}
++
++
++void
++load_store_optimize_pass::do_optimize (
++ HARD_REG_SET *available_regset,
++ offset_info_t offset_info,
++ load_store_infos_t *load_store_info) const
++{
++ new_base_reg_info_t new_base_reg_info;
++ rtx load_store_insn;
++ unsigned new_base_regnum;
++
++ new_base_regnum = find_available_reg (available_regset, m_new_base_regclass);
++ gcc_assert (new_base_regnum != INVALID_REGNUM);
++
++ new_base_reg_info =
++ gen_new_base ((*load_store_info)[0].base_reg,
++ offset_info,
++ new_base_regnum,
++ m_offset_lower_bound, m_offset_upper_bound);
++ unsigned i;
++ rtx insn;
++ insn = emit_insn_before (new_base_reg_info.set_insns[0],
++ (*load_store_info)[0].insn);
++ if (new_base_reg_info.n_set_insns > 1)
++ {
++ gcc_assert (new_base_reg_info.n_set_insns == 2);
++ emit_insn_before (new_base_reg_info.set_insns[1], insn);
++ }
++
++ for (i = 0; i < load_store_info->length (); ++i)
++ {
++ if (m_load_only_p && !(*load_store_info)[i].load_p)
++ continue;
++
++ if (!in_reg_class_p ((*load_store_info)[i].reg, m_allow_regclass))
++ continue;
++
++ HOST_WIDE_INT offset = (*load_store_info)[i].offset;
++
++ if (new_base_reg_info.need_adjust_offset_p)
++ offset = offset + new_base_reg_info.adjust_offset;
++
++ load_store_insn =
++ gen_reg_plus_imm_load_store ((*load_store_info)[i].reg,
++ new_base_reg_info.reg,
++ offset,
++ (*load_store_info)[i].load_p,
++ (*load_store_info)[i].mem);
++
++ emit_insn_before (load_store_insn, (*load_store_info)[i].insn);
++
++ delete_insn ((*load_store_info)[i].insn);
++ }
++
++ /* Recompute it CFG, to update BB_END() instruction. */
++ compute_bb_for_insn ();
++}
++
++static new_base_reg_info_t
++gen_new_base (rtx original_base_reg,
++ offset_info_t offset_info,
++ unsigned new_base_regno,
++ HOST_WIDE_INT offset_lower,
++ HOST_WIDE_INT offset_upper)
++{
++ new_base_reg_info_t new_base_reg_info;
++
++ /* Use gen_raw_REG instead of gen_rtx_REG to prevent break the reg
++ info for global one.
++ For example, gen_rtx_REG will return frame_pointer_rtx immediate
++ instead of create new rtx for gen_raw_REG (Pmode, FP_REGNUM). */
++ new_base_reg_info.reg = gen_raw_REG (Pmode, new_base_regno);
++
++ /* Setup register info. */
++ ORIGINAL_REGNO (new_base_reg_info.reg) = ORIGINAL_REGNO (original_base_reg);
++ REG_ATTRS (new_base_reg_info.reg) = REG_ATTRS (original_base_reg);
++
++ if (offset_info.max_offset <= offset_upper
++ && offset_info.min_offset >= offset_lower)
++ {
++ new_base_reg_info.set_insns[0] = gen_movsi (new_base_reg_info.reg,
++ original_base_reg);
++ new_base_reg_info.n_set_insns = 1;
++ new_base_reg_info.need_adjust_offset_p = false;
++ new_base_reg_info.adjust_offset = 0;
++ }
++ else
++ {
++ /* For example:
++ lwi45.fe allow -4 ~ -128 range:
++ offset_lower = #-4
++ offset_upper = #-128
++
++ lwi $r2, [$r12 + #10]
++ ->
++ addi $r8, $r12, #14 ! $r8 = $r12 + #10 - offset_lower
++ ! = $r12 + #10 - #-4
++ ! = $r12 + #14
++ lwi45.fe $r2, [$r8 - #4] ! [$r8 - #4]
++ ! = [$r12 + #14 - #4]
++ ! = [$r12 + #10]
++ */
++ new_base_reg_info.adjust_offset =
++ -(offset_info.min_offset - offset_lower);
++
++ rtx offset = GEN_INT (-new_base_reg_info.adjust_offset);
++
++
++ if (satisfies_constraint_Is15 (offset))
++ {
++ new_base_reg_info.set_insns[0] =
++ gen_addsi3(new_base_reg_info.reg,
++ original_base_reg,
++ offset);
++
++ new_base_reg_info.n_set_insns = 1;
++ }
++ else
++ {
++ if (!satisfies_constraint_Is20 (offset))
++ gcc_unreachable ();
++
++ new_base_reg_info.set_insns[1] =
++ gen_rtx_SET (new_base_reg_info.reg,
++ GEN_INT (-new_base_reg_info.adjust_offset));
++
++ new_base_reg_info.set_insns[0] =
++ gen_addsi3 (new_base_reg_info.reg,
++ new_base_reg_info.reg,
++ original_base_reg);
++
++ new_base_reg_info.n_set_insns = 2;
++ }
++
++ new_base_reg_info.need_adjust_offset_p = true;
++ }
++
++ return new_base_reg_info;
++}
++
++static bool
++nds32_4byte_load_store_reg_plus_offset (
++ rtx_insn *insn,
++ load_store_info_t *load_store_info)
++{
++ if (!INSN_P (insn))
++ return false;
++
++ rtx pattern = PATTERN (insn);
++ rtx mem = NULL_RTX;
++ rtx reg = NULL_RTX;
++ rtx base_reg = NULL_RTX;
++ rtx addr;
++ HOST_WIDE_INT offset = 0;
++ bool load_p = false;
++
++ if (GET_CODE (pattern) != SET)
++ return false;
++
++ if (MEM_P (SET_SRC (pattern)))
++ {
++ mem = SET_SRC (pattern);
++ reg = SET_DEST (pattern);
++ load_p = true;
++ }
++
++ if (MEM_P (SET_DEST (pattern)))
++ {
++ mem = SET_DEST (pattern);
++ reg = SET_SRC (pattern);
++ load_p = false;
++ }
++
++ if (mem == NULL_RTX || reg == NULL_RTX || !REG_P (reg))
++ return false;
++
++ gcc_assert (REG_P (reg));
++
++ addr = XEXP (mem, 0);
++
++ /* We only care about [reg] and [reg+const]. */
++ if (REG_P (addr))
++ {
++ base_reg = addr;
++ offset = 0;
++ }
++ else if (GET_CODE (addr) == PLUS
++ && CONST_INT_P (XEXP (addr, 1)))
++ {
++ base_reg = XEXP (addr, 0);
++ offset = INTVAL (XEXP (addr, 1));
++ if (!REG_P (base_reg))
++ return false;
++ }
++ else
++ return false;
++
++ /* At least need MIDDLE_REGS. */
++ if (!in_reg_class_p (reg, MIDDLE_REGS))
++ return false;
++
++ /* lwi450/swi450 */
++ if (offset == 0)
++ return false;
++
++ if (in_reg_class_p (reg, LOW_REGS))
++ {
++ /* lwi37.sp/swi37.sp/lwi37/swi37 */
++ if ((REGNO (base_reg) == SP_REGNUM
++ || REGNO (base_reg) == FP_REGNUM)
++ && (offset >= 0 && offset < 512 && (offset % 4 == 0)))
++ return false;
++
++ /* lwi333/swi333 */
++ if (in_reg_class_p (base_reg, LOW_REGS)
++ && (offset >= 0 && offset < 32 && (offset % 4 == 0)))
++ return false;
++ }
++
++ if (load_store_info)
++ {
++ load_store_info->load_p = load_p;
++ load_store_info->offset = offset;
++ load_store_info->reg = reg;
++ load_store_info->base_reg = base_reg;
++ load_store_info->insn = insn;
++ load_store_info->mem = mem;
++ }
++
++ if (GET_MODE (reg) != SImode)
++ return false;
++
++ return true;
++}
++
++static bool
++nds32_4byte_load_store_reg_plus_offset_p (rtx_insn *insn)
++{
++ return nds32_4byte_load_store_reg_plus_offset (insn, NULL);
++}
++
++static bool
++nds32_load_store_opt_profitable_p (basic_block bb)
++{
++ int candidate = 0;
++ int threshold = 2;
++ rtx_insn *insn;
++
++ if (dump_file)
++ fprintf (dump_file, "scan bb %d\n", bb->index);
++
++ FOR_BB_INSNS (bb, insn)
++ {
++ if (nds32_4byte_load_store_reg_plus_offset_p (insn))
++ candidate++;
++ }
++
++ if (dump_file)
++ fprintf (dump_file, " candidate = %d\n", candidate);
++
++ return candidate >= threshold;
++}
++
++static offset_info_t
++nds32_get_offset_info (auto_vec *load_store_info)
++{
++ unsigned i;
++ std::set offsets;
++ offset_info_t offset_info;
++ offset_info.max_offset = 0;
++ offset_info.min_offset = 0;
++ offset_info.num_offset = 0;
++
++ if (load_store_info->length () == 0)
++ return offset_info;
++
++ offset_info.max_offset = (*load_store_info)[0].offset;
++ offset_info.min_offset = (*load_store_info)[0].offset;
++ offsets.insert ((*load_store_info)[0].offset);
++
++ for (i = 1; i < load_store_info->length (); i++)
++ {
++ HOST_WIDE_INT offset = (*load_store_info)[i].offset;
++ offset_info.max_offset = MAX (offset_info.max_offset, offset);
++ offset_info.min_offset = MIN (offset_info.min_offset, offset);
++ offsets.insert (offset);
++ }
++
++ offset_info.num_offset = offsets.size ();
++
++ return offset_info;
++}
++
++static void
++nds32_do_load_store_opt (basic_block bb)
++{
++ rtx_insn *insn;
++ load_store_info_t load_store_info;
++ auto_vec load_store_infos[NDS32_GPR_NUM];
++ HARD_REG_SET available_regset;
++ int i;
++ unsigned j;
++ unsigned regno;
++ unsigned polluting;
++ df_ref def;
++ /* Dirty mean a register is define again after
++ first load/store instruction.
++ For example:
++
++ lwi $r2, [$r3 + #0x100]
++ mov $r3, $r4 ! $r3 is dirty after this instruction.
++ lwi $r1, [$r3 + #0x120] ! so this load can't chain with prev load.
++ */
++ bool dirty[NDS32_GPR_NUM];
++
++ if (dump_file)
++ fprintf (dump_file, "try load store opt for bb %d\n", bb->index);
++
++ for (i = 0; i < NDS32_GPR_NUM; ++i)
++ dirty[i] = false;
++
++ FOR_BB_INSNS (bb, insn)
++ {
++ if (!INSN_P (insn))
++ continue;
++
++ polluting = INVALID_REGNUM;
++
++ /* Set def reg is dirty if chain is not empty. */
++ FOR_EACH_INSN_DEF (def, insn)
++ {
++ regno = DF_REF_REGNO (def);
++
++ if (!NDS32_IS_GPR_REGNUM (regno))
++ continue;
++
++ if (!load_store_infos[regno].is_empty ())
++ {
++ /* Set pulluting here because the source register
++ may be the same one. */
++ if (dirty[regno] == false)
++ polluting = regno;
++
++ dirty[regno] = true;
++ }
++ }
++
++ /* Set all caller-save register is dirty if chain is not empty. */
++ if (CALL_P (insn))
++ {
++ for (i = 0; i < NDS32_GPR_NUM; ++i)
++ {
++ if (call_used_regs[i] && !load_store_infos[i].is_empty ())
++ dirty[i] = true;
++ }
++ }
++
++ if (nds32_4byte_load_store_reg_plus_offset (insn, &load_store_info))
++ {
++ regno = REGNO (load_store_info.base_reg);
++ gcc_assert (NDS32_IS_GPR_REGNUM (regno));
++
++ /* Don't add to chain if this reg is dirty. */
++ if (dirty[regno] && polluting != regno)
++ break;
++
++ /* If the register is first time to be used and be polluted
++ right away, we don't push it. */
++ if (regno == REGNO (load_store_info.reg) && load_store_info.load_p
++ && dirty[regno] == false)
++ continue;
++
++ load_store_infos[regno].safe_push (load_store_info);
++ }
++ }
++ for (i = 0; i < NDS32_GPR_NUM; ++i)
++ {
++ if (load_store_infos[i].length () <= 1)
++ {
++ if (dump_file && load_store_infos[i].length () == 1)
++ fprintf (dump_file,
++ "Skip Chain for $r%d since chain size only 1\n",
++ i);
++ continue;
++ }
++
++ if (dump_file)
++ {
++ fprintf (dump_file,
++ "Chain for $r%d: (size = %u)\n",
++ i, load_store_infos[i].length ());
++
++ for (j = 0; j < load_store_infos[i].length (); ++j)
++ {
++ fprintf (dump_file,
++ "regno = %d base_regno = %d "
++ "offset = " HOST_WIDE_INT_PRINT_DEC " "
++ "load_p = %d UID = %u\n",
++ REGNO (load_store_infos[i][j].reg),
++ REGNO (load_store_infos[i][j].base_reg),
++ load_store_infos[i][j].offset,
++ load_store_infos[i][j].load_p,
++ INSN_UID (load_store_infos[i][j].insn));
++ }
++ }
++
++ nds32_get_available_reg_set (bb,
++ load_store_infos[i][0].insn,
++ load_store_infos[i].last ().insn,
++ &available_regset);
++
++ if (dump_file)
++ {
++ print_hard_reg_set (dump_file, "", available_regset);
++ }
++
++ offset_info_t offset_info = nds32_get_offset_info (&load_store_infos[i]);
++ if (dump_file)
++ {
++ fprintf (dump_file,
++ "max offset = " HOST_WIDE_INT_PRINT_DEC "\n"
++ "min offset = " HOST_WIDE_INT_PRINT_DEC "\n"
++ "num offset = %d\n",
++ offset_info.max_offset,
++ offset_info.min_offset,
++ offset_info.num_offset);
++ }
++
++ int gain;
++ int best_gain = 0;
++ const load_store_optimize_pass *best_load_store_optimize_pass = NULL;
++
++ for (j = 0; j < N_LOAD_STORE_OPT_TYPE; ++j)
++ {
++ gain = load_store_optimizes[j]->calc_gain (&available_regset,
++ offset_info,
++ &load_store_infos[i]);
++
++ if (dump_file)
++ fprintf (dump_file, "%s gain = %d\n",
++ load_store_optimizes[j]->name (), gain);
++
++ if (gain > best_gain)
++ {
++ best_gain = gain;
++ best_load_store_optimize_pass = load_store_optimizes[j];
++ }
++ }
++
++ if (best_load_store_optimize_pass)
++ {
++ if (dump_file)
++ fprintf (dump_file, "%s is most profit, optimize it!\n",
++ best_load_store_optimize_pass->name ());
++
++ best_load_store_optimize_pass->do_optimize (&available_regset,
++ offset_info,
++ &load_store_infos[i]);
++
++ df_insn_rescan_all ();
++ }
++
++ }
++}
++
++static unsigned int
++nds32_load_store_opt (void)
++{
++ basic_block bb;
++
++ df_set_flags (DF_LR_RUN_DCE);
++ df_note_add_problem ();
++ df_analyze ();
++
++ FOR_EACH_BB_FN (bb, cfun)
++ {
++ if (nds32_load_store_opt_profitable_p (bb))
++ nds32_do_load_store_opt (bb);
++ }
++
++ return 1;
++}
++
++const pass_data pass_data_nds32_load_store_opt =
++{
++ RTL_PASS, /* type */
++ "load_store_opt", /* name */
++ OPTGROUP_NONE, /* optinfo_flags */
++ TV_MACH_DEP, /* tv_id */
++ 0, /* properties_required */
++ 0, /* properties_provided */
++ 0, /* properties_destroyed */
++ 0, /* todo_flags_start */
++ TODO_df_finish, /* todo_flags_finish */
++};
++
++class pass_nds32_load_store_opt : public rtl_opt_pass
++{
++public:
++ pass_nds32_load_store_opt (gcc::context *ctxt)
++ : rtl_opt_pass (pass_data_nds32_load_store_opt, ctxt)
++ {}
++
++ /* opt_pass methods: */
++ bool gate (function *) { return TARGET_16_BIT && TARGET_LOAD_STORE_OPT; }
++ unsigned int execute (function *) { return nds32_load_store_opt (); }
++};
++
++rtl_opt_pass *
++make_pass_nds32_load_store_opt (gcc::context *ctxt)
++{
++ return new pass_nds32_load_store_opt (ctxt);
++}
+diff --git a/gcc/config/nds32/nds32-load-store-opt.h b/gcc/config/nds32/nds32-load-store-opt.h
+new file mode 100644
+index 0000000..f94b56a
+--- /dev/null
++++ b/gcc/config/nds32/nds32-load-store-opt.h
+@@ -0,0 +1,117 @@
++/* Prototypes for load-store-opt of Andes NDS32 cpu for GNU compiler
++ Copyright (C) 2012-2016 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
++ . */
++
++#ifndef NDS32_LOAD_STORE_OPT_H
++#define NDS32_LOAD_STORE_OPT_H
++
++/* Define the type of a set of hard registers. */
++
++enum nds32_memory_post_type
++{
++ NDS32_NONE,
++ NDS32_POST_INC,
++ NDS32_POST_DEC
++};
++
++typedef struct {
++ rtx reg;
++ rtx base_reg;
++ rtx offset;
++ HOST_WIDE_INT shift;
++ bool load_p;
++ rtx insn;
++} rr_load_store_info_t;
++
++typedef struct {
++ rtx reg;
++ rtx base_reg;
++ HOST_WIDE_INT offset;
++ bool load_p;
++ rtx_insn *insn;
++ rtx mem;
++ int new_reg;
++ int order;
++ int group;
++ bool place;
++ enum nds32_memory_post_type post_type;
++} load_store_info_t;
++
++typedef struct {
++ HOST_WIDE_INT max_offset;
++ HOST_WIDE_INT min_offset;
++ /* How many different offset. */
++ int num_offset;
++} offset_info_t;
++
++typedef struct {
++ rtx set_insns[2];
++ int n_set_insns;
++ rtx reg;
++ bool need_adjust_offset_p;
++ HOST_WIDE_INT adjust_offset;
++} new_base_reg_info_t;
++
++typedef struct {
++ unsigned int amount;
++ unsigned int start;
++ unsigned int end;
++} available_reg_info_t;
++
++typedef auto_vec load_store_infos_t;
++
++class load_store_optimize_pass
++{
++public:
++ load_store_optimize_pass (enum reg_class,
++ enum reg_class,
++ HOST_WIDE_INT,
++ HOST_WIDE_INT,
++ bool,
++ const char *);
++ const char *name () const { return m_name; };
++ int calc_gain (HARD_REG_SET *,
++ offset_info_t,
++ load_store_infos_t *) const;
++ void do_optimize (HARD_REG_SET *,
++ offset_info_t,
++ load_store_infos_t *) const;
++private:
++ enum reg_class m_allow_regclass;
++ enum reg_class m_new_base_regclass;
++ HOST_WIDE_INT m_offset_lower_bound;
++ HOST_WIDE_INT m_offset_upper_bound;
++ bool m_load_only_p;
++ const char *m_name;
++};
++
++static inline rtx
++gen_reg_plus_imm_load_store (rtx reg, rtx base_reg,
++ HOST_WIDE_INT offset, bool load_p, rtx oldmem)
++{
++ rtx addr = plus_constant(Pmode, base_reg, offset);
++ rtx mem = gen_rtx_MEM (SImode, addr);
++ MEM_COPY_ATTRIBUTES (mem, oldmem);
++ if (load_p)
++ return gen_movsi (reg, mem);
++ else
++ return gen_movsi (mem, reg);
++}
++
++#endif /* ! NDS32_LOAD_STORE_OPT_H */
+diff --git a/gcc/config/nds32/nds32-md-auxiliary.c b/gcc/config/nds32/nds32-md-auxiliary.c
+index def8eda..3881df7 100644
+--- a/gcc/config/nds32/nds32-md-auxiliary.c
++++ b/gcc/config/nds32/nds32-md-auxiliary.c
+@@ -25,17 +25,74 @@
+ #include "system.h"
+ #include "coretypes.h"
+ #include "backend.h"
+-#include "target.h"
+-#include "rtl.h"
+ #include "tree.h"
+-#include "tm_p.h"
+-#include "optabs.h" /* For GEN_FCN. */
+-#include "recog.h"
++#include "rtl.h"
++#include "df.h"
++#include "alias.h"
++#include "stor-layout.h"
++#include "varasm.h"
++#include "calls.h"
++#include "regs.h"
++#include "insn-config.h" /* Required by recog.h. */
++#include "conditions.h"
+ #include "output.h"
++#include "insn-attr.h" /* For DFA state_t. */
++#include "insn-codes.h" /* For CODE_FOR_xxx. */
++#include "reload.h" /* For push_reload(). */
++#include "flags.h"
++#include "insn-config.h"
++#include "expmed.h"
++#include "dojump.h"
++#include "explow.h"
++#include "emit-rtl.h"
++#include "stmt.h"
++#include "expr.h"
++#include "recog.h"
++#include "diagnostic-core.h"
++#include "cfgrtl.h"
++#include "cfganal.h"
++#include "lcm.h"
++#include "cfgbuild.h"
++#include "cfgcleanup.h"
++#include "tm_p.h"
+ #include "tm-constrs.h"
++#include "optabs.h" /* For GEN_FCN. */
++#include "target.h"
++#include "langhooks.h" /* For add_builtin_function(). */
++#include "builtins.h"
++
++/* ------------------------------------------------------------------------ */
++
++/* This file is divided into three parts:
++
++ PART 1: Auxiliary static function definitions.
++
++ PART 2: Auxiliary function for expand RTL pattern.
++
++ PART 3: Auxiliary function for output asm template. */
+
+ /* ------------------------------------------------------------------------ */
+
++/* PART 1: Auxiliary static function definitions. */
++
++static int
++nds32_regno_to_enable4 (unsigned regno)
++{
++ switch (regno)
++ {
++ case 28: /* $r28/fp */
++ return 0x8;
++ case 29: /* $r29/gp */
++ return 0x4;
++ case 30: /* $r30/lp */
++ return 0x2;
++ case 31: /* $r31/sp */
++ return 0x1;
++ default:
++ gcc_unreachable ();
++ }
++}
++
+ /* A helper function to return character based on byte size. */
+ static char
+ nds32_byte_to_size (int byte)
+@@ -54,796 +111,3825 @@ nds32_byte_to_size (int byte)
+ }
+ }
+
+-/* A helper function to return memory format. */
+-enum nds32_16bit_address_type
+-nds32_mem_format (rtx op)
++static int
++nds32_inverse_cond_code (int code)
+ {
+- machine_mode mode_test;
+- int val;
+- int regno;
+-
+- if (!TARGET_16_BIT)
+- return ADDRESS_NOT_16BIT_FORMAT;
+-
+- mode_test = GET_MODE (op);
+-
+- op = XEXP (op, 0);
++ switch (code)
++ {
++ case NE:
++ return EQ;
++ case EQ:
++ return NE;
++ case GT:
++ return LE;
++ case LE:
++ return GT;
++ case GE:
++ return LT;
++ case LT:
++ return GE;
++ default:
++ gcc_unreachable ();
++ }
++}
+
+- /* 45 format. */
+- if (GET_CODE (op) == REG && (mode_test == SImode))
+- return ADDRESS_REG;
++static const char *
++nds32_cond_code_str (int code)
++{
++ switch (code)
++ {
++ case NE:
++ return "ne";
++ case EQ:
++ return "eq";
++ case GT:
++ return "gt";
++ case LE:
++ return "le";
++ case GE:
++ return "ge";
++ case LT:
++ return "lt";
++ default:
++ gcc_unreachable ();
++ }
++}
+
+- /* 333 format for QI/HImode. */
+- if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM))
+- return ADDRESS_LO_REG_IMM3U;
++static void
++output_cond_branch (int code, const char *suffix, bool r5_p,
++ bool long_jump_p, rtx *operands)
++{
++ char pattern[256];
++ const char *cond_code;
++ bool align_p = NDS32_ALIGN_P ();
++ const char *align = align_p ? "\t.align\t2\n" : "";
+
+- /* post_inc 333 format. */
+- if ((GET_CODE (op) == POST_INC) && (mode_test == SImode))
++ if (r5_p && REGNO (operands[2]) == 5 && TARGET_16_BIT)
+ {
+- regno = REGNO(XEXP (op, 0));
+-
+- if (regno < 8)
+- return ADDRESS_POST_INC_LO_REG_IMM3U;
++ /* This is special case for beqs38 and bnes38,
++ second operand 2 can't be $r5 and it's almost meanless,
++ however it may occur after copy propgation. */
++ if (code == EQ)
++ {
++ /* $r5 == $r5 always taken! */
++ if (long_jump_p)
++ snprintf (pattern, sizeof (pattern),
++ "j\t%%3");
++ else
++ snprintf (pattern, sizeof (pattern),
++ "j8\t%%3");
++ }
++ else
++ /* Don't output anything since $r5 != $r5 never taken! */
++ pattern[0] = '\0';
+ }
+-
+- /* post_inc 333 format. */
+- if ((GET_CODE (op) == POST_MODIFY)
+- && (mode_test == SImode)
+- && (REG_P (XEXP (XEXP (op, 1), 0)))
+- && (CONST_INT_P (XEXP (XEXP (op, 1), 1))))
++ else if (long_jump_p)
+ {
+- regno = REGNO (XEXP (XEXP (op, 1), 0));
+- val = INTVAL (XEXP (XEXP (op, 1), 1));
+- if (regno < 8 && val < 32)
+- return ADDRESS_POST_INC_LO_REG_IMM3U;
++ int inverse_code = nds32_inverse_cond_code (code);
++ cond_code = nds32_cond_code_str (inverse_code);
++
++ /* b $r0, $r1, .L0
++ =>
++ b $r0, $r1, .LCB0
++ j .L0
++ .LCB0:
++
++ or
++
++ b