diff --git a/gcc/common.opt b/gcc/common.opt index a255577..86448a3 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 858b878..d684736 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 @@ -2270,17 +2290,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}" @@ -4102,15 +4172,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 @@ -4120,31 +4226,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-*-*) @@ -4532,7 +4663,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..f1efdb2 --- /dev/null +++ b/gcc/config/nds32/linux.h @@ -0,0 +1,79 @@ +/* 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}}}} " + +#define CPP_SPEC "%{pthread:-D_REENTRANT}" + +/* The SYNC operations are implemented as library functions, not + INSN patterns. As a result, the HAVE defines for the patterns are + not defined. We need to define them to generate the corresponding + __GCC_HAVE_SYNC_COMPARE_AND_SWAP_* and __GCC_ATOMIC_*_LOCK_FREE + defines. + Ref: https://sourceware.org/ml/libc-alpha/2014-09/msg00322.html */ +#define HAVE_sync_compare_and_swapqi 1 +#define HAVE_sync_compare_and_swaphi 1 +#define HAVE_sync_compare_and_swapsi 1 diff --git a/gcc/config/nds32/nds32-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 $r0, $r1, .L0 + => + b $r0, $r1, .LCB0 + j .L0 + .LCB0: + */ + if (r5_p && TARGET_16_BIT) + { + snprintf (pattern, sizeof (pattern), + "b%ss38\t %%2, .LCB%%=\n\tj\t%%3\n%s.LCB%%=:", + cond_code, align); + } + else + { + snprintf (pattern, sizeof (pattern), + "b%s%s\t%%1, %%2, .LCB%%=\n\tj\t%%3\n%s.LCB%%=:", + cond_code, suffix, align); + } } - - if ((GET_CODE (op) == PLUS) - && (GET_CODE (XEXP (op, 0)) == REG) - && (GET_CODE (XEXP (op, 1)) == CONST_INT)) + else { - val = INTVAL (XEXP (op, 1)); - - regno = REGNO(XEXP (op, 0)); - - if (regno > 7 - && regno != SP_REGNUM - && regno != FP_REGNUM) - return ADDRESS_NOT_16BIT_FORMAT; - - switch (mode_test) + cond_code = nds32_cond_code_str (code); + if (r5_p && TARGET_16_BIT) { - case QImode: - /* 333 format. */ - if (val >= 0 && val < 8 && regno < 8) - return ADDRESS_LO_REG_IMM3U; - break; - - case HImode: - /* 333 format. */ - if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8) - return ADDRESS_LO_REG_IMM3U; - break; - - case SImode: - case SFmode: - case DFmode: - /* fp imply 37 format. */ - if ((regno == FP_REGNUM) && - (val >= 0 && val < 512 && (val % 4 == 0))) - return ADDRESS_FP_IMM7U; - /* sp imply 37 format. */ - else if ((regno == SP_REGNUM) && - (val >= 0 && val < 512 && (val % 4 == 0))) - return ADDRESS_SP_IMM7U; - /* 333 format. */ - else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8) - return ADDRESS_LO_REG_IMM3U; - break; - - default: - break; + /* bs38 $r1, .L0 */ + snprintf (pattern, sizeof (pattern), + "b%ss38\t %%2, %%3", cond_code); + } + else + { + /* b $r0, $r1, .L0 */ + snprintf (pattern, sizeof (pattern), + "b%s%s\t%%1, %%2, %%3", cond_code, suffix); } } - return ADDRESS_NOT_16BIT_FORMAT; + output_asm_insn (pattern, operands); } -/* Output 16-bit store. */ -const char * -nds32_output_16bit_store (rtx *operands, int byte) +static void +output_cond_branch_compare_zero (int code, const char *suffix, + bool long_jump_p, rtx *operands, + bool ta_implied_p) { - char pattern[100]; - char size; - rtx code = XEXP (operands[0], 0); - - size = nds32_byte_to_size (byte); + char pattern[256]; + const char *cond_code; + bool align_p = NDS32_ALIGN_P (); + const char *align = align_p ? "\t.align\t2\n" : ""; + if (long_jump_p) + { + int inverse_code = nds32_inverse_cond_code (code); + cond_code = nds32_cond_code_str (inverse_code); - switch (nds32_mem_format (operands[0])) + if (ta_implied_p && TARGET_16_BIT) + { + /* bz .L0 + => + bz .LCB0 + j .L0 + .LCB0: + */ + snprintf (pattern, sizeof (pattern), + "b%sz%s\t.LCB%%=\n\tj\t%%2\n%s.LCB%%=:", + cond_code, suffix, align); + } + else + { + /* bz $r0, .L0 + => + bz $r0, .LCB0 + j .L0 + .LCB0: + */ + snprintf (pattern, sizeof (pattern), + "b%sz%s\t%%1, .LCB%%=\n\tj\t%%2\n%s.LCB%%=:", + cond_code, suffix, align); + } + } + else { - case ADDRESS_REG: - operands[0] = code; - output_asm_insn ("swi450\t%1, [%0]", operands); - break; - case ADDRESS_LO_REG_IMM3U: - snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size); - output_asm_insn (pattern, operands); - break; - case ADDRESS_POST_INC_LO_REG_IMM3U: - snprintf (pattern, sizeof (pattern), "s%ci333.bi\t%%1, %%0", size); - output_asm_insn (pattern, operands); - break; - case ADDRESS_FP_IMM7U: - output_asm_insn ("swi37\t%1, %0", operands); - break; - case ADDRESS_SP_IMM7U: - /* Get immediate value and set back to operands[1]. */ - operands[0] = XEXP (code, 1); - output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands); - break; - default: - break; + cond_code = nds32_cond_code_str (code); + if (ta_implied_p && TARGET_16_BIT) + { + /* bz .L0 */ + snprintf (pattern, sizeof (pattern), + "b%sz%s\t%%2", cond_code, suffix); + } + else + { + /* bz $r0, .L0 */ + snprintf (pattern, sizeof (pattern), + "b%sz%s\t%%1, %%2", cond_code, suffix); + } } - return ""; + output_asm_insn (pattern, operands); } -/* Output 16-bit load. */ -const char * -nds32_output_16bit_load (rtx *operands, int byte) +static void +nds32_split_shiftrtdi3 (rtx dst, rtx src, rtx shiftamount, bool logic_shift_p) { - char pattern[100]; - unsigned char size; - rtx code = XEXP (operands[1], 0); + rtx src_high_part; + rtx dst_high_part, dst_low_part; - size = nds32_byte_to_size (byte); + dst_high_part = nds32_di_high_part_subreg (dst); + src_high_part = nds32_di_high_part_subreg (src); + dst_low_part = nds32_di_low_part_subreg (dst); - switch (nds32_mem_format (operands[1])) + if (CONST_INT_P (shiftamount)) { - case ADDRESS_REG: - operands[1] = code; - output_asm_insn ("lwi450\t%0, [%1]", operands); - break; - case ADDRESS_LO_REG_IMM3U: - snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size); - output_asm_insn (pattern, operands); - break; - case ADDRESS_POST_INC_LO_REG_IMM3U: - snprintf (pattern, sizeof (pattern), "l%ci333.bi\t%%0, %%1", size); - output_asm_insn (pattern, operands); - break; - case ADDRESS_FP_IMM7U: - output_asm_insn ("lwi37\t%0, %1", operands); - break; - case ADDRESS_SP_IMM7U: - /* Get immediate value and set back to operands[0]. */ - operands[1] = XEXP (code, 1); - output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands); - break; - default: - break; + if (INTVAL (shiftamount) < 32) + { + if (logic_shift_p) + { + emit_insn (gen_uwext (dst_low_part, src, + shiftamount)); + emit_insn (gen_lshrsi3 (dst_high_part, src_high_part, + shiftamount)); + } + else + { + emit_insn (gen_wext (dst_low_part, src, + shiftamount)); + emit_insn (gen_ashrsi3 (dst_high_part, src_high_part, + shiftamount)); + } + } + else + { + rtx new_shift_amout = gen_int_mode(INTVAL (shiftamount) - 32, SImode); + + if (logic_shift_p) + { + emit_insn (gen_lshrsi3 (dst_low_part, src_high_part, + new_shift_amout)); + emit_move_insn (dst_high_part, const0_rtx); + } + else + { + emit_insn (gen_ashrsi3 (dst_low_part, src_high_part, + new_shift_amout)); + emit_insn (gen_ashrsi3 (dst_high_part, src_high_part, + GEN_INT (31))); + } + } } + else + { + rtx dst_low_part_l32, dst_high_part_l32; + rtx dst_low_part_g32, dst_high_part_g32; + rtx new_shift_amout, select_reg; + dst_low_part_l32 = gen_reg_rtx (SImode); + dst_high_part_l32 = gen_reg_rtx (SImode); + dst_low_part_g32 = gen_reg_rtx (SImode); + dst_high_part_g32 = gen_reg_rtx (SImode); + new_shift_amout = gen_reg_rtx (SImode); + select_reg = gen_reg_rtx (SImode); + + emit_insn (gen_andsi3 (shiftamount, shiftamount, GEN_INT (0x3f))); + + if (logic_shift_p) + { + /* + if (shiftamount < 32) + dst_low_part = wext (src, shiftamount) + dst_high_part = src_high_part >> shiftamount + else + dst_low_part = src_high_part >> (shiftamount & 0x1f) + dst_high_part = 0 + */ + emit_insn (gen_uwext (dst_low_part_l32, src, shiftamount)); + emit_insn (gen_lshrsi3 (dst_high_part_l32, src_high_part, + shiftamount)); + + emit_insn (gen_andsi3 (new_shift_amout, shiftamount, GEN_INT (0x1f))); + emit_insn (gen_lshrsi3 (dst_low_part_g32, src_high_part, + new_shift_amout)); + emit_move_insn (dst_high_part_g32, const0_rtx); + } + else + { + /* + if (shiftamount < 32) + dst_low_part = wext (src, shiftamount) + dst_high_part = src_high_part >> shiftamount + else + dst_low_part = src_high_part >> (shiftamount & 0x1f) + # shift 31 for sign extend + dst_high_part = src_high_part >> 31 + */ + emit_insn (gen_wext (dst_low_part_l32, src, shiftamount)); + emit_insn (gen_ashrsi3 (dst_high_part_l32, src_high_part, + shiftamount)); + + emit_insn (gen_andsi3 (new_shift_amout, shiftamount, GEN_INT (0x1f))); + emit_insn (gen_ashrsi3 (dst_low_part_g32, src_high_part, + new_shift_amout)); + emit_insn (gen_ashrsi3 (dst_high_part_g32, src_high_part, + GEN_INT (31))); + } - return ""; + emit_insn (gen_slt_compare (select_reg, shiftamount, GEN_INT (32))); + + emit_insn (gen_cmovnsi (dst_low_part, select_reg, + dst_low_part_l32, dst_low_part_g32)); + emit_insn (gen_cmovnsi (dst_high_part, select_reg, + dst_high_part_l32, dst_high_part_g32)); + } } -/* Output 32-bit store. */ -const char * -nds32_output_32bit_store (rtx *operands, int byte) -{ - char pattern[100]; - unsigned char size; - rtx code = XEXP (operands[0], 0); +/* ------------------------------------------------------------------------ */ - size = nds32_byte_to_size (byte); +/* PART 2: Auxiliary function for expand RTL pattern. */ - switch (GET_CODE (code)) +enum nds32_expand_result_type +nds32_expand_cbranch (rtx *operands) +{ + rtx tmp_reg; + enum rtx_code code; + + code = GET_CODE (operands[0]); + + /* If operands[2] is (const_int 0), + we can use beqz,bnez,bgtz,bgez,bltz,or blez instructions. + So we have gcc generate original template rtx. */ + if (GET_CODE (operands[2]) == CONST_INT) + if (INTVAL (operands[2]) == 0) + if ((code != GTU) + && (code != GEU) + && (code != LTU) + && (code != LEU)) + return EXPAND_CREATE_TEMPLATE; + + /* For other comparison, NDS32 ISA only has slt (Set-on-Less-Than) + behavior for the comparison, we might need to generate other + rtx patterns to achieve same semantic. */ + switch (code) { - case REG: - /* (mem (reg X)) - => access location by using register, - use "sbi / shi / swi" */ - snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size); - break; - - case SYMBOL_REF: - case CONST: - /* (mem (symbol_ref X)) - (mem (const (...))) - => access global variables, - use "sbi.gp / shi.gp / swi.gp" */ - operands[0] = XEXP (operands[0], 0); - snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size); - break; + case GT: + case GTU: + if (GET_CODE (operands[2]) == CONST_INT) + { + /* GT reg_A, const_int => !(LT reg_A, const_int + 1) */ + if (optimize_size || optimize == 0) + tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); + else + tmp_reg = gen_reg_rtx (SImode); + + /* We want to plus 1 into the integer value + of operands[2] to create 'slt' instruction. + This caculation is performed on the host machine, + which may be 64-bit integer. + So the meaning of caculation result may be + different from the 32-bit nds32 target. + + For example: + 0x7fffffff + 0x1 -> 0x80000000, + this value is POSITIVE on 64-bit machine, + but the expected value on 32-bit nds32 target + should be NEGATIVE value. + + Hence, instead of using GEN_INT(), we use gen_int_mode() to + explicitly create SImode constant rtx. */ + enum rtx_code cmp_code; + + rtx plus1 = gen_int_mode (INTVAL (operands[2]) + 1, SImode); + if (satisfies_constraint_Is15 (plus1)) + { + operands[2] = plus1; + cmp_code = EQ; + if (code == GT) + { + /* GT, use slts instruction */ + emit_insn ( + gen_slts_compare (tmp_reg, operands[1], operands[2])); + } + else + { + /* GTU, use slt instruction */ + emit_insn ( + gen_slt_compare (tmp_reg, operands[1], operands[2])); + } + } + else + { + cmp_code = NE; + if (code == GT) + { + /* GT, use slts instruction */ + emit_insn ( + gen_slts_compare (tmp_reg, operands[2], operands[1])); + } + else + { + /* GTU, use slt instruction */ + emit_insn ( + gen_slt_compare (tmp_reg, operands[2], operands[1])); + } + } + + PUT_CODE (operands[0], cmp_code); + operands[1] = tmp_reg; + operands[2] = const0_rtx; + emit_insn (gen_cbranchsi4 (operands[0], operands[1], + operands[2], operands[3])); + + return EXPAND_DONE; + } + else + { + /* GT reg_A, reg_B => LT reg_B, reg_A */ + if (optimize_size || optimize == 0) + tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); + else + tmp_reg = gen_reg_rtx (SImode); + + if (code == GT) + { + /* GT, use slts instruction */ + emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1])); + } + else + { + /* GTU, use slt instruction */ + emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1])); + } + + PUT_CODE (operands[0], NE); + operands[1] = tmp_reg; + operands[2] = const0_rtx; + emit_insn (gen_cbranchsi4 (operands[0], operands[1], + operands[2], operands[3])); + + return EXPAND_DONE; + } - case POST_INC: - /* (mem (post_inc reg)) - => access location by using register which will be post increment, - use "sbi.bi / shi.bi / swi.bi" */ - snprintf (pattern, sizeof (pattern), - "s%ci.bi\t%%1, %%0, %d", size, byte); - break; + case GE: + case GEU: + /* GE reg_A, reg_B => !(LT reg_A, reg_B) */ + /* GE reg_A, const_int => !(LT reg_A, const_int) */ + if (optimize_size || optimize == 0) + tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); + else + tmp_reg = gen_reg_rtx (SImode); - case POST_DEC: - /* (mem (post_dec reg)) - => access location by using register which will be post decrement, - use "sbi.bi / shi.bi / swi.bi" */ - snprintf (pattern, sizeof (pattern), - "s%ci.bi\t%%1, %%0, -%d", size, byte); - break; + if (code == GE) + { + /* GE, use slts instruction */ + emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2])); + } + else + { + /* GEU, use slt instruction */ + emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2])); + } - case POST_MODIFY: - switch (GET_CODE (XEXP (XEXP (code, 1), 1))) + PUT_CODE (operands[0], EQ); + operands[1] = tmp_reg; + operands[2] = const0_rtx; + emit_insn (gen_cbranchsi4 (operands[0], operands[1], + operands[2], operands[3])); + + return EXPAND_DONE; + + case LT: + case LTU: + /* LT reg_A, reg_B => LT reg_A, reg_B */ + /* LT reg_A, const_int => LT reg_A, const_int */ + if (optimize_size || optimize == 0) + tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); + else + tmp_reg = gen_reg_rtx (SImode); + + if (code == LT) { - case REG: - case SUBREG: - /* (mem (post_modify (reg) (plus (reg) (reg)))) - => access location by using register which will be - post modified with reg, - use "sb.bi/ sh.bi / sw.bi" */ - snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size); - break; - case CONST_INT: - /* (mem (post_modify (reg) (plus (reg) (const_int)))) - => access location by using register which will be - post modified with const_int, - use "sbi.bi/ shi.bi / swi.bi" */ - snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size); - break; - default: - abort (); + /* LT, use slts instruction */ + emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2])); + } + else + { + /* LTU, use slt instruction */ + emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2])); } - break; - case PLUS: - switch (GET_CODE (XEXP (code, 1))) + PUT_CODE (operands[0], NE); + operands[1] = tmp_reg; + operands[2] = const0_rtx; + emit_insn (gen_cbranchsi4 (operands[0], operands[1], + operands[2], operands[3])); + + return EXPAND_DONE; + + case LE: + case LEU: + if (GET_CODE (operands[2]) == CONST_INT) { - case REG: - case SUBREG: - /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) - => access location by adding two registers, - use "sb / sh / sw" */ - snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size); - break; - case CONST_INT: - /* (mem (plus reg const_int)) - => access location by adding one register with const_int, - use "sbi / shi / swi" */ - snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size); - break; - default: - abort (); + /* LE reg_A, const_int => LT reg_A, const_int + 1 */ + if (optimize_size || optimize == 0) + tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); + else + tmp_reg = gen_reg_rtx (SImode); + + enum rtx_code cmp_code; + /* Note that (le:SI X INT_MAX) is not the same as (lt:SI X INT_MIN). + We better have an assert here in case GCC does not properly + optimize it away. The INT_MAX here is 0x7fffffff for target. */ + rtx plus1 = gen_int_mode (INTVAL (operands[2]) + 1, SImode); + if (satisfies_constraint_Is15 (plus1)) + { + operands[2] = plus1; + cmp_code = NE; + if (code == LE) + { + /* LE, use slts instruction */ + emit_insn ( + gen_slts_compare (tmp_reg, operands[1], operands[2])); + } + else + { + /* LEU, use slt instruction */ + emit_insn ( + gen_slt_compare (tmp_reg, operands[1], operands[2])); + } + } + else + { + cmp_code = EQ; + if (code == LE) + { + /* LE, use slts instruction */ + emit_insn ( + gen_slts_compare (tmp_reg, operands[2], operands[1])); + } + else + { + /* LEU, use slt instruction */ + emit_insn ( + gen_slt_compare (tmp_reg, operands[2], operands[1])); + } + } + + PUT_CODE (operands[0], cmp_code); + operands[1] = tmp_reg; + operands[2] = const0_rtx; + emit_insn (gen_cbranchsi4 (operands[0], operands[1], + operands[2], operands[3])); + + return EXPAND_DONE; + } + else + { + /* LE reg_A, reg_B => !(LT reg_B, reg_A) */ + if (optimize_size || optimize == 0) + tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); + else + tmp_reg = gen_reg_rtx (SImode); + + if (code == LE) + { + /* LE, use slts instruction */ + emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1])); + } + else + { + /* LEU, use slt instruction */ + emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1])); + } + + PUT_CODE (operands[0], EQ); + operands[1] = tmp_reg; + operands[2] = const0_rtx; + emit_insn (gen_cbranchsi4 (operands[0], operands[1], + operands[2], operands[3])); + + return EXPAND_DONE; } - break; - case LO_SUM: - operands[2] = XEXP (code, 1); - operands[0] = XEXP (code, 0); - snprintf (pattern, sizeof (pattern), - "s%ci\t%%1, [%%0 + lo12(%%2)]", size); - break; + case EQ: + case NE: + /* NDS32 ISA has various form for eq/ne behavior no matter + what kind of the operand is. + So just generate original template rtx. */ + + /* Put operands[2] into register if operands[2] is a large + const_int or ISAv2. */ + if (GET_CODE (operands[2]) == CONST_INT + && (!satisfies_constraint_Is11 (operands[2]) + || TARGET_ISA_V2)) + operands[2] = force_reg (SImode, operands[2]); + + return EXPAND_CREATE_TEMPLATE; default: - abort (); + return EXPAND_FAIL; } - - output_asm_insn (pattern, operands); - return ""; } -/* Output 32-bit load. */ -const char * -nds32_output_32bit_load (rtx *operands, int byte) +enum nds32_expand_result_type +nds32_expand_cstore (rtx *operands) { - char pattern[100]; - unsigned char size; - rtx code; - - code = XEXP (operands[1], 0); + rtx tmp_reg; + enum rtx_code code; - size = nds32_byte_to_size (byte); + code = GET_CODE (operands[1]); - switch (GET_CODE (code)) + switch (code) { - case REG: - /* (mem (reg X)) - => access location by using register, - use "lbi / lhi / lwi" */ - snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size); - break; - - case SYMBOL_REF: - case CONST: - /* (mem (symbol_ref X)) - (mem (const (...))) - => access global variables, - use "lbi.gp / lhi.gp / lwi.gp" */ - operands[1] = XEXP (operands[1], 0); - snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size); - break; + case EQ: + case NE: + if (GET_CODE (operands[3]) == CONST_INT) + { + /* reg_R = (reg_A == const_int_B) + --> xori reg_C, reg_A, const_int_B + slti reg_R, reg_C, const_int_1 + reg_R = (reg_A != const_int_B) + --> xori reg_C, reg_A, const_int_B + slti reg_R, const_int0, reg_C */ + tmp_reg = gen_reg_rtx (SImode); + + /* If the integer value is not in the range of imm15s, + we need to force register first because our addsi3 pattern + only accept nds32_rimm15s_operand predicate. */ + rtx new_imm = gen_int_mode (-INTVAL (operands[3]), SImode); + if (satisfies_constraint_Is15 (new_imm)) + emit_insn (gen_addsi3 (tmp_reg, operands[2], new_imm)); + else + { + if (!(satisfies_constraint_Iu15 (operands[3]) + || (TARGET_EXT_PERF + && satisfies_constraint_It15 (operands[3])))) + operands[3] = force_reg (SImode, operands[3]); + emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3])); + } + + if (code == EQ) + emit_insn (gen_slt_eq0 (operands[0], tmp_reg)); + else + emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg)); + + return EXPAND_DONE; + } + else + { + /* reg_R = (reg_A == reg_B) + --> xor reg_C, reg_A, reg_B + slti reg_R, reg_C, const_int_1 + reg_R = (reg_A != reg_B) + --> xor reg_C, reg_A, reg_B + slti reg_R, const_int0, reg_C */ + tmp_reg = gen_reg_rtx (SImode); + emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3])); + if (code == EQ) + emit_insn (gen_slt_eq0 (operands[0], tmp_reg)); + else + emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg)); + + return EXPAND_DONE; + } + case GT: + case GTU: + /* reg_R = (reg_A > reg_B) --> slt reg_R, reg_B, reg_A */ + /* reg_R = (reg_A > const_int_B) --> slt reg_R, const_int_B, reg_A */ + if (code == GT) + { + /* GT, use slts instruction */ + emit_insn (gen_slts_compare (operands[0], operands[3], operands[2])); + } + else + { + /* GTU, use slt instruction */ + emit_insn (gen_slt_compare (operands[0], operands[3], operands[2])); + } - case POST_INC: - /* (mem (post_inc reg)) - => access location by using register which will be post increment, - use "lbi.bi / lhi.bi / lwi.bi" */ - snprintf (pattern, sizeof (pattern), - "l%ci.bi\t%%0, %%1, %d", size, byte); - break; + return EXPAND_DONE; - case POST_DEC: - /* (mem (post_dec reg)) - => access location by using register which will be post decrement, - use "lbi.bi / lhi.bi / lwi.bi" */ - snprintf (pattern, sizeof (pattern), - "l%ci.bi\t%%0, %%1, -%d", size, byte); - break; + case GE: + case GEU: + if (GET_CODE (operands[3]) == CONST_INT) + { + /* reg_R = (reg_A >= const_int_B) + --> movi reg_C, const_int_B - 1 + slt reg_R, reg_C, reg_A */ + tmp_reg = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (tmp_reg, + gen_int_mode (INTVAL (operands[3]) - 1, + SImode))); + if (code == GE) + { + /* GE, use slts instruction */ + emit_insn (gen_slts_compare (operands[0], tmp_reg, operands[2])); + } + else + { + /* GEU, use slt instruction */ + emit_insn (gen_slt_compare (operands[0], tmp_reg, operands[2])); + } + + return EXPAND_DONE; + } + else + { + /* reg_R = (reg_A >= reg_B) + --> slt reg_R, reg_A, reg_B + xori reg_R, reg_R, const_int_1 */ + if (code == GE) + { + /* GE, use slts instruction */ + emit_insn (gen_slts_compare (operands[0], + operands[2], operands[3])); + } + else + { + /* GEU, use slt instruction */ + emit_insn (gen_slt_compare (operands[0], + operands[2], operands[3])); + } + + /* perform 'not' behavior */ + emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx)); + + return EXPAND_DONE; + } - case POST_MODIFY: - switch (GET_CODE (XEXP (XEXP (code, 1), 1))) + case LT: + case LTU: + /* reg_R = (reg_A < reg_B) --> slt reg_R, reg_A, reg_B */ + /* reg_R = (reg_A < const_int_B) --> slt reg_R, reg_A, const_int_B */ + if (code == LT) { - case REG: - case SUBREG: - /* (mem (post_modify (reg) (plus (reg) (reg)))) - => access location by using register which will be - post modified with reg, - use "lb.bi/ lh.bi / lw.bi" */ - snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size); - break; - case CONST_INT: - /* (mem (post_modify (reg) (plus (reg) (const_int)))) - => access location by using register which will be - post modified with const_int, - use "lbi.bi/ lhi.bi / lwi.bi" */ - snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size); - break; - default: - abort (); + /* LT, use slts instruction */ + emit_insn (gen_slts_compare (operands[0], operands[2], operands[3])); + } + else + { + /* LTU, use slt instruction */ + emit_insn (gen_slt_compare (operands[0], operands[2], operands[3])); } - break; - case PLUS: - switch (GET_CODE (XEXP (code, 1))) + return EXPAND_DONE; + + case LE: + case LEU: + if (GET_CODE (operands[3]) == CONST_INT) { - case REG: - case SUBREG: - /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) - use "lb / lh / lw" */ - snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size); - break; - case CONST_INT: - /* (mem (plus reg const_int)) - => access location by adding one register with const_int, - use "lbi / lhi / lwi" */ - snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size); - break; - default: - abort (); + /* reg_R = (reg_A <= const_int_B) + --> movi reg_C, const_int_B + 1 + slt reg_R, reg_A, reg_C */ + tmp_reg = gen_reg_rtx (SImode); + + emit_insn (gen_movsi (tmp_reg, + gen_int_mode (INTVAL (operands[3]) + 1, + SImode))); + if (code == LE) + { + /* LE, use slts instruction */ + emit_insn (gen_slts_compare (operands[0], operands[2], tmp_reg)); + } + else + { + /* LEU, use slt instruction */ + emit_insn (gen_slt_compare (operands[0], operands[2], tmp_reg)); + } + + return EXPAND_DONE; + } + else + { + /* reg_R = (reg_A <= reg_B) --> slt reg_R, reg_B, reg_A + xori reg_R, reg_R, const_int_1 */ + if (code == LE) + { + /* LE, use slts instruction */ + emit_insn (gen_slts_compare (operands[0], + operands[3], operands[2])); + } + else + { + /* LEU, use slt instruction */ + emit_insn (gen_slt_compare (operands[0], + operands[3], operands[2])); + } + + /* perform 'not' behavior */ + emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx)); + + return EXPAND_DONE; } - break; - case LO_SUM: - operands[2] = XEXP (code, 1); - operands[1] = XEXP (code, 0); - snprintf (pattern, sizeof (pattern), - "l%ci\t%%0, [%%1 + lo12(%%2)]", size); - break; default: - abort (); + gcc_unreachable (); } - - output_asm_insn (pattern, operands); - return ""; } -/* Output 32-bit load with signed extension. */ -const char * -nds32_output_32bit_load_s (rtx *operands, int byte) +void +nds32_expand_float_cbranch (rtx *operands) { - char pattern[100]; - unsigned char size; - rtx code; + enum rtx_code code = GET_CODE (operands[0]); + enum rtx_code new_code = code; + rtx cmp_op0 = operands[1]; + rtx cmp_op1 = operands[2]; + rtx tmp_reg; + rtx tmp; - code = XEXP (operands[1], 0); + int reverse = 0; - size = nds32_byte_to_size (byte); + /* Main Goal: Use compare instruction + branch instruction. - switch (GET_CODE (code)) + For example: + GT, GE: swap condition and swap operands and generate + compare instruction(LT, LE) + branch not equal instruction. + + UNORDERED, LT, LE, EQ: no need to change and generate + compare instruction(UNORDERED, LT, LE, EQ) + branch not equal instruction. + + ORDERED, NE: reverse condition and generate + compare instruction(EQ) + branch equal instruction. */ + + switch (code) { - case REG: - /* (mem (reg X)) - => access location by using register, - use "lbsi / lhsi" */ - snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size); + case GT: + case GE: + tmp = cmp_op0; + cmp_op0 = cmp_op1; + cmp_op1 = tmp; + new_code = swap_condition (new_code); break; - - case SYMBOL_REF: - case CONST: - /* (mem (symbol_ref X)) - (mem (const (...))) - => access global variables, - use "lbsi.gp / lhsi.gp" */ - operands[1] = XEXP (operands[1], 0); - snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size); + case UNORDERED: + case LT: + case LE: + case EQ: break; - - case POST_INC: - /* (mem (post_inc reg)) - => access location by using register which will be post increment, - use "lbsi.bi / lhsi.bi" */ - snprintf (pattern, sizeof (pattern), - "l%csi.bi\t%%0, %%1, %d", size, byte); + case ORDERED: + case NE: + new_code = reverse_condition (new_code); + reverse = 1; + break; + case UNGT: + case UNGE: + new_code = reverse_condition_maybe_unordered (new_code); + reverse = 1; break; + case UNLT: + case UNLE: + new_code = reverse_condition_maybe_unordered (new_code); + tmp = cmp_op0; + cmp_op0 = cmp_op1; + cmp_op1 = tmp; + new_code = swap_condition (new_code); + reverse = 1; + break; + default: + return; + } - case POST_DEC: - /* (mem (post_dec reg)) - => access location by using register which will be post decrement, - use "lbsi.bi / lhsi.bi" */ - snprintf (pattern, sizeof (pattern), - "l%csi.bi\t%%0, %%1, -%d", size, byte); + tmp_reg = gen_reg_rtx (SImode); + emit_insn (gen_rtx_SET (tmp_reg, + gen_rtx_fmt_ee (new_code, SImode, + cmp_op0, cmp_op1))); + + PUT_CODE (operands[0], reverse ? EQ : NE); + emit_insn (gen_cbranchsi4 (operands[0], tmp_reg, + const0_rtx, operands[3])); +} + +void +nds32_expand_float_cstore (rtx *operands) +{ + enum rtx_code code = GET_CODE (operands[1]); + enum rtx_code new_code = code; + enum machine_mode mode = GET_MODE (operands[2]); + + rtx cmp_op0 = operands[2]; + rtx cmp_op1 = operands[3]; + rtx tmp; + + /* Main Goal: Use compare instruction to store value. + + For example: + GT, GE: swap condition and swap operands. + reg_R = (reg_A > reg_B) --> fcmplt reg_R, reg_B, reg_A + reg_R = (reg_A >= reg_B) --> fcmple reg_R, reg_B, reg_A + + LT, LE, EQ: no need to change, it is already LT, LE, EQ. + reg_R = (reg_A < reg_B) --> fcmplt reg_R, reg_A, reg_B + reg_R = (reg_A <= reg_B) --> fcmple reg_R, reg_A, reg_B + reg_R = (reg_A == reg_B) --> fcmpeq reg_R, reg_A, reg_B + + ORDERED: reverse condition and using xor insturction to achieve 'ORDERED'. + reg_R = (reg_A != reg_B) --> fcmpun reg_R, reg_A, reg_B + xor reg_R, reg_R, const1_rtx + + NE: reverse condition and using xor insturction to achieve 'NE'. + reg_R = (reg_A != reg_B) --> fcmpeq reg_R, reg_A, reg_B + xor reg_R, reg_R, const1_rtx */ + switch (code) + { + case GT: + case GE: + tmp = cmp_op0; + cmp_op0 = cmp_op1; + cmp_op1 =tmp; + new_code = swap_condition (new_code); break; + case UNORDERED: + case LT: + case LE: + case EQ: + break; + case ORDERED: + if (mode == SFmode) + emit_insn (gen_cmpsf_un (operands[0], cmp_op0, cmp_op1)); + else + emit_insn (gen_cmpdf_un (operands[0], cmp_op0, cmp_op1)); - case POST_MODIFY: - switch (GET_CODE (XEXP (XEXP (code, 1), 1))) + emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx)); + return; + case NE: + if (mode == SFmode) + emit_insn (gen_cmpsf_eq (operands[0], cmp_op0, cmp_op1)); + else + emit_insn (gen_cmpdf_eq (operands[0], cmp_op0, cmp_op1)); + + emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx)); + return; + default: + return; + } + + emit_insn (gen_rtx_SET (operands[0], + gen_rtx_fmt_ee (new_code, SImode, + cmp_op0, cmp_op1))); +} + +enum nds32_expand_result_type +nds32_expand_movcc (rtx *operands) +{ + enum rtx_code code = GET_CODE (operands[1]); + enum rtx_code new_code = code; + enum machine_mode cmp0_mode = GET_MODE (XEXP (operands[1], 0)); + rtx cmp_op0 = XEXP (operands[1], 0); + rtx cmp_op1 = XEXP (operands[1], 1); + rtx tmp; + + if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE) + && XEXP (operands[1], 1) == const0_rtx) + { + /* If the operands[1] rtx is already (eq X 0) or (ne X 0), + we have gcc generate original template rtx. */ + return EXPAND_CREATE_TEMPLATE; + } + else if ((TARGET_FPU_SINGLE && cmp0_mode == SFmode) + || (TARGET_FPU_DOUBLE && cmp0_mode == DFmode)) + { + nds32_expand_float_movcc (operands); + } + else + { + /* Since there is only 'slt'(Set when Less Than) instruction for + comparison in Andes ISA, the major strategy we use here is to + convert conditional move into 'LT + EQ' or 'LT + NE' rtx combination. + We design constraints properly so that the reload phase will assist + to make one source operand to use same register as result operand. + Then we can use cmovz/cmovn to catch the other source operand + which has different register. */ + int reverse = 0; + + /* Main Goal: Use 'LT + EQ' or 'LT + NE' to target "then" part + Strategy : Reverse condition and swap comparison operands + + For example: + + a <= b ? P : Q (LE or LEU) + --> a > b ? Q : P (reverse condition) + --> b < a ? Q : P (swap comparison operands to achieve 'LT/LTU') + + a >= b ? P : Q (GE or GEU) + --> a < b ? Q : P (reverse condition to achieve 'LT/LTU') + + a < b ? P : Q (LT or LTU) + --> (NO NEED TO CHANGE, it is already 'LT/LTU') + + a > b ? P : Q (GT or GTU) + --> b < a ? P : Q (swap comparison operands to achieve 'LT/LTU') */ + switch (code) { - case REG: - case SUBREG: - /* (mem (post_modify (reg) (plus (reg) (reg)))) - => access location by using register which will be - post modified with reg, - use "lbs.bi/ lhs.bi" */ - snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size); + case GE: case GEU: case LE: case LEU: + new_code = reverse_condition (code); + reverse = 1; break; - case CONST_INT: - /* (mem (post_modify (reg) (plus (reg) (const_int)))) - => access location by using register which will be - post modified with const_int, - use "lbsi.bi/ lhsi.bi" */ - snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size); + case EQ: + case NE: + /* no need to reverse condition */ break; default: - abort (); + return EXPAND_FAIL; } - break; - case PLUS: - switch (GET_CODE (XEXP (code, 1))) + /* For '>' comparison operator, we swap operands + so that we can have 'LT/LTU' operator. */ + if (new_code == GT || new_code == GTU) { - case REG: - case SUBREG: - /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) - use "lbs / lhs" */ - snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size); + tmp = cmp_op0; + cmp_op0 = cmp_op1; + cmp_op1 = tmp; + + new_code = swap_condition (new_code); + } + + /* Use a temporary register to store slt/slts result. */ + tmp = gen_reg_rtx (SImode); + + if (new_code == EQ || new_code == NE) + { + emit_insn (gen_xorsi3 (tmp, cmp_op0, cmp_op1)); + /* tmp == 0 if cmp_op0 == cmp_op1. */ + operands[1] = gen_rtx_fmt_ee (new_code, VOIDmode, tmp, const0_rtx); + } + else + { + /* This emit_insn will create corresponding 'slt/slts' + insturction. */ + if (new_code == LT) + emit_insn (gen_slts_compare (tmp, cmp_op0, cmp_op1)); + else if (new_code == LTU) + emit_insn (gen_slt_compare (tmp, cmp_op0, cmp_op1)); + else + gcc_unreachable (); + + /* Change comparison semantic into (eq X 0) or (ne X 0) behavior + so that cmovz or cmovn will be matched later. + + For reverse condition cases, we want to create a semantic that: + (eq X 0) --> pick up "else" part + For normal cases, we want to create a semantic that: + (ne X 0) --> pick up "then" part + + Later we will have cmovz/cmovn instruction pattern to + match corresponding behavior and output instruction. */ + operands[1] = gen_rtx_fmt_ee (reverse ? EQ : NE, + VOIDmode, tmp, const0_rtx); + } + } + return EXPAND_CREATE_TEMPLATE; +} + +void +nds32_expand_float_movcc (rtx *operands) +{ + if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE) + && GET_MODE (XEXP (operands[1], 0)) == SImode + && XEXP (operands[1], 1) == const0_rtx) + { + /* If the operands[1] rtx is already (eq X 0) or (ne X 0), + we have gcc generate original template rtx. */ + return; + } + else + { + enum rtx_code code = GET_CODE (operands[1]); + enum rtx_code new_code = code; + enum machine_mode cmp0_mode = GET_MODE (XEXP (operands[1], 0)); + enum machine_mode cmp1_mode = GET_MODE (XEXP (operands[1], 1)); + rtx cmp_op0 = XEXP (operands[1], 0); + rtx cmp_op1 = XEXP (operands[1], 1); + rtx tmp; + + /* Compare instruction Operations: (cmp_op0 condition cmp_op1) ? 1 : 0, + when result is 1, and 'reverse' be set 1 for fcmovzs instructuin. */ + int reverse = 0; + + /* Main Goal: Use cmpare instruction + conditional move instruction. + Strategy : swap condition and swap comparison operands. + + For example: + a > b ? P : Q (GT) + --> a < b ? Q : P (swap condition) + --> b < a ? Q : P (swap comparison operands to achieve 'GT') + + a >= b ? P : Q (GE) + --> a <= b ? Q : P (swap condition) + --> b <= a ? Q : P (swap comparison operands to achieve 'GE') + + a < b ? P : Q (LT) + --> (NO NEED TO CHANGE, it is already 'LT') + + a >= b ? P : Q (LE) + --> (NO NEED TO CHANGE, it is already 'LE') + + a == b ? P : Q (EQ) + --> (NO NEED TO CHANGE, it is already 'EQ') */ + + switch (code) + { + case GT: + case GE: + tmp = cmp_op0; + cmp_op0 = cmp_op1; + cmp_op1 =tmp; + new_code = swap_condition (new_code); break; - case CONST_INT: - /* (mem (plus reg const_int)) - => access location by adding one register with const_int, - use "lbsi / lhsi" */ - snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size); + case UNORDERED: + case LT: + case LE: + case EQ: + break; + case ORDERED: + case NE: + reverse = 1; + new_code = reverse_condition (new_code); + break; + case UNGT: + case UNGE: + new_code = reverse_condition_maybe_unordered (new_code); + reverse = 1; + break; + case UNLT: + case UNLE: + new_code = reverse_condition_maybe_unordered (new_code); + tmp = cmp_op0; + cmp_op0 = cmp_op1; + cmp_op1 = tmp; + new_code = swap_condition (new_code); + reverse = 1; break; default: - abort (); + return; } - break; - case LO_SUM: - operands[2] = XEXP (code, 1); - operands[1] = XEXP (code, 0); - snprintf (pattern, sizeof (pattern), - "l%csi\t%%0, [%%1 + lo12(%%2)]", size); - break; + /* Use a temporary register to store fcmpxxs result. */ + tmp = gen_reg_rtx (SImode); + + /* Create float compare instruction for SFmode and DFmode, + other MODE using cstoresi create compare instruction. */ + if ((cmp0_mode == DFmode || cmp0_mode == SFmode) + && (cmp1_mode == DFmode || cmp1_mode == SFmode)) + { + /* This emit_insn create corresponding float compare instruction */ + emit_insn (gen_rtx_SET (tmp, + gen_rtx_fmt_ee (new_code, SImode, + cmp_op0, cmp_op1))); + } + else + { + /* This emit_insn using cstoresi create corresponding + compare instruction */ + PUT_CODE (operands[1], new_code); + emit_insn (gen_cstoresi4 (tmp, operands[1], + cmp_op0, cmp_op1)); + } + /* operands[1] crete corresponding condition move instruction + for fcmovzs and fcmovns. */ + operands[1] = gen_rtx_fmt_ee (reverse ? EQ : NE, + VOIDmode, tmp, const0_rtx); + } +} + +void +nds32_emit_push_fpr_callee_saved (int base_offset) +{ + rtx fpu_insn; + rtx reg, mem; + unsigned int regno = cfun->machine->callee_saved_first_fpr_regno; + unsigned int last_fpr = cfun->machine->callee_saved_last_fpr_regno; + + while (regno <= last_fpr) + { + /* Handling two registers, using fsdi instruction. */ + reg = gen_rtx_REG (DFmode, regno); + mem = gen_frame_mem (DFmode, plus_constant (Pmode, + stack_pointer_rtx, + base_offset)); + base_offset += 8; + regno += 2; + fpu_insn = emit_move_insn (mem, reg); + RTX_FRAME_RELATED_P (fpu_insn) = 1; + } +} + +void +nds32_emit_pop_fpr_callee_saved (int gpr_padding_size) +{ + rtx fpu_insn; + rtx reg, mem, addr; + rtx dwarf, adjust_sp_rtx; + unsigned int regno = cfun->machine->callee_saved_first_fpr_regno; + unsigned int last_fpr = cfun->machine->callee_saved_last_fpr_regno; + int padding = 0; + + while (regno <= last_fpr) + { + /* Handling two registers, using fldi.bi instruction. */ + if ((regno + 1) >= last_fpr) + padding = gpr_padding_size; + + reg = gen_rtx_REG (DFmode, (regno)); + addr = gen_rtx_POST_MODIFY (Pmode, stack_pointer_rtx, + gen_rtx_PLUS (Pmode, stack_pointer_rtx, + GEN_INT (8 + padding))); + mem = gen_frame_mem (DFmode, addr); + regno += 2; + fpu_insn = emit_move_insn (reg, mem); + + adjust_sp_rtx = + gen_rtx_SET (stack_pointer_rtx, + plus_constant (Pmode, stack_pointer_rtx, + 8 + padding)); + + dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, NULL_RTX); + /* Tell gcc we adjust SP in this insn. */ + dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, copy_rtx (adjust_sp_rtx), + dwarf); + RTX_FRAME_RELATED_P (fpu_insn) = 1; + REG_NOTES (fpu_insn) = dwarf; + } +} + +void +nds32_emit_v3pop_fpr_callee_saved (int base) +{ + int fpu_base_addr = base; + int regno; + rtx fpu_insn; + rtx reg, mem; + rtx dwarf; + + regno = cfun->machine->callee_saved_first_fpr_regno; + while (regno <= cfun->machine->callee_saved_last_fpr_regno) + { + /* Handling two registers, using fldi instruction. */ + reg = gen_rtx_REG (DFmode, regno); + mem = gen_frame_mem (DFmode, plus_constant (Pmode, + stack_pointer_rtx, + fpu_base_addr)); + fpu_base_addr += 8; + regno += 2; + fpu_insn = emit_move_insn (reg, mem); + dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, NULL_RTX); + RTX_FRAME_RELATED_P (fpu_insn) = 1; + REG_NOTES (fpu_insn) = dwarf; + } +} + +enum nds32_expand_result_type +nds32_expand_extv (rtx *operands) +{ + gcc_assert (CONST_INT_P (operands[2]) && CONST_INT_P (operands[3])); + HOST_WIDE_INT width = INTVAL (operands[2]); + HOST_WIDE_INT bitpos = INTVAL (operands[3]); + rtx dst = operands[0]; + rtx src = operands[1]; + + if (MEM_P (src) + && width == 32 + && (bitpos % BITS_PER_UNIT) == 0 + && GET_MODE_BITSIZE (GET_MODE (dst)) == width) + { + rtx newmem = adjust_address (src, GET_MODE (dst), + bitpos / BITS_PER_UNIT); + + rtx base_addr = force_reg (Pmode, XEXP (newmem, 0)); + + emit_insn (gen_unaligned_loadsi (dst, base_addr)); + + return EXPAND_DONE; + } + return EXPAND_FAIL; +} + +enum nds32_expand_result_type +nds32_expand_insv (rtx *operands) +{ + gcc_assert (CONST_INT_P (operands[1]) && CONST_INT_P (operands[2])); + HOST_WIDE_INT width = INTVAL (operands[1]); + HOST_WIDE_INT bitpos = INTVAL (operands[2]); + rtx dst = operands[0]; + rtx src = operands[3]; + + if (MEM_P (dst) + && width == 32 + && (bitpos % BITS_PER_UNIT) == 0 + && GET_MODE_BITSIZE (GET_MODE (src)) == width) + { + rtx newmem = adjust_address (dst, GET_MODE (src), + bitpos / BITS_PER_UNIT); + + rtx base_addr = force_reg (Pmode, XEXP (newmem, 0)); + + emit_insn (gen_unaligned_storesi (base_addr, src)); + + return EXPAND_DONE; + } + return EXPAND_FAIL; +} + +/* ------------------------------------------------------------------------ */ + +/* PART 3: Auxiliary function for output asm template. */ + +/* Function to generate PC relative jump table. + Refer to nds32.md for more details. + + The following is the sample for the case that diff value + can be presented in '.short' size. + + addi $r1, $r1, -(case_lower_bound) + slti $ta, $r1, (case_number) + beqz $ta, .L_skip_label + + la $ta, .L35 ! get jump table address + lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry + addi $ta, $r1, $ta + jr5 $ta + + ! jump table entry + L35: + .short .L25-.L35 + .short .L26-.L35 + .short .L27-.L35 + .short .L28-.L35 + .short .L29-.L35 + .short .L30-.L35 + .short .L31-.L35 + .short .L32-.L35 + .short .L33-.L35 + .short .L34-.L35 */ +const char * +nds32_output_casesi_pc_relative (rtx *operands) +{ + enum machine_mode mode; + rtx diff_vec; + + diff_vec = PATTERN (NEXT_INSN (as_a (operands[1]))); + + gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC); + + /* Step C: "t <-- operands[1]". */ + if (flag_pic) + { + output_asm_insn ("sethi\t$ta, hi20(%l1@GOTOFF)", operands); + output_asm_insn ("ori\t$ta, $ta, lo12(%l1@GOTOFF)", operands); + output_asm_insn ("add\t$ta, $ta, $gp", operands); + } + else + output_asm_insn ("la\t$ta, %l1", operands); + + /* Get the mode of each element in the difference vector. */ + mode = GET_MODE (diff_vec); + /* Step D: "z <-- (mem (plus (operands[0] << m) t))", + where m is 0, 1, or 2 to load address-diff value from table. */ + switch (mode) + { + case QImode: + output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands); + break; + case HImode: + output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands); + break; + case SImode: + output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands); + break; default: - abort (); + gcc_unreachable (); } - output_asm_insn (pattern, operands); - return ""; + /* Step E: "t <-- z + t". + Add table label_ref with address-diff value to + obtain target case address. */ + output_asm_insn ("add\t$ta, %2, $ta", operands); + + /* Step F: jump to target with register t. */ + if (TARGET_16_BIT) + return "jr5\t$ta"; + else + return "jr\t$ta"; } -/* Function to output stack push operation. - We need to deal with normal stack push multiple or stack v3push. */ +/* Function to generate normal jump table. */ const char * -nds32_output_stack_push (rtx par_rtx) +nds32_output_casesi (rtx *operands) { - /* A string pattern for output_asm_insn(). */ - char pattern[100]; - /* The operands array which will be used in output_asm_insn(). */ - rtx operands[3]; - /* Pick up varargs first regno and last regno for further use. */ - int rb_va_args = cfun->machine->va_args_first_regno; - int re_va_args = cfun->machine->va_args_last_regno; - int last_argument_regno = NDS32_FIRST_GPR_REGNUM - + NDS32_MAX_GPR_REGS_FOR_ARGS - - 1; - /* Pick up callee-saved first regno and last regno for further use. */ - int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno; - int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno; + /* Step C: "t <-- operands[1]". */ + if (flag_pic) + { + output_asm_insn ("sethi\t$ta, hi20(%l1@GOTOFF)", operands); + output_asm_insn ("ori\t$ta, $ta, lo12(%l1@GOTOFF)", operands); + output_asm_insn ("add\t$ta, $ta, $gp", operands); + } + else + output_asm_insn ("la\t$ta, %l1", operands); - /* First we need to check if we are pushing argument registers not used - for the named arguments. If so, we have to create 'smw.adm' (push.s) - instruction. */ - if (reg_mentioned_p (gen_rtx_REG (SImode, last_argument_regno), par_rtx)) + /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */ + output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands); + + /* No need to perform Step E, which is only used for + pc relative jump table. */ + + /* Step F: jump to target with register z. */ + if (TARGET_16_BIT) + return "jr5\t%2"; + else + return "jr\t%2"; +} + + +/* Function to return memory format. */ +enum nds32_16bit_address_type +nds32_mem_format (rtx op) +{ + enum 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); + + /* 45 format. */ + if (GET_CODE (op) == REG + && ((mode_test == SImode) || (mode_test == SFmode))) + return ADDRESS_REG; + + /* 333 format for QI/HImode. */ + if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM)) + return ADDRESS_LO_REG_IMM3U; + + /* post_inc 333 format. */ + if ((GET_CODE (op) == POST_INC) + && ((mode_test == SImode) || (mode_test == SFmode))) { - /* Set operands[0] and operands[1]. */ - operands[0] = gen_rtx_REG (SImode, rb_va_args); - operands[1] = gen_rtx_REG (SImode, re_va_args); - /* Create assembly code pattern: "Rb, Re, { }". */ - snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }"); - /* We use output_asm_insn() to output assembly code by ourself. */ - output_asm_insn (pattern, operands); - return ""; + regno = REGNO(XEXP (op, 0)); + + if (regno < 8) + return ADDRESS_POST_INC_LO_REG_IMM3U; + } + + /* post_inc 333 format. */ + if ((GET_CODE (op) == POST_MODIFY) + && ((mode_test == SImode) || (mode_test == SFmode)) + && (REG_P (XEXP (XEXP (op, 1), 0))) + && (CONST_INT_P (XEXP (XEXP (op, 1), 1)))) + { + regno = REGNO (XEXP (XEXP (op, 1), 0)); + val = INTVAL (XEXP (XEXP (op, 1), 1)); + if (regno < 8 && val > 0 && val < 32) + return ADDRESS_POST_MODIFY_LO_REG_IMM3U; } - /* If we step here, we are going to do v3push or multiple push operation. */ + if ((GET_CODE (op) == PLUS) + && (GET_CODE (XEXP (op, 0)) == REG) + && (GET_CODE (XEXP (op, 1)) == CONST_INT)) + { + val = INTVAL (XEXP (op, 1)); + + regno = REGNO(XEXP (op, 0)); + + if (regno > 8 + && regno != SP_REGNUM + && regno != FP_REGNUM) + return ADDRESS_NOT_16BIT_FORMAT; + + switch (mode_test) + { + case QImode: + /* 333 format. */ + if (val >= 0 && val < 8 && regno < 8) + return ADDRESS_LO_REG_IMM3U; + break; + + case HImode: + /* 333 format. */ + if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8) + return ADDRESS_LO_REG_IMM3U; + break; + + case SImode: + case SFmode: + case DFmode: + /* r8 imply fe format. */ + if ((regno == 8) && + (val >= -128 && val <= -4 && (val % 4 == 0))) + return ADDRESS_R8_IMM7U; + /* fp imply 37 format. */ + if ((regno == FP_REGNUM) && + (val >= 0 && val < 512 && (val % 4 == 0))) + return ADDRESS_FP_IMM7U; + /* sp imply 37 format. */ + else if ((regno == SP_REGNUM) && + (val >= 0 && val < 512 && (val % 4 == 0))) + return ADDRESS_SP_IMM7U; + /* 333 format. */ + else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8) + return ADDRESS_LO_REG_IMM3U; + break; + + default: + break; + } + } + + return ADDRESS_NOT_16BIT_FORMAT; +} + +/* Output 16-bit store. */ +const char * +nds32_output_16bit_store (rtx *operands, int byte) +{ + char pattern[100]; + char size; + rtx code = XEXP (operands[0], 0); + + size = nds32_byte_to_size (byte); + + switch (nds32_mem_format (operands[0])) + { + case ADDRESS_REG: + operands[0] = code; + output_asm_insn ("swi450\t%1, [%0]", operands); + break; + case ADDRESS_LO_REG_IMM3U: + snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size); + output_asm_insn (pattern, operands); + break; + case ADDRESS_POST_INC_LO_REG_IMM3U: + snprintf (pattern, sizeof (pattern), "swi333.bi\t%%1, %%0, 4"); + output_asm_insn (pattern, operands); + break; + case ADDRESS_POST_MODIFY_LO_REG_IMM3U: + snprintf (pattern, sizeof (pattern), "swi333.bi\t%%1, %%0"); + output_asm_insn (pattern, operands); + break; + case ADDRESS_FP_IMM7U: + output_asm_insn ("swi37\t%1, %0", operands); + break; + case ADDRESS_SP_IMM7U: + /* Get immediate value and set back to operands[1]. */ + operands[0] = XEXP (code, 1); + output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands); + break; + default: + break; + } + + return ""; +} + +/* Output 16-bit load. */ +const char * +nds32_output_16bit_load (rtx *operands, int byte) +{ + char pattern[100]; + unsigned char size; + rtx code = XEXP (operands[1], 0); + + size = nds32_byte_to_size (byte); + + switch (nds32_mem_format (operands[1])) + { + case ADDRESS_REG: + operands[1] = code; + output_asm_insn ("lwi450\t%0, [%1]", operands); + break; + case ADDRESS_LO_REG_IMM3U: + snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size); + output_asm_insn (pattern, operands); + break; + case ADDRESS_POST_INC_LO_REG_IMM3U: + snprintf (pattern, sizeof (pattern), "lwi333.bi\t%%0, %%1, 4"); + output_asm_insn (pattern, operands); + break; + case ADDRESS_POST_MODIFY_LO_REG_IMM3U: + snprintf (pattern, sizeof (pattern), "lwi333.bi\t%%0, %%1"); + output_asm_insn (pattern, operands); + break; + case ADDRESS_R8_IMM7U: + output_asm_insn ("lwi45.fe\t%0, %e1", operands); + break; + case ADDRESS_FP_IMM7U: + output_asm_insn ("lwi37\t%0, %1", operands); + break; + case ADDRESS_SP_IMM7U: + /* Get immediate value and set back to operands[0]. */ + operands[1] = XEXP (code, 1); + output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands); + break; + default: + break; + } + + return ""; +} + +/* Output 32-bit store. */ +const char * +nds32_output_32bit_store (rtx *operands, int byte) +{ + char pattern[100]; + unsigned char size; + rtx code = XEXP (operands[0], 0); + + size = nds32_byte_to_size (byte); + + switch (GET_CODE (code)) + { + case REG: + /* (mem (reg X)) + => access location by using register, + use "sbi / shi / swi" */ + snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size); + break; + + case SYMBOL_REF: + case CONST: + /* (mem (symbol_ref X)) + (mem (const (...))) + => access global variables, + use "sbi.gp / shi.gp / swi.gp" */ + operands[0] = XEXP (operands[0], 0); + snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size); + break; + + case POST_INC: + /* (mem (post_inc reg)) + => access location by using register which will be post increment, + use "sbi.bi / shi.bi / swi.bi" */ + snprintf (pattern, sizeof (pattern), + "s%ci.bi\t%%1, %%0, %d", size, byte); + break; + + case POST_DEC: + /* (mem (post_dec reg)) + => access location by using register which will be post decrement, + use "sbi.bi / shi.bi / swi.bi" */ + snprintf (pattern, sizeof (pattern), + "s%ci.bi\t%%1, %%0, -%d", size, byte); + break; + + case POST_MODIFY: + switch (GET_CODE (XEXP (XEXP (code, 1), 1))) + { + case REG: + case SUBREG: + /* (mem (post_modify (reg) (plus (reg) (reg)))) + => access location by using register which will be + post modified with reg, + use "sb.bi/ sh.bi / sw.bi" */ + snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size); + break; + case CONST_INT: + /* (mem (post_modify (reg) (plus (reg) (const_int)))) + => access location by using register which will be + post modified with const_int, + use "sbi.bi/ shi.bi / swi.bi" */ + snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size); + break; + default: + abort (); + } + break; + + case PLUS: + switch (GET_CODE (XEXP (code, 1))) + { + case REG: + case SUBREG: + /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) + => access location by adding two registers, + use "sb / sh / sw" */ + snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size); + break; + case CONST_INT: + /* (mem (plus reg const_int)) + => access location by adding one register with const_int, + use "sbi / shi / swi" */ + snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size); + break; + default: + abort (); + } + break; + + case LO_SUM: + operands[2] = XEXP (code, 1); + operands[0] = XEXP (code, 0); + snprintf (pattern, sizeof (pattern), + "s%ci\t%%1, [%%0 + lo12(%%2)]", size); + break; + + default: + abort (); + } + + output_asm_insn (pattern, operands); + return ""; +} + +/* Output 32-bit load. */ +const char * +nds32_output_32bit_load (rtx *operands, int byte) +{ + char pattern[100]; + unsigned char size; + rtx code; + + code = XEXP (operands[1], 0); + + size = nds32_byte_to_size (byte); + + switch (GET_CODE (code)) + { + case REG: + /* (mem (reg X)) + => access location by using register, + use "lbi / lhi / lwi" */ + snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size); + break; + + case SYMBOL_REF: + case CONST: + /* (mem (symbol_ref X)) + (mem (const (...))) + => access global variables, + use "lbi.gp / lhi.gp / lwi.gp" */ + operands[1] = XEXP (operands[1], 0); + snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size); + break; + + case POST_INC: + /* (mem (post_inc reg)) + => access location by using register which will be post increment, + use "lbi.bi / lhi.bi / lwi.bi" */ + snprintf (pattern, sizeof (pattern), + "l%ci.bi\t%%0, %%1, %d", size, byte); + break; + + case POST_DEC: + /* (mem (post_dec reg)) + => access location by using register which will be post decrement, + use "lbi.bi / lhi.bi / lwi.bi" */ + snprintf (pattern, sizeof (pattern), + "l%ci.bi\t%%0, %%1, -%d", size, byte); + break; + + case POST_MODIFY: + switch (GET_CODE (XEXP (XEXP (code, 1), 1))) + { + case REG: + case SUBREG: + /* (mem (post_modify (reg) (plus (reg) (reg)))) + => access location by using register which will be + post modified with reg, + use "lb.bi/ lh.bi / lw.bi" */ + snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size); + break; + case CONST_INT: + /* (mem (post_modify (reg) (plus (reg) (const_int)))) + => access location by using register which will be + post modified with const_int, + use "lbi.bi/ lhi.bi / lwi.bi" */ + snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size); + break; + default: + abort (); + } + break; + + case PLUS: + switch (GET_CODE (XEXP (code, 1))) + { + case REG: + case SUBREG: + /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) + use "lb / lh / lw" */ + snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size); + break; + case CONST_INT: + /* (mem (plus reg const_int)) + => access location by adding one register with const_int, + use "lbi / lhi / lwi" */ + snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size); + break; + default: + abort (); + } + break; + + case LO_SUM: + operands[2] = XEXP (code, 1); + operands[1] = XEXP (code, 0); + snprintf (pattern, sizeof (pattern), + "l%ci\t%%0, [%%1 + lo12(%%2)]", size); + break; + + default: + abort (); + } + + output_asm_insn (pattern, operands); + return ""; +} + +/* Output 32-bit load with signed extension. */ +const char * +nds32_output_32bit_load_se (rtx *operands, int byte) +{ + char pattern[100]; + unsigned char size; + rtx code; + + code = XEXP (operands[1], 0); + + size = nds32_byte_to_size (byte); + + switch (GET_CODE (code)) + { + case REG: + /* (mem (reg X)) + => access location by using register, + use "lbsi / lhsi" */ + snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size); + break; + + case SYMBOL_REF: + case CONST: + /* (mem (symbol_ref X)) + (mem (const (...))) + => access global variables, + use "lbsi.gp / lhsi.gp" */ + operands[1] = XEXP (operands[1], 0); + snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size); + break; + + case POST_INC: + /* (mem (post_inc reg)) + => access location by using register which will be post increment, + use "lbsi.bi / lhsi.bi" */ + snprintf (pattern, sizeof (pattern), + "l%csi.bi\t%%0, %%1, %d", size, byte); + break; + + case POST_DEC: + /* (mem (post_dec reg)) + => access location by using register which will be post decrement, + use "lbsi.bi / lhsi.bi" */ + snprintf (pattern, sizeof (pattern), + "l%csi.bi\t%%0, %%1, -%d", size, byte); + break; + + case POST_MODIFY: + switch (GET_CODE (XEXP (XEXP (code, 1), 1))) + { + case REG: + case SUBREG: + /* (mem (post_modify (reg) (plus (reg) (reg)))) + => access location by using register which will be + post modified with reg, + use "lbs.bi/ lhs.bi" */ + snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size); + break; + case CONST_INT: + /* (mem (post_modify (reg) (plus (reg) (const_int)))) + => access location by using register which will be + post modified with const_int, + use "lbsi.bi/ lhsi.bi" */ + snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size); + break; + default: + abort (); + } + break; + + case PLUS: + switch (GET_CODE (XEXP (code, 1))) + { + case REG: + case SUBREG: + /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg)) + use "lbs / lhs" */ + snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size); + break; + case CONST_INT: + /* (mem (plus reg const_int)) + => access location by adding one register with const_int, + use "lbsi / lhsi" */ + snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size); + break; + default: + abort (); + } + break; + + case LO_SUM: + operands[2] = XEXP (code, 1); + operands[1] = XEXP (code, 0); + snprintf (pattern, sizeof (pattern), + "l%csi\t%%0, [%%1 + lo12(%%2)]", size); + break; + + default: + abort (); + } + + output_asm_insn (pattern, operands); + return ""; +} + +/* Function to output stack push operation. + We need to deal with normal stack push multiple or stack v3push. */ +const char * +nds32_output_stack_push (rtx par_rtx) +{ + /* A string pattern for output_asm_insn(). */ + char pattern[100]; + /* The operands array which will be used in output_asm_insn(). */ + rtx operands[3]; + /* Pick up varargs first regno and last regno for further use. */ + int rb_va_args = cfun->machine->va_args_first_regno; + int re_va_args = cfun->machine->va_args_last_regno; + int last_argument_regno = NDS32_FIRST_GPR_REGNUM + + NDS32_MAX_GPR_REGS_FOR_ARGS + - 1; + /* Pick up first and last eh data regno for further use. */ + int rb_eh_data = cfun->machine->eh_return_data_first_regno; + int re_eh_data = cfun->machine->eh_return_data_last_regno; + int first_eh_data_regno = EH_RETURN_DATA_REGNO (0); + /* Pick up callee-saved first regno and last regno for further use. */ + int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno; + int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno; + + /* First we need to check if we are pushing argument registers not used + for the named arguments. If so, we have to create 'smw.adm' (push.s) + instruction. */ + if (reg_mentioned_p (gen_rtx_REG (SImode, last_argument_regno), par_rtx)) + { + /* Set operands[0] and operands[1]. */ + operands[0] = gen_rtx_REG (SImode, rb_va_args); + operands[1] = gen_rtx_REG (SImode, re_va_args); + /* Create assembly code pattern: "Rb, Re, { }". */ + snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }"); + /* We use output_asm_insn() to output assembly code by ourself. */ + output_asm_insn (pattern, operands); + return ""; + } + + /* If last_argument_regno is not mentioned in par_rtx, we can confirm that + we do not need to push argument registers for variadic function. + But we still need to check if we need to push exception handling + data registers. */ + if (reg_mentioned_p (gen_rtx_REG (SImode, first_eh_data_regno), par_rtx)) + { + /* Set operands[0] and operands[1]. */ + operands[0] = gen_rtx_REG (SImode, rb_eh_data); + operands[1] = gen_rtx_REG (SImode, re_eh_data); + /* Create assembly code pattern: "Rb, Re, { }". */ + snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }"); + /* We use output_asm_insn() to output assembly code by ourself. */ + output_asm_insn (pattern, operands); + return ""; + } + + /* If we step here, we are going to do v3push or multiple push operation. */ + + /* Refer to nds32.h, where we comment when push25/pop25 are available. */ + if (NDS32_V3PUSH_AVAILABLE_P) + { + /* For stack v3push: + operands[0]: Re + operands[1]: imm8u */ + + /* This variable is to check if 'push25 Re,imm8u' is available. */ + int sp_adjust; + + /* Set operands[0]. */ + operands[0] = gen_rtx_REG (SImode, re_callee_saved); + + /* Check if we can generate 'push25 Re,imm8u', + otherwise, generate 'push25 Re,0'. */ + sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) + && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)) + operands[1] = GEN_INT (sp_adjust); + else + { + /* Allocate callee saved fpr space. */ + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + sp_adjust = cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + operands[1] = GEN_INT (sp_adjust); + } + else + { + operands[1] = GEN_INT (0); + } + } + + /* Create assembly code pattern. */ + snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1"); + } + else + { + /* For normal stack push multiple: + operands[0]: Rb + operands[1]: Re + operands[2]: En4 */ + + /* This variable is used to check if we only need to generate En4 field. + As long as Rb==Re=SP_REGNUM, we set this variable to 1. */ + int push_en4_only_p = 0; + + /* Set operands[0] and operands[1]. */ + operands[0] = gen_rtx_REG (SImode, rb_callee_saved); + operands[1] = gen_rtx_REG (SImode, re_callee_saved); + + /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */ + if (!cfun->machine->fp_size + && !cfun->machine->gp_size + && !cfun->machine->lp_size + && REGNO (operands[0]) == SP_REGNUM + && REGNO (operands[1]) == SP_REGNUM) + { + /* No need to generate instruction. */ + return ""; + } + else + { + /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */ + if (REGNO (operands[0]) == SP_REGNUM + && REGNO (operands[1]) == SP_REGNUM) + push_en4_only_p = 1; + + /* Create assembly code pattern. + We need to handle the form: "Rb, Re, { $fp $gp $lp }". */ + snprintf (pattern, sizeof (pattern), + "push.s\t%s{%s%s%s }", + push_en4_only_p ? "" : "%0, %1, ", + cfun->machine->fp_size ? " $fp" : "", + cfun->machine->gp_size ? " $gp" : "", + cfun->machine->lp_size ? " $lp" : ""); + } + } + + /* We use output_asm_insn() to output assembly code by ourself. */ + output_asm_insn (pattern, operands); + return ""; +} + +/* Function to output stack pop operation. + We need to deal with normal stack pop multiple or stack v3pop. */ +const char * +nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED) +{ + /* A string pattern for output_asm_insn(). */ + char pattern[100]; + /* The operands array which will be used in output_asm_insn(). */ + rtx operands[3]; + /* Pick up first and last eh data regno for further use. */ + int rb_eh_data = cfun->machine->eh_return_data_first_regno; + int re_eh_data = cfun->machine->eh_return_data_last_regno; + int first_eh_data_regno = EH_RETURN_DATA_REGNO (0); + /* Pick up callee-saved first regno and last regno for further use. */ + int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno; + int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno; + + /* We need to check if we need to push exception handling + data registers. */ + if (reg_mentioned_p (gen_rtx_REG (SImode, first_eh_data_regno), par_rtx)) + { + /* Set operands[0] and operands[1]. */ + operands[0] = gen_rtx_REG (SImode, rb_eh_data); + operands[1] = gen_rtx_REG (SImode, re_eh_data); + /* Create assembly code pattern: "Rb, Re, { }". */ + snprintf (pattern, sizeof (pattern), "pop.s\t%s", "%0, %1, { }"); + /* We use output_asm_insn() to output assembly code by ourself. */ + output_asm_insn (pattern, operands); + return ""; + } + + /* If we step here, we are going to do v3pop or multiple pop operation. */ + + /* Refer to nds32.h, where we comment when push25/pop25 are available. */ + if (NDS32_V3PUSH_AVAILABLE_P) + { + /* For stack v3pop: + operands[0]: Re + operands[1]: imm8u */ + + /* This variable is to check if 'pop25 Re,imm8u' is available. */ + int sp_adjust; + + /* Set operands[0]. */ + operands[0] = gen_rtx_REG (SImode, re_callee_saved); + + /* Check if we can generate 'pop25 Re,imm8u', + otherwise, generate 'pop25 Re,0'. + We have to consider alloca issue as well. + If the function does call alloca(), the stack pointer is not fixed. + In that case, we cannot use 'pop25 Re,imm8u' directly. + We have to caculate stack pointer from frame pointer + and then use 'pop25 Re,0'. */ + sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) + && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust) + && !cfun->calls_alloca) + operands[1] = GEN_INT (sp_adjust); + else + { + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + /* If has fpr need to restore, the $sp on callee saved fpr + position, so we need to consider gpr pading bytes and + callee saved fpr size. */ + sp_adjust = cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + operands[1] = GEN_INT (sp_adjust); + } + else + { + operands[1] = GEN_INT (0); + } + } + + /* Create assembly code pattern. */ + snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1"); + } + else + { + /* For normal stack pop multiple: + operands[0]: Rb + operands[1]: Re + operands[2]: En4 */ + + /* This variable is used to check if we only need to generate En4 field. + As long as Rb==Re=SP_REGNUM, we set this variable to 1. */ + int pop_en4_only_p = 0; + + /* Set operands[0] and operands[1]. */ + operands[0] = gen_rtx_REG (SImode, rb_callee_saved); + operands[1] = gen_rtx_REG (SImode, re_callee_saved); + + /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */ + if (!cfun->machine->fp_size + && !cfun->machine->gp_size + && !cfun->machine->lp_size + && REGNO (operands[0]) == SP_REGNUM + && REGNO (operands[1]) == SP_REGNUM) + { + /* No need to generate instruction. */ + return ""; + } + else + { + /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */ + if (REGNO (operands[0]) == SP_REGNUM + && REGNO (operands[1]) == SP_REGNUM) + pop_en4_only_p = 1; + + /* Create assembly code pattern. + We need to handle the form: "Rb, Re, { $fp $gp $lp }". */ + snprintf (pattern, sizeof (pattern), + "pop.s\t%s{%s%s%s }", + pop_en4_only_p ? "" : "%0, %1, ", + cfun->machine->fp_size ? " $fp" : "", + cfun->machine->gp_size ? " $gp" : "", + cfun->machine->lp_size ? " $lp" : ""); + } + } + + /* We use output_asm_insn() to output assembly code by ourself. */ + output_asm_insn (pattern, operands); + return ""; +} + +/* Function to output return operation. */ +const char * +nds32_output_return (void) +{ + /* A string pattern for output_asm_insn(). */ + char pattern[100]; + /* The operands array which will be used in output_asm_insn(). */ + rtx operands[2]; + /* For stack v3pop: + operands[0]: Re + operands[1]: imm8u */ + int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno; + int sp_adjust; + + /* Set operands[0]. */ + operands[0] = gen_rtx_REG (SImode, re_callee_saved); + + /* Check if we can generate 'pop25 Re,imm8u', + otherwise, generate 'pop25 Re,0'. + We have to consider alloca issue as well. + If the function does call alloca(), the stack pointer is not fixed. + In that case, we cannot use 'pop25 Re,imm8u' directly. + We have to caculate stack pointer from frame pointer + and then use 'pop25 Re,0'. */ + sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) + && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust) + && !cfun->calls_alloca) + operands[1] = GEN_INT (sp_adjust); + else + operands[1] = GEN_INT (0); + + /* Create assembly code pattern. */ + snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1"); + /* We use output_asm_insn() to output assembly code by ourself. */ + output_asm_insn (pattern, operands); + return ""; +} + + +/* output a float load instruction */ +const char * +nds32_output_float_load (rtx *operands) +{ + char buff[100]; + const char *pattern; + rtx addr, addr_op0, addr_op1; + int dp = GET_MODE_SIZE (GET_MODE (operands[0])) == 8; + addr = XEXP (operands[1], 0); + switch (GET_CODE (addr)) + { + case REG: + pattern = "fl%ci\t%%0, %%1"; + break; + + case PLUS: + addr_op0 = XEXP (addr, 0); + addr_op1 = XEXP (addr, 1); + + if (REG_P (addr_op0) && REG_P (addr_op1)) + pattern = "fl%c\t%%0, %%1"; + else if (REG_P (addr_op0) && CONST_INT_P (addr_op1)) + pattern = "fl%ci\t%%0, %%1"; + else if (GET_CODE (addr_op0) == MULT && REG_P (addr_op1) + && REG_P (XEXP (addr_op0, 0)) + && CONST_INT_P (XEXP (addr_op0, 1))) + pattern = "fl%c\t%%0, %%1"; + else + gcc_unreachable (); + break; + + case POST_MODIFY: + addr_op0 = XEXP (addr, 0); + addr_op1 = XEXP (addr, 1); + + if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS + && REG_P (XEXP (addr_op1, 1))) + pattern = "fl%c.bi\t%%0, %%1"; + else if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS + && CONST_INT_P (XEXP (addr_op1, 1))) + pattern = "fl%ci.bi\t%%0, %%1"; + else + gcc_unreachable (); + break; + + case POST_INC: + if (REG_P (XEXP (addr, 0))) + { + if (dp) + pattern = "fl%ci.bi\t%%0, %%1, 8"; + else + pattern = "fl%ci.bi\t%%0, %%1, 4"; + } + else + gcc_unreachable (); + break; + + case POST_DEC: + if (REG_P (XEXP (addr, 0))) + { + if (dp) + pattern = "fl%ci.bi\t%%0, %%1, -8"; + else + pattern = "fl%ci.bi\t%%0, %%1, -4"; + } + else + gcc_unreachable (); + break; + + default: + gcc_unreachable (); + } + + sprintf (buff, pattern, dp ? 'd' : 's'); + output_asm_insn (buff, operands); + return ""; +} + +/* output a float store instruction */ +const char * +nds32_output_float_store (rtx *operands) +{ + char buff[100]; + const char *pattern; + rtx addr, addr_op0, addr_op1; + int dp = GET_MODE_SIZE (GET_MODE (operands[0])) == 8; + addr = XEXP (operands[0], 0); + switch (GET_CODE (addr)) + { + case REG: + pattern = "fs%ci\t%%1, %%0"; + break; + + case PLUS: + addr_op0 = XEXP (addr, 0); + addr_op1 = XEXP (addr, 1); + + if (REG_P (addr_op0) && REG_P (addr_op1)) + pattern = "fs%c\t%%1, %%0"; + else if (REG_P (addr_op0) && CONST_INT_P (addr_op1)) + pattern = "fs%ci\t%%1, %%0"; + else if (GET_CODE (addr_op0) == MULT && REG_P (addr_op1) + && REG_P (XEXP (addr_op0, 0)) + && CONST_INT_P (XEXP (addr_op0, 1))) + pattern = "fs%c\t%%1, %%0"; + else + gcc_unreachable (); + break; + + case POST_MODIFY: + addr_op0 = XEXP (addr, 0); + addr_op1 = XEXP (addr, 1); + + if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS + && REG_P (XEXP (addr_op1, 1))) + pattern = "fs%c.bi\t%%1, %%0"; + else if (REG_P (addr_op0) && GET_CODE (addr_op1) == PLUS + && CONST_INT_P (XEXP (addr_op1, 1))) + pattern = "fs%ci.bi\t%%1, %%0"; + else + gcc_unreachable (); + break; + + case POST_INC: + if (REG_P (XEXP (addr, 0))) + { + if (dp) + pattern = "fs%ci.bi\t%%1, %%0, 8"; + else + pattern = "fs%ci.bi\t%%1, %%0, 4"; + } + else + gcc_unreachable (); + break; + + case POST_DEC: + if (REG_P (XEXP (addr, 0))) + { + if (dp) + pattern = "fs%ci.bi\t%%1, %%0, -8"; + else + pattern = "fs%ci.bi\t%%1, %%0, -4"; + } + else + gcc_unreachable (); + break; + + default: + gcc_unreachable (); + } + + sprintf (buff, pattern, dp ? 'd' : 's'); + output_asm_insn (buff, operands); + return ""; +} + +const char * +nds32_output_smw_single_word (rtx *operands) +{ + char buff[100]; + unsigned regno; + int enable4; + bool update_base_p; + rtx base_addr = operands[0]; + rtx base_reg; + rtx otherops[2]; + + if (REG_P (XEXP (base_addr, 0))) + { + update_base_p = false; + base_reg = XEXP (base_addr, 0); + } + else + { + update_base_p = true; + base_reg = XEXP (XEXP (base_addr, 0), 0); + } + + const char *update_base = update_base_p ? "m" : ""; + + regno = REGNO (operands[1]); + + otherops[0] = base_reg; + otherops[1] = operands[1]; + + if (regno >= 28) + { + enable4 = nds32_regno_to_enable4 (regno); + sprintf (buff, "smw.bi%s\t$sp, [%%0], $sp, %x", update_base, enable4); + } + else + { + sprintf (buff, "smw.bi%s\t%%1, [%%0], %%1", update_base); + } + output_asm_insn (buff, otherops); + return ""; +} + +const char * +nds32_output_smw_double_word (rtx *operands) +{ + char buff[100]; + unsigned regno; + int enable4; + bool update_base_p; + rtx base_addr = operands[0]; + rtx base_reg; + rtx otherops[3]; + + if (REG_P (XEXP (base_addr, 0))) + { + update_base_p = false; + base_reg = XEXP (base_addr, 0); + } + else + { + update_base_p = true; + base_reg = XEXP (XEXP (base_addr, 0), 0); + } + + const char *update_base = update_base_p ? "m" : ""; + + regno = REGNO (operands[1]); + + otherops[0] = base_reg; + otherops[1] = operands[1]; + otherops[2] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);; + + if (regno >= 28) + { + enable4 = nds32_regno_to_enable4 (regno) + | nds32_regno_to_enable4 (regno + 1); + sprintf (buff, "smw.bi%s\t$sp, [%%0], $sp, %x", update_base, enable4); + } + else if (regno == 27) + { + enable4 = nds32_regno_to_enable4 (regno + 1); + sprintf (buff, "smw.bi%s\t%%1, [%%0], %%1, %x", update_base, enable4); + } + else + { + sprintf (buff, "smw.bi%s\t%%1, [%%0], %%2", update_base); + } + output_asm_insn (buff, otherops); + return ""; +} + + +const char * +nds32_output_lmw_single_word (rtx *operands) +{ + char buff[100]; + unsigned regno; + bool update_base_p; + int enable4; + rtx base_addr = operands[1]; + rtx base_reg; + rtx otherops[2]; + + if (REG_P (XEXP (base_addr, 0))) + { + update_base_p = false; + base_reg = XEXP (base_addr, 0); + } + else + { + update_base_p = true; + base_reg = XEXP (XEXP (base_addr, 0), 0); + } + + const char *update_base = update_base_p ? "m" : ""; + + regno = REGNO (operands[0]); + + otherops[0] = operands[0]; + otherops[1] = base_reg; + + if (regno >= 28) + { + enable4 = nds32_regno_to_enable4 (regno); + sprintf (buff, "lmw.bi%s\t$sp, [%%1], $sp, %x", update_base, enable4); + } + else + { + sprintf (buff, "lmw.bi%s\t%%0, [%%1], %%0", update_base); + } + output_asm_insn (buff, otherops); + return ""; +} + +void +nds32_expand_unaligned_load (rtx *operands, enum machine_mode mode) +{ + /* Initial memory offset. */ + int offset = WORDS_BIG_ENDIAN ? GET_MODE_SIZE (mode) - 1 : 0; + int offset_adj = WORDS_BIG_ENDIAN ? -1 : 1; + /* Initial register shift byte. */ + int shift = 0; + /* The first load byte instruction is not the same. */ + int width = GET_MODE_SIZE (mode) - 1; + rtx mem[2]; + rtx reg[2]; + rtx sub_reg; + rtx temp_reg, temp_sub_reg; + int num_reg; + + /* Generating a series of load byte instructions. + The first load byte instructions and other + load byte instructions are not the same. like: + First: + lbi reg0, [mem] + zeh reg0, reg0 + Second: + lbi temp_reg, [mem + offset] + sll temp_reg, (8 * shift) + ior reg0, temp_reg + + lbi temp_reg, [mem + (offset + 1)] + sll temp_reg, (8 * (shift + 1)) + ior reg0, temp_reg */ + + temp_reg = gen_reg_rtx (SImode); + temp_sub_reg = gen_lowpart (QImode, temp_reg); + + if (mode == DImode) + { + /* Load doubleword, we need two registers to access. */ + reg[0] = nds32_di_low_part_subreg (operands[0]); + reg[1] = nds32_di_high_part_subreg (operands[0]); + /* A register only store 4 byte. */ + width = GET_MODE_SIZE (SImode) - 1; + } + else + { + if (VECTOR_MODE_P (mode)) + reg[0] = gen_reg_rtx (SImode); + else + reg[0] = operands[0]; + } + + for (num_reg = (mode == DImode) ? 2 : 1; num_reg > 0; num_reg--) + { + sub_reg = gen_lowpart (QImode, reg[0]); + mem[0] = gen_rtx_MEM (QImode, plus_constant (Pmode, operands[1], offset)); + + /* Generating the first part instructions. + lbi reg0, [mem] + zeh reg0, reg0 */ + emit_move_insn (sub_reg, mem[0]); + emit_insn (gen_zero_extendqisi2 (reg[0], sub_reg)); + + while (width > 0) + { + offset = offset + offset_adj; + shift++; + width--; + + mem[1] = gen_rtx_MEM (QImode, plus_constant (Pmode, + operands[1], + offset)); + /* Generating the second part instructions. + lbi temp_reg, [mem + offset] + sll temp_reg, (8 * shift) + ior reg0, temp_reg */ + emit_move_insn (temp_sub_reg, mem[1]); + emit_insn (gen_ashlsi3 (temp_reg, temp_reg, + GEN_INT (shift * 8))); + emit_insn (gen_iorsi3 (reg[0], reg[0], temp_reg)); + } + + if (mode == DImode) + { + /* Using the second register to load memory information. */ + reg[0] = reg[1]; + shift = 0; + width = GET_MODE_SIZE (SImode) - 1; + offset = offset + offset_adj; + } + } + if (VECTOR_MODE_P (mode)) + convert_move (operands[0], reg[0], false); +} + +void +nds32_expand_unaligned_store (rtx *operands, enum machine_mode mode) +{ + /* Initial memory offset. */ + int offset = WORDS_BIG_ENDIAN ? GET_MODE_SIZE (mode) - 1 : 0; + int offset_adj = WORDS_BIG_ENDIAN ? -1 : 1; + /* Initial register shift byte. */ + int shift = 0; + /* The first load byte instruction is not the same. */ + int width = GET_MODE_SIZE (mode) - 1; + rtx mem[2]; + rtx reg[2]; + rtx sub_reg; + rtx temp_reg, temp_sub_reg; + int num_reg; + + /* Generating a series of store byte instructions. + The first store byte instructions and other + load byte instructions are not the same. like: + First: + sbi reg0, [mem + 0] + Second: + srli temp_reg, reg0, (8 * shift) + sbi temp_reg, [mem + offset] */ + + temp_reg = gen_reg_rtx (SImode); + temp_sub_reg = gen_lowpart (QImode, temp_reg); + + if (mode == DImode) + { + /* Load doubleword, we need two registers to access. */ + reg[0] = nds32_di_low_part_subreg (operands[1]); + reg[1] = nds32_di_high_part_subreg (operands[1]); + /* A register only store 4 byte. */ + width = GET_MODE_SIZE (SImode) - 1; + } + else + { + if (VECTOR_MODE_P (mode)) + { + reg[0] = gen_reg_rtx (SImode); + convert_move (reg[0], operands[1], false); + } + else + reg[0] = operands[1]; + } + + for (num_reg = (mode == DImode) ? 2 : 1; num_reg > 0; num_reg--) + { + sub_reg = gen_lowpart (QImode, reg[0]); + mem[0] = gen_rtx_MEM (QImode, plus_constant (Pmode, operands[0], offset)); + + /* Generating the first part instructions. + sbi reg0, [mem + 0] */ + emit_move_insn (mem[0], sub_reg); + + while (width > 0) + { + offset = offset + offset_adj; + shift++; + width--; + + mem[1] = gen_rtx_MEM (QImode, plus_constant (Pmode, + operands[0], + offset)); + /* Generating the second part instructions. + srli temp_reg, reg0, (8 * shift) + sbi temp_reg, [mem + offset] */ + emit_insn (gen_lshrsi3 (temp_reg, reg[0], + GEN_INT (shift * 8))); + emit_move_insn (mem[1], temp_sub_reg); + } + + if (mode == DImode) + { + /* Using the second register to load memory information. */ + reg[0] = reg[1]; + shift = 0; + width = GET_MODE_SIZE (SImode) - 1; + offset = offset + offset_adj; + } + } +} + +/* Using multiple load/store instruction to output doubleword instruction. */ +const char * +nds32_output_double (rtx *operands, bool load_p) +{ + char pattern[100]; + int reg = load_p ? 0 : 1; + int mem = load_p ? 1 : 0; + rtx otherops[3]; + rtx addr = XEXP (operands[mem], 0); + + otherops[0] = gen_rtx_REG (SImode, REGNO (operands[reg])); + otherops[1] = gen_rtx_REG (SImode, REGNO (operands[reg]) + 1); + + if (GET_CODE (addr) == POST_INC) + { + /* (mem (post_inc (reg))) */ + otherops[2] = XEXP (addr, 0); + snprintf (pattern, sizeof (pattern), + "%cmw.bim\t%%0, [%%2], %%1, 0", load_p ? 'l' : 's'); + } + else + { + /* (mem (reg)) */ + otherops[2] = addr; + snprintf (pattern, sizeof (pattern), + "%cmw.bi\t%%0, [%%2], %%1, 0", load_p ? 'l' : 's'); + + } + + output_asm_insn (pattern, otherops); + return ""; +} + +const char * +nds32_output_cbranchsi4_equality_zero (rtx_insn *insn, rtx *operands) +{ + enum rtx_code code; + bool long_jump_p = false; + + code = GET_CODE (operands[0]); + + /* This zero-comparison conditional branch has two forms: + 32-bit instruction => beqz/bnez imm16s << 1 + 16-bit instruction => beqzs8/bnezs8/beqz38/bnez38 imm8s << 1 + + For 32-bit case, + we assume it is always reachable. (but check range -65500 ~ 65500) + + For 16-bit case, + it must satisfy { 255 >= (label - pc) >= -256 } condition. + However, since the $pc for nds32 is at the beginning of the instruction, + we should leave some length space for current insn. + So we use range -250 ~ 250. */ + + switch (get_attr_length (insn)) + { + case 8: + long_jump_p = true; + /* fall through */ + case 2: + if (which_alternative == 0) + { + /* constraint: t */ + /* bzs8 .L0 + or + bzs8 .LCB0 + j .L0 + .LCB0: + */ + output_cond_branch_compare_zero (code, "s8", long_jump_p, + operands, true); + return ""; + } + else if (which_alternative == 1) + { + /* constraint: l */ + /* bz38 $r0, .L0 + or + bz38 $r0, .LCB0 + j .L0 + .LCB0: + */ + output_cond_branch_compare_zero (code, "38", long_jump_p, + operands, false); + return ""; + } + else + { + /* constraint: r */ + /* For which_alternative==2, it should not be here. */ + gcc_unreachable (); + } + case 10: + /* including constraints: t, l, and r */ + long_jump_p = true; + /* fall through */ + case 4: + /* including constraints: t, l, and r */ + output_cond_branch_compare_zero (code, "", long_jump_p, operands, false); + return ""; + + default: + gcc_unreachable (); + } +} + +const char * +nds32_output_cbranchsi4_equality_reg (rtx_insn *insn, rtx *operands) +{ + enum rtx_code code; + bool long_jump_p, r5_p; + int insn_length; + + insn_length = get_attr_length (insn); + + long_jump_p = (insn_length == 10 || insn_length == 8) ? true : false; + r5_p = (insn_length == 2 || insn_length == 8) ? true : false; + + code = GET_CODE (operands[0]); + + /* This register-comparison conditional branch has one form: + 32-bit instruction => beq/bne imm14s << 1 + + For 32-bit case, + we assume it is always reachable. (but check range -16350 ~ 16350). */ + + switch (code) + { + case EQ: + case NE: + output_cond_branch (code, "", r5_p, long_jump_p, operands); + return ""; + + default: + gcc_unreachable (); + } +} + +const char * +nds32_output_cbranchsi4_equality_reg_or_const_int (rtx_insn *insn, + rtx *operands) +{ + enum rtx_code code; + bool long_jump_p, r5_p; + int insn_length; + + insn_length = get_attr_length (insn); + + long_jump_p = (insn_length == 10 || insn_length == 8) ? true : false; + r5_p = (insn_length == 2 || insn_length == 8) ? true : false; + + code = GET_CODE (operands[0]); + + /* This register-comparison conditional branch has one form: + 32-bit instruction => beq/bne imm14s << 1 + 32-bit instruction => beqc/bnec imm8s << 1 + + For 32-bit case, we assume it is always reachable. + (but check range -16350 ~ 16350 and -250 ~ 250). */ + + switch (code) + { + case EQ: + case NE: + if (which_alternative == 2) + { + /* r, Is11 */ + /* bc */ + output_cond_branch (code, "c", r5_p, long_jump_p, operands); + } + else + { + /* r, r */ + /* v, r */ + output_cond_branch (code, "", r5_p, long_jump_p, operands); + } + return ""; + default: + gcc_unreachable (); + } +} + +const char * +nds32_output_cbranchsi4_greater_less_zero (rtx_insn *insn, rtx *operands) +{ + enum rtx_code code; + bool long_jump_p; + int insn_length; + + insn_length = get_attr_length (insn); + + gcc_assert (insn_length == 4 || insn_length == 10); + + long_jump_p = (insn_length == 10) ? true : false; + + code = GET_CODE (operands[0]); + + /* This zero-greater-less-comparison conditional branch has one form: + 32-bit instruction => bgtz/bgez/bltz/blez imm16s << 1 + + For 32-bit case, we assume it is always reachable. + (but check range -65500 ~ 65500). */ + + switch (code) + { + case GT: + case GE: + case LT: + case LE: + output_cond_branch_compare_zero (code, "", long_jump_p, operands, false); + break; + default: + gcc_unreachable (); + } + return ""; +} + +const char * +nds32_output_unpkd8 (rtx output, rtx input, + rtx high_idx_rtx, rtx low_idx_rtx, + bool signed_p) +{ + char pattern[100]; + rtx output_operands[2]; + HOST_WIDE_INT high_idx, low_idx; + high_idx = INTVAL (high_idx_rtx); + low_idx = INTVAL (low_idx_rtx); + + gcc_assert (high_idx >= 0 && high_idx <= 3); + gcc_assert (low_idx >= 0 && low_idx <= 3); + + /* We only have 10, 20, 30 and 31. */ + if ((low_idx != 0 || high_idx == 0) && + !(low_idx == 1 && high_idx == 3)) + return "#"; + + char sign_char = signed_p ? 's' : 'z'; + + sprintf (pattern, + "%cunpkd8" HOST_WIDE_INT_PRINT_DEC HOST_WIDE_INT_PRINT_DEC "\t%%0, %%1", + sign_char, high_idx, low_idx); + output_operands[0] = output; + output_operands[1] = input; + output_asm_insn (pattern, output_operands); + return ""; +} + +/* Return true if SYMBOL_REF X binds locally. */ + +static bool +nds32_symbol_binds_local_p (const_rtx x) +{ + return (SYMBOL_REF_DECL (x) + ? targetm.binds_local_p (SYMBOL_REF_DECL (x)) + : SYMBOL_REF_LOCAL_P (x)); +} + +const char * +nds32_output_call (rtx insn, rtx *operands, rtx symbol, const char *long_call, + const char *call, bool align_p) +{ + char pattern[100]; + bool noreturn_p; + + if (nds32_long_call_p (symbol)) + strcpy (pattern, long_call); + else + strcpy (pattern, call); + + if (flag_pic && CONSTANT_P (symbol) + && !nds32_symbol_binds_local_p (symbol)) + strcat (pattern, "@PLT"); + + if (align_p) + strcat (pattern, "\n\t.align 2"); + + noreturn_p = find_reg_note (insn, REG_NORETURN, NULL_RTX) != NULL_RTX; + + if (noreturn_p) + { + if (TARGET_16_BIT) + strcat (pattern, "\n\tnop16"); + else + strcat (pattern, "\n\tnop"); + } + + output_asm_insn (pattern, operands); + return ""; +} + +bool +nds32_need_split_sms_p (rtx in0_idx0, rtx in1_idx0, + rtx in0_idx1, rtx in1_idx1) +{ + /* smds or smdrs. */ + if (INTVAL (in0_idx0) == INTVAL (in1_idx0) + && INTVAL (in0_idx1) == INTVAL (in1_idx1) + && INTVAL (in0_idx0) != INTVAL (in0_idx1)) + return false; + + /* smxds. */ + if (INTVAL (in0_idx0) != INTVAL (in0_idx1) + && INTVAL (in1_idx0) != INTVAL (in1_idx1)) + return false; + + return true; +} + +const char * +nds32_output_sms (rtx in0_idx0, rtx in1_idx0, + rtx in0_idx1, rtx in1_idx1) +{ + if (nds32_need_split_sms_p (in0_idx0, in1_idx0, + in0_idx1, in1_idx1)) + return "#"; + /* out = in0[in0_idx0] * in1[in1_idx0] - in0[in0_idx1] * in1[in1_idx1] */ + + /* smds or smdrs. */ + if (INTVAL (in0_idx0) == INTVAL (in1_idx0) + && INTVAL (in0_idx1) == INTVAL (in1_idx1) + && INTVAL (in0_idx0) != INTVAL (in0_idx1)) + { + if (INTVAL (in0_idx0) == 0) + { + if (TARGET_BIG_ENDIAN) + return "smds\t%0, %1, %2"; + else + return "smdrs\t%0, %1, %2"; + } + else + { + if (TARGET_BIG_ENDIAN) + return "smdrs\t%0, %1, %2"; + else + return "smds\t%0, %1, %2"; + } + } + + if (INTVAL (in0_idx0) != INTVAL (in0_idx1) + && INTVAL (in1_idx0) != INTVAL (in1_idx1)) + { + if (INTVAL (in0_idx0) == 1) + { + if (TARGET_BIG_ENDIAN) + return "smxds\t%0, %2, %1"; + else + return "smxds\t%0, %1, %2"; + } + else + { + if (TARGET_BIG_ENDIAN) + return "smxds\t%0, %1, %2"; + else + return "smxds\t%0, %2, %1"; + } + } + + gcc_unreachable (); + return ""; +} + +void +nds32_split_sms (rtx out, rtx in0, rtx in1, + rtx in0_idx0, rtx in1_idx0, + rtx in0_idx1, rtx in1_idx1) +{ + rtx result0 = gen_reg_rtx (SImode); + rtx result1 = gen_reg_rtx (SImode); + emit_insn (gen_mulhisi3v (result0, in0, in1, + in0_idx0, in1_idx0)); + emit_insn (gen_mulhisi3v (result1, in0, in1, + in0_idx1, in1_idx1)); + emit_insn (gen_subsi3 (out, result0, result1)); +} + +/* Spilt a doubleword instrucion to two single word instructions. */ +void +nds32_spilt_doubleword (rtx *operands, bool load_p) +{ + int reg = load_p ? 0 : 1; + int mem = load_p ? 1 : 0; + rtx reg_rtx = load_p ? operands[0] : operands[1]; + rtx mem_rtx = load_p ? operands[1] : operands[0]; + rtx low_part[2], high_part[2]; + rtx sub_mem = XEXP (mem_rtx, 0); + + /* Generate low_part and high_part register pattern. + i.e. register pattern like: + (reg:DI) -> (subreg:SI (reg:DI)) + (subreg:SI (reg:DI)) */ + low_part[reg] = simplify_gen_subreg (SImode, reg_rtx, GET_MODE (reg_rtx), 0); + high_part[reg] = simplify_gen_subreg (SImode, reg_rtx, GET_MODE (reg_rtx), 4); + + /* Generate low_part and high_part memory pattern. + Memory format is (post_dec) will generate: + low_part: lwi.bi reg, [mem], 4 + high_part: lwi.bi reg, [mem], -12 */ + if (GET_CODE (sub_mem) == POST_DEC) + { + /* memory format is (post_dec (reg)), + so that extract (reg) from the (post_dec (reg)) pattern. */ + sub_mem = XEXP (sub_mem, 0); + + /* generate low_part and high_part memory format: + low_part: (post_modify ((reg) (plus (reg) (const 4))) + high_part: (post_modify ((reg) (plus (reg) (const -12))) */ + low_part[mem] = gen_frame_mem (SImode, + gen_rtx_POST_MODIFY (Pmode, sub_mem, + gen_rtx_PLUS (Pmode, + sub_mem, + GEN_INT (4)))); + high_part[mem] = gen_frame_mem (SImode, + gen_rtx_POST_MODIFY (Pmode, sub_mem, + gen_rtx_PLUS (Pmode, + sub_mem, + GEN_INT (-12)))); + } + else if (GET_CODE (sub_mem) == POST_MODIFY) + { + /* Memory format is (post_modify (reg) (plus (reg) (const))), + so that extract (reg) from the post_modify pattern. */ + rtx post_mem = XEXP (sub_mem, 0); + + /* Extract (const) from the (post_modify (reg) (plus (reg) (const))) + pattern. */ + + rtx plus_op = XEXP (sub_mem, 1); + rtx post_val = XEXP (plus_op, 1); + + /* Generate low_part and high_part memory format: + low_part: (post_modify ((reg) (plus (reg) (const))) + high_part: ((plus (reg) (const 4))) */ + low_part[mem] = gen_frame_mem (SImode, + gen_rtx_POST_MODIFY (Pmode, post_mem, + gen_rtx_PLUS (Pmode, + post_mem, + post_val))); + high_part[mem] = gen_frame_mem (SImode, plus_constant (Pmode, + post_mem, + 4)); + } + else + { + /* memory format: (symbol_ref), (const), (reg + const_int). */ + low_part[mem] = adjust_address (mem_rtx, SImode, 0); + high_part[mem] = adjust_address (mem_rtx, SImode, 4); + } + + /* After reload completed, we have dependent issue by low part register and + higt part memory. i.e. we cannot split a sequence + like: + load $r0, [%r1] + spilt to + lw $r0, [%r0] + lwi $r1, [%r0 + 4] + swap position + lwi $r1, [%r0 + 4] + lw $r0, [%r0] + For store instruction we don't have a problem. + + When memory format is [post_modify], we need to emit high part instruction, + before low part instruction. + expamle: + load $r0, [%r2], post_val + spilt to + load $r1, [%r2 + 4] + load $r0, [$r2], post_val. */ + if ((load_p && reg_overlap_mentioned_p (low_part[0], high_part[1])) + || GET_CODE (sub_mem) == POST_MODIFY) + { + operands[2] = high_part[0]; + operands[3] = high_part[1]; + operands[4] = low_part[0]; + operands[5] = low_part[1]; + } + else + { + operands[2] = low_part[0]; + operands[3] = low_part[1]; + operands[4] = high_part[0]; + operands[5] = high_part[1]; + } +} + +void +nds32_split_ashiftdi3 (rtx dst, rtx src, rtx shiftamount) +{ + rtx src_high_part, src_low_part; + rtx dst_high_part, dst_low_part; + + dst_high_part = nds32_di_high_part_subreg (dst); + dst_low_part = nds32_di_low_part_subreg (dst); + + src_high_part = nds32_di_high_part_subreg (src); + src_low_part = nds32_di_low_part_subreg (src); + + /* We need to handle shift more than 32 bit!!!! */ + if (CONST_INT_P (shiftamount)) + { + if (INTVAL (shiftamount) < 32) + { + rtx ext_start; + ext_start = gen_int_mode(32 - INTVAL (shiftamount), SImode); + + emit_insn (gen_wext (dst_high_part, src, ext_start)); + emit_insn (gen_ashlsi3 (dst_low_part, src_low_part, shiftamount)); + } + else + { + rtx new_shift_amout = gen_int_mode(INTVAL (shiftamount) - 32, SImode); + + emit_insn (gen_ashlsi3 (dst_high_part, src_low_part, + new_shift_amout)); + + emit_move_insn (dst_low_part, GEN_INT (0)); + } + } + else + { + rtx dst_low_part_l32, dst_high_part_l32; + rtx dst_low_part_g32, dst_high_part_g32; + rtx new_shift_amout, select_reg; + dst_low_part_l32 = gen_reg_rtx (SImode); + dst_high_part_l32 = gen_reg_rtx (SImode); + dst_low_part_g32 = gen_reg_rtx (SImode); + dst_high_part_g32 = gen_reg_rtx (SImode); + new_shift_amout = gen_reg_rtx (SImode); + select_reg = gen_reg_rtx (SImode); + + rtx ext_start; + ext_start = gen_reg_rtx (SImode); + + /* + if (shiftamount < 32) + dst_low_part = src_low_part << shiftamout + dst_high_part = wext (src, 32 - shiftamount) + # wext can't handle wext (src, 32) since it's only take rb[0:4] + # for extract. + dst_high_part = shiftamount == 0 ? src_high_part : dst_high_part + else + dst_low_part = 0 + dst_high_part = src_low_part << shiftamount & 0x1f + */ + + emit_insn (gen_subsi3 (ext_start, + gen_int_mode (32, SImode), + shiftamount)); + emit_insn (gen_wext (dst_high_part_l32, src, ext_start)); + + /* Handle for shiftamout == 0. */ + emit_insn (gen_cmovzsi (dst_high_part_l32, shiftamount, + src_high_part, dst_high_part_l32)); + + emit_insn (gen_ashlsi3 (dst_low_part_l32, src_low_part, shiftamount)); + + emit_move_insn (dst_low_part_g32, const0_rtx); + emit_insn (gen_andsi3 (new_shift_amout, shiftamount, GEN_INT (0x1f))); + emit_insn (gen_ashlsi3 (dst_high_part_g32, src_low_part, + new_shift_amout)); + + emit_insn (gen_slt_compare (select_reg, shiftamount, GEN_INT (32))); + + emit_insn (gen_cmovnsi (dst_low_part, select_reg, + dst_low_part_l32, dst_low_part_g32)); + emit_insn (gen_cmovnsi (dst_high_part, select_reg, + dst_high_part_l32, dst_high_part_g32)); + } +} + +void +nds32_split_ashiftrtdi3 (rtx dst, rtx src, rtx shiftamount) +{ + nds32_split_shiftrtdi3 (dst, src, shiftamount, false); +} + +void +nds32_split_lshiftrtdi3 (rtx dst, rtx src, rtx shiftamount) +{ + nds32_split_shiftrtdi3 (dst, src, shiftamount, true); +} + +void +nds32_split_rotatertdi3 (rtx dst, rtx src, rtx shiftamount) +{ + rtx dst_low_part_l32, dst_high_part_l32; + rtx dst_low_part_g32, dst_high_part_g32; + rtx select_reg, low5bit, low5bit_inv, minus32sa; + rtx dst_low_part_g32_tmph; + rtx dst_low_part_g32_tmpl; + rtx dst_high_part_l32_tmph; + rtx dst_high_part_l32_tmpl; + + rtx src_low_part, src_high_part; + rtx dst_high_part, dst_low_part; + + shiftamount = force_reg (SImode, shiftamount); + + emit_insn (gen_andsi3 (shiftamount, + shiftamount, + gen_int_mode (0x3f, SImode))); + + dst_high_part = nds32_di_high_part_subreg (dst); + dst_low_part = nds32_di_low_part_subreg (dst); + + src_high_part = nds32_di_high_part_subreg (src); + src_low_part = nds32_di_low_part_subreg (src); + + dst_low_part_l32 = gen_reg_rtx (SImode); + dst_high_part_l32 = gen_reg_rtx (SImode); + dst_low_part_g32 = gen_reg_rtx (SImode); + dst_high_part_g32 = gen_reg_rtx (SImode); + low5bit = gen_reg_rtx (SImode); + low5bit_inv = gen_reg_rtx (SImode); + minus32sa = gen_reg_rtx (SImode); + select_reg = gen_reg_rtx (SImode); + + dst_low_part_g32_tmph = gen_reg_rtx (SImode); + dst_low_part_g32_tmpl = gen_reg_rtx (SImode); + + dst_high_part_l32_tmph = gen_reg_rtx (SImode); + dst_high_part_l32_tmpl = gen_reg_rtx (SImode); + + emit_insn (gen_slt_compare (select_reg, shiftamount, GEN_INT (32))); + + /* if shiftamount < 32 + dst_low_part = wext(src, shiftamount) + else + dst_low_part = ((src_high_part >> (shiftamount & 0x1f)) + | (src_low_part << (32 - (shiftamount & 0x1f)))) + */ + emit_insn (gen_andsi3 (low5bit, shiftamount, gen_int_mode (0x1f, SImode))); + emit_insn (gen_subsi3 (low5bit_inv, gen_int_mode (32, SImode), low5bit)); + + emit_insn (gen_wext (dst_low_part_l32, src, shiftamount)); + + emit_insn (gen_lshrsi3 (dst_low_part_g32_tmpl, src_high_part, low5bit)); + emit_insn (gen_ashlsi3 (dst_low_part_g32_tmph, src_low_part, low5bit_inv)); + + emit_insn (gen_iorsi3 (dst_low_part_g32, + dst_low_part_g32_tmpl, + dst_low_part_g32_tmph)); + + emit_insn (gen_cmovnsi (dst_low_part, select_reg, + dst_low_part_l32, dst_low_part_g32)); + + /* if shiftamount < 32 + dst_high_part = ((src_high_part >> shiftamount) + | (src_low_part << (32 - shiftamount))) + dst_high_part = shiftamount == 0 ? src_high_part : dst_high_part + else + dst_high_part = wext(src, shiftamount & 0x1f) + */ + + emit_insn (gen_subsi3 (minus32sa, gen_int_mode (32, SImode), shiftamount)); + + emit_insn (gen_lshrsi3 (dst_high_part_l32_tmpl, src_high_part, shiftamount)); + emit_insn (gen_ashlsi3 (dst_high_part_l32_tmph, src_low_part, minus32sa)); + + emit_insn (gen_iorsi3 (dst_high_part_l32, + dst_high_part_l32_tmpl, + dst_high_part_l32_tmph)); + + emit_insn (gen_cmovzsi (dst_high_part_l32, shiftamount, + src_high_part, dst_high_part_l32)); + + emit_insn (gen_wext (dst_high_part_g32, src, low5bit)); + + emit_insn (gen_cmovnsi (dst_high_part, select_reg, + dst_high_part_l32, dst_high_part_g32)); +} + +/* Return true if OP contains a symbol reference. */ +bool +symbolic_reference_mentioned_p (rtx op) +{ + const char *fmt; + int i; - /* The v3push/v3pop instruction should only be applied on - none-isr and none-variadic function. */ - if (TARGET_V3PUSH - && !nds32_isr_function_p (current_function_decl) - && (cfun->machine->va_args_size == 0)) + if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) + return true; + + fmt = GET_RTX_FORMAT (GET_CODE (op)); + for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) { - /* For stack v3push: - operands[0]: Re - operands[1]: imm8u */ + if (fmt[i] == 'E') + { + int j; - /* This variable is to check if 'push25 Re,imm8u' is available. */ - int sp_adjust; + for (j = XVECLEN (op, i) - 1; j >= 0; j--) + if (symbolic_reference_mentioned_p (XVECEXP (op, i, j))) + return true; + } - /* Set operands[0]. */ - operands[0] = gen_rtx_REG (SImode, re_callee_saved); + else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i))) + return true; + } - /* Check if we can generate 'push25 Re,imm8u', - otherwise, generate 'push25 Re,0'. */ - sp_adjust = cfun->machine->local_size - + cfun->machine->out_args_size - + cfun->machine->callee_saved_area_gpr_padding_bytes; - if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) - && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)) - operands[1] = GEN_INT (sp_adjust); - else - operands[1] = GEN_INT (0); + return false; +} - /* Create assembly code pattern. */ - snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1"); - } - else - { - /* For normal stack push multiple: - operands[0]: Rb - operands[1]: Re - operands[2]: En4 */ +/* Expand PIC code for @GOTOFF and @GOT. - /* This variable is used to check if we only need to generate En4 field. - As long as Rb==Re=SP_REGNUM, we set this variable to 1. */ - int push_en4_only_p = 0; + Example for @GOTOFF: - /* Set operands[0] and operands[1]. */ - operands[0] = gen_rtx_REG (SImode, rb_callee_saved); - operands[1] = gen_rtx_REG (SImode, re_callee_saved); + la $r0, symbol@GOTOFF + -> sethi $ta, hi20(symbol@GOTOFF) + ori $ta, $ta, lo12(symbol@GOTOFF) + add $r0, $ta, $gp - /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */ - if (!cfun->machine->fp_size - && !cfun->machine->gp_size - && !cfun->machine->lp_size - && REGNO (operands[0]) == SP_REGNUM - && REGNO (operands[1]) == SP_REGNUM) + Example for @GOT: + + la $r0, symbol@GOT + -> sethi $ta, hi20(symbol@GOT) + ori $ta, $ta, lo12(symbol@GOT) + lw $r0, [$ta + $gp] +*/ +rtx +nds32_legitimize_pic_address (rtx x) +{ + rtx addr = x; + rtx reg = gen_reg_rtx (Pmode); + rtx pat; + + if (GET_CODE (x) == LABEL_REF + || (GET_CODE (x) == SYMBOL_REF + && (CONSTANT_POOL_ADDRESS_P (x) + || SYMBOL_REF_LOCAL_P (x)))) + { + addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_GOTOFF); + addr = gen_rtx_CONST (SImode, addr); + emit_insn (gen_sethi (reg, addr)); + emit_insn (gen_lo_sum (reg, reg, addr)); + x = gen_rtx_PLUS (Pmode, reg, pic_offset_table_rtx); + } + else if (GET_CODE (x) == SYMBOL_REF) + { + addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_GOT); + addr = gen_rtx_CONST (SImode, addr); + emit_insn (gen_sethi (reg, addr)); + emit_insn (gen_lo_sum (reg, reg, addr)); + + x = gen_const_mem (SImode, gen_rtx_PLUS (Pmode, pic_offset_table_rtx, + reg)); + } + else if (GET_CODE (x) == CONST) + { + /* We don't split constant in expand_pic_move because GOTOFF can combine + the addend with the symbol. */ + addr = XEXP (x, 0); + gcc_assert (GET_CODE (addr) == PLUS); + + rtx op0 = XEXP (addr, 0); + rtx op1 = XEXP (addr, 1); + + if ((GET_CODE (op0) == LABEL_REF + || (GET_CODE (op0) == SYMBOL_REF + && (CONSTANT_POOL_ADDRESS_P (op0) + || SYMBOL_REF_LOCAL_P (op0)))) + && GET_CODE (op1) == CONST_INT) { - /* No need to generate instruction. */ - return ""; + pat = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), UNSPEC_GOTOFF); + pat = gen_rtx_PLUS (Pmode, pat, op1); + pat = gen_rtx_CONST (Pmode, pat); + emit_insn (gen_sethi (reg, pat)); + emit_insn (gen_lo_sum (reg, reg, pat)); + x = gen_rtx_PLUS (Pmode, reg, pic_offset_table_rtx); + } + else if (GET_CODE (op0) == SYMBOL_REF + && GET_CODE (op1) == CONST_INT) + { + /* This is a constant offset from a @GOT symbol reference. */ + addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, op0), UNSPEC_GOT); + addr = gen_rtx_CONST (SImode, addr); + emit_insn (gen_sethi (reg, addr)); + emit_insn (gen_lo_sum (reg, reg, addr)); + addr = gen_const_mem (SImode, gen_rtx_PLUS (Pmode, + pic_offset_table_rtx, + reg)); + emit_move_insn (reg, addr); + if (satisfies_constraint_Is15 (op1)) + x = gen_rtx_PLUS (Pmode, reg, op1); + else + { + rtx tmp_reg = gen_reg_rtx (SImode); + emit_insn (gen_movsi (tmp_reg, op1)); + x = gen_rtx_PLUS (Pmode, reg, tmp_reg); + } } else { - /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */ - if (REGNO (operands[0]) == SP_REGNUM - && REGNO (operands[1]) == SP_REGNUM) - push_en4_only_p = 1; - - /* Create assembly code pattern. - We need to handle the form: "Rb, Re, { $fp $gp $lp }". */ - snprintf (pattern, sizeof (pattern), - "push.s\t%s{%s%s%s }", - push_en4_only_p ? "" : "%0, %1, ", - cfun->machine->fp_size ? " $fp" : "", - cfun->machine->gp_size ? " $gp" : "", - cfun->machine->lp_size ? " $lp" : ""); + /* Don't handle this pattern. */ + debug_rtx (x); + gcc_unreachable (); } } + return x; +} - /* We use output_asm_insn() to output assembly code by ourself. */ - output_asm_insn (pattern, operands); - return ""; +void +nds32_expand_pic_move (rtx *operands) +{ + rtx src; + + src = nds32_legitimize_pic_address (operands[1]); + emit_move_insn (operands[0], src); } -/* Function to output stack pop operation. - We need to deal with normal stack pop multiple or stack v3pop. */ -const char * -nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED) +/* Expand ICT symbol. + Example for @ICT and ICT model=large: + + la $r0, symbol@ICT + -> sethi $rt, hi20(symbol@ICT) + lwi $r0, [$rt + lo12(symbol@ICT)] + +*/ +rtx +nds32_legitimize_ict_address (rtx x) { - /* A string pattern for output_asm_insn(). */ - char pattern[100]; - /* The operands array which will be used in output_asm_insn(). */ - rtx operands[3]; - /* Pick up callee-saved first regno and last regno for further use. */ - int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno; - int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno; + rtx symbol = x; + rtx addr = x; + rtx reg = gen_reg_rtx (Pmode); + gcc_assert (GET_CODE (x) == SYMBOL_REF + && nds32_indirect_call_referenced_p (x)); - /* If we step here, we are going to do v3pop or multiple pop operation. */ + addr = gen_rtx_UNSPEC (SImode, gen_rtvec (1, symbol), UNSPEC_ICT); + addr = gen_rtx_CONST (SImode, addr); + emit_insn (gen_sethi (reg, addr)); - /* The v3push/v3pop instruction should only be applied on - none-isr and none-variadic function. */ - if (TARGET_V3PUSH - && !nds32_isr_function_p (current_function_decl) - && (cfun->machine->va_args_size == 0)) - { - /* For stack v3pop: - operands[0]: Re - operands[1]: imm8u */ + x = gen_const_mem (SImode, gen_rtx_LO_SUM (Pmode, reg, addr)); - /* This variable is to check if 'pop25 Re,imm8u' is available. */ - int sp_adjust; + return x; +} - /* Set operands[0]. */ - operands[0] = gen_rtx_REG (SImode, re_callee_saved); +void +nds32_expand_ict_move (rtx *operands) +{ + rtx src = operands[1]; - /* Check if we can generate 'pop25 Re,imm8u', - otherwise, generate 'pop25 Re,0'. - We have to consider alloca issue as well. - If the function does call alloca(), the stack pointer is not fixed. - In that case, we cannot use 'pop25 Re,imm8u' directly. - We have to caculate stack pointer from frame pointer - and then use 'pop25 Re,0'. */ - sp_adjust = cfun->machine->local_size - + cfun->machine->out_args_size - + cfun->machine->callee_saved_area_gpr_padding_bytes; - if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) - && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust) - && !cfun->calls_alloca) - operands[1] = GEN_INT (sp_adjust); - else - operands[1] = GEN_INT (0); + src = nds32_legitimize_ict_address (src); - /* Create assembly code pattern. */ - snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1"); + emit_move_insn (operands[0], src); +} + +/* Return true X is a indirect call symbol. */ +bool +nds32_indirect_call_referenced_p (rtx x) +{ + if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_ICT) + x = XVECEXP (x, 0, 0); + + if (GET_CODE (x) == SYMBOL_REF) + { + tree decl = SYMBOL_REF_DECL (x); + + return decl + && (lookup_attribute("indirect_call", + DECL_ATTRIBUTES(decl)) + != NULL); } + + return false; +} + +/* Return true X is need use long call. */ +bool +nds32_long_call_p (rtx symbol) +{ + if (nds32_indirect_call_referenced_p (symbol)) + return TARGET_ICT_MODEL_LARGE; else - { - /* For normal stack pop multiple: - operands[0]: Rb - operands[1]: Re - operands[2]: En4 */ + return TARGET_CMODEL_LARGE; +} - /* This variable is used to check if we only need to generate En4 field. - As long as Rb==Re=SP_REGNUM, we set this variable to 1. */ - int pop_en4_only_p = 0; +/* Return true if X contains a thread-local symbol. */ +bool +nds32_tls_referenced_p (rtx x) +{ + if (!targetm.have_tls) + return false; - /* Set operands[0] and operands[1]. */ - operands[0] = gen_rtx_REG (SImode, rb_callee_saved); - operands[1] = gen_rtx_REG (SImode, re_callee_saved); + if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS) + x = XEXP (XEXP (x, 0), 0); - /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */ - if (!cfun->machine->fp_size - && !cfun->machine->gp_size - && !cfun->machine->lp_size - && REGNO (operands[0]) == SP_REGNUM - && REGNO (operands[1]) == SP_REGNUM) - { - /* No need to generate instruction. */ - return ""; - } - else - { - /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */ - if (REGNO (operands[0]) == SP_REGNUM - && REGNO (operands[1]) == SP_REGNUM) - pop_en4_only_p = 1; + if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x)) + return true; - /* Create assembly code pattern. - We need to handle the form: "Rb, Re, { $fp $gp $lp }". */ - snprintf (pattern, sizeof (pattern), - "pop.s\t%s{%s%s%s }", - pop_en4_only_p ? "" : "%0, %1, ", - cfun->machine->fp_size ? " $fp" : "", - cfun->machine->gp_size ? " $gp" : "", - cfun->machine->lp_size ? " $lp" : ""); + return false; +} + +/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute + this (thread-local) address. */ +rtx +nds32_legitimize_tls_address (rtx x) +{ + rtx tmp_reg; + rtx tp_reg = gen_rtx_REG (Pmode, TP_REGNUM); + rtx pat, insns, reg0; + + if (GET_CODE (x) == SYMBOL_REF) + switch (SYMBOL_REF_TLS_MODEL (x)) + { + case TLS_MODEL_GLOBAL_DYNAMIC: + case TLS_MODEL_LOCAL_DYNAMIC: + /* Emit UNSPEC_TLS_DESC rather than expand rtl directly because spill + may destroy the define-use chain anylysis to insert relax_hint. */ + if (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_GLOBAL_DYNAMIC) + pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_TLSGD); + else + pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_TLSLD); + + pat = gen_rtx_CONST (SImode, pat); + reg0 = gen_rtx_REG (Pmode, 0); + /* If we can confirm all clobber reigsters, it doesn't have to use call + instruction. */ + insns = emit_call_insn (gen_tls_desc (pat, GEN_INT (0))); + use_reg (&CALL_INSN_FUNCTION_USAGE (insns), pic_offset_table_rtx); + RTL_CONST_CALL_P (insns) = 1; + tmp_reg = gen_reg_rtx (SImode); + emit_move_insn (tmp_reg, reg0); + x = tmp_reg; + break; + + case TLS_MODEL_INITIAL_EXEC: + pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_TLSIE); + tmp_reg = gen_reg_rtx (SImode); + pat = gen_rtx_CONST (SImode, pat); + emit_insn (gen_tls_ie (tmp_reg, pat, GEN_INT (0))); + if (flag_pic) + emit_use (pic_offset_table_rtx); + x = gen_rtx_PLUS (Pmode, tmp_reg, tp_reg); + break; + + case TLS_MODEL_LOCAL_EXEC: + /* Expand symbol_ref@TPOFF': + sethi $ta, hi20(symbol_ref@TPOFF) + ori $ta, $ta, lo12(symbol_ref@TPOFF) + add $r0, $ta, $tp */ + tmp_reg = gen_reg_rtx (SImode); + pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_TLSLE); + pat = gen_rtx_CONST (SImode, pat); + emit_insn (gen_sethi (tmp_reg, pat)); + emit_insn (gen_lo_sum (tmp_reg, tmp_reg, pat)); + x = gen_rtx_PLUS (Pmode, tmp_reg, tp_reg); + break; + + default: + gcc_unreachable (); + } + else if (GET_CODE (x) == CONST) + { + rtx base, addend; + split_const (x, &base, &addend); + + if (SYMBOL_REF_TLS_MODEL (base) == TLS_MODEL_LOCAL_EXEC) + { + /* Expand symbol_ref@TPOFF': + sethi $ta, hi20(symbol_ref@TPOFF + addend) + ori $ta, $ta, lo12(symbol_ref@TPOFF + addend) + add $r0, $ta, $tp */ + tmp_reg = gen_reg_rtx (SImode); + pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, base), UNSPEC_TLSLE); + pat = gen_rtx_PLUS (SImode, pat, addend); + pat = gen_rtx_CONST (SImode, pat); + emit_insn (gen_sethi (tmp_reg, pat)); + emit_insn (gen_lo_sum (tmp_reg, tmp_reg, pat)); + x = gen_rtx_PLUS (Pmode, tmp_reg, tp_reg); } } - /* We use output_asm_insn() to output assembly code by ourself. */ - output_asm_insn (pattern, operands); - return ""; + return x; } -/* Function to generate PC relative jump table. - Refer to nds32.md for more details. +void +nds32_expand_tls_move (rtx *operands) +{ + rtx src = operands[1]; + rtx base, addend; - The following is the sample for the case that diff value - can be presented in '.short' size. + if (CONSTANT_P (src)) + split_const (src, &base, &addend); - addi $r1, $r1, -(case_lower_bound) - slti $ta, $r1, (case_number) - beqz $ta, .L_skip_label + if (SYMBOL_REF_TLS_MODEL (base) == TLS_MODEL_LOCAL_EXEC) + src = nds32_legitimize_tls_address (src); + else + { + src = nds32_legitimize_tls_address (base); + if (addend != const0_rtx) + { + src = gen_rtx_PLUS (SImode, src, addend); + src = force_operand (src, operands[0]); + } + } - la $ta, .L35 ! get jump table address - lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry - addi $ta, $r1, $ta - jr5 $ta + emit_move_insn (operands[0], src); +} - ! jump table entry - L35: - .short .L25-.L35 - .short .L26-.L35 - .short .L27-.L35 - .short .L28-.L35 - .short .L29-.L35 - .short .L30-.L35 - .short .L31-.L35 - .short .L32-.L35 - .short .L33-.L35 - .short .L34-.L35 */ -const char * -nds32_output_casesi_pc_relative (rtx *operands) +void +nds32_expand_constant (enum machine_mode mode, HOST_WIDE_INT val, + rtx target, rtx source) { - machine_mode mode; - rtx diff_vec; + rtx temp = gen_reg_rtx (mode); + int clear_sign_bit_copies = 0; + int clear_zero_bit_copies = 0; + unsigned HOST_WIDE_INT remainder = val & 0xffffffffUL; + + /* Count number of leading zeros. */ + clear_sign_bit_copies = __builtin_clz (remainder); + /* Count number of trailing zeros. */ + clear_zero_bit_copies = __builtin_ctz (remainder); + + HOST_WIDE_INT sign_shift_mask = ((0xffffffffUL + << (32 - clear_sign_bit_copies)) + & 0xffffffffUL); + HOST_WIDE_INT zero_shift_mask = (1 << clear_zero_bit_copies) - 1; + + if (clear_sign_bit_copies > 0 && clear_sign_bit_copies < 17 + && (remainder | sign_shift_mask) == 0xffffffffUL) + { + /* Transfer AND to two shifts, example: + a = b & 0x7fffffff => (b << 1) >> 1 */ + rtx shift = GEN_INT (clear_sign_bit_copies); - diff_vec = PATTERN (NEXT_INSN (as_a (operands[1]))); + emit_insn (gen_ashlsi3 (temp, source, shift)); + emit_insn (gen_lshrsi3 (target, temp, shift)); + } + else if (clear_zero_bit_copies > 0 && clear_sign_bit_copies < 17 + && (remainder | zero_shift_mask) == 0xffffffffUL) + { + /* Transfer AND to two shifts, example: + a = b & 0xfff00000 => (b >> 20) << 20 */ + rtx shift = GEN_INT (clear_zero_bit_copies); - gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC); + emit_insn (gen_lshrsi3 (temp, source, shift)); + emit_insn (gen_ashlsi3 (target, temp, shift)); + } + else + { + emit_move_insn (temp, GEN_INT (val)); + emit_move_insn (target, gen_rtx_fmt_ee (AND, mode, source, temp)); + } +} - /* Step C: "t <-- operands[1]". */ - output_asm_insn ("la\t$ta, %l1", operands); +/* Auxiliary functions for lwm/smw. */ +bool +nds32_valid_smw_lwm_base_p (rtx op) +{ + rtx base_addr; - /* Get the mode of each element in the difference vector. */ - mode = GET_MODE (diff_vec); + if (!MEM_P (op)) + return false; - /* Step D: "z <-- (mem (plus (operands[0] << m) t))", - where m is 0, 1, or 2 to load address-diff value from table. */ - switch (mode) + base_addr = XEXP (op, 0); + + if (REG_P (base_addr)) + return true; + else { - case QImode: - output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands); - break; - case HImode: - output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands); - break; - case SImode: - output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands); - break; - default: - gcc_unreachable (); + if (GET_CODE (base_addr) == POST_INC + && REG_P (XEXP (base_addr, 0))) + return true; } - /* Step E: "t <-- z + t". - Add table label_ref with address-diff value to - obtain target case address. */ - output_asm_insn ("add\t$ta, %2, $ta", operands); + return false; +} - /* Step F: jump to target with register t. */ - if (TARGET_16_BIT) - return "jr5\t$ta"; - else - return "jr\t$ta"; +/* Auxiliary functions for manipulation DI mode. */ +rtx nds32_di_high_part_subreg(rtx reg) +{ + unsigned high_part_offset = subreg_highpart_offset (SImode, DImode); + + return simplify_gen_subreg ( + SImode, reg, + DImode, high_part_offset); } -/* Function to generate normal jump table. */ -const char * -nds32_output_casesi (rtx *operands) +rtx nds32_di_low_part_subreg(rtx reg) { - /* Step C: "t <-- operands[1]". */ - output_asm_insn ("la\t$ta, %l1", operands); + unsigned low_part_offset = subreg_lowpart_offset (SImode, DImode); - /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */ - output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands); + return simplify_gen_subreg ( + SImode, reg, + DImode, low_part_offset); +} - /* No need to perform Step E, which is only used for - pc relative jump table. */ +/* ------------------------------------------------------------------------ */ - /* Step F: jump to target with register z. */ - if (TARGET_16_BIT) - return "jr5\t%2"; +/* Auxiliary function for output TLS patterns. */ + +const char * +nds32_output_tls_desc (rtx *operands) +{ + char pattern[1000]; + + if (TARGET_RELAX_HINT) + snprintf (pattern, sizeof (pattern), + ".relax_hint %%1\n\tsethi $r0, hi20(%%0)\n\t" + ".relax_hint %%1\n\tori $r0, $r0, lo12(%%0)\n\t" + ".relax_hint %%1\n\tlw $r15, [$r0 + $gp]\n\t" + ".relax_hint %%1\n\tadd $r0, $r0, $gp\n\t" + ".relax_hint %%1\n\tjral $r15"); else - return "jr\t%2"; + snprintf (pattern, sizeof (pattern), + "sethi $r0, hi20(%%0)\n\t" + "ori $r0, $r0, lo12(%%0)\n\t" + "lw $r15, [$r0 + $gp]\n\t" + "add $r0, $r0, $gp\n\t" + "jral $r15"); + output_asm_insn (pattern, operands); + return ""; } -/* ------------------------------------------------------------------------ */ +const char * +nds32_output_tls_ie (rtx *operands) +{ + char pattern[1000]; + + if (flag_pic) + { + if (TARGET_RELAX_HINT) + snprintf (pattern, sizeof (pattern), + ".relax_hint %%2\n\tsethi %%0, hi20(%%1)\n\t" + ".relax_hint %%2\n\tori %%0, %%0, lo12(%%1)\n\t" + ".relax_hint %%2\n\tlw %%0, [%%0 + $gp]"); + else + snprintf (pattern, sizeof (pattern), + "sethi %%0, hi20(%%1)\n\t" + "ori %%0, %%0, lo12(%%1)\n\t" + "lw %%0, [%%0 + $gp]"); + } + else + { + if (TARGET_RELAX_HINT) + snprintf (pattern, sizeof (pattern), + ".relax_hint %%2\n\tsethi %%0, hi20(%%1)\n\t" + ".relax_hint %%2\n\tlwi %%0, [%%0 + lo12(%%1)]"); + else + snprintf (pattern, sizeof (pattern), + "sethi %%0, hi20(%%1)\n\t" + "lwi %%0, [%%0 + lo12(%%1)]"); + } + output_asm_insn (pattern, operands); + return ""; +} diff --git a/gcc/config/nds32/nds32-memory-manipulation.c b/gcc/config/nds32/nds32-memory-manipulation.c index 4c26dcc..c46ac8f 100644 --- a/gcc/config/nds32/nds32-memory-manipulation.c +++ b/gcc/config/nds32/nds32-memory-manipulation.c @@ -25,28 +25,1255 @@ #include "system.h" #include "coretypes.h" #include "backend.h" -#include "target.h" +#include "tree.h" #include "rtl.h" -#include "emit-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 six parts: + + PART 1: Auxiliary static function definitions. + + PART 2: Auxiliary function for expand movmem pattern. + + PART 3: Auxiliary function for expand setmem pattern. + + PART 4: Auxiliary function for expand movstr pattern. + + PART 5: Auxiliary function for expand strlen pattern. + + PART 6: Auxiliary function for expand load_multiple/store_multiple + pattern. */ + +/* ------------------------------------------------------------------------ */ + +/* PART 1: Auxiliary static function definitions. */ + +static void +nds32_emit_load_store (rtx reg, rtx mem, + enum machine_mode mode, + int offset, bool load_p) +{ + rtx new_mem; + new_mem = adjust_address (mem, mode, offset); + if (load_p) + emit_move_insn (reg, new_mem); + else + emit_move_insn (new_mem, reg); +} + +static void +nds32_emit_post_inc_load_store (rtx reg, rtx base_reg, + enum machine_mode mode, + bool load_p) +{ + gcc_assert (GET_MODE (reg) == mode); + gcc_assert (GET_MODE (base_reg) == Pmode); + + /* Do not gen (set (reg) (mem (post_inc (reg)))) directly here since it may + not recognize by gcc, so let gcc combine it at auto_inc_dec pass. */ + if (load_p) + emit_move_insn (reg, + gen_rtx_MEM (mode, + base_reg)); + else + emit_move_insn (gen_rtx_MEM (mode, + base_reg), + reg); + + emit_move_insn (base_reg, + plus_constant(Pmode, base_reg, GET_MODE_SIZE (mode))); +} + +static void +nds32_emit_mem_move (rtx src, rtx dst, + enum machine_mode mode, + int addr_offset) +{ + gcc_assert (MEM_P (src) && MEM_P (dst)); + rtx tmp_reg = gen_reg_rtx (mode); + nds32_emit_load_store (tmp_reg, src, mode, + addr_offset, /* load_p */ true); + nds32_emit_load_store (tmp_reg, dst, mode, + addr_offset, /* load_p */ false); +} + +static void +nds32_emit_mem_move_block (int base_regno, int count, + rtx *dst_base_reg, rtx *dst_mem, + rtx *src_base_reg, rtx *src_mem, + bool update_base_reg_p) +{ + rtx new_base_reg; + + emit_insn (nds32_expand_load_multiple (base_regno, count, + *src_base_reg, *src_mem, + update_base_reg_p, &new_base_reg)); + if (update_base_reg_p) + { + *src_base_reg = new_base_reg; + *src_mem = gen_rtx_MEM (SImode, *src_base_reg); + } + + emit_insn (nds32_expand_store_multiple (base_regno, count, + *dst_base_reg, *dst_mem, + update_base_reg_p, &new_base_reg)); + + if (update_base_reg_p) + { + *dst_base_reg = new_base_reg; + *dst_mem = gen_rtx_MEM (SImode, *dst_base_reg); + } +} + +/* ------------------------------------------------------------------------ */ + +/* PART 2: Auxiliary function for expand movmem pattern. */ + +static bool +nds32_expand_movmemsi_loop_unknown_size (rtx dstmem, rtx srcmem, + rtx size, + rtx alignment, bool use_zol_p) +{ + /* Emit loop version of movmem. + + andi $size_least_3_bit, $size, #~7 + add $dst_end, $dst, $size + move $dst_itr, $dst + move $src_itr, $src + beqz $size_least_3_bit, .Lbyte_mode_entry ! Not large enough. + add $double_word_end, $dst, $size_least_3_bit + + .Ldouble_word_mode_loop: + lmw.bim $tmp-begin, [$src_itr], $tmp-end, #0 ! $src_itr' = $src_itr + smw.bim $tmp-begin, [$dst_itr], $tmp-end, #0 ! $dst_itr' = $dst_itr + ! move will delete after register allocation + move $src_itr, $src_itr' + move $dst_itr, $dst_itr' + ! Not readch upper bound. Loop. + bne $double_word_end, $dst_itr, .Ldouble_word_mode_loop + + .Lbyte_mode_entry: + beq $dst_itr, $dst_end, .Lend_label + .Lbyte_mode_loop: + lbi.bi $tmp, [$src_itr], #1 + sbi.bi $tmp, [$dst_itr], #1 + ! Not readch upper bound. Loop. + bne $dst_itr, $dst_end, .Lbyte_mode_loop + .Lend_label: + */ + rtx dst_base_reg, src_base_reg; + rtx dst_itr, src_itr; + rtx dstmem_m, srcmem_m, dst_itr_m, src_itr_m; + rtx dst_end; + rtx size_least_3_bit; + rtx double_word_end = NULL; + rtx double_word_mode_loop, byte_mode_entry, byte_mode_loop, end_label; + rtx tmp; + rtx mask_least_3_bit; + int start_regno; + bool align_to_4_bytes = (INTVAL (alignment) & 3) == 0; + int hwloop_id = cfun->machine->hwloop_group_id; + + if (TARGET_ISA_V3M && !align_to_4_bytes) + return 0; + + if (TARGET_REDUCED_REGS) + start_regno = 2; + else + start_regno = 16; + + dst_itr = gen_reg_rtx (Pmode); + src_itr = gen_reg_rtx (Pmode); + dst_end = gen_reg_rtx (Pmode); + tmp = gen_reg_rtx (QImode); + mask_least_3_bit = GEN_INT (~7); + + double_word_mode_loop = gen_label_rtx (); + byte_mode_entry = gen_label_rtx (); + byte_mode_loop = gen_label_rtx (); + end_label = gen_label_rtx (); + + dst_base_reg = copy_to_mode_reg (Pmode, XEXP (dstmem, 0)); + src_base_reg = copy_to_mode_reg (Pmode, XEXP (srcmem, 0)); + /* andi $size_least_3_bit, $size, #~7 */ + size_least_3_bit = expand_binop (SImode, and_optab, size, mask_least_3_bit, + NULL_RTX, 0, OPTAB_WIDEN); + /* add $dst_end, $dst, $size */ + dst_end = expand_binop (Pmode, add_optab, dst_base_reg, size, + NULL_RTX, 0, OPTAB_WIDEN); + + /* move $dst_itr, $dst + move $src_itr, $src */ + emit_move_insn (dst_itr, dst_base_reg); + emit_move_insn (src_itr, src_base_reg); + + /* beqz $size_least_3_bit, .Lbyte_mode_entry ! Not large enough. */ + emit_cmp_and_jump_insns (size_least_3_bit, const0_rtx, EQ, NULL, + SImode, 1, byte_mode_entry); + if (TARGET_HWLOOP && use_zol_p) + { + rtx start_label = gen_rtx_LABEL_REF (Pmode, double_word_mode_loop); + /* We use multiple-load/store instruction once to process 8-bytes, + division 8-bytes for one cycle, generate + srli $size_least_3_bit, size_least_3_bit, 3. */ + emit_insn (gen_lshrsi3 (size_least_3_bit, size_least_3_bit, GEN_INT (3))); + /* mtlbi .Ldouble_word_mode_loop */ + emit_insn (gen_mtlbi_hint (start_label, GEN_INT (hwloop_id))); + emit_insn (gen_init_lc (size_least_3_bit, GEN_INT (hwloop_id))); + emit_insn (gen_no_hwloop ()); + } + else + { + /* add $double_word_end, $dst, $size_least_3_bit */ + double_word_end = expand_binop (Pmode, add_optab, + dst_base_reg, size_least_3_bit, + NULL_RTX, 0, OPTAB_WIDEN); + } + + /* .Ldouble_word_mode_loop: */ + emit_label (double_word_mode_loop); + /* lmw.bim $tmp-begin, [$src_itr], $tmp-end, #0 ! $src_itr' = $src_itr + smw.bim $tmp-begin, [$dst_itr], $tmp-end, #0 ! $dst_itr' = $dst_itr */ + src_itr_m = src_itr; + dst_itr_m = dst_itr; + srcmem_m = srcmem; + dstmem_m = dstmem; + nds32_emit_mem_move_block (start_regno, 2, + &dst_itr_m, &dstmem_m, + &src_itr_m, &srcmem_m, + true); + /* move $src_itr, $src_itr' + move $dst_itr, $dst_itr' */ + emit_move_insn (dst_itr, dst_itr_m); + emit_move_insn (src_itr, src_itr_m); + + if (TARGET_HWLOOP && use_zol_p) + { + rtx start_label = gen_rtx_LABEL_REF (Pmode, double_word_mode_loop); + /* Hwloop pseduo instrtion to handle CFG. */ + rtx cfg_insn = emit_jump_insn (gen_hwloop_cfg (GEN_INT (hwloop_id), + start_label)); + JUMP_LABEL (cfg_insn) = double_word_mode_loop; + cfun->machine->hwloop_group_id++; + } + else + { + /* ! Not readch upper bound. Loop. + bne $double_word_end, $dst_itr, .Ldouble_word_mode_loop */ + emit_cmp_and_jump_insns (double_word_end, dst_itr, NE, NULL, + Pmode, 1, double_word_mode_loop); + } + + /* .Lbyte_mode_entry: */ + emit_label (byte_mode_entry); + + /* beq $dst_itr, $dst_end, .Lend_label */ + emit_cmp_and_jump_insns (dst_itr, dst_end, EQ, NULL, + Pmode, 1, end_label); + /* .Lbyte_mode_loop: */ + emit_label (byte_mode_loop); + + emit_insn (gen_no_hwloop ()); + /* lbi.bi $tmp, [$src_itr], #1 */ + nds32_emit_post_inc_load_store (tmp, src_itr, QImode, true); + + /* sbi.bi $tmp, [$dst_itr], #1 */ + nds32_emit_post_inc_load_store (tmp, dst_itr, QImode, false); + /* ! Not readch upper bound. Loop. + bne $dst_itr, $dst_end, .Lbyte_mode_loop */ + emit_cmp_and_jump_insns (dst_itr, dst_end, NE, NULL, + SImode, 1, byte_mode_loop); + + /* .Lend_label: */ + emit_label (end_label); + + return true; +} + +static bool +nds32_expand_movmemsi_loop_known_size (rtx dstmem, rtx srcmem, + rtx size, rtx alignment) +{ + rtx dst_base_reg, src_base_reg; + rtx dst_itr, src_itr; + rtx dstmem_m, srcmem_m, dst_itr_m, src_itr_m; + rtx dst_end; + rtx double_word_mode_loop, byte_mode_loop; + rtx tmp; + int start_regno; + bool align_to_4_bytes = (INTVAL (alignment) & 3) == 0; + int hwloop_id = cfun->machine->hwloop_group_id; + unsigned HOST_WIDE_INT total_bytes = UINTVAL (size); + + if (TARGET_ISA_V3M && !align_to_4_bytes) + return 0; + + if (TARGET_REDUCED_REGS) + start_regno = 2; + else + start_regno = 16; + + dst_itr = gen_reg_rtx (Pmode); + src_itr = gen_reg_rtx (Pmode); + dst_end = gen_reg_rtx (Pmode); + tmp = gen_reg_rtx (QImode); + + double_word_mode_loop = gen_label_rtx (); + byte_mode_loop = gen_label_rtx (); + + dst_base_reg = copy_to_mode_reg (Pmode, XEXP (dstmem, 0)); + src_base_reg = copy_to_mode_reg (Pmode, XEXP (srcmem, 0)); + + if (total_bytes < 8) + { + /* Emit total_bytes less than 8 loop version of movmem. + add $dst_end, $dst, $size + move $dst_itr, $dst + .Lbyte_mode_loop: + lbi.bi $tmp, [$src_itr], #1 + sbi.bi $tmp, [$dst_itr], #1 + ! Not readch upper bound. Loop. + bne $dst_itr, $dst_end, .Lbyte_mode_loop */ + + /* add $dst_end, $dst, $size */ + dst_end = expand_binop (Pmode, add_optab, dst_base_reg, size, + NULL_RTX, 0, OPTAB_WIDEN); + /* move $dst_itr, $dst + move $src_itr, $src */ + emit_move_insn (dst_itr, dst_base_reg); + emit_move_insn (src_itr, src_base_reg); + + /* .Lbyte_mode_loop: */ + emit_label (byte_mode_loop); + + emit_insn (gen_no_hwloop ()); + /* lbi.bi $tmp, [$src_itr], #1 */ + nds32_emit_post_inc_load_store (tmp, src_itr, QImode, true); + + /* sbi.bi $tmp, [$dst_itr], #1 */ + nds32_emit_post_inc_load_store (tmp, dst_itr, QImode, false); + /* ! Not readch upper bound. Loop. + bne $dst_itr, $dst_end, .Lbyte_mode_loop */ + emit_cmp_and_jump_insns (dst_itr, dst_end, NE, NULL, + SImode, 1, byte_mode_loop); + return true; + } + else if (total_bytes % 8 == 0) + { + /* Emit multiple of 8 loop version of movmem. + + add $dst_end, $dst, $size + move $dst_itr, $dst + move $src_itr, $src + + .Ldouble_word_mode_loop: + lmw.bim $tmp-begin, [$src_itr], $tmp-end, #0 ! $src_itr' = $src_itr + smw.bim $tmp-begin, [$dst_itr], $tmp-end, #0 ! $dst_itr' = $dst_itr + ! move will delete after register allocation + move $src_itr, $src_itr' + move $dst_itr, $dst_itr' + ! Not readch upper bound. Loop. + bne $double_word_end, $dst_itr, .Ldouble_word_mode_loop */ + + if (TARGET_HWLOOP) + { + rtx start_label = gen_rtx_LABEL_REF (Pmode, double_word_mode_loop); + + rtx loop_count_reg = gen_reg_rtx (Pmode); + /* movi $loop_count_reg, total_bytes / 8 */ + emit_move_insn (loop_count_reg, GEN_INT (total_bytes / 8)); + /* mtlbi .Ldouble_word_mode_loop */ + emit_insn (gen_mtlbi_hint (start_label, GEN_INT (hwloop_id))); + /* mtusr $loop_count_reg, LC */ + emit_insn (gen_init_lc (loop_count_reg, GEN_INT (hwloop_id))); + emit_insn (gen_no_hwloop ()); + } + else + { + /* add $dst_end, $dst, $size */ + dst_end = expand_binop (Pmode, add_optab, dst_base_reg, size, + NULL_RTX, 0, OPTAB_WIDEN); + } + + /* move $dst_itr, $dst + move $src_itr, $src */ + emit_move_insn (dst_itr, dst_base_reg); + emit_move_insn (src_itr, src_base_reg); + + /* .Ldouble_word_mode_loop: */ + emit_label (double_word_mode_loop); + /* lmw.bim $tmp-begin, [$src_itr], $tmp-end, #0 ! $src_itr' = $src_itr + smw.bim $tmp-begin, [$dst_itr], $tmp-end, #0 ! $dst_itr' = $dst_itr */ + src_itr_m = src_itr; + dst_itr_m = dst_itr; + srcmem_m = srcmem; + dstmem_m = dstmem; + nds32_emit_mem_move_block (start_regno, 2, + &dst_itr_m, &dstmem_m, + &src_itr_m, &srcmem_m, + true); + /* move $src_itr, $src_itr' + move $dst_itr, $dst_itr' */ + emit_move_insn (dst_itr, dst_itr_m); + emit_move_insn (src_itr, src_itr_m); + + if (TARGET_HWLOOP) + { + rtx start_label = gen_rtx_LABEL_REF (Pmode, double_word_mode_loop); + /* Hwloop pseduo instrtion to handle CFG. */ + rtx cfg_insn = emit_jump_insn (gen_hwloop_cfg (GEN_INT (hwloop_id), + start_label)); + JUMP_LABEL (cfg_insn) = double_word_mode_loop; + cfun->machine->hwloop_group_id++; + } + else + { + /* ! Not readch upper bound. Loop. + bne $double_word_end, $dst_itr, .Ldouble_word_mode_loop */ + emit_cmp_and_jump_insns (dst_end, dst_itr, NE, NULL, + Pmode, 1, double_word_mode_loop); + } + } + else + { + /* Handle size greater than 8, and not a multiple of 8. */ + return nds32_expand_movmemsi_loop_unknown_size (dstmem, srcmem, + size, alignment, + true); + } + + return true; +} + +static bool +nds32_expand_movmemsi_loop (rtx dstmem, rtx srcmem, + rtx size, rtx alignment) +{ + if (CONST_INT_P (size)) + return nds32_expand_movmemsi_loop_known_size (dstmem, srcmem, + size, alignment); + else + return nds32_expand_movmemsi_loop_unknown_size (dstmem, srcmem, + size, alignment, false); +} + +static bool +nds32_expand_movmemsi_unroll (rtx dstmem, rtx srcmem, + rtx total_bytes, rtx alignment) +{ + rtx dst_base_reg, src_base_reg; + rtx tmp_reg; + int maximum_bytes; + int maximum_bytes_per_inst; + int maximum_regs; + int start_regno; + int i, inst_num; + HOST_WIDE_INT remain_bytes, remain_words; + bool align_to_4_bytes = (INTVAL (alignment) & 3) == 0; + bool align_to_2_bytes = (INTVAL (alignment) & 1) == 0; + + /* Because reduced-set regsiters has few registers + (r0~r5, r6~10, r15, r28~r31, where 'r15' and 'r28~r31' + cannot be used for register allocation), + using 8 registers (32 bytes) for moving memory block + may easily consume all of them. + It makes register allocation/spilling hard to work. + So we only allow maximum=4 registers (16 bytes) for + moving memory block under reduced-set registers. */ + if (TARGET_REDUCED_REGS) + { + maximum_regs = 4; + maximum_bytes = 64; + start_regno = 2; + } + else + { + if (TARGET_LINUX_ABI) + { + /* $r25 is $tp so we use up to 8 registers if using Linux ABI. */ + maximum_regs = 8; + maximum_bytes = 160; + start_regno = 16; + } + else + { + maximum_regs = 10; + maximum_bytes = 160; + start_regno = 16; + } + } + maximum_bytes_per_inst = maximum_regs * UNITS_PER_WORD; + + /* 1. Total_bytes is integer for sure. + 2. Alignment is integer for sure. + 3. Maximum 4 or 10 registers and up to 4 instructions, + 4 * 4 * 4 = 64 bytes, 8 * 4 * 10 = 160 bytes. + 4. The dstmem cannot be volatile memory access. + 5. The srcmem cannot be volatile memory access. + 6. Known shared alignment not align to 4 byte in v3m since lmw/smw *NOT* + support unalign access with v3m configure. */ + if (GET_CODE (total_bytes) != CONST_INT + || GET_CODE (alignment) != CONST_INT + || INTVAL (total_bytes) > maximum_bytes + || MEM_VOLATILE_P (dstmem) + || MEM_VOLATILE_P (srcmem) + || (TARGET_ISA_V3M && !align_to_4_bytes)) + return false; + + dst_base_reg = copy_to_mode_reg (SImode, XEXP (dstmem, 0)); + src_base_reg = copy_to_mode_reg (SImode, XEXP (srcmem, 0)); + remain_bytes = INTVAL (total_bytes); + + /* Do not update base address for last lmw/smw pair. */ + inst_num = ((INTVAL (total_bytes) + (maximum_bytes_per_inst - 1)) + / maximum_bytes_per_inst) - 1; + + for (i = 0; i < inst_num; i++) + { + nds32_emit_mem_move_block (start_regno, maximum_regs, + &dst_base_reg, &dstmem, + &src_base_reg, &srcmem, + true); + } + remain_bytes -= maximum_bytes_per_inst * inst_num; + + remain_words = remain_bytes / UNITS_PER_WORD; + remain_bytes = remain_bytes - (remain_words * UNITS_PER_WORD); + + if (remain_words != 0) + { + if (remain_bytes != 0) + nds32_emit_mem_move_block (start_regno, remain_words, + &dst_base_reg, &dstmem, + &src_base_reg, &srcmem, + true); + else + { + /* Do not update address if no further byte to move. */ + if (remain_words == 1) + { + /* emit move instruction if align to 4 byte and only 1 + word to move. */ + if (align_to_4_bytes) + nds32_emit_mem_move (srcmem, dstmem, SImode, 0); + else + { + tmp_reg = gen_reg_rtx (SImode); + emit_insn ( + gen_unaligned_load_w (tmp_reg, + gen_rtx_MEM (SImode, src_base_reg))); + emit_insn ( + gen_unaligned_store_w (gen_rtx_MEM (SImode, dst_base_reg), + tmp_reg)); + } + } + else + nds32_emit_mem_move_block (start_regno, remain_words, + &dst_base_reg, &dstmem, + &src_base_reg, &srcmem, + false); + } + } + + switch (remain_bytes) + { + case 3: + case 2: + { + if (align_to_2_bytes) + nds32_emit_mem_move (srcmem, dstmem, HImode, 0); + else + { + nds32_emit_mem_move (srcmem, dstmem, QImode, 0); + nds32_emit_mem_move (srcmem, dstmem, QImode, 1); + } + + if (remain_bytes == 3) + nds32_emit_mem_move (srcmem, dstmem, QImode, 2); + break; + } + case 1: + nds32_emit_mem_move (srcmem, dstmem, QImode, 0); + break; + case 0: + break; + default: + gcc_unreachable (); + } + + /* Successfully create patterns, return true. */ + return true; +} + +/* Function to move block memory content by + using load_multiple and store_multiple. + This is auxiliary extern function to help create rtx template. + Check nds32-multiple.md file for the patterns. */ +bool +nds32_expand_movmemsi (rtx dstmem, rtx srcmem, rtx total_bytes, rtx alignment) +{ + if (nds32_expand_movmemsi_unroll (dstmem, srcmem, total_bytes, alignment)) + return true; + + if (!optimize_size && optimize > 2) + return nds32_expand_movmemsi_loop (dstmem, srcmem, total_bytes, alignment); + + return false; +} + +/* ------------------------------------------------------------------------ */ + +/* PART 3: Auxiliary function for expand setmem pattern. */ + +static rtx +nds32_gen_dup_4_byte_to_word_value_aux (rtx value, rtx value4word) +{ + gcc_assert (GET_MODE (value) == QImode || CONST_INT_P (value)); + + if (CONST_INT_P (value)) + { + unsigned HOST_WIDE_INT val = UINTVAL (value) & GET_MODE_MASK(QImode); + rtx new_val = gen_int_mode (val | (val << 8) + | (val << 16) | (val << 24), SImode); + /* Just calculate at here if it's constant value. */ + emit_move_insn (value4word, new_val); + } + else + { + if (NDS32_EXT_DSP_P ()) + { + /* ! prepare word + insb $tmp, $value, 1 ! $tmp <- 0x0000abab + pkbb16 $tmp6, $tmp2, $tmp2 ! $value4word <- 0xabababab */ + rtx tmp = gen_reg_rtx (SImode); + + convert_move (tmp, value, true); + + emit_insn ( + gen_insvsi_internal (tmp, gen_int_mode (0x8, SImode), tmp)); + + emit_insn (gen_pkbbsi_1 (value4word, tmp, tmp)); + } + else + { + /* ! prepare word + andi $tmp1, $value, 0xff ! $tmp1 <- 0x000000ab + slli $tmp2, $tmp1, 8 ! $tmp2 <- 0x0000ab00 + or $tmp3, $tmp1, $tmp2 ! $tmp3 <- 0x0000abab + slli $tmp4, $tmp3, 16 ! $tmp4 <- 0xabab0000 + or $val4word, $tmp3, $tmp4 ! $value4word <- 0xabababab */ + + rtx tmp1, tmp2, tmp3, tmp4; + tmp1 = expand_binop (SImode, and_optab, value, + gen_int_mode (0xff, SImode), + NULL_RTX, 0, OPTAB_WIDEN); + tmp2 = expand_binop (SImode, ashl_optab, tmp1, + gen_int_mode (8, SImode), + NULL_RTX, 0, OPTAB_WIDEN); + tmp3 = expand_binop (SImode, ior_optab, tmp1, tmp2, + NULL_RTX, 0, OPTAB_WIDEN); + tmp4 = expand_binop (SImode, ashl_optab, tmp3, + gen_int_mode (16, SImode), + NULL_RTX, 0, OPTAB_WIDEN); + + emit_insn (gen_iorsi3 (value4word, tmp3, tmp4)); + } + } + + return value4word; +} + +static rtx +nds32_gen_dup_4_byte_to_word_value (rtx value) +{ + rtx value4word = gen_reg_rtx (SImode); + nds32_gen_dup_4_byte_to_word_value_aux (value, value4word); + + return value4word; +} + +static rtx +nds32_gen_dup_8_byte_to_double_word_value (rtx value) +{ + rtx value4doubleword = gen_reg_rtx (DImode); + + nds32_gen_dup_4_byte_to_word_value_aux ( + value, nds32_di_low_part_subreg(value4doubleword)); + + emit_move_insn (nds32_di_high_part_subreg(value4doubleword), + nds32_di_low_part_subreg(value4doubleword)); + return value4doubleword; +} + + +static rtx +emit_setmem_doubleword_loop (rtx itr, rtx size, rtx value) +{ + rtx word_mode_label = gen_label_rtx (); + rtx word_mode_end_label = gen_label_rtx (); + rtx byte_mode_size = gen_reg_rtx (SImode); + rtx byte_mode_size_tmp = gen_reg_rtx (SImode); + rtx word_mode_end = gen_reg_rtx (SImode); + rtx size_for_word = gen_reg_rtx (SImode); + + /* and $size_for_word, $size, #~0x7 */ + size_for_word = expand_binop (SImode, and_optab, size, + gen_int_mode (~0x7, SImode), + NULL_RTX, 0, OPTAB_WIDEN); + + emit_move_insn (byte_mode_size, size); + + /* beqz $size_for_word, .Lbyte_mode_entry */ + emit_cmp_and_jump_insns (size_for_word, const0_rtx, EQ, NULL, + SImode, 1, word_mode_end_label); + /* add $word_mode_end, $dst, $size_for_word */ + word_mode_end = expand_binop (Pmode, add_optab, itr, size_for_word, + NULL_RTX, 0, OPTAB_WIDEN); + + /* andi $byte_mode_size, $size, 0x7 */ + byte_mode_size_tmp = expand_binop (SImode, and_optab, size, GEN_INT (0x7), + NULL_RTX, 0, OPTAB_WIDEN); + + emit_move_insn (byte_mode_size, byte_mode_size_tmp); + + /* .Lword_mode: */ + emit_label (word_mode_label); + /* ! word-mode set loop + smw.bim $value4word, [$dst_itr], $value4word, 0 + bne $word_mode_end, $dst_itr, .Lword_mode */ + emit_insn (gen_unaligned_store_update_base_dw (itr, + itr, + value)); + emit_cmp_and_jump_insns (word_mode_end, itr, NE, NULL, + Pmode, 1, word_mode_label); + + emit_label (word_mode_end_label); + + return byte_mode_size; +} + +static rtx +emit_setmem_byte_loop (rtx itr, rtx size, rtx value, bool need_end) +{ + rtx end = gen_reg_rtx (Pmode); + rtx byte_mode_label = gen_label_rtx (); + rtx end_label = gen_label_rtx (); + + value = force_reg (QImode, value); + + if (need_end) + end = expand_binop (Pmode, add_optab, itr, size, + NULL_RTX, 0, OPTAB_WIDEN); + /* beqz $byte_mode_size, .Lend + add $byte_mode_end, $dst_itr, $byte_mode_size */ + emit_cmp_and_jump_insns (size, const0_rtx, EQ, NULL, + SImode, 1, end_label); + + if (!need_end) + end = expand_binop (Pmode, add_optab, itr, size, + NULL_RTX, 0, OPTAB_WIDEN); + + /* .Lbyte_mode: */ + emit_label (byte_mode_label); + + emit_insn (gen_no_hwloop ()); + /* ! byte-mode set loop + sbi.bi $value, [$dst_itr] ,1 + bne $byte_mode_end, $dst_itr, .Lbyte_mode */ + nds32_emit_post_inc_load_store (value, itr, QImode, false); + + emit_cmp_and_jump_insns (end, itr, NE, NULL, + Pmode, 1, byte_mode_label); + /* .Lend: */ + emit_label (end_label); + + if (need_end) + return end; + else + return NULL_RTX; +} + +static bool +nds32_expand_setmem_loop (rtx dstmem, rtx size, rtx value) +{ + rtx value4doubleword; + rtx value4byte; + rtx dst; + rtx byte_mode_size; + + /* Emit loop version of setmem. + memset: + ! prepare word + andi $tmp1, $val, 0xff ! $tmp1 <- 0x000000ab + slli $tmp2, $tmp1, 8 ! $tmp2 <- 0x0000ab00 + or $tmp3, $val, $tmp2 ! $tmp3 <- 0x0000abab + slli $tmp4, $tmp3, 16 ! $tmp4 <- 0xabab0000 + or $val4word, $tmp3, $tmp4 ! $value4word <- 0xabababab + + and $size_for_word, $size, #-4 + beqz $size_for_word, .Lword_mode_end + + add $word_mode_end, $dst, $size_for_word + andi $byte_mode_size, $size, 3 + + .Lword_mode: + ! word-mode set loop + smw.bim $value4word, [$dst], $value4word, 0 + bne $word_mode_end, $dst, .Lword_mode + + .Lword_mode_end: + beqz $byte_mode_size, .Lend + add $byte_mode_end, $dst, $byte_mode_size + + .Lbyte_mode: + ! byte-mode set loop + sbi.bi $value4word, [$dst] ,1 + bne $byte_mode_end, $dst, .Lbyte_mode + .Lend: */ + + dst = copy_to_mode_reg (SImode, XEXP (dstmem, 0)); + + /* ! prepare word + andi $tmp1, $value, 0xff ! $tmp1 <- 0x000000ab + slli $tmp2, $tmp1, 8 ! $tmp2 <- 0x0000ab00 + or $tmp3, $tmp1, $tmp2 ! $tmp3 <- 0x0000abab + slli $tmp4, $tmp3, 16 ! $tmp4 <- 0xabab0000 + or $val4word, $tmp3, $tmp4 ! $value4word <- 0xabababab */ + value4doubleword = nds32_gen_dup_8_byte_to_double_word_value (value); + + /* and $size_for_word, $size, #-4 + beqz $size_for_word, .Lword_mode_end + + add $word_mode_end, $dst, $size_for_word + andi $byte_mode_size, $size, 3 + + .Lword_mode: + ! word-mode set loop + smw.bim $value4word, [$dst], $value4word, 0 + bne $word_mode_end, $dst, .Lword_mode + .Lword_mode_end: */ + byte_mode_size = emit_setmem_doubleword_loop (dst, size, value4doubleword); + + /* beqz $byte_mode_size, .Lend + add $byte_mode_end, $dst, $byte_mode_size + + .Lbyte_mode: + ! byte-mode set loop + sbi.bi $value, [$dst] ,1 + bne $byte_mode_end, $dst, .Lbyte_mode + .Lend: */ + + value4byte = simplify_gen_subreg (QImode, value4doubleword, DImode, + subreg_lowpart_offset (QImode, DImode)); + + emit_setmem_byte_loop (dst, byte_mode_size, value4byte, false); + + return true; +} + +static bool +nds32_expand_setmem_loop_v3m (rtx dstmem, rtx size, rtx value) +{ + rtx base_reg = copy_to_mode_reg (Pmode, XEXP (dstmem, 0)); + rtx need_align_bytes = gen_reg_rtx (SImode); + rtx last_2_bit = gen_reg_rtx (SImode); + rtx byte_loop_base = gen_reg_rtx (SImode); + rtx byte_loop_size = gen_reg_rtx (SImode); + rtx remain_size = gen_reg_rtx (SImode); + rtx new_base_reg; + rtx value4byte, value4doubleword; + rtx byte_mode_size; + rtx last_byte_loop_label = gen_label_rtx (); + + size = force_reg (SImode, size); + + value4doubleword = nds32_gen_dup_8_byte_to_double_word_value (value); + value4byte = simplify_gen_subreg (QImode, value4doubleword, DImode, + subreg_lowpart_offset (QImode, DImode)); + + emit_move_insn (byte_loop_size, size); + emit_move_insn (byte_loop_base, base_reg); + + /* Jump to last byte loop if size is less than 16. */ + emit_cmp_and_jump_insns (size, gen_int_mode (16, SImode), LE, NULL, + SImode, 1, last_byte_loop_label); + + /* Make sure align to 4 byte first since v3m can't unalign access. */ + emit_insn (gen_andsi3 (last_2_bit, + base_reg, + gen_int_mode (0x3, SImode))); + + emit_insn (gen_subsi3 (need_align_bytes, + gen_int_mode (4, SImode), + last_2_bit)); + + /* Align to 4 byte. */ + new_base_reg = emit_setmem_byte_loop (base_reg, + need_align_bytes, + value4byte, + true); + + /* Calculate remain size. */ + emit_insn (gen_subsi3 (remain_size, size, need_align_bytes)); + + /* Set memory word by word. */ + byte_mode_size = emit_setmem_doubleword_loop (new_base_reg, + remain_size, + value4doubleword); + + emit_move_insn (byte_loop_base, new_base_reg); + emit_move_insn (byte_loop_size, byte_mode_size); + + emit_label (last_byte_loop_label); + + /* And set memory for remain bytes. */ + emit_setmem_byte_loop (byte_loop_base, byte_loop_size, value4byte, false); + return true; +} + +static bool +nds32_expand_setmem_unroll (rtx dstmem, rtx size, rtx value, + rtx align ATTRIBUTE_UNUSED, + rtx expected_align ATTRIBUTE_UNUSED, + rtx expected_size ATTRIBUTE_UNUSED) +{ + unsigned maximum_regs, maximum_bytes, start_regno, regno; + rtx value4word; + rtx dst_base_reg, new_base_reg; + unsigned HOST_WIDE_INT remain_bytes, remain_words, prepare_regs, fill_per_smw; + unsigned HOST_WIDE_INT real_size; + + if (TARGET_REDUCED_REGS) + { + maximum_regs = 4; + maximum_bytes = 64; + start_regno = 2; + } + else + { + maximum_regs = 8; + maximum_bytes = 128; + start_regno = 16; + } + + real_size = UINTVAL (size) & GET_MODE_MASK(SImode); + + if (!(CONST_INT_P (size) && real_size <= maximum_bytes)) + return false; + + remain_bytes = real_size; + + gcc_assert (GET_MODE (value) == QImode || CONST_INT_P (value)); + + value4word = nds32_gen_dup_4_byte_to_word_value (value); + + prepare_regs = remain_bytes / UNITS_PER_WORD; + + dst_base_reg = copy_to_mode_reg (SImode, XEXP (dstmem, 0)); + + if (prepare_regs > maximum_regs) + prepare_regs = maximum_regs; + + fill_per_smw = prepare_regs * UNITS_PER_WORD; + + regno = start_regno; + switch (prepare_regs) + { + case 2: + default: + { + rtx reg0 = gen_rtx_REG (SImode, regno); + rtx reg1 = gen_rtx_REG (SImode, regno+1); + unsigned last_regno = start_regno + prepare_regs - 1; + + emit_move_insn (reg0, value4word); + emit_move_insn (reg1, value4word); + rtx regd = gen_rtx_REG (DImode, regno); + regno += 2; + + /* Try to utilize movd44! */ + while (regno <= last_regno) + { + if ((regno + 1) <=last_regno) + { + rtx reg = gen_rtx_REG (DImode, regno); + emit_move_insn (reg, regd); + regno += 2; + } + else + { + rtx reg = gen_rtx_REG (SImode, regno); + emit_move_insn (reg, reg0); + regno += 1; + } + } + break; + } + case 1: + { + rtx reg = gen_rtx_REG (SImode, regno++); + emit_move_insn (reg, value4word); + } + break; + case 0: + break; + } + + if (fill_per_smw) + for (;remain_bytes >= fill_per_smw;remain_bytes -= fill_per_smw) + { + emit_insn (nds32_expand_store_multiple (start_regno, prepare_regs, + dst_base_reg, dstmem, + true, &new_base_reg)); + dst_base_reg = new_base_reg; + dstmem = gen_rtx_MEM (SImode, dst_base_reg); + } + + remain_words = remain_bytes / UNITS_PER_WORD; + + if (remain_words) + { + emit_insn (nds32_expand_store_multiple (start_regno, remain_words, + dst_base_reg, dstmem, + true, &new_base_reg)); + dst_base_reg = new_base_reg; + dstmem = gen_rtx_MEM (SImode, dst_base_reg); + } + + remain_bytes = remain_bytes - (remain_words * UNITS_PER_WORD); + + if (remain_bytes) + { + value = simplify_gen_subreg (QImode, value4word, SImode, + subreg_lowpart_offset(QImode, SImode)); + int offset = 0; + for (;remain_bytes;--remain_bytes, ++offset) + { + nds32_emit_load_store (value, dstmem, QImode, offset, false); + } + } + + return true; +} + +bool +nds32_expand_setmem (rtx dstmem, rtx size, rtx value, rtx align, + rtx expected_align, + rtx expected_size) +{ + bool align_to_4_bytes = (INTVAL (align) & 3) == 0; + + /* Only expand at O3 */ + if (optimize_size || optimize < 3) + return false; + + if (TARGET_ISA_V3M && !align_to_4_bytes) + return nds32_expand_setmem_loop_v3m (dstmem, size, value); + + if (nds32_expand_setmem_unroll (dstmem, size, value, + align, expected_align, expected_size)) + return true; + + return nds32_expand_setmem_loop (dstmem, size, value); +} + +/* ------------------------------------------------------------------------ */ + +/* PART 4: Auxiliary function for expand movstr pattern. */ + +bool +nds32_expand_movstr (rtx dst_end_ptr, + rtx dstmem, + rtx srcmem) +{ + rtx tmp; + rtx dst_base_reg, src_base_reg; + rtx new_dst_base_reg, new_src_base_reg; + rtx last_non_null_char_ptr; + rtx ffbi_result; + rtx loop_label; + + if (optimize_size || optimize < 3) + return false; + + tmp = gen_reg_rtx (SImode); + ffbi_result = gen_reg_rtx (Pmode); + new_dst_base_reg = gen_reg_rtx (Pmode); + new_src_base_reg = gen_reg_rtx (Pmode); + dst_base_reg = copy_to_mode_reg (SImode, XEXP (dstmem, 0)); + src_base_reg = copy_to_mode_reg (SImode, XEXP (srcmem, 0)); + loop_label = gen_label_rtx (); + + emit_label (loop_label); + emit_insn (gen_lmwzb (new_src_base_reg, src_base_reg, tmp)); + emit_insn (gen_smwzb (new_dst_base_reg, dst_base_reg, tmp)); + emit_insn (gen_unspec_ffb (ffbi_result, tmp, const0_rtx)); + + emit_move_insn (src_base_reg, new_src_base_reg); + emit_move_insn (dst_base_reg, new_dst_base_reg); + + emit_cmp_and_jump_insns (ffbi_result, const0_rtx, EQ, NULL, + SImode, 1, loop_label); + + last_non_null_char_ptr = expand_binop (Pmode, add_optab, dst_base_reg, + ffbi_result, NULL_RTX, 0, OPTAB_WIDEN); + + emit_move_insn (dst_end_ptr, last_non_null_char_ptr); + + return true; +} + +/* ------------------------------------------------------------------------ */ + +/* PART 5: Auxiliary function for expand strlen pattern. */ + +bool +nds32_expand_strlen (rtx result, rtx str, + rtx target_char, rtx align ATTRIBUTE_UNUSED) +{ + rtx base_reg, backup_base_reg; + rtx ffb_result; + rtx target_char_ptr, length; + rtx loop_label, tmp; + + if (optimize_size || optimize < 3) + return false; + + gcc_assert (MEM_P (str)); + gcc_assert (CONST_INT_P (target_char) || REG_P (target_char)); + + base_reg = copy_to_mode_reg (SImode, XEXP (str, 0)); + loop_label = gen_label_rtx (); + + ffb_result = gen_reg_rtx (Pmode); + tmp = gen_reg_rtx (SImode); + backup_base_reg = gen_reg_rtx (SImode); + + /* Emit loop version of strlen. + move $backup_base, $base + .Lloop: + lmw.bim $tmp, [$base], $tmp, 0 + ffb $ffb_result, $tmp, $target_char ! is there $target_char? + beqz $ffb_result, .Lloop + add $last_char_ptr, $base, $ffb_result + sub $length, $last_char_ptr, $backup_base */ + + /* move $backup_base, $base */ + emit_move_insn (backup_base_reg, base_reg); + + /* .Lloop: */ + emit_label (loop_label); + /* lmw.bim $tmp, [$base], $tmp, 0 */ + emit_insn (gen_unaligned_load_update_base_w (base_reg, tmp, base_reg)); + + /* ffb $ffb_result, $tmp, $target_char ! is there $target_char? */ + emit_insn (gen_unspec_ffb (ffb_result, tmp, target_char)); + + /* beqz $ffb_result, .Lloop */ + emit_cmp_and_jump_insns (ffb_result, const0_rtx, EQ, NULL, + SImode, 1, loop_label); + + /* add $target_char_ptr, $base, $ffb_result */ + target_char_ptr = expand_binop (Pmode, add_optab, base_reg, + ffb_result, NULL_RTX, 0, OPTAB_WIDEN); + + /* sub $length, $target_char_ptr, $backup_base */ + length = expand_binop (Pmode, sub_optab, target_char_ptr, + backup_base_reg, NULL_RTX, 0, OPTAB_WIDEN); + + emit_move_insn (result, length); + + return true; +} /* ------------------------------------------------------------------------ */ +/* PART 6: Auxiliary function for expand load_multiple/store_multiple + pattern. */ + /* Functions to expand load_multiple and store_multiple. They are auxiliary extern functions to help create rtx template. Check nds32-multiple.md file for the patterns. */ rtx nds32_expand_load_multiple (int base_regno, int count, - rtx base_addr, rtx basemem) + rtx base_addr, rtx basemem, + bool update_base_reg_p, + rtx *update_base_reg) { int par_index; int offset; + int start_idx; rtx result; rtx new_addr, mem, reg; + /* Generate a unaligned load to prevent load instruction pull out from + parallel, and then it will generate lwi, and lose unaligned acces */ + if (count == 1) + { + reg = gen_rtx_REG (SImode, base_regno); + if (update_base_reg_p) + { + *update_base_reg = gen_reg_rtx (SImode); + return gen_unaligned_load_update_base_w (*update_base_reg, reg, base_addr); + } + else + return gen_unaligned_load_w (reg, gen_rtx_MEM (SImode, base_addr)); + } + /* Create the pattern that is presented in nds32-multiple.md. */ + if (update_base_reg_p) + { + result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 1)); + start_idx = 1; + } + else + { + result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + start_idx = 0; + } + + if (update_base_reg_p) + { + offset = count * 4; + new_addr = plus_constant (Pmode, base_addr, offset); + *update_base_reg = gen_reg_rtx (SImode); - result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + XVECEXP (result, 0, 0) = gen_rtx_SET (*update_base_reg, new_addr); + } for (par_index = 0; par_index < count; par_index++) { @@ -57,7 +1284,7 @@ nds32_expand_load_multiple (int base_regno, int count, new_addr, offset); reg = gen_rtx_REG (SImode, base_regno + par_index); - XVECEXP (result, 0, par_index) = gen_rtx_SET (reg, mem); + XVECEXP (result, 0, (par_index + start_idx)) = gen_rtx_SET (reg, mem); } return result; @@ -65,16 +1292,49 @@ nds32_expand_load_multiple (int base_regno, int count, rtx nds32_expand_store_multiple (int base_regno, int count, - rtx base_addr, rtx basemem) + rtx base_addr, rtx basemem, + bool update_base_reg_p, + rtx *update_base_reg) { int par_index; int offset; + int start_idx; rtx result; rtx new_addr, mem, reg; + if (count == 1) + { + reg = gen_rtx_REG (SImode, base_regno); + if (update_base_reg_p) + { + *update_base_reg = gen_reg_rtx (SImode); + return gen_unaligned_store_update_base_w (*update_base_reg, base_addr, reg); + } + else + return gen_unaligned_store_w (gen_rtx_MEM (SImode, base_addr), reg); + } + /* Create the pattern that is presented in nds32-multiple.md. */ - result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + if (update_base_reg_p) + { + result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 1)); + start_idx = 1; + } + else + { + result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + start_idx = 0; + } + + if (update_base_reg_p) + { + offset = count * 4; + new_addr = plus_constant (Pmode, base_addr, offset); + *update_base_reg = gen_reg_rtx (SImode); + + XVECEXP (result, 0, 0) = gen_rtx_SET (*update_base_reg, new_addr); + } for (par_index = 0; par_index < count; par_index++) { @@ -85,58 +1345,11 @@ nds32_expand_store_multiple (int base_regno, int count, new_addr, offset); reg = gen_rtx_REG (SImode, base_regno + par_index); - XVECEXP (result, 0, par_index) = gen_rtx_SET (mem, reg); + XVECEXP (result, 0, par_index + start_idx) = gen_rtx_SET (mem, reg); } - return result; -} - -/* Function to move block memory content by - using load_multiple and store_multiple. - This is auxiliary extern function to help create rtx template. - Check nds32-multiple.md file for the patterns. */ -int -nds32_expand_movmemqi (rtx dstmem, rtx srcmem, rtx total_bytes, rtx alignment) -{ - HOST_WIDE_INT in_words, out_words; - rtx dst_base_reg, src_base_reg; - int maximum_bytes; - - /* Because reduced-set regsiters has few registers - (r0~r5, r6~10, r15, r28~r31, where 'r15' and 'r28~r31' - cannot be used for register allocation), - using 8 registers (32 bytes) for moving memory block - may easily consume all of them. - It makes register allocation/spilling hard to work. - So we only allow maximum=4 registers (16 bytes) for - moving memory block under reduced-set registers. */ - if (TARGET_REDUCED_REGS) - maximum_bytes = 16; - else - maximum_bytes = 32; - - /* 1. Total_bytes is integer for sure. - 2. Alignment is integer for sure. - 3. Maximum 4 or 8 registers, 4 * 4 = 16 bytes, 8 * 4 = 32 bytes. - 4. Requires (n * 4) block size. - 5. Requires 4-byte alignment. */ - if (GET_CODE (total_bytes) != CONST_INT - || GET_CODE (alignment) != CONST_INT - || INTVAL (total_bytes) > maximum_bytes - || INTVAL (total_bytes) & 3 - || INTVAL (alignment) & 3) - return 0; - dst_base_reg = copy_to_mode_reg (SImode, XEXP (dstmem, 0)); - src_base_reg = copy_to_mode_reg (SImode, XEXP (srcmem, 0)); - - out_words = in_words = INTVAL (total_bytes) / UNITS_PER_WORD; - - emit_insn (nds32_expand_load_multiple (0, in_words, src_base_reg, srcmem)); - emit_insn (nds32_expand_store_multiple (0, out_words, dst_base_reg, dstmem)); - - /* Successfully create patterns, return 1. */ - return 1; + return result; } /* ------------------------------------------------------------------------ */ diff --git a/gcc/config/nds32/nds32-modes.def b/gcc/config/nds32/nds32-modes.def index f2d0e6c..7a6f953 100644 --- a/gcc/config/nds32/nds32-modes.def +++ b/gcc/config/nds32/nds32-modes.def @@ -18,4 +18,6 @@ along with GCC; see the file COPYING3. If not see . */ -/* So far, there is no need to define any modes for nds32 target. */ +/* Vector modes. */ +VECTOR_MODES (INT, 4); /* V4QI V2HI */ +VECTOR_MODES (INT, 8); /* V8QI V4HI V2SI */ diff --git a/gcc/config/nds32/nds32-multiple.md b/gcc/config/nds32/nds32-multiple.md index babc7f2..500a1c6 100644 --- a/gcc/config/nds32/nds32-multiple.md +++ b/gcc/config/nds32/nds32-multiple.md @@ -49,17 +49,19 @@ otherwise we have to FAIL this rtx generation: 1. The number of consecutive registers must be integer. 2. Maximum 4 or 8 registers for lmw.bi instruction - (based on this nds32-multiple.md design). + (based on this nds32-multiple.md design). 3. Minimum 2 registers for lmw.bi instruction - (based on this nds32-multiple.md design). + (based on this nds32-multiple.md design). 4. operands[0] must be register for sure. 5. operands[1] must be memory for sure. - 6. Do not cross $r15 register because it is not allocatable. */ + 6. operands[1] is not volatile memory access. + 7. Do not cross $r15 register because it is not allocatable. */ if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) > maximum || INTVAL (operands[2]) < 2 || GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != MEM + || MEM_VOLATILE_P (operands[1]) || REGNO (operands[0]) + INTVAL (operands[2]) > TA_REGNUM) FAIL; @@ -69,12 +71,943 @@ INTVAL (operands[2]), force_reg (SImode, XEXP (operands[1], 0)), - operands[1]); + operands[1], + false, NULL); }) ;; Ordinary Load Multiple. +(define_insn "*lmw_bim_si25" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 100))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 52)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 56)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 60)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 64)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 68)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 72)))) + (set (match_operand:SI 22 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 76)))) + (set (match_operand:SI 23 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 80)))) + (set (match_operand:SI 24 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 84)))) + (set (match_operand:SI 25 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 88)))) + (set (match_operand:SI 26 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 92)))) + (set (match_operand:SI 27 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 96))))])] + "(XVECLEN (operands[0], 0) == 26)" + "lmw.bim\t%3, [%1], %27, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "25") + (set_attr "length" "4")] +) -(define_insn "*lmwsi8" +(define_insn "*lmw_bim_si24" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 96))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 52)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 56)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 60)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 64)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 68)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 72)))) + (set (match_operand:SI 22 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 76)))) + (set (match_operand:SI 23 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 80)))) + (set (match_operand:SI 24 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 84)))) + (set (match_operand:SI 25 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 88)))) + (set (match_operand:SI 26 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 92))))])] + "(XVECLEN (operands[0], 0) == 25)" + "lmw.bim\t%3, [%1], %26, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "24") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si23" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 92))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 52)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 56)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 60)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 64)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 68)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 72)))) + (set (match_operand:SI 22 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 76)))) + (set (match_operand:SI 23 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 80)))) + (set (match_operand:SI 24 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 84)))) + (set (match_operand:SI 25 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 88))))])] + "(XVECLEN (operands[0], 0) == 24)" + "lmw.bim\t%3, [%1], %25, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "23") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si22" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 88))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 52)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 56)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 60)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 64)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 68)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 72)))) + (set (match_operand:SI 22 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 76)))) + (set (match_operand:SI 23 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 80)))) + (set (match_operand:SI 24 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 84))))])] + "(XVECLEN (operands[0], 0) == 23)" + "lmw.bim\t%3, [%1], %24, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "22") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si21" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 84))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 52)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 56)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 60)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 64)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 68)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 72)))) + (set (match_operand:SI 22 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 76)))) + (set (match_operand:SI 23 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 80))))])] + "(XVECLEN (operands[0], 0) == 22)" + "lmw.bim\t%3, [%1], %23, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "21") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si20" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 80))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 52)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 56)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 60)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 64)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 68)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 72)))) + (set (match_operand:SI 22 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 76))))])] + "(XVECLEN (operands[0], 0) == 21)" + "lmw.bim\t%3, [%1], %22, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "20") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si19" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 76))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 52)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 56)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 60)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 64)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 68)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 72))))])] + "(XVECLEN (operands[0], 0) == 20)" + "lmw.bim\t%3, [%1], %21, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "19") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si18" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 72))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 52)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 56)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 60)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 64)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 68))))])] + "(XVECLEN (operands[0], 0) == 19)" + "lmw.bim\t%3, [%1], %20, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "18") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si17" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 68))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 52)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 56)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 60)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 64))))])] + "(XVECLEN (operands[0], 0) == 18)" + "lmw.bim\t%3, [%1], %19, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "17") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si16" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 64))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 52)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 56)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 60))))])] + "(XVECLEN (operands[0], 0) == 17)" + "lmw.bim\t%3, [%1], %18, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "16") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si15" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 60))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 52)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 56))))])] + "(XVECLEN (operands[0], 0) == 16)" + "lmw.bim\t%3, [%1], %17, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "15") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si14" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 56))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 52))))])] + "(XVECLEN (operands[0], 0) == 15)" + "lmw.bim\t%3, [%1], %16, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "14") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si13" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 52))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 48))))])] + "(XVECLEN (operands[0], 0) == 14)" + "lmw.bim\t%3, [%1], %15, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "13") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si12" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 48))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 44))))])] + "(XVECLEN (operands[0], 0) == 13)" + "lmw.bim\t%3, [%1], %14, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "12") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si11" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 44))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 40))))])] + "(XVECLEN (operands[0], 0) == 12)" + "lmw.bim\t%3, [%1], %13, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "11") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si10" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 40))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 36))))])] + "(XVECLEN (operands[0], 0) == 11)" + "lmw.bim\t%3, [%1], %12, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "10") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si9" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 36))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 32))))])] + "(XVECLEN (operands[0], 0) == 10)" + "lmw.bim\t%3, [%1], %11, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "9") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si8" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 32))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 28))))])] + "(XVECLEN (operands[0], 0) == 9)" + "lmw.bim\t%3, [%1], %10, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "8") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si7" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 28))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 24))))])] + "(XVECLEN (operands[0], 0) == 8)" + "lmw.bim\t%3, [%1], %9, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "7") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si6" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 24))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 20))))])] + "(XVECLEN (operands[0], 0) == 7)" + "lmw.bim\t%3, [%1], %8, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "6") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si5" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 20))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 16))))])] + "(XVECLEN (operands[0], 0) == 6)" + "lmw.bim\t%3, [%1], %7, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "5") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si4" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 16))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 12))))])] + "(XVECLEN (operands[0], 0) == 5)" + "lmw.bim\t%3, [%1], %6, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "4") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si3" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 12))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 8))))])] + "(XVECLEN (operands[0], 0) == 4)" + "lmw.bim\t%3, [%1], %5, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "3") + (set_attr "length" "4")] +) + +(define_insn "*lmw_bim_si2" + [(match_parallel 0 "nds32_load_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 8))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 2) (const_int 4))))])] + "(XVECLEN (operands[0], 0) == 3)" + "lmw.bim\t%3, [%1], %4, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "2") + (set_attr "length" "4")] +) + +(define_expand "unaligned_load_update_base_w" + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_operand:SI 2 "register_operand" "") (const_int 4))) + (set (match_operand:SI 1 "register_operand" "") + (unspec:SI [(mem:SI (match_dup 2))] UNSPEC_UALOAD_W))])] + "" +{ + /* DO NOT emit unaligned_load_w_m immediately since web pass don't + recognize post_inc, try it again after GCC 5.0. + REF: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63156 */ + emit_insn (gen_unaligned_load_w (operands[1], gen_rtx_MEM (SImode, operands[2]))); + emit_insn (gen_addsi3 (operands[0], operands[2], gen_int_mode (4, Pmode))); + DONE; +} + [(set_attr "type" "load_multiple") + (set_attr "combo" "1") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi25" [(match_parallel 0 "nds32_load_multiple_operation" [(set (match_operand:SI 2 "register_operand" "") (mem:SI (match_operand:SI 1 "register_operand" "r"))) @@ -91,14 +1024,49 @@ (set (match_operand:SI 8 "register_operand" "") (mem:SI (plus:SI (match_dup 1) (const_int 24)))) (set (match_operand:SI 9 "register_operand" "") - (mem:SI (plus:SI (match_dup 1) (const_int 28))))])] - "(XVECLEN (operands[0], 0) == 8)" - "lmw.bi\t%2, [%1], %9, 0x0" - [(set_attr "type" "load") - (set_attr "length" "4")] + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 52)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 56)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 60)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 64)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 68)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 72)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 76)))) + (set (match_operand:SI 22 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 80)))) + (set (match_operand:SI 23 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 84)))) + (set (match_operand:SI 24 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 88)))) + (set (match_operand:SI 25 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 92)))) + (set (match_operand:SI 26 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 96))))])] + "(XVECLEN (operands[0], 0) == 25)" + "lmw.bi\t%2, [%1], %26, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "25") + (set_attr "length" "4")] ) -(define_insn "*lmwsi7" +(define_insn "*lmwsi24" [(match_parallel 0 "nds32_load_multiple_operation" [(set (match_operand:SI 2 "register_operand" "") (mem:SI (match_operand:SI 1 "register_operand" "r"))) @@ -113,14 +1081,49 @@ (set (match_operand:SI 7 "register_operand" "") (mem:SI (plus:SI (match_dup 1) (const_int 20)))) (set (match_operand:SI 8 "register_operand" "") - (mem:SI (plus:SI (match_dup 1) (const_int 24))))])] - "(XVECLEN (operands[0], 0) == 7)" - "lmw.bi\t%2, [%1], %8, 0x0" - [(set_attr "type" "load") - (set_attr "length" "4")] + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 52)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 56)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 60)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 64)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 68)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 72)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 76)))) + (set (match_operand:SI 22 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 80)))) + (set (match_operand:SI 23 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 84)))) + (set (match_operand:SI 24 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 88)))) + (set (match_operand:SI 25 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 92))))])] + "(XVECLEN (operands[0], 0) == 24)" + "lmw.bi\t%2, [%1], %25, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "24") + (set_attr "length" "4")] ) -(define_insn "*lmwsi6" +(define_insn "*lmwsi23" [(match_parallel 0 "nds32_load_multiple_operation" [(set (match_operand:SI 2 "register_operand" "") (mem:SI (match_operand:SI 1 "register_operand" "r"))) @@ -133,14 +1136,49 @@ (set (match_operand:SI 6 "register_operand" "") (mem:SI (plus:SI (match_dup 1) (const_int 16)))) (set (match_operand:SI 7 "register_operand" "") - (mem:SI (plus:SI (match_dup 1) (const_int 20))))])] - "(XVECLEN (operands[0], 0) == 6)" - "lmw.bi\t%2, [%1], %7, 0x0" - [(set_attr "type" "load") - (set_attr "length" "4")] + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 52)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 56)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 60)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 64)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 68)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 72)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 76)))) + (set (match_operand:SI 22 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 80)))) + (set (match_operand:SI 23 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 84)))) + (set (match_operand:SI 24 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 88))))])] + "(XVECLEN (operands[0], 0) == 23)" + "lmw.bi\t%2, [%1], %24, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "23") + (set_attr "length" "4")] ) -(define_insn "*lmwsi5" +(define_insn "*lmwsi22" [(match_parallel 0 "nds32_load_multiple_operation" [(set (match_operand:SI 2 "register_operand" "") (mem:SI (match_operand:SI 1 "register_operand" "r"))) @@ -151,110 +1189,2430 @@ (set (match_operand:SI 5 "register_operand" "") (mem:SI (plus:SI (match_dup 1) (const_int 12)))) (set (match_operand:SI 6 "register_operand" "") - (mem:SI (plus:SI (match_dup 1) (const_int 16))))])] - "(XVECLEN (operands[0], 0) == 5)" - "lmw.bi\t%2, [%1], %6, 0x0" - [(set_attr "type" "load") - (set_attr "length" "4")] + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 52)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 56)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 60)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 64)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 68)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 72)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 76)))) + (set (match_operand:SI 22 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 80)))) + (set (match_operand:SI 23 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 84))))])] + "(XVECLEN (operands[0], 0) == 22)" + "lmw.bi\t%2, [%1], %23, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "22") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi21" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 52)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 56)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 60)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 64)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 68)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 72)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 76)))) + (set (match_operand:SI 22 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 80))))])] + "(XVECLEN (operands[0], 0) == 21)" + "lmw.bi\t%2, [%1], %22, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "21") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi20" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 52)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 56)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 60)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 64)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 68)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 72)))) + (set (match_operand:SI 21 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 76))))])] + "(XVECLEN (operands[0], 0) == 20)" + "lmw.bi\t%2, [%1], %21, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "20") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi19" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 52)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 56)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 60)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 64)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 68)))) + (set (match_operand:SI 20 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 72))))])] + "(XVECLEN (operands[0], 0) == 19)" + "lmw.bi\t%2, [%1], %20, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "19") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi18" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 52)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 56)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 60)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 64)))) + (set (match_operand:SI 19 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 68))))])] + "(XVECLEN (operands[0], 0) == 18)" + "lmw.bi\t%2, [%1], %19, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "18") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi17" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 52)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 56)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 60)))) + (set (match_operand:SI 18 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 64))))])] + "(XVECLEN (operands[0], 0) == 17)" + "lmw.bi\t%2, [%1], %18, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "17") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi16" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 52)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 56)))) + (set (match_operand:SI 17 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 60))))])] + "(XVECLEN (operands[0], 0) == 16)" + "lmw.bi\t%2, [%1], %17, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "16") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi15" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 52)))) + (set (match_operand:SI 16 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 56))))])] + "(XVECLEN (operands[0], 0) == 15)" + "lmw.bi\t%2, [%1], %16, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "15") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi14" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48)))) + (set (match_operand:SI 15 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 52))))])] + "(XVECLEN (operands[0], 0) == 14)" + "lmw.bi\t%2, [%1], %15, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "14") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi13" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44)))) + (set (match_operand:SI 14 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 48))))])] + "(XVECLEN (operands[0], 0) == 13)" + "lmw.bi\t%2, [%1], %14, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "13") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi12" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40)))) + (set (match_operand:SI 13 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 44))))])] + "(XVECLEN (operands[0], 0) == 12)" + "lmw.bi\t%2, [%1], %13, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "12") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi11" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36)))) + (set (match_operand:SI 12 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 40))))])] + "(XVECLEN (operands[0], 0) == 11)" + "lmw.bi\t%2, [%1], %12, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "11") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi10" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32)))) + (set (match_operand:SI 11 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 36))))])] + "(XVECLEN (operands[0], 0) == 10)" + "lmw.bi\t%2, [%1], %11, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "10") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi9" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28)))) + (set (match_operand:SI 10 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 32))))])] + "(XVECLEN (operands[0], 0) == 9)" + "lmw.bi\t%2, [%1], %10, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "9") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi8" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28))))])] + "(XVECLEN (operands[0], 0) == 8)" + "lmw.bi\t%2, [%1], %9, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "8") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi7" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24))))])] + "(XVECLEN (operands[0], 0) == 7)" + "lmw.bi\t%2, [%1], %8, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "7") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi6" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20))))])] + "(XVECLEN (operands[0], 0) == 6)" + "lmw.bi\t%2, [%1], %7, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "6") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi5" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16))))])] + "(XVECLEN (operands[0], 0) == 5)" + "lmw.bi\t%2, [%1], %6, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "5") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi4" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12))))])] + "(XVECLEN (operands[0], 0) == 4)" + "lmw.bi\t%2, [%1], %5, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "4") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi3" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8))))])] + "(XVECLEN (operands[0], 0) == 3)" + "lmw.bi\t%2, [%1], %4, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "3") + (set_attr "length" "4")] +) + +(define_insn "*lmwsi2" + [(match_parallel 0 "nds32_load_multiple_operation" + [(set (match_operand:SI 2 "register_operand" "") + (mem:SI (match_operand:SI 1 "register_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4))))])] + "(XVECLEN (operands[0], 0) == 2)" + "lmw.bi\t%2, [%1], %3, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "2") + (set_attr "length" "4")] +) + +;; Store Multiple Insns. +;; +;; operands[0] is the first memory location. +;; operands[1] is the first of the consecutive registers. +;; operands[2] is the number of consecutive registers. + +(define_expand "store_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "" +{ + int maximum; + + /* Because reduced-set regsiters has few registers + (r0~r5, r6~10, r15, r28~r31, where 'r15' and 'r28~r31' cannot + be used for register allocation), + using 8 registers for store_multiple may easily consume all of them. + It makes register allocation/spilling hard to work. + So we only allow maximum=4 registers for store_multiple + under reduced-set registers. */ + if (TARGET_REDUCED_REGS) + maximum = 4; + else + maximum = 8; + + /* Here are the conditions that must be all passed, + otherwise we have to FAIL this rtx generation: + 1. The number of consecutive registers must be integer. + 2. Maximum 4 or 8 registers for smw.bi instruction + (based on this nds32-multiple.md design). + 3. Minimum 2 registers for smw.bi instruction + (based on this nds32-multiple.md design). + 4. operands[0] must be memory for sure. + 5. operands[1] must be register for sure. + 6. operands[0] is not volatile memory access. + 7. Do not cross $r15 register because it is not allocatable. */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) > maximum + || INTVAL (operands[2]) < 2 + || GET_CODE (operands[0]) != MEM + || GET_CODE (operands[1]) != REG + || MEM_VOLATILE_P (operands[0]) + || REGNO (operands[1]) + INTVAL (operands[2]) > TA_REGNUM) + FAIL; + + /* For (mem addr), we force_reg on addr here, + so that nds32_expand_store_multiple can easily use it. */ + operands[3] = nds32_expand_store_multiple (REGNO (operands[1]), + INTVAL (operands[2]), + force_reg (SImode, + XEXP (operands[0], 0)), + operands[0], + false, NULL); +}) + +;; Ordinary Store Multiple. +(define_insn "*stm_bim_si25" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 100))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 52))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 56))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 60))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 64))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 68))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 72))) + (match_operand:SI 21 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 76))) + (match_operand:SI 22 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 80))) + (match_operand:SI 23 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 84))) + (match_operand:SI 24 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 88))) + (match_operand:SI 25 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 92))) + (match_operand:SI 26 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 96))) + (match_operand:SI 27 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 26)" + "smw.bim\t%3, [%1], %27, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "25") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si24" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 96))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 52))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 56))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 60))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 64))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 68))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 72))) + (match_operand:SI 21 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 76))) + (match_operand:SI 22 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 80))) + (match_operand:SI 23 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 84))) + (match_operand:SI 24 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 88))) + (match_operand:SI 25 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 92))) + (match_operand:SI 26 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 25)" + "smw.bim\t%3, [%1], %26, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "24") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si23" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 92))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 52))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 56))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 60))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 64))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 68))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 72))) + (match_operand:SI 21 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 76))) + (match_operand:SI 22 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 80))) + (match_operand:SI 23 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 84))) + (match_operand:SI 24 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 88))) + (match_operand:SI 25 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 24)" + "smw.bim\t%3, [%1], %25, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "23") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si22" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 88))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 52))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 56))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 60))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 64))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 68))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 72))) + (match_operand:SI 21 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 76))) + (match_operand:SI 22 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 80))) + (match_operand:SI 23 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 84))) + (match_operand:SI 24 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 23)" + "smw.bim\t%3, [%1], %24, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "22") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si21" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 84))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 52))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 56))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 60))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 64))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 68))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 72))) + (match_operand:SI 21 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 76))) + (match_operand:SI 22 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 80))) + (match_operand:SI 23 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 22)" + "smw.bim\t%3, [%1], %23, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "21") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si20" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 80))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 52))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 56))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 60))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 64))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 68))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 72))) + (match_operand:SI 21 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 76))) + (match_operand:SI 22 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 21)" + "smw.bim\t%3, [%1], %22, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "20") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si19" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 76))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 52))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 56))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 60))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 64))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 68))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 72))) + (match_operand:SI 21 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 20)" + "smw.bim\t%3, [%1], %21, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "19") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si18" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 72))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 52))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 56))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 60))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 64))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 68))) + (match_operand:SI 20 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 19)" + "smw.bim\t%3, [%1], %20, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "18") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si17" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 68))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 52))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 56))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 60))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 64))) + (match_operand:SI 19 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 18)" + "smw.bim\t%3, [%1], %19, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "17") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si16" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 64))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 52))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 56))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 60))) + (match_operand:SI 18 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 17)" + "smw.bim\t%3, [%1], %18, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "16") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si15" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 60))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 52))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 56))) + (match_operand:SI 17 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 16)" + "smw.bim\t%3, [%1], %17, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "15") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si14" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 56))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 52))) + (match_operand:SI 16 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 15)" + "smw.bim\t%3, [%1], %16, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "14") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si13" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 52))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 48))) + (match_operand:SI 15 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 14)" + "smw.bim\t%3, [%1], %15, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "13") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si12" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 48))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 44))) + (match_operand:SI 14 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 13)" + "smw.bim\t%3, [%1], %14, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "12") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si11" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 44))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 40))) + (match_operand:SI 13 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 12)" + "smw.bim\t%3, [%1], %13, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "11") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si10" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 40))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 36))) + (match_operand:SI 12 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 11)" + "smw.bim\t%3, [%1], %12, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "10") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si9" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 36))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 32))) + (match_operand:SI 11 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 10)" + "smw.bim\t%3, [%1], %11, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "9") + (set_attr "length" "4")] +) + + +(define_insn "*stm_bim_si8" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 32))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 28))) + (match_operand:SI 10 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 9)" + "smw.bim\t%3, [%1], %10, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "8") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si7" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 28))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 24))) + (match_operand:SI 9 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 8)" + "smw.bim\t%3, [%1], %9, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "7") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si6" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 24))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 20))) + (match_operand:SI 8 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 7)" + "smw.bim\t%3, [%1], %8, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "6") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si5" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 20))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 16))) + (match_operand:SI 7 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 6)" + "smw.bim\t%3, [%1], %7, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "5") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si4" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 16))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 12))) + (match_operand:SI 6 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 5)" + "smw.bim\t%3, [%1], %6, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "4") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si3" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 12))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 8))) + (match_operand:SI 5 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 4)" + "smw.bim\t%3, [%1], %5, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "3") + (set_attr "length" "4")] +) + +(define_insn "*stm_bim_si2" + [(match_parallel 0 "nds32_store_multiple_and_update_address_operation" + [(set (match_operand:SI 1 "register_operand" "=r") + (plus:SI (match_operand:SI 2 "register_operand" "1") (const_int 8))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 2) (const_int 4))) + (match_operand:SI 4 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 3)" + "smw.bim\t%3, [%1], %4, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "2") + (set_attr "length" "4")] +) + +(define_expand "unaligned_store_update_base_w" + [(parallel [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "register_operand" "0") (const_int 4))) + (set (mem:SI (match_dup 1)) + (unspec:SI [(match_operand:SI 2 "register_operand" "r")] UNSPEC_UASTORE_W))])] + "" +{ + /* DO NOT emit unaligned_store_w_m immediately since web pass don't + recognize post_inc, try it again after GCC 5.0. + REF: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63156 */ + emit_insn (gen_unaligned_store_w (gen_rtx_MEM (SImode, operands[1]), operands[2])); + emit_insn (gen_addsi3 (operands[0], operands[1], gen_int_mode (4, Pmode))); + DONE; +} + [(set_attr "type" "store_multiple") + (set_attr "combo" "1") + (set_attr "length" "4")] +) + +(define_expand "unaligned_store_update_base_dw" + [(parallel [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "register_operand" "0") (const_int 8))) + (set (mem:DI (match_dup 1)) + (unspec:DI [(match_operand:DI 2 "register_operand" "r")] UNSPEC_UASTORE_DW))])] + "" +{ + /* DO NOT emit unaligned_store_w_m immediately since web pass don't + recognize post_inc, try it again after GCC 5.0. + REF: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63156 */ + emit_insn (gen_unaligned_store_dw (gen_rtx_MEM (DImode, operands[1]), operands[2])); + emit_insn (gen_addsi3 (operands[0], operands[1], gen_int_mode (8, Pmode))); + DONE; +} + [(set_attr "type" "store_multiple") + (set_attr "combo" "2") + (set_attr "length" "4")] +) + +(define_insn "*stmsi25" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 52))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 56))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 60))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 64))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 68))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 72))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 76))) + (match_operand:SI 21 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 80))) + (match_operand:SI 22 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 84))) + (match_operand:SI 23 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 88))) + (match_operand:SI 24 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 92))) + (match_operand:SI 25 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 96))) + (match_operand:SI 26 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 25)" + "smw.bi\t%2, [%1], %26, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "25") + (set_attr "length" "4")] +) + +(define_insn "*stmsi24" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 52))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 56))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 60))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 64))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 68))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 72))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 76))) + (match_operand:SI 21 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 80))) + (match_operand:SI 22 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 84))) + (match_operand:SI 23 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 88))) + (match_operand:SI 24 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 92))) + (match_operand:SI 25 "register_operand" "")) +])] + "(XVECLEN (operands[0], 0) == 24)" + "smw.bi\t%2, [%1], %25, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "24") + (set_attr "length" "4")] +) + +(define_insn "*stmsi23" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 52))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 56))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 60))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 64))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 68))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 72))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 76))) + (match_operand:SI 21 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 80))) + (match_operand:SI 22 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 84))) + (match_operand:SI 23 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 88))) + (match_operand:SI 24 "register_operand" "")) +])] + "(XVECLEN (operands[0], 0) == 23)" + "smw.bi\t%2, [%1], %24, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "23") + (set_attr "length" "4")] +) + +(define_insn "*stmsi22" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 52))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 56))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 60))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 64))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 68))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 72))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 76))) + (match_operand:SI 21 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 80))) + (match_operand:SI 22 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 84))) + (match_operand:SI 23 "register_operand" "")) +])] + "(XVECLEN (operands[0], 0) == 22)" + "smw.bi\t%2, [%1], %23, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "22") + (set_attr "length" "4")] +) + +(define_insn "*stmsi21" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 52))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 56))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 60))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 64))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 68))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 72))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 76))) + (match_operand:SI 21 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 80))) + (match_operand:SI 22 "register_operand" "")) +])] + "(XVECLEN (operands[0], 0) == 21)" + "smw.bi\t%2, [%1], %22, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "21") + (set_attr "length" "4")] +) + +(define_insn "*stmsi20" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 52))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 56))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 60))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 64))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 68))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 72))) + (match_operand:SI 20 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 76))) + (match_operand:SI 21 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 20)" + "smw.bi\t%2, [%1], %21, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "20") + (set_attr "length" "4")] +) + +(define_insn "*stmsi19" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 52))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 56))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 60))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 64))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 68))) + (match_operand:SI 19 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 72))) + (match_operand:SI 20 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 19)" + "smw.bi\t%2, [%1], %20, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "19") + (set_attr "length" "4")] +) + +(define_insn "*stmsi18" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 52))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 56))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 60))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 64))) + (match_operand:SI 18 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 68))) + (match_operand:SI 19 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 18)" + "smw.bi\t%2, [%1], %19, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "18") + (set_attr "length" "4")] ) -(define_insn "*lmwsi4" - [(match_parallel 0 "nds32_load_multiple_operation" - [(set (match_operand:SI 2 "register_operand" "") - (mem:SI (match_operand:SI 1 "register_operand" "r"))) - (set (match_operand:SI 3 "register_operand" "") - (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (set (match_operand:SI 4 "register_operand" "") - (mem:SI (plus:SI (match_dup 1) (const_int 8)))) - (set (match_operand:SI 5 "register_operand" "") - (mem:SI (plus:SI (match_dup 1) (const_int 12))))])] - "(XVECLEN (operands[0], 0) == 4)" - "lmw.bi\t%2, [%1], %5, 0x0" - [(set_attr "type" "load") - (set_attr "length" "4")] +(define_insn "*stmsi17" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 52))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 56))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 60))) + (match_operand:SI 17 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 64))) + (match_operand:SI 18 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 17)" + "smw.bi\t%2, [%1], %18, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "17") + (set_attr "length" "4")] ) -(define_insn "*lmwsi3" - [(match_parallel 0 "nds32_load_multiple_operation" - [(set (match_operand:SI 2 "register_operand" "") - (mem:SI (match_operand:SI 1 "register_operand" "r"))) - (set (match_operand:SI 3 "register_operand" "") - (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (set (match_operand:SI 4 "register_operand" "") - (mem:SI (plus:SI (match_dup 1) (const_int 8))))])] - "(XVECLEN (operands[0], 0) == 3)" - "lmw.bi\t%2, [%1], %4, 0x0" - [(set_attr "type" "load") - (set_attr "length" "4")] +(define_insn "*stmsi16" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 52))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 56))) + (match_operand:SI 16 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 60))) + (match_operand:SI 17 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 16)" + "smw.bi\t%2, [%1], %17, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "16") + (set_attr "length" "4")] ) -(define_insn "*lmwsi2" - [(match_parallel 0 "nds32_load_multiple_operation" - [(set (match_operand:SI 2 "register_operand" "") - (mem:SI (match_operand:SI 1 "register_operand" "r"))) - (set (match_operand:SI 3 "register_operand" "") - (mem:SI (plus:SI (match_dup 1) (const_int 4))))])] - "(XVECLEN (operands[0], 0) == 2)" - "lmw.bi\t%2, [%1], %3, 0x0" - [(set_attr "type" "load") - (set_attr "length" "4")] +(define_insn "*stmsi15" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 52))) + (match_operand:SI 15 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 56))) + (match_operand:SI 16 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 15)" + "smw.bi\t%2, [%1], %16, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "15") + (set_attr "length" "4")] ) +(define_insn "*stmsi14" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 52))) + (match_operand:SI 15 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 14)" + "smw.bi\t%2, [%1], %15, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "14") + (set_attr "length" "4")] +) -;; Store Multiple Insns. -;; -;; operands[0] is the first memory location. -;; opernads[1] is the first of the consecutive registers. -;; operands[2] is the number of consecutive registers. - -(define_expand "store_multiple" - [(match_par_dup 3 [(set (match_operand:SI 0 "" "") - (match_operand:SI 1 "" "")) - (use (match_operand:SI 2 "" ""))])] - "" -{ - int maximum; +(define_insn "*stmsi13" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 48))) + (match_operand:SI 14 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 13)" + "smw.bi\t%2, [%1], %14, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "13") + (set_attr "length" "4")] +) - /* Because reduced-set regsiters has few registers - (r0~r5, r6~10, r15, r28~r31, where 'r15' and 'r28~r31' cannot - be used for register allocation), - using 8 registers for store_multiple may easily consume all of them. - It makes register allocation/spilling hard to work. - So we only allow maximum=4 registers for store_multiple - under reduced-set registers. */ - if (TARGET_REDUCED_REGS) - maximum = 4; - else - maximum = 8; +(define_insn "*stmsi12" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 44))) + (match_operand:SI 13 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 12)" + "smw.bi\t%2, [%1], %13, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "12") + (set_attr "length" "4")] +) - /* Here are the conditions that must be all passed, - otherwise we have to FAIL this rtx generation: - 1. The number of consecutive registers must be integer. - 2. Maximum 4 or 8 registers for smw.bi instruction - (based on this nds32-multiple.md design). - 3. Minimum 2 registers for smw.bi instruction - (based on this nds32-multiple.md design). - 4. operands[0] must be memory for sure. - 5. operands[1] must be register for sure. - 6. Do not cross $r15 register because it is not allocatable. */ - if (GET_CODE (operands[2]) != CONST_INT - || INTVAL (operands[2]) > maximum - || INTVAL (operands[2]) < 2 - || GET_CODE (operands[0]) != MEM - || GET_CODE (operands[1]) != REG - || REGNO (operands[1]) + INTVAL (operands[2]) > TA_REGNUM) - FAIL; +(define_insn "*stmsi11" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 40))) + (match_operand:SI 12 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 11)" + "smw.bi\t%2, [%1], %12, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "11") + (set_attr "length" "4")] +) - /* For (mem addr), we force_reg on addr here, - so that nds32_expand_store_multiple can easily use it. */ - operands[3] = nds32_expand_store_multiple (REGNO (operands[1]), - INTVAL (operands[2]), - force_reg (SImode, - XEXP (operands[0], 0)), - operands[0]); -}) +(define_insn "*stmsi10" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 36))) + (match_operand:SI 11 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 10)" + "smw.bi\t%2, [%1], %11, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "10") + (set_attr "length" "4")] +) -;; Ordinary Store Multiple. +(define_insn "*stmsi9" + [(match_parallel 0 "nds32_store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "register_operand" "r")) + (match_operand:SI 2 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 3 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 4 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 5 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 6 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 7 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 8 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 9 "register_operand" "")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 32))) + (match_operand:SI 10 "register_operand" ""))])] + "(XVECLEN (operands[0], 0) == 9)" + "smw.bi\t%2, [%1], %10, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "9") + (set_attr "length" "4")] +) (define_insn "*stmsi8" [(match_parallel 0 "nds32_store_multiple_operation" @@ -276,8 +3634,9 @@ (match_operand:SI 9 "register_operand" ""))])] "(XVECLEN (operands[0], 0) == 8)" "smw.bi\t%2, [%1], %9, 0x0" - [(set_attr "type" "store") - (set_attr "length" "4")] + [(set_attr "type" "store_multiple") + (set_attr "combo" "8") + (set_attr "length" "4")] ) (define_insn "*stmsi7" @@ -298,8 +3657,9 @@ (match_operand:SI 8 "register_operand" ""))])] "(XVECLEN (operands[0], 0) == 7)" "smw.bi\t%2, [%1], %8, 0x0" - [(set_attr "type" "store") - (set_attr "length" "4")] + [(set_attr "type" "store_multiple") + (set_attr "combo" "7") + (set_attr "length" "4")] ) (define_insn "*stmsi6" @@ -318,8 +3678,9 @@ (match_operand:SI 7 "register_operand" ""))])] "(XVECLEN (operands[0], 0) == 6)" "smw.bi\t%2, [%1], %7, 0x0" - [(set_attr "type" "store") - (set_attr "length" "4")] + [(set_attr "type" "store_multiple") + (set_attr "combo" "6") + (set_attr "length" "4")] ) (define_insn "*stmsi5" @@ -336,8 +3697,9 @@ (match_operand:SI 6 "register_operand" ""))])] "(XVECLEN (operands[0], 0) == 5)" "smw.bi\t%2, [%1], %6, 0x0" - [(set_attr "type" "store") - (set_attr "length" "4")] + [(set_attr "type" "store_multiple") + (set_attr "combo" "5") + (set_attr "length" "4")] ) (define_insn "*stmsi4" @@ -352,8 +3714,9 @@ (match_operand:SI 5 "register_operand" ""))])] "(XVECLEN (operands[0], 0) == 4)" "smw.bi\t%2, [%1], %5, 0x0" - [(set_attr "type" "store") - (set_attr "length" "4")] + [(set_attr "type" "store_multiple") + (set_attr "combo" "4") + (set_attr "length" "4")] ) (define_insn "*stmsi3" @@ -366,8 +3729,9 @@ (match_operand:SI 4 "register_operand" ""))])] "(XVECLEN (operands[0], 0) == 3)" "smw.bi\t%2, [%1], %4, 0x0" - [(set_attr "type" "store") - (set_attr "length" "4")] + [(set_attr "type" "store_multiple") + (set_attr "combo" "3") + (set_attr "length" "4")] ) (define_insn "*stmsi2" @@ -378,8 +3742,9 @@ (match_operand:SI 3 "register_operand" ""))])] "(XVECLEN (operands[0], 0) == 2)" "smw.bi\t%2, [%1], %3, 0x0" - [(set_attr "type" "store") - (set_attr "length" "4")] + [(set_attr "type" "store_multiple") + (set_attr "combo" "2") + (set_attr "length" "4")] ) ;; Move a block of memory if it is word aligned and MORE than 2 words long. @@ -391,14 +3756,14 @@ ;; operands[2] is the number of bytes to move. ;; operands[3] is the known shared alignment. -(define_expand "movmemqi" +(define_expand "movmemsi" [(match_operand:BLK 0 "general_operand" "") (match_operand:BLK 1 "general_operand" "") - (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 2 "nds32_reg_constant_operand" "") (match_operand:SI 3 "const_int_operand" "")] "" { - if (nds32_expand_movmemqi (operands[0], + if (nds32_expand_movmemsi (operands[0], operands[1], operands[2], operands[3])) @@ -408,3 +3773,75 @@ }) ;; ------------------------------------------------------------------------ + +(define_insn "lmwzb" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "register_operand" "0") (const_int 4))) + (set (match_operand:SI 2 "register_operand" "=r") + (unspec:SI [(mem:SI (match_dup 1))] UNSPEC_LMWZB))] + "" + "lmwzb.bm\t%2, [%1], %2, 0x0" + [(set_attr "type" "load_multiple") + (set_attr "combo" "1") + (set_attr "length" "4")] +) + +(define_insn "smwzb" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "register_operand" "0") (const_int 4))) + (set (mem:SI (match_dup 1)) + (unspec:SI [(match_operand:SI 2 "register_operand" "r")] UNSPEC_SMWZB))] + "" + "smwzb.bm\t%2, [%1], %2, 0x0" + [(set_attr "type" "store_multiple") + (set_attr "combo" "1") + (set_attr "length" "4")] +) + +(define_expand "movstr" + [(match_operand:SI 0 "register_operand" "") + (match_operand:BLK 1 "memory_operand" "") + (match_operand:BLK 2 "memory_operand" "")] + "TARGET_EXT_STRING && TARGET_INLINE_STRCPY" +{ + if (nds32_expand_movstr (operands[0], + operands[1], + operands[2])) + DONE; + + FAIL; +}) + +(define_expand "strlensi" + [(match_operand:SI 0 "register_operand") + (match_operand:BLK 1 "memory_operand") + (match_operand:QI 2 "nds32_reg_constant_operand") + (match_operand 3 "const_int_operand")] + "TARGET_EXT_STRING" +{ + if (nds32_expand_strlen (operands[0], operands[1], operands[2], operands[3])) + DONE; + + FAIL; +}) + +(define_expand "setmemsi" + [(use (match_operand:BLK 0 "memory_operand")) + (use (match_operand:SI 1 "nds32_reg_constant_operand")) + (use (match_operand:QI 2 "nonmemory_operand")) + (use (match_operand 3 "const_int_operand")) + (use (match_operand:SI 4 "const_int_operand")) + (use (match_operand:SI 5 "const_int_operand"))] + "" +{ + if (nds32_expand_setmem (operands[0], operands[1], + operands[2], operands[3], + operands[4], operands[5])) + DONE; + + FAIL; +}) + + + +;; ------------------------------------------------------------------------ diff --git a/gcc/config/nds32/nds32-n10.md b/gcc/config/nds32/nds32-n10.md new file mode 100644 index 0000000..7261608 --- /dev/null +++ b/gcc/config/nds32/nds32-n10.md @@ -0,0 +1,439 @@ +;; 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 N10 pipeline settings. +;; ------------------------------------------------------------------------ + +(define_automaton "nds32_n10_machine") + +;; ------------------------------------------------------------------------ +;; Pipeline Stages +;; ------------------------------------------------------------------------ +;; IF - Instruction Fetch +;; II - Instruction Issue / Instruction Decode +;; EX - Instruction Execution +;; MM - Memory Execution +;; WB - Instruction Retire / Result Write-Back + +(define_cpu_unit "n10_ii" "nds32_n10_machine") +(define_cpu_unit "n10_ex" "nds32_n10_machine") +(define_cpu_unit "n10_mm" "nds32_n10_machine") +(define_cpu_unit "n10_wb" "nds32_n10_machine") +(define_cpu_unit "n10f_iq" "nds32_n10_machine") +(define_cpu_unit "n10f_rf" "nds32_n10_machine") +(define_cpu_unit "n10f_e1" "nds32_n10_machine") +(define_cpu_unit "n10f_e2" "nds32_n10_machine") +(define_cpu_unit "n10f_e3" "nds32_n10_machine") +(define_cpu_unit "n10f_e4" "nds32_n10_machine") + +(define_insn_reservation "nds_n10_unknown" 1 + (and (eq_attr "type" "unknown") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_misc" 1 + (and (eq_attr "type" "misc") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_mmu" 1 + (and (eq_attr "type" "mmu") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_alu" 1 + (and (eq_attr "type" "alu") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_alu_shift" 1 + (and (eq_attr "type" "alu_shift") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ii+n10_ex, n10_ex+n10_mm, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_pbsad" 1 + (and (eq_attr "type" "pbsad") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex*3, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_pbsada" 1 + (and (eq_attr "type" "pbsada") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex*3, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_load" 1 + (and (match_test "nds32::load_single_p (insn)") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_store" 1 + (and (match_test "nds32::store_single_p (insn)") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_load_multiple_1" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "1"))) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_load_multiple_2" 1 + (and (eq_attr "pipeline_model" "n10") + (ior (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "2")) + (match_test "nds32::load_double_p (insn)"))) + "n10_ii, n10_ii+n10_ex, n10_ex+n10_mm, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_load_multiple_3" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "3"))) + "n10_ii, n10_ii+n10_ex, n10_ii+n10_ex+n10_mm, n10_ex+n10_mm+n10_wb, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_load_multiple_4" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "4"))) + "n10_ii, n10_ii+n10_ex, n10_ii+n10_ex+n10_mm, n10_ii+n10_ex+n10_mm+n10_wb, n10_ex+n10_mm+n10_wb, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_load_multiple_5" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "5"))) + "n10_ii, n10_ii+n10_ex, n10_ii+n10_ex+n10_mm, (n10_ii+n10_ex+n10_mm+n10_wb)*2, n10_ex+n10_mm+n10_wb, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_load_multiple_6" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "6"))) + "n10_ii, n10_ii+n10_ex, n10_ii+n10_ex+n10_mm, (n10_ii+n10_ex+n10_mm+n10_wb)*3, n10_ex+n10_mm+n10_wb, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_load_multiple_7" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "7"))) + "n10_ii, n10_ii+n10_ex, n10_ii+n10_ex+n10_mm, (n10_ii+n10_ex+n10_mm+n10_wb)*4, n10_ex+n10_mm+n10_wb, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_load_multiple_N" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "load_multiple") + (match_test "get_attr_combo (insn) >= 8"))) + "n10_ii, n10_ii+n10_ex, n10_ii+n10_ex+n10_mm, (n10_ii+n10_ex+n10_mm+n10_wb)*5, n10_ex+n10_mm+n10_wb, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_store_multiple_1" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "1"))) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_store_multiple_2" 1 + (and (eq_attr "pipeline_model" "n10") + (ior (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "2")) + (match_test "nds32::store_double_p (insn)"))) + "n10_ii, n10_ii+n10_ex, n10_ex+n10_mm, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_store_multiple_3" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "3"))) + "n10_ii, n10_ii+n10_ex, n10_ii+n10_ex+n10_mm, n10_ex+n10_mm+n10_wb, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_store_multiple_4" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "4"))) + "n10_ii, n10_ii+n10_ex, n10_ii+n10_ex+n10_mm, n10_ii+n10_ex+n10_mm+n10_wb, n10_ex+n10_mm+n10_wb, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_store_multiple_5" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "5"))) + "n10_ii, n10_ii+n10_ex, n10_ii+n10_ex+n10_mm, (n10_ii+n10_ex+n10_mm+n10_wb)*2, n10_ex+n10_mm+n10_wb, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_store_multiple_6" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "6"))) + "n10_ii, n10_ii+n10_ex, n10_ii+n10_ex+n10_mm, (n10_ii+n10_ex+n10_mm+n10_wb)*3, n10_ex+n10_mm+n10_wb, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_store_multiple_7" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "7"))) + "n10_ii, n10_ii+n10_ex, n10_ii+n10_ex+n10_mm, (n10_ii+n10_ex+n10_mm+n10_wb)*4, n10_ex+n10_mm+n10_wb, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_store_multiple_N" 1 + (and (eq_attr "pipeline_model" "n10") + (and (eq_attr "type" "store_multiple") + (match_test "get_attr_combo (insn) >= 8"))) + "n10_ii, n10_ii+n10_ex, n10_ii+n10_ex+n10_mm, (n10_ii+n10_ex+n10_mm+n10_wb)*5, n10_ex+n10_mm+n10_wb, n10_mm+n10_wb, n10_wb") + +(define_insn_reservation "nds_n10_mul" 1 + (and (eq_attr "type" "mul") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_mac" 1 + (and (eq_attr "type" "mac") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_div" 1 + (and (eq_attr "type" "div") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex*34, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_branch" 1 + (and (eq_attr "type" "branch") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_dsp_alu" 1 + (and (eq_attr "type" "dalu") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_dsp_alu64" 1 + (and (eq_attr "type" "dalu64") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_dsp_alu_round" 1 + (and (eq_attr "type" "daluround") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_dsp_cmp" 1 + (and (eq_attr "type" "dcmp") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_dsp_clip" 1 + (and (eq_attr "type" "dclip") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_dsp_mul" 1 + (and (eq_attr "type" "dmul") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_dsp_mac" 1 + (and (eq_attr "type" "dmac") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_dsp_insb" 1 + (and (eq_attr "type" "dinsb") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_dsp_pack" 1 + (and (eq_attr "type" "dpack") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_dsp_bpick" 1 + (and (eq_attr "type" "dbpick") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_dsp_wext" 1 + (and (eq_attr "type" "dwext") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ex, n10_mm, n10_wb") + +(define_insn_reservation "nds_n10_fpu_alu" 4 + (and (eq_attr "type" "falu") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10f_iq, n10f_rf, n10f_e1, n10f_e2, n10f_e3, n10f_e4") + +(define_insn_reservation "nds_n10_fpu_muls" 4 + (and (eq_attr "type" "fmuls") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10f_iq, n10f_rf, n10f_e1, n10f_e2, n10f_e3, n10f_e4") + +(define_insn_reservation "nds_n10_fpu_muld" 4 + (and (eq_attr "type" "fmuld") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10f_iq, n10f_rf, n10f_e1, n10f_e2*2, n10f_e3, n10f_e4") + +(define_insn_reservation "nds_n10_fpu_macs" 4 + (and (eq_attr "type" "fmacs") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10f_iq, n10f_rf, n10f_e1, n10f_e2*3, n10f_e3, n10f_e4") + +(define_insn_reservation "nds_n10_fpu_macd" 4 + (and (eq_attr "type" "fmacd") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10f_iq, n10f_rf, n10f_e1, n10f_e2*4, n10f_e3, n10f_e4") + +(define_insn_reservation "nds_n10_fpu_divs" 4 + (and (ior (eq_attr "type" "fdivs") + (eq_attr "type" "fsqrts")) + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10f_iq, n10f_rf, n10f_e1, n10f_e2*14, n10f_e3, n10f_e4") + +(define_insn_reservation "nds_n10_fpu_divd" 4 + (and (ior (eq_attr "type" "fdivd") + (eq_attr "type" "fsqrtd")) + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10f_iq, n10f_rf, n10f_e1, n10f_e2*28, n10f_e3, n10f_e4") + +(define_insn_reservation "nds_n10_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" "n10")) + "n10_ii, n10f_iq, n10f_rf, n10f_e1, n10f_e2, n10f_e3, n10f_e4") + +(define_insn_reservation "nds_n10_fpu_fmtsr" 4 + (and (eq_attr "type" "fmtsr") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10f_iq, n10f_rf, n10f_e1, n10f_e2, n10f_e3, n10f_e4") + +(define_insn_reservation "nds_n10_fpu_fmtdr" 4 + (and (eq_attr "type" "fmtdr") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ii+n10f_iq, n10f_iq+n10f_rf, n10f_rf+n10f_e1, n10f_e1+n10f_e2, n10f_e2+n10f_e3, n10f_e3+n10f_e4, n10f_e4") + +(define_insn_reservation "nds_n10_fpu_fmfsr" 2 + (and (eq_attr "type" "fmfsr") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10f_iq, n10f_rf, n10f_e1, n10f_e2, n10f_e3, n10f_e4") + +(define_insn_reservation "nds_n10_fpu_fmfdr" 2 + (and (eq_attr "type" "fmfdr") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10_ii+n10f_iq, n10f_iq+n10f_rf, n10f_rf+n10f_e1, n10f_e1+n10f_e2, n10f_e2+n10f_e3, n10f_e3+n10f_e4, n10f_e4") + +(define_insn_reservation "nds_n10_fpu_load" 3 + (and (eq_attr "type" "fload") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10f_iq, n10f_rf, n10f_e1, n10f_e2, n10f_e3, n10f_e4") + +(define_insn_reservation "nds_n10_fpu_store" 1 + (and (eq_attr "type" "fstore") + (eq_attr "pipeline_model" "n10")) + "n10_ii, n10f_iq, n10f_rf, n10f_e1, n10f_e2, n10f_e3, n10f_e4") + +;; ------------------------------------------------------------------------ +;; Comment Notations and Bypass Rules +;; ------------------------------------------------------------------------ +;; Producers (LHS) +;; LD +;; Load data from the memory and produce the loaded data. The result is +;; ready at MM. +;; 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 MM. +;; MUL, MAC +;; Compute data in the multiply-adder and produce the data. The result +;; is ready at MM. +;; DIV +;; Compute data in the divider and produce the data. The result is ready +;; at MM. +;; +;; Consumers (RHS) +;; ALU, MOVD44, PBSAD, PBSADA_RaRb, MUL, MAC, DIV, MMU +;; Require operands at EX. +;; ALU_SHIFT_Rb +;; An ALU-SHIFT instruction consists of a shift micro-operation followed +;; by an arithmetic micro-operation. The operand Rb is used by the first +;; micro-operation, and there are some latencies if data dependency occurs. +;; MAC_RaRb +;; A MAC instruction does multiplication at EX and does accumulation at MM, +;; so the operand Rt is required at MM, and operands Ra and Rb are required +;; at EX. +;; ADDR_IN +;; If an instruction requires an address as its input operand, the address +;; is required at EX. +;; ST +;; A store instruction requires its data at MM. +;; SMW(N, M) +;; There are N micro-operations within an instruction that stores multiple +;; words. Each M-th micro-operation requires its data at MM. +;; BR +;; If a branch instruction is conditional, its input data is required at EX. + +;; FPU_ADDR_OUT -> FPU_ADDR_IN +;; Main pipeline rules don't need this because those default latency is 1. +(define_bypass 1 + "nds_n10_fpu_load, nds_n10_fpu_store" + "nds_n10_fpu_load, nds_n10_fpu_store" + "nds32_n10_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_n10_load, nds_n10_mul, nds_n10_mac, nds_n10_div,\ + nds_n10_dsp_alu64, nds_n10_dsp_mul, nds_n10_dsp_mac,\ + nds_n10_dsp_alu_round, nds_n10_dsp_bpick, nds_n10_dsp_wext" + "nds_n10_alu, nds_n10_alu_shift,\ + nds_n10_pbsad, nds_n10_pbsada,\ + nds_n10_mul, nds_n10_mac, nds_n10_div,\ + nds_n10_branch,\ + nds_n10_load, nds_n10_store,\ + nds_n10_load_multiple_1, nds_n10_load_multiple_2, nds_n10_load_multiple_3,\ + nds_n10_load_multiple_4, nds_n10_load_multiple_5, nds_n10_load_multiple_6,\ + nds_n10_load_multiple_7, nds_n10_load_multiple_N,\ + nds_n10_store_multiple_1, nds_n10_store_multiple_2, nds_n10_store_multiple_3,\ + nds_n10_store_multiple_4, nds_n10_store_multiple_5, nds_n10_store_multiple_6,\ + nds_n10_store_multiple_7, nds_n10_store_multiple_N,\ + nds_n10_mmu,\ + nds_n10_dsp_alu, nds_n10_dsp_alu_round,\ + nds_n10_dsp_mul, nds_n10_dsp_mac, nds_n10_dsp_pack,\ + nds_n10_dsp_insb, nds_n10_dsp_cmp, nds_n10_dsp_clip,\ + nds_n10_dsp_wext, nds_n10_dsp_bpick" + "nds32_n10_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_n10_load_multiple_1, nds_n10_load_multiple_2, nds_n10_load_multiple_3,\ + nds_n10_load_multiple_4, nds_n10_load_multiple_5, nds_n10_load_multiple_6,\ + nds_n10_load_multiple_7, nds_n10_load_multiple_N" + "nds_n10_alu, nds_n10_alu_shift,\ + nds_n10_pbsad, nds_n10_pbsada,\ + nds_n10_mul, nds_n10_mac, nds_n10_div,\ + nds_n10_branch,\ + nds_n10_load, nds_n10_store,\ + nds_n10_load_multiple_1, nds_n10_load_multiple_2, nds_n10_load_multiple_3,\ + nds_n10_load_multiple_4, nds_n10_load_multiple_5, nds_n10_load_multiple_6,\ + nds_n10_load_multiple_7, nds_n10_load_multiple_N,\ + nds_n10_store_multiple_1, nds_n10_store_multiple_2, nds_n10_store_multiple_3,\ + nds_n10_store_multiple_4, nds_n10_store_multiple_5, nds_n10_store_multiple_6,\ + nds_n10_store_multiple_7, nds_n10_store_multiple_N,\ + nds_n10_mmu,\ + nds_n10_dsp_alu, nds_n10_dsp_alu_round,\ + nds_n10_dsp_mul, nds_n10_dsp_mac, nds_n10_dsp_pack,\ + nds_n10_dsp_insb, nds_n10_dsp_cmp, nds_n10_dsp_clip,\ + nds_n10_dsp_wext, nds_n10_dsp_bpick" + "nds32_n10_last_load_to_ex_p" +) diff --git a/gcc/config/nds32/nds32-n13.md b/gcc/config/nds32/nds32-n13.md new file mode 100644 index 0000000..622480d --- /dev/null +++ b/gcc/config/nds32/nds32-n13.md @@ -0,0 +1,401 @@ +;; 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 N13 pipeline settings. +;; ------------------------------------------------------------------------ + +(define_automaton "nds32_n13_machine") + +;; ------------------------------------------------------------------------ +;; Pipeline Stages +;; ------------------------------------------------------------------------ +;; F1 - Instruction Fetch First +;; Instruction Tag/Data Arrays +;; ITLB Address Translation +;; Branch Target Buffer Prediction +;; F2 - Instruction Fetch Second +;; Instruction Cache Hit Detection +;; Cache Way Selection +;; Inustruction Alignment +;; I1 - Instruction Issue First / Instruction Decode +;; Instruction Cache Replay Triggering +;; 32/16-Bit Instruction Decode +;; Return Address Stack Prediction +;; I2 - Instruction Issue Second / Register File Access +;; Instruction Issue Logic +;; Register File Access +;; E1 - Instruction Execute First / Address Generation / MAC First +;; Data Access Address generation +;; Multiply Operation +;; E2 - Instruction Execute Second / Data Access First / MAC Second / +;; ALU Execute +;; Skewed ALU +;; Branch/Jump/Return Resolution +;; Data Tag/Data arrays +;; DTLB address translation +;; Accumulation Operation +;; E3 - Instruction Execute Third / Data Access Second +;; Data Cache Hit Detection +;; Cache Way Selection +;; Data Alignment +;; E4 - Instruction Execute Fourth / Write Back +;; Interruption Resolution +;; Instruction Retire +;; Register File Write Back + +(define_cpu_unit "n13_i1" "nds32_n13_machine") +(define_cpu_unit "n13_i2" "nds32_n13_machine") +(define_cpu_unit "n13_e1" "nds32_n13_machine") +(define_cpu_unit "n13_e2" "nds32_n13_machine") +(define_cpu_unit "n13_e3" "nds32_n13_machine") +(define_cpu_unit "n13_e4" "nds32_n13_machine") + +(define_insn_reservation "nds_n13_unknown" 1 + (and (eq_attr "type" "unknown") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1, n13_e2, n13_e3, n13_e4") + +(define_insn_reservation "nds_n13_misc" 1 + (and (eq_attr "type" "misc") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1, n13_e2, n13_e3, n13_e4") + +(define_insn_reservation "nds_n13_mmu" 1 + (and (eq_attr "type" "mmu") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1, n13_e2, n13_e3, n13_e4") + +(define_insn_reservation "nds_n13_alu" 1 + (and (eq_attr "type" "alu") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1, n13_e2, n13_e3, n13_e4") + +(define_insn_reservation "nds_n13_alu_shift" 1 + (and (eq_attr "type" "alu_shift") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i2+n13_e1, n13_e1+n13_e2, n13_e2+n13_e3, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_pbsad" 1 + (and (eq_attr "type" "pbsad") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1, n13_e2*2, n13_e3, n13_e4") + +(define_insn_reservation "nds_n13_pbsada" 1 + (and (eq_attr "type" "pbsada") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1, n13_e2*3, n13_e3, n13_e4") + +(define_insn_reservation "nds_n13_load" 1 + (and (match_test "nds32::load_single_p (insn)") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1, n13_e2, n13_e3, n13_e4") + +(define_insn_reservation "nds_n13_store" 1 + (and (match_test "nds32::store_single_p (insn)") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1, n13_e2, n13_e3, n13_e4") + +(define_insn_reservation "nds_n13_load_multiple_1" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "1")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1, n13_e2, n13_e3, n13_e4") + +(define_insn_reservation "nds_n13_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" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i2+n13_e1, n13_e1+n13_e2, n13_e2+n13_e3, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_load_multiple_3" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "3")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2+n13_i2, n13_i1+n13_i2+n13_e1, n13_i2+n13_e1+n13_e2, n13_e1+n13_e2+n13_e3, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_load_multiple_4" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "4")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i1+n13_i2+n13_e1, n13_i1+n13_i2+n13_e1+n13_e2, n13_i2+n13_e1+n13_e2+n13_e3, n13_e1+n13_e2+n13_e3+n13_e4, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_load_multiple_5" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "5")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i1+n13_i2+n13_e1, n13_i1+n13_i2+n13_e1+n13_e2, n13_i1+n13_i2+n13_e1+n13_e2+n13_e3, n13_i2+n13_e1+n13_e2+n13_e3+n13_e4, n13_e1+n13_e2+n13_e3+n13_e4, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_load_multiple_6" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "6")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i1+n13_i2+n13_e1, n13_i1+n13_i2+n13_e1+n13_e2, n13_i1+n13_i2+n13_e1+n13_e2+n13_e3, n13_i1+n13_i2+n13_e1+n13_e2+n13_e3+n13_e4, n13_i2+n13_e1+n13_e2+n13_e3+n13_e4, n13_e1+n13_e2+n13_e3+n13_e4, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_load_multiple_7" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "7")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i1+n13_i2+n13_e1, n13_i1+n13_i2+n13_e1+n13_e2, n13_i1+n13_i2+n13_e1+n13_e2+n13_e3, (n13_i1+n13_i2+n13_e1+n13_e2+n13_e3+n13_e4)*2, n13_i2+n13_e1+n13_e2+n13_e3+n13_e4, n13_e1+n13_e2+n13_e3+n13_e4, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_load_multiple_8" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "8")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i1+n13_i2+n13_e1, n13_i1+n13_i2+n13_e1+n13_e2, n13_i1+n13_i2+n13_e1+n13_e2+n13_e3, (n13_i1+n13_i2+n13_e1+n13_e2+n13_e3+n13_e4)*3, n13_i2+n13_e1+n13_e2+n13_e3+n13_e4, n13_e1+n13_e2+n13_e3+n13_e4, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_load_multiple_12" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "12")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i1+n13_i2+n13_e1, n13_i1+n13_i2+n13_e1+n13_e2, n13_i1+n13_i2+n13_e1+n13_e2+n13_e3, (n13_i1+n13_i2+n13_e1+n13_e2+n13_e3+n13_e4)*7, n13_i2+n13_e1+n13_e2+n13_e3+n13_e4, n13_e1+n13_e2+n13_e3+n13_e4, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_store_multiple_1" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "1")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1, n13_e2, n13_e3, n13_e4") + +(define_insn_reservation "nds_n13_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" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i2+n13_e1, n13_e1+n13_e2, n13_e2+n13_e3, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_store_multiple_3" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "3")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2+n13_i2, n13_i1+n13_i2+n13_e1, n13_i2+n13_e1+n13_e2, n13_e1+n13_e2+n13_e3, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_store_multiple_4" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "4")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i1+n13_i2+n13_e1, n13_i1+n13_i2+n13_e1+n13_e2, n13_i2+n13_e1+n13_e2+n13_e3, n13_e1+n13_e2+n13_e3+n13_e4, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_store_multiple_5" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "5")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i1+n13_i2+n13_e1, n13_i1+n13_i2+n13_e1+n13_e2, n13_i1+n13_i2+n13_e1+n13_e2+n13_e3, n13_i2+n13_e1+n13_e2+n13_e3+n13_e4, n13_e1+n13_e2+n13_e3+n13_e4, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_store_multiple_6" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "6")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i1+n13_i2+n13_e1, n13_i1+n13_i2+n13_e1+n13_e2, n13_i1+n13_i2+n13_e1+n13_e2+n13_e3, n13_i1+n13_i2+n13_e1+n13_e2+n13_e3+n13_e4, n13_i2+n13_e1+n13_e2+n13_e3+n13_e4, n13_e1+n13_e2+n13_e3+n13_e4, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_store_multiple_7" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "7")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i1+n13_i2+n13_e1, n13_i1+n13_i2+n13_e1+n13_e2, n13_i1+n13_i2+n13_e1+n13_e2+n13_e3, (n13_i1+n13_i2+n13_e1+n13_e2+n13_e3+n13_e4)*2, n13_i2+n13_e1+n13_e2+n13_e3+n13_e4, n13_e1+n13_e2+n13_e3+n13_e4, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_store_multiple_8" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "8")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i1+n13_i2+n13_e1, n13_i1+n13_i2+n13_e1+n13_e2, n13_i1+n13_i2+n13_e1+n13_e2+n13_e3, (n13_i1+n13_i2+n13_e1+n13_e2+n13_e3+n13_e4)*3, n13_i2+n13_e1+n13_e2+n13_e3+n13_e4, n13_e1+n13_e2+n13_e3+n13_e4, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +(define_insn_reservation "nds_n13_store_multiple_12" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "12")) + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i1+n13_i2, n13_i1+n13_i2+n13_e1, n13_i1+n13_i2+n13_e1+n13_e2, n13_i1+n13_i2+n13_e1+n13_e2+n13_e3, (n13_i1+n13_i2+n13_e1+n13_e2+n13_e3+n13_e4)*7, n13_i2+n13_e1+n13_e2+n13_e3+n13_e4, n13_e1+n13_e2+n13_e3+n13_e4, n13_e2+n13_e3+n13_e4, n13_e3+n13_e4, n13_e4") + +;; The multiplier at E1 takes two cycles. +(define_insn_reservation "nds_n13_mul" 1 + (and (eq_attr "type" "mul") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1*2, n13_e2, n13_e3, n13_e4") + +(define_insn_reservation "nds_n13_mac" 1 + (and (eq_attr "type" "mac") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1*2, n13_e2, n13_e3, n13_e4") + +;; The cycles consumed at E2 are 32 - CLZ(abs(Ra)) + 2, +;; so the worst case is 34. +(define_insn_reservation "nds_n13_div" 1 + (and (eq_attr "type" "div") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1, n13_e2*34, n13_e3, n13_e4") + +(define_insn_reservation "nds_n13_branch" 1 + (and (eq_attr "type" "branch") + (eq_attr "pipeline_model" "n13")) + "n13_i1, n13_i2, n13_e1, n13_e2, n13_e3, n13_e4") + +;; ------------------------------------------------------------------------ +;; Comment Notations and Bypass Rules +;; ------------------------------------------------------------------------ +;; Producers (LHS) +;; LD +;; Load data from the memory and produce the loaded data. The result is +;; ready at E3. +;; 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 E3. +;; ADDR_OUT +;; Most load/store instructions can produce an address output if updating +;; the base register is required. The result is ready at E2, which is +;; produced by ALU. +;; ALU, ALU_SHIFT, SIMD +;; Compute data in ALU and produce the data. The result is ready at E2. +;; MUL, MAC +;; Compute data in the multiply-adder and produce the data. The result +;; is ready at E2. +;; DIV +;; Compute data in the divider and produce the data. The result is ready +;; at E2. +;; BR +;; Branch-with-link instructions produces a result containing the return +;; address. The result is ready at E2. +;; +;; Consumers (RHS) +;; ALU +;; General ALU instructions require operands at E2. +;; ALU_E1 +;; Some special ALU instructions, such as BSE, BSP and MOVD44, require +;; operand at E1. +;; MUL, DIV, PBSAD, MMU +;; Operands are required at E1. +;; PBSADA_Rt, PBSADA_RaRb +;; Operands Ra and Rb are required at E1, and the operand Rt is required +;; at E2. +;; ALU_SHIFT_Rb +;; An ALU-SHIFT instruction consists of a shift micro-operation followed +;; by an arithmetic micro-operation. The operand Rb is used by the first +;; micro-operation, and there are some latencies if data dependency occurs. +;; MAC_RaRb +;; A MAC instruction does multiplication at E1 and does accumulation at E2, +;; so the operand Rt is required at E2, and operands Ra and Rb are required +;; at E1. +;; ADDR_IN +;; If an instruction requires an address as its input operand, the address +;; is required at E1. +;; ST +;; A store instruction requires its data at E2. +;; SMW(N, M) +;; There are N micro-operations within an instruction that stores multiple +;; words. Each M-th micro-operation requires its data at E2. +;; BR +;; If a branch instruction is conditional, its input data is required at E2. + +;; LD -> ALU_E1, PBSAD, PBSADA_RaRb, MUL, MAC_RaRb, DIV, MMU, ADDR_IN +(define_bypass 3 + "nds_n13_load" + "nds_n13_alu, nds_n13_pbsad, nds_n13_pbsada,\ + nds_n13_mul, nds_n13_mac, nds_n13_div,\ + nds_n13_mmu,\ + nds_n13_load, nds_n13_store,\ + nds_n13_load_multiple_1,nds_n13_load_multiple_2, nds_n13_load_multiple_3,\ + nds_n13_load_multiple_4,nds_n13_load_multiple_5, nds_n13_load_multiple_6,\ + nds_n13_load_multiple_7,nds_n13_load_multiple_8, nds_n13_load_multiple_12,\ + nds_n13_store_multiple_1,nds_n13_store_multiple_2, nds_n13_store_multiple_3,\ + nds_n13_store_multiple_4,nds_n13_store_multiple_5, nds_n13_store_multiple_6,\ + nds_n13_store_multiple_7,nds_n13_store_multiple_8, nds_n13_store_multiple_12" + "nds32_n13_load_to_e1_p" +) + +;; LD -> ALU, ALU_SHIFT_Rb, PBSADA_Rt, BR, ST, SMW(N, 1) +(define_bypass 2 + "nds_n13_load" + "nds_n13_alu, nds_n13_alu_shift, nds_n13_pbsada, nds_n13_branch, nds_n13_store,\ + nds_n13_store_multiple_1,nds_n13_store_multiple_2, nds_n13_store_multiple_3,\ + nds_n13_store_multiple_4,nds_n13_store_multiple_5, nds_n13_store_multiple_6,\ + nds_n13_store_multiple_7,nds_n13_store_multiple_8, nds_n13_store_multiple_12" + "nds32_n13_load_to_e2_p" +) + +;; LMW(N, N) -> ALU_E1, PBSAD, PBSADA_RaRb, MUL, MAC_RaRb, DIV, MMU, ADDR_IN +(define_bypass 3 + "nds_n13_load_multiple_1,nds_n13_load_multiple_2, nds_n13_load_multiple_3,\ + nds_n13_load_multiple_4,nds_n13_load_multiple_5, nds_n13_load_multiple_6,\ + nds_n13_load_multiple_7,nds_n13_load_multiple_8, nds_n13_load_multiple_12" + "nds_n13_alu, nds_n13_pbsad, nds_n13_pbsada,\ + nds_n13_mul, nds_n13_mac, nds_n13_div,\ + nds_n13_mmu,\ + nds_n13_load, nds_n13_store,\ + nds_n13_load_multiple_1,nds_n13_load_multiple_2, nds_n13_load_multiple_3,\ + nds_n13_load_multiple_4,nds_n13_load_multiple_5, nds_n13_load_multiple_6,\ + nds_n13_load_multiple_7,nds_n13_load_multiple_8, nds_n13_load_multiple_12,\ + nds_n13_store_multiple_1,nds_n13_store_multiple_2, nds_n13_store_multiple_3,\ + nds_n13_store_multiple_4,nds_n13_store_multiple_5, nds_n13_store_multiple_6,\ + nds_n13_store_multiple_7,nds_n13_store_multiple_8, nds_n13_store_multiple_12" + "nds32_n13_last_load_to_e1_p") + +;; LMW(N, N) -> ALU, ALU_SHIFT_Rb, PBSADA_Rt, BR, ST, SMW(N, 1) +(define_bypass 2 + "nds_n13_load_multiple_1,nds_n13_load_multiple_2, nds_n13_load_multiple_3,\ + nds_n13_load_multiple_4,nds_n13_load_multiple_5, nds_n13_load_multiple_6,\ + nds_n13_load_multiple_7,nds_n13_load_multiple_8, nds_n13_load_multiple_12" + "nds_n13_alu, nds_n13_alu_shift, nds_n13_pbsada, nds_n13_branch, nds_n13_store,\ + nds_n13_store_multiple_1,nds_n13_store_multiple_2, nds_n13_store_multiple_3,\ + nds_n13_store_multiple_4,nds_n13_store_multiple_5, nds_n13_store_multiple_6,\ + nds_n13_store_multiple_7,nds_n13_store_multiple_8, nds_n13_store_multiple_12" + "nds32_n13_last_load_to_e2_p" +) + +;; LMW(N, N - 1) -> ALU_E1, PBSAD, PBSADA_RaRb, MUL, MAC_RaRb, DIV, MMU, ADDR_IN +(define_bypass 2 + "nds_n13_load_multiple_1,nds_n13_load_multiple_2, nds_n13_load_multiple_3,\ + nds_n13_load_multiple_4,nds_n13_load_multiple_5, nds_n13_load_multiple_6,\ + nds_n13_load_multiple_7,nds_n13_load_multiple_8, nds_n13_load_multiple_12" + "nds_n13_alu, nds_n13_pbsad, nds_n13_pbsada,\ + nds_n13_mul, nds_n13_mac, nds_n13_div,\ + nds_n13_mmu,\ + nds_n13_load, nds_n13_store,\ + nds_n13_load_multiple_1,nds_n13_load_multiple_2, nds_n13_load_multiple_3,\ + nds_n13_load_multiple_4,nds_n13_load_multiple_5, nds_n13_load_multiple_6,\ + nds_n13_load_multiple_7,nds_n13_load_multiple_8, nds_n13_load_multiple_12,\ + nds_n13_store_multiple_1,nds_n13_store_multiple_2, nds_n13_store_multiple_3,\ + nds_n13_store_multiple_4,nds_n13_store_multiple_5, nds_n13_store_multiple_6,\ + nds_n13_store_multiple_7,nds_n13_store_multiple_8, nds_n13_store_multiple_12" + "nds32_n13_last_two_load_to_e1_p") + +;; ALU, ALU_SHIFT, SIMD, BR, MUL, MAC, DIV, ADDR_OUT +;; -> ALU_E1, PBSAD, PBSADA_RaRb, MUL, MAC_RaRb, DIV, MMU, ADDR_IN +(define_bypass 2 + "nds_n13_alu, nds_n13_alu_shift, nds_n13_pbsad, nds_n13_pbsada, nds_n13_branch,\ + nds_n13_mul, nds_n13_mac, nds_n13_div,\ + nds_n13_load, nds_n13_store,\ + nds_n13_load_multiple_1,nds_n13_load_multiple_2, nds_n13_load_multiple_3,\ + nds_n13_load_multiple_4,nds_n13_load_multiple_5, nds_n13_load_multiple_6,\ + nds_n13_load_multiple_7,nds_n13_load_multiple_8, nds_n13_load_multiple_12,\ + nds_n13_store_multiple_1,nds_n13_store_multiple_2, nds_n13_store_multiple_3,\ + nds_n13_store_multiple_4,nds_n13_store_multiple_5, nds_n13_store_multiple_6,\ + nds_n13_store_multiple_7,nds_n13_store_multiple_8, nds_n13_store_multiple_12" + "nds_n13_alu, nds_n13_pbsad, nds_n13_pbsada,\ + nds_n13_mul, nds_n13_mac, nds_n13_div,\ + nds_n13_mmu,\ + nds_n13_load, nds_n13_store,\ + nds_n13_load_multiple_1,nds_n13_load_multiple_2, nds_n13_load_multiple_3,\ + nds_n13_load_multiple_4,nds_n13_load_multiple_5, nds_n13_load_multiple_6,\ + nds_n13_load_multiple_7,nds_n13_load_multiple_8, nds_n13_load_multiple_12,\ + nds_n13_store_multiple_1,nds_n13_store_multiple_2, nds_n13_store_multiple_3,\ + nds_n13_store_multiple_4,nds_n13_store_multiple_5, nds_n13_store_multiple_6,\ + nds_n13_store_multiple_7,nds_n13_store_multiple_8, nds_n13_store_multiple_12" + "nds32_n13_e2_to_e1_p") diff --git a/gcc/config/nds32/nds32-n7.md b/gcc/config/nds32/nds32-n7.md new file mode 100644 index 0000000..ff788ce --- /dev/null +++ b/gcc/config/nds32/nds32-n7.md @@ -0,0 +1,298 @@ +;; 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 N8 pipeline settings. +;; ------------------------------------------------------------------------ + +(define_automaton "nds32_n7_machine") + +;; ------------------------------------------------------------------------ +;; Pipeline Stages +;; ------------------------------------------------------------------------ +;; IF - Instruction Fetch +;; Instruction Alignment +;; Instruction Pre-decode +;; II - Instruction Issue +;; Instruction Decode +;; Register File Access +;; Instruction Execution +;; Interrupt Handling +;; EXD - Psuedo Stage +;; Load Data Completion + +(define_cpu_unit "n7_ii" "nds32_n7_machine") + +(define_insn_reservation "nds_n7_unknown" 1 + (and (eq_attr "type" "unknown") + (eq_attr "pipeline_model" "n7")) + "n7_ii") + +(define_insn_reservation "nds_n7_misc" 1 + (and (eq_attr "type" "misc") + (eq_attr "pipeline_model" "n7")) + "n7_ii") + +(define_insn_reservation "nds_n7_alu" 1 + (and (eq_attr "type" "alu") + (eq_attr "pipeline_model" "n7")) + "n7_ii") + +(define_insn_reservation "nds_n7_load" 1 + (and (match_test "nds32::load_single_p (insn)") + (eq_attr "pipeline_model" "n7")) + "n7_ii") + +(define_insn_reservation "nds_n7_store" 1 + (and (match_test "nds32::store_single_p (insn)") + (eq_attr "pipeline_model" "n7")) + "n7_ii") + +(define_insn_reservation "nds_n7_load_multiple_1" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "1")) + (eq_attr "pipeline_model" "n7")) + "n7_ii") + +(define_insn_reservation "nds_n7_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" "n7")) + "n7_ii*2") + +(define_insn_reservation "nds_n7_load_multiple_3" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "3")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*3") + +(define_insn_reservation "nds_n7_load_multiple_4" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "4")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*4") + +(define_insn_reservation "nds_n7_load_multiple_5" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "5")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*5") + +(define_insn_reservation "nds_n7_load_multiple_6" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "6")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*6") + +(define_insn_reservation "nds_n7_load_multiple_7" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "7")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*7") + +(define_insn_reservation "nds_n7_load_multiple_8" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "8")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*8") + +(define_insn_reservation "nds_n7_load_multiple_12" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "12")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*12") + +(define_insn_reservation "nds_n7_store_multiple_1" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "1")) + (eq_attr "pipeline_model" "n7")) + "n7_ii") + +(define_insn_reservation "nds_n7_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" "n7")) + "n7_ii*2") + +(define_insn_reservation "nds_n7_store_multiple_3" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "3")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*3") + +(define_insn_reservation "nds_n7_store_multiple_4" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "4")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*4") + +(define_insn_reservation "nds_n7_store_multiple_5" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "5")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*5") + +(define_insn_reservation "nds_n7_store_multiple_6" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "6")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*6") + +(define_insn_reservation "nds_n7_store_multiple_7" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "7")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*7") + +(define_insn_reservation "nds_n7_store_multiple_8" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "8")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*8") + +(define_insn_reservation "nds_n7_store_multiple_12" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "12")) + (eq_attr "pipeline_model" "n7")) + "n7_ii*12") + +(define_insn_reservation "nds_n7_mul_fast" 1 + (and (match_test "nds32_mul_config != MUL_TYPE_SLOW") + (and (eq_attr "type" "mul") + (eq_attr "pipeline_model" "n7"))) + "n7_ii") + +(define_insn_reservation "nds_n7_mul_slow" 1 + (and (match_test "nds32_mul_config == MUL_TYPE_SLOW") + (and (eq_attr "type" "mul") + (eq_attr "pipeline_model" "n7"))) + "n7_ii*17") + +(define_insn_reservation "nds_n7_mac_fast" 1 + (and (match_test "nds32_mul_config != MUL_TYPE_SLOW") + (and (eq_attr "type" "mac") + (eq_attr "pipeline_model" "n7"))) + "n7_ii*2") + +(define_insn_reservation "nds_n7_mac_slow" 1 + (and (match_test "nds32_mul_config == MUL_TYPE_SLOW") + (and (eq_attr "type" "mac") + (eq_attr "pipeline_model" "n7"))) + "n7_ii*18") + +(define_insn_reservation "nds_n7_div" 1 + (and (eq_attr "type" "div") + (eq_attr "pipeline_model" "n7")) + "n7_ii*37") + +(define_insn_reservation "nds_n7_branch" 1 + (and (eq_attr "type" "branch") + (eq_attr "pipeline_model" "n7")) + "n7_ii") + +;; ------------------------------------------------------------------------ +;; Comment Notations and Bypass Rules +;; ------------------------------------------------------------------------ +;; Producers (LHS) +;; LD_!bi +;; Load data from the memory (without updating the base register) 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. If the base register should be +;; updated, an extra micro-operation is inserted to the sequence, and the +;; result is ready at II. +;; +;; Consumers (RHS) +;; ALU, MUL, DIV +;; Require operands at II. +;; MOVD44_E +;; A double-word move instruction needs two micro-operations because the +;; reigster ports is 2R1W. The first micro-operation writes an even number +;; register, and the second micro-operation writes an odd number register. +;; Each input operand is required at II for each micro-operation. The letter +;; 'E' stands for even. +;; MAC_RaRb +;; A MAC instruction is separated into two micro-operations. The first +;; micro-operation does the multiplication, which requires operands Ra +;; and Rb at II. The second micro-options does the accumulation, which +;; requires the operand Rt at II. +;; ADDR_IN_MOP(N) +;; Because the reigster port is 2R1W, some load/store instructions are +;; separated into many micro-operations. N denotes the address input is +;; required by the N-th micro-operation. Such operand is required at II. +;; ST_bi +;; A post-increment store instruction requires its data at II. +;; ST_!bi_RI +;; A store instruction with an immediate offset requires its data at II. +;; If the offset field is a register (ST_!bi_RR), the instruction will be +;; separated into two micro-operations, and the second one requires the +;; input operand at II in order to store it to the memory. +;; SMW(N, M) +;; There are N micro-operations within an instruction that stores multiple +;; words. Each M-th micro-operation requires its data at II. If the base +;; register should be updated, an extra micro-operation is inserted to the +;; sequence. +;; BR_COND +;; If a branch instruction is conditional, its input data is required at II. + +;; LD_!bi +;; -> ALU, MOVD44_E, MUL, MAC_RaRb, DIV, BR, ADDR_IN_MOP(1), ST_bi, ST_!bi_RI, SMW(N, 1) +(define_bypass 2 + "nds_n7_load" + "nds_n7_alu,\ + nds_n7_mul_fast, nds_n7_mul_slow,\ + nds_n7_mac_fast, nds_n7_mac_slow,\ + nds_n7_div,\ + nds_n7_branch,\ + nds_n7_load, nds_n7_store,\ + nds_n7_load_multiple_1,nds_n7_load_multiple_2, nds_n7_load_multiple_3,\ + nds_n7_load_multiple_4,nds_n7_load_multiple_5, nds_n7_load_multiple_6,\ + nds_n7_load_multiple_7,nds_n7_load_multiple_8, nds_n7_load_multiple_12,\ + nds_n7_store_multiple_1,nds_n7_store_multiple_2, nds_n7_store_multiple_3,\ + nds_n7_store_multiple_4,nds_n7_store_multiple_5, nds_n7_store_multiple_6,\ + nds_n7_store_multiple_7,nds_n7_store_multiple_8, nds_n7_store_multiple_12" + "nds32_n7_load_to_ii_p" +) + +;; LMW(N, N) +;; -> ALU, MOVD44_E, MUL, MAC_RaRb, DIV, BR, AADR_IN_MOP(1), ST_bi, ST_!bi_RI, SMW(N, 1) +(define_bypass 2 + "nds_n7_load_multiple_1,nds_n7_load_multiple_2, nds_n7_load_multiple_3,\ + nds_n7_load_multiple_4,nds_n7_load_multiple_5, nds_n7_load_multiple_6,\ + nds_n7_load_multiple_7,nds_n7_load_multiple_8, nds_n7_load_multiple_12" + "nds_n7_alu,\ + nds_n7_mul_fast, nds_n7_mul_slow,\ + nds_n7_mac_fast, nds_n7_mac_slow,\ + nds_n7_div,\ + nds_n7_branch,\ + nds_n7_load, nds_n7_store,\ + nds_n7_load_multiple_1,nds_n7_load_multiple_2, nds_n7_load_multiple_3,\ + nds_n7_load_multiple_4,nds_n7_load_multiple_5, nds_n7_load_multiple_6,\ + nds_n7_load_multiple_7,nds_n7_load_multiple_8, nds_n7_load_multiple_12,\ + nds_n7_store_multiple_1,nds_n7_store_multiple_2, nds_n7_store_multiple_3,\ + nds_n7_store_multiple_4,nds_n7_store_multiple_5, nds_n7_store_multiple_6,\ + nds_n7_store_multiple_7,nds_n7_store_multiple_8, nds_n7_store_multiple_12" + "nds32_n7_last_load_to_ii_p" +) diff --git a/gcc/config/nds32/nds32-n8.md b/gcc/config/nds32/nds32-n8.md new file mode 100644 index 0000000..c3db9cd --- /dev/null +++ b/gcc/config/nds32/nds32-n8.md @@ -0,0 +1,389 @@ +;; 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 N8 pipeline settings. +;; ------------------------------------------------------------------------ + +(define_automaton "nds32_n8_machine") + +;; ------------------------------------------------------------------------ +;; Pipeline Stages +;; ------------------------------------------------------------------------ +;; IF - Instruction Fetch +;; II - Instruction Issue / Address Generation +;; EX - Instruction Execution +;; EXD - Psuedo Stage / Load Data Completion + +(define_cpu_unit "n8_ii" "nds32_n8_machine") +(define_cpu_unit "n8_ex" "nds32_n8_machine") + +(define_insn_reservation "nds_n8_unknown" 1 + (and (eq_attr "type" "unknown") + (eq_attr "pipeline_model" "n8")) + "n8_ii, n8_ex") + +(define_insn_reservation "nds_n8_misc" 1 + (and (eq_attr "type" "misc") + (eq_attr "pipeline_model" "n8")) + "n8_ii, n8_ex") + +(define_insn_reservation "nds_n8_alu" 1 + (and (eq_attr "type" "alu") + (eq_attr "pipeline_model" "n8")) + "n8_ii, n8_ex") + +(define_insn_reservation "nds_n8_load" 1 + (and (match_test "nds32::load_single_p (insn)") + (eq_attr "pipeline_model" "n8")) + "n8_ii, n8_ex") + +(define_insn_reservation "nds_n8_store" 1 + (and (match_test "nds32::store_single_p (insn)") + (eq_attr "pipeline_model" "n8")) + "n8_ii, n8_ex") + +(define_insn_reservation "nds_n8_load_multiple_1" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "1")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, n8_ex") + +(define_insn_reservation "nds_n8_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" "n8")) + "n8_ii, n8_ii+n8_ex, n8_ex") + +(define_insn_reservation "nds_n8_load_multiple_3" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "3")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*2, n8_ex") + +(define_insn_reservation "nds_n8_load_multiple_4" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "4")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*3, n8_ex") + +(define_insn_reservation "nds_n8_load_multiple_5" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "5")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*4, n8_ex") + +(define_insn_reservation "nds_n8_load_multiple_6" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "6")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*5, n8_ex") + +(define_insn_reservation "nds_n8_load_multiple_7" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "7")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*6, n8_ex") + +(define_insn_reservation "nds_n8_load_multiple_8" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "8")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*7, n8_ex") + +(define_insn_reservation "nds_n8_load_multiple_12" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "12")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*11, n8_ex") + +(define_insn_reservation "nds_n8_store_multiple_1" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "1")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, n8_ex") + +(define_insn_reservation "nds_n8_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" "n8")) + "n8_ii, n8_ii+n8_ex, n8_ex") + +(define_insn_reservation "nds_n8_store_multiple_3" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "3")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*2, n8_ex") + +(define_insn_reservation "nds_n8_store_multiple_4" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "4")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*3, n8_ex") + +(define_insn_reservation "nds_n8_store_multiple_5" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "5")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*4, n8_ex") + +(define_insn_reservation "nds_n8_store_multiple_6" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "6")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*5, n8_ex") + +(define_insn_reservation "nds_n8_store_multiple_7" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "7")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*6, n8_ex") + +(define_insn_reservation "nds_n8_store_multiple_8" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "8")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*7, n8_ex") + +(define_insn_reservation "nds_n8_store_multiple_12" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "12")) + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*11, n8_ex") + +(define_insn_reservation "nds_n8_mul_fast" 1 + (and (match_test "nds32_mul_config != MUL_TYPE_SLOW") + (and (eq_attr "type" "mul") + (eq_attr "pipeline_model" "n8"))) + "n8_ii, n8_ex") + +(define_insn_reservation "nds_n8_mul_slow" 1 + (and (match_test "nds32_mul_config == MUL_TYPE_SLOW") + (and (eq_attr "type" "mul") + (eq_attr "pipeline_model" "n8"))) + "n8_ii, n8_ex*16") + +(define_insn_reservation "nds_n8_mac_fast" 1 + (and (match_test "nds32_mul_config != MUL_TYPE_SLOW") + (and (eq_attr "type" "mac") + (eq_attr "pipeline_model" "n8"))) + "n8_ii, n8_ii+n8_ex, n8_ex") + +(define_insn_reservation "nds_n8_mac_slow" 1 + (and (match_test "nds32_mul_config == MUL_TYPE_SLOW") + (and (eq_attr "type" "mac") + (eq_attr "pipeline_model" "n8"))) + "n8_ii, (n8_ii+n8_ex)*16, n8_ex") + +(define_insn_reservation "nds_n8_div" 1 + (and (eq_attr "type" "div") + (eq_attr "pipeline_model" "n8")) + "n8_ii, (n8_ii+n8_ex)*36, n8_ex") + +(define_insn_reservation "nds_n8_branch" 1 + (and (eq_attr "type" "branch") + (eq_attr "pipeline_model" "n8")) + "n8_ii, n8_ex") + +;; ------------------------------------------------------------------------ +;; Comment Notations and Bypass Rules +;; ------------------------------------------------------------------------ +;; Producers (LHS) +;; LD_!bi +;; Load data from the memory (without updating the base register) and +;; produce the loaded data. The result is ready at EXD. +;; LD_bi +;; Load data from the memory (with updating the base register) and +;; produce the loaded data. The result is ready at EXD. Because the +;; register port is 2R1W, two micro-operations are required in order +;; to write two registers. The base register is updated by the second +;; micro-operation and the result is ready at EX. +;; 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. If the base register should be +;; updated, an extra micro-operation is inserted to the sequence, and the +;; result is ready at EX. +;; 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, MUL, MAC +;; The result is ready at EX. +;; MOVD44_O +;; A double-word move instruction needs to write registers twice. Because +;; the register port is 2R1W, two micro-operations are required. The even +;; number reigster is updated by the first one, and the odd number register +;; is updated by the second one. Each of the results is ready at EX. +;; The letter 'O' stands for odd. +;; DIV_Rs +;; A division instruction saves the quotient result to Rt and saves the +;; remainder result to Rs. It requires two micro-operations because the +;; register port is 2R1W. 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. +;; MOVD44_E +;; The letter 'E' stands for even, which is accessed by the first micro- +;; operation and a movd44 instruction. The operand is required at EX. +;; MAC_RaRb +;; A MAC instruction is separated into two micro-operations. The first +;; micro-operation does the multiplication, which requires operands Ra +;; and Rb at EX. The second micro-options does the accumulation, which +;; requires the operand Rt at EX. +;; ADDR_IN_MOP(N) +;; Because the reigster port is 2R1W, some load/store instructions are +;; separated into many micro-operations. N denotes the address input is +;; required by the N-th micro-operation. Such operand is required at II. +;; ST_bi +;; A post-increment store instruction requires its data at EX. +;; ST_!bi_RI +;; A store instruction with an immediate offset requires its data at EX. +;; If the offset field is a register (ST_!bi_RR), the instruction will be +;; separated into two micro-operations, and the second one requires the +;; input operand at EX in order to store it to the memory. +;; 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. If the base +;; register should be updated, an extra micro-operation is inserted to the +;; sequence. +;; BR_COND +;; If a branch instruction is conditional, its input data is required at EX. + +;; LD_!bi -> ADDR_IN_MOP(1) +(define_bypass 3 + "nds_n8_load" + "nds_n8_branch,\ + nds_n8_load, nds_n8_store,\ + nds_n8_load_multiple_1,nds_n8_load_multiple_2, nds_n8_load_multiple_3,\ + nds_n8_load_multiple_4,nds_n8_load_multiple_5, nds_n8_load_multiple_6,\ + nds_n8_load_multiple_7,nds_n8_load_multiple_8, nds_n8_load_multiple_12,\ + nds_n8_store_multiple_1,nds_n8_store_multiple_2, nds_n8_store_multiple_3,\ + nds_n8_store_multiple_4,nds_n8_store_multiple_5, nds_n8_store_multiple_6,\ + nds_n8_store_multiple_7,nds_n8_store_multiple_8, nds_n8_store_multiple_12" + "nds32_n8_load_to_ii_p" +) + +;; LMW(N, N) -> ADDR_IN_MOP(1) +(define_bypass 3 + "nds_n8_load_multiple_1,nds_n8_load_multiple_2, nds_n8_load_multiple_3,\ + nds_n8_load_multiple_4,nds_n8_load_multiple_5, nds_n8_load_multiple_6,\ + nds_n8_load_multiple_7,nds_n8_load_multiple_8, nds_n8_load_multiple_12" + "nds_n8_branch,\ + nds_n8_load, nds_n8_store,\ + nds_n8_load_multiple_1,nds_n8_load_multiple_2, nds_n8_load_multiple_3,\ + nds_n8_load_multiple_4,nds_n8_load_multiple_5, nds_n8_load_multiple_6,\ + nds_n8_load_multiple_7,nds_n8_load_multiple_8, nds_n8_load_multiple_12,\ + nds_n8_store_multiple_1,nds_n8_store_multiple_2, nds_n8_store_multiple_3,\ + nds_n8_store_multiple_4,nds_n8_store_multiple_5, nds_n8_store_multiple_6,\ + nds_n8_store_multiple_7,nds_n8_store_multiple_8, nds_n8_store_multiple_12" + "nds32_n8_last_load_to_ii_p" +) + +;; LMW(N, N - 1) -> ADDR_IN_MOP(1) +(define_bypass 2 + "nds_n8_load_multiple_1,nds_n8_load_multiple_2, nds_n8_load_multiple_3,\ + nds_n8_load_multiple_4,nds_n8_load_multiple_5, nds_n8_load_multiple_6,\ + nds_n8_load_multiple_7,nds_n8_load_multiple_8, nds_n8_load_multiple_12" + "nds_n8_branch,\ + nds_n8_load, nds_n8_store,\ + nds_n8_load_multiple_1,nds_n8_load_multiple_2, nds_n8_load_multiple_3,\ + nds_n8_load_multiple_4,nds_n8_load_multiple_5, nds_n8_load_multiple_6,\ + nds_n8_load_multiple_7,nds_n8_load_multiple_8, nds_n8_load_multiple_12,\ + nds_n8_store_multiple_1,nds_n8_store_multiple_2, nds_n8_store_multiple_3,\ + nds_n8_store_multiple_4,nds_n8_store_multiple_5, nds_n8_store_multiple_6,\ + nds_n8_store_multiple_7,nds_n8_store_multiple_8, nds_n8_store_multiple_12" + "nds32_n8_last_load_two_to_ii_p" +) + +;; LD_bi -> ADDR_IN_MOP(1) +(define_bypass 2 + "nds_n8_load" + "nds_n8_branch,\ + nds_n8_load, nds_n8_store,\ + nds_n8_load_multiple_1,nds_n8_load_multiple_2, nds_n8_load_multiple_3,\ + nds_n8_load_multiple_4,nds_n8_load_multiple_5, nds_n8_load_multiple_6,\ + nds_n8_load_multiple_7,nds_n8_load_multiple_8, nds_n8_load_multiple_12,\ + nds_n8_store_multiple_1,nds_n8_store_multiple_2, nds_n8_store_multiple_3,\ + nds_n8_store_multiple_4,nds_n8_store_multiple_5, nds_n8_store_multiple_6,\ + nds_n8_store_multiple_7,nds_n8_store_multiple_8, nds_n8_store_multiple_12" + "nds32_n8_load_bi_to_ii_p" +) + +;; LD_!bi -> ALU, MOVD44_E, MUL, MAC_RaRb, DIV, BR_COND, ST_bi, ST_!bi_RI, SMW(N, 1) +(define_bypass 2 + "nds_n8_load" + "nds_n8_alu, + nds_n8_mul_fast, nds_n8_mul_slow,\ + nds_n8_mac_fast, nds_n8_mac_slow,\ + nds_n8_div,\ + nds_n8_branch,\ + nds_n8_store,\ + nds_n8_store_multiple_1,nds_n8_store_multiple_2, nds_n8_store_multiple_3,\ + nds_n8_store_multiple_4,nds_n8_store_multiple_5, nds_n8_store_multiple_6,\ + nds_n8_store_multiple_7,nds_n8_store_multiple_8, nds_n8_store_multiple_12" + "nds32_n8_load_to_ex_p" +) + +;; ALU, MOVD44_O, MUL, MAC, DIV_Rs, LD_bi, ADDR_OUT -> ADDR_IN_MOP(1) +(define_bypass 2 + "nds_n8_alu, + nds_n8_mul_fast, nds_n8_mul_slow,\ + nds_n8_mac_fast, nds_n8_mac_slow,\ + nds_n8_div,\ + nds_n8_load, nds_n8_store,\ + nds_n8_load_multiple_1,nds_n8_load_multiple_2, nds_n8_load_multiple_3,\ + nds_n8_load_multiple_4,nds_n8_load_multiple_5, nds_n8_load_multiple_6,\ + nds_n8_load_multiple_7,nds_n8_load_multiple_8, nds_n8_load_multiple_12,\ + nds_n8_store_multiple_1,nds_n8_store_multiple_2, nds_n8_store_multiple_3,\ + nds_n8_store_multiple_4,nds_n8_store_multiple_5, nds_n8_store_multiple_6,\ + nds_n8_store_multiple_7,nds_n8_store_multiple_8, nds_n8_store_multiple_12" + "nds_n8_branch,\ + nds_n8_load, nds_n8_store,\ + nds_n8_load_multiple_1,nds_n8_load_multiple_2, nds_n8_load_multiple_3,\ + nds_n8_load_multiple_4,nds_n8_load_multiple_5, nds_n8_load_multiple_6,\ + nds_n8_load_multiple_7,nds_n8_load_multiple_8, nds_n8_load_multiple_12,\ + nds_n8_store_multiple_1,nds_n8_store_multiple_2, nds_n8_store_multiple_3,\ + nds_n8_store_multiple_4,nds_n8_store_multiple_5, nds_n8_store_multiple_6,\ + nds_n8_store_multiple_7,nds_n8_store_multiple_8, nds_n8_store_multiple_12" + "nds32_n8_ex_to_ii_p" +) + +;; LMW(N, N) -> ALU, MOVD44_E, MUL, MAC_RaRb, DIV, BR_COND, ST_bi, ST_!bi_RI, SMW(N, 1) +(define_bypass 2 + "nds_n8_load_multiple_1,nds_n8_load_multiple_2, nds_n8_load_multiple_3,\ + nds_n8_load_multiple_4,nds_n8_load_multiple_5, nds_n8_load_multiple_6,\ + nds_n8_load_multiple_7,nds_n8_load_multiple_8, nds_n8_load_multiple_12" + "nds_n8_alu, + nds_n8_mul_fast, nds_n8_mul_slow,\ + nds_n8_mac_fast, nds_n8_mac_slow,\ + nds_n8_div,\ + nds_n8_branch,\ + nds_n8_store,\ + nds_n8_store_multiple_1,nds_n8_store_multiple_2, nds_n8_store_multiple_3,\ + nds_n8_store_multiple_4,nds_n8_store_multiple_5, nds_n8_store_multiple_6,\ + nds_n8_store_multiple_7,nds_n8_store_multiple_8, nds_n8_store_multiple_12" + "nds32_n8_last_load_to_ex_p" +) diff --git a/gcc/config/nds32/nds32-n9-2r1w.md b/gcc/config/nds32/nds32-n9-2r1w.md new file mode 100644 index 0000000..d0db953 --- /dev/null +++ b/gcc/config/nds32/nds32-n9-2r1w.md @@ -0,0 +1,362 @@ +;; 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 N9 2R1W pipeline settings. +;; ------------------------------------------------------------------------ + +(define_automaton "nds32_n9_2r1w_machine") + +;; ------------------------------------------------------------------------ +;; Pipeline Stages +;; ------------------------------------------------------------------------ +;; IF - Instruction Fetch +;; II - Instruction Issue / Instruction Decode +;; EX - Instruction Execution +;; MM - Memory Execution +;; WB - Instruction Retire / Result Write-Back + +(define_cpu_unit "n9_2r1w_ii" "nds32_n9_2r1w_machine") +(define_cpu_unit "n9_2r1w_ex" "nds32_n9_2r1w_machine") +(define_cpu_unit "n9_2r1w_mm" "nds32_n9_2r1w_machine") +(define_cpu_unit "n9_2r1w_wb" "nds32_n9_2r1w_machine") + +(define_insn_reservation "nds_n9_2r1w_unknown" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "type" "unknown") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_misc" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "type" "misc") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_mmu" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "type" "mmu") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_alu" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "type" "alu") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_alu_shift" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "type" "alu_shift") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_pbsad" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "type" "pbsad") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ex*3, n9_2r1w_mm, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_pbsada" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "type" "pbsada") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ex*3, n9_2r1w_mm, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_load" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (match_test "nds32::load_single_p (insn)") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_store" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (match_test "nds32::store_single_p (insn)") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_load_multiple_1" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "1")))) + "n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_load_multiple_2" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (ior (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "2")) + (match_test "nds32::load_double_p (insn)")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_load_multiple_3" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "3")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_load_multiple_4" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "4")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_load_multiple_5" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "5")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*2, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_load_multiple_6" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "6")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*3, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_load_multiple_7" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "7")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*4, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_load_multiple_8" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "8")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*5, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_load_multiple_12" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "12")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*9, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_store_multiple_1" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "1")))) + "n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_store_multiple_2" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (ior (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "2")) + (match_test "nds32::store_double_p (insn)")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_store_multiple_3" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "3")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_store_multiple_4" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "4")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_store_multiple_5" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "5")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*2, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_store_multiple_6" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "6")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*3, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_store_multiple_7" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "7")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*4, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_store_multiple_8" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "8")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*5, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_store_multiple_12" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "12")))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm, (n9_2r1w_ii+n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb)*9, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_mul_fast" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W && nds32_mul_config != MUL_TYPE_SLOW") + (and (eq_attr "type" "mul") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_mul_slow" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W && nds32_mul_config == MUL_TYPE_SLOW") + (and (eq_attr "type" "mul") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ex*17, n9_2r1w_mm, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_mac_fast" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W && nds32_mul_config != MUL_TYPE_SLOW") + (and (eq_attr "type" "mac") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ii+n9_2r1w_ex, n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_mac_slow" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W && nds32_mul_config == MUL_TYPE_SLOW") + (and (eq_attr "type" "mac") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, (n9_2r1w_ii+n9_2r1w_ex)*17, n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_ex+n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_div" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "type" "div") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, (n9_2r1w_ii+n9_2r1w_ex)*34, n9_2r1w_ex+n9_2r1w_mm, n9_2r1w_mm+n9_2r1w_wb, n9_2r1w_wb") + +(define_insn_reservation "nds_n9_2r1w_branch" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_2R1W") + (and (eq_attr "type" "branch") + (eq_attr "pipeline_model" "n9"))) + "n9_2r1w_ii, n9_2r1w_ex, n9_2r1w_mm, n9_2r1w_wb") + +;; ------------------------------------------------------------------------ +;; Comment Notations and Bypass Rules +;; ------------------------------------------------------------------------ +;; Producers (LHS) +;; LD_!bi +;; Load data from the memory (without updating the base register) and +;; produce the loaded data. The result is ready at MM. Because the register +;; port is 2R1W, two micro-operations are required if the base register +;; should be updated. In this case, the base register is updated by the +;; second micro-operation, and the updated result is ready at EX. +;; 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 MM. If the base register should be +;; updated, an extra micro-operation is apppended to the end of the +;; sequence, and the result is ready at EX. +;; MUL, MAC +;; Compute data in the multiply-adder and produce the data. The result +;; is ready at MM. +;; DIV +;; Compute data in the divider and produce the data. The result is ready +;; at MM. +;; +;; Consumers (RHS) +;; ALU, PBSAD, PBSADA_RaRb, MUL, MAC, DIV, MMU +;; Require operands at EX. +;; ALU_SHIFT_Rb +;; An ALU-SHIFT instruction consists of a shift micro-operation followed +;; by an arithmetic micro-operation. The operand Rb is used by the first +;; micro-operation, and there are some latencies if data dependency occurs. +;; MOVD44_E +;; A double-word move instruction needs two micro-operations because the +;; reigster ports is 2R1W. The first micro-operation writes an even number +;; register, and the second micro-operation writes an odd number register. +;; Each input operand is required at EX for each micro-operation. MOVD44_E +;; stands for the first micro-operation. +;; MAC_RaRb, M2R +;; MAC instructions do multiplication at EX and do accumulation at MM, but +;; MAC instructions which operate on general purpose registers always +;; require operands at EX because MM stage cannot be forwarded in 2R1W mode. +;; ADDR_IN +;; If an instruction requires an address as its input operand, the address +;; is required at EX. +;; ST_bi +;; A post-increment store instruction requires its data at EX because MM +;; cannot be forwarded in 2R1W mode. +;; ST_!bi_RI +;; A store instruction with an immediate offset requires its data at EX +;; because MM cannot be forwarded in 2R1W mode. If the offset field is a +;; register (ST_!bi_RR), the instruction will be separated into two micro- +;; operations, and the second one requires the input operand at EX in order +;; to store it to the memory. +;; SMW(N, M) +;; There are N micro-operations within an instruction that stores multiple +;; words. Each M-th micro-operation requires its data at MM. +;; BR +;; If a branch instruction is conditional, its input data is required at EX. + +;; LD_!bi, MUL, MAC +;; -> ALU, ALU_SHIFT_Rb, PBSAD, PBSADA_RaRb, MOVD44_E, MUL, MAC_RaRb, M2R, DIV, ADDR_IN_!bi, ADDR_IN_bi_Ra, ST_bi, ST_!bi_RI, BR, MMU +(define_bypass 2 + "nds_n9_2r1w_load,\ + nds_n9_2r1w_mul_fast, nds_n9_2r1w_mul_slow,\ + nds_n9_2r1w_mac_fast, nds_n9_2r1w_mac_slow" + "nds_n9_2r1w_alu, nds_n9_2r1w_alu_shift,\ + nds_n9_2r1w_pbsad, nds_n9_2r1w_pbsada,\ + nds_n9_2r1w_mul_fast, nds_n9_2r1w_mul_slow,\ + nds_n9_2r1w_mac_fast, nds_n9_2r1w_mac_slow,\ + nds_n9_2r1w_branch,\ + nds_n9_2r1w_div,\ + nds_n9_2r1w_load,nds_n9_2r1w_store,\ + nds_n9_2r1w_load_multiple_1,nds_n9_2r1w_load_multiple_2, nds_n9_2r1w_load_multiple_3,\ + nds_n9_2r1w_load_multiple_4,nds_n9_2r1w_load_multiple_5, nds_n9_2r1w_load_multiple_6,\ + nds_n9_2r1w_load_multiple_7,nds_n9_2r1w_load_multiple_8, nds_n9_2r1w_load_multiple_12,\ + nds_n9_2r1w_store_multiple_1,nds_n9_2r1w_store_multiple_2, nds_n9_2r1w_store_multiple_3,\ + nds_n9_2r1w_store_multiple_4,nds_n9_2r1w_store_multiple_5, nds_n9_2r1w_store_multiple_6,\ + nds_n9_2r1w_store_multiple_7,nds_n9_2r1w_store_multiple_8, nds_n9_2r1w_store_multiple_12,\ + nds_n9_2r1w_mmu" + "nds32_n9_2r1w_mm_to_ex_p" +) + +;; LMW(N, N) +;; -> ALU, ALU_SHIFT_Rb, PBSAD, PBSADA_RaRb, MOVD44_E, MUL, MAC_RaRb, M2R, DIV, ADDR_IN_!bi, ADDR_IN_bi_Ra, ST_bi, ST_!bi_RI, BR, MMU +(define_bypass 2 + "nds_n9_2r1w_load_multiple_1,nds_n9_2r1w_load_multiple_2, nds_n9_2r1w_load_multiple_3,\ + nds_n9_2r1w_load_multiple_4,nds_n9_2r1w_load_multiple_5, nds_n9_2r1w_load_multiple_6,\ + nds_n9_2r1w_load_multiple_7,nds_n9_2r1w_load_multiple_8, nds_n9_2r1w_load_multiple_12" + "nds_n9_2r1w_alu, nds_n9_2r1w_alu_shift,\ + nds_n9_2r1w_pbsad, nds_n9_2r1w_pbsada,\ + nds_n9_2r1w_mul_fast, nds_n9_2r1w_mul_slow,\ + nds_n9_2r1w_mac_fast, nds_n9_2r1w_mac_slow,\ + nds_n9_2r1w_branch,\ + nds_n9_2r1w_div,\ + nds_n9_2r1w_load,nds_n9_2r1w_store,\ + nds_n9_2r1w_load_multiple_1,nds_n9_2r1w_load_multiple_2, nds_n9_2r1w_load_multiple_3,\ + nds_n9_2r1w_load_multiple_4,nds_n9_2r1w_load_multiple_5, nds_n9_2r1w_load_multiple_6,\ + nds_n9_2r1w_load_multiple_7,nds_n9_2r1w_load_multiple_8, nds_n9_2r1w_load_multiple_12,\ + nds_n9_2r1w_store_multiple_1,nds_n9_2r1w_store_multiple_2, nds_n9_2r1w_store_multiple_3,\ + nds_n9_2r1w_store_multiple_4,nds_n9_2r1w_store_multiple_5, nds_n9_2r1w_store_multiple_6,\ + nds_n9_2r1w_store_multiple_7,nds_n9_2r1w_store_multiple_8, nds_n9_2r1w_store_multiple_12,\ + nds_n9_2r1w_mmu" + "nds32_n9_last_load_to_ex_p" +) diff --git a/gcc/config/nds32/nds32-n9-3r2w.md b/gcc/config/nds32/nds32-n9-3r2w.md new file mode 100644 index 0000000..7849c72 --- /dev/null +++ b/gcc/config/nds32/nds32-n9-3r2w.md @@ -0,0 +1,357 @@ +;; 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 N9 3R2W pipeline settings. +;; ------------------------------------------------------------------------ + +(define_automaton "nds32_n9_3r2w_machine") + +;; ------------------------------------------------------------------------ +;; Pipeline Stages +;; ------------------------------------------------------------------------ +;; IF - Instruction Fetch +;; II - Instruction Issue / Instruction Decode +;; EX - Instruction Execution +;; MM - Memory Execution +;; WB - Instruction Retire / Result Write-Back + +(define_cpu_unit "n9_3r2w_ii" "nds32_n9_3r2w_machine") +(define_cpu_unit "n9_3r2w_ex" "nds32_n9_3r2w_machine") +(define_cpu_unit "n9_3r2w_mm" "nds32_n9_3r2w_machine") +(define_cpu_unit "n9_3r2w_wb" "nds32_n9_3r2w_machine") + +(define_insn_reservation "nds_n9_3r2w_unknown" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "type" "unknown") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_misc" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "type" "misc") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_mmu" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "type" "mmu") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_alu" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "type" "alu") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_alu_shift" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "type" "alu_shift") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_pbsad" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "type" "pbsad") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex*3, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_pbsada" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "type" "pbsada") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex*3, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_load" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (match_test "nds32::load_single_p (insn)") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_store" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (match_test "nds32::store_single_p (insn)") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_load_multiple_1" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "1")))) + "n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_load_multiple_2" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (ior (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "2")) + (match_test "nds32::load_double_p (insn)")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_load_multiple_3" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "3")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_load_multiple_4" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "4")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_load_multiple_5" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "5")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*2, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_load_multiple_6" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "6")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*3, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_load_multiple_7" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "7")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*4, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_load_multiple_8" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "8")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*5, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_load_multiple_12" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "12")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*9, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_store_multiple_1" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "1")))) + "n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_store_multiple_2" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (ior (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "2")) + (match_test "nds32::store_double_p (insn)")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_store_multiple_3" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "3")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_store_multiple_4" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "4")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_store_multiple_5" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "5")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*2, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_store_multiple_6" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "6")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*3, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_store_multiple_7" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "7")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*4, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_store_multiple_8" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "8")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*5, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_store_multiple_12" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "pipeline_model" "n9") + (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "12")))) + "n9_3r2w_ii, n9_3r2w_ii+n9_3r2w_ex, n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm, (n9_3r2w_ii+n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb)*9, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_mm+n9_3r2w_wb, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_mul_fast1" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W && nds32_mul_config == MUL_TYPE_FAST_1") + (and (eq_attr "type" "mul") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_mul_fast2" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W && nds32_mul_config == MUL_TYPE_FAST_2") + (and (eq_attr "type" "mul") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex*2, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_mul_slow" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W && nds32_mul_config == MUL_TYPE_SLOW") + (and (eq_attr "type" "mul") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex*17, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_mac_fast1" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W && nds32_mul_config == MUL_TYPE_FAST_1") + (and (eq_attr "type" "mac") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_mac_fast2" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W && nds32_mul_config == MUL_TYPE_FAST_2") + (and (eq_attr "type" "mac") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex*2, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_mac_slow" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W && nds32_mul_config == MUL_TYPE_SLOW") + (and (eq_attr "type" "mac") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex*17, n9_3r2w_ex+n9_3r2w_mm, n9_3r2w_ex+n9_3r2w_mm+n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_div" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "type" "div") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex*34, n9_3r2w_mm, n9_3r2w_wb") + +(define_insn_reservation "nds_n9_3r2w_branch" 1 + (and (match_test "nds32_register_ports_config == REG_PORT_3R2W") + (and (eq_attr "type" "branch") + (eq_attr "pipeline_model" "n9"))) + "n9_3r2w_ii, n9_3r2w_ex, n9_3r2w_mm, n9_3r2w_wb") + +;; ------------------------------------------------------------------------ +;; Comment Notations and Bypass Rules +;; ------------------------------------------------------------------------ +;; Producers (LHS) +;; LD +;; Load data from the memory and produce the loaded data. The result is +;; ready at MM. +;; 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 MM. +;; MUL, MAC +;; Compute data in the multiply-adder and produce the data. The result +;; is ready at MM. +;; DIV +;; Compute data in the divider and produce the data. The result is ready +;; at MM. +;; +;; Consumers (RHS) +;; ALU, MOVD44, PBSAD, PBSADA_RaRb, MUL, MAC, DIV, MMU +;; Require operands at EX. +;; ALU_SHIFT_Rb +;; An ALU-SHIFT instruction consists of a shift micro-operation followed +;; by an arithmetic micro-operation. The operand Rb is used by the first +;; micro-operation, and there are some latencies if data dependency occurs. +;; MAC_RaRb +;; A MAC instruction does multiplication at EX and does accumulation at MM, +;; so the operand Rt is required at MM, and operands Ra and Rb are required +;; at EX. +;; ADDR_IN +;; If an instruction requires an address as its input operand, the address +;; is required at EX. +;; ST +;; A store instruction requires its data at MM. +;; SMW(N, M) +;; There are N micro-operations within an instruction that stores multiple +;; words. Each M-th micro-operation requires its data at MM. +;; BR +;; If a branch instruction is conditional, its input data is required at EX. + +;; LD, MUL, MAC, DIV +;; -> ALU, ALU_SHIFT_Rb, PBSAD, PBSADA_RaRb, MOVD44, MUL, MAC_RaRb, DIV, ADDR_IN, BR, MMU +(define_bypass 2 + "nds_n9_3r2w_load,\ + nds_n9_3r2w_mul_fast1, nds_n9_3r2w_mul_fast2, nds_n9_3r2w_mul_slow,\ + nds_n9_3r2w_mac_fast1, nds_n9_3r2w_mac_fast2, nds_n9_3r2w_mac_slow,\ + nds_n9_3r2w_div" + "nds_n9_3r2w_alu, nds_n9_3r2w_alu_shift,\ + nds_n9_3r2w_pbsad, nds_n9_3r2w_pbsada,\ + nds_n9_3r2w_mul_fast1, nds_n9_3r2w_mul_fast2, nds_n9_3r2w_mul_slow,\ + nds_n9_3r2w_mac_fast1, nds_n9_3r2w_mac_fast2, nds_n9_3r2w_mac_slow,\ + nds_n9_3r2w_branch,\ + nds_n9_3r2w_div,\ + nds_n9_3r2w_load,nds_n9_3r2w_store,\ + nds_n9_3r2w_load_multiple_1,nds_n9_3r2w_load_multiple_2, nds_n9_3r2w_load_multiple_3,\ + nds_n9_3r2w_load_multiple_4,nds_n9_3r2w_load_multiple_5, nds_n9_3r2w_load_multiple_6,\ + nds_n9_3r2w_load_multiple_7,nds_n9_3r2w_load_multiple_8, nds_n9_3r2w_load_multiple_12,\ + nds_n9_3r2w_store_multiple_1,nds_n9_3r2w_store_multiple_2, nds_n9_3r2w_store_multiple_3,\ + nds_n9_3r2w_store_multiple_4,nds_n9_3r2w_store_multiple_5, nds_n9_3r2w_store_multiple_6,\ + nds_n9_3r2w_store_multiple_7,nds_n9_3r2w_store_multiple_8, nds_n9_3r2w_store_multiple_12,\ + nds_n9_3r2w_mmu" + "nds32_n9_3r2w_mm_to_ex_p" +) + +;; LMW(N, N) +;; -> ALU, ALU_SHIFT_Rb, PBSAD, PBSADA_RaRb, MOVD44, MUL, MAC_RaRb, DIV, ADDR_IN, BR, MMU +(define_bypass 2 + "nds_n9_3r2w_load_multiple_1,nds_n9_3r2w_load_multiple_2, nds_n9_3r2w_load_multiple_3,\ + nds_n9_3r2w_load_multiple_4,nds_n9_3r2w_load_multiple_5, nds_n9_3r2w_load_multiple_6,\ + nds_n9_3r2w_load_multiple_7,nds_n9_3r2w_load_multiple_8, nds_n9_3r2w_load_multiple_12" + "nds_n9_3r2w_alu, nds_n9_3r2w_alu_shift,\ + nds_n9_3r2w_pbsad, nds_n9_3r2w_pbsada,\ + nds_n9_3r2w_mul_fast1, nds_n9_3r2w_mul_fast2, nds_n9_3r2w_mul_slow,\ + nds_n9_3r2w_mac_fast1, nds_n9_3r2w_mac_fast2, nds_n9_3r2w_mac_slow,\ + nds_n9_3r2w_branch,\ + nds_n9_3r2w_div,\ + nds_n9_3r2w_load,nds_n9_3r2w_store,\ + nds_n9_3r2w_load_multiple_1,nds_n9_3r2w_load_multiple_2, nds_n9_3r2w_load_multiple_3,\ + nds_n9_3r2w_load_multiple_4,nds_n9_3r2w_load_multiple_5, nds_n9_3r2w_load_multiple_6,\ + nds_n9_3r2w_load_multiple_7,nds_n9_3r2w_load_multiple_8, nds_n9_3r2w_load_multiple_12,\ + nds_n9_3r2w_store_multiple_1,nds_n9_3r2w_store_multiple_2, nds_n9_3r2w_store_multiple_3,\ + nds_n9_3r2w_store_multiple_4,nds_n9_3r2w_store_multiple_5, nds_n9_3r2w_store_multiple_6,\ + nds_n9_3r2w_store_multiple_7,nds_n9_3r2w_store_multiple_8, nds_n9_3r2w_store_multiple_12,\ + nds_n9_3r2w_mmu" + "nds32_n9_last_load_to_ex_p" +) diff --git a/gcc/config/nds32/nds32-opts.h b/gcc/config/nds32/nds32-opts.h index 25c4081..e4017bb 100644 --- a/gcc/config/nds32/nds32-opts.h +++ b/gcc/config/nds32/nds32-opts.h @@ -22,14 +22,42 @@ #define NDS32_OPTS_H #define NDS32_DEFAULT_CACHE_BLOCK_SIZE 16 -#define NDS32_DEFAULT_ISR_VECTOR_SIZE (TARGET_ISA_V3 ? 4 : 16) +#define NDS32_DEFAULT_ISR_VECTOR_SIZE TARGET_DEFAULT_ISR_VECTOR_SIZE /* The various ANDES ISA. */ enum nds32_arch_type { ARCH_V2, + ARCH_V2J, ARCH_V3, - ARCH_V3M + ARCH_V3J, + ARCH_V3M, + ARCH_V3M_PLUS, + ARCH_V3F, + ARCH_V3S +}; + +/* The various ANDES CPU. */ +enum nds32_cpu_type +{ + CPU_N6, + CPU_N7, + CPU_N8, + CPU_E8, + CPU_N9, + CPU_N10, + CPU_GRAYWOLF, + CPU_N12, + CPU_N13, + CPU_PANTHER, + CPU_SIMPLE +}; + +/* The code model defines the address generation strategy. */ +enum nds32_memory_model_type +{ + MEMORY_MODEL_SLOW, + MEMORY_MODEL_FAST }; /* The code model defines the address generation strategy. */ @@ -40,4 +68,56 @@ enum nds32_cmodel_type CMODEL_LARGE }; +/* The code model defines the address generation strategy. */ +enum nds32_ict_model_type +{ + ICT_MODEL_SMALL, + ICT_MODEL_LARGE +}; + + +/* Multiply instruction configuration. */ +enum nds32_mul_type +{ + MUL_TYPE_FAST_1, + MUL_TYPE_FAST_2, + MUL_TYPE_SLOW +}; + +/* Register ports configuration. */ +enum nds32_register_ports +{ + REG_PORT_3R2W, + REG_PORT_2R1W +}; + +/* Which ABI to use. */ +enum abi_type +{ + NDS32_ABI_V2, + NDS32_ABI_V2_FP_PLUS +}; + +/* The various FPU number of registers. */ +enum float_reg_number +{ + NDS32_CONFIG_FPU_0, + NDS32_CONFIG_FPU_1, + NDS32_CONFIG_FPU_2, + NDS32_CONFIG_FPU_3, + NDS32_CONFIG_FPU_4, + NDS32_CONFIG_FPU_5, + NDS32_CONFIG_FPU_6, + NDS32_CONFIG_FPU_7 +}; + +/* Do lmwsmw opt model. */ +enum lmwsmw_cost_type +{ + LMWSMW_OPT_SIZE, + LMWSMW_OPT_SPEED, + LMWSMW_OPT_ALL, + LMWSMW_OPT_AUTO +}; + #endif diff --git a/gcc/config/nds32/nds32-panther.md b/gcc/config/nds32/nds32-panther.md new file mode 100644 index 0000000..d45de1c --- /dev/null +++ b/gcc/config/nds32/nds32-panther.md @@ -0,0 +1,446 @@ +;; 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 Panther pipeline settings. +;; ------------------------------------------------------------------------ + +(define_automaton "nds32_pn_machine") + +(define_cpu_unit "pn_i3_0" "nds32_pn_machine") +(define_cpu_unit "pn_i3_1" "nds32_pn_machine") +(define_cpu_unit "pn_e1_p0" "nds32_pn_machine") +(define_cpu_unit "pn_e2_p0" "nds32_pn_machine") +(define_cpu_unit "pn_e3_p0" "nds32_pn_machine") +(define_cpu_unit "pn_e4_p0" "nds32_pn_machine") +(define_cpu_unit "pn_wb_p0" "nds32_pn_machine") +(define_cpu_unit "pn_e1_p1" "nds32_pn_machine") +(define_cpu_unit "pn_e2_p1" "nds32_pn_machine") +(define_cpu_unit "pn_e3_p1" "nds32_pn_machine") +(define_cpu_unit "pn_e4_p1" "nds32_pn_machine") +(define_cpu_unit "pn_wb_p1" "nds32_pn_machine") +(define_cpu_unit "pn_e1_p2" "nds32_pn_machine") +(define_cpu_unit "pn_e2_p2" "nds32_pn_machine") +(define_cpu_unit "pn_e3_p2" "nds32_pn_machine") +(define_cpu_unit "pn_e4_p2" "nds32_pn_machine") +(define_cpu_unit "pn_wb_p2" "nds32_pn_machine") + +(define_reservation "pn_i3" "pn_i3_0 | pn_i3_1") +(define_reservation "pn_e1" "pn_e1_p0 | pn_e1_p1") +(define_reservation "pn_e2" "pn_e2_p0 | pn_e2_p1") +(define_reservation "pn_e3" "pn_e3_p0 | pn_e3_p1") +(define_reservation "pn_e4" "pn_e4_p0 | pn_e4_p1") +(define_reservation "pn_wb" "pn_wb_p0 | pn_wb_p1") + +(define_insn_reservation "nds_pn_unknown" 1 + (and (eq_attr "type" "unknown") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1, pn_e2, pn_e3, pn_e4, pn_wb") + +(define_insn_reservation "nds_pn_misc" 1 + (and (eq_attr "type" "misc") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1, pn_e2, pn_e3, pn_e4, pn_wb") + +(define_insn_reservation "nds_pn_mmu" 1 + (and (eq_attr "type" "mmu") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1, pn_e2, pn_e3, pn_e4, pn_wb") + +(define_insn_reservation "nds_pn_movd44" 1 + (and (and (and (eq_attr "type" "alu") + (eq_attr "subtype" "simple")) + (match_test "nds32::movd44_insn_p (insn)")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p1, pn_e2_p1, pn_e3_p1, pn_e4_p1, pn_wb_p1") + +(define_insn_reservation "nds_pn_alu" 1 + (and (and (and (eq_attr "type" "alu") + (eq_attr "subtype" "simple")) + (match_test "!nds32::movd44_insn_p (insn)")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1, pn_e2, pn_e3, pn_e4, pn_wb") + +(define_insn_reservation "nds_pn_shift" 1 + (and (and (eq_attr "type" "alu") + (eq_attr "subtype" "shift")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1, pn_e2, pn_e3, pn_e4, pn_wb") + +(define_insn_reservation "nds_pn_alu_shift" 1 + (and (eq_attr "type" "alu_shift") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1, pn_e2, pn_e3, pn_e4, pn_wb") + +(define_insn_reservation "nds_pn_pbsad" 1 + (and (eq_attr "type" "pbsad") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1, pn_e2, pn_e3*2, pn_e4, pn_wb") + +(define_insn_reservation "nds_pn_pbsada" 1 + (and (eq_attr "type" "pbsada") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1, pn_e2, pn_e3*3, pn_e4, pn_wb") + +(define_insn_reservation "nds_pn_load_full_word" 1 + (and (match_test "nds32::load_full_word_p (insn)") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_load_partial_word" 1 + (and (match_test "nds32::load_partial_word_p (insn)") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_store" 1 + (and (match_test "nds32::store_single_p (insn)") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_load_multiple_1" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "1")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_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" "panther")) + "pn_i3, pn_e1_p2*2, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_load_multiple_3" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "3")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*3, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_load_multiple_4" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "4")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*4, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_load_multiple_5" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "5")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*5, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_load_multiple_6" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "5")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*6, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_load_multiple_7" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "7")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*7, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_load_multiple_8" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "8")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*8, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_load_multiple_12" 1 + (and (and (eq_attr "type" "load_multiple") + (eq_attr "combo" "12")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*12, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_store_multiple_1" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "1")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_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" "panther")) + "pn_i3, pn_e1_p2*2, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_store_multiple_3" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "3")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*3, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_store_multiple_4" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "4")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*4, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_store_multiple_5" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "5")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*5, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_store_multiple_6" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "5")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*6, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_store_multiple_7" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "7")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*7, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_store_multiple_8" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "8")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*8, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_store_multiple_12" 1 + (and (and (eq_attr "type" "store_multiple") + (eq_attr "combo" "12")) + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p2*12, pn_e2_p2, pn_e3_p2, pn_e4_p2, pn_wb_p2") + +(define_insn_reservation "nds_pn_mul" 1 + (and (eq_attr "type" "mul") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p1, pn_e2_p1, pn_e3_p1, pn_e4_p1, pn_wb_p1") + +(define_insn_reservation "nds_pn_mac" 1 + (and (eq_attr "type" "mac") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p1, pn_e2_p1, pn_e3_p1, pn_e4_p1, pn_wb_p1") + +;; The cycles consumed in E4 stage is 32 - CLZ(abs(Ra)) + 2, +;; so the worst case is 34. +(define_insn_reservation "nds_pn_div" 1 + (and (eq_attr "type" "div") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p1, pn_e2_p1, pn_e3_p1, pn_e4_p1*34, pn_wb_p1") + +(define_insn_reservation "nds_pn_branch" 1 + (and (eq_attr "type" "branch") + (eq_attr "pipeline_model" "panther")) + "pn_i3, pn_e1_p0, pn_e2_p0, pn_e3_p0, pn_e4_p0, pn_wb_p0") + +;; SHIFT -> ADDR_IN +(define_bypass 2 + "nds_pn_shift" + "nds_pn_load_full_word, nds_pn_load_partial_word, nds_pn_store,\ + nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds32_pn_e2_to_e1_p" +) + +;; ALU, MOVD44 -> ADDR_IN +(define_bypass 3 + "nds_pn_alu, nds_pn_movd44" + "nds_pn_load_full_word, nds_pn_load_partial_word, nds_pn_store,\ + nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds32_pn_e3_to_e1_p" +) + +;; ALU, MOVD44 -> SHIFT, MUL, MAC_RaRb +(define_bypass 2 + "nds_pn_alu, nds_pn_movd44" + "nds_pn_shift, nds_pn_mul, nds_pn_mac" + "nds32_pn_e3_to_e2_p" +) + +;; MUL, MAC, DIV, LW, ADDR_OUT -> ADDR_IN +(define_bypass 4 + "nds_pn_mul, nds_pn_mac, nds_pn_div,\ + nds_pn_load_full_word, nds_pn_load_partial_word, nds_pn_store,\ + nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds_pn_load_full_word, nds_pn_load_partial_word, nds_pn_store,\ + nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds32_pn_e4_to_e1_p" +) + +;; MUL, MAC, DIV, LW, ADDR_OUT -> SHIFT, MUL, MAC_RaRb +(define_bypass 3 + "nds_pn_mul, nds_pn_mac, nds_pn_div,\ + nds_pn_load_full_word, nds_pn_load_partial_word, nds_pn_store,\ + nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds_pn_shift, nds_pn_mul, nds_pn_mac" + "nds32_pn_e4_to_e2_p" +) + +;; MUL, MAC, DIV, LW, ADDR_OUT -> ALU, MOVD44, BR_COND, ST, SMW(N, 1) +(define_bypass 2 + "nds_pn_mul, nds_pn_mac, nds_pn_div,\ + nds_pn_load_full_word, nds_pn_load_partial_word, nds_pn_store,\ + nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds_pn_alu, nds_pn_movd44, nds_pn_branch,\ + nds_pn_store,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds32_pn_e4_to_e3_p" +) + +;; LH, LB -> ADDR_IN +(define_bypass 5 + "nds_pn_load_partial_word" + "nds_pn_load_full_word, nds_pn_load_partial_word, nds_pn_store,\ + nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds32_pn_wb_to_e1_p" +) + +;; LH, LB -> SHIFT, MUL, MAC_RaRb +(define_bypass 4 + "nds_pn_load_partial_word" + "nds_pn_shift, nds_pn_mul, nds_pn_mac" + "nds32_pn_wb_to_e2_p" +) + +;; LH, LB -> ALU, MOVD44, BR_COND, ST, SMW(N, 1) +(define_bypass 3 + "nds_pn_load_partial_word" + "nds_pn_alu, nds_pn_movd44, nds_pn_branch,\ + nds_pn_store,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds32_pn_wb_to_e3_p" +) + +;; LH, LB -> DIV +(define_bypass 2 + "nds_pn_load_partial_word" + "nds_pn_div" + "nds32_pn_wb_to_e4_p" +) + +;; LMW(N, N) -> ADDR_IN +(define_bypass 4 + "nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12" + "nds_pn_load_full_word, nds_pn_load_partial_word, nds_pn_store,\ + nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds32_pn_last_load_to_e1_p" +) + +;; LMW(N, N) -> SHIFT, MUL, MAC_RaRb +(define_bypass 3 + "nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12" + "nds_pn_shift, nds_pn_mul, nds_pn_mac" + "nds32_pn_last_load_to_e2_p" +) + +;; LMW(N, N - 1) -> ADDR_IN +(define_bypass 3 + "nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12" + "nds_pn_load_full_word, nds_pn_load_partial_word, nds_pn_store,\ + nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds32_pn_last_two_load_to_e1_p" +) + +;; LMW(N, N - 2) -> ADDR_IN +(define_bypass 2 + "nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12" + "nds_pn_load_full_word, nds_pn_load_partial_word, nds_pn_store,\ + nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds32_pn_last_three_load_to_e1_p" +) + +;; LMW(N, N - 1) -> SHIFT, MUL, MAC_RaRb +(define_bypass 2 + "nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12" + "nds_pn_shift, nds_pn_mul, nds_pn_mac" + "nds32_pn_last_two_load_to_e2_p" +) + +;; LMW(N, N) -> ALU, MOVD44, BR_COND +(define_bypass 2 + "nds_pn_load_multiple_1, nds_pn_load_multiple_2, nds_pn_load_multiple_3,\ + nds_pn_load_multiple_4, nds_pn_load_multiple_5, nds_pn_load_multiple_6,\ + nds_pn_load_multiple_7, nds_pn_load_multiple_8, nds_pn_load_multiple_12" + "nds_pn_alu, nds_pn_movd44, nds_pn_branch,\ + nds_pn_store,\ + nds_pn_store_multiple_1, nds_pn_store_multiple_2, nds_pn_store_multiple_3,\ + nds_pn_store_multiple_4, nds_pn_store_multiple_5, nds_pn_store_multiple_6,\ + nds_pn_store_multiple_7, nds_pn_store_multiple_8, nds_pn_store_multiple_12" + "nds32_pn_last_load_to_e3_p" +) diff --git a/gcc/config/nds32/nds32-peephole2.md b/gcc/config/nds32/nds32-peephole2.md index 07e3a2b..bb47385 100644 --- a/gcc/config/nds32/nds32-peephole2.md +++ b/gcc/config/nds32/nds32-peephole2.md @@ -19,6 +19,197 @@ ;; . -;; Use define_peephole2 to handle possible target-specific optimization. +;; Use define_split, define_peephole, and define_peephole2 to +;; handle possible target-specific optimization in this file. ;; ------------------------------------------------------------------------ +;; Try to utilize 16-bit instruction by swap operand if possible. +;; ------------------------------------------------------------------------ + +;; Try to make add as add45. +(define_peephole2 + [(set (match_operand:QIHISI 0 "register_operand" "") + (plus:QIHISI (match_operand:QIHISI 1 "register_operand" "") + (match_operand:QIHISI 2 "register_operand" "")))] + "reload_completed + && TARGET_16_BIT + && REGNO (operands[0]) == REGNO (operands[2]) + && REGNO (operands[0]) != REGNO (operands[1]) + && TEST_HARD_REG_BIT (reg_class_contents[MIDDLE_REGS], REGNO (operands[0]))" + [(set (match_dup 0) (plus:QIHISI (match_dup 2) (match_dup 1)))]) + +;; Try to make xor/ior/and/mult as xor33/ior33/and33/mult33. +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operator:SI 1 "nds32_have_33_inst_operator" + [(match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "register_operand" "")]))] + "reload_completed + && TARGET_16_BIT + && REGNO (operands[0]) == REGNO (operands[3]) + && REGNO (operands[0]) != REGNO (operands[2]) + && TEST_HARD_REG_BIT (reg_class_contents[LOW_REGS], REGNO (operands[0])) + && TEST_HARD_REG_BIT (reg_class_contents[LOW_REGS], REGNO (operands[2]))" + [(set (match_dup 0) (match_op_dup 1 [(match_dup 3) (match_dup 2)]))]) + +(define_peephole + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "register_operand" "")) + (set (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "register_operand" ""))] + "TARGET_16_BIT + && !TARGET_ISA_V2 + && NDS32_IS_GPR_REGNUM (REGNO (operands[0])) + && NDS32_IS_GPR_REGNUM (REGNO (operands[1])) + && ((REGNO (operands[0]) & 0x1) == 0) + && ((REGNO (operands[1]) & 0x1) == 0) + && (REGNO (operands[0]) + 1) == REGNO (operands[2]) + && (REGNO (operands[1]) + 1) == REGNO (operands[3])" + "movd44\t%0, %1" + [(set_attr "type" "alu") + (set_attr "length" "2")]) + +;; Merge two fcpyss to fcpysd. +(define_peephole2 + [(set (match_operand:SF 0 "float_even_register_operand" "") + (match_operand:SF 1 "float_even_register_operand" "")) + (set (match_operand:SF 2 "float_odd_register_operand" "") + (match_operand:SF 3 "float_odd_register_operand" ""))] + "(TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) + && REGNO (operands[0]) == REGNO (operands[2]) - 1 + && REGNO (operands[1]) == REGNO (operands[3]) - 1" + [(set (match_dup 4) (match_dup 5))] + { + operands[4] = gen_rtx_REG (DFmode, REGNO (operands[0])); + operands[5] = gen_rtx_REG (DFmode, REGNO (operands[1])); + }) + +(define_peephole2 + [(set (match_operand:SF 0 "float_odd_register_operand" "") + (match_operand:SF 1 "float_odd_register_operand" "")) + (set (match_operand:SF 2 "float_even_register_operand" "") + (match_operand:SF 3 "float_even_register_operand" ""))] + "(TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) + && REGNO (operands[2]) == REGNO (operands[0]) - 1 + && REGNO (operands[3]) == REGNO (operands[1]) - 1" + [(set (match_dup 4) (match_dup 5))] + { + operands[4] = gen_rtx_REG (DFmode, REGNO (operands[2])); + operands[5] = gen_rtx_REG (DFmode, REGNO (operands[3])); + }) + +;; Merge two flsi to fldi. +(define_peephole2 + [(set (match_operand:SF 0 "float_even_register_operand" "") + (match_operand:SF 1 "memory_operand" "")) + (set (match_operand:SF 2 "float_odd_register_operand" "") + (match_operand:SF 3 "memory_operand" ""))] + "REGNO (operands[0]) == REGNO (operands[2]) - 1 + && nds32_memory_merge_peep_p (operands[3], operands[1])" + [(set (match_dup 0) (match_dup 1))] +{ + operands[1] = widen_memory_access (operands[3], DFmode, 0); + operands[0] = gen_rtx_REG (DFmode, REGNO (operands[0])); +}) + +(define_peephole2 + [(set (match_operand:SF 0 "float_odd_register_operand" "") + (match_operand:SF 1 "memory_operand" "")) + (set (match_operand:SF 2 "float_even_register_operand" "") + (match_operand:SF 3 "memory_operand" ""))] + "REGNO (operands[2]) == REGNO (operands[0]) - 1 + && nds32_memory_merge_peep_p (operands[1], operands[3])" + [(set (match_dup 0) (match_dup 1))] +{ + operands[1] = widen_memory_access (operands[1], DFmode, 0); + operands[0] = gen_rtx_REG (DFmode, REGNO (operands[2])); +}) + +;; Merge two fssi to fsdi. +(define_peephole2 + [(set (match_operand:SF 0 "memory_operand" "") + (match_operand:SF 1 "float_even_register_operand" "")) + (set (match_operand:SF 2 "memory_operand" "") + (match_operand:SF 3 "float_odd_register_operand" ""))] + "REGNO (operands[1]) == REGNO (operands[3]) - 1 + && nds32_memory_merge_peep_p (operands[2], operands[0])" + [(set (match_dup 0) (match_dup 1))] +{ + operands[0] = widen_memory_access (operands[2], DFmode, 0); + operands[1] = gen_rtx_REG (DFmode, REGNO (operands[1])); +}) + +(define_peephole2 + [(set (match_operand:SF 0 "memory_operand" "") + (match_operand:SF 1 "float_odd_register_operand" "")) + (set (match_operand:SF 2 "memory_operand" "") + (match_operand:SF 3 "float_even_register_operand" ""))] + "REGNO (operands[3]) == REGNO (operands[1]) - 1 + && nds32_memory_merge_peep_p (operands[0], operands[2])" + [(set (match_dup 0) (match_dup 1))] +{ + operands[0] = widen_memory_access (operands[0], DFmode, 0); + operands[1] = gen_rtx_REG (DFmode, REGNO (operands[3])); +}) + +;; ------------------------------------------------------------------------ +;; GCC will prefer [u]divmodsi3 rather than [u]divsi3 even remainder is +;; unused, so we use split to drop mod operation for lower register pressure. + +(define_split + [(set (match_operand:SI 0 "register_operand") + (div:SI (match_operand:SI 1 "register_operand") + (match_operand:SI 2 "register_operand"))) + (set (match_operand:SI 3 "register_operand") + (mod:SI (match_dup 1) (match_dup 2)))] + "find_regno_note (insn, REG_UNUSED, REGNO (operands[3])) != NULL + && can_create_pseudo_p ()" + [(set (match_dup 0) + (div:SI (match_dup 1) + (match_dup 2)))]) + +(define_split + [(set (match_operand:SI 0 "register_operand") + (udiv:SI (match_operand:SI 1 "register_operand") + (match_operand:SI 2 "register_operand"))) + (set (match_operand:SI 3 "register_operand") + (umod:SI (match_dup 1) (match_dup 2)))] + "find_regno_note (insn, REG_UNUSED, REGNO (operands[3])) != NULL + && can_create_pseudo_p ()" + [(set (match_dup 0) + (udiv:SI (match_dup 1) + (match_dup 2)))]) + +(define_peephole2 + [(set (match_operand:DI 0 "register_operand") + (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand")) + (sign_extend:DI (match_operand:SI 2 "register_operand"))))] + "NDS32_EXT_DSP_P () + && peep2_regno_dead_p (1, WORDS_BIG_ENDIAN ? REGNO (operands[0]) + 1 : REGNO (operands[0]))" + [(const_int 1)] +{ + rtx highpart = nds32_di_high_part_subreg (operands[0]); + emit_insn (gen_smulsi3_highpart (highpart, operands[1], operands[2])); + DONE; +}) + +(define_split + [(set (match_operand:DI 0 "nds32_general_register_operand" "") + (match_operand:DI 1 "nds32_general_register_operand" ""))] + "find_regno_note (insn, REG_UNUSED, REGNO (operands[0])) != NULL + || find_regno_note (insn, REG_UNUSED, REGNO (operands[0]) + 1) != NULL" + [(set (match_dup 0) (match_dup 1))] +{ + rtx dead_note = find_regno_note (curr_insn, REG_UNUSED, REGNO (operands[0])); + HOST_WIDE_INT offset; + if (dead_note == NULL_RTX) + offset = 0; + else + offset = 4; + operands[0] = simplify_gen_subreg ( + SImode, operands[0], + DImode, offset); + operands[1] = simplify_gen_subreg ( + SImode, operands[1], + DImode, offset); +}) diff --git a/gcc/config/nds32/nds32-pipelines-auxiliary.c b/gcc/config/nds32/nds32-pipelines-auxiliary.c index a396fff..903a2ed 100644 --- a/gcc/config/nds32/nds32-pipelines-auxiliary.c +++ b/gcc/config/nds32/nds32-pipelines-auxiliary.c @@ -21,14 +21,2638 @@ /* ------------------------------------------------------------------------ */ +#include #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 "tree-pass.h" /* ------------------------------------------------------------------------ */ -/* This file is prepared for future implementation of precise - pipeline description for nds32 target. */ +namespace nds32 { +namespace scheduling { + +/* Classify the memory access direction. It's unknown if the offset register + is not a constant value. */ +enum memory_access_direction +{ + MEM_ACCESS_DIR_POS, + MEM_ACCESS_DIR_NEG, + MEM_ACCESS_DIR_UNKNOWN +}; + +/* This class provides some wrappers of the DFA scheduler. Due to the design + drawback of the DFA scheduler, creating two instances at the same time is + now allowed. Use the loosest relationship such as 'dependency' instead of + 'aggregation' or 'composition' can minimize this issue. */ +class pipeline_simulator +{ +public: + pipeline_simulator (); + ~pipeline_simulator (); + + void advance_cycle (int cycles = 1); + int query_latency (rtx_insn *producer, rtx_insn *consumer) const; + int issue_insn (rtx_insn *insn); + int force_issue_insn (rtx_insn *insn); + +private: + static int gcc_dfa_initialized_; + state_t state_; +}; + +/* Insert pseudo NOPs so that we can see stall cycles caused by structural or + data hazards in the assembly code. The design of this class is similar to + the 'template method' pattern, but we don't need to maintain multiple + customized algorithms at the same time. Hence this class has no virtual + functions providing further customizations. */ +class stall_inserter +{ +private: + enum dep_type { RES_DEP, DATA_DEP }; + +public: + void insert_stalls (); + +private: + static rtx emit_pseudo_nop_before (rtx_insn *insn, int cycles, enum dep_type type); + + void insert_structural_hazard_stalls (); + void insert_data_hazard_stalls (); + void emit_pseudo_nops_for_data_hazards (rtx_insn *insn, + pipeline_simulator &simulator); +}; + +class pass_nds32_print_stalls : public rtl_opt_pass +{ +public: + pass_nds32_print_stalls (gcc::context *ctxt); + + bool gate (function *); + unsigned int execute (function *); +}; + +int pipeline_simulator::gcc_dfa_initialized_ = 0; + +const pass_data pass_data_nds32_print_stalls = +{ + RTL_PASS, /* type */ + "print_stalls", /* 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 */ +}; + +rtl_opt_pass * +make_pass_nds32_print_stalls (gcc::context *ctxt) +{ + return new pass_nds32_print_stalls (ctxt); +} + +/* A safe wrapper to the function reg_overlap_mentioned_p (). */ +bool +reg_overlap_p (rtx x, rtx in) +{ + if (x == NULL_RTX || in == NULL_RTX) + return false; + + return static_cast (reg_overlap_mentioned_p (x, in)); +} + +/* Calculate the cycle distance between two insns in pipeline view. + Hence each insn can be treated as one cycle. + TODO: multi-cycle insns should be handled + specially, but we haven't done it here. */ +int +cycle_distance (rtx_insn *from, rtx_insn *to) +{ + int count = 1; + + for (from = NEXT_INSN (from); from && from != to; from = NEXT_INSN (from)) + { + if (!insn_executable_p (from)) + continue; + + if (insn_pseudo_nop_p (from)) + count += INTVAL (XVECEXP (PATTERN (from), 0, 0)); + else + ++count; + } + + return count; +} + +/* Determine the memory access direction of a load/store insn. */ +memory_access_direction +determine_access_direction (rtx_insn *insn) +{ + int post_update_rtx_index; + rtx plus_rtx; + rtx mem_rtx; + rtx offset_rtx; + + switch (get_attr_type (insn)) + { + case TYPE_LOAD_MULTIPLE: + gcc_assert (parallel_elements (insn) >= 2); + + post_update_rtx_index = find_post_update_rtx (insn); + if (post_update_rtx_index != -1) + plus_rtx = SET_SRC (parallel_element (insn, post_update_rtx_index)); + else + { + /* (parallel + [(set (reg) (mem (reg))) : index 0 + (set (reg) (mem (plus (reg) (...)))) : index 1 + ...]) */ + mem_rtx = SET_SRC (parallel_element (insn, 1)); + if (GET_CODE (mem_rtx) == UNSPEC) + mem_rtx = XVECEXP (mem_rtx, 0, 0); + gcc_assert (MEM_P (mem_rtx)); + plus_rtx = XEXP (mem_rtx, 0); + } + break; + + case TYPE_STORE_MULTIPLE: + gcc_assert (parallel_elements (insn) >= 2); + + post_update_rtx_index = find_post_update_rtx (insn); + if (post_update_rtx_index != -1) + plus_rtx = SET_SRC (parallel_element (insn, post_update_rtx_index)); + else + { + /* (parallel + [(set (mem (reg)) (reg)) : index 0 + (set (mem (plus (reg) (...))) (reg)) : index 1 + ...]) */ + mem_rtx = SET_DEST (parallel_element (insn, 1)); + if (GET_CODE (mem_rtx) == UNSPEC) + mem_rtx = XVECEXP (mem_rtx, 0, 0); + gcc_assert (MEM_P (mem_rtx)); + plus_rtx = XEXP (mem_rtx, 0); + } + break; + + case TYPE_LOAD: + case TYPE_STORE: + mem_rtx = extract_mem_rtx (insn); + + switch (GET_CODE (XEXP (mem_rtx, 0))) + { + case POST_INC: + /* (mem (post_inc (...))) */ + return MEM_ACCESS_DIR_POS; + + case POST_DEC: + /* (mem (post_dec (...))) */ + return MEM_ACCESS_DIR_NEG; + + case PLUS: + /* (mem (plus (reg) (...))) */ + plus_rtx = XEXP (mem_rtx, 0); + break; + + case POST_MODIFY: + /* (mem (post_modify (reg) (plus (reg) (...)))) */ + plus_rtx = XEXP (XEXP (mem_rtx, 0), 1); + break; + + default: + gcc_unreachable (); + } + break; + + default: + gcc_unreachable (); + } + + gcc_assert (GET_CODE (plus_rtx) == PLUS); + + offset_rtx = XEXP (plus_rtx, 1); + if (GET_CODE (offset_rtx) == CONST_INT) + { + if (INTVAL (offset_rtx) < 0) + return MEM_ACCESS_DIR_NEG; + else + return MEM_ACCESS_DIR_POS; + } + + return MEM_ACCESS_DIR_UNKNOWN; +} + +/* Return the nth load/store operation in the real micro-operation + accessing order. */ +rtx +extract_nth_access_rtx (rtx_insn *insn, int n) +{ + int n_elems = parallel_elements (insn); + int post_update_rtx_index = find_post_update_rtx (insn); + memory_access_direction direction = determine_access_direction (insn); + + gcc_assert (direction != MEM_ACCESS_DIR_UNKNOWN); + + /* Reverse the order if the direction negative. */ + if (direction == MEM_ACCESS_DIR_NEG) + n = -1 * n - 1; + + if (post_update_rtx_index != -1) + { + if (n >= 0 && post_update_rtx_index <= n) + ++n; + else if (n < 0 && post_update_rtx_index >= n + n_elems) + --n; + } + + return parallel_element (insn, n); +} + +/* Returns the register operated by the nth load/store operation in the real + micro-operation accessing order. This function assumes INSN must be a + multiple-word load/store insn. */ +rtx +extract_nth_lmsw_access_reg (rtx_insn *insn, int n) +{ + rtx nth_rtx = extract_nth_access_rtx (insn, n); + + if (nth_rtx == NULL_RTX) + return NULL_RTX; + + switch (get_attr_type (insn)) + { + case TYPE_LOAD_MULTIPLE: + return SET_DEST (nth_rtx); + + case TYPE_STORE_MULTIPLE: + return SET_SRC (nth_rtx); + + default: + gcc_unreachable (); + } +} + +/* Returns the register operated by the nth load/store operation in the real + micro-operation accessing order. This function assumes INSN must be a + double-word load/store insn. */ +rtx +extract_nth_ls2_access_reg (rtx_insn *insn, int n) +{ + rtx reg; + enum machine_mode mode; + + if (post_update_insn_p (insn)) + { + memory_access_direction direction = determine_access_direction (insn); + gcc_assert (direction != MEM_ACCESS_DIR_UNKNOWN); + + /* Reverse the order if the direction negative. */ + if (direction == MEM_ACCESS_DIR_NEG) + n = -1 * n - 1; + } + + /* Handle the out-of-range case. */ + if (n < -2 || n > 1) + return NULL_RTX; + + /* Convert the index to a positive one. */ + if (n < 0) + n = 2 + n; + + switch (get_attr_type (insn)) + { + case TYPE_LOAD: + reg = SET_DEST (PATTERN (insn)); + break; + + case TYPE_STORE: + reg = SET_SRC (PATTERN (insn)); + break; + + default: + gcc_unreachable (); + } + + gcc_assert (REG_P (reg) || GET_CODE (reg) == SUBREG); + + switch (GET_MODE (reg)) + { + case DImode: + mode = SImode; + break; + + case DFmode: + mode = SFmode; + break; + + default: + gcc_unreachable (); + } + + if (n == 0) + return gen_lowpart (mode, reg); + else + return gen_highpart (mode, reg); +} + +/* Returns the register operated by the nth load/store operation in the real + micro-operation accessing order. */ +rtx +extract_nth_access_reg (rtx_insn *insn, int index) +{ + switch (GET_CODE (PATTERN (insn))) + { + case PARALLEL: + return extract_nth_lmsw_access_reg (insn, index); + + case SET: + return extract_nth_ls2_access_reg (insn, index); + + default: + gcc_unreachable (); + } +} + +/* Determine if the latency is occured when the consumer PBSADA_INSN uses the + value of DEF_REG in its Ra or Rb fields. */ +bool +pbsada_insn_ra_rb_dep_reg_p (rtx pbsada_insn, rtx def_reg) +{ + rtx unspec_rtx = SET_SRC (PATTERN (pbsada_insn)); + gcc_assert (GET_CODE (unspec_rtx) == UNSPEC); + + rtx pbsada_ra = XVECEXP (unspec_rtx, 0, 0); + rtx pbsada_rb = XVECEXP (unspec_rtx, 0, 1); + + if (rtx_equal_p (def_reg, pbsada_ra) + || rtx_equal_p (def_reg, pbsada_rb)) + return true; + + return false; +} + +/* Determine if the latency is occured when the consumer PBSADA_INSN uses the + value of DEF_REG in its Rt field. */ +bool +pbsada_insn_rt_dep_reg_p (rtx pbsada_insn, rtx def_reg) +{ + rtx pbsada_rt = SET_DEST (PATTERN (pbsada_insn)); + + if (rtx_equal_p (def_reg, pbsada_rt)) + return true; + + return false; +} + +/* Check if INSN is a movd44 insn consuming DEF_REG. */ +bool +movd44_even_dep_p (rtx_insn *insn, rtx def_reg) +{ + if (!movd44_insn_p (insn)) + return false; + + rtx use_rtx = SET_SRC (PATTERN (insn)); + + if (REG_P (def_reg)) + { + return rtx_equal_p (def_reg, use_rtx); + } + else if (GET_CODE (def_reg) == SUBREG + && GET_MODE (def_reg) == SImode + && rtx_equal_p (SUBREG_REG (def_reg), use_rtx)) + { + if (TARGET_BIG_ENDIAN && SUBREG_BYTE (def_reg) == 4) + return true; + + if (!TARGET_BIG_ENDIAN && SUBREG_BYTE (def_reg) == 0) + return true; + + return false; + } + + return false; +} + +/* Check if INSN is a wext insn consuming DEF_REG. */ +bool +wext_odd_dep_p (rtx insn, rtx def_reg) +{ + rtx shift_rtx = XEXP (SET_SRC (PATTERN (insn)), 0); + rtx use_reg = XEXP (shift_rtx, 0); + rtx pos_rtx = XEXP (shift_rtx, 1); + + if (REG_P (pos_rtx) && reg_overlap_p (def_reg, pos_rtx)) + return true; + + if (GET_MODE (def_reg) == DImode) + return reg_overlap_p (def_reg, use_reg); + + gcc_assert (REG_P (def_reg) || GET_CODE (def_reg) == SUBREG); + gcc_assert (REG_P (use_reg)); + + if (REG_P (def_reg)) + { + if (!TARGET_BIG_ENDIAN) + return REGNO (def_reg) == REGNO (use_reg) + 1; + else + return REGNO (def_reg) == REGNO (use_reg); + } + + if (GET_CODE (def_reg) == SUBREG) + { + if (!reg_overlap_p (def_reg, use_reg)) + return false; + + if (!TARGET_BIG_ENDIAN) + return SUBREG_BYTE (def_reg) == 4; + else + return SUBREG_BYTE (def_reg) == 0; + } + + return false; +} + +/* Check if INSN is a bpick insn consuming DEF_REG. */ +bool +bpick_ra_rb_dep_p (rtx insn, rtx def_reg) +{ + rtx ior_rtx = SET_SRC (PATTERN (insn)); + rtx and1_rtx = XEXP (ior_rtx, 0); + rtx and2_rtx = XEXP (ior_rtx, 1); + rtx reg1_0 = XEXP (and1_rtx, 0); + rtx reg1_1 = XEXP (and1_rtx, 1); + rtx reg2_0 = XEXP (and2_rtx, 0); + rtx reg2_1 = XEXP (and2_rtx, 1); + + if (GET_CODE (reg1_0) == NOT) + { + if (rtx_equal_p (reg1_0, reg2_0)) + return reg_overlap_p (def_reg, reg1_1) + || reg_overlap_p (def_reg, reg2_1); + + if (rtx_equal_p (reg1_0, reg2_1)) + return reg_overlap_p (def_reg, reg1_1) + || reg_overlap_p (def_reg, reg2_0); + } + + if (GET_CODE (reg1_1) == NOT) + { + if (rtx_equal_p (reg1_1, reg2_0)) + return reg_overlap_p (def_reg, reg1_0) + || reg_overlap_p (def_reg, reg2_1); + + if (rtx_equal_p (reg1_1, reg2_1)) + return reg_overlap_p (def_reg, reg1_0) + || reg_overlap_p (def_reg, reg2_0); + } + + if (GET_CODE (reg2_0) == NOT) + { + if (rtx_equal_p (reg2_0, reg1_0)) + return reg_overlap_p (def_reg, reg2_1) + || reg_overlap_p (def_reg, reg1_1); + + if (rtx_equal_p (reg2_0, reg1_1)) + return reg_overlap_p (def_reg, reg2_1) + || reg_overlap_p (def_reg, reg1_0); + } + + if (GET_CODE (reg2_1) == NOT) + { + if (rtx_equal_p (reg2_1, reg1_0)) + return reg_overlap_p (def_reg, reg2_0) + || reg_overlap_p (def_reg, reg1_1); + + if (rtx_equal_p (reg2_1, reg1_1)) + return reg_overlap_p (def_reg, reg2_0) + || reg_overlap_p (def_reg, reg1_0); + } + + gcc_unreachable (); +} + +pipeline_simulator::pipeline_simulator () +{ + /* The design of dfa_start () operates on static global variables and + allocates memory space without checking whether the function is called + twice or not. We add some guards in order to protect it from abusing. */ + if (!gcc_dfa_initialized_++) + dfa_start (); + + state_ = xmalloc (state_size()); + state_reset (state_); +} + +pipeline_simulator::~pipeline_simulator () +{ + /* The design of dfa_finish () operates on a static global variable and + deallocates memory space without checking whether the function is called + twice or not. We add some guards in order to protect it from abusing. */ + free (state_); + + gcc_assert(gcc_dfa_initialized_ > 0); + if (!--gcc_dfa_initialized_) + dfa_finish (); +} + +void +pipeline_simulator::advance_cycle (int cycles) +{ + gcc_assert (cycles > 0); + + /* The second argument was 'NULL', but we found the expression is directly + written in insn-automata.c: + if (insn == 0) + insn_code = DFA__ADVANCE_CYCLE; + Hence we change it to '0' in order to make it consistent. */ + while (cycles--) + state_transition (state_, 0); +} + +/* A wrapper of insn_latency () provided by the insn-attr.h in the object tree. + See that file for more information. */ +int +pipeline_simulator::query_latency (rtx_insn *producer, rtx_insn *consumer) const +{ + return insn_latency (producer, consumer); +} + +/* Return 0 or negative if we can issue INSN at the current cycle. Otherwise, + return a postive value indicates how many cycles we have to wait. The + interface is consistent with state_transition () provided by insn-attr.h + in the object directory. See that file for more information. */ +int +pipeline_simulator::issue_insn (rtx_insn *insn) +{ + int stalls; + + /* Skip cycles specified by pseudo NOPs. */ + if (insn_pseudo_nop_p (insn)) + { + int nop_stalls = INTVAL (XVECEXP (PATTERN (insn), 0, 0)); + + gcc_assert (nop_stalls > 0); + advance_cycle (nop_stalls); + stalls = -1; + } + else + { + stalls = state_transition (state_, insn); + + /* All targets are single-issue, so we advance one cycle once after + an insn has been issued successfully. */ + if (stalls <= 0) + advance_cycle (); + } + + return stalls; +} + +/* This function is similar to issue_insn (), but it advances cycles until INSN + can be issued successfully. If INSN can be issued at the current cycle, the + return value will be 0 or negaitive. Otherwise, the function will return + the cycles it has been skipped. */ +int +pipeline_simulator::force_issue_insn (rtx_insn *insn) +{ + int stalls; + + stalls = issue_insn (insn); + + /* Skip cycles until we can issue the insn. */ + if (stalls > 0) + { + advance_cycle (stalls); + issue_insn (insn); + } + + return stalls; +} + +/* The main flow of the class STALL_INSERTER. We insert NOPs for structural + hazards because self-stalled instructions also consume the delay cycles + caused by data hazards. */ +void +stall_inserter::insert_stalls () +{ + compute_bb_for_insn_safe (); + + insert_structural_hazard_stalls (); + insert_data_hazard_stalls (); + + /* We have to call the following two functions again after we inserting + some insns after it has been invoked. Otherwise, an assert expression + in final () will be triggered and cause to an internal compiler error. */ + init_insn_lengths (); + shorten_branches (get_insns ()); + + free_bb_for_insn (); +} + +/* A helper function inserting NOPs. CYCLES indicates how many cycles the NOP + insn consumes. TYPE indicates what type of the NOP insn we want to insert; + now there are two types available: RES_DEP and DATA_DEP. */ +rtx +stall_inserter::emit_pseudo_nop_before ( + rtx_insn *insn, int cycles, enum dep_type type) +{ + rtx nop_pattern; + rtx_insn *nop_insn; + int recog; + + switch (type) + { + case RES_DEP: + nop_pattern = gen_nop_res_dep (GEN_INT (cycles)); + break; + case DATA_DEP: + nop_pattern = gen_nop_data_dep (GEN_INT (cycles)); + break; + default: + gcc_unreachable (); + } + + nop_insn = emit_insn_before (nop_pattern, insn); + recog = recog_memoized (nop_insn); + gcc_assert(recog != -1); + + return nop_insn; +} + +void +stall_inserter::insert_structural_hazard_stalls () +{ + pipeline_simulator simulator; + rtx_insn *insn; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (!insn_executable_p (insn)) continue; + + int stalls = simulator.force_issue_insn (insn); + + if (stalls > 0) + emit_pseudo_nop_before (insn, stalls, RES_DEP); + } +} + +void +stall_inserter::insert_data_hazard_stalls () +{ + pipeline_simulator simulator; + rtx_insn *insn; + + /* Calling to df_insn_rescan_all here is required in order to avoid crash + when some special options are specified by users, such as + -O0 -fschedule-insns2. */ + df_chain_add_problem (DF_DU_CHAIN); + df_insn_rescan_all (); + df_analyze (); + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (!insn_executable_p (insn)) continue; + + simulator.force_issue_insn (insn); + emit_pseudo_nops_for_data_hazards (insn, simulator); + } + + /* We must call df_finish_pass manually because it should be invoked before + BB information is destroyed. Hence we cannot set the TODO_df_finish flag + to the pass manager. */ + df_insn_rescan_all (); + df_finish_pass (false); +} + +/* Traverse all insns using the results produced by INSN and ask SIMULATOR + how many delay cycles between them. If there are some delay cycles, insert + corresponding NOP insns there. */ +void +stall_inserter::emit_pseudo_nops_for_data_hazards ( + rtx_insn *insn, pipeline_simulator &simulator) +{ + df_ref def; + df_link *link; + std::set processed_insns; + + FOR_EACH_INSN_DEF (def, insn) + { + for (link = DF_REF_CHAIN (def); link; link = link->next) + { + if (!DF_REF_INSN_INFO (link->ref)) + continue; + + rtx_insn *use_insn = DF_REF_INSN (link->ref); + + if (!insn_executable_p (use_insn) + || processed_insns.count (use_insn)) + continue; + + int stalls = simulator.query_latency (insn, use_insn); + int distance = cycle_distance (insn, use_insn); + + if (stalls > distance) + { + stalls -= distance; + emit_pseudo_nop_before (use_insn, stalls, DATA_DEP); + processed_insns.insert (use_insn); + } + } + } +} + +pass_nds32_print_stalls::pass_nds32_print_stalls (gcc::context *ctxt) + : rtl_opt_pass (pass_data_nds32_print_stalls, ctxt) +{ +} + +bool pass_nds32_print_stalls::gate (function *) +{ + return TARGET_PRINT_STALLS; +} + +unsigned int +pass_nds32_print_stalls::execute (function *) +{ + stall_inserter inserter; + + inserter.insert_stalls (); + return 0; +} + +} // namespace scheduling +} // namespace nds32 + +/* ------------------------------------------------------------------------ */ + +using namespace nds32; +using namespace nds32::scheduling; + +namespace { // anonymous namespace + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at II. */ +bool +n7_consumed_by_ii_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + /* MOVD44_E */ + case TYPE_ALU: + if (movd44_even_dep_p (consumer, def_reg)) + return true; + + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_MUL: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_MAC: + use_rtx = extract_mac_non_acc_rtx (consumer); + break; + + /* Some special instructions, divmodsi4 and udivmodsi4, produce two + results, the quotient and the remainder. It requires two micro- + operations in order to write two registers. We have to check the + dependency from the producer to the first micro-operation. */ + case TYPE_DIV: + if (divmod_p (consumer)) + use_rtx = SET_SRC (parallel_element (consumer, 0)); + else + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_LOAD: + /* ADDR_IN_bi_Ra, ADDR_IN_!bi */ + if (post_update_insn_p (consumer)) + use_rtx = extract_base_reg (consumer); + else + use_rtx = extract_mem_rtx (consumer); + break; + + case TYPE_STORE: + /* ADDR_IN_bi_Ra, ADDR_IN_!bi */ + if (post_update_insn_p (consumer)) + use_rtx = extract_base_reg (consumer); + else + use_rtx = extract_mem_rtx (consumer); + + if (reg_overlap_p (def_reg, use_rtx)) + return true; + + /* ST_bi, ST_!bi_RI */ + if (!post_update_insn_p (consumer) + && !immed_offset_p (extract_mem_rtx (consumer))) + return false; + + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_LOAD_MULTIPLE: + use_rtx = extract_base_reg (consumer); + break; + + case TYPE_STORE_MULTIPLE: + /* ADDR_IN */ + use_rtx = extract_base_reg (consumer); + if (reg_overlap_p (def_reg, use_rtx)) + return true; + + /* SMW (N, 1) */ + use_rtx = extract_nth_access_rtx (consumer, 0); + break; + + case TYPE_BRANCH: + use_rtx = PATTERN (consumer); + break; + + default: + gcc_unreachable (); + } + + if (reg_overlap_p (def_reg, use_rtx)) + return true; + + return false; +} + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at AG (II). */ +bool +n8_consumed_by_addr_in_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_BRANCH: + use_rtx = extract_branch_target_rtx (consumer); + break; + + case TYPE_LOAD: + if (load_single_p (consumer)) + use_rtx = extract_mem_rtx (consumer); + else + use_rtx = extract_base_reg (consumer); + break; + + case TYPE_STORE: + if (store_single_p (consumer) + && (!post_update_insn_p (consumer) + || immed_offset_p (extract_mem_rtx (consumer)))) + use_rtx = extract_mem_rtx (consumer); + else + use_rtx = extract_base_reg (consumer); + break; + + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + use_rtx = extract_base_reg (consumer); + break; + + default: + gcc_unreachable (); + } + + return reg_overlap_p (def_reg, use_rtx); +} + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at EX. */ +bool +n8_consumed_by_ex_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_ALU: + if (movd44_even_dep_p (consumer, def_reg)) + return true; + + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_MUL: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_MAC: + use_rtx = extract_mac_non_acc_rtx (consumer); + break; + + /* Some special instructions, divmodsi4 and udivmodsi4, produce two + results, the quotient and the remainder. It requires two micro- + operations in order to write two registers. We have to check the + dependency from the producer to the first micro-operation. */ + case TYPE_DIV: + if (divmod_p (consumer)) + use_rtx = SET_SRC (parallel_element (consumer, 0)); + else + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_BRANCH: + use_rtx = extract_branch_condition_rtx (consumer); + break; + + case TYPE_STORE: + /* exclude ST_!bi_RR */ + if (!post_update_insn_p (consumer) + && !immed_offset_p (extract_mem_rtx (consumer))) + return false; + + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_STORE_MULTIPLE: + use_rtx = extract_nth_access_rtx (consumer, 0); + break; + + default: + gcc_unreachable (); + } + + return reg_overlap_p (def_reg, use_rtx); +} + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at AG (II). */ +bool +e8_consumed_by_addr_in_p (rtx_insn *consumer, rtx def_reg) +{ + return n8_consumed_by_addr_in_p (consumer, def_reg); +} + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at EX. */ +bool +e8_consumed_by_ex_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_ALU: + case TYPE_STORE: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_MUL: + case TYPE_MAC: + case TYPE_DIV: + case TYPE_BRANCH: + case TYPE_STORE_MULTIPLE: + return n8_consumed_by_ex_p (consumer, def_reg); + + default: + gcc_unreachable (); + } + + return reg_overlap_p (def_reg, use_rtx); +} + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at EX. */ +bool +n9_2r1w_consumed_by_ex_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_ALU: + if (movd44_even_dep_p (consumer, def_reg)) + return true; + + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_PBSAD: + case TYPE_MUL: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_ALU_SHIFT: + use_rtx = extract_shift_reg (consumer); + break; + + case TYPE_PBSADA: + return pbsada_insn_ra_rb_dep_reg_p (consumer, def_reg); + + case TYPE_MAC: + use_rtx = PATTERN (consumer); + break; + + case TYPE_DIV: + if (divmod_p (consumer)) + use_rtx = SET_SRC (parallel_element (consumer, 0)); + else + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_MMU: + if (GET_CODE (PATTERN (consumer)) == SET) + use_rtx = SET_SRC (PATTERN (consumer)); + else + return true; + break; + + case TYPE_LOAD: + /* ADDR_IN_bi_Ra, ADDR_IN_!bi */ + if (post_update_insn_p (consumer)) + use_rtx = extract_base_reg (consumer); + else + use_rtx = extract_mem_rtx (consumer); + break; + + case TYPE_STORE: + /* ADDR_IN_bi_Ra, ADDR_IN_!bi */ + if (post_update_insn_p (consumer)) + use_rtx = extract_base_reg (consumer); + else + use_rtx = extract_mem_rtx (consumer); + + if (reg_overlap_p (def_reg, use_rtx)) + return true; + + /* exclude ST_!bi_RR */ + if (!post_update_insn_p (consumer) + && !immed_offset_p (extract_mem_rtx (consumer))) + return false; + + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_LOAD_MULTIPLE: + use_rtx = extract_base_reg (consumer); + break; + + case TYPE_STORE_MULTIPLE: + /* ADDR_IN */ + use_rtx = extract_base_reg (consumer); + if (reg_overlap_p (def_reg, use_rtx)) + return true; + + /* SMW (N, 1) */ + use_rtx = extract_nth_access_rtx (consumer, 0); + break; + + case TYPE_BRANCH: + use_rtx = PATTERN (consumer); + break; + + default: + gcc_unreachable (); + } + + if (reg_overlap_p (def_reg, use_rtx)) + return true; + + return false; +} + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at EX. */ +bool +n9_3r2w_consumed_by_ex_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_ALU: + case TYPE_PBSAD: + case TYPE_MUL: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_ALU_SHIFT: + use_rtx = extract_shift_reg (consumer); + break; + + case TYPE_PBSADA: + return pbsada_insn_ra_rb_dep_reg_p (consumer, def_reg); + + case TYPE_MAC: + use_rtx = extract_mac_non_acc_rtx (consumer); + break; + + /* Some special instructions, divmodsi4 and udivmodsi4, produce two + results, the quotient and the remainder. In 2R1W configuration, + it requires two micro-operations in order to write two registers. + We have to check the dependency from the producer to the first + micro-operation. */ + case TYPE_DIV: + if (divmod_p (consumer)) + use_rtx = SET_SRC (parallel_element (consumer, 0)); + else + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_MMU: + if (GET_CODE (PATTERN (consumer)) == SET) + use_rtx = SET_SRC (PATTERN (consumer)); + else + return true; + break; + + case TYPE_LOAD: + case TYPE_STORE: + use_rtx = extract_mem_rtx (consumer); + break; + + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + use_rtx = extract_base_reg (consumer); + break; + + case TYPE_BRANCH: + use_rtx = PATTERN (consumer); + break; + + default: + gcc_unreachable (); + } + + if (reg_overlap_p (def_reg, use_rtx)) + return true; + + return false; +} + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at EX. */ +bool +n10_consumed_by_ex_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_ALU: + case TYPE_PBSAD: + case TYPE_MUL: + case TYPE_DALU: + case TYPE_DALU64: + case TYPE_DMUL: + case TYPE_DPACK: + case TYPE_DINSB: + case TYPE_DCMP: + case TYPE_DCLIP: + case TYPE_DALUROUND: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_ALU_SHIFT: + use_rtx = extract_shift_reg (consumer); + break; + + case TYPE_PBSADA: + return pbsada_insn_ra_rb_dep_reg_p (consumer, def_reg); + + case TYPE_MAC: + case TYPE_DMAC: + use_rtx = extract_mac_non_acc_rtx (consumer); + break; + + /* Some special instructions, divmodsi4 and udivmodsi4, produce two + results, the quotient and the remainder. */ + case TYPE_DIV: + if (divmod_p (consumer)) + use_rtx = SET_SRC (parallel_element (consumer, 0)); + else + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_DWEXT: + return wext_odd_dep_p (consumer, def_reg); + + case TYPE_DBPICK: + return bpick_ra_rb_dep_p (consumer, def_reg); + + case TYPE_MMU: + if (GET_CODE (PATTERN (consumer)) == SET) + use_rtx = SET_SRC (PATTERN (consumer)); + else + return true; + break; + + case TYPE_LOAD: + case TYPE_STORE: + use_rtx = extract_mem_rtx (consumer); + break; + + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + use_rtx = extract_base_reg (consumer); + break; + + case TYPE_BRANCH: + use_rtx = PATTERN (consumer); + break; + + default: + gcc_unreachable (); + } + + if (reg_overlap_p (def_reg, use_rtx)) + return true; + + return false; +} + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at EX. */ +bool +gw_consumed_by_ex_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_ALU: + case TYPE_PBSAD: + case TYPE_MUL: + case TYPE_DALU: + case TYPE_DALU64: + case TYPE_DMUL: + case TYPE_DPACK: + case TYPE_DINSB: + case TYPE_DCMP: + case TYPE_DCLIP: + case TYPE_DALUROUND: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_ALU_SHIFT: + use_rtx = extract_shift_reg (consumer); + break; + + case TYPE_PBSADA: + return pbsada_insn_ra_rb_dep_reg_p (consumer, def_reg); + + case TYPE_MAC: + case TYPE_DMAC: + use_rtx = extract_mac_non_acc_rtx (consumer); + break; + + /* Some special instructions, divmodsi4 and udivmodsi4, produce two + results, the quotient and the remainder. We have to check the + dependency from the producer to the first micro-operation. */ + case TYPE_DIV: + if (divmod_p (consumer)) + use_rtx = SET_SRC (parallel_element (consumer, 0)); + else + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_DWEXT: + return wext_odd_dep_p (consumer, def_reg); + + case TYPE_DBPICK: + return bpick_ra_rb_dep_p (consumer, def_reg); + + case TYPE_MMU: + if (GET_CODE (PATTERN (consumer)) == SET) + use_rtx = SET_SRC (PATTERN (consumer)); + else + return true; + break; + + case TYPE_LOAD: + case TYPE_STORE: + use_rtx = extract_mem_rtx (consumer); + break; + + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + use_rtx = extract_base_reg (consumer); + break; + + case TYPE_BRANCH: + use_rtx = PATTERN (consumer); + break; + + default: + gcc_unreachable (); + } + + if (reg_overlap_p (def_reg, use_rtx)) + return true; + + return false; +} + +/* Check dependencies from any stages to ALU_E1 (E1). This is a helper + function of n13_consumed_by_e1_dep_p (). */ +bool +n13_alu_e1_insn_dep_reg_p (rtx_insn *alu_e1_insn, rtx def_reg) +{ + rtx unspec_rtx, operand_ra, operand_rb; + rtx src_rtx, dst_rtx; + + switch (INSN_CODE (alu_e1_insn)) + { + /* BSP and BSE are supported by built-in functions, the corresponding + patterns are formed by UNSPEC RTXs. We have to handle them + individually. */ + case CODE_FOR_unspec_bsp: + case CODE_FOR_unspec_bse: + unspec_rtx = SET_SRC (parallel_element (alu_e1_insn, 0)); + gcc_assert (GET_CODE (unspec_rtx) == UNSPEC); + + operand_ra = XVECEXP (unspec_rtx, 0, 0); + operand_rb = XVECEXP (unspec_rtx, 0, 1); + + if (rtx_equal_p (def_reg, operand_ra) + || rtx_equal_p (def_reg, operand_rb)) + return true; + + return false; + + /* Unlink general ALU instructions, MOVD44 requires operands at E1. */ + case CODE_FOR_move_di: + case CODE_FOR_move_df: + src_rtx = SET_SRC (PATTERN (alu_e1_insn)); + dst_rtx = SET_DEST (PATTERN (alu_e1_insn)); + + if (REG_P (dst_rtx) && REG_P (src_rtx) + && rtx_equal_p (src_rtx, def_reg)) + return true; + + return false; + + default: + return false; + } +} + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at E1. Because the address generation unti is + at E1, the address input should be ready at E1. Note that the branch + target is also a kind of addresses, so we have to check it. */ +bool +n13_consumed_by_e1_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + /* ALU_E1 */ + case TYPE_ALU: + return n13_alu_e1_insn_dep_reg_p (consumer, def_reg); + + case TYPE_PBSADA: + return pbsada_insn_ra_rb_dep_reg_p (consumer, def_reg); + + case TYPE_PBSAD: + case TYPE_MUL: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_MAC: + use_rtx = extract_mac_non_acc_rtx (consumer); + break; + + case TYPE_DIV: + if (divmod_p (consumer)) + use_rtx = SET_SRC (parallel_element (consumer, 0)); + else + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_MMU: + if (GET_CODE (PATTERN (consumer)) == SET) + use_rtx = SET_SRC (PATTERN (consumer)); + else + return true; + break; + + case TYPE_BRANCH: + use_rtx = extract_branch_target_rtx (consumer); + break; + + case TYPE_LOAD: + case TYPE_STORE: + use_rtx = extract_mem_rtx (consumer); + break; + + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + use_rtx = extract_base_reg (consumer); + break; + + default: + return false; + } + + if (reg_overlap_p (def_reg, use_rtx)) + return true; + + return false; +} + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at E2. */ +bool +n13_consumed_by_e2_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_ALU: + case TYPE_STORE: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_ALU_SHIFT: + use_rtx = extract_shift_reg (consumer); + break; + + case TYPE_PBSADA: + return pbsada_insn_rt_dep_reg_p (consumer, def_reg); + + case TYPE_STORE_MULTIPLE: + use_rtx = extract_nth_access_rtx (consumer, 0); + break; + + case TYPE_BRANCH: + use_rtx = extract_branch_condition_rtx (consumer); + break; + + default: + gcc_unreachable(); + } + + if (reg_overlap_p (def_reg, use_rtx)) + return true; + + return false; +} + +/* Check the dependency between the producer defining DEF_REG and CONSUMER + requiring input operand at AG (E1). */ +bool +pn_consumed_by_e1_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_LOAD: + if (load_single_p (consumer)) + use_rtx = extract_mem_rtx (consumer); + else + use_rtx = extract_base_reg (consumer); + break; + + case TYPE_STORE: + if (store_single_p (consumer) + && (!post_update_insn_p (consumer) + || immed_offset_p (extract_mem_rtx (consumer)))) + use_rtx = extract_mem_rtx (consumer); + else + use_rtx = extract_base_reg (consumer); + break; + + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + use_rtx = extract_base_reg (consumer); + break; + + default: + gcc_unreachable (); + } + + return reg_overlap_p (def_reg, use_rtx); +} + +bool +pn_consumed_by_e2_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_ALU: + if (get_attr_subtype (consumer) != SUBTYPE_SHIFT) + return false; + case TYPE_PBSAD: + case TYPE_PBSADA: + case TYPE_MUL: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_MAC: + use_rtx = extract_mac_non_acc_rtx (consumer); + break; + + default: + gcc_unreachable (); + } + + return reg_overlap_p (def_reg, use_rtx); +} + +bool +pn_consumed_by_e3_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_ALU: + if (get_attr_subtype (consumer) == SUBTYPE_SHIFT) + return false; + case TYPE_PBSAD: + case TYPE_PBSADA: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_BRANCH: + return (reg_overlap_p (def_reg, extract_branch_target_rtx (consumer)) + || reg_overlap_p (def_reg, + extract_branch_condition_rtx (consumer))); + break; + + case TYPE_STORE: + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + case TYPE_STORE_MULTIPLE: + use_rtx = extract_nth_access_rtx (consumer, 0); + break; + + default: + gcc_unreachable (); + } + + return reg_overlap_p (def_reg, use_rtx); +} + +bool +pn_consumed_by_e4_dep_p (rtx_insn *consumer, rtx def_reg) +{ + rtx use_rtx; + + switch (get_attr_type (consumer)) + { + case TYPE_MAC: + use_rtx = SET_DEST (PATTERN (consumer)); + break; + + case TYPE_DIV: + if (divmod_p (consumer)) + use_rtx = SET_SRC (parallel_element (consumer, 0)); + else + use_rtx = SET_SRC (PATTERN (consumer)); + break; + + default: + gcc_unreachable (); + } + + return reg_overlap_p (def_reg, use_rtx); +} + +} // anonymous namespace + +/* ------------------------------------------------------------------------ */ + +/* Guard functions for N7 core. */ + +bool +nds32_n7_load_to_ii_p (rtx_insn *producer, rtx_insn *consumer) +{ + if (post_update_insn_p (producer)) + return false; + + rtx def_reg = SET_DEST (PATTERN (producer)); + + return n7_consumed_by_ii_dep_p (consumer, def_reg); +} + +bool +nds32_n7_last_load_to_ii_p (rtx_insn *producer, rtx_insn *consumer) +{ + /* If PRODUCER is a post-update LMW insn, the last micro-operation updates + the base register and the result is ready in II stage, so we don't need + to handle that case in this guard function and the corresponding bypass + rule. */ + if (post_update_insn_p (producer)) + return false; + + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + if (last_def_reg == NULL_RTX) + return false; + + gcc_assert (REG_P (last_def_reg) || GET_CODE (last_def_reg) == SUBREG); + + return n7_consumed_by_ii_dep_p (consumer, last_def_reg); +} + +/* Guard functions for N8 core. */ + +bool +nds32_n8_load_to_ii_p (rtx_insn *producer, rtx_insn *consumer) +{ + if (post_update_insn_p (producer)) + return false; + + rtx def_reg = SET_DEST (PATTERN (producer)); + + return n8_consumed_by_addr_in_p (consumer, def_reg); +} + +bool +nds32_n8_load_bi_to_ii_p (rtx_insn *producer, rtx_insn *consumer) +{ + if (!post_update_insn_p (producer)) + return false; + + rtx def_reg = SET_DEST (PATTERN (producer)); + + return n8_consumed_by_addr_in_p (consumer, def_reg); +} + +bool +nds32_n8_load_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + if (post_update_insn_p (producer)) + return false; + + rtx def_reg = SET_DEST (PATTERN (producer)); + + return n8_consumed_by_ex_p (consumer, def_reg); +} + +bool +nds32_n8_ex_to_ii_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_ALU: + if (movd44_insn_p (producer)) + def_reg = extract_movd44_odd_reg (producer); + else + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_MUL: + case TYPE_MAC: + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_DIV: + if (divmod_p (producer)) + def_reg = SET_DEST (parallel_element (producer, 1)); + else + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_LOAD: + case TYPE_STORE: + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + if (!post_update_insn_p (producer)) + return false; + + def_reg = extract_base_reg (producer); + break; + + default: + gcc_unreachable (); + } + + return n8_consumed_by_addr_in_p (consumer, def_reg); +} + +bool +nds32_n8_last_load_to_ii_p (rtx_insn *producer, rtx_insn *consumer) +{ + /* If PRODUCER is a post-update LMW insn, the last micro-operation updates + the base register and the result is ready in EX stage, so we don't need + to handle that case in this guard function and the corresponding bypass + rule. */ + if (post_update_insn_p (producer)) + return false; + + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + if (last_def_reg == NULL_RTX) + return false; + + gcc_assert (REG_P (last_def_reg) || GET_CODE (last_def_reg) == SUBREG); + + return n8_consumed_by_addr_in_p (consumer, last_def_reg); +} + +bool +nds32_n8_last_load_two_to_ii_p (rtx_insn *producer, rtx_insn *consumer) +{ + int index = -2; + + /* If PRODUCER is a post-update insn, there is an additional one micro- + operation inserted in the end, so the last memory access operation should + be handled by this guard function and the corresponding bypass rule. */ + if (post_update_insn_p (producer)) + index = -1; + + rtx last_two_def_reg = extract_nth_access_reg (producer, index); + + if (last_two_def_reg == NULL_RTX) + return false; + + gcc_assert (REG_P (last_two_def_reg) + || GET_CODE (last_two_def_reg) == SUBREG); + + return n8_consumed_by_addr_in_p (consumer, last_two_def_reg); +} + +bool +nds32_n8_last_load_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + /* If PRODUCER is a post-update LMW insn, the last micro-operation updates + the base register and the result is ready in EX stage, so we don't need + to handle that case in this guard function and the corresponding bypass + rule. */ + if (post_update_insn_p (producer)) + return false; + + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + if (last_def_reg == NULL_RTX) + return false; + + gcc_assert (REG_P (last_def_reg) || GET_CODE (last_def_reg) == SUBREG); + + return n8_consumed_by_ex_p (consumer, last_def_reg); +} + +/* Guard functions for E8 cores. */ + +bool +nds32_e8_load_to_ii_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg = SET_DEST (PATTERN (producer)); + + return e8_consumed_by_addr_in_p (consumer, def_reg); +} + +bool +nds32_e8_load_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg = SET_DEST (PATTERN (producer)); + + return e8_consumed_by_ex_p (consumer, def_reg); +} + +bool +nds32_e8_ex_to_ii_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_ALU: + /* No data hazards if AGEN's input is produced by MOVI or SETHI. */ + if (GET_CODE (PATTERN (producer)) == SET) + { + rtx dest = SET_DEST (PATTERN (producer)); + rtx src = SET_SRC (PATTERN (producer)); + + if ((REG_P (dest) || GET_CODE (dest) == SUBREG) + && (GET_CODE (src) == CONST_INT || GET_CODE (src) == HIGH)) + return false; + } + + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_MUL: + case TYPE_MAC: + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_DIV: + if (divmod_p (producer)) + { + rtx def_reg1 = SET_DEST (parallel_element (producer, 0)); + rtx def_reg2 = SET_DEST (parallel_element (producer, 1)); + + return (e8_consumed_by_addr_in_p (consumer, def_reg1) + || e8_consumed_by_addr_in_p (consumer, def_reg2)); + } + + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_LOAD: + case TYPE_STORE: + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + if (!post_update_insn_p (producer)) + return false; + + def_reg = extract_base_reg (producer); + break; + + default: + gcc_unreachable (); + } + + return e8_consumed_by_addr_in_p (consumer, def_reg); +} + +bool +nds32_e8_last_load_to_ii_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + if (last_def_reg == NULL_RTX) + return false; + + gcc_assert (REG_P (last_def_reg) || GET_CODE (last_def_reg) == SUBREG); + + return e8_consumed_by_addr_in_p (consumer, last_def_reg); +} + +bool +nds32_e8_last_load_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + if (last_def_reg == NULL_RTX) + return false; + + gcc_assert (REG_P (last_def_reg) || GET_CODE (last_def_reg) == SUBREG); + + return e8_consumed_by_ex_p (consumer, last_def_reg); +} + +/* Guard functions for N9 cores. */ + +/* Check dependencies from MM to EX. */ +bool +nds32_n9_2r1w_mm_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + /* LD_!bi */ + case TYPE_LOAD: + if (post_update_insn_p (producer)) + return false; + + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_MUL: + case TYPE_MAC: + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return n9_2r1w_consumed_by_ex_dep_p (consumer, def_reg); +} + +/* Check dependencies from MM to EX. */ +bool +nds32_n9_3r2w_mm_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_LOAD: + case TYPE_MUL: + case TYPE_MAC: + def_reg = SET_DEST (PATTERN (producer)); + break; + + /* Some special instructions, divmodsi4 and udivmodsi4, produce two + results, the quotient and the remainder. We have to handle them + individually. */ + case TYPE_DIV: + if (divmod_p (producer)) + { + rtx def_reg1 = SET_DEST (parallel_element (producer, 0)); + rtx def_reg2 = SET_DEST (parallel_element (producer, 1)); + + return (n9_3r2w_consumed_by_ex_dep_p (consumer, def_reg1) + || n9_3r2w_consumed_by_ex_dep_p (consumer, def_reg2)); + } + + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return n9_3r2w_consumed_by_ex_dep_p (consumer, def_reg); +} + +/* Check dependencies from LMW(N, N) to EX. */ +bool +nds32_n9_last_load_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + if (nds32_register_ports_config == REG_PORT_2R1W) + { + /* The base-update micro operation occupies the last cycle. */ + if (post_update_insn_p (producer)) + return false; + + /* When the base register is in the list of a load multiple insn and the + access order of the base register is not the last one, we need an + additional micro operation to commit the load result to the base + register -- we can treat the base register as the last defined + register. */ + size_t i; + size_t n_elems = parallel_elements (producer); + rtx base_reg = extract_base_reg (producer); + + for (i = 0; i < n_elems; ++i) + { + rtx load_rtx = extract_nth_access_rtx (producer, i); + rtx list_element = SET_DEST (load_rtx); + + if (rtx_equal_p (base_reg, list_element) && i != n_elems - 1) + { + last_def_reg = base_reg; + break; + } + } + + return n9_2r1w_consumed_by_ex_dep_p (consumer, last_def_reg); + } + else + return n9_3r2w_consumed_by_ex_dep_p (consumer, last_def_reg); +} + +/* Guard functions for N10 cores. */ + +/* Check dependencies from EX to EX (ADDR_OUT -> ADDR_IN). */ +bool +nds32_n10_ex_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + gcc_assert (get_attr_type (producer) == TYPE_FLOAD + || get_attr_type (producer) == TYPE_FSTORE); + gcc_assert (get_attr_type (consumer) == TYPE_FLOAD + || get_attr_type (consumer) == TYPE_FSTORE); + + if (!post_update_insn_p (producer)) + return false; + + return reg_overlap_p (extract_base_reg (producer), + extract_mem_rtx (consumer)); +} + +/* Check dependencies from MM to EX. */ +bool +nds32_n10_mm_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_LOAD: + case TYPE_MUL: + case TYPE_MAC: + case TYPE_DALU64: + case TYPE_DMUL: + case TYPE_DMAC: + case TYPE_DALUROUND: + case TYPE_DBPICK: + case TYPE_DWEXT: + def_reg = SET_DEST (PATTERN (producer)); + break; + + /* Some special instructions, divmodsi4 and udivmodsi4, produce two + results, the quotient and the remainder. We have to handle them + individually. */ + case TYPE_DIV: + if (divmod_p (producer)) + { + rtx def_reg1 = SET_DEST (parallel_element (producer, 0)); + rtx def_reg2 = SET_DEST (parallel_element (producer, 1)); + + return (n10_consumed_by_ex_dep_p (consumer, def_reg1) + || n10_consumed_by_ex_dep_p (consumer, def_reg2)); + } + + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return n10_consumed_by_ex_dep_p (consumer, def_reg); +} + +/* Check dependencies from LMW(N, N) to EX. */ +bool +nds32_n10_last_load_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + return n10_consumed_by_ex_dep_p (consumer, last_def_reg); +} + +/* Guard functions for Graywolf cores. */ + +/* Check dependencies from EX to EX (ADDR_OUT -> ADDR_IN). */ +bool +nds32_gw_ex_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + return nds32_n10_ex_to_ex_p (producer, consumer); +} + +/* Check dependencies from MM to EX. */ +bool +nds32_gw_mm_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_LOAD: + case TYPE_MUL: + case TYPE_MAC: + case TYPE_DALU64: + case TYPE_DMUL: + case TYPE_DMAC: + case TYPE_DALUROUND: + case TYPE_DBPICK: + case TYPE_DWEXT: + def_reg = SET_DEST (PATTERN (producer)); + break; + + /* Some special instructions, divmodsi4 and udivmodsi4, produce two + results, the quotient and the remainder. We have to handle them + individually. */ + case TYPE_DIV: + if (divmod_p (producer)) + { + rtx def_reg1 = SET_DEST (parallel_element (producer, 0)); + rtx def_reg2 = SET_DEST (parallel_element (producer, 1)); + + return (gw_consumed_by_ex_dep_p (consumer, def_reg1) + || gw_consumed_by_ex_dep_p (consumer, def_reg2)); + } + + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return gw_consumed_by_ex_dep_p (consumer, def_reg); +} + +/* Check dependencies from LMW(N, N) to EX. */ +bool +nds32_gw_last_load_to_ex_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + return gw_consumed_by_ex_dep_p (consumer, last_def_reg); +} + +/* Guard functions for N12/N13 cores. */ + +/* Check dependencies from E2 to E1. */ +bool +nds32_n13_e2_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + /* Only post-update load/store instructions are considered. These + instructions produces address output at E2. */ + case TYPE_LOAD: + case TYPE_STORE: + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + if (!post_update_insn_p (producer)) + return false; + + def_reg = extract_base_reg (producer); + break; + + case TYPE_ALU: + case TYPE_ALU_SHIFT: + case TYPE_PBSAD: + case TYPE_PBSADA: + case TYPE_MUL: + case TYPE_MAC: + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_BRANCH: + return true; + + case TYPE_DIV: + /* Some special instructions, divmodsi4 and udivmodsi4, produce two + results, the quotient and the remainder. We have to handle them + individually. */ + if (divmod_p (producer)) + { + rtx def_reg1 = SET_DEST (parallel_element (producer, 0)); + rtx def_reg2 = SET_DEST (parallel_element (producer, 1)); + + return (n13_consumed_by_e1_dep_p (consumer, def_reg1) + || n13_consumed_by_e1_dep_p (consumer, def_reg2)); + } + + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return n13_consumed_by_e1_dep_p (consumer, def_reg); +} + +/* Check dependencies from Load-Store Unit (E3) to E1. */ +bool +nds32_n13_load_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg = SET_DEST (PATTERN (producer)); + + gcc_assert (get_attr_type (producer) == TYPE_LOAD); + gcc_assert (REG_P (def_reg) || GET_CODE (def_reg) == SUBREG); + + return n13_consumed_by_e1_dep_p (consumer, def_reg); +} + +/* Check dependencies from Load-Store Unit (E3) to E2. */ +bool +nds32_n13_load_to_e2_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg = SET_DEST (PATTERN (producer)); + + gcc_assert (get_attr_type (producer) == TYPE_LOAD); + gcc_assert (REG_P (def_reg) || GET_CODE (def_reg) == SUBREG); + + return n13_consumed_by_e2_dep_p (consumer, def_reg); +} + +/* Check dependencies from LMW(N, N) to E1. */ +bool +nds32_n13_last_load_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + return n13_consumed_by_e1_dep_p (consumer, last_def_reg); +} + +/* Check dependencies from LMW(N, N) to E2. */ +bool +nds32_n13_last_load_to_e2_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + return n13_consumed_by_e2_dep_p (consumer, last_def_reg); +} + +/* Check dependencies from LMW(N, N-1) to E2. */ +bool +nds32_n13_last_two_load_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_two_def_reg = extract_nth_access_reg (producer, -2); + + if (last_two_def_reg == NULL_RTX) + return false; + + return n13_consumed_by_e1_dep_p (consumer, last_two_def_reg); +} + +/* Guard functions for Panther cores. */ + +/* Check dependencies from E2 to E1. */ +bool +nds32_pn_e2_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_ALU: + gcc_assert (get_attr_subtype (producer) == SUBTYPE_SHIFT); + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return pn_consumed_by_e1_dep_p (consumer, def_reg); +} + +/* Check dependencies from E3 to E1. */ +bool +nds32_pn_e3_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_ALU: + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return pn_consumed_by_e1_dep_p (consumer, def_reg); +} + +/* Check dependencies from E3 to E2. */ +bool +nds32_pn_e3_to_e2_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_ALU: + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return pn_consumed_by_e2_dep_p (consumer, def_reg); +} + +/* Check dependencies from E4 to E1. */ +bool +nds32_pn_e4_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_MUL: + case TYPE_MAC: + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_DIV: + if (divmod_p (producer)) + { + rtx def_reg1 = SET_DEST (parallel_element (producer, 0)); + rtx def_reg2 = SET_DEST (parallel_element (producer, 1)); + + return (pn_consumed_by_e1_dep_p (consumer, def_reg1) + || pn_consumed_by_e1_dep_p (consumer, def_reg2)); + } + + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_LOAD: + if (post_update_insn_p (producer) + && pn_consumed_by_e1_dep_p (consumer, extract_base_reg (producer))) + return true; + + if (!load_full_word_p (producer)) + return false; + + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_STORE: + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + if (!post_update_insn_p (producer)) + return false; + + def_reg = extract_base_reg (producer); + break; + + default: + gcc_unreachable (); + } + + return pn_consumed_by_e1_dep_p (consumer, def_reg); +} + +/* Check dependencies from E4 to E2. */ +bool +nds32_pn_e4_to_e2_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_MUL: + case TYPE_MAC: + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_DIV: + if (divmod_p (producer)) + { + rtx def_reg1 = SET_DEST (parallel_element (producer, 0)); + rtx def_reg2 = SET_DEST (parallel_element (producer, 1)); + + return (pn_consumed_by_e2_dep_p (consumer, def_reg1) + || pn_consumed_by_e2_dep_p (consumer, def_reg2)); + } + + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_LOAD: + if (post_update_insn_p (producer) + && pn_consumed_by_e2_dep_p (consumer, extract_base_reg (producer))) + return true; + + if (!load_full_word_p (producer)) + return false; + + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_STORE: + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + if (!post_update_insn_p (producer)) + return false; + + def_reg = extract_base_reg (producer); + break; + + default: + gcc_unreachable (); + } + + return pn_consumed_by_e2_dep_p (consumer, def_reg); +} + +/* Check dependencies from E4 to E3. */ +bool +nds32_pn_e4_to_e3_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_MUL: + case TYPE_MAC: + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_DIV: + if (divmod_p (producer)) + { + rtx def_reg1 = SET_DEST (parallel_element (producer, 0)); + rtx def_reg2 = SET_DEST (parallel_element (producer, 1)); + + return (pn_consumed_by_e3_dep_p (consumer, def_reg1) + || pn_consumed_by_e3_dep_p (consumer, def_reg2)); + } + + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_LOAD: + if (post_update_insn_p (producer) + && pn_consumed_by_e3_dep_p (consumer, extract_base_reg (producer))) + return true; + + if (load_partial_word_p (producer)) + return false; + + def_reg = SET_DEST (PATTERN (producer)); + break; + + case TYPE_STORE: + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + if (!post_update_insn_p (producer)) + return false; + + def_reg = extract_base_reg (producer); + break; + + default: + gcc_unreachable (); + } + + return pn_consumed_by_e3_dep_p (consumer, def_reg); +} + +/* Check dependencies from WB to E1. */ +bool +nds32_pn_wb_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_LOAD: + if (!load_partial_word_p (producer)) + return false; + + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return pn_consumed_by_e1_dep_p (consumer, def_reg); +} + +/* Check dependencies from WB to E2. */ +bool +nds32_pn_wb_to_e2_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_LOAD: + if (!load_partial_word_p (producer)) + return false; + + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return pn_consumed_by_e2_dep_p (consumer, def_reg); +} + +/* Check dependencies from WB to E3. */ +bool +nds32_pn_wb_to_e3_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_LOAD: + if (!load_partial_word_p (producer)) + return false; + + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return pn_consumed_by_e3_dep_p (consumer, def_reg); +} + +/* Check dependencies from WB to E4. */ +bool +nds32_pn_wb_to_e4_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx def_reg; + + switch (get_attr_type (producer)) + { + case TYPE_LOAD: + if (!load_partial_word_p (producer)) + return false; + + def_reg = SET_DEST (PATTERN (producer)); + break; + + default: + gcc_unreachable (); + } + + return pn_consumed_by_e4_dep_p (consumer, def_reg); +} + +/* Check dependencies from LMW(N, N) to E1. */ +bool +nds32_pn_last_load_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + return pn_consumed_by_e1_dep_p (consumer, last_def_reg); +} + +/* Check dependencies from LMW(N, N) to E2. */ +bool +nds32_pn_last_load_to_e2_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + return pn_consumed_by_e2_dep_p (consumer, last_def_reg); +} + +/* Check dependencies from LMW(N, N) to E3. */ +bool +nds32_pn_last_load_to_e3_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_def_reg = extract_nth_access_reg (producer, -1); + + return pn_consumed_by_e3_dep_p (consumer, last_def_reg); +} + +/* Check dependencies from LMW(N, N - 1) to E1. */ +bool +nds32_pn_last_two_load_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_two_def_reg = extract_nth_access_reg (producer, -2); + + if (last_two_def_reg == NULL_RTX) + return false; + + return pn_consumed_by_e1_dep_p (consumer, last_two_def_reg); +} + +/* Check dependencies from LMW(N, N - 1) to E2. */ +bool +nds32_pn_last_two_load_to_e2_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_two_def_reg = extract_nth_access_reg (producer, -2); + + if (last_two_def_reg == NULL_RTX) + return false; + + return pn_consumed_by_e2_dep_p (consumer, last_two_def_reg); +} + +/* Check dependencies from LMW(N, N - 2) to E1. */ +bool +nds32_pn_last_three_load_to_e1_p (rtx_insn *producer, rtx_insn *consumer) +{ + rtx last_three_def_reg = extract_nth_access_reg (producer, -3); + + if (last_three_def_reg == NULL_RTX) + return false; + + return pn_consumed_by_e1_dep_p (consumer, last_three_def_reg); +} /* ------------------------------------------------------------------------ */ diff --git a/gcc/config/nds32/nds32-predicates.c b/gcc/config/nds32/nds32-predicates.c index 361d001..b45d3e6 100644 --- a/gcc/config/nds32/nds32-predicates.c +++ b/gcc/config/nds32/nds32-predicates.c @@ -24,14 +24,41 @@ #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" /* ------------------------------------------------------------------------ */ @@ -98,21 +125,33 @@ nds32_consecutive_registers_load_store_p (rtx op, We have to extract reg and mem of every element and check if the information is valid for multiple load/store operation. */ bool -nds32_valid_multiple_load_store (rtx op, bool load_p) +nds32_valid_multiple_load_store_p (rtx op, bool load_p, bool bim_p) { int count; int first_elt_regno; + int update_base_elt_idx; + int offset; rtx elt; + rtx update_base; - /* Get the counts of elements in the parallel rtx. */ - count = XVECLEN (op, 0); - /* Pick up the first element. */ - elt = XVECEXP (op, 0, 0); + /* Get the counts of elements in the parallel rtx. + Last one is update base register if bim_p. + and pick up the first element. */ + if (bim_p) + { + count = XVECLEN (op, 0) - 1; + elt = XVECEXP (op, 0, 1); + } + else + { + count = XVECLEN (op, 0); + elt = XVECEXP (op, 0, 0); + } /* Perform some quick check for the first element in the parallel rtx. */ if (GET_CODE (elt) != SET || count <= 1 - || count > 8) + || count > 25) return false; /* Pick up regno of first element for further detail checking. @@ -138,11 +177,29 @@ nds32_valid_multiple_load_store (rtx op, bool load_p) Refer to nds32-multiple.md for more information about following checking. The starting element of parallel rtx is index 0. */ - if (!nds32_consecutive_registers_load_store_p (op, load_p, 0, + if (!nds32_consecutive_registers_load_store_p (op, load_p, bim_p ? 1 : 0, first_elt_regno, count)) return false; + if (bim_p) + { + update_base_elt_idx = 0; + update_base = XVECEXP (op, 0, update_base_elt_idx); + if (!REG_P (SET_DEST (update_base))) + return false; + if (GET_CODE (SET_SRC (update_base)) != PLUS) + return false; + else + { + offset = count * UNITS_PER_WORD; + elt = XEXP (SET_SRC (update_base), 1); + if (GET_CODE (elt) != CONST_INT + || (INTVAL (elt) != offset)) + return false; + } + } + /* Pass all test, this is a valid rtx. */ return true; } @@ -174,47 +231,47 @@ nds32_valid_stack_push_pop_p (rtx op, bool push_p) { elt = XVECEXP (op, 0, index); if (GET_CODE (elt) != SET) - return false; + return false; } /* For push operation, the parallel rtx looks like: (parallel [(set (mem (plus (reg:SI SP_REGNUM) (const_int -32))) - (reg:SI Rb)) - (set (mem (plus (reg:SI SP_REGNUM) (const_int -28))) - (reg:SI Rb+1)) - ... - (set (mem (plus (reg:SI SP_REGNUM) (const_int -16))) - (reg:SI Re)) - (set (mem (plus (reg:SI SP_REGNUM) (const_int -12))) - (reg:SI FP_REGNUM)) - (set (mem (plus (reg:SI SP_REGNUM) (const_int -8))) - (reg:SI GP_REGNUM)) - (set (mem (plus (reg:SI SP_REGNUM) (const_int -4))) - (reg:SI LP_REGNUM)) - (set (reg:SI SP_REGNUM) - (plus (reg:SI SP_REGNUM) (const_int -32)))]) + (reg:SI Rb)) + (set (mem (plus (reg:SI SP_REGNUM) (const_int -28))) + (reg:SI Rb+1)) + ... + (set (mem (plus (reg:SI SP_REGNUM) (const_int -16))) + (reg:SI Re)) + (set (mem (plus (reg:SI SP_REGNUM) (const_int -12))) + (reg:SI FP_REGNUM)) + (set (mem (plus (reg:SI SP_REGNUM) (const_int -8))) + (reg:SI GP_REGNUM)) + (set (mem (plus (reg:SI SP_REGNUM) (const_int -4))) + (reg:SI LP_REGNUM)) + (set (reg:SI SP_REGNUM) + (plus (reg:SI SP_REGNUM) (const_int -32)))]) For pop operation, the parallel rtx looks like: (parallel [(set (reg:SI Rb) - (mem (reg:SI SP_REGNUM))) - (set (reg:SI Rb+1) - (mem (plus (reg:SI SP_REGNUM) (const_int 4)))) - ... - (set (reg:SI Re) - (mem (plus (reg:SI SP_REGNUM) (const_int 16)))) - (set (reg:SI FP_REGNUM) - (mem (plus (reg:SI SP_REGNUM) (const_int 20)))) - (set (reg:SI GP_REGNUM) - (mem (plus (reg:SI SP_REGNUM) (const_int 24)))) - (set (reg:SI LP_REGNUM) - (mem (plus (reg:SI SP_REGNUM) (const_int 28)))) - (set (reg:SI SP_REGNUM) - (plus (reg:SI SP_REGNUM) (const_int 32)))]) */ + (mem (reg:SI SP_REGNUM))) + (set (reg:SI Rb+1) + (mem (plus (reg:SI SP_REGNUM) (const_int 4)))) + ... + (set (reg:SI Re) + (mem (plus (reg:SI SP_REGNUM) (const_int 16)))) + (set (reg:SI FP_REGNUM) + (mem (plus (reg:SI SP_REGNUM) (const_int 20)))) + (set (reg:SI GP_REGNUM) + (mem (plus (reg:SI SP_REGNUM) (const_int 24)))) + (set (reg:SI LP_REGNUM) + (mem (plus (reg:SI SP_REGNUM) (const_int 28)))) + (set (reg:SI SP_REGNUM) + (plus (reg:SI SP_REGNUM) (const_int 32)))]) */ /* 1. Consecutive registers push/pop operations. - We need to calculate how many registers should be consecutive. - The $sp adjustment rtx, $fp push rtx, $gp push rtx, - and $lp push rtx are excluded. */ + We need to calculate how many registers should be consecutive. + The $sp adjustment rtx, $fp push rtx, $gp push rtx, + and $lp push rtx are excluded. */ /* Detect whether we have $fp, $gp, or $lp in the parallel rtx. */ save_fp = reg_mentioned_p (gen_rtx_REG (SImode, FP_REGNUM), op); @@ -238,19 +295,19 @@ nds32_valid_stack_push_pop_p (rtx op, bool push_p) first_regno = REGNO (elt_reg); /* The 'push' operation is a kind of store operation. - The 'pop' operation is a kind of load operation. - Pass corresponding false/true as second argument (bool load_p). - The par_index is supposed to start with index 0. */ + The 'pop' operation is a kind of load operation. + Pass corresponding false/true as second argument (bool load_p). + The par_index is supposed to start with index 0. */ if (!nds32_consecutive_registers_load_store_p (op, !push_p ? true : false, 0, first_regno, rest_count)) - return false; + return false; } /* 2. Valid $fp/$gp/$lp push/pop operations. - Remember to set start index for checking them. */ + Remember to set start index for checking them. */ /* The rest_count is the start index for checking $fp/$gp/$lp. */ index = rest_count; @@ -269,9 +326,9 @@ nds32_valid_stack_push_pop_p (rtx op, bool push_p) index++; if (GET_CODE (elt_mem) != MEM - || GET_CODE (elt_reg) != REG - || REGNO (elt_reg) != FP_REGNUM) - return false; + || GET_CODE (elt_reg) != REG + || REGNO (elt_reg) != FP_REGNUM) + return false; } if (save_gp) { @@ -281,9 +338,9 @@ nds32_valid_stack_push_pop_p (rtx op, bool push_p) index++; if (GET_CODE (elt_mem) != MEM - || GET_CODE (elt_reg) != REG - || REGNO (elt_reg) != GP_REGNUM) - return false; + || GET_CODE (elt_reg) != REG + || REGNO (elt_reg) != GP_REGNUM) + return false; } if (save_lp) { @@ -293,16 +350,16 @@ nds32_valid_stack_push_pop_p (rtx op, bool push_p) index++; if (GET_CODE (elt_mem) != MEM - || GET_CODE (elt_reg) != REG - || REGNO (elt_reg) != LP_REGNUM) - return false; + || GET_CODE (elt_reg) != REG + || REGNO (elt_reg) != LP_REGNUM) + return false; } /* 3. The last element must be stack adjustment rtx. - Its form of rtx should be: - (set (reg:SI SP_REGNUM) - (plus (reg:SI SP_REGNUM) (const_int X))) - The X could be positive or negative value. */ + Its form of rtx should be: + (set (reg:SI SP_REGNUM) + (plus (reg:SI SP_REGNUM) (const_int X))) + The X could be positive or negative value. */ /* Pick up the last element. */ elt = XVECEXP (op, 0, total_count - 1); @@ -322,54 +379,57 @@ nds32_valid_stack_push_pop_p (rtx op, bool push_p) } /* Function to check if 'bclr' instruction can be used with IVAL. */ -int -nds32_can_use_bclr_p (int ival) +bool +nds32_can_use_bclr_p (HOST_WIDE_INT ival) { int one_bit_count; + unsigned HOST_WIDE_INT mask = GET_MODE_MASK (SImode); /* Calculate the number of 1-bit of (~ival), if there is only one 1-bit, it means the original ival has only one 0-bit, So it is ok to perform 'bclr' operation. */ - one_bit_count = popcount_hwi ((unsigned HOST_WIDE_INT) (~ival)); + one_bit_count = popcount_hwi ((unsigned HOST_WIDE_INT) (~ival) & mask); /* 'bclr' is a performance extension instruction. */ - return (TARGET_PERF_EXT && (one_bit_count == 1)); + return (TARGET_EXT_PERF && (one_bit_count == 1)); } /* Function to check if 'bset' instruction can be used with IVAL. */ -int -nds32_can_use_bset_p (int ival) +bool +nds32_can_use_bset_p (HOST_WIDE_INT ival) { int one_bit_count; + unsigned HOST_WIDE_INT mask = GET_MODE_MASK (SImode); /* Caculate the number of 1-bit of ival, if there is only one 1-bit, it is ok to perform 'bset' operation. */ - one_bit_count = popcount_hwi ((unsigned HOST_WIDE_INT) (ival)); + one_bit_count = popcount_hwi ((unsigned HOST_WIDE_INT) (ival) & mask); /* 'bset' is a performance extension instruction. */ - return (TARGET_PERF_EXT && (one_bit_count == 1)); + return (TARGET_EXT_PERF && (one_bit_count == 1)); } /* Function to check if 'btgl' instruction can be used with IVAL. */ -int -nds32_can_use_btgl_p (int ival) +bool +nds32_can_use_btgl_p (HOST_WIDE_INT ival) { int one_bit_count; + unsigned HOST_WIDE_INT mask = GET_MODE_MASK (SImode); /* Caculate the number of 1-bit of ival, if there is only one 1-bit, it is ok to perform 'btgl' operation. */ - one_bit_count = popcount_hwi ((unsigned HOST_WIDE_INT) (ival)); + one_bit_count = popcount_hwi ((unsigned HOST_WIDE_INT) (ival) & mask); /* 'btgl' is a performance extension instruction. */ - return (TARGET_PERF_EXT && (one_bit_count == 1)); + return (TARGET_EXT_PERF && (one_bit_count == 1)); } /* Function to check if 'bitci' instruction can be used with IVAL. */ -int -nds32_can_use_bitci_p (int ival) +bool +nds32_can_use_bitci_p (HOST_WIDE_INT ival) { /* If we are using V3 ISA, we have 'bitci' instruction. Try to see if we can present 'andi' semantic with @@ -381,4 +441,286 @@ nds32_can_use_bitci_p (int ival) && satisfies_constraint_Iu15 (gen_int_mode (~ival, SImode))); } +/* Return true if is load/store with SYMBOL_REF addressing mode + and memory mode is SImode. */ +bool +nds32_symbol_load_store_p (rtx_insn *insn) +{ + rtx mem_src = NULL_RTX; + + switch (get_attr_type (insn)) + { + case TYPE_LOAD: + mem_src = SET_SRC (PATTERN (insn)); + break; + case TYPE_STORE: + mem_src = SET_DEST (PATTERN (insn)); + break; + default: + break; + } + + /* Find load/store insn with addressing mode is SYMBOL_REF. */ + if (mem_src != NULL_RTX) + { + if ((GET_CODE (mem_src) == ZERO_EXTEND) + || (GET_CODE (mem_src) == SIGN_EXTEND)) + mem_src = XEXP (mem_src, 0); + + if ((GET_CODE (XEXP (mem_src, 0)) == SYMBOL_REF) + || (GET_CODE (XEXP (mem_src, 0)) == LO_SUM)) + return true; + } + + return false; +} + +/* Vaild memory operand for floating-point loads and stores */ +bool +nds32_float_mem_operand_p (rtx op) +{ + enum machine_mode mode = GET_MODE (op); + rtx addr = XEXP (op, 0); + + /* Not support [symbol] [const] memory */ + if (GET_CODE (addr) == SYMBOL_REF + || GET_CODE (addr) == CONST + || GET_CODE (addr) == LO_SUM) + return false; + + if (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == SYMBOL_REF) + return false; + + /* Restrict const range: (imm12s << 2) */ + if (GET_CODE (XEXP (addr, 1)) == CONST_INT) + { + if ((mode == SImode || mode == SFmode) + && NDS32_SINGLE_WORD_ALIGN_P (INTVAL (XEXP (addr, 1))) + && !satisfies_constraint_Is14 ( XEXP(addr, 1))) + return false; + + if ((mode == DImode || mode == DFmode) + && NDS32_DOUBLE_WORD_ALIGN_P (INTVAL (XEXP (addr, 1))) + && !satisfies_constraint_Is14 (XEXP (addr, 1))) + return false; + } + } + + return true; +} + +int +nds32_cond_move_p (rtx cmp_rtx) +{ + enum machine_mode cmp0_mode = GET_MODE (XEXP (cmp_rtx, 0)); + enum machine_mode cmp1_mode = GET_MODE (XEXP (cmp_rtx, 1)); + enum rtx_code cond = GET_CODE (cmp_rtx); + + if ((cmp0_mode == DFmode || cmp0_mode == SFmode) + && (cmp1_mode == DFmode || cmp1_mode == SFmode) + && (cond == ORDERED || cond == UNORDERED)) + return true; + return false; +} + +/* Return true if the addresses in mem1 and mem2 are suitable for use in + an fldi or fsdi instruction. + + This can only happen when addr1 and addr2, the addresses in mem1 + and mem2, are consecutive memory locations (addr1 + 4 == addr2). + addr1 must also be aligned on a 64-bit boundary. */ +bool +nds32_memory_merge_peep_p (rtx mem1, rtx mem2) +{ + rtx addr1, addr2; + unsigned int reg1; + HOST_WIDE_INT offset1; + + /* The mems cannot be volatile. */ + if (MEM_VOLATILE_P (mem1) || MEM_VOLATILE_P (mem2)) + return false; + + /* MEM1 should be aligned on a 64-bit boundary. */ + if (MEM_ALIGN (mem1) < 64) + return false; + + addr1 = XEXP (mem1, 0); + addr2 = XEXP (mem2, 0); + + /* Extract a register number and offset (if used) from the first addr. */ + if (GET_CODE (addr1) == PLUS) + { + if (GET_CODE (XEXP (addr1, 0)) != REG) + return false; + else + { + reg1 = REGNO (XEXP (addr1, 0)); + if (GET_CODE (XEXP (addr1, 1)) != CONST_INT) + return false; + + offset1 = INTVAL (XEXP (addr1, 1)); + } + } + else if (GET_CODE (addr1) != REG) + return false; + else + { + reg1 = REGNO (addr1); + /* This was a simple (mem (reg)) expression. Offset is 0. */ + offset1 = 0; + } + /* Make sure the second address is a (mem (plus (reg) (const_int). */ + if (GET_CODE (addr2) != PLUS) + return false; + + if (GET_CODE (XEXP (addr2, 0)) != REG + || GET_CODE (XEXP (addr2, 1)) != CONST_INT) + return false; + + if (reg1 != REGNO (XEXP (addr2, 0))) + return false; + + /* The first offset must be evenly divisible by 8 to ensure the + address is 64 bit aligned. */ + if (offset1 % 8 != 0) + return false; + + /* The offset for the second addr must be 4 more than the first addr. */ + if (INTVAL (XEXP (addr2, 1)) != offset1 + 4) + return false; + + return true; +} + +bool +nds32_const_double_range_ok_p (rtx op, enum machine_mode mode, + HOST_WIDE_INT lower, HOST_WIDE_INT upper) +{ + if (GET_CODE (op) != CONST_DOUBLE + || GET_MODE (op) != mode) + return false; + + const REAL_VALUE_TYPE *rv; + long val; + + rv = CONST_DOUBLE_REAL_VALUE (op); + REAL_VALUE_TO_TARGET_SINGLE (*rv, val); + + return val >= lower && val < upper; +} + +bool +nds32_const_unspec_p (rtx x) +{ + if (GET_CODE (x) == CONST) + { + x = XEXP (x, 0); + + if (GET_CODE (x) == PLUS) + x = XEXP (x, 0); + + if (GET_CODE (x) == UNSPEC) + { + switch (XINT (x, 1)) + { + case UNSPEC_GOTINIT: + case UNSPEC_GOT: + case UNSPEC_GOTOFF: + case UNSPEC_PLT: + case UNSPEC_TLSGD: + case UNSPEC_TLSLD: + case UNSPEC_TLSIE: + case UNSPEC_TLSLE: + return false; + default: + return true; + } + } + } + + if (GET_CODE (x) == SYMBOL_REF + && SYMBOL_REF_TLS_MODEL (x)) + return false; + + return true; +} + +HOST_WIDE_INT +const_vector_to_hwint (rtx op) +{ + HOST_WIDE_INT hwint = 0; + HOST_WIDE_INT mask; + int i; + int shift_adv; + int shift = 0; + int nelem; + + switch (GET_MODE (op)) + { + case V2HImode: + mask = 0xffff; + shift_adv = 16; + nelem = 2; + break; + case V4QImode: + mask = 0xff; + shift_adv = 8; + nelem = 4; + break; + default: + gcc_unreachable (); + } + + if (TARGET_BIG_ENDIAN) + { + for (i = 0; i < nelem; ++i) + { + HOST_WIDE_INT val = XINT (XVECEXP (op, 0, nelem - i - 1), 0); + hwint |= (val & mask) << shift; + shift = shift + shift_adv; + } + } + else + { + for (i = 0; i < nelem; ++i) + { + HOST_WIDE_INT val = XINT (XVECEXP (op, 0, i), 0); + hwint |= (val & mask) << shift; + shift = shift + shift_adv; + } + } + + return hwint; +} + +bool +nds32_valid_CVp5_p (rtx op) +{ + HOST_WIDE_INT ival = const_vector_to_hwint (op); + return (ival < ((1 << 5) + 16)) && (ival >= (0 + 16)); +} + +bool +nds32_valid_CVs5_p (rtx op) +{ + HOST_WIDE_INT ival = const_vector_to_hwint (op); + return (ival < (1 << 4)) && (ival >= -(1 << 4)); +} + +bool +nds32_valid_CVs2_p (rtx op) +{ + HOST_WIDE_INT ival = const_vector_to_hwint (op); + return (ival < (1 << 19)) && (ival >= -(1 << 19)); +} + +bool +nds32_valid_CVhi_p (rtx op) +{ + HOST_WIDE_INT ival = const_vector_to_hwint (op); + return (ival != 0) && ((ival & 0xfff) == 0); +} + /* ------------------------------------------------------------------------ */ diff --git a/gcc/config/nds32/nds32-protos.h b/gcc/config/nds32/nds32-protos.h index d66749d..19e69e3 100644 --- a/gcc/config/nds32/nds32-protos.h +++ b/gcc/config/nds32/nds32-protos.h @@ -28,10 +28,14 @@ extern void nds32_init_expanders (void); /* Register Usage. */ +/* -- Order of Allocation of Registers. */ +extern void nds32_adjust_reg_alloc_order (void); + /* -- How Values Fit in Registers. */ -extern int nds32_hard_regno_nregs (int, machine_mode); -extern int nds32_hard_regno_mode_ok (int, machine_mode); +extern int nds32_hard_regno_nregs (int, enum machine_mode); +extern int nds32_hard_regno_mode_ok (int, enum machine_mode); +extern int nds32_modes_tieable_p (enum machine_mode, enum machine_mode); /* Register Classes. */ @@ -43,6 +47,7 @@ extern enum reg_class nds32_regno_reg_class (int); /* -- Basic Stack Layout. */ +extern rtx nds32_dynamic_chain_address (rtx); extern rtx nds32_return_addr_rtx (int, rtx); /* -- Eliminating Frame Pointer and Arg Pointer. */ @@ -61,22 +66,88 @@ extern void nds32_expand_prologue (void); extern void nds32_expand_epilogue (bool); extern void nds32_expand_prologue_v3push (void); extern void nds32_expand_epilogue_v3pop (bool); +extern void nds32_emit_push_fpr_callee_saved (int); +extern void nds32_emit_pop_fpr_callee_saved (int); +extern void nds32_emit_v3pop_fpr_callee_saved (int); + +/* Controlling Debugging Information Format. */ + +extern unsigned int nds32_dbx_register_number (unsigned int); /* ------------------------------------------------------------------------ */ -/* Auxiliary functions for auxiliary macros in nds32.h. */ +/* Auxiliary functions for manipulation DI mode. */ -extern bool nds32_ls_333_p (rtx, rtx, rtx, machine_mode); +extern rtx nds32_di_high_part_subreg(rtx); +extern rtx nds32_di_low_part_subreg(rtx); /* Auxiliary functions for expanding rtl used in nds32-multiple.md. */ -extern rtx nds32_expand_load_multiple (int, int, rtx, rtx); -extern rtx nds32_expand_store_multiple (int, int, rtx, rtx); -extern int nds32_expand_movmemqi (rtx, rtx, rtx, rtx); +extern rtx nds32_expand_load_multiple (int, int, rtx, rtx, bool, rtx *); +extern rtx nds32_expand_store_multiple (int, int, rtx, rtx, bool, rtx *); +extern bool nds32_expand_movmemsi (rtx, rtx, rtx, rtx); +extern bool nds32_expand_setmem (rtx, rtx, rtx, rtx, rtx, rtx); +extern bool nds32_expand_movstr (rtx, rtx, rtx); +extern bool nds32_expand_strlen (rtx, rtx, rtx, rtx); /* Auxiliary functions for multiple load/store predicate checking. */ -extern bool nds32_valid_multiple_load_store (rtx, bool); +extern bool nds32_valid_multiple_load_store_p (rtx, bool, bool); + +/* Auxiliary functions for guard function checking in pipelines.md. */ + +extern bool nds32_n7_load_to_ii_p (rtx_insn *, rtx_insn *); +extern bool nds32_n7_last_load_to_ii_p (rtx_insn *, rtx_insn *); + +extern bool nds32_n8_load_to_ii_p (rtx_insn *, rtx_insn *); +extern bool nds32_n8_load_bi_to_ii_p (rtx_insn *, rtx_insn *); +extern bool nds32_n8_load_to_ex_p (rtx_insn *, rtx_insn *); +extern bool nds32_n8_ex_to_ii_p (rtx_insn *, rtx_insn *); +extern bool nds32_n8_last_load_to_ii_p (rtx_insn *, rtx_insn *); +extern bool nds32_n8_last_load_two_to_ii_p (rtx_insn *, rtx_insn *); +extern bool nds32_n8_last_load_to_ex_p (rtx_insn *, rtx_insn *); + +extern bool nds32_e8_load_to_ii_p (rtx_insn *, rtx_insn *); +extern bool nds32_e8_load_to_ex_p (rtx_insn *, rtx_insn *); +extern bool nds32_e8_ex_to_ii_p (rtx_insn *, rtx_insn *); +extern bool nds32_e8_last_load_to_ii_p (rtx_insn *, rtx_insn *); +extern bool nds32_e8_last_load_to_ex_p (rtx_insn *, rtx_insn *); + +extern bool nds32_n9_2r1w_mm_to_ex_p (rtx_insn *, rtx_insn *); +extern bool nds32_n9_3r2w_mm_to_ex_p (rtx_insn *, rtx_insn *); +extern bool nds32_n9_last_load_to_ex_p (rtx_insn *, rtx_insn *); + +extern bool nds32_n10_ex_to_ex_p (rtx_insn *, rtx_insn *); +extern bool nds32_n10_mm_to_ex_p (rtx_insn *, rtx_insn *); +extern bool nds32_n10_last_load_to_ex_p (rtx_insn *, rtx_insn *); + +extern bool nds32_gw_ex_to_ex_p (rtx_insn *, rtx_insn *); +extern bool nds32_gw_mm_to_ex_p (rtx_insn *, rtx_insn *); +extern bool nds32_gw_last_load_to_ex_p (rtx_insn *, rtx_insn *); + +extern bool nds32_n13_e2_to_e1_p (rtx_insn *, rtx_insn *); +extern bool nds32_n13_load_to_e1_p (rtx_insn *, rtx_insn *); +extern bool nds32_n13_load_to_e2_p (rtx_insn *, rtx_insn *); +extern bool nds32_n13_last_load_to_e1_p (rtx_insn *, rtx_insn *); +extern bool nds32_n13_last_load_to_e2_p (rtx_insn *, rtx_insn *); +extern bool nds32_n13_last_two_load_to_e1_p (rtx_insn *, rtx_insn *); + +extern bool nds32_pn_e2_to_e1_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_e3_to_e1_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_e3_to_e2_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_e4_to_e1_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_e4_to_e2_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_e4_to_e3_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_wb_to_e1_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_wb_to_e2_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_wb_to_e3_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_wb_to_e4_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_last_load_to_e1_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_last_load_to_e2_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_last_load_to_e3_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_last_two_load_to_e1_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_last_two_load_to_e2_p (rtx_insn *, rtx_insn *); +extern bool nds32_pn_last_three_load_to_e1_p (rtx_insn *, rtx_insn *); /* Auxiliary functions for stack operation predicate checking. */ @@ -84,55 +155,176 @@ extern bool nds32_valid_stack_push_pop_p (rtx, bool); /* Auxiliary functions for bit operation detection. */ -extern int nds32_can_use_bclr_p (int); -extern int nds32_can_use_bset_p (int); -extern int nds32_can_use_btgl_p (int); +extern bool nds32_can_use_bclr_p (HOST_WIDE_INT); +extern bool nds32_can_use_bset_p (HOST_WIDE_INT); +extern bool nds32_can_use_btgl_p (HOST_WIDE_INT); -extern int nds32_can_use_bitci_p (int); +extern bool nds32_can_use_bitci_p (HOST_WIDE_INT); -/* Auxiliary function for 'Computing the Length of an Insn'. */ +extern bool nds32_const_double_range_ok_p (rtx, enum machine_mode, + HOST_WIDE_INT, HOST_WIDE_INT); -extern int nds32_adjust_insn_length (rtx_insn *, int); +extern bool nds32_const_unspec_p (rtx x); /* Auxiliary functions for FP_AS_GP detection. */ -extern int nds32_fp_as_gp_check_available (void); +extern bool nds32_symbol_load_store_p (rtx_insn *); +extern bool nds32_naked_function_p (tree); /* Auxiliary functions for jump table generation. */ extern const char *nds32_output_casesi_pc_relative (rtx *); extern const char *nds32_output_casesi (rtx *); +/* Auxiliary functions for conditional branch generation. */ + +extern enum nds32_expand_result_type nds32_expand_cbranch (rtx *); +extern enum nds32_expand_result_type nds32_expand_cstore (rtx *); +extern void nds32_expand_float_cbranch (rtx *); +extern void nds32_expand_float_cstore (rtx *); + +/* Auxiliary functions for conditional move generation. */ + +extern enum nds32_expand_result_type nds32_expand_movcc (rtx *); +extern void nds32_expand_float_movcc (rtx *); + +/* Auxiliary functions for expand unalign load instruction. */ + +extern void nds32_expand_unaligned_load (rtx *, enum machine_mode); + +/* Auxiliary functions for expand extv/insv instruction. */ + +extern enum nds32_expand_result_type nds32_expand_extv (rtx *); +extern enum nds32_expand_result_type nds32_expand_insv (rtx *); + +/* Auxiliary functions for expand unalign store instruction. */ + +extern void nds32_expand_unaligned_store (rtx *, enum machine_mode); + +/* Auxiliary functions for expand PIC instruction. */ + +extern void nds32_expand_pic_move (rtx *); + +/* Auxiliary functions to legitimize PIC address. */ + +extern rtx nds32_legitimize_pic_address (rtx); + +/* Auxiliary functions for expand TLS instruction. */ + +extern void nds32_expand_tls_move (rtx *); + +/* Auxiliary functions to legitimize TLS address. */ + +extern rtx nds32_legitimize_tls_address (rtx); + +/* Auxiliary functions to identify thread-local symbol. */ + +extern bool nds32_tls_referenced_p (rtx); + +/* Auxiliary functions for expand ICT instruction. */ + +extern void nds32_expand_ict_move (rtx *); + +/* Auxiliary functions to legitimize address for indirect-call symbol. */ + +extern rtx nds32_legitimize_ict_address (rtx); + +/* Auxiliary functions to identify indirect-call symbol. */ + +extern bool nds32_indirect_call_referenced_p (rtx); + +/* Auxiliary functions to identify long-call symbol. */ +extern bool nds32_long_call_p (rtx); + +/* Auxiliary functions to identify SYMBOL_REF and LABEL_REF pattern. */ + +extern bool symbolic_reference_mentioned_p (rtx); + +/* Auxiliary functions to identify conditional move comparison operand. */ + +extern int nds32_cond_move_p (rtx); + +/* Auxiliary functions to identify address for peephole2 merge instruction. */ + +extern bool nds32_memory_merge_peep_p (rtx, rtx); + /* Auxiliary functions to identify 16 bit addresing mode. */ extern enum nds32_16bit_address_type nds32_mem_format (rtx); +/* Auxiliary functions to identify floating-point addresing mode. */ + +extern bool nds32_float_mem_operand_p (rtx); + /* Auxiliary functions to output assembly code. */ extern const char *nds32_output_16bit_store (rtx *, int); extern const char *nds32_output_16bit_load (rtx *, int); extern const char *nds32_output_32bit_store (rtx *, int); extern const char *nds32_output_32bit_load (rtx *, int); -extern const char *nds32_output_32bit_load_s (rtx *, int); +extern const char *nds32_output_32bit_load_se (rtx *, int); +extern const char *nds32_output_float_load(rtx *); +extern const char *nds32_output_float_store(rtx *); +extern const char *nds32_output_smw_single_word (rtx *); +extern const char *nds32_output_smw_double_word (rtx *); +extern const char *nds32_output_lmw_single_word (rtx *); +extern const char *nds32_output_double (rtx *, bool); +extern const char *nds32_output_cbranchsi4_equality_zero (rtx_insn *, rtx *); +extern const char *nds32_output_cbranchsi4_equality_reg (rtx_insn *, rtx *); +extern const char *nds32_output_cbranchsi4_equality_reg_or_const_int (rtx_insn *, + rtx *); +extern const char *nds32_output_cbranchsi4_greater_less_zero (rtx_insn *, rtx *); + +extern const char *nds32_output_unpkd8 (rtx, rtx, rtx, rtx, bool); + +extern const char *nds32_output_call (rtx, rtx *, rtx, + const char *, const char *, bool); +extern const char *nds32_output_tls_desc (rtx *); +extern const char *nds32_output_tls_ie (rtx *); /* Auxiliary functions to output stack push/pop instruction. */ extern const char *nds32_output_stack_push (rtx); extern const char *nds32_output_stack_pop (rtx); +extern const char *nds32_output_return (void); + + +/* Auxiliary functions to split/output sms pattern. */ +extern bool nds32_need_split_sms_p (rtx, rtx, rtx, rtx); +extern const char *nds32_output_sms (rtx, rtx, rtx, rtx); +extern void nds32_split_sms (rtx, rtx, rtx, rtx, rtx, rtx, rtx); + +/* Auxiliary functions to split double word RTX pattern. */ + +extern void nds32_spilt_doubleword (rtx *, bool); +extern void nds32_split_ashiftdi3 (rtx, rtx, rtx); +extern void nds32_split_ashiftrtdi3 (rtx, rtx, rtx); +extern void nds32_split_lshiftrtdi3 (rtx, rtx, rtx); +extern void nds32_split_rotatertdi3 (rtx, rtx, rtx); + +/* Auxiliary functions to split large constant RTX pattern. */ + +extern void nds32_expand_constant (enum machine_mode, + HOST_WIDE_INT, rtx, rtx); /* Auxiliary functions to check using return with null epilogue. */ extern int nds32_can_use_return_insn (void); +extern enum machine_mode nds32_case_vector_shorten_mode (int, int, rtx); /* Auxiliary functions to decide output alignment or not. */ extern int nds32_target_alignment (rtx); +extern unsigned int nds32_data_alignment (tree, unsigned int); +extern unsigned int nds32_constant_alignment (tree, unsigned int); +extern unsigned int nds32_local_alignment (tree, unsigned int); /* Auxiliary functions to expand builtin functions. */ extern void nds32_init_builtins_impl (void); extern rtx nds32_expand_builtin_impl (tree, rtx, rtx, - machine_mode, int); + enum machine_mode, int); +extern tree nds32_builtin_decl_impl (unsigned, bool); /* Auxiliary functions for ISR implementation. */ @@ -141,10 +333,86 @@ extern void nds32_construct_isr_vectors_information (tree, const char *); extern void nds32_asm_file_start_for_isr (void); extern void nds32_asm_file_end_for_isr (void); extern bool nds32_isr_function_p (tree); +extern bool nds32_isr_function_critical_p (tree); /* Auxiliary functions for cost calculation. */ +extern void nds32_init_rtx_costs (void); extern bool nds32_rtx_costs_impl (rtx, machine_mode, int, int, int *, bool); -extern int nds32_address_cost_impl (rtx, machine_mode, addr_space_t, bool); +extern int nds32_address_cost_impl (rtx, enum machine_mode, addr_space_t, bool); +extern struct register_pass_info insert_pass_fp_as_gp; + +extern int nds32_adjust_insn_length (rtx_insn *, int); + +/* Auxiliary functions for pre-define marco. */ +extern void nds32_cpu_cpp_builtins(struct cpp_reader *); + +/* Auxiliary functions for const_vector's constraints. */ + +extern HOST_WIDE_INT const_vector_to_hwint (rtx); +extern bool nds32_valid_CVp5_p (rtx); +extern bool nds32_valid_CVs5_p (rtx); +extern bool nds32_valid_CVs2_p (rtx); +extern bool nds32_valid_CVhi_p (rtx); + +/* Auxiliary functions for lwm/smw. */ + +extern bool nds32_valid_smw_lwm_base_p (rtx); + +/* Auxiliary functions for register rename pass. */ +extern reg_class_t nds32_preferred_rename_class_impl (reg_class_t); + +extern bool nds32_split_double_word_load_store_p (rtx *,bool); + +namespace nds32 { + +extern rtx extract_pattern_from_insn (rtx); + +size_t parallel_elements (rtx); +rtx parallel_element (rtx, int); + +bool insn_pseudo_nop_p (rtx_insn *); +bool insn_executable_p (rtx_insn *); +rtx_insn *prev_executable_insn (rtx_insn *); +rtx_insn *next_executable_insn (rtx_insn *); +rtx_insn *prev_executable_insn_local (rtx_insn *); +rtx_insn *next_executable_insn_local (rtx_insn *); +bool insn_deleted_p (rtx_insn *); + +bool load_single_p (rtx_insn *); +bool store_single_p (rtx_insn *); +bool load_double_p (rtx_insn *); +bool store_double_p (rtx_insn *); +bool store_offset_reg_p (rtx_insn *); +bool load_full_word_p (rtx_insn *); +bool load_partial_word_p (rtx_insn *); +bool post_update_insn_p (rtx_insn *); +bool immed_offset_p (rtx); +int find_post_update_rtx (rtx_insn *); +rtx extract_mem_rtx (rtx_insn *); +rtx extract_base_reg (rtx_insn *); +rtx extract_offset_rtx (rtx_insn *); + +rtx extract_shift_reg (rtx_insn *); + +bool movd44_insn_p (rtx_insn *); +rtx extract_movd44_even_reg (rtx_insn *); +rtx extract_movd44_odd_reg (rtx_insn *); + +rtx extract_mac_acc_rtx (rtx_insn *); +rtx extract_mac_non_acc_rtx (rtx_insn *); + +bool divmod_p (rtx_insn *); + +rtx extract_branch_target_rtx (rtx_insn *); +rtx extract_branch_condition_rtx (rtx_insn *); + +void compute_bb_for_insn_safe (); + +void exchange_insns (rtx_insn *, rtx_insn *); + +} // namespace nds32 + +extern bool nds32_include_fp_arith; /* ------------------------------------------------------------------------ */ diff --git a/gcc/config/nds32/nds32-reg-utils.c b/gcc/config/nds32/nds32-reg-utils.c new file mode 100644 index 0000000..1fd8a83 --- /dev/null +++ b/gcc/config/nds32/nds32-reg-utils.c @@ -0,0 +1,190 @@ + +/* 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 "nds32-reg-utils.h" + +#define NDS32_GPR_NUM 32 + +static bool debug_live_reg = false; + +void +nds32_live_regs (basic_block bb, rtx_insn *first, rtx_insn *last, bitmap *live) +{ + df_ref def; + rtx_insn *insn; + bitmap_copy (*live, DF_LR_IN (bb)); + df_simulate_initialize_forwards (bb, *live); + rtx_insn *first_insn = BB_HEAD (bb); + + for (insn = first_insn; insn != first; insn = NEXT_INSN (insn)) + df_simulate_one_insn_forwards (bb, insn, *live); + + if (dump_file && debug_live_reg) + { + fprintf (dump_file, "scan live regs:\nfrom:\n"); + print_rtl_single (dump_file, first); + + fprintf (dump_file, "to:\n"); + print_rtl_single (dump_file, last); + + fprintf (dump_file, "bb lr in:\n"); + dump_bitmap (dump_file, DF_LR_IN (bb)); + + fprintf (dump_file, "init:\n"); + dump_bitmap (dump_file, *live); + } + + for (insn = first; insn != last; insn = NEXT_INSN (insn)) + { + if (!INSN_P (insn)) + continue; + + FOR_EACH_INSN_DEF (def, insn) + bitmap_set_bit (*live, DF_REF_REGNO (def)); + + if (dump_file && debug_live_reg) + { + fprintf (dump_file, "scaning:\n"); + print_rtl_single (dump_file, insn); + dump_bitmap (dump_file, *live); + } + } + + gcc_assert (INSN_P (insn)); + + FOR_EACH_INSN_DEF (def, insn) + bitmap_set_bit (*live, DF_REF_REGNO (def)); + + if (dump_file && debug_live_reg) + { + fprintf (dump_file, "scaning:\n"); + print_rtl_single (dump_file, last); + dump_bitmap (dump_file, *live); + } +} + +void +print_hard_reg_set (FILE *file, const char *prefix, HARD_REG_SET set) +{ + int i; + bool first = true; + fprintf (file, "%s{ ", prefix); + + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + if (TEST_HARD_REG_BIT (set, i)) + { + if (first) + { + fprintf (file, "%s", reg_names[i]); + first = false; + } + else + fprintf (file, ", %s", reg_names[i]); + } + } + fprintf (file, "}\n"); +} + +void +nds32_get_available_reg_set (basic_block bb, + rtx_insn *first, + rtx_insn *last, + HARD_REG_SET *available_regset) +{ + bitmap live; + HARD_REG_SET live_regset; + unsigned i; + live = BITMAP_ALLOC (®_obstack); + + nds32_live_regs (bb, first, last, &live); + + REG_SET_TO_HARD_REG_SET (live_regset, live); + + /* Reverse available_regset. */ + COMPL_HARD_REG_SET (*available_regset, live_regset); + + /* We only care $r0-$r31, so mask $r0-$r31. */ + AND_HARD_REG_SET (*available_regset, reg_class_contents[GENERAL_REGS]); + + /* Fixed register also not available. */ + for (i = NDS32_FIRST_GPR_REGNUM; i <= NDS32_LAST_GPR_REGNUM; ++i) + { + if (fixed_regs[i]) + CLEAR_HARD_REG_BIT (*available_regset, i); + } + + BITMAP_FREE (live); +} diff --git a/gcc/config/nds32/nds32-reg-utils.h b/gcc/config/nds32/nds32-reg-utils.h new file mode 100644 index 0000000..16c23a3 --- /dev/null +++ b/gcc/config/nds32/nds32-reg-utils.h @@ -0,0 +1,61 @@ +/* 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_REG_UTILS_OPT_H +#define NDS32_REG_UTILS_OPT_H + +/* Auxiliary functions for register usage analysis. */ +extern void nds32_live_regs (basic_block, rtx_insn *, rtx_insn *, bitmap *); +extern void print_hard_reg_set (FILE *, const char *, HARD_REG_SET); +extern void nds32_get_available_reg_set (basic_block, rtx_insn *, + rtx_insn *, HARD_REG_SET *); + +static inline bool +in_reg_class_p (unsigned regno, enum reg_class clazz) +{ + return TEST_HARD_REG_BIT (reg_class_contents[clazz], regno); +} + +static inline bool +in_reg_class_p (rtx reg, enum reg_class clazz) +{ + gcc_assert (REG_P (reg)); + return in_reg_class_p (REGNO (reg), clazz); +} + +static inline unsigned +find_available_reg (HARD_REG_SET *available_regset, enum reg_class clazz) +{ + hard_reg_set_iterator hrsi; + unsigned regno; + EXECUTE_IF_SET_IN_HARD_REG_SET (reg_class_contents[clazz], 0, 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))) + return regno; + } + + return INVALID_REGNUM; +} + + + +#endif diff --git a/gcc/config/nds32/nds32-regrename.c b/gcc/config/nds32/nds32-regrename.c new file mode 100644 index 0000000..0875722 --- /dev/null +++ b/gcc/config/nds32/nds32-regrename.c @@ -0,0 +1,389 @@ +/* Register rename 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 "regrename.h" + +static reg_class_t current_preferred_rename_class = NO_REGS; + +reg_class_t +nds32_preferred_rename_class_impl (reg_class_t rclass) +{ + if (rclass == GENERAL_REGS) + return current_preferred_rename_class; + else + return NO_REGS; +} + +static void +print_hard_reg_set (FILE *file, HARD_REG_SET set) +{ + int i; + + fprintf (file, "{ "); + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + { + if (TEST_HARD_REG_BIT (set, i)) + fprintf (file, "%d ", i); + } + fprintf (file, "}\n"); +} + +void +dump_hard_reg_set (FILE *file, HARD_REG_SET set) +{ + print_hard_reg_set (file, set); +} + +static bool +in_reg_class_p (unsigned regno, enum reg_class clazz) +{ + return TEST_HARD_REG_BIT (reg_class_contents[clazz], regno); +} + +static unsigned +try_find_best_rename_reg (du_head_p op_chain, reg_class_t preferred_class) +{ + HARD_REG_SET unavailable; + unsigned new_reg; + current_preferred_rename_class = preferred_class; + + COMPL_HARD_REG_SET (unavailable, reg_class_contents[preferred_class]); + CLEAR_HARD_REG_BIT (unavailable, op_chain->regno); + + new_reg = find_rename_reg (op_chain, GENERAL_REGS, + &unavailable, op_chain->regno, false); + + current_preferred_rename_class = NO_REGS; + return new_reg; +} + +static bool +try_rename_operand_to (rtx insn, unsigned op_pos, + reg_class_t preferred_rename_class) +{ + insn_rr_info *info; + du_head_p op_chain; + unsigned newreg; + unsigned oldreg; + + 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; + + /* Already use preferred class, so do nothing. */ + if (TEST_HARD_REG_BIT (reg_class_contents[preferred_rename_class], + op_chain->regno)) + return false; + + if (dump_file) + { + fprintf (dump_file, "Try to rename operand %d to %s:\n", + op_pos, reg_class_names[preferred_rename_class]); + print_rtl_single (dump_file, insn); + } + + oldreg = op_chain->regno; + newreg = try_find_best_rename_reg (op_chain, preferred_rename_class); + + if (newreg == oldreg) + return false; + + regrename_do_replace (op_chain, newreg); + + if (dump_file) + { + fprintf (dump_file, "Rename operand %d to %s is Done:\n", + op_pos, reg_class_names[preferred_rename_class]); + print_rtl_single (dump_file, insn); + } + return true; +} + +static bool +rename_slt_profitlable (rtx insn) +{ + rtx pattern; + pattern = PATTERN (insn); + rtx src = SET_SRC (pattern); + rtx op0 = XEXP (src, 0); + rtx op1 = XEXP (src, 0); + + insn_rr_info *info; + du_head_p op_chain; + int op_pos = 0; + + 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 (in_reg_class_p (op_chain->regno, R15_TA_REG)) + return false; + + /* slt[s]45 need second operand in MIDDLE_REGS class. */ + if (!REG_P (op0) || !in_reg_class_p (REGNO (op0), MIDDLE_REGS)) + return false; + + /* slt[s]i45 only allow 5 bit unsigned integer. */ + if (REG_P (op1) + || (CONST_INT_P (op1) && satisfies_constraint_Iu05 (op1))) + return true; + + return false; +} + +static bool +rename_cbranch_eq0_low_reg_profitlable (rtx insn) +{ + insn_rr_info *info; + du_head_p op_chain; + int op_pos = 1; + + 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 (in_reg_class_p (op_chain->regno, LOW_REGS)) + return false; + + return true; +} + + +static bool +rename_cbranch_eq0_r15_profitlable (rtx insn) +{ + rtx pattern; + pattern = PATTERN (insn); + rtx if_then_else = SET_SRC (pattern); + rtx cond = XEXP (if_then_else, 0); + rtx op0 = XEXP (cond, 0); + + insn_rr_info *info; + du_head_p op_chain; + int op_pos = 1; + + 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 (in_reg_class_p (op_chain->regno, R15_TA_REG)) + return false; + + /* LOW_REGS or R15_TA_REG both are 2-byte instruction. */ + if (REG_P (op0) && in_reg_class_p (REGNO (op0), LOW_REGS)) + return false; + + return true; +} + +static bool +rename_cbranch_eq_reg_profitlable (rtx insn) +{ + rtx pattern; + pattern = PATTERN (insn); + rtx if_then_else = SET_SRC (pattern); + rtx cond = XEXP (if_then_else, 0); + rtx op1 = XEXP (cond, 1); + + insn_rr_info *info; + du_head_p op_chain; + int op_pos = 1; + + 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 (in_reg_class_p (op_chain->regno, R5_REG)) + return false; + + if (REG_P (op1) && in_reg_class_p (REGNO (op1), LOW_REGS)) + return true; + else + return false; +} + +static void +do_regrename () +{ + basic_block bb; + rtx_insn *insn; + + FOR_EACH_BB_FN (bb, cfun) + { + FOR_BB_INSNS (bb, insn) + { + if (!INSN_P (insn)) + continue; + + switch (recog_memoized (insn)) + { + case CODE_FOR_slts_compare_impl: + case CODE_FOR_slt_compare_impl: + /* Try to rename operand 0 to $r15 if profitable. */ + if (rename_slt_profitlable (insn)) + try_rename_operand_to (insn, 0, R15_TA_REG); + break; + case CODE_FOR_slt_eq0: + /* Try to rename operand 0 to $r15. */ + if (rename_slt_profitlable (insn)) + try_rename_operand_to (insn, 0, R15_TA_REG); + break; + case CODE_FOR_cbranchsi4_equality_zero: + /* Try to rename operand 1 to $r15. */ + if (rename_cbranch_eq0_r15_profitlable (insn)) + if (!try_rename_operand_to (insn, 1, R15_TA_REG)) + if (rename_cbranch_eq0_low_reg_profitlable (insn)) + try_rename_operand_to (insn, 1, LOW_REGS); + break; + case CODE_FOR_cbranchsi4_equality_reg: + case CODE_FOR_cbranchsi4_equality_reg_or_const_int: + /* Try to rename operand 1 to $r5. */ + if (rename_cbranch_eq_reg_profitlable (insn)) + try_rename_operand_to (insn, 1, R5_REG); + break; + } + } + } +} + +static unsigned int +nds32_regrename (void) +{ + 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); + + do_regrename (); + + regrename_finish (); + return 1; +} + +const pass_data pass_data_nds32_regrename = +{ + RTL_PASS, /* type */ + "nds32-regrename", /* 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_regrename_opt : public rtl_opt_pass +{ +public: + pass_nds32_regrename_opt (gcc::context *ctxt) + : rtl_opt_pass (pass_data_nds32_regrename, ctxt) + {} + + /* opt_pass methods: */ + bool gate (function *) { return TARGET_16_BIT && TARGET_REGRENAME_OPT; } + unsigned int execute (function *) { return nds32_regrename (); } +}; + +rtl_opt_pass * +make_pass_nds32_regrename_opt (gcc::context *ctxt) +{ + return new pass_nds32_regrename_opt (ctxt); +} diff --git a/gcc/config/nds32/nds32-relax-opt.c b/gcc/config/nds32/nds32-relax-opt.c new file mode 100644 index 0000000..0919af6 --- /dev/null +++ b/gcc/config/nds32/nds32-relax-opt.c @@ -0,0 +1,612 @@ +/* relax-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 "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 "emit-rtl.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" +using namespace nds32; + +/* This is used to create unique relax hint id value. + The initial value is 0. */ +static int relax_group_id = 0; + +/* Group the following pattern as relax candidates: + + 1. sethi $ra, hi20(sym) + ori $ra, $ra, lo12(sym) + ==> + addi.gp $ra, sym + + 2. sethi $ra, hi20(sym) + lwi $rb, [$ra + lo12(sym)] + ==> + lwi.gp $rb, [(sym)] + + 3. sethi $ra, hi20(sym) + ori $ra, $ra, lo12(sym) + lwi $rb, [$ra] + swi $rc, [$ra] + ==> + lwi37 $rb, [(sym)] + swi37 $rc, [(sym)] */ + +/* Return true if is load/store with REG addressing mode + and memory mode is SImode. */ +static bool +nds32_reg_base_load_store_p (rtx_insn *insn) +{ + rtx mem_src = NULL_RTX; + + switch (get_attr_type (insn)) + { + case TYPE_LOAD: + mem_src = SET_SRC (PATTERN (insn)); + break; + case TYPE_STORE: + mem_src = SET_DEST (PATTERN (insn)); + break; + default: + break; + } + + /* Find load/store insn with addressing mode is REG. */ + if (mem_src != NULL_RTX) + { + if ((GET_CODE (mem_src) == ZERO_EXTEND) + || (GET_CODE (mem_src) == SIGN_EXTEND)) + mem_src = XEXP (mem_src, 0); + + if (GET_CODE (XEXP (mem_src, 0)) == REG) + return true; + } + + return false; +} + +/* Return true if insn is a sp/fp base or sp/fp plus load-store instruction. */ + +static bool +nds32_sp_base_or_plus_load_store_p (rtx_insn *insn) +{ + rtx mem_src = NULL_RTX; + + switch (get_attr_type (insn)) + { + case TYPE_LOAD: + mem_src = SET_SRC (PATTERN (insn)); + break; + case TYPE_STORE: + mem_src = SET_DEST (PATTERN (insn)); + break; + default: + break; + } + /* Find load/store insn with addressing mode is REG. */ + if (mem_src != NULL_RTX) + { + if ((GET_CODE (mem_src) == ZERO_EXTEND) + || (GET_CODE (mem_src) == SIGN_EXTEND)) + mem_src = XEXP (mem_src, 0); + + if ((GET_CODE (XEXP (mem_src, 0)) == PLUS)) + mem_src = XEXP (mem_src, 0); + + if (REG_P (XEXP (mem_src, 0)) + && ((frame_pointer_needed + && REGNO (XEXP (mem_src, 0)) == FP_REGNUM) + || REGNO (XEXP (mem_src, 0)) == SP_REGNUM)) + return true; + } + + return false; +} + +/* Return true if is load with [REG + REG/CONST_INT] addressing mode. */ +static bool +nds32_plus_reg_load_store_p (rtx_insn *insn) +{ + rtx mem_src = NULL_RTX; + + switch (get_attr_type (insn)) + { + case TYPE_LOAD: + mem_src = SET_SRC (PATTERN (insn)); + break; + case TYPE_STORE: + mem_src = SET_DEST (PATTERN (insn)); + break; + default: + break; + } + + /* Find load/store insn with addressing mode is [REG + REG/CONST]. */ + if (mem_src != NULL_RTX) + { + if ((GET_CODE (mem_src) == ZERO_EXTEND) + || (GET_CODE (mem_src) == SIGN_EXTEND)) + mem_src = XEXP (mem_src, 0); + + if ((GET_CODE (XEXP (mem_src, 0)) == PLUS)) + mem_src = XEXP (mem_src, 0); + else + return false; + + if (GET_CODE (XEXP (mem_src, 0)) == REG) + return true; + + } + + return false; +} + +/* Return true if ins is hwloop last instruction. */ +static bool +nds32_hwloop_last_insn_p (rtx_insn *insn) +{ + if (recog_memoized (insn) == CODE_FOR_hwloop_last_insn) + return true; + + return false; +} + +/* Return true if x is const and the referance is ict symbol. */ +static bool +nds32_ict_const_p (rtx x) +{ + if (GET_CODE (x) == CONST) + { + x = XEXP (x, 0); + return nds32_indirect_call_referenced_p (x); + } + return FALSE; +} + +/* Group the following pattern as relax candidates: + + GOT: + sethi $ra, hi20(sym) + ori $ra, $ra, lo12(sym) + lw $rb, [$ra + $gp] + + GOTOFF, TLSLE: + sethi $ra, hi20(sym) + ori $ra, $ra, lo12(sym) + LS $rb, [$ra + $gp] + + GOTOFF, TLSLE: + sethi $ra, hi20(sym) + ori $ra, $ra, lo12(sym) + add $rb, $ra, $gp($tp) + + Initial GOT table: + sethi $gp,hi20(sym) + ori $gp, $gp, lo12(sym) + add5.pc $gp */ + +static auto_vec nds32_group_infos; +/* Group the PIC and TLS relax candidate instructions for linker. */ +static bool +nds32_pic_tls_group (rtx_insn *def_insn, + enum nds32_relax_insn_type relax_type, + int sym_type) +{ + df_ref def_record; + df_link *link; + rtx_insn *use_insn = NULL; + rtx pat, new_pat; + def_record = DF_INSN_DEFS (def_insn); + for (link = DF_REF_CHAIN (def_record); link; link = link->next) + { + if (!DF_REF_INSN_INFO (link->ref)) + continue; + + use_insn = DF_REF_INSN (link->ref); + + /* Skip if define insn and use insn not in the same basic block. */ + if (!dominated_by_p (CDI_DOMINATORS, + BLOCK_FOR_INSN (use_insn), + BLOCK_FOR_INSN (def_insn))) + return FALSE; + + /* Skip if use_insn not active insn. */ + if (!active_insn_p (use_insn)) + return FALSE; + + switch (relax_type) + { + case RELAX_ORI: + + /* GOTOFF, TLSLE: + sethi $ra, hi20(sym) + ori $ra, $ra, lo12(sym) + add $rb, $ra, $gp($tp) */ + if ((sym_type == UNSPEC_TLSLE + || sym_type == UNSPEC_GOTOFF) + && (recog_memoized (use_insn) == CODE_FOR_addsi3)) + { + pat = XEXP (PATTERN (use_insn), 1); + new_pat = + gen_rtx_UNSPEC (SImode, + gen_rtvec (2, XEXP (pat, 0), XEXP (pat, 1)), + UNSPEC_ADD32); + validate_replace_rtx (pat, new_pat, use_insn); + nds32_group_infos.safe_push (use_insn); + } + else if (nds32_plus_reg_load_store_p (use_insn) + && !nds32_sp_base_or_plus_load_store_p (use_insn)) + nds32_group_infos.safe_push (use_insn); + else + return FALSE; + break; + + default: + return FALSE; + } + } + return TRUE; +} + +static int +nds32_pic_tls_symbol_type (rtx x) +{ + x = XEXP (SET_SRC (PATTERN (x)), 1); + + if (GET_CODE (x) == CONST) + { + x = XEXP (x, 0); + + if (GET_CODE (x) == PLUS) + x = XEXP (x, 0); + + return XINT (x, 1); + } + + return XINT (x, 1); +} + +/* Group the relax candidates with group id. */ +static void +nds32_group_insns (rtx sethi) +{ + df_ref def_record, use_record; + df_link *link; + rtx_insn *use_insn = NULL; + rtx group_id; + bool valid; + + def_record = DF_INSN_DEFS (sethi); + + for (link = DF_REF_CHAIN (def_record); link; link = link->next) + { + if (!DF_REF_INSN_INFO (link->ref)) + continue; + + use_insn = DF_REF_INSN (link->ref); + + /* Skip if define insn and use insn not in the same basic block. */ + if (!dominated_by_p (CDI_DOMINATORS, + BLOCK_FOR_INSN (use_insn), + BLOCK_FOR_INSN (sethi))) + return; + + /* Skip if the low-part used register is from different high-part + instructions. */ + use_record = DF_INSN_USES (use_insn); + if (DF_REF_CHAIN (use_record) && DF_REF_CHAIN (use_record)->next) + return; + + /* Skip if use_insn not active insn. */ + if (!active_insn_p (use_insn)) + return; + + /* Initial use_insn_type. */ + if (!(recog_memoized (use_insn) == CODE_FOR_lo_sum + || nds32_symbol_load_store_p (use_insn) + || (nds32_reg_base_load_store_p (use_insn) + &&!nds32_sp_base_or_plus_load_store_p (use_insn)))) + return; + } + + group_id = GEN_INT (relax_group_id); + /* Insert .relax_* directive for sethi. */ + emit_insn_before (gen_relax_group (group_id), sethi); + + /* Scan the use insns and insert the directive. */ + for (link = DF_REF_CHAIN (def_record); link; link = link->next) + { + if (!DF_REF_INSN_INFO (link->ref)) + continue; + + use_insn = DF_REF_INSN (link->ref); + + /* Insert .relax_* directive. */ + if (active_insn_p (use_insn)) + emit_insn_before (gen_relax_group (group_id), use_insn); + + /* Find ori ra, ra, unspec(symbol) instruction. */ + if (use_insn != NULL + && recog_memoized (use_insn) == CODE_FOR_lo_sum + && !nds32_const_unspec_p (XEXP (SET_SRC (PATTERN (use_insn)), 1))) + { + int sym_type = nds32_pic_tls_symbol_type (use_insn); + valid = nds32_pic_tls_group (use_insn, RELAX_ORI, sym_type); + + /* Insert .relax_* directive. */ + while (!nds32_group_infos.is_empty ()) + { + use_insn = nds32_group_infos.pop (); + if (valid) + emit_insn_before (gen_relax_group (group_id), use_insn); + } + } + } + + relax_group_id++; +} + +/* Convert relax group id in rtl. */ + +static void +nds32_group_tls_insn (rtx insn) +{ + rtx pat = PATTERN (insn); + rtx unspec_relax_group = XEXP (XVECEXP (pat, 0, 1), 0); + + while (GET_CODE (pat) != SET && GET_CODE (pat) == PARALLEL) + { + pat = XVECEXP (pat, 0, 0); + } + + if (GET_CODE (unspec_relax_group) == UNSPEC + && XINT (unspec_relax_group, 1) == UNSPEC_VOLATILE_RELAX_GROUP) + { + XVECEXP (unspec_relax_group, 0, 0) = GEN_INT (relax_group_id); + } + + relax_group_id++; +} + +static bool +nds32_float_reg_load_store_p (rtx_insn *insn) +{ + rtx pat = PATTERN (insn); + + if (get_attr_type (insn) == TYPE_FLOAD + && GET_CODE (pat) == SET + && (GET_MODE (XEXP (pat, 0)) == SFmode + || GET_MODE (XEXP (pat, 0)) == DFmode) + && MEM_P (XEXP (pat, 1))) + { + rtx addr = XEXP (XEXP (pat, 1), 0); + + /* [$ra] */ + if (REG_P (addr)) + return true; + /* [$ra + offset] */ + if (GET_CODE (addr) == PLUS + && REG_P (XEXP (addr, 0)) + && CONST_INT_P (XEXP (addr, 1))) + return true; + } + return false; +} + + +/* Group float load-store instructions: + la $ra, symbol + flsi $rt, [$ra + offset] */ + +static void +nds32_group_float_insns (rtx insn) +{ + df_ref def_record, use_record; + df_link *link; + rtx_insn *use_insn = NULL; + rtx group_id; + + def_record = DF_INSN_DEFS (insn); + + for (link = DF_REF_CHAIN (def_record); link; link = link->next) + { + if (!DF_REF_INSN_INFO (link->ref)) + continue; + + use_insn = DF_REF_INSN (link->ref); + + /* Skip if define insn and use insn not in the same basic block. */ + if (!dominated_by_p (CDI_DOMINATORS, + BLOCK_FOR_INSN (use_insn), + BLOCK_FOR_INSN (insn))) + return; + + /* Skip if the low-part used register is from different high-part + instructions. */ + use_record = DF_INSN_USES (use_insn); + if (DF_REF_CHAIN (use_record) && DF_REF_CHAIN (use_record)->next) + return; + + /* Skip if use_insn not active insn. */ + if (!active_insn_p (use_insn)) + return; + + if (!nds32_float_reg_load_store_p (use_insn) + || find_post_update_rtx (use_insn) != -1) + return; + } + + group_id = GEN_INT (relax_group_id); + /* Insert .relax_* directive for insn. */ + emit_insn_before (gen_relax_group (group_id), insn); + + /* Scan the use insns and insert the directive. */ + for (link = DF_REF_CHAIN (def_record); link; link = link->next) + { + if (!DF_REF_INSN_INFO (link->ref)) + continue; + + use_insn = DF_REF_INSN (link->ref); + + /* Insert .relax_* directive. */ + emit_insn_before (gen_relax_group (group_id), use_insn); + } + + relax_group_id++; +} + +/* Group the relax candidate instructions for linker. */ +static void +nds32_relax_group (void) +{ + rtx_insn *insn; + + compute_bb_for_insn (); + + df_chain_add_problem (DF_DU_CHAIN | DF_UD_CHAIN); + df_insn_rescan_all (); + df_analyze (); + df_set_flags (DF_DEFER_INSN_RESCAN); + calculate_dominance_info (CDI_DOMINATORS); + + insn = get_insns (); + gcc_assert (NOTE_P (insn)); + + for (insn = next_active_insn (insn); insn; insn = next_active_insn (insn)) + { + if (NONJUMP_INSN_P (insn)) + { + /* Find sethi ra, symbol instruction. */ + if (recog_memoized (insn) == CODE_FOR_sethi + && nds32_symbolic_operand (XEXP (SET_SRC (PATTERN (insn)), 0), + SImode) + && !nds32_ict_const_p (XEXP (SET_SRC (PATTERN (insn)), 0)) + && !nds32_hwloop_last_insn_p (next_active_insn (insn))) + + nds32_group_insns (insn); + else if (recog_memoized (insn) == CODE_FOR_tls_ie) + nds32_group_tls_insn (insn); + else if (TARGET_FPU_SINGLE + && recog_memoized (insn) == CODE_FOR_move_addr + && !nds32_ict_const_p (XEXP (SET_SRC (PATTERN (insn)), 0)) + && !nds32_hwloop_last_insn_p (next_active_insn (insn))) + { + nds32_group_float_insns (insn); + } + } + else if (CALL_P (insn) && recog_memoized (insn) == CODE_FOR_tls_desc) + { + nds32_group_tls_insn (insn); + } + } + + /* We must call df_finish_pass manually because it should be invoked before + BB information is destroyed. Hence we cannot set the TODO_df_finish flag + to the pass manager. */ + df_insn_rescan_all (); + df_finish_pass (false); + free_dominance_info (CDI_DOMINATORS); +} + +static unsigned int +nds32_relax_opt (void) +{ + if (TARGET_RELAX_HINT) + nds32_relax_group (); + return 1; +} + +const pass_data pass_data_nds32_relax_opt = +{ + RTL_PASS, /* type */ + "relax_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_relax_opt : public rtl_opt_pass +{ +public: + pass_nds32_relax_opt (gcc::context *ctxt) + : rtl_opt_pass (pass_data_nds32_relax_opt, ctxt) + {} + + /* opt_pass methods: */ + bool gate (function *) { return TARGET_RELAX_HINT; } + unsigned int execute (function *) { return nds32_relax_opt (); } +}; + +rtl_opt_pass * +make_pass_nds32_relax_opt (gcc::context *ctxt) +{ + return new pass_nds32_relax_opt (ctxt); +} diff --git a/gcc/config/nds32/nds32-scalbn-transform.c b/gcc/config/nds32/nds32-scalbn-transform.c new file mode 100644 index 0000000..fba7c6f --- /dev/null +++ b/gcc/config/nds32/nds32-scalbn-transform.c @@ -0,0 +1,364 @@ +/* A Gimple-level pass of Andes NDS32 cpu for GNU compiler. + This pass transforms the multiplications whose multiplier is a + power of 2. + + 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-fold.h" + + +/* Return true if the current function name is scalbn/scalbnf, or its alias + includes scalbn/scalbnf, otherwise return false. */ + +static bool +nds32_is_scalbn_alias_func_p (void) +{ + int i; + struct ipa_ref *ref; + struct cgraph_node *cfun_node; + + if (!strcmp (function_name (cfun), "scalbn") + || !strcmp (function_name (cfun), "scalbnf")) + return true; + + cfun_node = cgraph_node::get (current_function_decl); + + if (!cfun_node) + return false; + + for (i = 0; cfun_node->iterate_referring (i, ref); i++) + if (ref->use == IPA_REF_ALIAS) + { + struct cgraph_node *alias = dyn_cast (ref->referring); + if (!strcmp (alias->asm_name (), "scalbn") + || !strcmp (alias->asm_name (), "scalbnf")) + return true; + } + + return false; +} + +/* Return true if value of tree node RT is power of 2. */ + +static bool +nds32_real_ispow2_p (tree rt) +{ + if (TREE_CODE (rt) != REAL_CST) + return false; + + if (TREE_REAL_CST_PTR (rt)->cl != rvc_normal) + return false; + + int i; + for (i = 0; i < SIGSZ-1; ++i) + if (TREE_REAL_CST_PTR (rt)->sig[i] != 0) + return false; + if (TREE_REAL_CST_PTR (rt)->sig[SIGSZ-1] != SIG_MSB) + return false; + + return true; +} + +/* Return the exponent of tree node RT in base 2. */ + +static int +nds32_real_pow2exp (tree rt) +{ + return REAL_EXP (TREE_REAL_CST_PTR (rt)) - 1; +} + +/* Return true if GS is the target of scalbn transform. */ + +static bool +nds32_scalbn_transform_target_p (gimple *gs) +{ + if (is_gimple_assign (gs)) + if ((gimple_assign_rhs_code (gs) == MULT_EXPR) + && (TREE_CODE (TREE_TYPE (gimple_assign_rhs1 (gs))) == REAL_TYPE) + && nds32_real_ispow2_p (gimple_assign_rhs2 (gs))) + return true; + return false; +} + +/* Do scalbn transform for a GIMPLE statement GS. + + When the multiplier of GIMPLE statement GS is a positive number, + GS will be transform to one gimple_call statement and one + gimple_assign statement as follows: + A = B * 128.0 -> temp = BUILT_IN_SCALBN (B, 7) + A = temp + + When the multiplier is a negative number, the multiplier will be + conversed the sign first since BUILT_IN_SCALBN can't handle + negative multiplier. The example is shown below: + A = B * -128.0 -> temp = BUILT_IN_SCALBN (B, 7) + A = -temp +*/ + +static void +nds32_do_scalbn_transform (gimple *gs) +{ + tree mult_cand = gimple_assign_rhs1 (gs); /* Multiplicand */ + tree mult_er = gimple_assign_rhs2 (gs); /* Multiplier */ + bool is_neg = false; + + /* Choose the function by type of arg. */ + enum built_in_function fn_name; + tree type = TREE_TYPE (mult_cand); + if (TYPE_MAIN_VARIANT (type) == double_type_node) + fn_name = BUILT_IN_SCALBN; + else if (TYPE_MAIN_VARIANT (type) == float_type_node) + fn_name = BUILT_IN_SCALBNF; + /* Do not transform long double to scalbnl since some c library don't provide + it if target don't have real long double type + else if (TYPE_MAIN_VARIANT (type) == long_double_type_node) + fn_name = BUILT_IN_SCALBNL; + */ + else + return; + + /* Converse the sign of negative number. */ + if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (mult_er))) + { + is_neg = true; + mult_er = build_real (TREE_TYPE (mult_er), + real_value_negate (&TREE_REAL_CST (mult_er))); + } + + /* Set function name for building gimple_call. */ + tree fndecl = builtin_decl_explicit (fn_name); + + /* Set last arg for building gimple_call. */ + tree exp = build_int_cst (integer_type_node, + nds32_real_pow2exp (mult_er)); + + /* Build a new temp ssa. */ + tree temp_call_ssa = make_ssa_name (TREE_TYPE (gimple_assign_lhs (gs)), NULL); + + /* Build gimple_call stmt to replace GS. */ + gimple *call_stmt = gimple_build_call (fndecl, + 2, + mult_cand, + exp); + gimple_call_set_lhs (call_stmt, temp_call_ssa); + + enum tree_code subcode = NOP_EXPR; + /* Handle negative value. */ + if (is_neg) + subcode = NEGATE_EXPR; + + /* Build gimple_assign for return value or change the sign. */ + gimple *assign_stmt = + gimple_build_assign (gimple_assign_lhs (gs), + subcode, + gimple_call_lhs (call_stmt)); + + /* Replace gimple_assign GS by new gimple_call. */ + gimple_stmt_iterator gsi = gsi_for_stmt (gs); + update_stmt (call_stmt); + gsi_insert_before (&gsi, call_stmt, GSI_NEW_STMT); + + /* Insert the gimple_assign after the scalbn call. */ + update_stmt (assign_stmt); + gsi_next (&gsi); + gsi_replace (&gsi, assign_stmt, false); +} + +/* Do scalbn transform for each basic block BB. */ + +static int +nds32_scalbn_transform_basic_block (basic_block bb) +{ + gimple_stmt_iterator gsi; + int transform_number = 0; + + if (dump_file) + fprintf (dump_file, + "\n;; Transforming the multiplication for basic block %d\n", + bb->index); + + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + + if (nds32_scalbn_transform_target_p (stmt)) + { + if (dump_file) + { + fprintf (dump_file, + "* The multiplier of stmt %d is transforming.\n", + gimple_uid (stmt)); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM|TDF_RAW); + } + nds32_do_scalbn_transform (stmt); + transform_number++; + } + } + + return transform_number; +} + +/* This function is the entry of scalbn transform pass. */ + +static int +nds32_scalbn_transform_opt (void) +{ + basic_block bb; + int total_transform_number = 0; + + /* Ignore current and builtin function name are the same. */ + if (nds32_is_scalbn_alias_func_p ()) + { + if (dump_file) + fprintf (dump_file, + "* Ignore function %s. " + "Transform it will cause infinite loop.\n", + function_name (cfun)); + return 0; + } + + FOR_EACH_BB_FN (bb, cfun) + { + total_transform_number += nds32_scalbn_transform_basic_block (bb); + } + + if (dump_file) + { + if (total_transform_number > 0) + fprintf (dump_file, + "\n;; Transform %d multiplication stmt in function %s\n", + total_transform_number, + current_function_name ()); + else + fprintf (dump_file, + "\n;; No multiplication stmt is transformed in function %s\n", + current_function_name ()); + } + + return 1; +} + +static bool +gate_nds32_scalbn_transform (void) +{ + return flag_nds32_scalbn_transform + && !TARGET_FPU_SINGLE + && !flag_no_builtin; +} + +const pass_data pass_data_nds32_scalbn_transform_opt = +{ + GIMPLE_PASS, /* type */ + "scalbn_transform", /* 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 */ + TODO_update_ssa, /* todo_flags_finish */ +}; + +class pass_nds32_scalbn_transform_opt : public gimple_opt_pass +{ +public: + pass_nds32_scalbn_transform_opt (gcc::context *ctxt) + : gimple_opt_pass (pass_data_nds32_scalbn_transform_opt, ctxt) + {} + + /* opt_pass methods: */ + bool gate (function *) { return gate_nds32_scalbn_transform (); } + unsigned int execute (function *) { return nds32_scalbn_transform_opt (); } +}; + +gimple_opt_pass * +make_pass_nds32_scalbn_transform_opt (gcc::context *ctxt) +{ + return new pass_nds32_scalbn_transform_opt (ctxt); +} diff --git a/gcc/config/nds32/nds32-sign-conversion.c b/gcc/config/nds32/nds32-sign-conversion.c new file mode 100644 index 0000000..74eefba --- /dev/null +++ b/gcc/config/nds32/nds32-sign-conversion.c @@ -0,0 +1,218 @@ +/* A Gimple-level pass of Andes NDS32 cpu for GNU compiler that + converse the sign of constant operand when the FPU do not be + accessed. + + 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-fold.h" + +/* Return true if GS is the target of sign conversion. */ + +static bool +nds32_sign_conversion_target_p (gimple *gs) +{ + if (is_gimple_assign (gs)) + if ((gimple_assign_rhs_code (gs) == MINUS_EXPR) + && (TREE_CODE (gimple_assign_rhs2 (gs)) == REAL_CST)) + return true; + return false; +} + +/* Do sign conversion for a GIMPLE statement GS. */ + +static void +nds32_do_sign_conversion (gimple *gs) +{ + /* Rewrite the rhs operand. */ + enum tree_code op_code = gimple_assign_rhs_code (gs); + op_code = PLUS_EXPR; + gimple_assign_set_rhs_code (gs, op_code); + /* Rewrite the constant value. */ + tree rhs2 = gimple_assign_rhs2 (gs); + rhs2 = build_real (TREE_TYPE (rhs2), + real_value_negate (&TREE_REAL_CST (rhs2))); + gimple_assign_set_rhs2 (gs, rhs2); + /* When the statement is modified, please mark this statement is modified. */ + update_stmt (gs); +} + +/* Do sign conversion for each basic block BB. */ + +static int +nds32_sign_conversion_basic_block (basic_block bb) +{ + gimple_stmt_iterator gsi; + int converse_number = 0; + + if (dump_file) + fprintf (dump_file, + "\n;; Conversing the sign of gimple stmts for basic block %d\n", + bb->index); + + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + + if (nds32_sign_conversion_target_p (stmt)) + { + if (dump_file) + { + fprintf (dump_file, "* The sign of stmt %d is conversing.\n", + gimple_uid (stmt)); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM|TDF_RAW); + } + nds32_do_sign_conversion (stmt); + converse_number++; + } + } + + return converse_number; +} + +/* This function is the entry of sign conversion pass. */ + +static int +nds32_sign_conversion_opt (void) +{ + basic_block bb; + int total_converse_number = 0; + + FOR_EACH_BB_FN (bb, cfun) + { + total_converse_number += nds32_sign_conversion_basic_block (bb); + } + + if (dump_file) + { + if (total_converse_number > 0) + fprintf (dump_file, "\n;; Converse %d stmts in function %s\n", + total_converse_number, + current_function_name ()); + else + fprintf (dump_file, + "\n;; No sign of stmt is conversed in function %s\n", + current_function_name ()); + } + + return 1; +} + +const pass_data pass_data_nds32_sign_conversion_opt = +{ + GIMPLE_PASS, /* type */ + "sign_conversion", /* 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 */ + TODO_update_ssa, /* todo_flags_finish */ +}; + +class pass_nds32_sign_conversion_opt : public gimple_opt_pass +{ +public: + pass_nds32_sign_conversion_opt (gcc::context *ctxt) + : gimple_opt_pass (pass_data_nds32_sign_conversion_opt, ctxt) + {} + + /* opt_pass methods: */ + bool gate (function *) + { + return flag_nds32_sign_conversion && !TARGET_FPU_SINGLE; + } + unsigned int execute (function *) { return nds32_sign_conversion_opt (); } +}; + +gimple_opt_pass * +make_pass_nds32_sign_conversion_opt (gcc::context *ctxt) +{ + return new pass_nds32_sign_conversion_opt (ctxt); +} diff --git a/gcc/config/nds32/nds32-soft-fp-comm.c b/gcc/config/nds32/nds32-soft-fp-comm.c new file mode 100644 index 0000000..98ba3d5 --- /dev/null +++ b/gcc/config/nds32/nds32-soft-fp-comm.c @@ -0,0 +1,205 @@ +/* Operand commutative for soft floating point arithmetic 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" + +#define SF_ARG0_REGNO 0 +#define SF_ARG1_REGNO 1 + +#define DF_ARG0_REGNO 0 +#define DF_ARG1_REGNO 2 + +static int +nds32_soft_fp_arith_comm_opt (void) +{ + basic_block bb; + rtx_insn *insn; + FOR_EACH_BB_FN (bb, cfun) + { + FOR_BB_INSNS (bb, insn) + { + if (!CALL_P (insn)) + continue; + + rtx pat = PATTERN (insn); + rtx call_rtx = XVECEXP (pat, 0, 0); + + if (GET_CODE (call_rtx) == SET) + call_rtx = SET_SRC (call_rtx); + + rtx func_mem = XEXP (call_rtx, 0); + rtx symbol = XEXP (func_mem, 0); + + if (GET_CODE (symbol) != SYMBOL_REF) + continue; + + const char *func_name = XSTR (symbol, 0); + bool df_p; + if (((strcmp("__mulsf3", func_name) == 0) + || (strcmp("__addsf3", func_name) == 0))) + df_p = false; + else if (((strcmp("__muldf3", func_name) == 0) + || (strcmp("__adddf3", func_name) == 0))) + df_p = true; + else + continue; + + rtx_insn *prev_insn = insn; + rtx_insn *arg0_insn = NULL; + rtx_insn *arg1_insn = NULL; + unsigned arg0_regno = df_p ? DF_ARG0_REGNO : SF_ARG0_REGNO; + unsigned arg1_regno = df_p ? DF_ARG1_REGNO : SF_ARG1_REGNO; + enum machine_mode mode = df_p ? DFmode : SFmode; + while ((prev_insn = PREV_INSN (prev_insn)) && prev_insn) + { + if (arg0_insn != NULL && arg1_insn != NULL) + break; + + if (BLOCK_FOR_INSN (prev_insn) != BLOCK_FOR_INSN (insn)) + break; + + if (!NONJUMP_INSN_P (prev_insn)) + break; + + if (!INSN_P (prev_insn)) + continue; + + rtx set = PATTERN (prev_insn); + + if (GET_CODE (set) != SET) + continue; + + rtx dst_reg = SET_DEST (set); + + if (!REG_P (dst_reg)) + break; + + unsigned regno = REGNO (dst_reg); + + if (regno == arg0_regno) + { + arg0_insn = prev_insn; + continue; + } + else if (regno == arg1_regno) + { + arg1_insn = prev_insn; + continue; + } + break; + } + if (arg0_insn == NULL || arg1_insn == NULL) + continue; + + rtx arg0_src = SET_SRC (PATTERN (arg0_insn)); + rtx arg1_src = SET_SRC (PATTERN (arg1_insn)); + + if ((REG_P (arg0_src) + && GET_MODE (arg0_src) == mode + && REGNO (arg0_src) == arg1_regno) + || (REG_P (arg1_src) + && GET_MODE (arg1_src) == mode + && REGNO (arg1_src) == arg0_regno)) + { + /* Swap operand! */ + rtx tmp = SET_DEST (PATTERN (arg0_insn)); + SET_DEST (PATTERN (arg0_insn)) = SET_DEST (PATTERN (arg1_insn)); + SET_DEST (PATTERN (arg1_insn)) = tmp; + } + } + } + return 1; +} + +const pass_data pass_data_nds32_soft_fp_arith_comm_opt = +{ + RTL_PASS, /* type */ + "soft_fp_arith_comm", /* 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_soft_fp_arith_comm_opt : public rtl_opt_pass +{ +public: + pass_nds32_soft_fp_arith_comm_opt (gcc::context *ctxt) + : rtl_opt_pass (pass_data_nds32_soft_fp_arith_comm_opt, ctxt) + {} + + /* opt_pass methods: */ + bool gate (function *) { + return TARGET_SOFT_FP_ARITH_COMM && !TARGET_FPU_SINGLE; + } + unsigned int execute (function *) { return nds32_soft_fp_arith_comm_opt (); } +}; + +rtl_opt_pass * +make_pass_nds32_soft_fp_arith_comm_opt (gcc::context *ctxt) +{ + return new pass_nds32_soft_fp_arith_comm_opt (ctxt); +} diff --git a/gcc/config/nds32/nds32-utils.c b/gcc/config/nds32/nds32-utils.c new file mode 100644 index 0000000..3b16738 --- /dev/null +++ b/gcc/config/nds32/nds32-utils.c @@ -0,0 +1,923 @@ +/* Auxiliary functions for pipeline descriptions pattern 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 "nds32-protos.h" + +namespace nds32 { + +/* Get the rtx in the PATTERN field of an insn. If INSN is not an insn, + the funciton doesn't change anything and returns it directly. */ +rtx +extract_pattern_from_insn (rtx insn) +{ + if (INSN_P (insn)) + return PATTERN (insn); + + return insn; +} + +/* Get the number of elements in a parallel rtx. */ +size_t +parallel_elements (rtx parallel_rtx) +{ + parallel_rtx = extract_pattern_from_insn (parallel_rtx); + gcc_assert (GET_CODE (parallel_rtx) == PARALLEL); + + return XVECLEN (parallel_rtx, 0); +} + +/* Extract an rtx from a parallel rtx with index NTH. If NTH is a negative + value, the function returns the last NTH rtx. */ +rtx +parallel_element (rtx parallel_rtx, int nth) +{ + parallel_rtx = extract_pattern_from_insn (parallel_rtx); + gcc_assert (GET_CODE (parallel_rtx) == PARALLEL); + + int len = parallel_elements (parallel_rtx); + + if (nth >= 0) + { + if (nth >= len) + return NULL_RTX; + + return XVECEXP (parallel_rtx, 0, nth); + } + else + { + if (len + nth < 0) + return NULL_RTX; + + return XVECEXP (parallel_rtx, 0, len + nth); + } +} + +/* Return true if an insn is a pseudo NOP that is not a real instruction + occupying a real cycle and space of the text section. */ +bool +insn_pseudo_nop_p (rtx_insn *insn) +{ + if (INSN_CODE (insn) == CODE_FOR_nop_data_dep + || INSN_CODE (insn) == CODE_FOR_nop_res_dep) + return true; + + return false; +} + +/* Indicate whether an insn is a real insn which occupy at least one cycle + or not. The determination cannot be target-independent because some targets + use UNSPEC or UNSPEC_VOLATILE insns to represent real instructions. */ +bool +insn_executable_p (rtx_insn *insn) +{ + if (!INSN_P (insn)) + return false; + + if (insn_pseudo_nop_p (insn)) + return true; + + if (get_attr_length (insn) == 0) + return false; + + switch (GET_CODE (PATTERN (insn))) + { + case CONST_INT: + case USE: + case CLOBBER: + case ADDR_VEC: + case ADDR_DIFF_VEC: + case UNSPEC: + case UNSPEC_VOLATILE: + return false; + + default: + return true; + } + + return true; +} + +/* Find the previous executable insn. */ +rtx_insn * +prev_executable_insn (rtx_insn *insn) +{ + insn = PREV_INSN (insn); + while (insn && !insn_executable_p (insn)) + insn = PREV_INSN (insn); + + return insn; +} + +/* Find the next executable insn. */ +rtx_insn * +next_executable_insn (rtx_insn *insn) +{ + insn = NEXT_INSN (insn); + while (insn && !insn_executable_p (insn)) + insn = NEXT_INSN (insn); + + return insn; +} + +/* Find the previous executable insn in the current basic block. */ +rtx_insn * +prev_executable_insn_local (rtx_insn *insn) +{ + insn = PREV_INSN (insn); + while (insn && !insn_executable_p (insn)) + { + if(LABEL_P (insn) || JUMP_P (insn) || CALL_P (insn)) + return NULL; + + insn = PREV_INSN (insn); + } + + return insn; +} + +/* Find the next executable insn in the current basic block. */ +rtx_insn * +next_executable_insn_local (rtx_insn *insn) +{ + insn = NEXT_INSN (insn); + while (insn && !insn_executable_p (insn)) + { + if(LABEL_P (insn) || JUMP_P (insn) || CALL_P (insn)) + return NULL; + + insn = NEXT_INSN (insn); + } + + return insn; +} + +/* Return true if an insn is marked as deleted. */ +bool +insn_deleted_p (rtx_insn *insn) +{ + if (insn->deleted ()) + return true; + + if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_DELETED) + return true; + + return false; +} + +/* Functions to determine whether INSN is single-word, double-word + or partial-word load/store insn. */ + +bool +load_single_p (rtx_insn *insn) +{ + if (get_attr_type (insn) != TYPE_LOAD) + return false; + + if (INSN_CODE (insn) == CODE_FOR_move_di || + INSN_CODE (insn) == CODE_FOR_move_df) + return false; + + return true; +} + +bool +store_single_p (rtx_insn *insn) +{ + if (get_attr_type (insn) != TYPE_STORE) + return false; + + if (INSN_CODE (insn) == CODE_FOR_move_di || + INSN_CODE (insn) == CODE_FOR_move_df) + return false; + + return true; +} + +bool +load_double_p (rtx_insn *insn) +{ + if (get_attr_type (insn) != TYPE_LOAD) + return false; + + if (INSN_CODE (insn) != CODE_FOR_move_di && + INSN_CODE (insn) != CODE_FOR_move_df) + return false; + + return true; +} + +bool +store_double_p (rtx_insn *insn) +{ + if (get_attr_type (insn) != TYPE_STORE) + return false; + + if (INSN_CODE (insn) != CODE_FOR_move_di && + INSN_CODE (insn) != CODE_FOR_move_df) + return false; + + return true; +} + +bool +store_offset_reg_p (rtx_insn *insn) +{ + if (get_attr_type (insn) != TYPE_STORE) + return false; + + rtx offset_rtx = extract_offset_rtx (insn); + + if (offset_rtx == NULL_RTX) + return false; + + if (REG_P (offset_rtx)) + return true; + + return false; +} + +bool +load_full_word_p (rtx_insn *insn) +{ + if (!nds32::load_single_p (insn)) + return false; + + if (GET_MODE (SET_SRC (PATTERN (insn))) == SImode) + return true; + + return false; +} + +bool +load_partial_word_p (rtx_insn *insn) +{ + if (!nds32::load_single_p (insn)) + return false; + + if (GET_MODE (SET_SRC (PATTERN (insn))) == HImode + || GET_MODE (SET_SRC (PATTERN (insn))) == QImode) + return true; + + return false; +} + +/* Determine if INSN is a post update insn. */ +bool +post_update_insn_p (rtx_insn *insn) +{ + if (find_post_update_rtx (insn) == -1) + return false; + else + return true; +} + +/* Check if the address of MEM_RTX consists of a base register and an + immediate offset. */ +bool +immed_offset_p (rtx mem_rtx) +{ + gcc_assert (MEM_P (mem_rtx)); + + rtx addr_rtx = XEXP (mem_rtx, 0); + + /* (mem (reg)) is equivalent to (mem (plus (reg) (const_int 0))) */ + if (REG_P (addr_rtx)) + return true; + + /* (mem (plus (reg) (const_int))) */ + if (GET_CODE (addr_rtx) == PLUS + && GET_CODE (XEXP (addr_rtx, 1)) == CONST_INT) + return true; + + return false; +} + +/* Find the post update rtx in INSN. If INSN is a load/store multiple insn, + the function returns the vector index of its parallel part. If INSN is a + single load/store insn, the function returns 0. If INSN is not a post- + update insn, the function returns -1. */ +int +find_post_update_rtx (rtx_insn *insn) +{ + rtx mem_rtx; + int i, len; + + switch (get_attr_type (insn)) + { + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + /* Find a pattern in a parallel rtx: + (set (reg) (plus (reg) (const_int))) */ + len = parallel_elements (insn); + for (i = 0; i < len; ++i) + { + rtx curr_insn = parallel_element (insn, i); + + if (GET_CODE (curr_insn) == SET + && REG_P (SET_DEST (curr_insn)) + && GET_CODE (SET_SRC (curr_insn)) == PLUS) + return i; + } + return -1; + + case TYPE_LOAD: + case TYPE_FLOAD: + case TYPE_STORE: + case TYPE_FSTORE: + mem_rtx = extract_mem_rtx (insn); + /* (mem (post_inc (reg))) */ + switch (GET_CODE (XEXP (mem_rtx, 0))) + { + case POST_INC: + case POST_DEC: + case POST_MODIFY: + return 0; + + default: + return -1; + } + + default: + gcc_unreachable (); + } +} + +/* Extract the MEM rtx from a load/store insn. */ +rtx +extract_mem_rtx (rtx_insn *insn) +{ + rtx body = PATTERN (insn); + + switch (get_attr_type (insn)) + { + case TYPE_LOAD: + case TYPE_FLOAD: + if (MEM_P (SET_SRC (body))) + return SET_SRC (body); + + /* unaligned address: (unspec [(mem)]) */ + if (GET_CODE (SET_SRC (body)) == UNSPEC) + { + gcc_assert (MEM_P (XVECEXP (SET_SRC (body), 0, 0))); + return XVECEXP (SET_SRC (body), 0, 0); + } + + /* (sign_extend (mem)) */ + gcc_assert (MEM_P (XEXP (SET_SRC (body), 0))); + return XEXP (SET_SRC (body), 0); + + case TYPE_STORE: + case TYPE_FSTORE: + if (MEM_P (SET_DEST (body))) + return SET_DEST (body); + + /* unaligned address: (unspec [(mem)]) */ + if (GET_CODE (SET_DEST (body)) == UNSPEC) + { + gcc_assert (MEM_P (XVECEXP (SET_DEST (body), 0, 0))); + return XVECEXP (SET_DEST (body), 0, 0); + } + + /* (sign_extend (mem)) */ + gcc_assert (MEM_P (XEXP (SET_DEST (body), 0))); + return XEXP (SET_DEST (body), 0); + + default: + gcc_unreachable (); + } +} + +/* Extract the base register from load/store insns. The function returns + NULL_RTX if the address is not consist of any registers. */ +rtx +extract_base_reg (rtx_insn *insn) +{ + int post_update_rtx_index; + rtx mem_rtx; + rtx plus_rtx; + + /* Find the MEM rtx. If we can find an insn updating the base register, + the base register will be returned directly. */ + switch (get_attr_type (insn)) + { + case TYPE_LOAD_MULTIPLE: + post_update_rtx_index = find_post_update_rtx (insn); + + if (post_update_rtx_index != -1) + return SET_DEST (parallel_element (insn, post_update_rtx_index)); + + mem_rtx = SET_SRC (parallel_element (insn, 0)); + break; + + case TYPE_STORE_MULTIPLE: + post_update_rtx_index = find_post_update_rtx (insn); + + if (post_update_rtx_index != -1) + return SET_DEST (parallel_element (insn, post_update_rtx_index)); + + mem_rtx = SET_DEST (parallel_element (insn, 0)); + break; + + case TYPE_LOAD: + case TYPE_FLOAD: + case TYPE_STORE: + case TYPE_FSTORE: + mem_rtx = extract_mem_rtx (insn); + break; + + default: + gcc_unreachable (); + } + + gcc_assert (MEM_P (mem_rtx)); + + /* (mem (reg)) */ + if (REG_P (XEXP (mem_rtx, 0))) + return XEXP (mem_rtx, 0); + + /* (mem (lo_sum (reg) (symbol_ref)) */ + if (GET_CODE (XEXP (mem_rtx, 0)) == LO_SUM) + return XEXP (XEXP (mem_rtx, 0), 0); + + plus_rtx = XEXP (mem_rtx, 0); + + if (GET_CODE (plus_rtx) == SYMBOL_REF + || GET_CODE (plus_rtx) == CONST) + return NULL_RTX; + + /* (mem (plus (reg) (const_int))) or + (mem (plus (mult (reg) (const_int 4)) (reg))) or + (mem (post_inc (reg))) or + (mem (post_dec (reg))) or + (mem (post_modify (reg) (plus (reg) (reg)))) */ + gcc_assert (GET_CODE (plus_rtx) == PLUS + || GET_CODE (plus_rtx) == POST_INC + || GET_CODE (plus_rtx) == POST_DEC + || GET_CODE (plus_rtx) == POST_MODIFY); + + if (REG_P (XEXP (plus_rtx, 0))) + return XEXP (plus_rtx, 0); + + gcc_assert (REG_P (XEXP (plus_rtx, 1))); + return XEXP (plus_rtx, 1); +} + +/* Extract the offset rtx from load/store insns. The function returns + NULL_RTX if offset is absent. */ +rtx +extract_offset_rtx (rtx_insn *insn) +{ + rtx mem_rtx; + rtx plus_rtx; + rtx offset_rtx; + + /* Find the MEM rtx. The multiple load/store insns doens't have + the offset field so we can return NULL_RTX here. */ + switch (get_attr_type (insn)) + { + case TYPE_LOAD_MULTIPLE: + case TYPE_STORE_MULTIPLE: + return NULL_RTX; + + case TYPE_LOAD: + case TYPE_FLOAD: + case TYPE_STORE: + case TYPE_FSTORE: + mem_rtx = extract_mem_rtx (insn); + break; + + default: + gcc_unreachable (); + } + + gcc_assert (MEM_P (mem_rtx)); + + /* (mem (reg)) */ + if (REG_P (XEXP (mem_rtx, 0))) + return NULL_RTX; + + plus_rtx = XEXP (mem_rtx, 0); + + switch (GET_CODE (plus_rtx)) + { + case SYMBOL_REF: + case CONST: + case POST_INC: + case POST_DEC: + return NULL_RTX; + + case PLUS: + /* (mem (plus (reg) (const_int))) or + (mem (plus (mult (reg) (const_int 4)) (reg))) */ + if (REG_P (XEXP (plus_rtx, 0))) + offset_rtx = XEXP (plus_rtx, 1); + else + { + gcc_assert (REG_P (XEXP (plus_rtx, 1))); + offset_rtx = XEXP (plus_rtx, 0); + } + + if (ARITHMETIC_P (offset_rtx)) + { + gcc_assert (GET_CODE (offset_rtx) == MULT); + gcc_assert (REG_P (XEXP (offset_rtx, 0))); + offset_rtx = XEXP (offset_rtx, 0); + } + break; + + case LO_SUM: + /* (mem (lo_sum (reg) (symbol_ref)) */ + offset_rtx = XEXP (plus_rtx, 1); + break; + + case POST_MODIFY: + /* (mem (post_modify (reg) (plus (reg) (reg / const_int)))) */ + gcc_assert (REG_P (XEXP (plus_rtx, 0))); + plus_rtx = XEXP (plus_rtx, 1); + gcc_assert (GET_CODE (plus_rtx) == PLUS); + offset_rtx = XEXP (plus_rtx, 0); + break; + + default: + gcc_unreachable (); + } + + return offset_rtx; +} + +/* Extract the register of the shift operand from an ALU_SHIFT rtx. */ +rtx +extract_shift_reg (rtx_insn *insn) +{ + rtx alu_shift_rtx = extract_pattern_from_insn (insn); + + rtx alu_rtx = SET_SRC (alu_shift_rtx); + rtx shift_rtx; + + /* Various forms of ALU_SHIFT can be made by the combiner. + See the difference between add_slli and sub_slli in nds32.md. */ + if (REG_P (XEXP (alu_rtx, 0))) + shift_rtx = XEXP (alu_rtx, 1); + else + shift_rtx = XEXP (alu_rtx, 0); + + return XEXP (shift_rtx, 0); +} + +/* Check if INSN is a movd44 insn. */ +bool +movd44_insn_p (rtx_insn *insn) +{ + if (get_attr_type (insn) == TYPE_ALU + && (INSN_CODE (insn) == CODE_FOR_move_di + || INSN_CODE (insn) == CODE_FOR_move_df)) + { + rtx body = PATTERN (insn); + gcc_assert (GET_CODE (body) == SET); + + rtx src = SET_SRC (body); + rtx dest = SET_DEST (body); + + if ((REG_P (src) || GET_CODE (src) == SUBREG) + && (REG_P (dest) || GET_CODE (dest) == SUBREG)) + return true; + + return false; + } + + return false; +} + +/* Extract the first result (even reg) of a movd44 insn. */ +rtx +extract_movd44_even_reg (rtx_insn *insn) +{ + gcc_assert (movd44_insn_p (insn)); + + rtx def_reg = SET_DEST (PATTERN (insn)); + enum machine_mode mode; + + gcc_assert (REG_P (def_reg) || GET_CODE (def_reg) == SUBREG); + switch (GET_MODE (def_reg)) + { + case DImode: + mode = SImode; + break; + + case DFmode: + mode = SFmode; + break; + + default: + gcc_unreachable (); + } + + return gen_lowpart (mode, def_reg); +} + +/* Extract the second result (odd reg) of a movd44 insn. */ +rtx +extract_movd44_odd_reg (rtx_insn *insn) +{ + gcc_assert (movd44_insn_p (insn)); + + rtx def_reg = SET_DEST (PATTERN (insn)); + enum machine_mode mode; + + gcc_assert (REG_P (def_reg) || GET_CODE (def_reg) == SUBREG); + switch (GET_MODE (def_reg)) + { + case DImode: + mode = SImode; + break; + + case DFmode: + mode = SFmode; + break; + + default: + gcc_unreachable (); + } + + return gen_highpart (mode, def_reg); +} + +/* Extract the rtx representing the accumulation operand of a MAC insn. */ +rtx +extract_mac_acc_rtx (rtx_insn *insn) +{ + return SET_DEST (PATTERN (insn)); +} + +/* Extract the rtx representing non-accumulation operands of a MAC insn. */ +rtx +extract_mac_non_acc_rtx (rtx_insn *insn) +{ + rtx exp = SET_SRC (PATTERN (insn)); + + switch (get_attr_type (insn)) + { + case TYPE_MAC: + case TYPE_DMAC: + if (REG_P (XEXP (exp, 0))) + return XEXP (exp, 1); + else + return XEXP (exp, 0); + + default: + gcc_unreachable (); + } +} + +/* Check if the DIV insn needs two write ports. */ +bool +divmod_p (rtx_insn *insn) +{ + gcc_assert (get_attr_type (insn) == TYPE_DIV); + + if (INSN_CODE (insn) == CODE_FOR_divmodsi4 + || INSN_CODE (insn) == CODE_FOR_udivmodsi4) + return true; + + return false; +} + +/* Extract the rtx representing the branch target to help recognize + data hazards. */ +rtx +extract_branch_target_rtx (rtx_insn *insn) +{ + gcc_assert (CALL_P (insn) || JUMP_P (insn)); + + rtx body = PATTERN (insn); + + if (GET_CODE (body) == SET) + { + /* RTXs in IF_THEN_ELSE are branch conditions. */ + if (GET_CODE (SET_SRC (body)) == IF_THEN_ELSE) + return NULL_RTX; + + return SET_SRC (body); + } + + if (GET_CODE (body) == CALL) + return XEXP (body, 0); + + if (GET_CODE (body) == PARALLEL) + { + rtx first_rtx = parallel_element (body, 0); + + if (GET_CODE (first_rtx) == SET) + return SET_SRC (first_rtx); + + if (GET_CODE (first_rtx) == CALL) + return XEXP (first_rtx, 0); + } + + /* Handle special cases of bltzal, bgezal and jralnez. */ + if (GET_CODE (body) == COND_EXEC) + { + rtx addr_rtx = XEXP (body, 1); + + if (GET_CODE (addr_rtx) == SET) + return SET_SRC (addr_rtx); + + if (GET_CODE (addr_rtx) == PARALLEL) + { + rtx first_rtx = parallel_element (addr_rtx, 0); + + if (GET_CODE (first_rtx) == SET) + { + rtx call_rtx = SET_SRC (first_rtx); + gcc_assert (GET_CODE (call_rtx) == CALL); + + return XEXP (call_rtx, 0); + } + + if (GET_CODE (first_rtx) == CALL) + return XEXP (first_rtx, 0); + } + } + + gcc_unreachable (); +} + +/* Extract the rtx representing the branch condition to help recognize + data hazards. */ +rtx +extract_branch_condition_rtx (rtx_insn *insn) +{ + gcc_assert (CALL_P (insn) || JUMP_P (insn)); + + rtx body = PATTERN (insn); + + if (GET_CODE (body) == SET) + { + rtx if_then_else_rtx = SET_SRC (body); + + if (GET_CODE (if_then_else_rtx) == IF_THEN_ELSE) + return XEXP (if_then_else_rtx, 0); + + return NULL_RTX; + } + + if (GET_CODE (body) == COND_EXEC) + return XEXP (body, 0); + + return NULL_RTX; +} + +/* Building the CFG in later back end passes cannot call compute_bb_for_insn () + directly because calling to BLOCK_FOR_INSN (insn) when some insns have been + deleted can cause a segmentation fault. Use this function to rebuild the CFG + can avoid such issues. */ +void +compute_bb_for_insn_safe () +{ + basic_block bb; + + FOR_EACH_BB_FN (bb, cfun) + { + rtx_insn *insn, *next_insn, *last_insn; + bool after_last_insn = false; + + /* Find the last non-deleted insn. */ + for (last_insn = BB_END (bb); + PREV_INSN (last_insn) && insn_deleted_p (last_insn); + last_insn = PREV_INSN (last_insn)); + + /* Bind each insn to its BB and adjust BB_END (bb). */ + for (insn = BB_HEAD (bb); insn; insn = NEXT_INSN (insn)) + { + BLOCK_FOR_INSN (insn) = bb; + + if (insn == last_insn) + after_last_insn = true; + + next_insn = NEXT_INSN (insn); + + if (after_last_insn + && (!next_insn + || LABEL_P (next_insn) + || NOTE_INSN_BASIC_BLOCK_P (next_insn))) + { + BB_END (bb) = insn; + break; + } + } + } +} + +/* Exchange insns positions. */ +void +exchange_insns (rtx_insn *insn1, rtx_insn *insn2) +{ + if (INSN_UID (insn1) == INSN_UID (insn2)) + return; + + rtx_insn *insn1_from = insn1; + rtx_insn *insn1_to = insn1; + rtx_insn *insn2_from = insn2; + rtx_insn *insn2_to = insn2; + + if (PREV_INSN (insn1) + && INSN_CODE (PREV_INSN (insn1)) == CODE_FOR_relax_group) + insn1_from = PREV_INSN (insn1); + + if (PREV_INSN (insn2) + && INSN_CODE (PREV_INSN (insn2)) == CODE_FOR_relax_group) + insn2_from = PREV_INSN (insn2); + + if (GET_MODE (insn1) == TImode && GET_MODE (insn2) == VOIDmode) + { + PUT_MODE (insn1, VOIDmode); + PUT_MODE (insn2, TImode); + } + else if (GET_MODE (insn1) == VOIDmode && GET_MODE (insn2) == TImode) + { + PUT_MODE (insn1, TImode); + PUT_MODE (insn2, VOIDmode); + } + + if (PREV_INSN (insn1_from)) + { + rtx_insn *insn1_prev = PREV_INSN (insn1_from); + + reorder_insns (insn1_from, insn1_to, insn2); + reorder_insns (insn2_from, insn2_to, insn1_prev); + + return; + } + + gcc_assert (PREV_INSN (insn2_from)); + + rtx_insn *insn2_prev = PREV_INSN (insn2_from); + + reorder_insns (insn2_from, insn2_to, insn1); + reorder_insns (insn1_from, insn1_to, insn2_prev); + + return; +} + +} // namespace nds32 diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c index c47c122..fd9c04e 100644 --- a/gcc/config/nds32/nds32.c +++ b/gcc/config/nds32/nds32.c @@ -24,48 +24,103 @@ #include "system.h" #include "coretypes.h" #include "backend.h" -#include "target.h" -#include "rtl.h" #include "tree.h" +#include "rtl.h" #include "df.h" -#include "tm_p.h" -#include "optabs.h" /* For GEN_FCN. */ -#include "regs.h" -#include "emit-rtl.h" -#include "recog.h" -#include "diagnostic-core.h" +#include "alias.h" +#include "stringpool.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 "cfgloop.h" +#include "cfghooks.h" +#include "hw-doloop.h" +#include "context.h" +#include "sched-int.h" /* This file should be included last. */ #include "target-def.h" /* ------------------------------------------------------------------------ */ -/* This file is divided into five parts: +/* This file is divided into six parts: - PART 1: Auxiliary static variable definitions and - target hook static variable definitions. + PART 1: Auxiliary external function and variable declarations. - PART 2: Auxiliary static function definitions. + PART 2: Auxiliary static variable definitions and + target hook static variable definitions. - PART 3: Implement target hook stuff definitions. + PART 3: Auxiliary static function definitions. - PART 4: Implemet extern function definitions, - the prototype is in nds32-protos.h. + PART 4: Implement target hook stuff definitions. - PART 5: Initialize target hook structure and definitions. */ + PART 5: Implemet extern function definitions, + the prototype is in nds32-protos.h. + + PART 6: Initialize target hook structure and definitions. */ + +/* ------------------------------------------------------------------------ */ + +/* PART 1: Auxiliary function and variable declarations. */ + +namespace nds32 { +namespace scheduling { + +rtl_opt_pass *make_pass_nds32_print_stalls (gcc::context *); + +} // namespace scheduling +} // namespace nds32 + +rtl_opt_pass *make_pass_nds32_fp_as_gp (gcc::context *); +rtl_opt_pass *make_pass_nds32_load_store_opt (gcc::context *); +rtl_opt_pass *make_pass_nds32_soft_fp_arith_comm_opt(gcc::context *); +rtl_opt_pass *make_pass_nds32_regrename_opt (gcc::context *); +rtl_opt_pass *make_pass_nds32_gcse_opt (gcc::context *); +rtl_opt_pass *make_pass_nds32_relax_opt (gcc::context *); +rtl_opt_pass *make_pass_nds32_rename_lmwsmw_opt (gcc::context *); +rtl_opt_pass *make_pass_nds32_gen_lmwsmw_opt (gcc::context *); +rtl_opt_pass *make_pass_nds32_const_remater_opt (gcc::context *); +rtl_opt_pass *make_pass_nds32_cprop_acc_opt (gcc::context *); + +gimple_opt_pass *make_pass_nds32_sign_conversion_opt (gcc::context *); +gimple_opt_pass *make_pass_nds32_scalbn_transform_opt (gcc::context *); +gimple_opt_pass *make_pass_nds32_abi_compatible (gcc::context *); /* ------------------------------------------------------------------------ */ -/* PART 1: Auxiliary static variable definitions and - target hook static variable definitions. */ +/* PART 2: Auxiliary static variable definitions and + target hook static variable definitions. */ /* Define intrinsic register names. Please refer to nds32_intrinsic.h file, the index is corresponding to @@ -73,14 +128,217 @@ NOTE that the base value starting from 1024. */ static const char * const nds32_intrinsic_register_names[] = { - "$PSW", "$IPSW", "$ITYPE", "$IPC" + "$CPU_VER", + "$ICM_CFG", + "$DCM_CFG", + "$MMU_CFG", + "$MSC_CFG", + "$MSC_CFG2", + "$CORE_ID", + "$FUCOP_EXIST", + + "$PSW", + "$IPSW", + "$P_IPSW", + "$IVB", + "$EVA", + "$P_EVA", + "$ITYPE", + "$P_ITYPE", + + "$MERR", + "$IPC", + "$P_IPC", + "$OIPC", + "$P_P0", + "$P_P1", + + "$INT_MASK", + "$INT_MASK2", + "$INT_MASK3", + "$INT_PEND", + "$INT_PEND2", + "$INT_PEND3", + "$SP_USR", + "$SP_PRIV", + "$INT_PRI", + "$INT_PRI2", + "$INT_PRI3", + "$INT_PRI4", + "$INT_CTRL", + "$INT_TRIGGER", + "$INT_TRIGGER2", + "$INT_GPR_PUSH_DIS", + + "$MMU_CTL", + "$L1_PPTB", + "$TLB_VPN", + "$TLB_DATA", + "$TLB_MISC", + "$VLPT_IDX", + "$ILMB", + "$DLMB", + + "$CACHE_CTL", + "$HSMP_SADDR", + "$HSMP_EADDR", + "$SDZ_CTL", + "$N12MISC_CTL", + "$MISC_CTL", + "$ECC_MISC", + + "$BPC0", + "$BPC1", + "$BPC2", + "$BPC3", + "$BPC4", + "$BPC5", + "$BPC6", + "$BPC7", + + "$BPA0", + "$BPA1", + "$BPA2", + "$BPA3", + "$BPA4", + "$BPA5", + "$BPA6", + "$BPA7", + + "$BPAM0", + "$BPAM1", + "$BPAM2", + "$BPAM3", + "$BPAM4", + "$BPAM5", + "$BPAM6", + "$BPAM7", + + "$BPV0", + "$BPV1", + "$BPV2", + "$BPV3", + "$BPV4", + "$BPV5", + "$BPV6", + "$BPV7", + + "$BPCID0", + "$BPCID1", + "$BPCID2", + "$BPCID3", + "$BPCID4", + "$BPCID5", + "$BPCID6", + "$BPCID7", + + "$EDM_CFG", + "$EDMSW", + "$EDM_CTL", + "$EDM_DTR", + "$BPMTC", + "$DIMBR", + + "$TECR0", + "$TECR1", + "$PFMC0", + "$PFMC1", + "$PFMC2", + "$PFM_CTL", + "$PFT_CTL", + "$HSP_CTL", + "$SP_BOUND", + "$SP_BOUND_PRIV", + "$SP_BASE", + "$SP_BASE_PRIV", + "$FUCOP_CTL", + "$PRUSR_ACC_CTL", + + "$DMA_CFG", + "$DMA_GCSW", + "$DMA_CHNSEL", + "$DMA_ACT", + "$DMA_SETUP", + "$DMA_ISADDR", + "$DMA_ESADDR", + "$DMA_TCNT", + "$DMA_STATUS", + "$DMA_2DSET", + "$DMA_2DSCTL", + "$DMA_RCNT", + "$DMA_HSTATUS", + + "$PC", + "$SP_USR1", + "$SP_USR2", + "$SP_USR3", + "$SP_PRIV1", + "$SP_PRIV2", + "$SP_PRIV3", + "$BG_REGION", + "$SFCR", + "$SIGN", + "$ISIGN", + "$P_ISIGN", + "$IFC_LP", + "$ITB" +}; + +/* Define instrinsic cctl names. */ +static const char * const nds32_cctl_names[] = +{ + "L1D_VA_FILLCK", + "L1D_VA_ULCK", + "L1I_VA_FILLCK", + "L1I_VA_ULCK", + + "L1D_IX_WBINVAL", + "L1D_IX_INVAL", + "L1D_IX_WB", + "L1I_IX_INVAL", + + "L1D_VA_INVAL", + "L1D_VA_WB", + "L1D_VA_WBINVAL", + "L1I_VA_INVAL", + + "L1D_IX_RTAG", + "L1D_IX_RWD", + "L1I_IX_RTAG", + "L1I_IX_RWD", + + "L1D_IX_WTAG", + "L1D_IX_WWD", + "L1I_IX_WTAG", + "L1I_IX_WWD" +}; + +static const char * const nds32_dpref_names[] = +{ + "SRD", + "MRD", + "SWR", + "MWR", + "PTE", + "CLWR" +}; + +/* Defining register allocation order for performance. + We want to allocate callee-saved registers after others. + It may be used by nds32_adjust_reg_alloc_order(). */ +static const int nds32_reg_alloc_order_for_speed[] = +{ + 0, 1, 2, 3, 4, 5, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15 }; /* Defining target-specific uses of __attribute__. */ static const struct attribute_spec nds32_attribute_table[] = { /* Syntax: { name, min_len, max_len, decl_required, type_required, - function_type_required, handler, affects_type_identity } */ + function_type_required, handler, affects_type_identity } */ /* The interrupt vid: [0-63]+ (actual vector number starts from 9 to 72). */ { "interrupt", 1, 64, false, false, false, NULL, false }, @@ -93,6 +351,7 @@ static const struct attribute_spec nds32_attribute_table[] = { "nested", 0, 0, false, false, false, NULL, false }, { "not_nested", 0, 0, false, false, false, NULL, false }, { "nested_ready", 0, 0, false, false, false, NULL, false }, + { "critical", 0, 0, false, false, false, NULL, false }, /* The attributes describing isr register save scheme. */ { "save_all", 0, 0, false, false, false, NULL, false }, @@ -102,17 +361,32 @@ static const struct attribute_spec nds32_attribute_table[] = { "nmi", 1, 1, false, false, false, NULL, false }, { "warm", 1, 1, false, false, false, NULL, false }, + /* The attributes describing isr security level. */ + { "secure", 1, 1, false, false, false, NULL, false }, + /* The attribute telling no prologue/epilogue. */ { "naked", 0, 0, false, false, false, NULL, false }, + /* The attribute is used to set signature. */ + { "signature", 0, 0, false, false, false, NULL, false }, + + /* The attribute is used to tell this function to be ROM patch. */ + { "indirect_call",0, 0, false, false, false, NULL, false }, + + /* FOR BACKWARD COMPATIBILITY, + this attribute also tells no prologue/epilogue. */ + { "no_prologue", 0, 0, false, false, false, NULL, false }, + + /* The attribute turn off hwloop optimization. */ + { "no_ext_zol", 0, 0, false, false, false, NULL, false}, + /* The last attribute spec is set to be NULL. */ { NULL, 0, 0, false, false, false, NULL, false } }; - /* ------------------------------------------------------------------------ */ -/* PART 2: Auxiliary static function definitions. */ +/* PART 3: Auxiliary static function definitions. */ /* Function to save and restore machine-specific function data. */ static struct machine_function * @@ -121,12 +395,24 @@ nds32_init_machine_status (void) struct machine_function *machine; machine = ggc_cleared_alloc (); + /* Initially assume this function does not use __builtin_eh_return. */ + machine->use_eh_return_p = 0; + /* Initially assume this function needs prologue/epilogue. */ machine->naked_p = 0; /* Initially assume this function does NOT use fp_as_gp optimization. */ machine->fp_as_gp_p = 0; + /* Initially this function is not under strictly aligned situation. */ + machine->strict_aligned_p = 0; + + /* Initially this function has no naked and no_prologue attributes. */ + machine->attr_naked_p = 0; + machine->attr_no_prologue_p = 0; + + /* Initially this function hwloop group ID number. */ + machine->hwloop_group_id = 0; return machine; } @@ -137,23 +423,63 @@ nds32_compute_stack_frame (void) { int r; int block_size; + bool v3pushpop_p; /* Because nds32_compute_stack_frame() will be called from different place, everytime we enter this function, we have to assume this function needs prologue/epilogue. */ cfun->machine->naked_p = 0; + /* We need to mark whether this function has naked and no_prologue + attribute so that we can distinguish the difference if users applies + -mret-in-naked-func option. */ + cfun->machine->attr_naked_p + = lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) + ? 1 : 0; + cfun->machine->attr_no_prologue_p + = lookup_attribute ("no_prologue", DECL_ATTRIBUTES (current_function_decl)) + ? 1 : 0; + + /* If __builtin_eh_return is used, we better have frame pointer needed + so that we can easily locate the stack slot of return address. */ + if (crtl->calls_eh_return) + { + frame_pointer_needed = 1; + + /* We need to mark eh data registers that need to be saved + in the stack. */ + cfun->machine->eh_return_data_first_regno = EH_RETURN_DATA_REGNO (0); + for (r = 0; EH_RETURN_DATA_REGNO (r) != INVALID_REGNUM; r++) + cfun->machine->eh_return_data_last_regno = r; + + cfun->machine->eh_return_data_regs_size + = 4 * (cfun->machine->eh_return_data_last_regno + - cfun->machine->eh_return_data_first_regno + + 1); + cfun->machine->use_eh_return_p = 1; + } + else + { + /* Assigning SP_REGNUM to eh_first_regno and eh_last_regno means we + do not need to handle __builtin_eh_return case in this function. */ + cfun->machine->eh_return_data_first_regno = SP_REGNUM; + cfun->machine->eh_return_data_last_regno = SP_REGNUM; + + cfun->machine->eh_return_data_regs_size = 0; + cfun->machine->use_eh_return_p = 0; + } + /* Get variadic arguments size to prepare pretend arguments and we will push them into stack at prologue by ourself. */ cfun->machine->va_args_size = crtl->args.pretend_args_size; if (cfun->machine->va_args_size != 0) { cfun->machine->va_args_first_regno - = NDS32_GPR_ARG_FIRST_REGNUM - + NDS32_MAX_GPR_REGS_FOR_ARGS - - (crtl->args.pretend_args_size / UNITS_PER_WORD); + = NDS32_GPR_ARG_FIRST_REGNUM + + NDS32_MAX_GPR_REGS_FOR_ARGS + - (crtl->args.pretend_args_size / UNITS_PER_WORD); cfun->machine->va_args_last_regno - = NDS32_GPR_ARG_FIRST_REGNUM + NDS32_MAX_GPR_REGS_FOR_ARGS - 1; + = NDS32_GPR_ARG_FIRST_REGNUM + NDS32_MAX_GPR_REGS_FOR_ARGS - 1; } else { @@ -183,11 +509,13 @@ nds32_compute_stack_frame (void) /* If $gp value is required to be saved on stack, it needs 4 bytes space. Check whether we are using PIC code genration. */ - cfun->machine->gp_size = (flag_pic) ? 4 : 0; + cfun->machine->gp_size = + (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM)) ? 4 : 0; /* If $lp value is required to be saved on stack, it needs 4 bytes space. Check whether $lp is ever live. */ - cfun->machine->lp_size = (df_regs_ever_live_p (LP_REGNUM)) ? 4 : 0; + cfun->machine->lp_size + = (flag_always_save_lp || df_regs_ever_live_p (LP_REGNUM)) ? 4 : 0; /* Initially there is no padding bytes. */ cfun->machine->callee_saved_area_gpr_padding_bytes = 0; @@ -196,6 +524,10 @@ nds32_compute_stack_frame (void) cfun->machine->callee_saved_gpr_regs_size = 0; cfun->machine->callee_saved_first_gpr_regno = SP_REGNUM; cfun->machine->callee_saved_last_gpr_regno = SP_REGNUM; + cfun->machine->callee_saved_fpr_regs_size = 0; + cfun->machine->callee_saved_first_fpr_regno = SP_REGNUM; + cfun->machine->callee_saved_last_fpr_regno = SP_REGNUM; + /* Currently, there is no need to check $r28~$r31 because we will save them in another way. */ for (r = 0; r < 28; r++) @@ -213,43 +545,77 @@ nds32_compute_stack_frame (void) } } + /* Recording fpu callee-saved register. */ + if (TARGET_HARD_FLOAT) + { + for (r = NDS32_FIRST_FPR_REGNUM; r < NDS32_LAST_FPR_REGNUM; r++) + { + if (NDS32_REQUIRED_CALLEE_SAVED_P (r)) + { + /* Mark the first required callee-saved register. */ + if (cfun->machine->callee_saved_first_fpr_regno == SP_REGNUM) + { + /* Make first callee-saved number is even, + bacause we use doubleword access, and this way + promise 8-byte alignemt. */ + if (!NDS32_FPR_REGNO_OK_FOR_DOUBLE (r)) + cfun->machine->callee_saved_first_fpr_regno = r - 1; + else + cfun->machine->callee_saved_first_fpr_regno = r; + } + cfun->machine->callee_saved_last_fpr_regno = r; + } + } + + /* Make last callee-saved register number is odd, + we hope callee-saved register is even. */ + int last_fpr = cfun->machine->callee_saved_last_fpr_regno; + if (NDS32_FPR_REGNO_OK_FOR_DOUBLE (last_fpr)) + cfun->machine->callee_saved_last_fpr_regno++; + } + /* Check if this function can omit prologue/epilogue code fragment. - If there is 'naked' attribute in this function, + If there is 'no_prologue'/'naked'/'secure' attribute in this function, we can set 'naked_p' flag to indicate that we do not have to generate prologue/epilogue. Or, if all the following conditions succeed, we can set this function 'naked_p' as well: condition 1: first_regno == last_regno == SP_REGNUM, - which means we do not have to save - any callee-saved registers. + which means we do not have to save + any callee-saved registers. condition 2: Both $lp and $fp are NOT live in this function, - which means we do not need to save them and there - is no outgoing size. + which means we do not need to save them and there + is no outgoing size. condition 3: There is no local_size, which means - we do not need to adjust $sp. */ - if (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) + we do not need to adjust $sp. */ + if (lookup_attribute ("no_prologue", DECL_ATTRIBUTES (current_function_decl)) + || lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) + || lookup_attribute ("secure", DECL_ATTRIBUTES (current_function_decl)) || (cfun->machine->callee_saved_first_gpr_regno == SP_REGNUM && cfun->machine->callee_saved_last_gpr_regno == SP_REGNUM + && cfun->machine->callee_saved_first_fpr_regno == SP_REGNUM + && cfun->machine->callee_saved_last_fpr_regno == SP_REGNUM && !df_regs_ever_live_p (FP_REGNUM) && !df_regs_ever_live_p (LP_REGNUM) - && cfun->machine->local_size == 0)) + && cfun->machine->local_size == 0 + && !flag_pic)) { /* Set this function 'naked_p' and other functions can check this flag. - Note that in nds32 port, the 'naked_p = 1' JUST means there is no - callee-saved, local size, and outgoing size. - The varargs space and ret instruction may still present in - the prologue/epilogue expanding. */ + Note that in nds32 port, the 'naked_p = 1' JUST means there is no + callee-saved, local size, and outgoing size. + The varargs space and ret instruction may still present in + the prologue/epilogue expanding. */ cfun->machine->naked_p = 1; /* No need to save $fp, $gp, and $lp. - We should set these value to be zero - so that nds32_initial_elimination_offset() can work properly. */ + We should set these value to be zero + so that nds32_initial_elimination_offset() can work properly. */ cfun->machine->fp_size = 0; cfun->machine->gp_size = 0; cfun->machine->lp_size = 0; /* If stack usage computation is required, - we need to provide the static stack size. */ + we need to provide the static stack size. */ if (flag_stack_usage_info) current_function_static_stack_size = 0; @@ -257,6 +623,8 @@ nds32_compute_stack_frame (void) return; } + v3pushpop_p = NDS32_V3PUSH_AVAILABLE_P; + /* Adjustment for v3push instructions: If we are using v3push (push25/pop25) instructions, we need to make sure Rb is $r6 and Re is @@ -264,16 +632,14 @@ nds32_compute_stack_frame (void) Some results above will be discarded and recomputed. Note that it is only available under V3/V3M ISA and we DO NOT setup following stuff for isr or variadic function. */ - if (TARGET_V3PUSH - && !nds32_isr_function_p (current_function_decl) - && (cfun->machine->va_args_size == 0)) + if (v3pushpop_p) { /* Recompute: - cfun->machine->fp_size - cfun->machine->gp_size - cfun->machine->lp_size - cfun->machine->callee_saved_regs_first_regno - cfun->machine->callee_saved_regs_last_regno */ + cfun->machine->fp_size + cfun->machine->gp_size + cfun->machine->lp_size + cfun->machine->callee_saved_first_gpr_regno + cfun->machine->callee_saved_last_gpr_regno */ /* For v3push instructions, $fp, $gp, and $lp are always saved. */ cfun->machine->fp_size = 4; @@ -316,11 +682,48 @@ nds32_compute_stack_frame (void) } } - /* We have correctly set callee_saved_regs_first_regno - and callee_saved_regs_last_regno. - Initially, the callee_saved_regs_size is supposed to be 0. - As long as callee_saved_regs_last_regno is not SP_REGNUM, - we can update callee_saved_regs_size with new size. */ + int sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + + if (!v3pushpop_p + && nds32_memory_model_option == MEMORY_MODEL_FAST + && sp_adjust == 0 + && !frame_pointer_needed) + { + block_size = cfun->machine->fp_size + + cfun->machine->gp_size + + cfun->machine->lp_size; + + if (cfun->machine->callee_saved_last_gpr_regno != SP_REGNUM) + block_size += (4 * (cfun->machine->callee_saved_last_gpr_regno + - cfun->machine->callee_saved_first_gpr_regno + + 1)); + + if (!NDS32_DOUBLE_WORD_ALIGN_P (block_size)) + { + /* $r14 is last callee save register. */ + if (cfun->machine->callee_saved_last_gpr_regno + < NDS32_LAST_CALLEE_SAVE_GPR_REGNUM) + { + cfun->machine->callee_saved_last_gpr_regno++; + } + else if (cfun->machine->callee_saved_first_gpr_regno == SP_REGNUM) + { + cfun->machine->callee_saved_first_gpr_regno + = NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM; + cfun->machine->callee_saved_last_gpr_regno + = NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM; + } + } + } + + /* We have correctly set callee_saved_first_gpr_regno + and callee_saved_last_gpr_regno. + Initially, the callee_saved_gpr_regs_size is supposed to be 0. + As long as callee_saved_last_gpr_regno is not SP_REGNUM, + we can update callee_saved_gpr_regs_size with new size. */ if (cfun->machine->callee_saved_last_gpr_regno != SP_REGNUM) { /* Compute pushed size of callee-saved registers. */ @@ -330,10 +733,22 @@ nds32_compute_stack_frame (void) + 1); } + if (TARGET_HARD_FLOAT) + { + /* Compute size of callee svaed floating-point registers. */ + if (cfun->machine->callee_saved_last_fpr_regno != SP_REGNUM) + { + cfun->machine->callee_saved_fpr_regs_size + = 4 * (cfun->machine->callee_saved_last_fpr_regno + - cfun->machine->callee_saved_first_fpr_regno + + 1); + } + } + /* Important: We need to make sure that - (fp_size + gp_size + lp_size + callee_saved_regs_size) - is 8-byte alignment. - If it is not, calculate the padding bytes. */ + (fp_size + gp_size + lp_size + callee_saved_gpr_regs_size) + is 8-byte alignment. + If it is not, calculate the padding bytes. */ block_size = cfun->machine->fp_size + cfun->machine->gp_size + cfun->machine->lp_size @@ -361,14 +776,15 @@ nds32_compute_stack_frame (void) "push registers to memory", "adjust stack pointer". */ static void -nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) +nds32_emit_stack_push_multiple (unsigned Rb, unsigned Re, + bool save_fp_p, bool save_gp_p, bool save_lp_p, + bool vaarg_p) { - int regno; + unsigned regno; int extra_count; int num_use_regs; int par_index; int offset; - int save_fp, save_gp, save_lp; rtx reg; rtx mem; @@ -381,39 +797,34 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) necessary information for data analysis, so we create a parallel rtx like this: (parallel [(set (mem (plus (reg:SI SP_REGNUM) (const_int -32))) - (reg:SI Rb)) - (set (mem (plus (reg:SI SP_REGNUM) (const_int -28))) - (reg:SI Rb+1)) - ... - (set (mem (plus (reg:SI SP_REGNUM) (const_int -16))) - (reg:SI Re)) - (set (mem (plus (reg:SI SP_REGNUM) (const_int -12))) - (reg:SI FP_REGNUM)) - (set (mem (plus (reg:SI SP_REGNUM) (const_int -8))) - (reg:SI GP_REGNUM)) - (set (mem (plus (reg:SI SP_REGNUM) (const_int -4))) - (reg:SI LP_REGNUM)) - (set (reg:SI SP_REGNUM) - (plus (reg:SI SP_REGNUM) (const_int -32)))]) */ - - /* Determine whether we need to save $fp, $gp, or $lp. */ - save_fp = INTVAL (En4) & 0x8; - save_gp = INTVAL (En4) & 0x4; - save_lp = INTVAL (En4) & 0x2; + (reg:SI Rb)) + (set (mem (plus (reg:SI SP_REGNUM) (const_int -28))) + (reg:SI Rb+1)) + ... + (set (mem (plus (reg:SI SP_REGNUM) (const_int -16))) + (reg:SI Re)) + (set (mem (plus (reg:SI SP_REGNUM) (const_int -12))) + (reg:SI FP_REGNUM)) + (set (mem (plus (reg:SI SP_REGNUM) (const_int -8))) + (reg:SI GP_REGNUM)) + (set (mem (plus (reg:SI SP_REGNUM) (const_int -4))) + (reg:SI LP_REGNUM)) + (set (reg:SI SP_REGNUM) + (plus (reg:SI SP_REGNUM) (const_int -32)))]) */ /* Calculate the number of registers that will be pushed. */ extra_count = 0; - if (save_fp) + if (save_fp_p) extra_count++; - if (save_gp) + if (save_gp_p) extra_count++; - if (save_lp) + if (save_lp_p) extra_count++; /* Note that Rb and Re may be SP_REGNUM. DO NOT count it in. */ - if (REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM) + if (Rb == SP_REGNUM && Re == SP_REGNUM) num_use_regs = extra_count; else - num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + extra_count; + num_use_regs = Re - Rb + 1 + extra_count; /* In addition to used registers, we need one more space for (set sp sp-x) rtx. */ @@ -425,10 +836,10 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) offset = -(num_use_regs * 4); /* Create (set mem regX) from Rb, Rb+1 up to Re. */ - for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++) + for (regno = Rb; regno <= Re; regno++) { /* Rb and Re may be SP_REGNUM. - We need to break this loop immediately. */ + We need to break this loop immediately. */ if (regno == SP_REGNUM) break; @@ -444,7 +855,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) } /* Create (set mem fp), (set mem gp), and (set mem lp) if necessary. */ - if (save_fp) + if (save_fp_p) { reg = gen_rtx_REG (SImode, FP_REGNUM); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -456,7 +867,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) offset = offset + 4; par_index++; } - if (save_gp) + if (save_gp_p) { reg = gen_rtx_REG (SImode, GP_REGNUM); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -468,7 +879,7 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) offset = offset + 4; par_index++; } - if (save_lp) + if (save_lp_p) { reg = gen_rtx_REG (SImode, LP_REGNUM); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -514,14 +925,14 @@ nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p) "pop registers from memory", "adjust stack pointer". */ static void -nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) +nds32_emit_stack_pop_multiple (unsigned Rb, unsigned Re, + bool save_fp_p, bool save_gp_p, bool save_lp_p) { - int regno; + unsigned regno; int extra_count; int num_use_regs; int par_index; int offset; - int save_fp, save_gp, save_lp; rtx reg; rtx mem; @@ -534,39 +945,34 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) necessary information for data analysis, so we create a parallel rtx like this: (parallel [(set (reg:SI Rb) - (mem (reg:SI SP_REGNUM))) - (set (reg:SI Rb+1) - (mem (plus (reg:SI SP_REGNUM) (const_int 4)))) - ... - (set (reg:SI Re) - (mem (plus (reg:SI SP_REGNUM) (const_int 16)))) - (set (reg:SI FP_REGNUM) - (mem (plus (reg:SI SP_REGNUM) (const_int 20)))) - (set (reg:SI GP_REGNUM) - (mem (plus (reg:SI SP_REGNUM) (const_int 24)))) - (set (reg:SI LP_REGNUM) - (mem (plus (reg:SI SP_REGNUM) (const_int 28)))) - (set (reg:SI SP_REGNUM) - (plus (reg:SI SP_REGNUM) (const_int 32)))]) */ - - /* Determine whether we need to restore $fp, $gp, or $lp. */ - save_fp = INTVAL (En4) & 0x8; - save_gp = INTVAL (En4) & 0x4; - save_lp = INTVAL (En4) & 0x2; + (mem (reg:SI SP_REGNUM))) + (set (reg:SI Rb+1) + (mem (plus (reg:SI SP_REGNUM) (const_int 4)))) + ... + (set (reg:SI Re) + (mem (plus (reg:SI SP_REGNUM) (const_int 16)))) + (set (reg:SI FP_REGNUM) + (mem (plus (reg:SI SP_REGNUM) (const_int 20)))) + (set (reg:SI GP_REGNUM) + (mem (plus (reg:SI SP_REGNUM) (const_int 24)))) + (set (reg:SI LP_REGNUM) + (mem (plus (reg:SI SP_REGNUM) (const_int 28)))) + (set (reg:SI SP_REGNUM) + (plus (reg:SI SP_REGNUM) (const_int 32)))]) */ /* Calculate the number of registers that will be poped. */ extra_count = 0; - if (save_fp) + if (save_fp_p) extra_count++; - if (save_gp) + if (save_gp_p) extra_count++; - if (save_lp) + if (save_lp_p) extra_count++; /* Note that Rb and Re may be SP_REGNUM. DO NOT count it in. */ - if (REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM) + if (Rb == SP_REGNUM && Re == SP_REGNUM) num_use_regs = extra_count; else - num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + extra_count; + num_use_regs = Re - Rb + 1 + extra_count; /* In addition to used registers, we need one more space for (set sp sp+x) rtx. */ @@ -578,10 +984,10 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) offset = 0; /* Create (set regX mem) from Rb, Rb+1 up to Re. */ - for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++) + for (regno = Rb; regno <= Re; regno++) { /* Rb and Re may be SP_REGNUM. - We need to break this loop immediately. */ + We need to break this loop immediately. */ if (regno == SP_REGNUM) break; @@ -599,7 +1005,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) } /* Create (set fp mem), (set gp mem), and (set lp mem) if necessary. */ - if (save_fp) + if (save_fp_p) { reg = gen_rtx_REG (SImode, FP_REGNUM); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -613,7 +1019,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf); } - if (save_gp) + if (save_gp_p) { reg = gen_rtx_REG (SImode, GP_REGNUM); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -627,7 +1033,7 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf); } - if (save_lp) + if (save_lp_p) { reg = gen_rtx_REG (SImode, LP_REGNUM); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -670,12 +1076,11 @@ nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4) "push registers to memory", "adjust stack pointer". */ static void -nds32_emit_stack_v3push (rtx Rb, - rtx Re, - rtx En4 ATTRIBUTE_UNUSED, - rtx imm8u) +nds32_emit_stack_v3push (unsigned Rb, + unsigned Re, + unsigned imm8u) { - int regno; + unsigned regno; int num_use_regs; int par_index; int offset; @@ -690,27 +1095,27 @@ nds32_emit_stack_v3push (rtx Rb, necessary information for data analysis, so we create a parallel rtx like this: (parallel [(set (mem (plus (reg:SI SP_REGNUM) (const_int -32))) - (reg:SI Rb)) - (set (mem (plus (reg:SI SP_REGNUM) (const_int -28))) - (reg:SI Rb+1)) - ... - (set (mem (plus (reg:SI SP_REGNUM) (const_int -16))) - (reg:SI Re)) - (set (mem (plus (reg:SI SP_REGNUM) (const_int -12))) - (reg:SI FP_REGNUM)) - (set (mem (plus (reg:SI SP_REGNUM) (const_int -8))) - (reg:SI GP_REGNUM)) - (set (mem (plus (reg:SI SP_REGNUM) (const_int -4))) - (reg:SI LP_REGNUM)) - (set (reg:SI SP_REGNUM) - (plus (reg:SI SP_REGNUM) (const_int -32-imm8u)))]) */ + (reg:SI Rb)) + (set (mem (plus (reg:SI SP_REGNUM) (const_int -28))) + (reg:SI Rb+1)) + ... + (set (mem (plus (reg:SI SP_REGNUM) (const_int -16))) + (reg:SI Re)) + (set (mem (plus (reg:SI SP_REGNUM) (const_int -12))) + (reg:SI FP_REGNUM)) + (set (mem (plus (reg:SI SP_REGNUM) (const_int -8))) + (reg:SI GP_REGNUM)) + (set (mem (plus (reg:SI SP_REGNUM) (const_int -4))) + (reg:SI LP_REGNUM)) + (set (reg:SI SP_REGNUM) + (plus (reg:SI SP_REGNUM) (const_int -32-imm8u)))]) */ /* Calculate the number of registers that will be pushed. Since $fp, $gp, and $lp is always pushed with v3push instruction, we need to count these three registers. Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14. So there is no need to worry about Rb=Re=SP_REGNUM case. */ - num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + 3; + num_use_regs = Re - Rb + 1 + 3; /* In addition to used registers, we need one more space for (set sp sp-x-imm8u) rtx. */ @@ -724,7 +1129,7 @@ nds32_emit_stack_v3push (rtx Rb, /* Create (set mem regX) from Rb, Rb+1 up to Re. Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14. So there is no need to worry about Rb=Re=SP_REGNUM case. */ - for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++) + for (regno = Rb; regno <= Re; regno++) { reg = gen_rtx_REG (SImode, regno); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -776,7 +1181,7 @@ nds32_emit_stack_v3push (rtx Rb, = gen_rtx_SET (stack_pointer_rtx, plus_constant (Pmode, stack_pointer_rtx, - offset - INTVAL (imm8u))); + offset - imm8u)); XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx; RTX_FRAME_RELATED_P (adjust_sp_rtx) = 1; @@ -794,12 +1199,11 @@ nds32_emit_stack_v3push (rtx Rb, "pop registers from memory", "adjust stack pointer". */ static void -nds32_emit_stack_v3pop (rtx Rb, - rtx Re, - rtx En4 ATTRIBUTE_UNUSED, - rtx imm8u) +nds32_emit_stack_v3pop (unsigned Rb, + unsigned Re, + unsigned imm8u) { - int regno; + unsigned regno; int num_use_regs; int par_index; int offset; @@ -815,27 +1219,27 @@ nds32_emit_stack_v3pop (rtx Rb, necessary information for data analysis, so we create a parallel rtx like this: (parallel [(set (reg:SI Rb) - (mem (reg:SI SP_REGNUM))) - (set (reg:SI Rb+1) - (mem (plus (reg:SI SP_REGNUM) (const_int 4)))) - ... - (set (reg:SI Re) - (mem (plus (reg:SI SP_REGNUM) (const_int 16)))) - (set (reg:SI FP_REGNUM) - (mem (plus (reg:SI SP_REGNUM) (const_int 20)))) - (set (reg:SI GP_REGNUM) - (mem (plus (reg:SI SP_REGNUM) (const_int 24)))) - (set (reg:SI LP_REGNUM) - (mem (plus (reg:SI SP_REGNUM) (const_int 28)))) - (set (reg:SI SP_REGNUM) - (plus (reg:SI SP_REGNUM) (const_int 32+imm8u)))]) */ + (mem (reg:SI SP_REGNUM))) + (set (reg:SI Rb+1) + (mem (plus (reg:SI SP_REGNUM) (const_int 4)))) + ... + (set (reg:SI Re) + (mem (plus (reg:SI SP_REGNUM) (const_int 16)))) + (set (reg:SI FP_REGNUM) + (mem (plus (reg:SI SP_REGNUM) (const_int 20)))) + (set (reg:SI GP_REGNUM) + (mem (plus (reg:SI SP_REGNUM) (const_int 24)))) + (set (reg:SI LP_REGNUM) + (mem (plus (reg:SI SP_REGNUM) (const_int 28)))) + (set (reg:SI SP_REGNUM) + (plus (reg:SI SP_REGNUM) (const_int 32+imm8u)))]) */ /* Calculate the number of registers that will be poped. Since $fp, $gp, and $lp is always poped with v3pop instruction, we need to count these three registers. Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14. So there is no need to worry about Rb=Re=SP_REGNUM case. */ - num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + 3; + num_use_regs = Re - Rb + 1 + 3; /* In addition to used registers, we need one more space for (set sp sp+x+imm8u) rtx. */ @@ -849,7 +1253,7 @@ nds32_emit_stack_v3pop (rtx Rb, /* Create (set regX mem) from Rb, Rb+1 up to Re. Under v3pop, Rb is $r6, while Re is $r6, $r8, $r10, or $r14. So there is no need to worry about Rb=Re=SP_REGNUM case. */ - for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++) + for (regno = Rb; regno <= Re; regno++) { reg = gen_rtx_REG (SImode, regno); mem = gen_frame_mem (SImode, plus_constant (Pmode, @@ -907,11 +1311,24 @@ nds32_emit_stack_v3pop (rtx Rb, = gen_rtx_SET (stack_pointer_rtx, plus_constant (Pmode, stack_pointer_rtx, - offset + INTVAL (imm8u))); + offset + imm8u)); XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx; - /* Tell gcc we adjust SP in this insn. */ - dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, copy_rtx (adjust_sp_rtx), dwarf); + if (frame_pointer_needed) + { + /* (expr_list:REG_CFA_DEF_CFA (plus:SI (reg/f:SI $sp) + (const_int 0)) + mean reset frame pointer to $sp and reset to offset 0. */ + rtx cfa_adjust_rtx = gen_rtx_PLUS (Pmode, stack_pointer_rtx, + const0_rtx); + dwarf = alloc_reg_note (REG_CFA_DEF_CFA, cfa_adjust_rtx, dwarf); + } + else + { + /* Tell gcc we adjust SP in this insn. */ + dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, + copy_rtx (adjust_sp_rtx), dwarf); + } parallel_insn = emit_insn (parallel_insn); @@ -924,6 +1341,32 @@ nds32_emit_stack_v3pop (rtx Rb, REG_NOTES (parallel_insn) = dwarf; } +static void +nds32_emit_load_gp (void) +{ + rtx got_symbol, pat; + + /* Initial GLOBAL OFFSET TABLE don't do the scheduling. */ + emit_insn (gen_blockage ()); + + got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); + /* sethi $gp, _GLOBAL_OFFSET_TABLE_ -8 */ + pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, got_symbol), UNSPEC_GOTINIT); + pat = gen_rtx_CONST (SImode, gen_rtx_PLUS (Pmode, pat, GEN_INT (-8))); + emit_insn (gen_sethi (pic_offset_table_rtx,pat)); + + /* ori $gp, $gp, _GLOBAL_OFFSET_TABLE_ -4 */ + pat = gen_rtx_UNSPEC (SImode, gen_rtvec (1, got_symbol), UNSPEC_GOTINIT); + pat = gen_rtx_CONST (SImode, gen_rtx_PLUS (Pmode, pat, GEN_INT (-4))); + emit_insn (gen_lo_sum (pic_offset_table_rtx, pic_offset_table_rtx, pat)); + + /* add5.pc $gp */ + emit_insn (gen_add_pc (pic_offset_table_rtx, pic_offset_table_rtx)); + + /* Initial GLOBAL OFFSET TABLE don't do the scheduling. */ + emit_insn (gen_blockage ()); +} + /* Function that may creates more instructions for large value on adjusting stack pointer. @@ -933,79 +1376,70 @@ nds32_emit_stack_v3pop (rtx Rb, the adjustment value is not able to be fit in the 'addi' instruction. One solution is to move value into a register and then use 'add' instruction. - In practice, we use TA_REGNUM ($r15) to accomplish this purpose. - Also, we need to return zero for sp adjustment so that - proglogue/epilogue knows there is no need to create 'addi' instruction. */ -static int -nds32_force_addi_stack_int (int full_value) + In practice, we use TA_REGNUM ($r15) to accomplish this purpose. */ +static void +nds32_emit_adjust_frame (rtx to_reg, rtx from_reg, int adjust_value) { - int adjust_value; - rtx tmp_reg; - rtx sp_adjust_insn; + rtx frame_adjust_insn; + rtx adjust_value_rtx = GEN_INT (adjust_value); + + if (adjust_value == 0) + return; - if (!satisfies_constraint_Is15 (GEN_INT (full_value))) + if (!satisfies_constraint_Is15 (adjust_value_rtx)) { /* The value is not able to fit in single addi instruction. - Create more instructions of moving value into a register - and then add stack pointer with it. */ + Create more instructions of moving value into a register + and then add stack pointer with it. */ /* $r15 is going to be temporary register to hold the value. */ tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); /* Create one more instruction to move value - into the temporary register. */ - emit_move_insn (tmp_reg, GEN_INT (full_value)); + into the temporary register. */ + emit_move_insn (tmp_reg, adjust_value_rtx); /* Create new 'add' rtx. */ - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - tmp_reg); + frame_adjust_insn = gen_addsi3 (to_reg, + from_reg, + tmp_reg); /* Emit rtx into insn list and receive its transformed insn rtx. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); - - /* At prologue, we need to tell GCC that this is frame related insn, - so that we can consider this instruction to output debug information. - If full_value is NEGATIVE, it means this function - is invoked by expand_prologue. */ - if (full_value < 0) - { - /* Because (tmp_reg <- full_value) may be split into two - rtl patterns, we can not set its RTX_FRAME_RELATED_P. - We need to construct another (sp <- sp + full_value) - and then insert it into sp_adjust_insn's reg note to - represent a frame related expression. - GCC knows how to refer it and output debug information. */ - - rtx plus_rtx; - rtx set_rtx; + frame_adjust_insn = emit_insn (frame_adjust_insn); - plus_rtx = plus_constant (Pmode, stack_pointer_rtx, full_value); - set_rtx = gen_rtx_SET (stack_pointer_rtx, plus_rtx); - add_reg_note (sp_adjust_insn, REG_FRAME_RELATED_EXPR, set_rtx); + /* Because (tmp_reg <- full_value) may be split into two + rtl patterns, we can not set its RTX_FRAME_RELATED_P. + We need to construct another (sp <- sp + full_value) + and then insert it into sp_adjust_insn's reg note to + represent a frame related expression. + GCC knows how to refer it and output debug information. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; - } + rtx plus_rtx; + rtx set_rtx; - /* We have used alternative way to adjust stack pointer value. - Return zero so that prologue/epilogue - will not generate other instructions. */ - return 0; + plus_rtx = plus_constant (Pmode, from_reg, adjust_value); + set_rtx = gen_rtx_SET (to_reg, plus_rtx); + add_reg_note (frame_adjust_insn, REG_FRAME_RELATED_EXPR, set_rtx); } else { - /* The value is able to fit in addi instruction. - However, remember to make it to be positive value - because we want to return 'adjustment' result. */ - adjust_value = (full_value < 0) ? (-full_value) : (full_value); - - return adjust_value; + /* Generate sp adjustment instruction if and only if sp_adjust != 0. */ + frame_adjust_insn = gen_addsi3 (to_reg, + from_reg, + adjust_value_rtx); + /* Emit rtx into instructions list and receive INSN rtx form. */ + frame_adjust_insn = emit_insn (frame_adjust_insn); } + + /* The insn rtx 'sp_adjust_insn' will change frame layout. + We need to use RTX_FRAME_RELATED_P so that GCC is able to + generate CFI (Call Frame Information) stuff. */ + RTX_FRAME_RELATED_P (frame_adjust_insn) = 1; } /* Return true if MODE/TYPE need double word alignment. */ static bool -nds32_needs_double_word_align (machine_mode mode, const_tree type) +nds32_needs_double_word_align (enum machine_mode mode, const_tree type) { unsigned int align; @@ -1015,18 +1449,25 @@ nds32_needs_double_word_align (machine_mode mode, const_tree type) return (align > PARM_BOUNDARY); } -/* Return true if FUNC is a naked function. */ -static bool +bool nds32_naked_function_p (tree func) { - tree t; + /* FOR BACKWARD COMPATIBILITY, + we need to support 'no_prologue' attribute as well. */ + tree t_naked; + tree t_no_prologue; if (TREE_CODE (func) != FUNCTION_DECL) abort (); - t = lookup_attribute ("naked", DECL_ATTRIBUTES (func)); + /* We have to use lookup_attribute() to check attributes. + Because attr_naked_p and attr_no_prologue_p are set in + nds32_compute_stack_frame() and the function has not been + invoked yet. */ + t_naked = lookup_attribute ("naked", DECL_ATTRIBUTES (func)); + t_no_prologue = lookup_attribute ("no_prologue", DECL_ATTRIBUTES (func)); - return (t != NULL_TREE); + return ((t_naked != NULL_TREE) || (t_no_prologue != NULL_TREE)); } /* Function that check if 'X' is a valid address register. @@ -1035,7 +1476,7 @@ nds32_naked_function_p (tree func) STRICT : true => We are in reload pass or after reload pass. - The register number should be strictly limited in general registers. + The register number should be strictly limited in general registers. STRICT : false => Before reload pass, we are free to use any register number. */ @@ -1058,10 +1499,10 @@ nds32_address_register_rtx_p (rtx x, bool strict) /* Function that check if 'INDEX' is valid to be a index rtx for address. OUTER_MODE : Machine mode of outer address rtx. - INDEX : Check if this rtx is valid to be a index for address. + INDEX : Check if this rtx is valid to be a index for address. STRICT : If it is true, we are in reload pass or after reload pass. */ static bool -nds32_legitimate_index_p (machine_mode outer_mode, +nds32_legitimate_index_p (enum machine_mode outer_mode, rtx index, bool strict) { @@ -1074,7 +1515,7 @@ nds32_legitimate_index_p (machine_mode outer_mode, case REG: regno = REGNO (index); /* If we are in reload pass or after reload pass, - we need to limit it to general register. */ + we need to limit it to general register. */ if (strict) return REGNO_OK_FOR_INDEX_P (regno); else @@ -1082,45 +1523,73 @@ nds32_legitimate_index_p (machine_mode outer_mode, case CONST_INT: /* The alignment of the integer value is determined by 'outer_mode'. */ - if (GET_MODE_SIZE (outer_mode) == 1) + switch (GET_MODE_SIZE (outer_mode)) { + case 1: /* Further check if the value is legal for the 'outer_mode'. */ - if (!satisfies_constraint_Is15 (index)) - return false; + if (satisfies_constraint_Is15 (index)) + return true; + break; - /* Pass all test, the value is valid, return true. */ - return true; - } - if (GET_MODE_SIZE (outer_mode) == 2 - && NDS32_HALF_WORD_ALIGN_P (INTVAL (index))) - { + case 2: /* Further check if the value is legal for the 'outer_mode'. */ - if (!satisfies_constraint_Is16 (index)) - return false; + if (satisfies_constraint_Is16 (index)) + { + /* If it is not under strictly aligned situation, + we can return true without checking alignment. */ + if (!cfun->machine->strict_aligned_p) + return true; + /* Make sure address is half word alignment. */ + else if (NDS32_HALF_WORD_ALIGN_P (INTVAL (index))) + return true; + } + break; - /* Pass all test, the value is valid, return true. */ - return true; - } - if (GET_MODE_SIZE (outer_mode) == 4 - && NDS32_SINGLE_WORD_ALIGN_P (INTVAL (index))) - { + case 4: /* Further check if the value is legal for the 'outer_mode'. */ - if (!satisfies_constraint_Is17 (index)) - return false; + if (satisfies_constraint_Is17 (index)) + { + if ((TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE)) + { + if (!satisfies_constraint_Is14 (index)) + return false; + } + + /* If it is not under strictly aligned situation, + we can return true without checking alignment. */ + if (!cfun->machine->strict_aligned_p) + return true; + /* Make sure address is word alignment. */ + else if (NDS32_SINGLE_WORD_ALIGN_P (INTVAL (index))) + return true; + } + break; - /* Pass all test, the value is valid, return true. */ - return true; - } - if (GET_MODE_SIZE (outer_mode) == 8 - && NDS32_SINGLE_WORD_ALIGN_P (INTVAL (index))) - { - /* Further check if the value is legal for the 'outer_mode'. */ - if (!satisfies_constraint_Is17 (gen_int_mode (INTVAL (index) + 4, - SImode))) - return false; + case 8: + if (satisfies_constraint_Is17 (gen_int_mode (INTVAL (index) + 4, + SImode))) + { + if ((TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE)) + { + if (!satisfies_constraint_Is14 (index)) + return false; + } + + /* If it is not under strictly aligned situation, + we can return true without checking alignment. */ + if (!cfun->machine->strict_aligned_p) + return true; + /* Make sure address is word alignment. + Currently we do not have 64-bit load/store yet, + so we will use two 32-bit load/store instructions to do + memory access and they are single word alignment. */ + else if (NDS32_SINGLE_WORD_ALIGN_P (INTVAL (index))) + return true; + } + break; - /* Pass all test, the value is valid, return true. */ - return true; + default: + return false; } return false; @@ -1134,9 +1603,10 @@ nds32_legitimate_index_p (machine_mode outer_mode, int multiplier; multiplier = INTVAL (op1); - /* We only allow (mult reg const_int_1) - or (mult reg const_int_2) or (mult reg const_int_4). */ - if (multiplier != 1 && multiplier != 2 && multiplier != 4) + /* We only allow (mult reg const_int_1), (mult reg const_int_2), + (mult reg const_int_4) or (mult reg const_int_8). */ + if (multiplier != 1 && multiplier != 2 + && multiplier != 4 && multiplier != 8) return false; regno = REGNO (op0); @@ -1161,8 +1631,9 @@ nds32_legitimate_index_p (machine_mode outer_mode, sv = INTVAL (op1); /* We only allow (ashift reg const_int_0) - or (ashift reg const_int_1) or (ashift reg const_int_2). */ - if (sv != 0 && sv != 1 && sv !=2) + or (ashift reg const_int_1) or (ashift reg const_int_2) or + (ashift reg const_int_3). */ + if (sv != 0 && sv != 1 && sv !=2 && sv != 3) return false; regno = REGNO (op0); @@ -1181,18 +1652,302 @@ nds32_legitimate_index_p (machine_mode outer_mode, } } +static void +nds32_insert_innermost_loop (void) +{ + struct loop *loop; + basic_block *bbs, bb; + + compute_bb_for_insn (); + /* initial loop structure */ + loop_optimizer_init (AVOID_CFG_MODIFICATIONS); + + /* Scan all inner most loops. */ + FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST) + { + bbs = get_loop_body (loop); + bb = *bbs; + free (bbs); + + emit_insn_before (gen_innermost_loop_begin (), + BB_HEAD (bb)); + + /* Find the final basic block in the loop. */ + while (bb) + { + if (bb->next_bb == NULL) + break; + + if (bb->next_bb->loop_father != loop) + break; + + bb = bb->next_bb; + } + + emit_insn_before (gen_innermost_loop_end (), + BB_END (bb)); + } + + /* release loop structre */ + loop_optimizer_finalize (); +} + +/* Insert isps for function with signature attribute. */ +static void +nds32_insert_isps (void) +{ + rtx_insn *insn; + unsigned first = 0; + + if (!lookup_attribute ("signature", DECL_ATTRIBUTES (current_function_decl))) + return; + + insn = get_insns (); + while (insn) + { + /* In order to ensure protect whole function, emit the first + isps here rather than in prologue.*/ + if (!first && INSN_P (insn)) + { + emit_insn_before (gen_unspec_signature_begin (), insn); + first = 1; + } + + if (LABEL_P (insn) || CALL_P (insn) || any_condjump_p (insn) + || (INSN_P (insn) && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE + && (XINT (PATTERN (insn), 1) == UNSPEC_VOLATILE_SYSCALL + || XINT (PATTERN (insn), 1) == UNSPEC_VOLATILE_TRAP + || XINT (PATTERN (insn), 1) == UNSPEC_VOLATILE_TEQZ + || XINT (PATTERN (insn), 1) == UNSPEC_VOLATILE_TNEZ))) + { + emit_insn_after (gen_unspec_signature_begin (), insn); + } + insn = NEXT_INSN (insn); + } +} + +static void +nds32_register_pass ( + rtl_opt_pass *(*make_pass_func) (gcc::context *), + enum pass_positioning_ops pass_pos, + const char *ref_pass_name) +{ + opt_pass *new_opt_pass = make_pass_func (g); + + struct register_pass_info insert_pass = + { + new_opt_pass, /* pass */ + ref_pass_name, /* reference_pass_name */ + 1, /* ref_pass_instance_number */ + pass_pos /* po_op */ + }; + + register_pass (&insert_pass); +} + +static void +nds32_register_pass ( + gimple_opt_pass *(*make_pass_func) (gcc::context *), + enum pass_positioning_ops pass_pos, + const char *ref_pass_name) +{ + opt_pass *new_opt_pass = make_pass_func (g); + + struct register_pass_info insert_pass = + { + new_opt_pass, /* pass */ + ref_pass_name, /* reference_pass_name */ + 1, /* ref_pass_instance_number */ + pass_pos /* po_op */ + }; + + register_pass (&insert_pass); +} + +/* This function is called from nds32_option_override (). + All new passes should be registered here. */ +static void +nds32_register_passes (void) +{ + nds32_register_pass ( + make_pass_nds32_fp_as_gp, + PASS_POS_INSERT_BEFORE, + "ira"); + + nds32_register_pass ( + make_pass_nds32_relax_opt, + PASS_POS_INSERT_AFTER, + "mach"); + + nds32_register_pass ( + make_pass_nds32_load_store_opt, + PASS_POS_INSERT_AFTER, + "mach"); + + nds32_register_pass ( + make_pass_nds32_soft_fp_arith_comm_opt, + PASS_POS_INSERT_BEFORE, + "mach"); + + nds32_register_pass ( + make_pass_nds32_regrename_opt, + PASS_POS_INSERT_AFTER, + "mach"); + + nds32_register_pass ( + make_pass_nds32_gcse_opt, + PASS_POS_INSERT_BEFORE, + "cprop_hardreg"); + + nds32_register_pass ( + make_pass_nds32_cprop_acc_opt, + PASS_POS_INSERT_AFTER, + "cprop_hardreg"); + + nds32_register_pass ( + make_pass_cprop_hardreg, + PASS_POS_INSERT_AFTER, + "mach"); + + nds32_register_pass ( + make_pass_nds32_rename_lmwsmw_opt, + PASS_POS_INSERT_AFTER, + "jump2"); + + nds32_register_pass ( + make_pass_nds32_gen_lmwsmw_opt, + PASS_POS_INSERT_BEFORE, + "peephole2"); + + nds32_register_pass ( + make_pass_nds32_const_remater_opt, + PASS_POS_INSERT_BEFORE, + "ira"); + + nds32_register_pass ( + make_pass_nds32_scalbn_transform_opt, + PASS_POS_INSERT_AFTER, + "optimized"); + + nds32_register_pass ( + make_pass_nds32_sign_conversion_opt, + PASS_POS_INSERT_BEFORE, + "optimized"); + + nds32_register_pass ( + make_pass_nds32_abi_compatible, + PASS_POS_INSERT_BEFORE, + "optimized"); + + nds32_register_pass ( + nds32::scheduling::make_pass_nds32_print_stalls, + PASS_POS_INSERT_BEFORE, + "final"); +} + /* ------------------------------------------------------------------------ */ -/* PART 3: Implement target hook stuff definitions. */ +/* PART 4: Implement target hook stuff definitions. */ + + +/* Computing the Length of an Insn. + Modifies the length assigned to instruction INSN. + LEN is the initially computed length of the insn. */ +int +nds32_adjust_insn_length (rtx_insn *insn, int length) +{ + int adjust_value = 0; + switch (recog_memoized (insn)) + { + case CODE_FOR_call_internal: + case CODE_FOR_call_value_internal: + { + if (NDS32_ALIGN_P ()) + { + rtx_insn *next_insn = next_active_insn (insn); + if (next_insn && get_attr_length (next_insn) != 2) + adjust_value += 2; + } + /* We need insert a nop after a noretun function call + to prevent software breakpoint corrupt the next function. */ + if (find_reg_note (insn, REG_NORETURN, NULL_RTX)) + { + if (TARGET_16_BIT) + adjust_value += 2; + else + adjust_value += 4; + } + } + return length + adjust_value; + + default: + return length; + } +} + +/* Storage Layout. */ + +/* This function will be called just before expansion into rtl. */ +static void +nds32_expand_to_rtl_hook (void) +{ + /* We need to set strictly aligned situation. + After that, the memory address checking in nds32_legitimate_address_p() + will take alignment offset into consideration so that it will not create + unaligned [base + offset] access during the rtl optimization. */ + cfun->machine->strict_aligned_p = 1; +} + + +/* Register Usage. */ + +static void +nds32_conditional_register_usage (void) +{ + int regno; + + if (TARGET_LINUX_ABI) + fixed_regs[TP_REGNUM] = 1; + + if (TARGET_HARD_FLOAT) + { + for (regno = NDS32_FIRST_FPR_REGNUM; + regno <= NDS32_LAST_FPR_REGNUM; regno++) + { + fixed_regs[regno] = 0; + if (regno < NDS32_FIRST_FPR_REGNUM + NDS32_MAX_FPR_REGS_FOR_ARGS) + call_used_regs[regno] = 1; + else if (regno >= NDS32_FIRST_FPR_REGNUM + 22 + && regno < NDS32_FIRST_FPR_REGNUM + 48) + call_used_regs[regno] = 1; + else + call_used_regs[regno] = 0; + } + } + else if (TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) + { + for (regno = NDS32_FIRST_FPR_REGNUM; + regno <= NDS32_LAST_FPR_REGNUM; + regno++) + fixed_regs[regno] = 0; + } +} + /* Register Classes. */ +static reg_class_t +nds32_preferred_rename_class (reg_class_t rclass) +{ + return nds32_preferred_rename_class_impl (rclass); +} + static unsigned char nds32_class_max_nregs (reg_class_t rclass ATTRIBUTE_UNUSED, - machine_mode mode) + enum machine_mode mode) { /* Return the maximum number of consecutive registers - needed to represent "mode" in a register of "rclass". */ + needed to represent MODE in a register of RCLASS. */ return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD); } @@ -1200,9 +1955,24 @@ static int nds32_register_priority (int hard_regno) { /* Encourage to use r0-r7 for LRA when optimize for size. */ - if (optimize_size && hard_regno < 8) - return 4; - return 3; + if (optimize_size) + { + if (hard_regno < 8) + return 4; + else if (hard_regno < 16) + return 3; + else if (hard_regno < 28) + return 2; + else + return 1; + } + else + { + if (hard_regno > 27) + return 1; + else + return 4; + } } @@ -1222,8 +1992,8 @@ nds32_register_priority (int hard_regno) 2. return address 3. callee-saved registers 4. (we will calculte in nds32_compute_stack_frame() - and save it at - cfun->machine->callee_saved_area_padding_bytes) + and save it at + cfun->machine->callee_saved_area_padding_bytes) [Block B] 1. local variables @@ -1241,29 +2011,29 @@ nds32_register_priority (int hard_regno) By applying the basic frame/stack/argument pointers concept, the layout of a stack frame shoule be like this: - | | + | | old stack pointer -> ---- - | | \ - | | saved arguments for - | | vararg functions - | | / + | | \ + | | saved arguments for + | | vararg functions + | | / hard frame pointer -> -- & argument pointer | | \ - | | previous hardware frame pointer - | | return address - | | callee-saved registers - | | / - frame pointer -> -- - | | \ - | | local variables - | | and incoming arguments - | | / - -- - | | \ - | | outgoing - | | arguments - | | / - stack pointer -> ---- + | | previous hardware frame pointer + | | return address + | | callee-saved registers + | | / + frame pointer -> -- + | | \ + | | local variables + | | and incoming arguments + | | / + -- + | | \ + | | outgoing + | | arguments + | | / + stack pointer -> ---- $SFP and $AP are used to represent frame pointer and arguments pointer, which will be both eliminated as hard frame pointer. */ @@ -1291,7 +2061,7 @@ nds32_can_eliminate (const int from_reg, const int to_reg) /* -- Passing Arguments in Registers. */ static rtx -nds32_function_arg (cumulative_args_t ca, machine_mode mode, +nds32_function_arg (cumulative_args_t ca, enum machine_mode mode, const_tree type, bool named) { unsigned int regno; @@ -1306,7 +2076,7 @@ nds32_function_arg (cumulative_args_t ca, machine_mode mode, if (!named) { /* If we are under hard float abi, we have arguments passed on the - stack and all situation can be handled by GCC itself. */ + stack and all situation can be handled by GCC itself. */ if (TARGET_HARD_FLOAT) return NULL_RTX; @@ -1320,7 +2090,7 @@ nds32_function_arg (cumulative_args_t ca, machine_mode mode, } /* No register available, return NULL_RTX. - The compiler will use stack to pass argument instead. */ + The compiler will use stack to pass argument instead. */ return NULL_RTX; } @@ -1329,14 +2099,34 @@ nds32_function_arg (cumulative_args_t ca, machine_mode mode, are different. */ if (TARGET_HARD_FLOAT) { - /* Currently we have not implemented hard float yet. */ - gcc_unreachable (); + /* For TARGET_HARD_FLOAT calling convention, we use GPR and FPR + to pass argument. We have to further check TYPE and MODE so + that we can determine which kind of register we shall use. */ + + /* Note that we need to pass argument entirely in registers under + hard float abi. */ + if (GET_MODE_CLASS (mode) == MODE_FLOAT + && NDS32_ARG_ENTIRE_IN_FPR_REG_P (cum->fpr_offset, mode, type)) + { + /* Pick up the next available FPR register number. */ + regno + = NDS32_AVAILABLE_REGNUM_FOR_FPR_ARG (cum->fpr_offset, mode, type); + return gen_rtx_REG (mode, regno); + } + else if (GET_MODE_CLASS (mode) != MODE_FLOAT + && NDS32_ARG_ENTIRE_IN_GPR_REG_P (cum->gpr_offset, mode, type)) + { + /* Pick up the next available GPR register number. */ + regno + = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type); + return gen_rtx_REG (mode, regno); + } } else { /* For !TARGET_HARD_FLOAT calling convention, we always use GPR to pass - argument. Since we allow to pass argument partially in registers, - we can just return it if there are still registers available. */ + argument. Since we allow to pass argument partially in registers, + we can just return it if there are still registers available. */ if (NDS32_ARG_PARTIAL_IN_GPR_REG_P (cum->gpr_offset, mode, type)) { /* Pick up the next available register number. */ @@ -1353,7 +2143,7 @@ nds32_function_arg (cumulative_args_t ca, machine_mode mode, } static bool -nds32_must_pass_in_stack (machine_mode mode, const_tree type) +nds32_must_pass_in_stack (enum machine_mode mode, const_tree type) { /* Return true if a type must be passed in memory. If it is NOT using hard float abi, small aggregates can be @@ -1366,7 +2156,7 @@ nds32_must_pass_in_stack (machine_mode mode, const_tree type) } static int -nds32_arg_partial_bytes (cumulative_args_t ca, machine_mode mode, +nds32_arg_partial_bytes (cumulative_args_t ca, enum machine_mode mode, tree type, bool named ATTRIBUTE_UNUSED) { /* Returns the number of bytes at the beginning of an argument that @@ -1400,7 +2190,7 @@ nds32_arg_partial_bytes (cumulative_args_t ca, machine_mode mode, remaining_reg_count = NDS32_MAX_GPR_REGS_FOR_ARGS - (NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type) - - NDS32_GPR_ARG_FIRST_REGNUM); + - NDS32_GPR_ARG_FIRST_REGNUM); /* Note that we have to return the nubmer of bytes, not registers count. */ if (needed_reg_count > remaining_reg_count) @@ -1410,26 +2200,23 @@ nds32_arg_partial_bytes (cumulative_args_t ca, machine_mode mode, } static void -nds32_function_arg_advance (cumulative_args_t ca, machine_mode mode, +nds32_function_arg_advance (cumulative_args_t ca, enum machine_mode mode, const_tree type, bool named) { - machine_mode sub_mode; CUMULATIVE_ARGS *cum = get_cumulative_args (ca); if (named) { /* We need to further check TYPE and MODE so that we can determine - which kind of register we shall advance. */ - if (type && TREE_CODE (type) == COMPLEX_TYPE) - sub_mode = TYPE_MODE (TREE_TYPE (type)); - else - sub_mode = mode; + which kind of register we shall advance. */ /* Under hard float abi, we may advance FPR registers. */ - if (TARGET_HARD_FLOAT && GET_MODE_CLASS (sub_mode) == MODE_FLOAT) + if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT) { - /* Currently we have not implemented hard float yet. */ - gcc_unreachable (); + cum->fpr_offset + = NDS32_AVAILABLE_REGNUM_FOR_FPR_ARG (cum->fpr_offset, mode, type) + - NDS32_FPR_ARG_FIRST_REGNUM + + NDS32_NEED_N_REGS_FOR_ARG (mode, type); } else { @@ -1442,9 +2229,9 @@ nds32_function_arg_advance (cumulative_args_t ca, machine_mode mode, else { /* If this nameless argument is NOT under TARGET_HARD_FLOAT, - we can advance next register as well so that caller is - able to pass arguments in registers and callee must be - in charge of pushing all of them into stack. */ + we can advance next register as well so that caller is + able to pass arguments in registers and callee must be + in charge of pushing all of them into stack. */ if (!TARGET_HARD_FLOAT) { cum->gpr_offset @@ -1456,13 +2243,23 @@ nds32_function_arg_advance (cumulative_args_t ca, machine_mode mode, } static unsigned int -nds32_function_arg_boundary (machine_mode mode, const_tree type) +nds32_function_arg_boundary (enum machine_mode mode, const_tree type) { return (nds32_needs_double_word_align (mode, type) ? NDS32_DOUBLE_WORD_ALIGNMENT : PARM_BOUNDARY); } +bool +nds32_vector_mode_supported_p (enum machine_mode mode) +{ + if (mode == V4QImode + || mode == V2HImode) + return NDS32_EXT_DSP_P (); + + return false; +} + /* -- How Scalar Function Values Are Returned. */ static rtx @@ -1470,28 +2267,68 @@ nds32_function_value (const_tree ret_type, const_tree fn_decl_or_type ATTRIBUTE_UNUSED, bool outgoing ATTRIBUTE_UNUSED) { - machine_mode mode; + enum machine_mode mode; int unsignedp; mode = TYPE_MODE (ret_type); unsignedp = TYPE_UNSIGNED (ret_type); - mode = promote_mode (ret_type, mode, &unsignedp); + if (INTEGRAL_TYPE_P (ret_type)) + mode = promote_mode (ret_type, mode, &unsignedp); - return gen_rtx_REG (mode, NDS32_GPR_RET_FIRST_REGNUM); + if (TARGET_HARD_FLOAT && (mode == SFmode || mode == DFmode)) + return gen_rtx_REG (mode, NDS32_FPR_RET_FIRST_REGNUM); + else + return gen_rtx_REG (mode, NDS32_GPR_RET_FIRST_REGNUM); } static rtx -nds32_libcall_value (machine_mode mode, +nds32_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) { + if (TARGET_HARD_FLOAT && (mode == SFmode || mode == DFmode)) + return gen_rtx_REG (mode, NDS32_FPR_RET_FIRST_REGNUM); + return gen_rtx_REG (mode, NDS32_GPR_RET_FIRST_REGNUM); } static bool nds32_function_value_regno_p (const unsigned int regno) { - return (regno == NDS32_GPR_RET_FIRST_REGNUM); + if (regno == NDS32_GPR_RET_FIRST_REGNUM + || (TARGET_HARD_FLOAT + && regno == NDS32_FPR_RET_FIRST_REGNUM)) + return true; + + return false; +} + +/* -- How Large Values Are Returned. */ + +static bool +nds32_return_in_memory (const_tree type, + const_tree fntype ATTRIBUTE_UNUSED) +{ + /* Note that int_size_in_bytes can return -1 if the size can vary + or is larger than an integer. */ + HOST_WIDE_INT size = int_size_in_bytes (type); + + /* For COMPLEX_TYPE, if the total size cannot be hold within two registers, + the return value is supposed to be in memory. We need to be aware of + that the size may be -1. */ + if (TREE_CODE (type) == COMPLEX_TYPE) + if (size < 0 || size > 2 * UNITS_PER_WORD) + return true; + + /* If it is BLKmode and the total size cannot be hold within two registers, + the return value is supposed to be in memory. We need to be aware of + that the size may be -1. */ + if (TYPE_MODE (type) == BLKmode) + if (size < 0 || size > 2 * UNITS_PER_WORD) + return true; + + /* For other cases, having result in memory is unnecessary. */ + return false; } /* -- Function Entry and Exit. */ @@ -1522,7 +2359,7 @@ nds32_asm_function_prologue (FILE *file, /* Use df_regs_ever_live_p() to detect if the register is ever used in the current function. */ fprintf (file, "\t! registers ever_live: "); - for (r = 0; r < 32; r++) + for (r = 0; r < 65; r++) { if (df_regs_ever_live_p (r)) fprintf (file, "%s, ", reg_names[r]); @@ -1554,6 +2391,10 @@ nds32_asm_function_prologue (FILE *file, attrs = TREE_CHAIN (attrs); } fputc ('\n', file); + + /* If there is any critical isr in this file, disable linker ifc. */ + if (nds32_isr_function_critical_p (current_function_decl)) + fprintf (file, "\t.no_relax ifc\n"); } /* After rtl prologue has been expanded, this function is used. */ @@ -1561,56 +2402,12 @@ static void nds32_asm_function_end_prologue (FILE *file) { fprintf (file, "\t! END PROLOGUE\n"); - - /* If frame pointer is NOT needed and -mfp-as-gp is issued, - we can generate special directive: ".omit_fp_begin" - to guide linker doing fp-as-gp optimization. - However, for a naked function, which means - it should not have prologue/epilogue, - using fp-as-gp still requires saving $fp by push/pop behavior and - there is no benefit to use fp-as-gp on such small function. - So we need to make sure this function is NOT naked as well. */ - if (!frame_pointer_needed - && !cfun->machine->naked_p - && cfun->machine->fp_as_gp_p) - { - fprintf (file, "\t! ----------------------------------------\n"); - fprintf (file, "\t! Guide linker to do " - "link time optimization: fp-as-gp\n"); - fprintf (file, "\t! We add one more instruction to " - "initialize $fp near to $gp location.\n"); - fprintf (file, "\t! If linker fails to use fp-as-gp transformation,\n"); - fprintf (file, "\t! this extra instruction should be " - "eliminated at link stage.\n"); - fprintf (file, "\t.omit_fp_begin\n"); - fprintf (file, "\tla\t$fp,_FP_BASE_\n"); - fprintf (file, "\t! ----------------------------------------\n"); - } } /* Before rtl epilogue has been expanded, this function is used. */ static void nds32_asm_function_begin_epilogue (FILE *file) { - /* If frame pointer is NOT needed and -mfp-as-gp is issued, - we can generate special directive: ".omit_fp_end" - to claim fp-as-gp optimization range. - However, for a naked function, - which means it should not have prologue/epilogue, - using fp-as-gp still requires saving $fp by push/pop behavior and - there is no benefit to use fp-as-gp on such small function. - So we need to make sure this function is NOT naked as well. */ - if (!frame_pointer_needed - && !cfun->machine->naked_p - && cfun->machine->fp_as_gp_p) - { - fprintf (file, "\t! ----------------------------------------\n"); - fprintf (file, "\t! Claim the range of fp-as-gp " - "link time optimization\n"); - fprintf (file, "\t.omit_fp_end\n"); - fprintf (file, "\t! ----------------------------------------\n"); - } - fprintf (file, "\t! BEGIN EPILOGUE\n"); } @@ -1638,41 +2435,104 @@ nds32_asm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, ? 1 : 0); + if (flag_pic) + { + fprintf (file, "\tsmw.adm\t$r31, [$r31], $r31, 4\n"); + fprintf (file, "\tsethi\t%s, hi20(_GLOBAL_OFFSET_TABLE_-8)\n", + reg_names [PIC_OFFSET_TABLE_REGNUM]); + fprintf (file, "\tori\t%s, %s, lo12(_GLOBAL_OFFSET_TABLE_-4)\n", + reg_names [PIC_OFFSET_TABLE_REGNUM], + reg_names [PIC_OFFSET_TABLE_REGNUM]); + + if (TARGET_ISA_V3) + fprintf (file, "\tadd5.pc\t$gp\n"); + else + { + fprintf (file, "\tmfusr\t$ta, $pc\n"); + fprintf (file, "\tadd\t%s, $ta, %s\n", + reg_names [PIC_OFFSET_TABLE_REGNUM], + reg_names [PIC_OFFSET_TABLE_REGNUM]); + } + } + if (delta != 0) { if (satisfies_constraint_Is15 (GEN_INT (delta))) { - fprintf (file, "\taddi\t$r%d, $r%d, %ld\n", + fprintf (file, "\taddi\t$r%d, $r%d, " HOST_WIDE_INT_PRINT_DEC "\n", this_regno, this_regno, delta); } else if (satisfies_constraint_Is20 (GEN_INT (delta))) { - fprintf (file, "\tmovi\t$ta, %ld\n", delta); + fprintf (file, "\tmovi\t$ta, " HOST_WIDE_INT_PRINT_DEC "\n", delta); fprintf (file, "\tadd\t$r%d, $r%d, $ta\n", this_regno, this_regno); } else { - fprintf (file, "\tsethi\t$ta, hi20(%ld)\n", delta); - fprintf (file, "\tori\t$ta, $ta, lo12(%ld)\n", delta); + fprintf (file, + "\tsethi\t$ta, hi20(" HOST_WIDE_INT_PRINT_DEC ")\n", + delta); + fprintf (file, + "\tori\t$ta, $ta, lo12(" HOST_WIDE_INT_PRINT_DEC ")\n", + delta); fprintf (file, "\tadd\t$r%d, $r%d, $ta\n", this_regno, this_regno); } } - fprintf (file, "\tb\t"); - assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); - fprintf (file, "\n"); + if (flag_pic) + { + fprintf (file, "\tla\t$ta, "); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "@PLT\n"); + fprintf (file, "\t! epilogue\n"); + fprintf (file, "\tlwi.bi\t%s, [%s], 4\n", + reg_names[PIC_OFFSET_TABLE_REGNUM], + reg_names[STACK_POINTER_REGNUM]); + fprintf (file, "\tbr\t$ta\n"); + } + else + { + fprintf (file, "\tb\t"); + assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); + fprintf (file, "\n"); + } final_end_function (); } /* -- Permitting tail calls. */ +/* Return true if it is ok to do sibling call optimization. */ +static bool +nds32_function_ok_for_sibcall (tree decl, + tree exp ATTRIBUTE_UNUSED) +{ + /* The DECL is NULL if it is an indirect call. */ + + /* 1. Do not apply sibling call if -mv3push is enabled, + because pop25 instruction also represents return behavior. + 2. If this function is a isr function, do not apply sibling call + because it may perform the behavior that user does not expect. + 3. If this function is a variadic function, do not apply sibling call + because the stack layout may be a mess. + 4. We don't want to apply sibling call optimization for indirect + sibcall because the pop behavior in epilogue may pollute the + content of caller-saved regsiter when the register is used for + indirect sibcall. + 5. In pic mode, it may use some registers for PLT call. */ + return (!TARGET_V3PUSH + && !nds32_isr_function_p (current_function_decl) + && (cfun->machine->va_args_size == 0) + && decl + && !flag_pic); +} + /* Determine whether we need to enable warning for function return check. */ static bool nds32_warn_func_return (tree decl) { -/* Naked functions are implemented entirely in assembly, including the - return sequence, so suppress warnings about this. */ + /* Naked functions are implemented entirely in assembly, including the + return sequence, so suppress warnings about this. */ return !nds32_naked_function_p (decl); } @@ -1681,7 +2541,7 @@ nds32_warn_func_return (tree decl) static void nds32_setup_incoming_varargs (cumulative_args_t ca, - machine_mode mode, + enum machine_mode mode, tree type, int *pretend_args_size, int second_time ATTRIBUTE_UNUSED) @@ -1795,7 +2655,7 @@ nds32_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) sorry ("a nested function is not supported for reduced registers"); /* STEP 1: Copy trampoline code template into stack, - fill up essential data into stack. */ + fill up essential data into stack. */ /* Extract nested function address rtx. */ fnaddr = XEXP (DECL_RTL (fndecl), 0); @@ -1831,8 +2691,8 @@ nds32_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) && (tramp_align_in_bytes % nds32_cache_block_size) == 0) { /* Under this condition, the starting address of trampoline - must be aligned to the starting address of each cache block - and we do not have to worry about cross-boundary issue. */ + must be aligned to the starting address of each cache block + and we do not have to worry about cross-boundary issue. */ for (i = 0; i < (TRAMPOLINE_SIZE + nds32_cache_block_size - 1) / nds32_cache_block_size; @@ -1847,10 +2707,10 @@ nds32_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) else if (TRAMPOLINE_SIZE > nds32_cache_block_size) { /* The starting address of trampoline code - may not be aligned to the cache block, - so the trampoline code may be across two cache block. - We need to sync the last element, which is 4-byte size, - of trampoline template. */ + may not be aligned to the cache block, + so the trampoline code may be across two cache block. + We need to sync the last element, which is 4-byte size, + of trampoline template. */ for (i = 0; i < (TRAMPOLINE_SIZE + nds32_cache_block_size - 1) / nds32_cache_block_size; @@ -1871,16 +2731,16 @@ nds32_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) else { /* This is the simplest case. - Because TRAMPOLINE_SIZE is less than or - equal to nds32_cache_block_size, - we can just sync start address and - the last element of trampoline code. */ + Because TRAMPOLINE_SIZE is less than or + equal to nds32_cache_block_size, + we can just sync start address and + the last element of trampoline code. */ /* Sync starting address of tampoline code. */ emit_move_insn (tmp_reg, sync_cache_addr); emit_insn (isync_insn); /* Sync the last element, which is 4-byte size, - of trampoline template. */ + of trampoline template. */ emit_move_insn (tmp_reg, plus_constant (Pmode, sync_cache_addr, TRAMPOLINE_SIZE - 4)); @@ -1896,11 +2756,52 @@ nds32_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) /* Addressing Modes. */ static bool -nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) +nds32_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) { + if (TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) + { + /* When using floating-point instructions, + we don't allow 'addr' to be [symbol_ref], [CONST] pattern. */ + if ((mode == DFmode || mode == SFmode) + && (GET_CODE (x) == SYMBOL_REF + || GET_CODE(x) == CONST)) + return false; + + /* Allow [post_modify] addressing mode, when using FPU instructions. */ + if (GET_CODE (x) == POST_MODIFY + && mode == DFmode) + { + if (GET_CODE (XEXP (x, 0)) == REG + && GET_CODE (XEXP (x, 1)) == PLUS) + { + rtx plus_op = XEXP (x, 1); + rtx op0 = XEXP (plus_op, 0); + rtx op1 = XEXP (plus_op, 1); + + if (nds32_address_register_rtx_p (op0, strict) + && CONST_INT_P (op1)) + { + if (satisfies_constraint_Is14 (op1)) + { + /* If it is not under strictly aligned situation, + we can return true without checking alignment. */ + if (!cfun->machine->strict_aligned_p) + return true; + /* Make sure address is word alignment. + Currently we do not have 64-bit load/store yet, + so we will use two 32-bit load/store instructions to do + memory access and they are single word alignment. */ + else if (NDS32_SINGLE_WORD_ALIGN_P (INTVAL (op1))) + return true; + } + } + } + } + } + /* For (mem:DI addr) or (mem:DF addr) case, we only allow 'addr' to be [reg], [symbol_ref], - [const], or [reg + const_int] pattern. */ + [const], or [reg + const_int] pattern. */ if (mode == DImode || mode == DFmode) { /* Allow [Reg + const_int] addressing mode. */ @@ -1910,13 +2811,19 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) && nds32_legitimate_index_p (mode, XEXP (x, 1), strict) && CONST_INT_P (XEXP (x, 1))) return true; - else if (nds32_address_register_rtx_p (XEXP (x, 1), strict) && nds32_legitimate_index_p (mode, XEXP (x, 0), strict) && CONST_INT_P (XEXP (x, 0))) return true; } + /* Allow [post_inc] and [post_dec] addressing mode. */ + if (GET_CODE (x) == POST_INC || GET_CODE (x) == POST_DEC) + { + if (nds32_address_register_rtx_p (XEXP (x, 0), strict)) + return true; + } + /* Now check [reg], [symbol_ref], and [const]. */ if (GET_CODE (x) != REG && GET_CODE (x) != SYMBOL_REF @@ -1933,18 +2840,26 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) case SYMBOL_REF: /* (mem (symbol_ref A)) => [symbol_ref] */ + + if (flag_pic || SYMBOL_REF_TLS_MODEL (x)) + return false; + + if (TARGET_ICT_MODEL_LARGE && nds32_indirect_call_referenced_p (x)) + return false; + /* If -mcmodel=large, the 'symbol_ref' is not a valid address - during or after LRA/reload phase. */ + during or after LRA/reload phase. */ if (TARGET_CMODEL_LARGE && (reload_completed || reload_in_progress || lra_in_progress)) return false; /* If -mcmodel=medium and the symbol references to rodata section, - the 'symbol_ref' is not a valid address during or after - LRA/reload phase. */ + the 'symbol_ref' is not a valid address during or after + LRA/reload phase. */ if (TARGET_CMODEL_MEDIUM - && NDS32_SYMBOL_REF_RODATA_P (x) + && (NDS32_SYMBOL_REF_RODATA_P (x) + || CONSTANT_POOL_ADDRESS_P (x)) && (reload_completed || reload_in_progress || lra_in_progress)) @@ -1954,7 +2869,7 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) case CONST: /* (mem (const (...))) - => [ + const_addr ], where const_addr = symbol_ref + const_int */ + => [ + const_addr ], where const_addr = symbol_ref + const_int */ if (GET_CODE (XEXP (x, 0)) == PLUS) { rtx plus_op = XEXP (x, 0); @@ -1965,17 +2880,21 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) if (GET_CODE (op0) == SYMBOL_REF && CONST_INT_P (op1)) { /* Now we see the [ + const_addr ] pattern, but we need - some further checking. */ + some further checking. */ + + if (flag_pic) + return false; + /* If -mcmodel=large, the 'const_addr' is not a valid address - during or after LRA/reload phase. */ + during or after LRA/reload phase. */ if (TARGET_CMODEL_LARGE && (reload_completed || reload_in_progress || lra_in_progress)) return false; /* If -mcmodel=medium and the symbol references to rodata section, - the 'const_addr' is not a valid address during or after - LRA/reload phase. */ + the 'const_addr' is not a valid address during or after + LRA/reload phase. */ if (TARGET_CMODEL_MEDIUM && NDS32_SYMBOL_REF_RODATA_P (op0) && (reload_completed @@ -1993,9 +2912,9 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) case POST_MODIFY: /* (mem (post_modify (reg) (plus (reg) (reg)))) - => [Ra], Rb */ + => [Ra], Rb */ /* (mem (post_modify (reg) (plus (reg) (const_int)))) - => [Ra], const_int */ + => [Ra], const_int */ if (GET_CODE (XEXP (x, 0)) == REG && GET_CODE (XEXP (x, 1)) == PLUS) { @@ -2018,7 +2937,7 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) /* (mem (post_inc reg)) => [Ra], 1/2/4 */ /* (mem (post_dec reg)) => [Ra], -1/-2/-4 */ /* The 1/2/4 or -1/-2/-4 have been displayed in nds32.md. - We only need to deal with register Ra. */ + We only need to deal with register Ra. */ if (nds32_address_register_rtx_p (XEXP (x, 0), strict)) return true; else @@ -2026,11 +2945,11 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) case PLUS: /* (mem (plus reg const_int)) - => [Ra + imm] */ + => [Ra + imm] */ /* (mem (plus reg reg)) - => [Ra + Rb] */ + => [Ra + Rb] */ /* (mem (plus (mult reg const_int) reg)) - => [Ra + Rb << sv] */ + => [Ra + Rb << sv] */ if (nds32_address_register_rtx_p (XEXP (x, 0), strict) && nds32_legitimate_index_p (mode, XEXP (x, 1), strict)) return true; @@ -2042,39 +2961,292 @@ nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict) case LO_SUM: /* (mem (lo_sum (reg) (symbol_ref))) */ - /* (mem (lo_sum (reg) (const))) */ - gcc_assert (REG_P (XEXP (x, 0))); - if (GET_CODE (XEXP (x, 1)) == SYMBOL_REF - || GET_CODE (XEXP (x, 1)) == CONST) - return nds32_legitimate_address_p (mode, XEXP (x, 1), strict); - else + /* (mem (lo_sum (reg) (const (plus (symbol_ref) (reg)))) */ + /* TLS case: (mem (lo_sum (reg) (const (unspec symbol_ref X)))) */ + /* The LO_SUM is a valid address if and only if we would like to + generate 32-bit full address memory access with any of following + circumstance: + 1. -mcmodel=large. + 2. -mcmodel=medium and the symbol_ref references to rodata. */ + { + rtx sym = NULL_RTX; + + if (flag_pic) + return false; + + if (!REG_P (XEXP (x, 0))) + return false; + + if (GET_CODE (XEXP (x, 1)) == SYMBOL_REF) + sym = XEXP (x, 1); + else if (GET_CODE (XEXP (x, 1)) == CONST) + { + rtx plus = XEXP(XEXP (x, 1), 0); + if (GET_CODE (plus) == PLUS) + sym = XEXP (plus, 0); + else if (GET_CODE (plus) == UNSPEC) + sym = XVECEXP (plus, 0, 0); + } + else + return false; + + gcc_assert (GET_CODE (sym) == SYMBOL_REF); + + if (TARGET_ICT_MODEL_LARGE + && nds32_indirect_call_referenced_p (sym)) + return true; + + if (TARGET_CMODEL_LARGE) + return true; + else if (TARGET_CMODEL_MEDIUM + && NDS32_SYMBOL_REF_RODATA_P (sym)) + return true; + else + return false; + } + + default: + return false; + } +} + +static rtx +nds32_legitimize_address (rtx x, + rtx oldx ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED) +{ + if (nds32_tls_referenced_p (x)) + x = nds32_legitimize_tls_address (x); + else if (flag_pic && SYMBOLIC_CONST_P (x)) + x = nds32_legitimize_pic_address (x); + else if (TARGET_ICT_MODEL_LARGE && nds32_indirect_call_referenced_p (x)) + x = nds32_legitimize_ict_address (x); + + return x; +} + +static bool +nds32_legitimate_constant_p (enum machine_mode mode, rtx x) +{ + switch (GET_CODE (x)) + { + case CONST_DOUBLE: + if ((TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) + && (mode == DFmode || mode == SFmode)) + return false; + break; + case CONST: + x = XEXP (x, 0); + + if (GET_CODE (x) == PLUS) + { + if (!CONST_INT_P (XEXP (x, 1))) + return false; + x = XEXP (x, 0); + } + + if (GET_CODE (x) == UNSPEC) + { + switch (XINT (x, 1)) + { + case UNSPEC_GOT: + case UNSPEC_GOTOFF: + case UNSPEC_PLT: + case UNSPEC_TLSGD: + case UNSPEC_TLSLD: + case UNSPEC_TLSIE: + case UNSPEC_TLSLE: + case UNSPEC_ICT: + return false; + default: + return true; + } + } + break; + case SYMBOL_REF: + /* TLS symbols need a call to resolve in + precompute_register_parameters. */ + if (SYMBOL_REF_TLS_MODEL (x)) return false; + break; + default: + return true; + } + + return true; +} + +/* Reorgnize the UNSPEC CONST and return its direct symbol. */ +static rtx +nds32_delegitimize_address (rtx x) +{ + x = delegitimize_mem_from_attrs (x); + + if (GET_CODE(x) == CONST) + { + rtx inner = XEXP (x, 0); + + /* Handle for GOTOFF. */ + if (GET_CODE (inner) == PLUS) + inner = XEXP (inner, 0); + + if (GET_CODE (inner) == UNSPEC) + { + switch (XINT (inner, 1)) + { + case UNSPEC_GOTINIT: + case UNSPEC_GOT: + case UNSPEC_GOTOFF: + case UNSPEC_PLT: + case UNSPEC_TLSGD: + case UNSPEC_TLSLD: + case UNSPEC_TLSIE: + case UNSPEC_TLSLE: + case UNSPEC_ICT: + x = XVECEXP (inner, 0, 0); + break; + default: + break; + } + } + } + return x; +} + +static enum machine_mode +nds32_vectorize_preferred_simd_mode (enum machine_mode mode) +{ + if (!NDS32_EXT_DSP_P ()) + return word_mode; + + switch (mode) + { + case QImode: + return V4QImode; + case HImode: + return V2HImode; + default: + return word_mode; + } +} +static bool +nds32_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x) +{ + switch (GET_CODE (x)) + { + case CONST: + return !nds32_legitimate_constant_p (mode, x); + case SYMBOL_REF: + /* All symbols have to be accessed through gp-relative in PIC mode. */ + /* We don't want to force symbol as constant pool in .text section, + because we use the gp-relatived instruction to load in small + or medium model. */ + if (flag_pic + || SYMBOL_REF_TLS_MODEL (x) + || TARGET_CMODEL_SMALL + || TARGET_CMODEL_MEDIUM) + return true; + break; + case CONST_INT: + case CONST_DOUBLE: + if (flag_pic && (lra_in_progress || reload_completed)) + return true; + break; default: return false; } + return false; +} + + +/* Condition Code Status. */ + +/* -- Representation of condition codes using registers. */ + +static void +nds32_canonicalize_comparison (int *code, + rtx *op0 ATTRIBUTE_UNUSED, + rtx *op1, + bool op0_preserve_value ATTRIBUTE_UNUSED) +{ + /* When the instruction combination pass tries to combine a comparison insn + with its previous insns, it also transforms the operator in order to + minimize its constant field. For example, it tries to transform a + comparison insn from + (set (reg:SI 54) + (ltu:SI (reg:SI 52) + (const_int 10 [0xa]))) + to + (set (reg:SI 54) + (leu:SI (reg:SI 52) + (const_int 9 [0x9]))) + + However, the nds32 target only provides instructions supporting the LTU + operation directly, and the implementation of the pattern "cbranchsi4" + only expands the LTU form. In order to handle the non-LTU operations + generated from passes other than the RTL expansion pass, we have to + implement this hook to revert those changes. Since we only expand the LTU + operator in the RTL expansion pass, we might only need to handle the LEU + case, unless we find other optimization passes perform more aggressive + transformations. */ + + if (*code == LEU && CONST_INT_P (*op1)) + { + *op1 = gen_int_mode (INTVAL (*op1) + 1, SImode); + *code = LTU; + } } /* Describing Relative Costs of Operations. */ static int -nds32_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, +nds32_register_move_cost (enum machine_mode mode, reg_class_t from, reg_class_t to) { - if (from == HIGH_REGS || to == HIGH_REGS) - return 6; + /* In garywolf cpu, FPR to GPR is chaper than other cpu. */ + if (TARGET_PIPELINE_GRAYWOLF) + { + if (GET_MODE_SIZE (mode) == 8) + { + /* DPR to GPR. */ + if (from == FP_REGS && to != FP_REGS) + return 3; + /* GPR to DPR. */ + if (from != FP_REGS && to == FP_REGS) + return 2; + } + else + { + if ((from == FP_REGS && to != FP_REGS) + || (from != FP_REGS && to == FP_REGS)) + return 2; + } + } - return 2; + if ((from == FP_REGS && to != FP_REGS) + || (from != FP_REGS && to == FP_REGS)) + return 3; + else if (from == HIGH_REGS || to == HIGH_REGS) + return optimize_size ? 6 : 2; + else + return 2; } static int -nds32_memory_move_cost (machine_mode mode ATTRIBUTE_UNUSED, +nds32_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, reg_class_t rclass ATTRIBUTE_UNUSED, bool in ATTRIBUTE_UNUSED) { - return 8; + /* Memory access is only need 1 cycle in our low-end processor, + however memory access is most 4-byte instruction, + so let it 8 for optimize_size, otherwise be 2. */ + if (nds32_memory_model_option == MEMORY_MODEL_FAST) + return optimize_size ? 8 : 4; + else + return 8; } /* This target hook describes the relative costs of RTL expressions. @@ -2094,7 +3266,7 @@ nds32_rtx_costs (rtx x, static int nds32_address_cost (rtx address, - machine_mode mode, + enum machine_mode mode, addr_space_t as, bool speed) { @@ -2102,6 +3274,55 @@ nds32_address_cost (rtx address, } +/* Adjusting the Instruction Scheduler. */ + +static int +nds32_sched_issue_rate (void) +{ + switch (nds32_cpu_option) + { + case CPU_GRAYWOLF: + case CPU_PANTHER: + return 2; + + default: + return 1; + } +} + +static int +nds32_sched_adjust_cost (rtx_insn *insn ATTRIBUTE_UNUSED, rtx link, rtx_insn *dep ATTRIBUTE_UNUSED, int cost) +{ + if (REG_NOTE_KIND (link) == REG_DEP_ANTI + || REG_NOTE_KIND (link) == REG_DEP_OUTPUT) + { + if (nds32_sched_issue_rate () > 1) + return 1; + + return 0; + } + + return cost; +} + +static void +nds32_set_sched_flags (spec_info_t spec_info ATTRIBUTE_UNUSED) +{ + if (!flag_reorg_out_of_order + || nds32_sched_issue_rate () < 2) + return; + + unsigned int *flags = &(current_sched_info->flags); + + // Disallow the sheculder to find inc/mem pairs and break dependencies by + // duplication address computations. Otherwise, after doing so, the + // scheduler will treat that the two insns can be issued at the same cycle + // so that the later insn isn't marked as TImode. It will result in a wrong + // behavior for out-of-order reorganization. + *flags |= DONT_BREAK_DEPENDENCIES; +} + + /* Dividing the Output into Sections (Texts, Data, . . . ). */ /* If references to a symbol or a constant must be treated differently @@ -2150,17 +3371,56 @@ nds32_asm_file_start (void) { default_file_start (); + if (flag_pic) + fprintf (asm_out_file, "\t.pic\n"); + /* Tell assembler which ABI we are using. */ fprintf (asm_out_file, "\t! ABI version\n"); - fprintf (asm_out_file, "\t.abi_2\n"); + if (TARGET_HARD_FLOAT) + fprintf (asm_out_file, "\t.abi_2fp_plus\n"); + else + fprintf (asm_out_file, "\t.abi_2\n"); /* Tell assembler that this asm code is generated by compiler. */ fprintf (asm_out_file, "\t! This asm file is generated by compiler\n"); fprintf (asm_out_file, "\t.flag\tverbatim\n"); - /* Give assembler the size of each vector for interrupt handler. */ - fprintf (asm_out_file, "\t! This vector size directive is required " - "for checking inconsistency on interrupt handler\n"); - fprintf (asm_out_file, "\t.vec_size\t%d\n", nds32_isr_vector_size); + + /* We need to provide the size of each vector for interrupt handler + under elf toolchain. */ + if (!TARGET_LINUX_ABI) + { + fprintf (asm_out_file, "\t! This vector size directive is required " + "for checking inconsistency on interrupt handler\n"); + fprintf (asm_out_file, "\t.vec_size\t%d\n", nds32_isr_vector_size); + } + + /* If user enables '-mforce-fp-as-gp' or compiles programs with -Os, + the compiler may produce 'la $fp,_FP_BASE_' instruction + at prologue for fp-as-gp optimization. + We should emit weak reference of _FP_BASE_ to avoid undefined reference + in case user does not pass '--relax' option to linker. */ + if (!TARGET_LINUX_ABI && (TARGET_FORCE_FP_AS_GP || optimize_size)) + { + fprintf (asm_out_file, "\t! This weak reference is required to do " + "fp-as-gp link time optimization\n"); + fprintf (asm_out_file, "\t.weak\t_FP_BASE_\n"); + } + /* If user enables '-mifc', we should emit relaxation directive + to tell linker that this file is allowed to do ifc optimization. */ + if (TARGET_IFC) + { + fprintf (asm_out_file, "\t! This relaxation directive is required " + "to do ifc link time optimization\n"); + fprintf (asm_out_file, "\t.relax\tifc\n"); + } + /* If user enables '-mex9', we should emit relaxation directive + to tell linker that this file is allowed to do ex9 optimization. */ + if (TARGET_EX9) + { + fprintf (asm_out_file, "\t! This relaxation directive is required " + "to do ex9 link time optimization\n"); + fprintf (asm_out_file, "\t.relax\tex9\n"); + } fprintf (asm_out_file, "\t! ------------------------------------\n"); @@ -2171,6 +3431,53 @@ nds32_asm_file_start (void) if (TARGET_ISA_V3M) fprintf (asm_out_file, "\t! ISA family\t\t: %s\n", "V3M"); + switch (nds32_cpu_option) + { + case CPU_N6: + fprintf (asm_out_file, "\t! Pipeline model\t: %s\n", "N6"); + break; + + case CPU_N7: + fprintf (asm_out_file, "\t! Pipeline model\t: %s\n", "N7"); + break; + + case CPU_N8: + fprintf (asm_out_file, "\t! Pipeline model\t: %s\n", "N8"); + break; + + case CPU_E8: + fprintf (asm_out_file, "\t! Pipeline model\t: %s\n", "E8"); + break; + + case CPU_N9: + fprintf (asm_out_file, "\t! Pipeline model\t: %s\n", "N9"); + break; + + case CPU_N10: + fprintf (asm_out_file, "\t! Pipeline model\t: %s\n", "N10"); + break; + + case CPU_GRAYWOLF: + fprintf (asm_out_file, "\t! Pipeline model\t: %s\n", "Graywolf"); + break; + + case CPU_N12: + case CPU_N13: + fprintf (asm_out_file, "\t! Pipeline model\t: %s\n", "N13"); + break; + + case CPU_PANTHER: + fprintf (asm_out_file, "\t! Pipeline model\t: %s\n", "Panther"); + break; + + case CPU_SIMPLE: + fprintf (asm_out_file, "\t! Pipeline model\t: %s\n", "SIMPLE"); + break; + + default: + gcc_unreachable (); + } + if (TARGET_CMODEL_SMALL) fprintf (asm_out_file, "\t! Code model\t\t: %s\n", "SMALL"); if (TARGET_CMODEL_MEDIUM) @@ -2181,6 +3488,15 @@ nds32_asm_file_start (void) fprintf (asm_out_file, "\t! Endian setting\t: %s\n", ((TARGET_BIG_ENDIAN) ? "big-endian" : "little-endian")); + fprintf (asm_out_file, "\t! Use SP floating-point instruction\t: %s\n", + ((TARGET_FPU_SINGLE) ? "Yes" + : "No")); + fprintf (asm_out_file, "\t! Use DP floating-point instruction\t: %s\n", + ((TARGET_FPU_DOUBLE) ? "Yes" + : "No")); + fprintf (asm_out_file, "\t! ABI version\t\t: %s\n", + ((TARGET_HARD_FLOAT) ? "ABI2FP+" + : "ABI2")); fprintf (asm_out_file, "\t! ------------------------------------\n"); @@ -2188,8 +3504,14 @@ nds32_asm_file_start (void) ((TARGET_CMOV) ? "Yes" : "No")); fprintf (asm_out_file, "\t! Use performance extension\t: %s\n", - ((TARGET_PERF_EXT) ? "Yes" + ((TARGET_EXT_PERF) ? "Yes" : "No")); + fprintf (asm_out_file, "\t! Use performance extension 2\t: %s\n", + ((TARGET_EXT_PERF2) ? "Yes" + : "No")); + fprintf (asm_out_file, "\t! Use string extension\t\t: %s\n", + ((TARGET_EXT_STRING) ? "Yes" + : "No")); fprintf (asm_out_file, "\t! ------------------------------------\n"); @@ -2203,10 +3525,18 @@ nds32_asm_file_start (void) ((TARGET_REDUCED_REGS) ? "Yes" : "No")); + fprintf (asm_out_file, "\t! Support unaligned access\t\t: %s\n", + (flag_unaligned_access ? "Yes" + : "No")); + fprintf (asm_out_file, "\t! ------------------------------------\n"); if (optimize_size) fprintf (asm_out_file, "\t! Optimization level\t: -Os\n"); + else if (optimize_fast) + fprintf (asm_out_file, "\t! Optimization level\t: -Ofast\n"); + else if (optimize_debug) + fprintf (asm_out_file, "\t! Optimization level\t: -Og\n"); else fprintf (asm_out_file, "\t! Optimization level\t: -O%d\n", optimize); @@ -2225,9 +3555,65 @@ nds32_asm_file_end (void) { nds32_asm_file_end_for_isr (); + /* The NDS32 Linux stack is mapped non-executable by default, so add a + .note.GNU-stack section. */ + if (TARGET_LINUX_ABI) + file_end_indicate_exec_stack (); + fprintf (asm_out_file, "\t! ------------------------------------\n"); } +static bool +nds32_asm_output_addr_const_extra (FILE *file, rtx x) +{ + if (GET_CODE (x) == UNSPEC) + { + switch (XINT (x, 1)) + { + case UNSPEC_GOTINIT: + output_addr_const (file, XVECEXP (x, 0, 0)); + break; + case UNSPEC_GOTOFF: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@GOTOFF", file); + break; + case UNSPEC_GOT: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@GOT", file); + break; + case UNSPEC_PLT: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@PLT", file); + break; + case UNSPEC_TLSGD: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@TLSDESC", file); + break; + case UNSPEC_TLSLD: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@TLSDESC", file); + break; + case UNSPEC_TLSIE: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@GOTTPOFF", file); + break; + case UNSPEC_TLSLE: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@TPOFF", file); + break; + case UNSPEC_ICT: + output_addr_const (file, XVECEXP (x, 0, 0)); + fputs ("@ICT", file); + break; + default: + return false; + } + return true; + } + else + return false; +} + /* -- Output and Generation of Labels. */ static void @@ -2243,7 +3629,15 @@ nds32_asm_globalize_label (FILE *stream, const char *name) static void nds32_print_operand (FILE *stream, rtx x, int code) { - int op_value; + HOST_WIDE_INT op_value = 0; + HOST_WIDE_INT one_position; + HOST_WIDE_INT zero_position; + bool pick_lsb_p = false; + bool pick_msb_p = false; + int regno; + + if (CONST_INT_P (x)) + op_value = INTVAL (x); switch (code) { @@ -2251,27 +3645,80 @@ nds32_print_operand (FILE *stream, rtx x, int code) /* Do nothing special. */ break; - case 'V': - /* 'x' is supposed to be CONST_INT, get the value. */ + case 'b': + /* Use exact_log2() to search the 0-bit position. */ gcc_assert (CONST_INT_P (x)); - op_value = INTVAL (x); + zero_position = exact_log2 (~UINTVAL (x) & GET_MODE_MASK (SImode)); + gcc_assert (zero_position != -1); + fprintf (stream, HOST_WIDE_INT_PRINT_DEC, zero_position); - /* According to the Andes architecture, - the system/user register index range is 0 ~ 1023. - In order to avoid conflict between user-specified-integer value - and enum-specified-register value, - the 'enum nds32_intrinsic_registers' value - in nds32_intrinsic.h starts from 1024. */ - if (op_value < 1024 && op_value >= 0) - { - /* If user gives integer value directly (0~1023), - we just print out the value. */ - fprintf (stream, "%d", op_value); - } - else if (op_value < 0 - || op_value >= ((int) ARRAY_SIZE (nds32_intrinsic_register_names) - + 1024)) - { + /* No need to handle following process, so return immediately. */ + return; + + case 'e': + gcc_assert (MEM_P (x) + && GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT); + fprintf (stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (XEXP (XEXP (x, 0), 1))); + + /* No need to handle following process, so return immediately. */ + return; + + case 'v': + gcc_assert (CONST_INT_P (x) + && (INTVAL (x) == 0 + || INTVAL (x) == 8 + || INTVAL (x) == 16 + || INTVAL (x) == 24)); + fprintf (stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) / 8); + + /* No need to handle following process, so return immediately. */ + return; + + case 'B': + /* Use exact_log2() to search the 1-bit position. */ + gcc_assert (CONST_INT_P (x)); + one_position = exact_log2 (UINTVAL (x) & GET_MODE_MASK (SImode)); + gcc_assert (one_position != -1); + fprintf (stream, HOST_WIDE_INT_PRINT_DEC, one_position); + + /* No need to handle following process, so return immediately. */ + return; + + case 'L': + /* X is supposed to be REG rtx. */ + gcc_assert (REG_P (x)); + /* Claim that we are going to pick LSB part of X. */ + pick_lsb_p = true; + break; + + case 'H': + /* X is supposed to be REG rtx. */ + gcc_assert (REG_P (x)); + /* Claim that we are going to pick MSB part of X. */ + pick_msb_p = true; + break; + + case 'V': + /* X is supposed to be CONST_INT, get the value. */ + gcc_assert (CONST_INT_P (x)); + + /* According to the Andes architecture, + the system/user register index range is 0 ~ 1023. + In order to avoid conflict between user-specified-integer value + and enum-specified-register value, + the 'enum nds32_intrinsic_registers' value + in nds32_intrinsic.h starts from 1024. */ + if (op_value < 1024 && op_value >= 0) + { + /* If user gives integer value directly (0~1023), + we just print out the value. */ + fprintf (stream, HOST_WIDE_INT_PRINT_DEC, op_value); + } + else if (op_value < 0 + || op_value >= ((int) ARRAY_SIZE (nds32_intrinsic_register_names) + + 1024)) + { /* The enum index value for array size is out of range. */ error ("intrinsic register index is out of range"); } @@ -2286,6 +3733,45 @@ nds32_print_operand (FILE *stream, rtx x, int code) /* No need to handle following process, so return immediately. */ return; + case 'R': /* cctl valck */ + /* Note the cctl divide to 5 group and share the same name table. */ + if (op_value < 0 || op_value > 4) + error ("CCTL intrinsic function subtype out of range!"); + fprintf (stream, "%s", nds32_cctl_names[op_value]); + return; + + case 'T': /* cctl idxwbinv */ + /* Note the cctl divide to 5 group and share the same name table. */ + if (op_value < 0 || op_value > 4) + error ("CCTL intrinsic function subtype out of range!"); + fprintf (stream, "%s", nds32_cctl_names[op_value + 4]); + return; + + case 'U': /* cctl vawbinv */ + /* Note the cctl divide to 5 group and share the same name table. */ + if (op_value < 0 || op_value > 4) + error ("CCTL intrinsic function subtype out of range!"); + fprintf (stream, "%s", nds32_cctl_names[op_value + 8]); + return; + + case 'X': /* cctl idxread */ + /* Note the cctl divide to 5 group and share the same name table. */ + if (op_value < 0 || op_value > 4) + error ("CCTL intrinsic function subtype out of range!"); + fprintf (stream, "%s", nds32_cctl_names[op_value + 12]); + return; + + case 'W': /* cctl idxwitre */ + /* Note the cctl divide to 5 group and share the same name table. */ + if (op_value < 0 || op_value > 4) + error ("CCTL intrinsic function subtype out of range!"); + fprintf (stream, "%s", nds32_cctl_names[op_value + 16]); + return; + + case 'Z': /* dpref */ + fprintf (stream, "%s", nds32_dpref_names[op_value]); + return; + default : /* Unknown flag. */ output_operand_lossage ("invalid operand output code"); @@ -2295,35 +3781,113 @@ nds32_print_operand (FILE *stream, rtx x, int code) switch (GET_CODE (x)) { case LABEL_REF: + output_addr_const (stream, x); + break; + case SYMBOL_REF: output_addr_const (stream, x); + + if (!TARGET_LINUX_ABI && nds32_indirect_call_referenced_p (x)) + fprintf (stream, "@ICT"); + break; case REG: + /* Print a Double-precision register name. */ + if ((GET_MODE (x) == DImode || GET_MODE (x) == DFmode) + && NDS32_IS_FPR_REGNUM (REGNO (x))) + { + regno = REGNO (x); + if (!NDS32_FPR_REGNO_OK_FOR_DOUBLE (regno)) + { + output_operand_lossage ("invalid operand for code '%c'", code); + break; + } + fprintf (stream, "$fd%d", (regno - NDS32_FIRST_FPR_REGNUM) >> 1); + break; + } + + /* Print LSB or MSB part of register pair if the + constraint modifier 'L' or 'H' is specified. */ + if ((GET_MODE (x) == DImode || GET_MODE (x) == DFmode) + && NDS32_IS_GPR_REGNUM (REGNO (x))) + { + if ((pick_lsb_p && WORDS_BIG_ENDIAN) + || (pick_msb_p && !WORDS_BIG_ENDIAN)) + { + /* If we would like to print out LSB register under big-endian, + or print out MSB register under little-endian, we need to + increase register number. */ + regno = REGNO (x); + regno++; + fputs (reg_names[regno], stream); + break; + } + } + /* Forbid using static chain register ($r16) - on reduced-set registers configuration. */ + on reduced-set registers configuration. */ if (TARGET_REDUCED_REGS && REGNO (x) == STATIC_CHAIN_REGNUM) sorry ("a nested function is not supported for reduced registers"); /* Normal cases, print out register name. */ - fputs (reg_names[REGNO (x)], stream); + regno = REGNO (x); + fputs (reg_names[regno], stream); break; case MEM: output_address (GET_MODE (x), XEXP (x, 0)); break; + case HIGH: + if (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE) + { + const REAL_VALUE_TYPE *rv; + long val; + gcc_assert (GET_MODE (x) == SFmode); + + rv = CONST_DOUBLE_REAL_VALUE (XEXP (x, 0)); + REAL_VALUE_TO_TARGET_SINGLE (*rv, val); + + fprintf (stream, "hi20(0x%lx)", val); + } + else + gcc_unreachable (); + break; + + case CONST_DOUBLE: + const REAL_VALUE_TYPE *rv; + long val; + gcc_assert (GET_MODE (x) == SFmode); + + rv = CONST_DOUBLE_REAL_VALUE (x); + REAL_VALUE_TO_TARGET_SINGLE (*rv, val); + + fprintf (stream, "0x%lx", val); + break; + case CODE_LABEL: case CONST_INT: case CONST: output_addr_const (stream, x); break; + case CONST_VECTOR: + fprintf (stream, HOST_WIDE_INT_PRINT_HEX, const_vector_to_hwint (x)); + break; + + case LO_SUM: + /* This is a special case for inline assembly using memory address 'p'. + The inline assembly code is expected to use pesudo instruction + for the operand. EX: la */ + output_addr_const (stream, XEXP(x, 1)); + break; + default: /* Generally, output_addr_const () is able to handle most cases. - We want to see what CODE could appear, - so we use gcc_unreachable() to stop it. */ + We want to see what CODE could appear, + so we use gcc_unreachable() to stop it. */ debug_rtx (x); gcc_unreachable (); break; @@ -2331,7 +3895,9 @@ nds32_print_operand (FILE *stream, rtx x, int code) } static void -nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) +nds32_print_operand_address (FILE *stream, + machine_mode mode ATTRIBUTE_UNUSED, + rtx x) { rtx op0, op1; @@ -2346,15 +3912,25 @@ nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) fputs ("]", stream); break; + case LO_SUM: + /* This is a special case for inline assembly using memory operand 'm'. + The inline assembly code is expected to use pesudo instruction + for the operand. EX: [ls].[bhw] */ + fputs ("[ + ", stream); + op1 = XEXP (x, 1); + output_addr_const (stream, op1); + fputs ("]", stream); + break; + case REG: /* Forbid using static chain register ($r16) - on reduced-set registers configuration. */ + on reduced-set registers configuration. */ if (TARGET_REDUCED_REGS && REGNO (x) == STATIC_CHAIN_REGNUM) sorry ("a nested function is not supported for reduced registers"); /* [Ra] */ - fprintf (stream, "[%s]", reg_names[REGNO (x)]); + fprintf (stream, "[%s + 0]", reg_names[REGNO (x)]); break; case PLUS: @@ -2362,13 +3938,13 @@ nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) op1 = XEXP (x, 1); /* Checking op0, forbid using static chain register ($r16) - on reduced-set registers configuration. */ + on reduced-set registers configuration. */ if (TARGET_REDUCED_REGS && REG_P (op0) && REGNO (op0) == STATIC_CHAIN_REGNUM) sorry ("a nested function is not supported for reduced registers"); /* Checking op1, forbid using static chain register ($r16) - on reduced-set registers configuration. */ + on reduced-set registers configuration. */ if (TARGET_REDUCED_REGS && REG_P (op1) && REGNO (op1) == STATIC_CHAIN_REGNUM) @@ -2377,8 +3953,8 @@ nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) if (REG_P (op0) && CONST_INT_P (op1)) { /* [Ra + imm] */ - fprintf (stream, "[%s + (%d)]", - reg_names[REGNO (op0)], (int)INTVAL (op1)); + fprintf (stream, "[%s + (" HOST_WIDE_INT_PRINT_DEC ")]", + reg_names[REGNO (op0)], INTVAL (op1)); } else if (REG_P (op0) && REG_P (op1)) { @@ -2391,8 +3967,8 @@ nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) /* [Ra + Rb << sv] From observation, the pattern looks like: (plus:SI (mult:SI (reg:SI 58) - (const_int 4 [0x4])) - (reg/f:SI 57)) */ + (const_int 4 [0x4])) + (reg/f:SI 57)) */ int sv; /* We need to set sv to output shift value. */ @@ -2402,6 +3978,8 @@ nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) sv = 1; else if (INTVAL (XEXP (op0, 1)) == 4) sv = 2; + else if (INTVAL (XEXP (op0, 1)) == 8) + sv = 3; else gcc_unreachable (); @@ -2410,6 +3988,20 @@ nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) reg_names[REGNO (XEXP (op0, 0))], sv); } + else if (GET_CODE (op0) == ASHIFT && REG_P (op1)) + { + /* [Ra + Rb << sv] + In normal, ASHIFT can be converted to MULT like above case. + But when the address rtx does not go through canonicalize_address + defined in fwprop, we'll need this case. */ + int sv = INTVAL (XEXP (op0, 1)); + gcc_assert (sv <= 3 && sv >=0); + + fprintf (stream, "[%s + %s << %d]", + reg_names[REGNO (op1)], + reg_names[REGNO (XEXP (op0, 0))], + sv); + } else { /* The control flow is not supposed to be here. */ @@ -2421,20 +4013,20 @@ nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) case POST_MODIFY: /* (post_modify (regA) (plus (regA) (regB))) - (post_modify (regA) (plus (regA) (const_int))) - We would like to extract - regA and regB (or const_int) from plus rtx. */ + (post_modify (regA) (plus (regA) (const_int))) + We would like to extract + regA and regB (or const_int) from plus rtx. */ op0 = XEXP (XEXP (x, 1), 0); op1 = XEXP (XEXP (x, 1), 1); /* Checking op0, forbid using static chain register ($r16) - on reduced-set registers configuration. */ + on reduced-set registers configuration. */ if (TARGET_REDUCED_REGS && REG_P (op0) && REGNO (op0) == STATIC_CHAIN_REGNUM) sorry ("a nested function is not supported for reduced registers"); /* Checking op1, forbid using static chain register ($r16) - on reduced-set registers configuration. */ + on reduced-set registers configuration. */ if (TARGET_REDUCED_REGS && REG_P (op1) && REGNO (op1) == STATIC_CHAIN_REGNUM) @@ -2449,8 +4041,8 @@ nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) else if (REG_P (op0) && CONST_INT_P (op1)) { /* [Ra], imm */ - fprintf (stream, "[%s], %d", - reg_names[REGNO (op0)], (int)INTVAL (op1)); + fprintf (stream, "[%s], " HOST_WIDE_INT_PRINT_DEC, + reg_names[REGNO (op0)], INTVAL (op1)); } else { @@ -2466,7 +4058,7 @@ nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) op0 = XEXP (x, 0); /* Checking op0, forbid using static chain register ($r16) - on reduced-set registers configuration. */ + on reduced-set registers configuration. */ if (TARGET_REDUCED_REGS && REG_P (op0) && REGNO (op0) == STATIC_CHAIN_REGNUM) @@ -2490,14 +4082,92 @@ nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x) default : /* Generally, output_addr_const () is able to handle most cases. - We want to see what CODE could appear, - so we use gcc_unreachable() to stop it. */ + We want to see what CODE could appear, + so we use gcc_unreachable() to stop it. */ debug_rtx (x); gcc_unreachable (); break; } } +/* -- Assembler Commands for Exception Regions. */ + +static rtx +nds32_dwarf_register_span (rtx reg) +{ + rtx dwarf_high, dwarf_low; + rtx dwarf_single; + enum machine_mode mode; + int regno; + + mode = GET_MODE (reg); + regno = REGNO (reg); + + /* We need to adjust dwarf register information for floating-point registers + rather than using default register number mapping. */ + if (regno >= NDS32_FIRST_FPR_REGNUM + && regno <= NDS32_LAST_FPR_REGNUM) + { + if (mode == DFmode || mode == SCmode) + { + /* By default, GCC maps increasing register numbers to increasing + memory locations, but paired FPRs in NDS32 target are always + big-endian, i.e.: + + fd0 : fs0 fs1 + (MSB) (LSB) + + We must return parallel rtx to represent such layout. */ + dwarf_high = gen_rtx_REG (word_mode, regno); + dwarf_low = gen_rtx_REG (word_mode, regno + 1); + return gen_rtx_PARALLEL (VOIDmode, + gen_rtvec (2, dwarf_low, dwarf_high)); + } + else if (mode == DCmode) + { + rtx dwarf_high_re = gen_rtx_REG (word_mode, regno); + rtx dwarf_low_re = gen_rtx_REG (word_mode, regno + 1); + rtx dwarf_high_im = gen_rtx_REG (word_mode, regno); + rtx dwarf_low_im = gen_rtx_REG (word_mode, regno + 1); + return gen_rtx_PARALLEL (VOIDmode, + gen_rtvec (4, dwarf_low_re, dwarf_high_re, + dwarf_high_im, dwarf_low_im)); + } + else if (mode == SFmode || mode == SImode) + { + /* Create new dwarf information with adjusted register number. */ + dwarf_single = gen_rtx_REG (word_mode, regno); + return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, dwarf_single)); + } + else + { + /* We should not be here. */ + gcc_unreachable (); + } + } + + return NULL_RTX; +} + +/* Map internal gcc register numbers to DWARF2 register numbers. */ + +unsigned int +nds32_dbx_register_number (unsigned int regno) +{ + /* The nds32 port in GDB maintains a mapping between dwarf register + number and displayed register name. For backward compatibility to + previous toolchain, currently our gdb still has four registers + (d0.l, d0.h, d1.l, and d1.h) between GPR and FPR while compiler + does not count those four registers in its register number table. + So we have to add 4 on its register number and then create new + dwarf information. Hopefully we can discard such workaround + in the future. */ + if (NDS32_IS_FPR_REGNUM (regno)) + return regno + 4; + + return regno; +} + /* Defining target-specific uses of __attribute__. */ @@ -2526,6 +4196,27 @@ nds32_merge_decl_attributes (tree olddecl, tree newdecl) static void nds32_insert_attributes (tree decl, tree *attributes) { + /* A "indirect_call" function attribute implies "noinline" and "noclone" + for elf toolchain to support ROM patch mechanism. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && lookup_attribute ("indirect_call", *attributes) != NULL) + { + tree new_attrs = *attributes; + + if (TARGET_LINUX_ABI) + error("cannot use indirect_call attribute under linux toolchain"); + + if (lookup_attribute ("noinline", new_attrs) == NULL) + new_attrs = tree_cons (get_identifier ("noinline"), NULL, new_attrs); + if (lookup_attribute ("noclone", new_attrs) == NULL) + new_attrs = tree_cons (get_identifier ("noclone"), NULL, new_attrs); + + if (!TREE_PUBLIC (decl)) + error("indirect_call attribute can't apply for static function"); + + *attributes = new_attrs; + } + /* For function declaration, we need to check isr-specific attributes: 1. Call nds32_check_isr_attrs_conflict() to check any conflict. 2. Check valid integer value for interrupt/exception. @@ -2543,14 +4234,46 @@ nds32_insert_attributes (tree decl, tree *attributes) nds32_check_isr_attrs_conflict (decl, func_attrs); /* Now we are starting to check valid id value - for interrupt/exception/reset. - Note that we ONLY check its validity here. - To construct isr vector information, it is still performed - by nds32_construct_isr_vectors_information(). */ + for interrupt/exception/reset. + Note that we ONLY check its validity here. + To construct isr vector information, it is still performed + by nds32_construct_isr_vectors_information(). */ intr = lookup_attribute ("interrupt", func_attrs); excp = lookup_attribute ("exception", func_attrs); reset = lookup_attribute ("reset", func_attrs); + /* The following code may use attribute arguments. If there is no + argument from source code, it will cause segmentation fault. + Therefore, return dircetly and report error message later. */ + if ((intr && TREE_VALUE (intr) == NULL) + || (excp && TREE_VALUE (excp) == NULL) + || (reset && TREE_VALUE (reset) == NULL)) + return; + + /* ------------------------------------------------------------- */ + /* 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 use other functions to parse string in the + nds32_construct_isr_vectors_information() and then set necessary + isr information in the nds32_isr_vectors[] array. Here we can + just return immediately to avoid new-syntax checking. */ + if (intr != NULL_TREE + && TREE_CODE (TREE_VALUE (TREE_VALUE (intr))) == STRING_CST) + return; + if (excp != NULL_TREE + && TREE_CODE (TREE_VALUE (TREE_VALUE (excp))) == STRING_CST) + return; + if (reset != NULL_TREE + && TREE_CODE (TREE_VALUE (TREE_VALUE (reset))) == STRING_CST) + return; + /* ------------------------------------------------------------- */ + if (intr || excp) { /* Deal with interrupt/exception. */ @@ -2576,8 +4299,8 @@ nds32_insert_attributes (tree decl, tree *attributes) id = TREE_VALUE (id_list); /* Issue error if it is not a valid integer value. */ if (TREE_CODE (id) != INTEGER_CST - || wi::ltu_p (id, lower_bound) - || wi::gtu_p (id, upper_bound)) + || TREE_INT_CST_LOW (id) < lower_bound + || TREE_INT_CST_LOW (id) > upper_bound) error ("invalid id value for interrupt/exception attribute"); /* Advance to next id. */ @@ -2604,8 +4327,8 @@ nds32_insert_attributes (tree decl, tree *attributes) /* 3. Check valid integer value for reset. */ if (TREE_CODE (id) != INTEGER_CST - || wi::ltu_p (id, lower_bound) - || wi::gtu_p (id, upper_bound)) + || TREE_INT_CST_LOW (id) < lower_bound + || TREE_INT_CST_LOW (id) > upper_bound) error ("invalid id value for reset attribute"); /* 4. Check valid function for nmi/warm. */ @@ -2667,17 +4390,40 @@ nds32_option_override (void) { /* Under V2 ISA, we need to strictly disable TARGET_V3PUSH. */ target_flags &= ~MASK_V3PUSH; + /* Under V2 ISA, we need to strictly disable TARGET_IFC. */ + target_flags &= ~MASK_IFC; + /* Under V2 ISA, we need to strictly disable TARGET_EX9. */ + target_flags &= ~MASK_EX9; + /* If this is ARCH_V2J, we need to enable TARGET_REDUCED_REGS. */ + if (nds32_arch_option == ARCH_V2J) + target_flags |= MASK_REDUCED_REGS; } if (TARGET_ISA_V3) { - /* Under V3 ISA, currently nothing should be strictly set. */ + /* If this is ARCH_V3J, we need to enable TARGET_REDUCED_REGS. */ + if (nds32_arch_option == ARCH_V3J) + target_flags |= MASK_REDUCED_REGS; } if (TARGET_ISA_V3M) { /* Under V3M ISA, we need to strictly enable TARGET_REDUCED_REGS. */ target_flags |= MASK_REDUCED_REGS; - /* Under V3M ISA, we need to strictly disable TARGET_PERF_EXT. */ - target_flags &= ~MASK_PERF_EXT; + if (nds32_arch_option != ARCH_V3M_PLUS) + { + /* Under V3M ISA, we need to strictly disable TARGET_IFC. */ + target_flags &= ~MASK_IFC; + /* Under V3M ISA, we need to strictly disable TARGET_EX9. */ + target_flags &= ~MASK_EX9; + } + /* Under V3M ISA, we need to strictly disable TARGET_EXT_PERF. */ + target_flags &= ~MASK_EXT_PERF; + /* Under V3M ISA, we need to strictly disable TARGET_EXT_PERF2. */ + target_flags &= ~MASK_EXT_PERF2; + /* Under V3M ISA, we need to strictly disable TARGET_EXT_STRING. */ + target_flags &= ~MASK_EXT_STRING; + + if (flag_pic) + error ("not support -fpic option for v3m toolchain"); } /* See if we are using reduced-set registers: @@ -2688,48 +4434,572 @@ nds32_option_override (void) int r; /* Prevent register allocator from - choosing it as doing register allocation. */ + choosing it as doing register allocation. */ for (r = 11; r <= 14; r++) fixed_regs[r] = call_used_regs[r] = 1; for (r = 16; r <= 27; r++) fixed_regs[r] = call_used_regs[r] = 1; } + /* See if user explicitly would like to use fp-as-gp optimization. + If so, we must prevent $fp from being allocated + during register allocation. */ + if (TARGET_FORCE_FP_AS_GP) + fixed_regs[FP_REGNUM] = call_used_regs[FP_REGNUM] = 1; + if (!TARGET_16_BIT) { /* Under no 16 bit ISA, we need to strictly disable TARGET_V3PUSH. */ target_flags &= ~MASK_V3PUSH; } - /* Currently, we don't support PIC code generation yet. */ - if (flag_pic) - sorry ("not support -fpic"); + if (TARGET_HARD_FLOAT && !(TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE)) + { + if (nds32_arch_option == ARCH_V3S || nds32_arch_option == ARCH_V3F) + error ("Disable FPU ISA, " + "the ABI option must be enable '-mfloat-abi=soft'"); + else + error ("'-mabi=2fp+' option only support when FPU available, " + "must be enable '-mext-fpu-sp' or '-mext-fpu-dp'"); + } + + nds32_register_passes (); + + nds32_init_rtx_costs (); } /* Miscellaneous Parameters. */ +static rtx_insn * +nds32_md_asm_adjust (vec &outputs ATTRIBUTE_UNUSED, + vec &inputs ATTRIBUTE_UNUSED, + vec &constraints ATTRIBUTE_UNUSED, + vec &clobbers, HARD_REG_SET &clobbered_regs) +{ + if (!flag_inline_asm_r15) + { + clobbers.safe_push (gen_rtx_REG (SImode, TA_REGNUM)); + SET_HARD_REG_BIT (clobbered_regs, TA_REGNUM); + } + + return NULL; +} +/* Insert end_label and check loop body whether is empty. */ +static bool +nds32_hwloop_insert_end_label (rtx loop_id, rtx end_label) +{ + rtx_insn *insn = NULL; + basic_block bb; + rtx cfg_id; + rtx_insn *last_insn; + + FOR_EACH_BB_FN (bb, cfun) + { + FOR_BB_INSNS (bb, insn) + { + if (NOTE_P (insn)) + continue; + + if (recog_memoized (insn) == CODE_FOR_hwloop_cfg + && INSN_P (insn)) + { + cfg_id = XVECEXP (XVECEXP (PATTERN (insn), 0, 5), 0, 0); + if (cfg_id == loop_id) + { + for (last_insn = PREV_INSN (insn); last_insn != BB_HEAD (bb); + last_insn = PREV_INSN (last_insn)) + { + if (NONDEBUG_INSN_P (last_insn)) + { + emit_label_before (end_label, last_insn); + if (TARGET_IFC) + { + /* The last_insn don't do ifcall. */ + emit_insn_before (gen_no_ifc_begin (), last_insn); + emit_insn_after (gen_no_ifc_end (), last_insn); + } + if (TARGET_EX9) + { + /* The last_insn don't do ex9. */ + emit_insn_before (gen_no_ex9_begin (), last_insn); + emit_insn_after (gen_no_ex9_end (), last_insn); + } + /* Record last instruction for identify in relax pass. */ + emit_insn_after (gen_hwloop_last_insn (), last_insn); + return true; + } + } + + if (NOTE_INSN_BASIC_BLOCK_P (last_insn)) + { + rtx_insn *nop = emit_insn_before (gen_unspec_nop (), + last_insn); + emit_label_before (end_label, nop); + if (TARGET_IFC) + { + /* The last_insn don't do ifcall. */ + emit_insn_before (gen_no_ifc_begin (), last_insn); + emit_insn_after (gen_no_ifc_end (), last_insn); + } + if (TARGET_EX9) + { + /* The last_insn don't do ex9. */ + emit_insn_before (gen_no_ex9_begin (), last_insn); + emit_insn_after (gen_no_ex9_end (), last_insn); + } + return true; + } + } + } + } + } + + if (insn != NULL) + delete_insn (insn); + return false; +} + +static void +nds32_hwloop_remove (rtx loop_id) +{ + rtx_insn *insn; + rtx le_id; + basic_block bb; + + FOR_EACH_BB_FN (bb, cfun) + { + FOR_BB_INSNS (bb, insn) + { + if (NOTE_P (insn)) + continue; + + if (recog_memoized (insn) == CODE_FOR_init_lc + && INSN_P (insn)) + { + le_id = XVECEXP (XVECEXP (PATTERN (insn), 0, 1), 0, 0); + if (loop_id == le_id) + { + delete_insn (insn); + return; + } + } + } + } +} + +/* Insert isb instruction for hwloop. */ +static void +nds32_hwloop_insert_isb (rtx loop_id) +{ + rtx_insn *insn; + rtx le_id; + basic_block bb; + + FOR_EACH_BB_FN (bb, cfun) + { + FOR_BB_INSNS (bb, insn) + { + if (NOTE_P (insn)) + continue; + + if (recog_memoized (insn) == CODE_FOR_init_lc + && INSN_P (insn)) + { + le_id = XVECEXP (XVECEXP (PATTERN (insn), 0, 1), 0, 0); + if (loop_id == le_id) + { + emit_insn_after (gen_unspec_volatile_isb (), insn); + return; + } + } + } + } +} +/* Insert mtlei instruction for hwloop. */ +static void +nds32_hwloop_insert_init_end () +{ + rtx_insn *insn; + basic_block bb; + rtx loop_id, end_label; + bool hwloop_p; + + FOR_EACH_BB_FN (bb, cfun) + { + FOR_BB_INSNS (bb, insn) + { + if (NOTE_P (insn)) + continue; + + if (recog_memoized (insn) == CODE_FOR_mtlbi_hint + && INSN_P (insn)) + { + end_label = gen_label_rtx (); + loop_id = XVECEXP (XVECEXP (PATTERN (insn), 0, 1), 0, 0); + hwloop_p = nds32_hwloop_insert_end_label (loop_id, end_label); + + if (!hwloop_p) + { + delete_insn (insn); + nds32_hwloop_remove (loop_id); + } + else + { + emit_insn_after (gen_mtlei (gen_rtx_LABEL_REF (Pmode, end_label)), insn); + nds32_hwloop_insert_isb (loop_id); + } + } + } + } +} + +/* Reorganize insns issued at the same cycle in out of order. */ +static void +nds32_reorg_out_of_order () +{ + using namespace nds32; + + // The function is controoled by -mreorg-out-of-order and the issue rate. + if (!flag_reorg_out_of_order + || nds32_sched_issue_rate () < 2) + return; + + // We only move load insns up at this moment. + rtx_insn *insn; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (!insn_executable_p (insn) + || GET_MODE (insn) != TImode + || get_attr_type (insn) == TYPE_STORE_MULTIPLE + || get_attr_type (insn) == TYPE_LOAD_MULTIPLE + || get_attr_type (insn) == TYPE_LOAD + || get_attr_type (insn) == TYPE_FLOAD + || get_attr_type (insn) == TYPE_STORE + || get_attr_type (insn) == TYPE_FSTORE) + continue; + + rtx_insn *load_insn = insn; + + while ((load_insn = next_executable_insn_local (load_insn))) + { + if (GET_MODE (load_insn) == TImode) + { + load_insn = NULL; + break; + } + + if ((get_attr_type (load_insn) == TYPE_LOAD + || get_attr_type (load_insn) == TYPE_FLOAD) + && get_attr_length (load_insn) < 4) + break; + } + + if (load_insn == NULL_RTX) + continue; + + exchange_insns (insn, load_insn); + } +} + +/* Perform machine-dependent processing. */ +static void +nds32_machine_dependent_reorg (void) +{ + /* We are freeing block_for_insn in the toplev to keep compatibility + with old MDEP_REORGS that are not CFG based. Recompute it + now. */ + compute_bb_for_insn (); + + nds32_reorg_out_of_order (); + + if (TARGET_HWLOOP) + nds32_hwloop_insert_init_end (); + + if (flag_var_tracking) + { + df_analyze (); + timevar_push (TV_VAR_TRACKING); + variable_tracking_main (); + timevar_pop (TV_VAR_TRACKING); + df_finish_pass (false); + } + + /* Use -minnermost-loop to enable, + need more testing to verify result. */ + if (TARGET_INNERMOST_LOOP) + nds32_insert_innermost_loop (); + + nds32_insert_isps (); +} + static void nds32_init_builtins (void) { nds32_init_builtins_impl (); } +static tree +nds32_builtin_decl (unsigned code, bool initialize_p) +{ + /* Implement in nds32-intrinsic.c. */ + return nds32_builtin_decl_impl (code, initialize_p); +} + static rtx nds32_expand_builtin (tree exp, rtx target, rtx subtarget, - machine_mode mode, + enum machine_mode mode, int ignore) { + /* Implement in nds32-intrinsic.c. */ return nds32_expand_builtin_impl (exp, target, subtarget, mode, ignore); } +static bool +nds32_have_conditional_execution (void) +{ + /* Lie to gcc that we have conditional execution for change optimization flow + in if-conversion, LRA and scheduling phase. + In our experiment result show that cand reduce about 2% code size with very + minor performance degradation in average. */ + return optimize_size; +} + +/* Implement TARGET_INIT_LIBFUNCS. */ +static void +nds32_init_libfuncs (void) +{ + if (TARGET_LINUX_ABI) + init_sync_libfuncs (UNITS_PER_WORD); +} + +/* Implement TARGET_CAN_USE_DOLOOP_P. */ +static bool +nds32_can_use_doloop_p (const widest_int &, const widest_int &iterations_max, + unsigned int, bool entered_at_top) +{ + /* Using hwloop must be entered from the top. */ + if (!entered_at_top) + return false; + + if (lookup_attribute ("no_ext_zol", DECL_ATTRIBUTES (current_function_decl))) + return false; + + /* Initial hardware loops too costly, so we must avoid to + generate a hardware loops when loop count less then 8. */ + if (!NDS32_HW_LOOP_P () + || iterations_max.ulow() < 8) + return false; + return true; +} + +/* NULL if INSN insn is valid within a low-overhead loop. + Otherwise return why doloop cannot be applied. */ +static const char * +nds32_invalid_within_doloop (const rtx_insn *insn) +{ + if (CALL_P (insn)) + return "Function call in the loop."; + else if (INSN_CODE (insn) == CODE_FOR_pop25return + || INSN_CODE (insn) == CODE_FOR_return_internal) + return "Simple return in the loop."; + else if (INSN_CODE (insn) == CODE_FOR_unspec_no_hwloop) + return "no_hwloop hint in the loop"; + + return NULL; +} /* ------------------------------------------------------------------------ */ -/* PART 4: Implemet extern function definitions, - the prototype is in nds32-protos.h. */ +/* PART 5: Implemet extern function definitions, + the prototype is in nds32-protos.h. */ + +/* Run-time Target Specification. */ + +void +nds32_cpu_cpp_builtins(struct cpp_reader *pfile) +{ +#define builtin_define(TXT) cpp_define (pfile, TXT) +#define builtin_assert(TXT) cpp_assert (pfile, TXT) + builtin_define ("__nds32__"); + builtin_define ("__NDS32__"); + + /* We need to provide builtin macro to describe the size of + each vector for interrupt handler under elf toolchain. */ + if (!TARGET_LINUX_ABI) + { + if (TARGET_ISR_VECTOR_SIZE_4_BYTE) + builtin_define ("__NDS32_ISR_VECTOR_SIZE_4__"); + else + builtin_define ("__NDS32_ISR_VECTOR_SIZE_16__"); + } + + if (TARGET_HARD_FLOAT) + builtin_define ("__NDS32_ABI_2FP_PLUS__"); + else + builtin_define ("__NDS32_ABI_2__"); + + if (TARGET_ISA_V2) + builtin_define ("__NDS32_ISA_V2__"); + if (TARGET_ISA_V3) + builtin_define ("__NDS32_ISA_V3__"); + if (TARGET_ISA_V3M) + builtin_define ("__NDS32_ISA_V3M__"); + + if (TARGET_FPU_SINGLE) + builtin_define ("__NDS32_EXT_FPU_SP__"); + if (TARGET_FPU_DOUBLE) + builtin_define ("__NDS32_EXT_FPU_DP__"); + + if (TARGET_EXT_FPU_FMA) + builtin_define ("__NDS32_EXT_FPU_FMA__"); + if (NDS32_EXT_FPU_DOT_E) + builtin_define ("__NDS32_EXT_FPU_DOT_E__"); + if (TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) + { + switch (nds32_fp_regnum) + { + case 0: + case 4: + builtin_define ("__NDS32_EXT_FPU_CONFIG_0__"); + break; + case 1: + case 5: + builtin_define ("__NDS32_EXT_FPU_CONFIG_1__"); + break; + case 2: + case 6: + builtin_define ("__NDS32_EXT_FPU_CONFIG_2__"); + break; + case 3: + case 7: + builtin_define ("__NDS32_EXT_FPU_CONFIG_3__"); + break; + default: + abort (); + } + } + + if (TARGET_BIG_ENDIAN) + builtin_define ("__NDS32_EB__"); + else + builtin_define ("__NDS32_EL__"); + + if (TARGET_REDUCED_REGS) + builtin_define ("__NDS32_REDUCED_REGS__"); + if (TARGET_CMOV) + builtin_define ("__NDS32_CMOV__"); + if (TARGET_EXT_PERF) + builtin_define ("__NDS32_EXT_PERF__"); + if (TARGET_EXT_PERF2) + builtin_define ("__NDS32_EXT_PERF2__"); + if (TARGET_EXT_STRING) + builtin_define ("__NDS32_EXT_STRING__"); + if (TARGET_16_BIT) + builtin_define ("__NDS32_16_BIT__"); + if (TARGET_GP_DIRECT) + builtin_define ("__NDS32_GP_DIRECT__"); + if (TARGET_VH) + builtin_define ("__NDS32_VH__"); + if (NDS32_EXT_DSP_P ()) + builtin_define ("__NDS32_EXT_DSP__"); + if (NDS32_HW_LOOP_P ()) + builtin_define ("__NDS32_EXT_ZOL__"); + + /* Extra builtin macros. */ + if (TARGET_ISA_V3 || TARGET_ISA_V3M_PLUS) + builtin_define ("__NDS32_EXT_IFC__"); + if (TARGET_ISA_V3 || TARGET_ISA_V3M_PLUS) + builtin_define ("__NDS32_EXT_EX9__"); + if (TARGET_BIG_ENDIAN) + builtin_define ("__big_endian__"); + + builtin_assert ("cpu=nds32"); + builtin_assert ("machine=nds32"); + + /* FOR BACKWARD COMPATIBILITY. */ + if (TARGET_ISA_V2) + builtin_define ("__NDS32_BASELINE_V2__"); + if (TARGET_ISA_V3) + builtin_define ("__NDS32_BASELINE_V3__"); + if (TARGET_ISA_V3M) + builtin_define ("__NDS32_BASELINE_V3M__"); + if (TARGET_REDUCED_REGS) + builtin_define ("__NDS32_REDUCE_REGS__"); + + if (TARGET_ISA_V2) + builtin_define ("NDS32_BASELINE_V2"); + if (TARGET_ISA_V3) + builtin_define ("NDS32_BASELINE_V3"); + if (TARGET_ISA_V3M) + builtin_define ("NDS32_BASELINE_V3M"); + if (TARGET_REDUCED_REGS) + builtin_define ("NDS32_REDUCE_REGS"); + if (TARGET_FPU_SINGLE) + builtin_define ("NDS32_EXT_FPU_SP"); + if (TARGET_FPU_DOUBLE) + builtin_define ("NDS32_EXT_FPU_DP"); + if (TARGET_EXT_PERF) + builtin_define ("NDS32_EXT_PERF"); + if (TARGET_EXT_PERF2) + builtin_define ("NDS32_EXT_PERF2"); + if (TARGET_EXT_STRING) + builtin_define ("NDS32_EXT_STRING"); + if (TARGET_ISA_V3) + builtin_define ("NDS32_EXT_IFC"); + if (TARGET_ISA_V3) + builtin_define ("NDS32_EXT_EX9"); + + if (TARGET_HARD_FLOAT) + builtin_define ("NDS32_ABI_2FP_PLUS"); + else + builtin_define ("NDS32_ABI_2"); + + if (TARGET_BIG_ENDIAN) + builtin_define ("NDS32_EB"); + else + builtin_define ("NDS32_EL"); + + if (TARGET_ISA_V2) + builtin_define ("__NDS32_BASELINE_V2"); + if (TARGET_ISA_V3) + builtin_define ("__NDS32_BASELINE_V3"); + if (TARGET_ISA_V3M) + builtin_define ("__NDS32_BASELINE_V3M"); + if (TARGET_REDUCED_REGS) + builtin_define ("__NDS32_REDUCE_REGS"); + if (TARGET_FPU_SINGLE) + builtin_define ("__NDS32_EXT_FPU_SP"); + if (TARGET_FPU_DOUBLE) + builtin_define ("__NDS32_EXT_FPU_DP"); + if (TARGET_EXT_PERF) + builtin_define ("__NDS32_EXT_PERF"); + if (TARGET_EXT_PERF2) + builtin_define ("__NDS32_EXT_PERF2"); + if (TARGET_EXT_STRING) + builtin_define ("__NDS32_EXT_STRING"); + if (TARGET_ISA_V3) + builtin_define ("__NDS32_EXT_IFC"); + + if (TARGET_ISA_V3) + builtin_define ("__NDS32_EXT_EX9"); + + if (TARGET_HARD_FLOAT) + builtin_define ("__NDS32_ABI_2FP_PLUS"); + else + builtin_define ("__NDS32_ABI_2"); + + if (TARGET_BIG_ENDIAN) + builtin_define ("__NDS32_EB"); + else + builtin_define ("__NDS32_EL"); +#undef builtin_define +#undef builtin_assert +} + /* Defining Data Structures for Per-function Information. */ @@ -2743,26 +5013,80 @@ nds32_init_expanders (void) /* Register Usage. */ +/* -- Order of Allocation of Registers. */ + +void +nds32_adjust_reg_alloc_order (void) +{ + const int nds32_reg_alloc_order[] = REG_ALLOC_ORDER; + + /* Copy the default register allocation order, which is designed + to optimize for code size. */ + memcpy(reg_alloc_order, nds32_reg_alloc_order, sizeof (reg_alloc_order)); + + /* Adjust few register allocation order when optimizing for speed. */ + if (!optimize_size) + { + memcpy (reg_alloc_order, nds32_reg_alloc_order_for_speed, + sizeof (nds32_reg_alloc_order_for_speed)); + } +} + /* -- How Values Fit in Registers. */ int nds32_hard_regno_nregs (int regno ATTRIBUTE_UNUSED, - machine_mode mode) + enum machine_mode mode) { return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD); } int -nds32_hard_regno_mode_ok (int regno, machine_mode mode) +nds32_hard_regno_mode_ok (int regno, enum machine_mode mode) { + if (regno > FIRST_PSEUDO_REGISTER) + return true; + + if ((TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) && NDS32_IS_FPR_REGNUM (regno)) + { + if (NDS32_IS_EXT_FPR_REGNUM(regno)) + return (NDS32_FPR_REGNO_OK_FOR_DOUBLE(regno) && (mode == DFmode)); + else if (mode == SFmode || mode == SImode) + return NDS32_FPR_REGNO_OK_FOR_SINGLE (regno); + else if (mode == DFmode) + return NDS32_FPR_REGNO_OK_FOR_DOUBLE (regno); + + return false; + } + /* Restrict double-word quantities to even register pairs. */ - if (HARD_REGNO_NREGS (regno, mode) == 1 - || !((regno) & 1)) - return 1; + if (regno <= NDS32_LAST_GPR_REGNUM) + return (HARD_REGNO_NREGS (regno, mode) == 1 + || !((regno) & 1)); - return 0; + return false; } +int +nds32_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2) +{ + if ((GET_MODE_CLASS (mode1) == MODE_INT + && GET_MODE_CLASS (mode2) == MODE_INT) + && GET_MODE_SIZE (mode1) <= UNITS_PER_WORD + && GET_MODE_SIZE (mode2) <= UNITS_PER_WORD) + return true; + + if (GET_MODE_SIZE (mode1) == GET_MODE_SIZE (mode2)) + { + if ((TARGET_FPU_SINGLE && !TARGET_FPU_DOUBLE) + && (mode1 == DFmode || mode2 == DFmode)) + return false; + else + return true; + } + + return false; +} /* Register Classes. */ @@ -2784,7 +5108,16 @@ nds32_regno_reg_class (int regno) else if (regno >= 20 && regno <= 31) return HIGH_REGS; else if (regno == 32 || regno == 33) - return FRAME_REGS; + { + /* $SFP and $AP is FRAME_REGS in fact, However prevent IRA don't + know how to allocate register for $SFP and $AP, just tell IRA they + are GENERAL_REGS, and ARM do this hack too. */ + return GENERAL_REGS; + } + else if (regno >= 34 && regno <= 97) + return FP_REGS; + else if (regno >= 98 && regno <= 100) + return LOOP_REGS; else return NO_REGS; } @@ -2795,14 +5128,39 @@ nds32_regno_reg_class (int regno) /* -- Basic Stack Layout. */ rtx +nds32_dynamic_chain_address (rtx frameaddr) +{ + if (TARGET_V3PUSH) + { + /* If -mv3push is specified, we push $fp, $gp, and $lp into stack. + We can access dynamic chain address from stack by [$fp - 12]. */ + return plus_constant (Pmode, frameaddr, -12); + } + else + { + /* For general case we push $fp and $lp into stack at prologue. + We can access dynamic chain address from stack by [$fp - 8]. */ + return plus_constant (Pmode, frameaddr, -8); + } +} + +rtx nds32_return_addr_rtx (int count, - rtx frameaddr ATTRIBUTE_UNUSED) + rtx frameaddr) { - /* There is no way to determine the return address - if frameaddr is the frame that has 'count' steps - up from current frame. */ + int offset; + rtx addr; + if (count != 0) - return NULL_RTX; + { + /* In nds32 ABI design, we can expect that $lp is always available + from stack by [$fp - 4] location. */ + offset = -4; + addr = plus_constant (Pmode, frameaddr, offset); + addr = memory_address (Pmode, addr); + + return gen_rtx_MEM (Pmode, addr); + } /* If count == 0, it means we are at current frame, the return address is $r30 ($lp). */ @@ -2821,15 +5179,18 @@ nds32_initial_elimination_offset (unsigned int from_reg, unsigned int to_reg) nds32_compute_stack_frame (); /* Remember to consider - cfun->machine->callee_saved_area_padding_bytes + cfun->machine->callee_saved_area_gpr_padding_bytes and + cfun->machine->eh_return_data_regs_size when calculating offset. */ if (from_reg == ARG_POINTER_REGNUM && to_reg == STACK_POINTER_REGNUM) { offset = (cfun->machine->fp_size - + cfun->machine->gp_size + + cfun->machine->gp_size + cfun->machine->lp_size + cfun->machine->callee_saved_gpr_regs_size + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size + + cfun->machine->eh_return_data_regs_size + cfun->machine->local_size + cfun->machine->out_args_size); } @@ -2850,7 +5211,9 @@ nds32_initial_elimination_offset (unsigned int from_reg, unsigned int to_reg) + cfun->machine->gp_size + cfun->machine->lp_size + cfun->machine->callee_saved_gpr_regs_size - + cfun->machine->callee_saved_area_gpr_padding_bytes); + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size + + cfun->machine->eh_return_data_regs_size); } else { @@ -2869,10 +5232,11 @@ nds32_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fndecl ATTRIBUTE_UNUSED, int n_named_args ATTRIBUTE_UNUSED) { - /* Initial available registers - (in offset, corresponding to NDS32_GPR_ARG_FIRST_REGNUM) + /* Initial available registers. The values are offset against + NDS32_GPR_ARG_FIRST_REGNUM and NDS32_FPR_ARG_FIRST_REGNUM for passing arguments. */ cum->gpr_offset = 0; + cum->fpr_offset = 0; } /* -- Function Entry and Exit. */ @@ -2883,125 +5247,178 @@ nds32_expand_prologue (void) { int fp_adjust; int sp_adjust; - int en4_const; - - rtx Rb, Re; - rtx fp_adjust_insn, sp_adjust_insn; + unsigned Rb, Re; /* Compute and setup stack frame size. The result will be in cfun->machine. */ nds32_compute_stack_frame (); + /* Check frame_pointer_needed again to prevent fp is need after reload. */ + if (frame_pointer_needed) + cfun->machine->fp_as_gp_p = false; + /* If this is a variadic function, first we need to push argument registers that hold the unnamed argument value. */ if (cfun->machine->va_args_size != 0) { - Rb = gen_rtx_REG (SImode, cfun->machine->va_args_first_regno); - Re = gen_rtx_REG (SImode, cfun->machine->va_args_last_regno); - /* No need to push $fp, $gp, or $lp, so use GEN_INT(0). */ - nds32_emit_stack_push_multiple (Rb, Re, GEN_INT (0), true); + Rb = cfun->machine->va_args_first_regno; + Re = cfun->machine->va_args_last_regno; + /* No need to push $fp, $gp, or $lp. */ + nds32_emit_stack_push_multiple (Rb, Re, false, false, false, true); /* We may also need to adjust stack pointer for padding bytes - because varargs may cause $sp not 8-byte aligned. */ + because varargs may cause $sp not 8-byte aligned. */ if (cfun->machine->va_args_area_padding_bytes) { /* Generate sp adjustment instruction. */ sp_adjust = cfun->machine->va_args_area_padding_bytes; - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (-1 * sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); - - /* The insn rtx 'sp_adjust_insn' will change frame layout. - We need to use RTX_FRAME_RELATED_P so that GCC is able to - generate CFI (Call Frame Information) stuff. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + -1 * sp_adjust); } } /* If the function is 'naked', we do not have to generate prologue code fragment. */ - if (cfun->machine->naked_p) + if (cfun->machine->naked_p && !flag_pic) return; /* Get callee_first_regno and callee_last_regno. */ - Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno); - Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno); - - /* nds32_emit_stack_push_multiple(first_regno, last_regno), - the pattern 'stack_push_multiple' is implemented in nds32.md. - For En4 field, we have to calculate its constant value. - Refer to Andes ISA for more information. */ - en4_const = 0; - if (cfun->machine->fp_size) - en4_const += 8; - if (cfun->machine->gp_size) - en4_const += 4; - if (cfun->machine->lp_size) - en4_const += 2; + Rb = cfun->machine->callee_saved_first_gpr_regno; + Re = cfun->machine->callee_saved_last_gpr_regno; /* If $fp, $gp, $lp, and all callee-save registers are NOT required to be saved, we don't have to create multiple push instruction. Otherwise, a multiple push instruction is needed. */ - if (!(REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM && en4_const == 0)) + if (!(Rb == SP_REGNUM && Re == SP_REGNUM + && cfun->machine->fp_size == 0 + && cfun->machine->gp_size == 0 + && cfun->machine->lp_size == 0)) { /* Create multiple push instruction rtx. */ - nds32_emit_stack_push_multiple (Rb, Re, GEN_INT (en4_const), false); + nds32_emit_stack_push_multiple ( + Rb, Re, + cfun->machine->fp_size, cfun->machine->gp_size, cfun->machine->lp_size, + false); + } + + /* Save eh data registers. */ + if (cfun->machine->use_eh_return_p) + { + Rb = cfun->machine->eh_return_data_first_regno; + Re = cfun->machine->eh_return_data_last_regno; + + /* No need to push $fp, $gp, or $lp. + Also, this is not variadic arguments push. */ + nds32_emit_stack_push_multiple (Rb, Re, false, false, false, false); } - /* Check frame_pointer_needed to see - if we shall emit fp adjustment instruction. */ - if (frame_pointer_needed) - { - /* adjust $fp = $sp + ($fp size) + ($gp size) + ($lp size) - + (4 * callee-saved-registers) - Note: No need to adjust - cfun->machine->callee_saved_area_padding_bytes, - because, at this point, stack pointer is just - at the position after push instruction. */ - fp_adjust = cfun->machine->fp_size - + cfun->machine->gp_size - + cfun->machine->lp_size - + cfun->machine->callee_saved_gpr_regs_size; - fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx, + /* Check frame_pointer_needed to see + if we shall emit fp adjustment instruction. */ + if (frame_pointer_needed) + { + /* adjust $fp = $sp + ($fp size) + ($gp size) + ($lp size) + + (4 * callee-saved-registers) + + (4 * exception-handling-data-registers) + Note: No need to adjust + cfun->machine->callee_saved_area_gpr_padding_bytes, + because, at this point, stack pointer is just + at the position after push instruction. */ + fp_adjust = cfun->machine->fp_size + + cfun->machine->gp_size + + cfun->machine->lp_size + + cfun->machine->callee_saved_gpr_regs_size + + cfun->machine->eh_return_data_regs_size; + + nds32_emit_adjust_frame (hard_frame_pointer_rtx, + stack_pointer_rtx, + fp_adjust); + } + + /* Save fpu registers. */ + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + /* When $sp moved to bottom of stack, we need to check whether + the range of offset in the FPU instruction. */ + int fpr_offset = cfun->machine->local_size + + cfun->machine->out_args_size + + cfun->machine->callee_saved_fpr_regs_size; + + /* Check FPU instruction offset imm14s. */ + if (!satisfies_constraint_Is14 (GEN_INT (fpr_offset))) + { + int fpr_space = cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + + /* Save fpu registers, need to allocate stack space + for fpu callee registers. And now $sp position + on callee saved fpr registers. */ + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + -1 * fpr_space); + + /* Emit fpu store instruction, using [$sp + offset] store + fpu registers. */ + nds32_emit_push_fpr_callee_saved (0); + + /* Adjust $sp = $sp - local_size - out_args_size. */ + sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size; + + /* Allocate stack space for local size and out args size. */ + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + -1 * sp_adjust); + } + else + { + /* Offset range in Is14, so $sp moved to bottom of stack. */ + + /* Adjust $sp = $sp - local_size - out_args_size + - callee_saved_area_gpr_padding_bytes + - callee_saved_fpr_regs_size. */ + sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + + nds32_emit_adjust_frame (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (fp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - fp_adjust_insn = emit_insn (fp_adjust_insn); + -1 * sp_adjust); - /* The insn rtx 'fp_adjust_insn' will change frame layout. */ - RTX_FRAME_RELATED_P (fp_adjust_insn) = 1; + /* Emit fpu store instruction, using [$sp + offset] store + fpu registers. */ + int fpr_position = cfun->machine->out_args_size + + cfun->machine->local_size; + nds32_emit_push_fpr_callee_saved (fpr_position); + } } - - /* Adjust $sp = $sp - local_size - out_args_size - - callee_saved_area_padding_bytes. */ - sp_adjust = cfun->machine->local_size - + cfun->machine->out_args_size - + cfun->machine->callee_saved_area_gpr_padding_bytes; - /* sp_adjust value may be out of range of the addi instruction, - create alternative add behavior with TA_REGNUM if necessary, - using NEGATIVE value to tell that we are decreasing address. */ - sp_adjust = nds32_force_addi_stack_int ( (-1) * sp_adjust); - if (sp_adjust) + else { - /* Generate sp adjustment instruction if and only if sp_adjust != 0. */ - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (-1 * sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); + /* Adjust $sp = $sp - local_size - out_args_size + - callee_saved_area_gpr_padding_bytes. */ + sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size + + cfun->machine->callee_saved_area_gpr_padding_bytes; - /* The insn rtx 'sp_adjust_insn' will change frame layout. - We need to use RTX_FRAME_RELATED_P so that GCC is able to - generate CFI (Call Frame Information) stuff. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; + /* sp_adjust value may be out of range of the addi instruction, + create alternative add behavior with TA_REGNUM if necessary, + using NEGATIVE value to tell that we are decreasing address. */ + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + -1 * sp_adjust); } - /* Prevent the instruction scheduler from - moving instructions across the boundary. */ - emit_insn (gen_blockage ()); + /* Emit gp setup instructions for -fpic. */ + if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM)) + nds32_emit_load_gp (); + + /* If user applies -mno-sched-prolog-epilog option, + we need to prevent instructions of function body from being + scheduled with stack adjustment in prologue. */ + if (!flag_sched_prolog_epilog) + emit_insn (gen_blockage ()); } /* Function for normal multiple pop epilogue. */ @@ -3009,18 +5426,17 @@ void nds32_expand_epilogue (bool sibcall_p) { int sp_adjust; - int en4_const; - - rtx Rb, Re; - rtx sp_adjust_insn; + unsigned Rb, Re; /* Compute and setup stack frame size. The result will be in cfun->machine. */ nds32_compute_stack_frame (); - /* Prevent the instruction scheduler from - moving instructions across the boundary. */ - emit_insn (gen_blockage ()); + /* If user applies -mno-sched-prolog-epilog option, + we need to prevent instructions of function body from being + scheduled with stack adjustment in epilogue. */ + if (!flag_sched_prolog_epilog) + emit_insn (gen_blockage ()); /* If the function is 'naked', we do not have to generate epilogue code fragment BUT 'ret' instruction. @@ -3029,110 +5445,156 @@ nds32_expand_epilogue (bool sibcall_p) if (cfun->machine->naked_p) { /* If this is a variadic function, we do not have to restore argument - registers but need to adjust stack pointer back to previous stack - frame location before return. */ + registers but need to adjust stack pointer back to previous stack + frame location before return. */ if (cfun->machine->va_args_size != 0) { /* Generate sp adjustment instruction. We need to consider padding bytes here. */ sp_adjust = cfun->machine->va_args_size + cfun->machine->va_args_area_padding_bytes; - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); - /* The insn rtx 'sp_adjust_insn' will change frame layout. - We need to use RTX_FRAME_RELATED_P so that GCC is able to - generate CFI (Call Frame Information) stuff. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + sp_adjust); } /* Generate return instruction by using 'return_internal' pattern. - Make sure this instruction is after gen_blockage(). */ + Make sure this instruction is after gen_blockage(). + First we need to check this is a function without sibling call. */ if (!sibcall_p) - emit_jump_insn (gen_return_internal ()); + { + /* We need to further check attributes to determine whether + there should be return instruction at epilogue. + If the attribute naked exists but -mno-ret-in-naked-func + is issued, there is NO need to generate return instruction. */ + if (cfun->machine->attr_naked_p && !flag_ret_in_naked_func) + return; + + emit_jump_insn (gen_return_internal ()); + } return; } if (frame_pointer_needed) { - /* adjust $sp = $fp - ($fp size) - ($gp size) - ($lp size) - - (4 * callee-saved-registers) - Note: No need to adjust - cfun->machine->callee_saved_area_padding_bytes, - because we want to adjust stack pointer - to the position for pop instruction. */ - sp_adjust = cfun->machine->fp_size - + cfun->machine->gp_size - + cfun->machine->lp_size - + cfun->machine->callee_saved_gpr_regs_size; - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, + /* Restore fpu registers. */ + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + int gpr_padding = cfun->machine->callee_saved_area_gpr_padding_bytes; + + /* adjust $sp = $fp - ($fp size) - ($gp size) - ($lp size) + - (4 * callee-saved-registers) + - (4 * exception-handling-data-registers) + - (4 * callee-saved-gpr-registers padding byte) + - (4 * callee-saved-fpr-registers) + Note: we want to adjust stack pointer + to the position for callee-saved fpr register, + And restore fpu register use .bi instruction to adjust $sp + from callee-saved fpr register to pop instruction. */ + sp_adjust = cfun->machine->fp_size + + cfun->machine->gp_size + + cfun->machine->lp_size + + cfun->machine->callee_saved_gpr_regs_size + + cfun->machine->eh_return_data_regs_size + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + + nds32_emit_adjust_frame (stack_pointer_rtx, hard_frame_pointer_rtx, - GEN_INT (-1 * sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); + -1 * sp_adjust); + + /* Emit fpu load instruction, using .bi instruction + load fpu registers. */ + nds32_emit_pop_fpr_callee_saved (gpr_padding); + } + else + { + /* adjust $sp = $fp - ($fp size) - ($gp size) - ($lp size) + - (4 * callee-saved-registers) + - (4 * exception-handling-data-registers) + Note: No need to adjust + cfun->machine->callee_saved_area_gpr_padding_bytes, + because we want to adjust stack pointer + to the position for pop instruction. */ + sp_adjust = cfun->machine->fp_size + + cfun->machine->gp_size + + cfun->machine->lp_size + + cfun->machine->callee_saved_gpr_regs_size + + cfun->machine->eh_return_data_regs_size; - /* The insn rtx 'sp_adjust_insn' will change frame layout. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; + nds32_emit_adjust_frame (stack_pointer_rtx, + hard_frame_pointer_rtx, + -1 * sp_adjust); + } } else { - /* If frame pointer is NOT needed, - we cannot calculate the sp adjustment from frame pointer. - Instead, we calculate the adjustment by local_size, - out_args_size, and callee_saved_area_padding_bytes. - Notice that such sp adjustment value may be out of range, - so we have to deal with it as well. */ + /* Restore fpu registers. */ + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + int gpr_padding = cfun->machine->callee_saved_area_gpr_padding_bytes; - /* Adjust $sp = $sp + local_size + out_args_size - + callee_saved_area_padding_bytes. */ - sp_adjust = cfun->machine->local_size - + cfun->machine->out_args_size - + cfun->machine->callee_saved_area_gpr_padding_bytes; - /* sp_adjust value may be out of range of the addi instruction, - create alternative add behavior with TA_REGNUM if necessary, - using POSITIVE value to tell that we are increasing address. */ - sp_adjust = nds32_force_addi_stack_int (sp_adjust); - if (sp_adjust) - { - /* Generate sp adjustment instruction - if and only if sp_adjust != 0. */ - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); + /* Adjust $sp = $sp + local_size + out_args_size. */ + sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size; - /* The insn rtx 'sp_adjust_insn' will change frame layout. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + sp_adjust); + + /* Emit fpu load instruction, using .bi instruction + load fpu registers, and adjust $sp from callee-saved fpr register + to callee-saved gpr register. */ + nds32_emit_pop_fpr_callee_saved (gpr_padding); + } + else + { + /* If frame pointer is NOT needed, + we cannot calculate the sp adjustment from frame pointer. + Instead, we calculate the adjustment by local_size, + out_args_size, and callee_saved_area_gpr_padding_bytes. + Notice that such sp adjustment value may be out of range, + so we have to deal with it as well. */ + + /* Adjust $sp = $sp + local_size + out_args_size + + callee_saved_area_gpr_padding_bytes. */ + sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size + + cfun->machine->callee_saved_area_gpr_padding_bytes; + + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + sp_adjust); } } + /* Restore eh data registers. */ + if (cfun->machine->use_eh_return_p) + { + Rb = cfun->machine->eh_return_data_first_regno; + Re = cfun->machine->eh_return_data_last_regno; + + /* No need to pop $fp, $gp, or $lp. */ + nds32_emit_stack_pop_multiple (Rb, Re, false, false, false); + } + /* Get callee_first_regno and callee_last_regno. */ - Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno); - Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno); - - /* nds32_emit_stack_pop_multiple(first_regno, last_regno), - the pattern 'stack_pop_multiple' is implementad in nds32.md. - For En4 field, we have to calculate its constant value. - Refer to Andes ISA for more information. */ - en4_const = 0; - if (cfun->machine->fp_size) - en4_const += 8; - if (cfun->machine->gp_size) - en4_const += 4; - if (cfun->machine->lp_size) - en4_const += 2; + Rb = cfun->machine->callee_saved_first_gpr_regno; + Re = cfun->machine->callee_saved_last_gpr_regno; /* If $fp, $gp, $lp, and all callee-save registers are NOT required to be saved, we don't have to create multiple pop instruction. Otherwise, a multiple pop instruction is needed. */ - if (!(REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM && en4_const == 0)) + if (!(Rb == SP_REGNUM && Re == SP_REGNUM + && cfun->machine->fp_size == 0 + && cfun->machine->gp_size == 0 + && cfun->machine->lp_size == 0)) { /* Create multiple pop instruction rtx. */ - nds32_emit_stack_pop_multiple (Rb, Re, GEN_INT (en4_const)); + nds32_emit_stack_pop_multiple ( + Rb, Re, + cfun->machine->fp_size, cfun->machine->gp_size, cfun->machine->lp_size); } /* If this is a variadic function, we do not have to restore argument @@ -3141,19 +5603,49 @@ nds32_expand_epilogue (bool sibcall_p) if (cfun->machine->va_args_size != 0) { /* Generate sp adjustment instruction. - We need to consider padding bytes here. */ + We need to consider padding bytes here. */ sp_adjust = cfun->machine->va_args_size + cfun->machine->va_args_area_padding_bytes; - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); - /* The insn rtx 'sp_adjust_insn' will change frame layout. - We need to use RTX_FRAME_RELATED_P so that GCC is able to - generate CFI (Call Frame Information) stuff. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + sp_adjust); + } + + /* If this function uses __builtin_eh_return, make stack adjustment + for exception handler. */ + if (cfun->machine->use_eh_return_p) + { + /* We need to unwind the stack by the offset computed by + EH_RETURN_STACKADJ_RTX. However, at this point the CFA is + based on SP. Ideally we would update the SP and define the + CFA along the lines of: + + SP = SP + EH_RETURN_STACKADJ_RTX + (regnote CFA = SP - EH_RETURN_STACKADJ_RTX) + + However the dwarf emitter only understands a constant + register offset. + + The solution chosen here is to use the otherwise $ta ($r15) + as a temporary register to hold the current SP value. The + CFA is described using $ta then SP is modified. */ + + rtx ta_reg; + rtx insn; + + ta_reg = gen_rtx_REG (SImode, TA_REGNUM); + + insn = emit_move_insn (ta_reg, stack_pointer_rtx); + add_reg_note (insn, REG_CFA_DEF_CFA, ta_reg); + RTX_FRAME_RELATED_P (insn) = 1; + + emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, + EH_RETURN_STACKADJ_RTX)); + + /* Ensure the assignment to $ta does not get optimized away. */ + emit_use (ta_reg); } /* Generate return instruction. */ @@ -3167,28 +5659,35 @@ nds32_expand_prologue_v3push (void) { int fp_adjust; int sp_adjust; - - rtx Rb, Re; - rtx fp_adjust_insn, sp_adjust_insn; + int fpr_space = 0; + unsigned Rb, Re; /* Compute and setup stack frame size. The result will be in cfun->machine. */ nds32_compute_stack_frame (); + if (cfun->machine->callee_saved_gpr_regs_size > 0) + df_set_regs_ever_live (FP_REGNUM, 1); + + /* Check frame_pointer_needed again to prevent fp is need after reload. */ + if (frame_pointer_needed) + cfun->machine->fp_as_gp_p = false; + /* If the function is 'naked', we do not have to generate prologue code fragment. */ - if (cfun->machine->naked_p) + if (cfun->machine->naked_p && !flag_pic) return; /* Get callee_first_regno and callee_last_regno. */ - Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno); - Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno); + Rb = cfun->machine->callee_saved_first_gpr_regno; + Re = cfun->machine->callee_saved_last_gpr_regno; /* Calculate sp_adjust first to test if 'push25 Re,imm8u' is available, where imm8u has to be 8-byte alignment. */ sp_adjust = cfun->machine->local_size + cfun->machine->out_args_size - + cfun->machine->callee_saved_area_gpr_padding_bytes; + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)) @@ -3196,94 +5695,118 @@ nds32_expand_prologue_v3push (void) /* We can use 'push25 Re,imm8u'. */ /* nds32_emit_stack_v3push(last_regno, sp_adjust), - the pattern 'stack_v3push' is implemented in nds32.md. - The (const_int 14) means v3push always push { $fp $gp $lp }. */ - nds32_emit_stack_v3push (Rb, Re, - GEN_INT (14), GEN_INT (sp_adjust)); + the pattern 'stack_v3push' is implemented in nds32.md. */ + nds32_emit_stack_v3push (Rb, Re, sp_adjust); + + /* Save fpu registers. */ + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + /* Calculate fpr position. */ + int fpr_position = cfun->machine->local_size + + cfun->machine->out_args_size; + /* Emit fpu store instruction, using [$sp + offset] store + fpu registers. */ + nds32_emit_push_fpr_callee_saved (fpr_position); + } /* Check frame_pointer_needed to see - if we shall emit fp adjustment instruction. */ + if we shall emit fp adjustment instruction. */ if (frame_pointer_needed) { /* adjust $fp = $sp + 4 ($fp size) - + 4 ($gp size) - + 4 ($lp size) - + (4 * n) (callee-saved registers) - + sp_adjust ('push25 Re,imm8u') + + 4 ($gp size) + + 4 ($lp size) + + (4 * n) (callee-saved registers) + + sp_adjust ('push25 Re,imm8u') Note: Since we use 'push25 Re,imm8u', - the position of stack pointer is further - changed after push instruction. - Hence, we need to take sp_adjust value - into consideration. */ + the position of stack pointer is further + changed after push instruction. + Hence, we need to take sp_adjust value + into consideration. */ fp_adjust = cfun->machine->fp_size + cfun->machine->gp_size + cfun->machine->lp_size + cfun->machine->callee_saved_gpr_regs_size + sp_adjust; - fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx, - stack_pointer_rtx, - GEN_INT (fp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - fp_adjust_insn = emit_insn (fp_adjust_insn); + + nds32_emit_adjust_frame (hard_frame_pointer_rtx, + stack_pointer_rtx, + fp_adjust); } } else { - /* We have to use 'push25 Re,0' and - expand one more instruction to adjust $sp later. */ + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + /* Calculate fpr space. */ + fpr_space = cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + + /* We have to use 'push25 Re, fpr_space', to pre-allocate + callee saved fpr registers space. */ + nds32_emit_stack_v3push (Rb, Re, fpr_space); + nds32_emit_push_fpr_callee_saved (0); + } + else + { + /* We have to use 'push25 Re,0' and + expand one more instruction to adjust $sp later. */ - /* nds32_emit_stack_v3push(last_regno, sp_adjust), - the pattern 'stack_v3push' is implemented in nds32.md. - The (const_int 14) means v3push always push { $fp $gp $lp }. */ - nds32_emit_stack_v3push (Rb, Re, - GEN_INT (14), GEN_INT (0)); + /* nds32_emit_stack_v3push(last_regno, sp_adjust), + the pattern 'stack_v3push' is implemented in nds32.md. */ + nds32_emit_stack_v3push (Rb, Re, 0); + } /* Check frame_pointer_needed to see - if we shall emit fp adjustment instruction. */ + if we shall emit fp adjustment instruction. */ if (frame_pointer_needed) { /* adjust $fp = $sp + 4 ($fp size) - + 4 ($gp size) - + 4 ($lp size) - + (4 * n) (callee-saved registers) + + 4 ($gp size) + + 4 ($lp size) + + (4 * n) (callee-saved registers) Note: Since we use 'push25 Re,0', - the stack pointer is just at the position - after push instruction. - No need to take sp_adjust into consideration. */ + the stack pointer is just at the position + after push instruction. + No need to take sp_adjust into consideration. */ fp_adjust = cfun->machine->fp_size + cfun->machine->gp_size + cfun->machine->lp_size + cfun->machine->callee_saved_gpr_regs_size; - fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx, - stack_pointer_rtx, - GEN_INT (fp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - fp_adjust_insn = emit_insn (fp_adjust_insn); - } - /* Because we use 'push25 Re,0', - we need to expand one more instruction to adjust $sp. - However, sp_adjust value may be out of range of the addi instruction, - create alternative add behavior with TA_REGNUM if necessary, - using NEGATIVE value to tell that we are decreasing address. */ - sp_adjust = nds32_force_addi_stack_int ( (-1) * sp_adjust); - if (sp_adjust) - { - /* Generate sp adjustment instruction - if and only if sp_adjust != 0. */ - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (-1 * sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + /* We use 'push25 Re, fpr_space', the $sp is + on callee saved fpr position, so need to consider + fpr space. */ + fp_adjust = fp_adjust + fpr_space; + } + + nds32_emit_adjust_frame (hard_frame_pointer_rtx, + stack_pointer_rtx, + fp_adjust); + } - /* The insn rtx 'sp_adjust_insn' will change frame layout. - We need to use RTX_FRAME_RELATED_P so that GCC is able to - generate CFI (Call Frame Information) stuff. */ - RTX_FRAME_RELATED_P (sp_adjust_insn) = 1; + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + /* We use 'push25 Re, fpr_space', + the $sp is on callee saved fpr position, + no need to consider fpr space. */ + sp_adjust = sp_adjust - fpr_space; } + + /* Because we use 'push25 Re,0', + we need to expand one more instruction to adjust $sp. + using NEGATIVE value to tell that we are decreasing address. */ + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + -1 * sp_adjust); } + /* Emit gp setup instructions for -fpic. */ + if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM)) + nds32_emit_load_gp (); + /* Prevent the instruction scheduler from moving instructions across the boundary. */ emit_insn (gen_blockage ()); @@ -3294,9 +5817,7 @@ void nds32_expand_epilogue_v3pop (bool sibcall_p) { int sp_adjust; - - rtx Rb, Re; - rtx sp_adjust_insn; + unsigned Rb, Re; /* Compute and setup stack frame size. The result will be in cfun->machine. */ @@ -3311,21 +5832,32 @@ nds32_expand_epilogue_v3pop (bool sibcall_p) if (cfun->machine->naked_p) { /* Generate return instruction by using 'return_internal' pattern. - Make sure this instruction is after gen_blockage(). */ + Make sure this instruction is after gen_blockage(). + First we need to check this is a function without sibling call. */ if (!sibcall_p) - emit_jump_insn (gen_return_internal ()); + { + /* We need to further check attributes to determine whether + there should be return instruction at epilogue. + If the attribute naked exists but -mno-ret-in-naked-func + is issued, there is NO need to generate return instruction. */ + if (cfun->machine->attr_naked_p && !flag_ret_in_naked_func) + return; + + emit_jump_insn (gen_return_internal ()); + } return; } /* Get callee_first_regno and callee_last_regno. */ - Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno); - Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno); + Rb = cfun->machine->callee_saved_first_gpr_regno; + Re = cfun->machine->callee_saved_last_gpr_regno; /* Calculate sp_adjust first to test if 'pop25 Re,imm8u' is available, where imm8u has to be 8-byte alignment. */ sp_adjust = cfun->machine->local_size + cfun->machine->out_args_size - + cfun->machine->callee_saved_area_gpr_padding_bytes; + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; /* We have to consider alloca issue as well. If the function does call alloca(), the stack pointer is not fixed. @@ -3338,38 +5870,65 @@ nds32_expand_epilogue_v3pop (bool sibcall_p) && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust) && !cfun->calls_alloca) { + /* Restore fpu registers. */ + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + int fpr_position = cfun->machine->local_size + + cfun->machine->out_args_size; + /* Emit fpu load instruction, using [$sp + offset] restore + fpu registers. */ + nds32_emit_v3pop_fpr_callee_saved (fpr_position); + } + /* We can use 'pop25 Re,imm8u'. */ /* nds32_emit_stack_v3pop(last_regno, sp_adjust), - the pattern 'stack_v3pop' is implementad in nds32.md. - The (const_int 14) means v3pop always pop { $fp $gp $lp }. */ - nds32_emit_stack_v3pop (Rb, Re, - GEN_INT (14), GEN_INT (sp_adjust)); + the pattern 'stack_v3pop' is implementad in nds32.md. */ + nds32_emit_stack_v3pop (Rb, Re, sp_adjust); } else { /* We have to use 'pop25 Re,0', and prior to it, - we must expand one more instruction to adjust $sp. */ + we must expand one more instruction to adjust $sp. */ if (frame_pointer_needed) { /* adjust $sp = $fp - 4 ($fp size) - - 4 ($gp size) - - 4 ($lp size) - - (4 * n) (callee-saved registers) + - 4 ($gp size) + - 4 ($lp size) + - (4 * n) (callee-saved registers) Note: No need to adjust - cfun->machine->callee_saved_area_padding_bytes, - because we want to adjust stack pointer - to the position for pop instruction. */ + cfun->machine->callee_saved_area_gpr_padding_bytes, + because we want to adjust stack pointer + to the position for pop instruction. */ sp_adjust = cfun->machine->fp_size + cfun->machine->gp_size + cfun->machine->lp_size + cfun->machine->callee_saved_gpr_regs_size; - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, + + /* Restore fpu registers. */ + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + /* Set $sp to callee saved fpr position, we need to restore + fpr registers. */ + sp_adjust = sp_adjust + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + + nds32_emit_adjust_frame (stack_pointer_rtx, + hard_frame_pointer_rtx, + -1 * sp_adjust); + + /* Emit fpu load instruction, using [$sp + offset] restore + fpu registers. */ + nds32_emit_v3pop_fpr_callee_saved (0); + } + else + { + nds32_emit_adjust_frame (stack_pointer_rtx, hard_frame_pointer_rtx, - GEN_INT (-1 * sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); + -1 * sp_adjust); + } } else { @@ -3381,33 +5940,57 @@ nds32_expand_epilogue_v3pop (bool sibcall_p) so we have to deal with it as well. */ /* Adjust $sp = $sp + local_size + out_args_size - + callee_saved_area_padding_bytes. */ + + callee_saved_area_gpr_padding_bytes + + callee_saved_fpr_regs_size. */ sp_adjust = cfun->machine->local_size + cfun->machine->out_args_size - + cfun->machine->callee_saved_area_gpr_padding_bytes; - /* sp_adjust value may be out of range of the addi instruction, - create alternative add behavior with TA_REGNUM if necessary, - using POSITIVE value to tell that we are increasing address. */ - sp_adjust = nds32_force_addi_stack_int (sp_adjust); - if (sp_adjust) + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + + /* Restore fpu registers. */ + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + /* Set $sp to callee saved fpr position, we need to restore + fpr registers. */ + sp_adjust = sp_adjust + - cfun->machine->callee_saved_area_gpr_padding_bytes + - cfun->machine->callee_saved_fpr_regs_size; + + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + sp_adjust); + + /* Emit fpu load instruction, using [$sp + offset] restore + fpu registers. */ + nds32_emit_v3pop_fpr_callee_saved (0); + } + else { - /* Generate sp adjustment instruction - if and only if sp_adjust != 0. */ - sp_adjust_insn = gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (sp_adjust)); - /* Emit rtx into instructions list and receive INSN rtx form. */ - sp_adjust_insn = emit_insn (sp_adjust_insn); + /* sp_adjust value may be out of range of the addi instruction, + create alternative add behavior with TA_REGNUM if necessary, + using POSITIVE value to tell that we are increasing + address. */ + nds32_emit_adjust_frame (stack_pointer_rtx, + stack_pointer_rtx, + sp_adjust); } } - /* nds32_emit_stack_v3pop(last_regno, sp_adjust), - the pattern 'stack_v3pop' is implementad in nds32.md. */ - /* The (const_int 14) means v3pop always pop { $fp $gp $lp }. */ - nds32_emit_stack_v3pop (Rb, Re, - GEN_INT (14), GEN_INT (0)); + if (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM) + { + /* We have fpr need to restore, so $sp is set on callee saved fpr + position. And we use 'pop25 Re, fpr_space' to adjust $sp. */ + int fpr_space = cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + nds32_emit_stack_v3pop (Rb, Re, fpr_space); + } + else + { + /* nds32_emit_stack_v3pop(last_regno, sp_adjust), + the pattern 'stack_v3pop' is implementad in nds32.md. */ + nds32_emit_stack_v3pop (Rb, Re, 0); + } } - /* Generate return instruction. */ emit_jump_insn (gen_pop25return ()); } @@ -3418,97 +6001,179 @@ nds32_expand_epilogue_v3pop (bool sibcall_p) int nds32_can_use_return_insn (void) { + int sp_adjust; + /* Prior to reloading, we can't tell how many registers must be saved. Thus we can not determine whether this function has null epilogue. */ if (!reload_completed) return 0; + /* If attribute 'naked' appears but -mno-ret-in-naked-func is used, + we cannot use return instruction. */ + if (cfun->machine->attr_naked_p && !flag_ret_in_naked_func) + return 0; + + sp_adjust = cfun->machine->local_size + + cfun->machine->out_args_size + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size; + if (!cfun->machine->fp_as_gp_p + && satisfies_constraint_Iu08 (GEN_INT (sp_adjust)) + && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust) + && !cfun->calls_alloca + && NDS32_V3PUSH_AVAILABLE_P + && !(TARGET_HARD_FLOAT + && (cfun->machine->callee_saved_first_fpr_regno != SP_REGNUM))) + return 1; + /* If no stack was created, two conditions must be satisfied: 1. This is a naked function. - So there is no callee-saved, local size, or outgoing size. + So there is no callee-saved, local size, or outgoing size. 2. This is NOT a variadic function. - So there is no pushing arguement registers into the stack. */ - return (cfun->machine->naked_p && (cfun->machine->va_args_size == 0)); + So there is no pushing arguement registers into the stack. */ + return ((cfun->machine->naked_p && (cfun->machine->va_args_size == 0))); } -/* ------------------------------------------------------------------------ */ - -/* Function to test 333-form for load/store instructions. - This is auxiliary extern function for auxiliary macro in nds32.h. - Because it is a little complicated, we use function instead of macro. */ -bool -nds32_ls_333_p (rtx rt, rtx ra, rtx imm, machine_mode mode) +enum machine_mode +nds32_case_vector_shorten_mode (int min_offset, int max_offset, + rtx body ATTRIBUTE_UNUSED) { - if (REGNO_REG_CLASS (REGNO (rt)) == LOW_REGS - && REGNO_REG_CLASS (REGNO (ra)) == LOW_REGS) + if (min_offset < 0 || max_offset >= 0x2000) + return SImode; + else { - if (GET_MODE_SIZE (mode) == 4) - return satisfies_constraint_Iu05 (imm); - - if (GET_MODE_SIZE (mode) == 2) - return satisfies_constraint_Iu04 (imm); - - if (GET_MODE_SIZE (mode) == 1) - return satisfies_constraint_Iu03 (imm); + /* The jump table maybe need to 2 byte alignment, + so reserved 1 byte for check max_offset. */ + if (max_offset >= 0xff) + return HImode; + else + return QImode; } +} + +static bool +nds32_cannot_copy_insn_p (rtx_insn *insn) +{ + /* The hwloop_cfg insn cannot be copied. */ + if (recog_memoized (insn) == CODE_FOR_hwloop_cfg) + return true; return false; } - -/* Computing the Length of an Insn. - Modifies the length assigned to instruction INSN. - LEN is the initially computed length of the insn. */ +/* Return alignment for the label. */ int -nds32_adjust_insn_length (rtx_insn *insn, int length) +nds32_target_alignment (rtx label) { - rtx src, dst; + rtx_insn *insn; - switch (recog_memoized (insn)) + if (!NDS32_ALIGN_P ()) + return 0; + + insn = next_active_insn (label); + + /* Always align to 4 byte when first instruction after label is jump + instruction since length for that might changed, so let's always align + it for make sure we don't lose any perfomance here. */ + if (insn == 0 + || (get_attr_length (insn) == 2 + && !JUMP_P (insn) && !CALL_P (insn))) + return 0; + else + return 2; +} + +/* Return alignment for data. */ +unsigned int +nds32_data_alignment (tree data, + unsigned int basic_align) +{ + if ((basic_align < BITS_PER_WORD) + && (TREE_CODE (data) == ARRAY_TYPE + || TREE_CODE (data) == UNION_TYPE + || TREE_CODE (data) == RECORD_TYPE)) + return BITS_PER_WORD; + else + return basic_align; +} + +/* Return alignment for constant value. */ +unsigned int +nds32_constant_alignment (tree constant, + unsigned int basic_align) +{ + /* Make string literal and constant for constructor to word align. */ + if (((TREE_CODE (constant) == STRING_CST + || TREE_CODE (constant) == CONSTRUCTOR + || TREE_CODE (constant) == UNION_TYPE + || TREE_CODE (constant) == RECORD_TYPE + || TREE_CODE (constant) == ARRAY_TYPE) + && basic_align < BITS_PER_WORD)) + return BITS_PER_WORD; + else + return basic_align; +} + +/* Return alignment for local variable. */ +unsigned int +nds32_local_alignment (tree local ATTRIBUTE_UNUSED, + unsigned int basic_align) +{ + bool at_least_align_to_word = false; + /* Make local array, struct and union at least align to word for make + sure it can unroll memcpy when initialize by constant. */ + switch (TREE_CODE (local)) { - case CODE_FOR_move_df: - case CODE_FOR_move_di: - /* Adjust length of movd44 to 2. */ - src = XEXP (PATTERN (insn), 1); - dst = XEXP (PATTERN (insn), 0); - - if (REG_P (src) - && REG_P (dst) - && (REGNO (src) % 2) == 0 - && (REGNO (dst) % 2) == 0) - length = 2; + case ARRAY_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + at_least_align_to_word = true; break; - default: + at_least_align_to_word = false; break; } - - return length; + if (at_least_align_to_word + && (basic_align < BITS_PER_WORD)) + return BITS_PER_WORD; + else + return basic_align; } - -/* Return align 2 (log base 2) if the next instruction of LABEL is 4 byte. */ -int -nds32_target_alignment (rtx label) +bool +nds32_split_double_word_load_store_p(rtx *operands, bool load_p) { - rtx_insn *insn; + rtx mem = load_p ? operands[1] : operands[0]; + /* Do split at split2 if -O0 or schedule 2 not enable. */ + if (optimize == 0 || !flag_schedule_insns_after_reload) + return !satisfies_constraint_Da (mem) || MEM_VOLATILE_P (mem); - if (optimize_size) - return 0; + /* Split double word load store after copy propgation. */ + if (current_pass == NULL) + return false; - insn = next_active_insn (label); + const char *pass_name = current_pass->name; + if (pass_name && ((strcmp (pass_name, "split4") == 0) + || (strcmp (pass_name, "split5") == 0))) + return !satisfies_constraint_Da (mem) || MEM_VOLATILE_P (mem); - if (insn == 0) - return 0; - else if ((get_attr_length (insn) % 4) == 0) - return 2; + return false; +} + +static bool +nds32_use_blocks_for_constant_p (enum machine_mode mode, + const_rtx x ATTRIBUTE_UNUSED) +{ + if ((TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) + && (mode == DFmode || mode == SFmode)) + return true; else - return 0; + return false; } /* ------------------------------------------------------------------------ */ -/* PART 5: Initialize target hook structure and definitions. */ +/* PART 6: Initialize target hook structure and definitions. */ /* Controlling the Compilation Driver. */ @@ -3525,6 +6190,9 @@ nds32_target_alignment (rtx label) #define TARGET_PROMOTE_FUNCTION_MODE \ default_promote_function_mode_always_promote +#undef TARGET_EXPAND_TO_RTL_HOOK +#define TARGET_EXPAND_TO_RTL_HOOK nds32_expand_to_rtl_hook + /* Layout of Source Language Data Types. */ @@ -3533,6 +6201,9 @@ nds32_target_alignment (rtx label) /* -- Basic Characteristics of Registers. */ +#undef TARGET_CONDITIONAL_REGISTER_USAGE +#define TARGET_CONDITIONAL_REGISTER_USAGE nds32_conditional_register_usage + /* -- Order of Allocation of Registers. */ /* -- How Values Fit in Registers. */ @@ -3544,6 +6215,9 @@ nds32_target_alignment (rtx label) /* Register Classes. */ +#undef TARGET_PREFERRED_RENAME_CLASS +#define TARGET_PREFERRED_RENAME_CLASS nds32_preferred_rename_class + #undef TARGET_CLASS_MAX_NREGS #define TARGET_CLASS_MAX_NREGS nds32_class_max_nregs @@ -3591,6 +6265,9 @@ nds32_target_alignment (rtx label) #undef TARGET_FUNCTION_ARG_BOUNDARY #define TARGET_FUNCTION_ARG_BOUNDARY nds32_function_arg_boundary +#undef TARGET_VECTOR_MODE_SUPPORTED_P +#define TARGET_VECTOR_MODE_SUPPORTED_P nds32_vector_mode_supported_p + /* -- How Scalar Function Values Are Returned. */ #undef TARGET_FUNCTION_VALUE @@ -3604,6 +6281,9 @@ nds32_target_alignment (rtx label) /* -- How Large Values Are Returned. */ +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY nds32_return_in_memory + /* -- Caller-Saves Register Allocation. */ /* -- Function Entry and Exit. */ @@ -3630,6 +6310,9 @@ nds32_target_alignment (rtx label) /* -- Permitting tail calls. */ +#undef TARGET_FUNCTION_OK_FOR_SIBCALL +#define TARGET_FUNCTION_OK_FOR_SIBCALL nds32_function_ok_for_sibcall + #undef TARGET_WARN_FUNC_RETURN #define TARGET_WARN_FUNC_RETURN nds32_warn_func_return @@ -3662,6 +6345,21 @@ nds32_target_alignment (rtx label) #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P nds32_legitimate_address_p +#undef TARGET_LEGITIMIZE_ADDRESS +#define TARGET_LEGITIMIZE_ADDRESS nds32_legitimize_address + +#undef TARGET_LEGITIMATE_CONSTANT_P +#define TARGET_LEGITIMATE_CONSTANT_P nds32_legitimate_constant_p + +#undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE +#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE nds32_vectorize_preferred_simd_mode + +#undef TARGET_CANNOT_FORCE_CONST_MEM +#define TARGET_CANNOT_FORCE_CONST_MEM nds32_cannot_force_const_mem + +#undef TARGET_DELEGITIMIZE_ADDRESS +#define TARGET_DELEGITIMIZE_ADDRESS nds32_delegitimize_address + /* Anchored Addresses. */ @@ -3672,6 +6370,9 @@ nds32_target_alignment (rtx label) /* -- Representation of condition codes using registers. */ +#undef TARGET_CANONICALIZE_COMPARISON +#define TARGET_CANONICALIZE_COMPARISON nds32_canonicalize_comparison + /* -- Macros to control conditional execution. */ @@ -3692,6 +6393,15 @@ nds32_target_alignment (rtx label) /* Adjusting the Instruction Scheduler. */ +#undef TARGET_SCHED_ISSUE_RATE +#define TARGET_SCHED_ISSUE_RATE nds32_sched_issue_rate + +#undef TARGET_SCHED_ADJUST_COST +#define TARGET_SCHED_ADJUST_COST nds32_sched_adjust_cost + +#undef TARGET_SCHED_SET_SCHED_FLAGS +#define TARGET_SCHED_SET_SCHED_FLAGS nds32_set_sched_flags + /* Dividing the Output into Sections (Texts, Data, . . . ). */ @@ -3719,6 +6429,9 @@ nds32_target_alignment (rtx label) #undef TARGET_ASM_ALIGNED_SI_OP #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" +#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA +#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA nds32_asm_output_addr_const_extra + /* -- Output of Uninitialized Variables. */ /* -- Output and Generation of Labels. */ @@ -3741,6 +6454,9 @@ nds32_target_alignment (rtx label) /* -- Assembler Commands for Exception Regions. */ +#undef TARGET_DWARF_REGISTER_SPAN +#define TARGET_DWARF_REGISTER_SPAN nds32_dwarf_register_span + /* -- Assembler Commands for Alignment. */ @@ -3756,6 +6472,11 @@ nds32_target_alignment (rtx label) /* -- Macros for SDB and DWARF Output. */ +/* Variable tracking should be run after all optimizations which + change order of insns. It also needs a valid CFG. */ +#undef TARGET_DELAY_VARTRACK +#define TARGET_DELAY_VARTRACK true + /* -- Macros for VMS Debug Format. */ @@ -3785,6 +6506,9 @@ nds32_target_alignment (rtx label) /* Emulating TLS. */ +#undef TARGET_HAVE_TLS +#define TARGET_HAVE_TLS TARGET_LINUX_ABI + /* Defining coprocessor specifics for MIPS targets. */ @@ -3800,12 +6524,43 @@ nds32_target_alignment (rtx label) /* Miscellaneous Parameters. */ +#undef TARGET_MD_ASM_ADJUST +#define TARGET_MD_ASM_ADJUST nds32_md_asm_adjust + +#undef TARGET_MACHINE_DEPENDENT_REORG +#define TARGET_MACHINE_DEPENDENT_REORG nds32_machine_dependent_reorg + #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS nds32_init_builtins +#undef TARGET_BUILTIN_DECL +#define TARGET_BUILTIN_DECL nds32_builtin_decl + #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN nds32_expand_builtin +#undef TARGET_HAVE_CONDITIONAL_EXECUTION +#define TARGET_HAVE_CONDITIONAL_EXECUTION nds32_have_conditional_execution + +#undef TARGET_INIT_LIBFUNCS +#define TARGET_INIT_LIBFUNCS nds32_init_libfuncs + +#undef TARGET_CAN_USE_DOLOOP_P +#define TARGET_CAN_USE_DOLOOP_P nds32_can_use_doloop_p + +#undef TARGET_INVALID_WITHIN_DOLOOP +#define TARGET_INVALID_WITHIN_DOLOOP nds32_invalid_within_doloop + +#undef TARGET_CANNOT_COPY_INSN_P +#define TARGET_CANNOT_COPY_INSN_P nds32_cannot_copy_insn_p + +#undef TARGET_MIN_ANCHOR_OFFSET +#define TARGET_MIN_ANCHOR_OFFSET -((long long int) 1 << 14) +#undef TARGET_MAX_ANCHOR_OFFSET +#define TARGET_MAX_ANCHOR_OFFSET (((long long int) 1 << 14) - 1) +#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P +#define TARGET_USE_BLOCKS_FOR_CONSTANT_P nds32_use_blocks_for_constant_p + /* ------------------------------------------------------------------------ */ diff --git a/gcc/config/nds32/nds32.h b/gcc/config/nds32/nds32.h index eb4558c..a3e07cd 100644 --- a/gcc/config/nds32/nds32.h +++ b/gcc/config/nds32/nds32.h @@ -24,6 +24,9 @@ /* The following are auxiliary macros or structure declarations that are used all over the nds32.c and nds32.h. */ +#define ADJUST_INSN_LENGTH(INSN, LENGTH) \ + (LENGTH = nds32_adjust_insn_length (INSN, LENGTH)) + /* Use SYMBOL_FLAG_MACH_DEP to define our own symbol_ref flag. It is used in nds32_encode_section_info() to store flag in symbol_ref in case the symbol should be placed in .rodata section. @@ -33,68 +36,23 @@ #define NDS32_SYMBOL_REF_RODATA_P(x) \ ((SYMBOL_REF_FLAGS (x) & NDS32_SYMBOL_FLAG_RODATA) != 0) -/* Computing the Length of an Insn. */ -#define ADJUST_INSN_LENGTH(INSN, LENGTH) \ - (LENGTH = nds32_adjust_insn_length (INSN, LENGTH)) +enum nds32_relax_insn_type +{ + RELAX_ORI, + RELAX_PLT_ADD, + RELAX_TLS_ADD_or_LW, + RELAX_TLS_ADD_LW, + RELAX_TLS_LW_JRAL, + RELAX_DONE +}; -/* Check instruction LS-37-FP-implied form. - Note: actually its immediate range is imm9u - since it is used for lwi37/swi37 instructions. */ -#define NDS32_LS_37_FP_P(rt, ra, imm) \ - (REGNO_REG_CLASS (REGNO (rt)) == LOW_REGS \ - && REGNO (ra) == FP_REGNUM \ - && satisfies_constraint_Iu09 (imm)) - -/* Check instruction LS-37-SP-implied form. - Note: actually its immediate range is imm9u - since it is used for lwi37/swi37 instructions. */ -#define NDS32_LS_37_SP_P(rt, ra, imm) \ - (REGNO_REG_CLASS (REGNO (rt)) == LOW_REGS \ - && REGNO (ra) == SP_REGNUM \ - && satisfies_constraint_Iu09 (imm)) - - -/* Check load/store instruction form : Rt3, Ra3, imm3u. */ -#define NDS32_LS_333_P(rt, ra, imm, mode) nds32_ls_333_p (rt, ra, imm, mode) - -/* Check load/store instruction form : Rt4, Ra5, const_int_0. - Note: no need to check ra because Ra5 means it covers all registers. */ -#define NDS32_LS_450_P(rt, ra, imm) \ - ((imm == const0_rtx) \ - && (REGNO_REG_CLASS (REGNO (rt)) == LOW_REGS \ - || REGNO_REG_CLASS (REGNO (rt)) == MIDDLE_REGS)) - -/* Check instruction RRI-333-form. */ -#define NDS32_RRI_333_P(rt, ra, imm) \ - (REGNO_REG_CLASS (REGNO (rt)) == LOW_REGS \ - && REGNO_REG_CLASS (REGNO (ra)) == LOW_REGS \ - && satisfies_constraint_Iu03 (imm)) - -/* Check instruction RI-45-form. */ -#define NDS32_RI_45_P(rt, ra, imm) \ - (REGNO (rt) == REGNO (ra) \ - && (REGNO_REG_CLASS (REGNO (rt)) == LOW_REGS \ - || REGNO_REG_CLASS (REGNO (rt)) == MIDDLE_REGS) \ - && satisfies_constraint_Iu05 (imm)) - - -/* Check instruction RR-33-form. */ -#define NDS32_RR_33_P(rt, ra) \ - (REGNO_REG_CLASS (REGNO (rt)) == LOW_REGS \ - && REGNO_REG_CLASS (REGNO (ra)) == LOW_REGS) - -/* Check instruction RRR-333-form. */ -#define NDS32_RRR_333_P(rt, ra, rb) \ - (REGNO_REG_CLASS (REGNO (rt)) == LOW_REGS \ - && REGNO_REG_CLASS (REGNO (ra)) == LOW_REGS \ - && REGNO_REG_CLASS (REGNO (rb)) == LOW_REGS) - -/* Check instruction RR-45-form. - Note: no need to check rb because Rb5 means it covers all registers. */ -#define NDS32_RR_45_P(rt, ra, rb) \ - (REGNO (rt) == REGNO (ra) \ - && (REGNO_REG_CLASS (REGNO (rt)) == LOW_REGS \ - || REGNO_REG_CLASS (REGNO (rt)) == MIDDLE_REGS)) +/* Classifies expand result for expand helper function. */ +enum nds32_expand_result_type +{ + EXPAND_DONE, + EXPAND_FAIL, + EXPAND_CREATE_TEMPLATE +}; /* Classifies address type to distinguish 16-bit/32-bit format. */ enum nds32_16bit_address_type @@ -105,6 +63,10 @@ enum nds32_16bit_address_type ADDRESS_LO_REG_IMM3U, /* post_inc [lo_reg + imm3u]: 333 format address. */ ADDRESS_POST_INC_LO_REG_IMM3U, + /* post_modify [lo_reg + imm3u]: 333 format address. */ + ADDRESS_POST_MODIFY_LO_REG_IMM3U, + /* [$r8 + imm7u]: r8 imply address. */ + ADDRESS_R8_IMM7U, /* [$fp + imm7u]: fp imply address. */ ADDRESS_FP_IMM7U, /* [$sp + imm7u]: sp imply address. */ @@ -113,23 +75,67 @@ enum nds32_16bit_address_type ADDRESS_NOT_16BIT_FORMAT }; - /* ------------------------------------------------------------------------ */ /* Define maximum numbers of registers for passing arguments. */ #define NDS32_MAX_GPR_REGS_FOR_ARGS 6 +#define NDS32_MAX_FPR_REGS_FOR_ARGS 6 /* Define the register number for first argument. */ #define NDS32_GPR_ARG_FIRST_REGNUM 0 +#define NDS32_FPR_ARG_FIRST_REGNUM 34 /* Define the register number for return value. */ #define NDS32_GPR_RET_FIRST_REGNUM 0 +#define NDS32_FPR_RET_FIRST_REGNUM 34 /* Define the first integer register number. */ #define NDS32_FIRST_GPR_REGNUM 0 /* Define the last integer register number. */ #define NDS32_LAST_GPR_REGNUM 31 +#define NDS32_FIRST_CALLEE_SAVE_GPR_REGNUM 6 +#define NDS32_LAST_CALLEE_SAVE_GPR_REGNUM \ + (TARGET_REDUCED_REGS ? 10 : 14) + +/* Define the floating-point number of registers. */ +#define NDS32_FLOAT_REGISTER_NUMBER \ + (((nds32_fp_regnum == NDS32_CONFIG_FPU_0) \ + || (nds32_fp_regnum == NDS32_CONFIG_FPU_4)) ? 8 \ + : ((nds32_fp_regnum == NDS32_CONFIG_FPU_1) \ + || (nds32_fp_regnum == NDS32_CONFIG_FPU_5)) ? 16 \ + : ((nds32_fp_regnum == NDS32_CONFIG_FPU_2) \ + || (nds32_fp_regnum == NDS32_CONFIG_FPU_6)) ? 32 \ + : ((nds32_fp_regnum == NDS32_CONFIG_FPU_3) \ + || (nds32_fp_regnum == NDS32_CONFIG_FPU_7)) ? 64 \ + : 32) + +#define NDS32_EXT_FPU_DOT_E (nds32_fp_regnum >= 4) + +/* Define the first floating-point register number. */ +#define NDS32_FIRST_FPR_REGNUM 34 +/* Define the last floating-point register number. */ +#define NDS32_LAST_FPR_REGNUM \ + (NDS32_FIRST_FPR_REGNUM + NDS32_FLOAT_REGISTER_NUMBER - 1) + + +#define NDS32_IS_EXT_FPR_REGNUM(regno) \ + (((regno) >= NDS32_FIRST_FPR_REGNUM + 32) \ + && ((regno) < NDS32_FIRST_FPR_REGNUM + 64)) + +#define NDS32_IS_FPR_REGNUM(regno) \ + (((regno) >= NDS32_FIRST_FPR_REGNUM) \ + && ((regno) <= NDS32_LAST_FPR_REGNUM)) + +#define NDS32_FPR_REGNO_OK_FOR_SINGLE(regno) \ + ((regno) <= NDS32_LAST_FPR_REGNUM) + +#define NDS32_FPR_REGNO_OK_FOR_DOUBLE(regno) \ + ((((regno) - NDS32_FIRST_FPR_REGNUM) & 1) == 0) + +#define NDS32_IS_GPR_REGNUM(regno) \ + (((regno) <= NDS32_LAST_GPR_REGNUM)) + /* Define double word alignment bits. */ #define NDS32_DOUBLE_WORD_ALIGNMENT 64 @@ -138,6 +144,16 @@ enum nds32_16bit_address_type #define NDS32_SINGLE_WORD_ALIGN_P(value) (((value) & 0x03) == 0) #define NDS32_DOUBLE_WORD_ALIGN_P(value) (((value) & 0x07) == 0) +/* Determine whether we would like to have code generation strictly aligned. + We set it strictly aligned when -malways-align is enabled. + Check gcc/common/config/nds32/nds32-common.c for the optimizations that + apply -malways-align. */ +#define NDS32_ALIGN_P() (TARGET_ALWAYS_ALIGN) + +#define NDS32_HW_LOOP_P() (TARGET_HWLOOP && !TARGET_FORCE_NO_HWLOOP) + +#define NDS32_EXT_DSP_P() (TARGET_EXT_DSP && !TARGET_FORCE_NO_EXT_DSP) + /* Get alignment according to mode or type information. When 'type' is nonnull, there is no need to look at 'mode'. */ #define NDS32_MODE_TYPE_ALIGN(mode, type) \ @@ -159,21 +175,28 @@ enum nds32_16bit_address_type /* This macro is used to return the register number for passing argument. We need to obey the following rules: 1. If it is required MORE THAN one register, - we need to further check if it really needs to be - aligned on double words. - a) If double word alignment is necessary, - the register number must be even value. - b) Otherwise, the register number can be odd or even value. + we need to further check if it really needs to be + aligned on double words. + a) If double word alignment is necessary, + the register number must be even value. + b) Otherwise, the register number can be odd or even value. 2. If it is required ONLY one register, - the register number can be odd or even value. */ -#define NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG(reg_offset, mode, type) \ - ((NDS32_NEED_N_REGS_FOR_ARG (mode, type) > 1) \ - ? ((NDS32_MODE_TYPE_ALIGN (mode, type) > PARM_BOUNDARY) \ - ? (((reg_offset) + NDS32_GPR_ARG_FIRST_REGNUM + 1) & ~1) \ - : ((reg_offset) + NDS32_GPR_ARG_FIRST_REGNUM)) \ + the register number can be odd or even value. */ +#define NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG(reg_offset, mode, type) \ + ((NDS32_NEED_N_REGS_FOR_ARG (mode, type) > 1) \ + ? ((NDS32_MODE_TYPE_ALIGN (mode, type) > PARM_BOUNDARY) \ + ? (((reg_offset) + NDS32_GPR_ARG_FIRST_REGNUM + 1) & ~1) \ + : ((reg_offset) + NDS32_GPR_ARG_FIRST_REGNUM)) \ : ((reg_offset) + NDS32_GPR_ARG_FIRST_REGNUM)) -/* This macro is to check if there are still available registers +#define NDS32_AVAILABLE_REGNUM_FOR_FPR_ARG(reg_offset, mode, type) \ + ((NDS32_NEED_N_REGS_FOR_ARG (mode, type) > 1) \ + ? ((NDS32_MODE_TYPE_ALIGN (mode, type) > PARM_BOUNDARY) \ + ? (((reg_offset) + NDS32_FPR_ARG_FIRST_REGNUM + 1) & ~1) \ + : ((reg_offset) + NDS32_FPR_ARG_FIRST_REGNUM)) \ + : ((reg_offset) + NDS32_FPR_ARG_FIRST_REGNUM)) + +/* These two macros are to check if there are still available registers for passing argument, which must be entirely in registers. */ #define NDS32_ARG_ENTIRE_IN_GPR_REG_P(reg_offset, mode, type) \ ((NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (reg_offset, mode, type) \ @@ -181,13 +204,23 @@ enum nds32_16bit_address_type <= (NDS32_GPR_ARG_FIRST_REGNUM \ + NDS32_MAX_GPR_REGS_FOR_ARGS)) -/* This macro is to check if there are still available registers +#define NDS32_ARG_ENTIRE_IN_FPR_REG_P(reg_offset, mode, type) \ + ((NDS32_AVAILABLE_REGNUM_FOR_FPR_ARG (reg_offset, mode, type) \ + + NDS32_NEED_N_REGS_FOR_ARG (mode, type)) \ + <= (NDS32_FPR_ARG_FIRST_REGNUM \ + + NDS32_MAX_FPR_REGS_FOR_ARGS)) + +/* These two macros are to check if there are still available registers for passing argument, either entirely in registers or partially in registers. */ #define NDS32_ARG_PARTIAL_IN_GPR_REG_P(reg_offset, mode, type) \ (NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (reg_offset, mode, type) \ < NDS32_GPR_ARG_FIRST_REGNUM + NDS32_MAX_GPR_REGS_FOR_ARGS) +#define NDS32_ARG_PARTIAL_IN_FPR_REG_P(reg_offset, mode, type) \ + (NDS32_AVAILABLE_REGNUM_FOR_FPR_ARG (reg_offset, mode, type) \ + < NDS32_FPR_ARG_FIRST_REGNUM + NDS32_MAX_FPR_REGS_FOR_ARGS) + /* This macro is to check if the register is required to be saved on stack. If call_used_regs[regno] == 0, regno is the callee-saved register. If df_regs_ever_live_p(regno) == true, it is used in the current function. @@ -196,6 +229,19 @@ enum nds32_16bit_address_type #define NDS32_REQUIRED_CALLEE_SAVED_P(regno) \ ((!call_used_regs[regno]) && (df_regs_ever_live_p (regno))) +/* This macro is to check if the push25/pop25 are available to be used + for code generation. Because pop25 also performs return behavior, + the instructions may not be available for some cases. + If we want to use push25/pop25, all the following conditions must + be satisfied: + 1. TARGET_V3PUSH is set. + 2. Current function is not an ISR function. + 3. Current function is not a variadic function.*/ +#define NDS32_V3PUSH_AVAILABLE_P \ + (TARGET_V3PUSH \ + && !nds32_isr_function_p (current_function_decl) \ + && (cfun->machine->va_args_size == 0)) + /* ------------------------------------------------------------------------ */ /* A C structure for machine-specific, per-function data. @@ -222,6 +268,10 @@ struct GTY(()) machine_function callee-saved registers. */ int callee_saved_gpr_regs_size; + /* Number of bytes on the stack for saving floating-point + callee-saved registers. */ + int callee_saved_fpr_regs_size; + /* The padding bytes in callee-saved area may be required. */ int callee_saved_area_gpr_padding_bytes; @@ -230,26 +280,57 @@ struct GTY(()) machine_function /* The last required general purpose callee-saved register. */ int callee_saved_last_gpr_regno; + /* The first required floating-point callee-saved register. */ + int callee_saved_first_fpr_regno; + /* The last required floating-point callee-saved register. */ + int callee_saved_last_fpr_regno; + /* The padding bytes in varargs area may be required. */ int va_args_area_padding_bytes; - /* The first required register that should be saved on stack for va_args. */ int va_args_first_regno; /* The last required register that should be saved on stack for va_args. */ int va_args_last_regno; + /* Number of bytes on the stack for saving exception handling registers. */ + int eh_return_data_regs_size; + /* The first register of passing exception handling information. */ + int eh_return_data_first_regno; + /* The last register of passing exception handling information. */ + int eh_return_data_last_regno; + + /* Indicate that whether this function + calls __builtin_eh_return. */ + int use_eh_return_p; + /* Indicate that whether this function needs prologue/epilogue code generation. */ int naked_p; /* Indicate that whether this function uses fp_as_gp optimization. */ int fp_as_gp_p; + /* Indicate that whether this function is under strictly aligned + situation for legitimate address checking. This flag informs + nds32_legitimate_address_p() how to treat offset alignment: + 1. The IVOPT phase needs to detect available range for memory access, + such as checking [base + 32767] ~ [base + (-32768)]. + For this case we do not want address to be strictly aligned. + 2. The rtl lowering and optimization are close to target code. + For this case we need address to be strictly aligned. */ + int strict_aligned_p; + + /* Record two similar attributes status. */ + int attr_naked_p; + int attr_no_prologue_p; + /* Record hwloop group, use in reorg pass. */ + int hwloop_group_id; }; /* A C structure that contains the arguments information. */ typedef struct { unsigned int gpr_offset; + unsigned int fpr_offset; } nds32_cumulative_args; /* ------------------------------------------------------------------------ */ @@ -288,7 +369,8 @@ enum nds32_isr_nested_type { NDS32_NESTED, NDS32_NOT_NESTED, - NDS32_NESTED_READY + NDS32_NESTED_READY, + NDS32_CRITICAL }; /* Define structure to record isr information. @@ -316,6 +398,13 @@ struct nds32_isr_info unless user specifies attribute to change it. */ enum nds32_isr_nested_type nested_type; + /* Secure isr level. + Currently we have 0-3 security level. + It should be set to 0 by default. + For security processors, this is determined by secure + attribute or compiler options. */ + unsigned int security_level; + /* Total vectors. The total vectors = interrupt + exception numbers + reset. It should be set to 0 by default. @@ -340,19 +429,477 @@ enum nds32_builtins { NDS32_BUILTIN_ISYNC, NDS32_BUILTIN_ISB, + NDS32_BUILTIN_DSB, + NDS32_BUILTIN_MSYNC_ALL, + NDS32_BUILTIN_MSYNC_STORE, NDS32_BUILTIN_MFSR, NDS32_BUILTIN_MFUSR, NDS32_BUILTIN_MTSR, + NDS32_BUILTIN_MTSR_ISB, + NDS32_BUILTIN_MTSR_DSB, NDS32_BUILTIN_MTUSR, NDS32_BUILTIN_SETGIE_EN, - NDS32_BUILTIN_SETGIE_DIS + NDS32_BUILTIN_SETGIE_DIS, + NDS32_BUILTIN_FMFCFG, + NDS32_BUILTIN_FMFCSR, + NDS32_BUILTIN_FMTCSR, + NDS32_BUILTIN_FCPYNSS, + NDS32_BUILTIN_FCPYSS, + NDS32_BUILTIN_FCPYNSD, + NDS32_BUILTIN_FCPYSD, + NDS32_BUILTIN_FABSS, + NDS32_BUILTIN_FABSD, + NDS32_BUILTIN_FSQRTS, + NDS32_BUILTIN_FSQRTD, + NDS32_BUILTIN_ABS, + NDS32_BUILTIN_AVE, + NDS32_BUILTIN_BCLR, + NDS32_BUILTIN_BSET, + NDS32_BUILTIN_BTGL, + NDS32_BUILTIN_BTST, + NDS32_BUILTIN_CLIP, + NDS32_BUILTIN_CLIPS, + NDS32_BUILTIN_CLZ, + NDS32_BUILTIN_CLO, + NDS32_BUILTIN_MAX, + NDS32_BUILTIN_MIN, + NDS32_BUILTIN_PBSAD, + NDS32_BUILTIN_PBSADA, + NDS32_BUILTIN_BSE, + NDS32_BUILTIN_BSP, + NDS32_BUILTIN_FFB, + NDS32_BUILTIN_FFMISM, + NDS32_BUILTIN_FLMISM, + NDS32_BUILTIN_KADDW, + NDS32_BUILTIN_KSUBW, + NDS32_BUILTIN_KADDH, + NDS32_BUILTIN_KSUBH, + NDS32_BUILTIN_KDMBB, + NDS32_BUILTIN_V_KDMBB, + NDS32_BUILTIN_KDMBT, + NDS32_BUILTIN_V_KDMBT, + NDS32_BUILTIN_KDMTB, + NDS32_BUILTIN_V_KDMTB, + NDS32_BUILTIN_KDMTT, + NDS32_BUILTIN_V_KDMTT, + NDS32_BUILTIN_KHMBB, + NDS32_BUILTIN_V_KHMBB, + NDS32_BUILTIN_KHMBT, + NDS32_BUILTIN_V_KHMBT, + NDS32_BUILTIN_KHMTB, + NDS32_BUILTIN_V_KHMTB, + NDS32_BUILTIN_KHMTT, + NDS32_BUILTIN_V_KHMTT, + NDS32_BUILTIN_KSLRAW, + NDS32_BUILTIN_KSLRAW_U, + NDS32_BUILTIN_RDOV, + NDS32_BUILTIN_CLROV, + NDS32_BUILTIN_ROTR, + NDS32_BUILTIN_SVA, + NDS32_BUILTIN_SVS, + NDS32_BUILTIN_WSBH, + NDS32_BUILTIN_JR_ITOFF, + NDS32_BUILTIN_JR_TOFF, + NDS32_BUILTIN_JRAL_ITON, + NDS32_BUILTIN_JRAL_TON, + NDS32_BUILTIN_RET_ITOFF, + NDS32_BUILTIN_RET_TOFF, + NDS32_BUILTIN_STANDBY_NO_WAKE_GRANT, + NDS32_BUILTIN_STANDBY_WAKE_GRANT, + NDS32_BUILTIN_STANDBY_WAKE_DONE, + NDS32_BUILTIN_TEQZ, + NDS32_BUILTIN_TNEZ, + NDS32_BUILTIN_TRAP, + NDS32_BUILTIN_SETEND_BIG, + NDS32_BUILTIN_SETEND_LITTLE, + NDS32_BUILTIN_SYSCALL, + NDS32_BUILTIN_BREAK, + NDS32_BUILTIN_NOP, + NDS32_BUILTIN_SCHE_BARRIER, + NDS32_BUILTIN_GET_CURRENT_SP, + NDS32_BUILTIN_SET_CURRENT_SP, + NDS32_BUILTIN_RETURN_ADDRESS, + NDS32_BUILTIN_LLW, + NDS32_BUILTIN_LWUP, + NDS32_BUILTIN_LBUP, + NDS32_BUILTIN_SCW, + NDS32_BUILTIN_SWUP, + NDS32_BUILTIN_SBUP, + NDS32_BUILTIN_CCTL_VA_LCK, + NDS32_BUILTIN_CCTL_IDX_WBINVAL, + NDS32_BUILTIN_CCTL_VA_WBINVAL_L1, + NDS32_BUILTIN_CCTL_VA_WBINVAL_LA, + NDS32_BUILTIN_CCTL_IDX_READ, + NDS32_BUILTIN_CCTL_IDX_WRITE, + NDS32_BUILTIN_CCTL_L1D_INVALALL, + NDS32_BUILTIN_CCTL_L1D_WBALL_ALVL, + NDS32_BUILTIN_CCTL_L1D_WBALL_ONE_LVL, + NDS32_BUILTIN_DPREF_QW, + NDS32_BUILTIN_DPREF_HW, + NDS32_BUILTIN_DPREF_W, + NDS32_BUILTIN_DPREF_DW, + NDS32_BUILTIN_TLBOP_TRD, + NDS32_BUILTIN_TLBOP_TWR, + NDS32_BUILTIN_TLBOP_RWR, + NDS32_BUILTIN_TLBOP_RWLK, + NDS32_BUILTIN_TLBOP_UNLK, + NDS32_BUILTIN_TLBOP_PB, + NDS32_BUILTIN_TLBOP_INV, + NDS32_BUILTIN_TLBOP_FLUA, + NDS32_BUILTIN_UALOAD_HW, + NDS32_BUILTIN_UALOAD_W, + NDS32_BUILTIN_UALOAD_DW, + NDS32_BUILTIN_UASTORE_HW, + NDS32_BUILTIN_UASTORE_W, + NDS32_BUILTIN_UASTORE_DW, + NDS32_BUILTIN_GIE_DIS, + NDS32_BUILTIN_GIE_EN, + NDS32_BUILTIN_ENABLE_INT, + NDS32_BUILTIN_DISABLE_INT, + NDS32_BUILTIN_SET_PENDING_SWINT, + NDS32_BUILTIN_CLR_PENDING_SWINT, + NDS32_BUILTIN_CLR_PENDING_HWINT, + NDS32_BUILTIN_GET_ALL_PENDING_INT, + NDS32_BUILTIN_GET_PENDING_INT, + NDS32_BUILTIN_SET_INT_PRIORITY, + NDS32_BUILTIN_GET_INT_PRIORITY, + NDS32_BUILTIN_SET_TRIG_LEVEL, + NDS32_BUILTIN_SET_TRIG_EDGE, + NDS32_BUILTIN_GET_TRIG_TYPE, + NDS32_BUILTIN_SIGNATURE_BEGIN, + NDS32_BUILTIN_SIGNATURE_END, + NDS32_BUILTIN_DSP_BEGIN, + NDS32_BUILTIN_ADD16, + NDS32_BUILTIN_V_UADD16, + NDS32_BUILTIN_V_SADD16, + NDS32_BUILTIN_RADD16, + NDS32_BUILTIN_V_RADD16, + NDS32_BUILTIN_URADD16, + NDS32_BUILTIN_V_URADD16, + NDS32_BUILTIN_KADD16, + NDS32_BUILTIN_V_KADD16, + NDS32_BUILTIN_UKADD16, + NDS32_BUILTIN_V_UKADD16, + NDS32_BUILTIN_SUB16, + NDS32_BUILTIN_V_USUB16, + NDS32_BUILTIN_V_SSUB16, + NDS32_BUILTIN_RSUB16, + NDS32_BUILTIN_V_RSUB16, + NDS32_BUILTIN_URSUB16, + NDS32_BUILTIN_V_URSUB16, + NDS32_BUILTIN_KSUB16, + NDS32_BUILTIN_V_KSUB16, + NDS32_BUILTIN_UKSUB16, + NDS32_BUILTIN_V_UKSUB16, + NDS32_BUILTIN_CRAS16, + NDS32_BUILTIN_V_UCRAS16, + NDS32_BUILTIN_V_SCRAS16, + NDS32_BUILTIN_RCRAS16, + NDS32_BUILTIN_V_RCRAS16, + NDS32_BUILTIN_URCRAS16, + NDS32_BUILTIN_V_URCRAS16, + NDS32_BUILTIN_KCRAS16, + NDS32_BUILTIN_V_KCRAS16, + NDS32_BUILTIN_UKCRAS16, + NDS32_BUILTIN_V_UKCRAS16, + NDS32_BUILTIN_CRSA16, + NDS32_BUILTIN_V_UCRSA16, + NDS32_BUILTIN_V_SCRSA16, + NDS32_BUILTIN_RCRSA16, + NDS32_BUILTIN_V_RCRSA16, + NDS32_BUILTIN_URCRSA16, + NDS32_BUILTIN_V_URCRSA16, + NDS32_BUILTIN_KCRSA16, + NDS32_BUILTIN_V_KCRSA16, + NDS32_BUILTIN_UKCRSA16, + NDS32_BUILTIN_V_UKCRSA16, + NDS32_BUILTIN_ADD8, + NDS32_BUILTIN_V_UADD8, + NDS32_BUILTIN_V_SADD8, + NDS32_BUILTIN_RADD8, + NDS32_BUILTIN_V_RADD8, + NDS32_BUILTIN_URADD8, + NDS32_BUILTIN_V_URADD8, + NDS32_BUILTIN_KADD8, + NDS32_BUILTIN_V_KADD8, + NDS32_BUILTIN_UKADD8, + NDS32_BUILTIN_V_UKADD8, + NDS32_BUILTIN_SUB8, + NDS32_BUILTIN_V_USUB8, + NDS32_BUILTIN_V_SSUB8, + NDS32_BUILTIN_RSUB8, + NDS32_BUILTIN_V_RSUB8, + NDS32_BUILTIN_URSUB8, + NDS32_BUILTIN_V_URSUB8, + NDS32_BUILTIN_KSUB8, + NDS32_BUILTIN_V_KSUB8, + NDS32_BUILTIN_UKSUB8, + NDS32_BUILTIN_V_UKSUB8, + NDS32_BUILTIN_SRA16, + NDS32_BUILTIN_V_SRA16, + NDS32_BUILTIN_SRA16_U, + NDS32_BUILTIN_V_SRA16_U, + NDS32_BUILTIN_SRL16, + NDS32_BUILTIN_V_SRL16, + NDS32_BUILTIN_SRL16_U, + NDS32_BUILTIN_V_SRL16_U, + NDS32_BUILTIN_SLL16, + NDS32_BUILTIN_V_SLL16, + NDS32_BUILTIN_KSLL16, + NDS32_BUILTIN_V_KSLL16, + NDS32_BUILTIN_KSLRA16, + NDS32_BUILTIN_V_KSLRA16, + NDS32_BUILTIN_KSLRA16_U, + NDS32_BUILTIN_V_KSLRA16_U, + NDS32_BUILTIN_CMPEQ16, + NDS32_BUILTIN_V_SCMPEQ16, + NDS32_BUILTIN_V_UCMPEQ16, + NDS32_BUILTIN_SCMPLT16, + NDS32_BUILTIN_V_SCMPLT16, + NDS32_BUILTIN_SCMPLE16, + NDS32_BUILTIN_V_SCMPLE16, + NDS32_BUILTIN_UCMPLT16, + NDS32_BUILTIN_V_UCMPLT16, + NDS32_BUILTIN_UCMPLE16, + NDS32_BUILTIN_V_UCMPLE16, + NDS32_BUILTIN_CMPEQ8, + NDS32_BUILTIN_V_SCMPEQ8, + NDS32_BUILTIN_V_UCMPEQ8, + NDS32_BUILTIN_SCMPLT8, + NDS32_BUILTIN_V_SCMPLT8, + NDS32_BUILTIN_SCMPLE8, + NDS32_BUILTIN_V_SCMPLE8, + NDS32_BUILTIN_UCMPLT8, + NDS32_BUILTIN_V_UCMPLT8, + NDS32_BUILTIN_UCMPLE8, + NDS32_BUILTIN_V_UCMPLE8, + NDS32_BUILTIN_SMIN16, + NDS32_BUILTIN_V_SMIN16, + NDS32_BUILTIN_UMIN16, + NDS32_BUILTIN_V_UMIN16, + NDS32_BUILTIN_SMAX16, + NDS32_BUILTIN_V_SMAX16, + NDS32_BUILTIN_UMAX16, + NDS32_BUILTIN_V_UMAX16, + NDS32_BUILTIN_SCLIP16, + NDS32_BUILTIN_V_SCLIP16, + NDS32_BUILTIN_UCLIP16, + NDS32_BUILTIN_V_UCLIP16, + NDS32_BUILTIN_KHM16, + NDS32_BUILTIN_V_KHM16, + NDS32_BUILTIN_KHMX16, + NDS32_BUILTIN_V_KHMX16, + NDS32_BUILTIN_KABS16, + NDS32_BUILTIN_V_KABS16, + NDS32_BUILTIN_SMIN8, + NDS32_BUILTIN_V_SMIN8, + NDS32_BUILTIN_UMIN8, + NDS32_BUILTIN_V_UMIN8, + NDS32_BUILTIN_SMAX8, + NDS32_BUILTIN_V_SMAX8, + NDS32_BUILTIN_UMAX8, + NDS32_BUILTIN_V_UMAX8, + NDS32_BUILTIN_KABS8, + NDS32_BUILTIN_V_KABS8, + NDS32_BUILTIN_SUNPKD810, + NDS32_BUILTIN_V_SUNPKD810, + NDS32_BUILTIN_SUNPKD820, + NDS32_BUILTIN_V_SUNPKD820, + NDS32_BUILTIN_SUNPKD830, + NDS32_BUILTIN_V_SUNPKD830, + NDS32_BUILTIN_SUNPKD831, + NDS32_BUILTIN_V_SUNPKD831, + NDS32_BUILTIN_ZUNPKD810, + NDS32_BUILTIN_V_ZUNPKD810, + NDS32_BUILTIN_ZUNPKD820, + NDS32_BUILTIN_V_ZUNPKD820, + NDS32_BUILTIN_ZUNPKD830, + NDS32_BUILTIN_V_ZUNPKD830, + NDS32_BUILTIN_ZUNPKD831, + NDS32_BUILTIN_V_ZUNPKD831, + NDS32_BUILTIN_RADDW, + NDS32_BUILTIN_URADDW, + NDS32_BUILTIN_RSUBW, + NDS32_BUILTIN_URSUBW, + NDS32_BUILTIN_SRA_U, + NDS32_BUILTIN_KSLL, + NDS32_BUILTIN_PKBB16, + NDS32_BUILTIN_V_PKBB16, + NDS32_BUILTIN_PKBT16, + NDS32_BUILTIN_V_PKBT16, + NDS32_BUILTIN_PKTB16, + NDS32_BUILTIN_V_PKTB16, + NDS32_BUILTIN_PKTT16, + NDS32_BUILTIN_V_PKTT16, + NDS32_BUILTIN_SMMUL, + NDS32_BUILTIN_SMMUL_U, + NDS32_BUILTIN_KMMAC, + NDS32_BUILTIN_KMMAC_U, + NDS32_BUILTIN_KMMSB, + NDS32_BUILTIN_KMMSB_U, + NDS32_BUILTIN_KWMMUL, + NDS32_BUILTIN_KWMMUL_U, + NDS32_BUILTIN_SMMWB, + NDS32_BUILTIN_V_SMMWB, + NDS32_BUILTIN_SMMWB_U, + NDS32_BUILTIN_V_SMMWB_U, + NDS32_BUILTIN_SMMWT, + NDS32_BUILTIN_V_SMMWT, + NDS32_BUILTIN_SMMWT_U, + NDS32_BUILTIN_V_SMMWT_U, + NDS32_BUILTIN_KMMAWB, + NDS32_BUILTIN_V_KMMAWB, + NDS32_BUILTIN_KMMAWB_U, + NDS32_BUILTIN_V_KMMAWB_U, + NDS32_BUILTIN_KMMAWT, + NDS32_BUILTIN_V_KMMAWT, + NDS32_BUILTIN_KMMAWT_U, + NDS32_BUILTIN_V_KMMAWT_U, + NDS32_BUILTIN_SMBB, + NDS32_BUILTIN_V_SMBB, + NDS32_BUILTIN_SMBT, + NDS32_BUILTIN_V_SMBT, + NDS32_BUILTIN_SMTT, + NDS32_BUILTIN_V_SMTT, + NDS32_BUILTIN_KMDA, + NDS32_BUILTIN_V_KMDA, + NDS32_BUILTIN_KMXDA, + NDS32_BUILTIN_V_KMXDA, + NDS32_BUILTIN_SMDS, + NDS32_BUILTIN_V_SMDS, + NDS32_BUILTIN_SMDRS, + NDS32_BUILTIN_V_SMDRS, + NDS32_BUILTIN_SMXDS, + NDS32_BUILTIN_V_SMXDS, + NDS32_BUILTIN_KMABB, + NDS32_BUILTIN_V_KMABB, + NDS32_BUILTIN_KMABT, + NDS32_BUILTIN_V_KMABT, + NDS32_BUILTIN_KMATT, + NDS32_BUILTIN_V_KMATT, + NDS32_BUILTIN_KMADA, + NDS32_BUILTIN_V_KMADA, + NDS32_BUILTIN_KMAXDA, + NDS32_BUILTIN_V_KMAXDA, + NDS32_BUILTIN_KMADS, + NDS32_BUILTIN_V_KMADS, + NDS32_BUILTIN_KMADRS, + NDS32_BUILTIN_V_KMADRS, + NDS32_BUILTIN_KMAXDS, + NDS32_BUILTIN_V_KMAXDS, + NDS32_BUILTIN_KMSDA, + NDS32_BUILTIN_V_KMSDA, + NDS32_BUILTIN_KMSXDA, + NDS32_BUILTIN_V_KMSXDA, + NDS32_BUILTIN_SMAL, + NDS32_BUILTIN_V_SMAL, + NDS32_BUILTIN_BITREV, + NDS32_BUILTIN_WEXT, + NDS32_BUILTIN_BPICK, + NDS32_BUILTIN_INSB, + NDS32_BUILTIN_SADD64, + NDS32_BUILTIN_UADD64, + NDS32_BUILTIN_RADD64, + NDS32_BUILTIN_URADD64, + NDS32_BUILTIN_KADD64, + NDS32_BUILTIN_UKADD64, + NDS32_BUILTIN_SSUB64, + NDS32_BUILTIN_USUB64, + NDS32_BUILTIN_RSUB64, + NDS32_BUILTIN_URSUB64, + NDS32_BUILTIN_KSUB64, + NDS32_BUILTIN_UKSUB64, + NDS32_BUILTIN_SMAR64, + NDS32_BUILTIN_SMSR64, + NDS32_BUILTIN_UMAR64, + NDS32_BUILTIN_UMSR64, + NDS32_BUILTIN_KMAR64, + NDS32_BUILTIN_KMSR64, + NDS32_BUILTIN_UKMAR64, + NDS32_BUILTIN_UKMSR64, + NDS32_BUILTIN_SMALBB, + NDS32_BUILTIN_V_SMALBB, + NDS32_BUILTIN_SMALBT, + NDS32_BUILTIN_V_SMALBT, + NDS32_BUILTIN_SMALTT, + NDS32_BUILTIN_V_SMALTT, + NDS32_BUILTIN_SMALDA, + NDS32_BUILTIN_V_SMALDA, + NDS32_BUILTIN_SMALXDA, + NDS32_BUILTIN_V_SMALXDA, + NDS32_BUILTIN_SMALDS, + NDS32_BUILTIN_V_SMALDS, + NDS32_BUILTIN_SMALDRS, + NDS32_BUILTIN_V_SMALDRS, + NDS32_BUILTIN_SMALXDS, + NDS32_BUILTIN_V_SMALXDS, + NDS32_BUILTIN_SMUL16, + NDS32_BUILTIN_V_SMUL16, + NDS32_BUILTIN_SMULX16, + NDS32_BUILTIN_V_SMULX16, + NDS32_BUILTIN_UMUL16, + NDS32_BUILTIN_V_UMUL16, + NDS32_BUILTIN_UMULX16, + NDS32_BUILTIN_V_UMULX16, + NDS32_BUILTIN_SMSLDA, + NDS32_BUILTIN_V_SMSLDA, + NDS32_BUILTIN_SMSLXDA, + NDS32_BUILTIN_V_SMSLXDA, + NDS32_BUILTIN_UCLIP32, + NDS32_BUILTIN_SCLIP32, + NDS32_BUILTIN_KABS, + NDS32_BUILTIN_UALOAD_U16, + NDS32_BUILTIN_UALOAD_S16, + NDS32_BUILTIN_UALOAD_U8, + NDS32_BUILTIN_UALOAD_S8, + NDS32_BUILTIN_UASTORE_U16, + NDS32_BUILTIN_UASTORE_S16, + NDS32_BUILTIN_UASTORE_U8, + NDS32_BUILTIN_UASTORE_S8, + NDS32_BUILTIN_DSP_END, + NDS32_BUILTIN_NO_HWLOOP, + NDS32_BUILTIN_UNALIGNED_FEATURE, + NDS32_BUILTIN_ENABLE_UNALIGNED, + NDS32_BUILTIN_DISABLE_UNALIGNED, + NDS32_BUILTIN_COUNT }; /* ------------------------------------------------------------------------ */ -#define TARGET_ISA_V2 (nds32_arch_option == ARCH_V2) -#define TARGET_ISA_V3 (nds32_arch_option == ARCH_V3) -#define TARGET_ISA_V3M (nds32_arch_option == ARCH_V3M) +#define TARGET_ISR_VECTOR_SIZE_4_BYTE \ + (nds32_isr_vector_size == 4) + +#define TARGET_ISA_V2 \ + (nds32_arch_option == ARCH_V2 || nds32_arch_option == ARCH_V2J) +#define TARGET_ISA_V3 \ + (nds32_arch_option == ARCH_V3 \ + || nds32_arch_option == ARCH_V3J \ + || nds32_arch_option == ARCH_V3F \ + || nds32_arch_option == ARCH_V3S) +#define TARGET_ISA_V3M \ + (nds32_arch_option == ARCH_V3M || \ + nds32_arch_option == ARCH_V3M_PLUS) + +#define TARGET_ISA_V3M_PLUS \ + (nds32_arch_option == ARCH_V3M_PLUS) + +#define TARGET_PIPELINE_N7 \ + (nds32_cpu_option == CPU_N7) +#define TARGET_PIPELINE_N8 \ + (nds32_cpu_option == CPU_N6 \ + || nds32_cpu_option == CPU_N8) +#define TARGET_PIPELINE_N9 \ + (nds32_cpu_option == CPU_N9) +#define TARGET_PIPELINE_N10 \ + (nds32_cpu_option == CPU_N10) +#define TARGET_PIPELINE_N13 \ + (nds32_cpu_option == CPU_N12 || nds32_cpu_option == CPU_N13) +#define TARGET_PIPELINE_GRAYWOLF \ + (nds32_cpu_option == CPU_GRAYWOLF) +#define TARGET_PIPELINE_PANTHER \ + (nds32_cpu_option == CPU_PANTHER) +#define TARGET_PIPELINE_SIMPLE \ + (nds32_cpu_option == CPU_SIMPLE) #define TARGET_CMODEL_SMALL \ (nds32_cmodel_option == CMODEL_SMALL) @@ -361,55 +908,153 @@ enum nds32_builtins #define TARGET_CMODEL_LARGE \ (nds32_cmodel_option == CMODEL_LARGE) +#define TARGET_ICT_MODEL_SMALL \ + (nds32_ict_model == ICT_MODEL_SMALL) + +#define TARGET_ICT_MODEL_LARGE \ + (nds32_ict_model == ICT_MODEL_LARGE) + /* When -mcmodel=small or -mcmodel=medium, compiler may generate gp-base instruction directly. */ #define TARGET_GP_DIRECT \ (nds32_cmodel_option == CMODEL_SMALL\ || nds32_cmodel_option == CMODEL_MEDIUM) -#define TARGET_SOFT_FLOAT 1 -#define TARGET_HARD_FLOAT 0 +/* There are three kinds of mul configurations: + 1-cycle fast mul, 2-cycle fast mul, and slow mul operation. */ +#define TARGET_MUL_FAST_1 \ + (nds32_mul_config == MUL_TYPE_FAST_1) +#define TARGET_MUL_FAST_2 \ + (nds32_mul_config == MUL_TYPE_FAST_2) +#define TARGET_MUL_SLOW \ + (nds32_mul_config == MUL_TYPE_SLOW) + +/* Run-time Target Specification. */ +#define TARGET_SOFT_FLOAT (nds32_abi == NDS32_ABI_V2) +/* Use hardware floating point calling convention. */ +#define TARGET_HARD_FLOAT (nds32_abi == NDS32_ABI_V2_FP_PLUS) + +/* Record arch version in TARGET_ARCH_DEFAULT. 0 means soft ABI, + 1 means hard ABI and using full floating-point instruction, + 2 means hard ABI and only using single-precision floating-point + instruction */ +#if TARGET_ARCH_DEFAULT == 1 +# define TARGET_DEFAULT_ABI NDS32_ABI_V2_FP_PLUS +# define TARGET_DEFAULT_FPU_ISA MASK_FPU_DOUBLE | MASK_FPU_SINGLE +# define TARGET_DEFAULT_FPU_FMA 0 +#else +# if TARGET_ARCH_DEFAULT == 2 +# define TARGET_DEFAULT_ABI NDS32_ABI_V2_FP_PLUS +# define TARGET_DEFAULT_FPU_ISA MASK_FPU_SINGLE +# define TARGET_DEFAULT_FPU_FMA 0 +# else +# define TARGET_DEFAULT_ABI NDS32_ABI_V2 +# define TARGET_DEFAULT_FPU_ISA 0 +# define TARGET_DEFAULT_FPU_FMA 0 +# endif +#endif + +#define TARGET_CONFIG_FPU_DEFAULT NDS32_CONFIG_FPU_2 + +#define TARGET_LMWSMW_OPT_AUTO \ + (flag_lmwsmw_cost == LMWSMW_OPT_AUTO) + +#define TARGET_LMWSMW_OPT_SIZE \ + (flag_lmwsmw_cost == LMWSMW_OPT_SIZE) + +#define TARGET_LMWSMW_OPT_SPEED \ + (flag_lmwsmw_cost == LMWSMW_OPT_SPEED) + +#define TARGET_LMWSMW_OPT_ALL \ + (flag_lmwsmw_cost == LMWSMW_OPT_ALL) + +/* ------------------------------------------------------------------------ */ + +#ifdef TARGET_DEFAULT_RELAX +# define NDS32_RELAX_SPEC " %{!mno-relax:--relax}" +#else +# define NDS32_RELAX_SPEC " %{mrelax:--relax}" +#endif + +#ifdef TARGET_OS_DEFAULT_IFC +# define NDS32_IFC_SPEC " %{Os3|Os|mifc:%{!mno-ifc:--mifc}}" +#else +# define NDS32_IFC_SPEC " %{mifc:--mifc}" +#endif +#define NDS32_IFC_V3M_PLUS_SPEC " %{march=v3m+:%{Os3|Os|mifc:%{!mno-ifc:-mifc}}}" + +#ifdef TARGET_OS_DEFAULT_EX9 +# define NDS32_EX9_SPEC " %{Os3|Os|mex9:%{!mno-ex9:--mex9}}" +#else +# define NDS32_EX9_SPEC " %{mex9:--mex9}" +#endif +#define NDS32_EX9_V3M_PLUS_SPEC " %{march=v3m+:%{Os3|Os|mex9:%{!mno-ex9:-mex9}}}" + +#ifdef TARGET_DEFAULT_EXT_DSP +# define NDS32_EXT_DSP_SPEC " %{!mno-ext-dsp:-mext-dsp}" +#else +# define NDS32_EXT_DSP_SPEC "" +#endif + +#ifdef TARGET_DEFAULT_HWLOOP +# define NDS32_HWLOOP_SPEC " %{!mno-ext-zol:-mext-zol}" +#else +# define NDS32_HWLOOP_SPEC "" +#endif + +#ifdef TARGET_DEFAULT_16BIT +# define NDS32_16BIT_SPEC " %{!mno-16-bit:%{!mno-16bit:-m16bit}}" +#else +# define NDS32_16BIT_SPEC " %{!m16-bit:%{!m16bit:-mno-16bit}}" +#endif /* ------------------------------------------------------------------------ */ /* Controlling the Compilation Driver. */ +#define DRIVER_SELF_SPECS \ + " %{mno-16bit|mno-16-bit:-mno-ifc -mno-ex9}" \ + NDS32_IFC_V3M_PLUS_SPEC \ + NDS32_EX9_V3M_PLUS_SPEC \ + NDS32_16BIT_SPEC + #define OPTION_DEFAULT_SPECS \ - {"arch", "%{!march=*:-march=%(VALUE)}" } + {"arch", " %{!march=*:-march=%(VALUE)}" \ + " %{march=v3f:%{!mfloat-abi=*:-mfloat-abi=hard}" \ + " %{!mno-ext-fpu-sp:%{!mext-fpu-sp:-mext-fpu-sp}}" \ + " %{!mno-ext-fpu-dp:%{!mext-fpu-dp:-mext-fpu-dp}}}" \ + " %{march=v3s:%{!mfloat-abi=*:-mfloat-abi=hard}" \ + " %{!mno-ext-fpu-sp:%{!mext-fpu-sp:-mext-fpu-sp}}}" }, \ + {"cpu", "%{!mcpu=*:-mcpu=%(VALUE)}" }, \ + {"memory_model", "%{!mmemory-model=*:-mmemory-model=%(VALUE)}"}, \ + {"float", "%{!mfloat-abi=*:-mfloat-abi=%(VALUE)}" } #define CC1_SPEC \ - "" + " %{Os1:-Os -mno-ifc -mno-ex9;" \ + "Os2:-Os -minnermost-loop;" \ + "Os3:-Os}" \ + " %{ffast-math:%{!mno-soft-fp-arith-comm:-msoft-fp-arith-comm}}" \ + NDS32_EXT_DSP_SPEC \ + NDS32_HWLOOP_SPEC #define ASM_SPEC \ - " %{mbig-endian:-EB} %{mlittle-endian:-EL}" - -/* If user issues -mrelax, we need to pass '--relax' to linker. */ -#define LINK_SPEC \ " %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ - " %{mrelax:--relax}" - -#define LIB_SPEC \ - " -lc -lgloss" - -/* The option -mno-ctor-dtor can disable constructor/destructor feature - by applying different crt stuff. In the convention, crt0.o is the - startup file without constructor/destructor; - crt1.o, crti.o, crtbegin.o, crtend.o, and crtn.o are the - startup files with constructor/destructor. - Note that crt0.o, crt1.o, crti.o, and crtn.o are provided - by newlib/mculib/glibc/ublic, while crtbegin.o and crtend.o are - currently provided by GCC for nds32 target. - - For nds32 target so far: - If -mno-ctor-dtor, we are going to link - "crt0.o [user objects]". - If general cases, we are going to link - "crt1.o crtbegin1.o [user objects] crtend1.o". */ -#define STARTFILE_SPEC \ - " %{!mno-ctor-dtor:crt1.o%s;:crt0.o%s}" \ - " %{!mno-ctor-dtor:crtbegin1.o%s}" -#define ENDFILE_SPEC \ - " %{!mno-ctor-dtor:crtend1.o%s}" + " %{march=*:-march=%*}" \ + " %{mno-16-bit|mno-16bit:-mno-16bit-ext}" \ + " %{march=v3m:%{!mfull-regs:%{!mreduced-regs:-mreduced-regs}}}" \ + " %{mfull-regs:-mno-reduced-regs}" \ + " %{mreduced-regs:-mreduced-regs}" \ + " %{mabi=*:-mabi=v%*}" \ + " %{mconfig-fpu=*:-mfpu-freg=%*}" \ + " %{mext-fpu-mac:-mmac}" \ + " %{mno-ext-fpu-mac:-mno-mac}" \ + " %{mext-fpu-sp:-mfpu-sp-ext}" \ + " %{mno-ext-fpu-sp:-mno-fpu-sp-ext}" \ + " %{mext-fpu-dp:-mfpu-dp-ext}" \ + " %{mno-ext-fpu-sp:-mno-fpu-dp-ext}" \ + " %{mext-dsp:-mdsp-ext}" \ + " %{mext-zol:-mzol-ext}" \ + " %{O|O1|O2|O3|Ofast:-O1;:-Os}" /* The TARGET_BIG_ENDIAN_DEFAULT is defined if we configure gcc with --target=nds32be-* setting. @@ -422,7 +1067,11 @@ enum nds32_builtins /* Currently we only have elf toolchain, where -mcmodel=medium is always the default. */ -#define NDS32_CMODEL_DEFAULT "mcmodel=medium" +#if TARGET_ELF +# define NDS32_CMODEL_DEFAULT "mcmodel=medium" +#else +# define NDS32_CMODEL_DEFAULT "mcmodel=medium" +#endif #define MULTILIB_DEFAULTS \ { NDS32_ENDIAN_DEFAULT, NDS32_CMODEL_DEFAULT } @@ -430,34 +1079,8 @@ enum nds32_builtins /* Run-time Target Specification. */ -#define TARGET_CPU_CPP_BUILTINS() \ - do \ - { \ - builtin_define ("__nds32__"); \ - \ - if (TARGET_ISA_V2) \ - builtin_define ("__NDS32_ISA_V2__"); \ - if (TARGET_ISA_V3) \ - builtin_define ("__NDS32_ISA_V3__"); \ - if (TARGET_ISA_V3M) \ - builtin_define ("__NDS32_ISA_V3M__"); \ - \ - if (TARGET_BIG_ENDIAN) \ - builtin_define ("__big_endian__"); \ - if (TARGET_REDUCED_REGS) \ - builtin_define ("__NDS32_REDUCED_REGS__"); \ - if (TARGET_CMOV) \ - builtin_define ("__NDS32_CMOV__"); \ - if (TARGET_PERF_EXT) \ - builtin_define ("__NDS32_PERF_EXT__"); \ - if (TARGET_16_BIT) \ - builtin_define ("__NDS32_16_BIT__"); \ - if (TARGET_GP_DIRECT) \ - builtin_define ("__NDS32_GP_DIRECT__"); \ - \ - builtin_assert ("cpu=nds32"); \ - builtin_assert ("machine=nds32"); \ - } while (0) +#define TARGET_CPU_CPP_BUILTINS() \ + nds32_cpu_cpp_builtins (pfile) /* Defining Data Structures for Per-function Information. */ @@ -487,10 +1110,20 @@ enum nds32_builtins #define STACK_BOUNDARY 64 -#define FUNCTION_BOUNDARY 32 +#define FUNCTION_BOUNDARY \ + ((NDS32_ALIGN_P () || TARGET_ALIGN_FUNCTION) ? (TARGET_PIPELINE_PANTHER ? 64 : 32) : 16) #define BIGGEST_ALIGNMENT 64 +#define DATA_ALIGNMENT(constant, basic_align) \ + nds32_data_alignment (constant, basic_align) + +#define CONSTANT_ALIGNMENT(constant, basic_align) \ + nds32_constant_alignment (constant, basic_align) + +#define LOCAL_ALIGNMENT(type, basic_align) \ + nds32_local_alignment (type, basic_align) + #define EMPTY_FIELD_BOUNDARY 32 #define STRUCTURE_SIZE_BOUNDARY 8 @@ -515,8 +1148,8 @@ enum nds32_builtins #define SIZE_TYPE "long unsigned int" #define PTRDIFF_TYPE "long int" -#define WCHAR_TYPE "short unsigned int" -#define WCHAR_TYPE_SIZE 16 +#define WCHAR_TYPE "unsigned int" +#define WCHAR_TYPE_SIZE 32 /* Register Usage. */ @@ -526,7 +1159,7 @@ enum nds32_builtins from 0 to just below FIRST_PSEUDO_REGISTER. All registers that the compiler knows about must be given numbers, even those that are not normally considered general registers. */ -#define FIRST_PSEUDO_REGISTER 34 +#define FIRST_PSEUDO_REGISTER 101 /* An initializer that says which registers are used for fixed purposes all throughout the compiled code and are therefore @@ -537,24 +1170,38 @@ enum nds32_builtins $r30 : $lp $r31 : $sp - caller-save registers: $r0 ~ $r5, $r16 ~ $r23 - callee-save registers: $r6 ~ $r10, $r11 ~ $r14 + caller-save registers: $r0 ~ $r5, $r16 ~ $r23, $fs0 ~ $fs5, $fs22 ~ $fs47 + callee-save registers: $r6 ~ $r10, $r11 ~ $r14, $fs6 ~ $fs21, $fs48 ~ $fs63 reserved for assembler : $r15 reserved for other use : $r24, $r25, $r26, $r27 */ -#define FIXED_REGISTERS \ -{ /* r0 r1 r2 r3 r4 r5 r6 r7 */ \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - /* r8 r9 r10 r11 r12 r13 r14 r15 */ \ - 0, 0, 0, 0, 0, 0, 0, 1, \ - /* r16 r17 r18 r19 r20 r21 r22 r23 */ \ - 0, 0, 0, 0, 0, 0, 0, 0, \ - /* r24 r25 r26 r27 r28 r29 r30 r31 */ \ - 1, 1, 1, 1, 0, 1, 0, 1, \ - /* ARG_POINTER:32 */ \ - 1, \ - /* FRAME_POINTER:33 */ \ - 1 \ +#define FIXED_REGISTERS \ +{ /* r0 r1 r2 r3 r4 r5 r6 r7 */ \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + /* r8 r9 r10 r11 r12 r13 r14 r15 */ \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + /* r16 r17 r18 r19 r20 r21 r22 r23 */ \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + /* r24 r25 r26 r27 r28 r29 r30 r31 */ \ + 0, 0, 1, 1, 0, 1, 0, 1, \ + /* AP FP fs0 fs1 fs2 fs3 fs4 fs5 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fs6 fs7 fs8 fs9 fs10 fs11 fs12 fs13 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fs14 fs15 fs16 fs17 fs18 fs19 fs20 fs21 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fs22 fs23 fs24 fs25 fs26 fs27 fs28 fs29 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fs30 fs31 fd16 fd17 fd18 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fd19 fd20 fd21 fd22 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fd23 fd24 fd25 fd26 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fd27 fd28 fd29 fd30 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fd31 LB LE LC */ \ + 1, 1, 1, 1, 1 \ } /* Identifies the registers that are not available for @@ -563,35 +1210,59 @@ enum nds32_builtins 0 : callee-save registers 1 : caller-save registers */ -#define CALL_USED_REGISTERS \ -{ /* r0 r1 r2 r3 r4 r5 r6 r7 */ \ - 1, 1, 1, 1, 1, 1, 0, 0, \ - /* r8 r9 r10 r11 r12 r13 r14 r15 */ \ - 0, 0, 0, 0, 0, 0, 0, 1, \ - /* r16 r17 r18 r19 r20 r21 r22 r23 */ \ - 1, 1, 1, 1, 1, 1, 1, 1, \ - /* r24 r25 r26 r27 r28 r29 r30 r31 */ \ - 1, 1, 1, 1, 0, 1, 0, 1, \ - /* ARG_POINTER:32 */ \ - 1, \ - /* FRAME_POINTER:33 */ \ - 1 \ +#define CALL_USED_REGISTERS \ +{ /* r0 r1 r2 r3 r4 r5 r6 r7 */ \ + 1, 1, 1, 1, 1, 1, 0, 0, \ + /* r8 r9 r10 r11 r12 r13 r14 r15 */ \ + 0, 0, 0, 0, 0, 0, 0, 1, \ + /* r16 r17 r18 r19 r20 r21 r22 r23 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* r24 r25 r26 r27 r28 r29 r30 r31 */ \ + 1, 1, 1, 1, 0, 1, 0, 1, \ + /* AP FP fs0 fs1 fs2 fs3 fs4 fs5 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fs6 fs7 fs8 fs9 fs10 fs11 fs12 fs13 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fs14 fs15 fs16 fs17 fs18 fs19 fs20 fs21 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fs22 fs23 fs24 fs25 fs26 fs27 fs28 fs29 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fs30 fs31 fd16 fd17 fd18 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fd19 fd20 fd21 fd22 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fd23 fd24 fd25 fd26 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fd27 fd28 fd29 fd30 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* fd31 LB LE LC */ \ + 1, 1, 1, 1, 1 \ } /* In nds32 target, we have three levels of registers: LOW_COST_REGS : $r0 ~ $r7 MIDDLE_COST_REGS : $r8 ~ $r11, $r16 ~ $r19 HIGH_COST_REGS : $r12 ~ $r14, $r20 ~ $r31 */ -#define REG_ALLOC_ORDER \ -{ \ - 0, 1, 2, 3, 4, 5, 6, 7, \ - 8, 9, 10, 11, 16, 17, 18, 19, \ - 12, 13, 14, 15, 20, 21, 22, 23, \ - 24, 25, 26, 27, 28, 29, 30, 31, \ - 32, \ - 33 \ +#define REG_ALLOC_ORDER \ +{ 0, 1, 2, 3, 4, 5, 6, 7, \ + 16, 17, 18, 19, 9, 10, 11, 12, \ + 13, 14, 8, 15, 20, 21, 22, 23, \ + 24, 25, 26, 27, 28, 29, 30, 31, \ + 32, 33, 34, 35, 36, 37, 38, 39, \ + 40, 41, 42, 43, 44, 45, 46, 47, \ + 48, 49, 50, 51, 52, 53, 54, 55, \ + 56, 57, 58, 59, 60, 61, 62, 63, \ + 64, 65, 66, 67, 68, 69, 70, 71, \ + 72, 73, 74, 75, 76, 77, 78, 79, \ + 80, 81, 82, 83, 84, 85, 86, 87, \ + 88, 89, 90, 91, 92, 93, 94, 95, \ + 96, 97, 98, 99, 100, \ } +/* ADJUST_REG_ALLOC_ORDER is a macro which permits reg_alloc_order + to be rearranged based on optimizing for speed or size. */ +#define ADJUST_REG_ALLOC_ORDER nds32_adjust_reg_alloc_order () + /* Tell IRA to use the order we define rather than messing it up with its own cost calculations. */ #define HONOR_REG_ALLOC_ORDER optimize_size @@ -609,11 +1280,7 @@ enum nds32_builtins Define this macro to return nonzero in as many cases as possible since doing so will allow GCC to perform better register allocation. We can use general registers to tie QI/HI/SI modes together. */ -#define MODES_TIEABLE_P(mode1, mode2) \ - (GET_MODE_CLASS (mode1) == MODE_INT \ - && GET_MODE_CLASS (mode2) == MODE_INT \ - && GET_MODE_SIZE (mode1) <= UNITS_PER_WORD \ - && GET_MODE_SIZE (mode2) <= UNITS_PER_WORD) +#define MODES_TIEABLE_P(mode1, mode2) nds32_modes_tieable_p (mode1, mode2) /* Register Classes. */ @@ -628,13 +1295,18 @@ enum nds32_builtins enum reg_class { NO_REGS, + R5_REG, + R8_REG, R15_TA_REG, STACK_REG, + FRAME_POINTER_REG, LOW_REGS, MIDDLE_REGS, HIGH_REGS, GENERAL_REGS, FRAME_REGS, + FP_REGS, + LOOP_REGS, ALL_REGS, LIM_REG_CLASSES }; @@ -644,27 +1316,50 @@ enum reg_class #define REG_CLASS_NAMES \ { \ "NO_REGS", \ + "R5_REG", \ + "R8_REG", \ "R15_TA_REG", \ "STACK_REG", \ + "FRAME_POINTER_REG", \ "LOW_REGS", \ "MIDDLE_REGS", \ "HIGH_REGS", \ "GENERAL_REGS", \ "FRAME_REGS", \ + "FP_REGS", \ + "LOOP_REGS", \ "ALL_REGS" \ } #define REG_CLASS_CONTENTS \ -{ \ - {0x00000000, 0x00000000}, /* NO_REGS : */ \ - {0x00008000, 0x00000000}, /* R15_TA_REG : 15 */ \ - {0x80000000, 0x00000000}, /* STACK_REG : 31 */ \ - {0x000000ff, 0x00000000}, /* LOW_REGS : 0-7 */ \ - {0x000f0fff, 0x00000000}, /* MIDDLE_REGS : 0-11, 16-19 */ \ - {0xfff07000, 0x00000000}, /* HIGH_REGS : 12-14, 20-31 */ \ - {0xffffffff, 0x00000000}, /* GENERAL_REGS: 0-31 */ \ - {0x00000000, 0x00000003}, /* FRAME_REGS : 32, 33 */ \ - {0xffffffff, 0x00000003} /* ALL_REGS : 0-31, 32, 33 */ \ +{ /* NO_REGS */ \ + {0x00000000, 0x00000000, 0x00000000, 0x00000000}, \ + /* R5_REG : 5 */ \ + {0x00000020, 0x00000000, 0x00000000, 0x00000000}, \ + /* R8_REG : 8 */ \ + {0x00000100, 0x00000000, 0x00000000, 0x00000000}, \ + /* R15_TA_REG : 15 */ \ + {0x00008000, 0x00000000, 0x00000000, 0x00000000}, \ + /* STACK_REG : 31 */ \ + {0x80000000, 0x00000000, 0x00000000, 0x00000000}, \ + /* FRAME_POINTER_REG : 28 */ \ + {0x10000000, 0x00000000, 0x00000000, 0x00000000}, \ + /* LOW_REGS : 0-7 */ \ + {0x000000ff, 0x00000000, 0x00000000, 0x00000000}, \ + /* MIDDLE_REGS : 0-11, 16-19 */ \ + {0x000f0fff, 0x00000000, 0x00000000, 0x00000000}, \ + /* HIGH_REGS : 12-14, 20-31 */ \ + {0xfff07000, 0x00000000, 0x00000000, 0x00000000}, \ + /* GENERAL_REGS : 0-31 */ \ + {0xffffffff, 0x00000000, 0x00000000, 0x00000000}, \ + /* FRAME_REGS : 32, 33 */ \ + {0x00000000, 0x00000003, 0x00000000, 0x00000000}, \ + /* FP_REGS : 34-98 */ \ + {0x00000000, 0xfffffffc, 0xffffffff, 0x00000003}, \ + /* LOOP_REGS 99-101 */ \ + {0x00000000, 0x00000000, 0x00000000, 0x0000001c}, \ + /* ALL_REGS : 0-101 */ \ + {0xffffffff, 0xffffffff, 0xffffffff, 0x0000001f} \ } #define REGNO_REG_CLASS(regno) nds32_regno_reg_class (regno) @@ -672,13 +1367,18 @@ enum reg_class #define BASE_REG_CLASS GENERAL_REGS #define INDEX_REG_CLASS GENERAL_REGS +#define TEST_REGNO(R, TEST, VALUE) \ + ((R TEST VALUE) || ((unsigned) reg_renumber[R] TEST VALUE)) + /* Return nonzero if it is suitable for use as a base register in operand addresses. So far, we return nonzero only if "num" is a hard reg of the suitable class or a pseudo register which is allocated to a suitable hard reg. */ #define REGNO_OK_FOR_BASE_P(num) \ - ((num) < 32 || (unsigned) reg_renumber[num] < 32) + (TEST_REGNO (num, <, 32) \ + || TEST_REGNO (num, ==, FRAME_POINTER_REGNUM) \ + || TEST_REGNO (num, ==, ARG_POINTER_REGNUM)) /* Return nonzero if it is suitable for use as a index register in operand addresses. @@ -688,7 +1388,15 @@ enum reg_class The difference between an index register and a base register is that the index register may be scaled. */ #define REGNO_OK_FOR_INDEX_P(num) \ - ((num) < 32 || (unsigned) reg_renumber[num] < 32) + (TEST_REGNO (num, <, 32) \ + || TEST_REGNO (num, ==, FRAME_POINTER_REGNUM) \ + || TEST_REGNO (num, ==, ARG_POINTER_REGNUM)) + +/* Don't spill double-precision register to two singal-precision registers */ +#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ + ((TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) \ + && GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \ + ? reg_classes_intersect_p (CLASS, FP_REGS) : 0) /* Obsolete Macros for Defining Constraints. */ @@ -707,6 +1415,11 @@ enum reg_class #define FIRST_PARM_OFFSET(fundecl) \ (NDS32_DOUBLE_WORD_ALIGN_P (crtl->args.pretend_args_size) ? 0 : 4) +/* A C expression whose value is RTL representing the address in a stack frame + where the pointer to the caller's frame is stored. */ +#define DYNAMIC_CHAIN_ADDRESS(frameaddr) \ + nds32_dynamic_chain_address (frameaddr) + #define RETURN_ADDR_RTX(count, frameaddr) \ nds32_return_addr_rtx (count, frameaddr) @@ -718,6 +1431,15 @@ enum reg_class #define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LP_REGNUM) #define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (LP_REGNUM) +/* Use $r0 $r1 to pass exception handling information. */ +#define EH_RETURN_DATA_REGNO(N) (((N) < 2) ? (N) : INVALID_REGNUM) +/* The register $r2 that represents a location in which to store a stack + adjustment to be applied before function return. + This is used to unwind the stack to an exception handler's call frame. */ +#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 2) + +#define DBX_REGISTER_NUMBER(REGNO) nds32_dbx_register_number (REGNO) + #define STACK_POINTER_REGNUM SP_REGNUM #define FRAME_POINTER_REGNUM 33 @@ -746,12 +1468,11 @@ enum reg_class #define INIT_CUMULATIVE_ARGS(cum, fntype, libname, fndecl, n_named_args) \ nds32_init_cumulative_args (&cum, fntype, libname, fndecl, n_named_args) -/* The REGNO is an unsigned integer but NDS32_GPR_ARG_FIRST_REGNUM may be 0. - We better cast REGNO into signed integer so that we can avoid - 'comparison of unsigned expression >= 0 is always true' warning. */ -#define FUNCTION_ARG_REGNO_P(regno) \ - (((int) regno - NDS32_GPR_ARG_FIRST_REGNUM >= 0) \ - && ((int) regno - NDS32_GPR_ARG_FIRST_REGNUM < NDS32_MAX_GPR_REGS_FOR_ARGS)) +#define FUNCTION_ARG_REGNO_P(regno) \ + (IN_RANGE ((regno), NDS32_FIRST_GPR_REGNUM, NDS32_MAX_GPR_REGS_FOR_ARGS - 1) \ + || ((TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE) \ + && IN_RANGE ((regno), NDS32_FPR_ARG_FIRST_REGNUM, \ + NDS32_FIRST_FPR_REGNUM + NDS32_MAX_FPR_REGS_FOR_ARGS - 1))) #define DEFAULT_PCC_STRUCT_RETURN 0 @@ -763,7 +1484,15 @@ enum reg_class #define EXIT_IGNORE_STACK 1 #define FUNCTION_PROFILER(file, labelno) \ - fprintf (file, "/* profiler %d */", (labelno)) + fprintf (file, "/* profiler %d */\n", (labelno)) + +#define PROFILE_HOOK(LABEL) \ + { \ + rtx fun, lp; \ + lp = get_hard_reg_initial_val (Pmode, LP_REGNUM); \ + fun = gen_rtx_SYMBOL_REF (Pmode, "_mcount"); \ + emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lp, Pmode); \ + } /* Implementing the Varargs Macros. */ @@ -780,13 +1509,13 @@ enum reg_class The trampoline code for nds32 target must contains following parts: 1. instructions (4 * 4 = 16 bytes): - get $pc first - load chain_value to static chain register via $pc - load nested function address to $r15 via $pc - jump to desired nested function via $r15 + get $pc first + load chain_value to static chain register via $pc + load nested function address to $r15 via $pc + jump to desired nested function via $r15 2. data (4 * 2 = 8 bytes): - chain_value - nested function address + chain_value + nested function address Please check nds32.c implementation for more information. */ #define TRAMPOLINE_SIZE 24 @@ -811,9 +1540,22 @@ enum reg_class /* We have "LW.bi Rt, [Ra], Rb" instruction form. */ #define HAVE_POST_MODIFY_REG 1 -#define CONSTANT_ADDRESS_P(x) (CONSTANT_P (x) && GET_CODE (x) != CONST_DOUBLE) +#define USE_LOAD_POST_INCREMENT(mode) \ + (GET_MODE_SIZE (mode) <= GET_MODE_SIZE(DImode)) +#define USE_LOAD_POST_DECREMENT(mode) \ + (GET_MODE_SIZE (mode) <= GET_MODE_SIZE(DImode)) +#define USE_STORE_POST_DECREMENT(mode) USE_LOAD_POST_DECREMENT(mode) +#define USE_STORE_POST_INCREMENT(mode) USE_LOAD_POST_INCREMENT(mode) + +#define CONSTANT_ADDRESS_P(x) \ + (CONSTANT_P (x) && memory_address_p (GET_MODE (x), x)) -#define MAX_REGS_PER_ADDRESS 2 +/* CONST_DOUBLE is legal without TARGET_FPU in legitimate_constant_p. + Therefore, let it be a legal PIC operand and split it later.*/ +#define LEGITIMATE_PIC_OPERAND_P(x) \ + (GET_CODE (x) != CONST_DOUBLE || !(TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE)) + +#define MAX_REGS_PER_ADDRESS 3 /* Anchored Addresses. */ @@ -827,7 +1569,11 @@ enum reg_class /* A C expression for the cost of a branch instruction. A value of 1 is the default; other values are interpreted relative to that. */ -#define BRANCH_COST(speed_p, predictable_p) ((speed_p) ? 2 : 0) +#define BRANCH_COST(speed_p, predictable_p) ((speed_p) ? 2 : 1) + +/* Override BRANCH_COST heuristic which empirically produces worse + performance for removing short circuiting from the logical ops. */ +#define LOGICAL_OP_NON_SHORT_CIRCUIT 0 #define SLOW_BYTE_ACCESS 1 @@ -857,12 +1603,17 @@ enum reg_class #define PIC_OFFSET_TABLE_REGNUM GP_REGNUM +#define SYMBOLIC_CONST_P(X) \ +(GET_CODE (X) == SYMBOL_REF \ + || GET_CODE (X) == LABEL_REF \ + || (GET_CODE (X) == CONST && symbolic_reference_mentioned_p (X))) + /* Defining the Output Assembler Language. */ #define ASM_COMMENT_START "!" -#define ASM_APP_ON "! #APP" +#define ASM_APP_ON "! #APP\n" #define ASM_APP_OFF "! #NO_APP\n" @@ -877,14 +1628,77 @@ enum reg_class #define LOCAL_LABEL_PREFIX "." -#define REGISTER_NAMES \ -{ \ - "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", \ +#define REGISTER_NAMES \ +{ "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", \ "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$ta", \ "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23", \ "$r24", "$r25", "$r26", "$r27", "$fp", "$gp", "$lp", "$sp", \ - "$AP", \ - "$SFP" \ + "$AP", "$SFP", "$fs0", "$fs1", "$fs2", "$fs3", "$fs4", "$fs5", \ + "$fs6", "$fs7", "$fs8", "$fs9", "$fs10","$fs11","$fs12","$fs13",\ + "$fs14","$fs15","$fs16","$fs17","$fs18","$fs19","$fs20","$fs21",\ + "$fs22","$fs23","$fs24","$fs25","$fs26","$fs27","$fs28","$fs29",\ + "$fs30","$fs31","$fs32","$fs33","$fs34","$fs35","$fs36","$fs37",\ + "$fs38","$fs39","$fs40","$fs41","$fs42","$fs43","$fs44","$fs45",\ + "$fs46","$fs47","$fs48","$fs49","$fs50","$fs51","$fs52","$fs53",\ + "$fs54","$fs55","$fs56","$fs57","$fs58","$fs59","$fs60","$fs61",\ + "$fs62","$fs63", "LB", "LE", "LC" \ +} + +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + {"$r15", 15}, \ + {"$r28", 28}, {"$r29", 29}, {"$r30", 30}, {"$r31", 31}, \ + {"$a0", 0}, {"$a1", 1}, {"$a2", 2}, \ + {"$a3", 3}, {"$a4", 4}, {"$a5", 5}, \ + {"$s0", 6}, {"$s1", 7}, {"$s2", 8}, {"$s3", 9}, \ + {"$s4", 10}, {"$s5", 11}, {"$s6", 12}, {"$s7", 13}, \ + {"$s8", 14}, \ + {"$t0", 16}, {"$t1", 17}, {"$t2", 18}, {"$t3", 19}, \ + {"$t4", 20}, {"$t5", 21}, {"$t6", 22}, {"$t7", 23}, \ + {"$t8", 24}, {"$t9", 25}, \ + {"$p0", 26}, {"$p1", 27}, \ + {"$h0", 0}, {"$h1", 1}, {"$h2", 2}, {"$h3", 3}, \ + {"$h4", 4}, {"$h5", 5}, {"$h6", 6}, {"$h7", 7}, \ + {"$h8", 8}, {"$h9", 9}, {"$h10", 10}, {"$h11", 11}, \ + {"$h12", 16}, {"$h13", 17}, {"$h14", 18}, {"$h15", 19}, \ + {"$o0", 0}, {"$o1", 1}, {"$o2", 2}, {"$o3", 3}, \ + {"$o4", 4}, {"$o5", 5}, {"$o6", 6}, {"$o7", 7}, \ +} + +#define OVERLAPPING_REGISTER_NAMES \ +{ \ + {"$fd0", NDS32_FIRST_FPR_REGNUM + 0, 2}, \ + {"$fd1", NDS32_FIRST_FPR_REGNUM + 2, 2}, \ + {"$fd2", NDS32_FIRST_FPR_REGNUM + 4, 2}, \ + {"$fd3", NDS32_FIRST_FPR_REGNUM + 6, 2}, \ + {"$fd4", NDS32_FIRST_FPR_REGNUM + 8, 2}, \ + {"$fd5", NDS32_FIRST_FPR_REGNUM + 10, 2}, \ + {"$fd6", NDS32_FIRST_FPR_REGNUM + 12, 2}, \ + {"$fd7", NDS32_FIRST_FPR_REGNUM + 14, 2}, \ + {"$fd8", NDS32_FIRST_FPR_REGNUM + 16, 2}, \ + {"$fd9", NDS32_FIRST_FPR_REGNUM + 18, 2}, \ + {"$fd10", NDS32_FIRST_FPR_REGNUM + 20, 2}, \ + {"$fd11", NDS32_FIRST_FPR_REGNUM + 22, 2}, \ + {"$fd12", NDS32_FIRST_FPR_REGNUM + 24, 2}, \ + {"$fd13", NDS32_FIRST_FPR_REGNUM + 26, 2}, \ + {"$fd14", NDS32_FIRST_FPR_REGNUM + 28, 2}, \ + {"$fd15", NDS32_FIRST_FPR_REGNUM + 30, 2}, \ + {"$fd16", NDS32_FIRST_FPR_REGNUM + 32, 2}, \ + {"$fd17", NDS32_FIRST_FPR_REGNUM + 34, 2}, \ + {"$fd18", NDS32_FIRST_FPR_REGNUM + 36, 2}, \ + {"$fd19", NDS32_FIRST_FPR_REGNUM + 38, 2}, \ + {"$fd20", NDS32_FIRST_FPR_REGNUM + 40, 2}, \ + {"$fd21", NDS32_FIRST_FPR_REGNUM + 42, 2}, \ + {"$fd22", NDS32_FIRST_FPR_REGNUM + 44, 2}, \ + {"$fd23", NDS32_FIRST_FPR_REGNUM + 46, 2}, \ + {"$fd24", NDS32_FIRST_FPR_REGNUM + 48, 2}, \ + {"$fd25", NDS32_FIRST_FPR_REGNUM + 50, 2}, \ + {"$fd26", NDS32_FIRST_FPR_REGNUM + 52, 2}, \ + {"$fd27", NDS32_FIRST_FPR_REGNUM + 54, 2}, \ + {"$fd28", NDS32_FIRST_FPR_REGNUM + 56, 2}, \ + {"$fd29", NDS32_FIRST_FPR_REGNUM + 58, 2}, \ + {"$fd30", NDS32_FIRST_FPR_REGNUM + 60, 2}, \ + {"$fd31", NDS32_FIRST_FPR_REGNUM + 62, 2}, \ } /* Output normal jump table entry. */ @@ -896,19 +1710,19 @@ enum reg_class do \ { \ switch (GET_MODE (body)) \ - { \ - case QImode: \ - asm_fprintf (stream, "\t.byte\t.L%d-.L%d\n", value, rel); \ - break; \ - case HImode: \ - asm_fprintf (stream, "\t.short\t.L%d-.L%d\n", value, rel); \ - break; \ - case SImode: \ - asm_fprintf (stream, "\t.word\t.L%d-.L%d\n", value, rel); \ - break; \ - default: \ - gcc_unreachable(); \ - } \ + { \ + case QImode: \ + asm_fprintf (stream, "\t.byte\t.L%d-.L%d\n", value, rel); \ + break; \ + case HImode: \ + asm_fprintf (stream, "\t.short\t.L%d-.L%d\n", value, rel); \ + break; \ + case SImode: \ + asm_fprintf (stream, "\t.word\t.L%d-.L%d\n", value, rel); \ + break; \ + default: \ + gcc_unreachable(); \ + } \ } while (0) /* We have to undef it first because elfos.h formerly define it @@ -925,10 +1739,10 @@ enum reg_class do \ { \ /* Because our jump table is in text section, \ - we need to make sure 2-byte alignment after \ - the jump table for instructions fetch. */ \ + we need to make sure 2-byte alignment after \ + the jump table for instructions fetch. */ \ if (GET_MODE (PATTERN (table)) == QImode) \ - ASM_OUTPUT_ALIGN (stream, 1); \ + ASM_OUTPUT_ALIGN (stream, 1); \ asm_fprintf (stream, "\t! Jump Table End\n"); \ } while (0) @@ -992,9 +1806,7 @@ enum reg_class /* Return the preferred mode for and addr_diff_vec when the mininum and maximum offset are known. */ #define CASE_VECTOR_SHORTEN_MODE(min_offset, max_offset, body) \ - ((min_offset < 0 || max_offset >= 0x2000 ) ? SImode \ - : (max_offset >= 100) ? HImode \ - : QImode) + nds32_case_vector_shorten_mode (min_offset, max_offset, body) /* Generate pc relative jump table when -fpic or -Os. */ #define CASE_VECTOR_PC_RELATIVE (flag_pic || optimize_size) @@ -1027,6 +1839,11 @@ enum reg_class when the condition is true. */ #define STORE_FLAG_VALUE 1 +/* A C expression that indicates whether the architecture defines a value for + clz or ctz with a zero operand. In nds32 clz for 0 result 32 is defined + in ISA spec */ +#define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = 32, 1) + /* An alias for the machine mode for pointers. */ #define Pmode SImode diff --git a/gcc/config/nds32/nds32.md b/gcc/config/nds32/nds32.md index 494a78d..557c466 100644 --- a/gcc/config/nds32/nds32.md +++ b/gcc/config/nds32/nds32.md @@ -46,58 +46,144 @@ ;; Include DImode/DFmode operations. (include "nds32-doubleword.md") +;; Include floating-point patterns. +(include "nds32-fpu.md") + ;; Include peephole patterns. (include "nds32-peephole2.md") +;; ------------------------------------------------------------------------ + +;; CPU pipeline model. +(define_attr "pipeline_model" "n7,n8,e8,n9,n10,graywolf,n13,panther,simple" + (const + (cond [(match_test "nds32_cpu_option == CPU_N7") (const_string "n7") + (match_test "nds32_cpu_option == CPU_N6 || nds32_cpu_option == CPU_N8") (const_string "n8") + (match_test "nds32_cpu_option == CPU_E8") (const_string "e8") + (match_test "nds32_cpu_option == CPU_N9") (const_string "n9") + (match_test "nds32_cpu_option == CPU_N10") (const_string "n10") + (match_test "nds32_cpu_option == CPU_GRAYWOLF") (const_string "graywolf") + (match_test "nds32_cpu_option == CPU_N12") (const_string "n13") + (match_test "nds32_cpu_option == CPU_N13") (const_string "n13") + (match_test "nds32_cpu_option == CPU_PANTHER") (const_string "panther") + (match_test "nds32_cpu_option == CPU_SIMPLE") (const_string "simple")] + (const_string "n9")))) + ;; Insn type, it is used to default other attribute values. (define_attr "type" - "unknown,move,load,store,alu,compare,branch,call,misc" + "unknown,load,store,load_multiple,store_multiple,alu,alu_shift,pbsad,pbsada,mul,mac,div,branch,mmu,misc,\ + falu,fmuls,fmuld,fmacs,fmacd,fdivs,fdivd,fsqrts,fsqrtd,fcmp,fabs,fcpy,fcmov,fmfsr,fmfdr,fmtsr,fmtdr,fload,fstore,\ + dalu,dalu64,daluround,dcmp,dclip,dmul,dmac,dinsb,dpack,dbpick,dwext" (const_string "unknown")) +;; Insn sub-type +(define_attr "subtype" + "simple,shift,saturation" + (const_string "simple")) ;; Length, in bytes, default is 4-bytes. (define_attr "length" "" (const_int 4)) +;; Indicate the amount of micro instructions. +(define_attr "combo" + "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25" + (const_string "1")) + +;; Insn in which feature set, it is used to enable/disable insn alternatives. +;; v1 : Baseline Instructions +;; v2 : Baseline Version 2 Instructions +;; v3m : Baseline Version 3m Instructions +;; v3 : Baseline Version 3 Instructions +;; pe1 : Performance Extension Instructions +;; pe2 : Performance Extension Version 2 Instructions +;; se : String Extension instructions +(define_attr "feature" + "v1,v2,v3m,v3,pe1,pe2,se,fpu" + (const_string "v1")) ;; Enabled, which is used to enable/disable insn alternatives. ;; Note that we use length and TARGET_16_BIT here as criteria. -;; If the instruction pattern already check TARGET_16_BIT to -;; determine the length by itself, its enabled attribute should be -;; always 1 to avoid the conflict with the settings here. -(define_attr "enabled" "" - (cond [(and (eq_attr "length" "2") - (match_test "!TARGET_16_BIT")) - (const_int 0)] - (const_int 1))) +;; If the instruction pattern already check TARGET_16_BIT to determine +;; the length by itself, its enabled attribute should be customized to +;; avoid the conflict between length attribute and this default setting. +(define_attr "enabled" "no,yes" + (if_then_else + (and (eq_attr "length" "2") + (match_test "!TARGET_16_BIT")) + (const_string "no") + (cond [(eq_attr "feature" "v1") (const_string "yes") + (eq_attr "feature" "v2") (if_then_else (match_test "TARGET_ISA_V2 || TARGET_ISA_V3 || TARGET_ISA_V3M") + (const_string "yes") + (const_string "no")) + (eq_attr "feature" "v3") (if_then_else (match_test "TARGET_ISA_V3") + (const_string "yes") + (const_string "no")) + (eq_attr "feature" "v3m") (if_then_else (match_test "TARGET_ISA_V3 || TARGET_ISA_V3M") + (const_string "yes") + (const_string "no")) + (eq_attr "feature" "pe1") (if_then_else (match_test "TARGET_EXT_PERF") + (const_string "yes") + (const_string "no")) + (eq_attr "feature" "pe2") (if_then_else (match_test "TARGET_EXT_PERF2") + (const_string "yes") + (const_string "no")) + (eq_attr "feature" "se") (if_then_else (match_test "TARGET_EXT_STRING") + (const_string "yes") + (const_string "no")) + (eq_attr "feature" "fpu") (if_then_else (match_test "TARGET_FPU_SINGLE || TARGET_FPU_DOUBLE") + (const_string "yes") + (const_string "no"))] + (const_string "yes")))) ;; ---------------------------------------------------------------------------- +(include "nds32-dspext.md") ;; Move instructions. ;; For QImode and HImode, the immediate value can be fit in imm20s. ;; So there is no need to split rtx for QI and HI patterns. -(define_expand "movqi" - [(set (match_operand:QI 0 "general_operand" "") - (match_operand:QI 1 "general_operand" ""))] +(define_expand "mov" + [(set (match_operand:QIHI 0 "general_operand" "") + (match_operand:QIHI 1 "general_operand" ""))] "" { /* Need to force register if mem <- !reg. */ if (MEM_P (operands[0]) && !REG_P (operands[1])) - operands[1] = force_reg (QImode, operands[1]); + operands[1] = force_reg (mode, operands[1]); + + if (MEM_P (operands[1]) && optimize > 0) + { + rtx reg = gen_reg_rtx (SImode); + + emit_insn (gen_zero_extendsi2 (reg, operands[1])); + operands[1] = gen_lowpart (mode, reg); + } }) -(define_expand "movhi" - [(set (match_operand:HI 0 "general_operand" "") - (match_operand:HI 1 "general_operand" ""))] +(define_expand "movmisalign" + [(set (match_operand:SIDI 0 "general_operand" "") + (match_operand:SIDI 1 "general_operand" ""))] "" { - /* Need to force register if mem <- !reg. */ + rtx addr; if (MEM_P (operands[0]) && !REG_P (operands[1])) - operands[1] = force_reg (HImode, 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 "movsi" @@ -130,12 +216,33 @@ low12_int)); DONE; } + + if (REG_P (operands[0]) && SYMBOLIC_CONST_P (operands[1])) + { + if (TARGET_ICT_MODEL_LARGE + && nds32_indirect_call_referenced_p (operands[1])) + { + nds32_expand_ict_move (operands); + DONE; + } + else 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:QIHISI 0 "nonimmediate_operand" "=r, r, U45, U33, U37, U45, m, l, l, l, d, r, d, r, r, r") - (match_operand:QIHISI 1 "nds32_move_operand" " r, r, l, l, l, d, r, U45, U33, U37, U45, m, Ip05, Is05, Is20, Ihig"))] - "" + [(set (match_operand:QIHISI 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:QIHISI 1 "nds32_move_operand" " r, r, l, l, l, d, r,U45,U33,U37,U45,Ufe, m,Ip05, Is05, Is20, Ihig, *f, r, *f, Q, *f, r"))] + "register_operand(operands[0], mode) + || register_operand(operands[1], mode)" { switch (which_alternative) { @@ -154,37 +261,54 @@ case 8: case 9: case 10: - return nds32_output_16bit_load (operands, ); case 11: - return nds32_output_32bit_load (operands, ); + return nds32_output_16bit_load (operands, ); case 12: - return "movpi45\t%0, %1"; + return nds32_output_32bit_load (operands, ); case 13: - return "movi55\t%0, %1"; + return "movpi45\t%0, %1"; case 14: - return "movi\t%0, %1"; + 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,alu,alu,alu,alu") - (set_attr "length" " 2, 4, 2, 2, 2, 2, 4, 2, 2, 2, 2, 4, 2, 2, 4, 4")]) + [(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")]) ;; We use nds32_symbolic_operand to limit that only CONST/SYMBOL_REF/LABEL_REF ;; are able to match such instruction template. -(define_insn "*move_addr" - [(set (match_operand:SI 0 "register_operand" "=l, r") - (match_operand:SI 1 "nds32_symbolic_operand" " i, i"))] +(define_insn "move_addr" + [(set (match_operand:SI 0 "nds32_general_register_operand" "=l, r") + (match_operand:SI 1 "nds32_nonunspec_symbolic_operand" " i, i"))] "" "la\t%0, %1" - [(set_attr "type" "move") + [(set_attr "type" "alu") (set_attr "length" "8")]) -(define_insn "*sethi" +(define_insn "sethi" [(set (match_operand:SI 0 "register_operand" "=r") (high:SI (match_operand:SI 1 "nds32_symbolic_operand" " i")))] "" @@ -193,7 +317,7 @@ (set_attr "length" "4")]) -(define_insn "*lo_sum" +(define_insn "lo_sum" [(set (match_operand:SI 0 "register_operand" "=r") (lo_sum:SI (match_operand:SI 1 "register_operand" " r") (match_operand:SI 2 "nds32_symbolic_operand" " i")))] @@ -208,8 +332,8 @@ ;; Zero extension instructions. (define_insn "zero_extendsi2" - [(set (match_operand:SI 0 "register_operand" "=l, r, l, *r") - (zero_extend:SI (match_operand:QIHI 1 "nonimmediate_operand" " l, r, U33, m")))] + [(set (match_operand:SI 0 "register_operand" "=l, r, l, *r") + (zero_extend:SI (match_operand:QIHI 1 "nonimmediate_operand" " l, r,U33, m")))] "" { switch (which_alternative) @@ -245,7 +369,7 @@ case 1: return "se\t%0, %1"; case 2: - return nds32_output_32bit_load_s (operands, ); + return nds32_output_32bit_load_se (operands, ); default: gcc_unreachable (); @@ -256,25 +380,70 @@ ;; ---------------------------------------------------------------------------- +(define_expand "extv" + [(set (match_operand 0 "register_operand" "") + (sign_extract (match_operand 1 "nonimmediate_operand" "") + (match_operand 2 "const_int_operand" "") + (match_operand 3 "const_int_operand" "")))] + "" +{ + enum nds32_expand_result_type result = nds32_expand_extv (operands); + switch (result) + { + case EXPAND_DONE: + DONE; + break; + case EXPAND_FAIL: + FAIL; + break; + case EXPAND_CREATE_TEMPLATE: + break; + default: + gcc_unreachable (); + } +}) + +(define_expand "insv" + [(set (zero_extract (match_operand 0 "nonimmediate_operand" "") + (match_operand 1 "const_int_operand" "") + (match_operand 2 "const_int_operand" "")) + (match_operand 3 "register_operand" ""))] + "" +{ + enum nds32_expand_result_type result = nds32_expand_insv (operands); + switch (result) + { + case EXPAND_DONE: + DONE; + break; + case EXPAND_FAIL: + FAIL; + break; + case EXPAND_CREATE_TEMPLATE: + break; + default: + gcc_unreachable (); + } +}) ;; Arithmetic instructions. -(define_insn "add3" - [(set (match_operand:QIHISI 0 "register_operand" "= d, l, d, l, d, l, k, l, r, r") - (plus:QIHISI (match_operand:QIHISI 1 "register_operand" "% 0, l, 0, l, 0, l, 0, k, r, r") - (match_operand:QIHISI 2 "nds32_rimm15s_operand" " In05, In03, Iu05, Iu03, r, l, Is10, Iu06, Is15, r")))] +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "= d, l, d, l, d,l, k, l, r, r") + (plus:SI (match_operand:SI 1 "register_operand" "% 0, l, 0, l, 0,l, 0, k, r, r") + (match_operand:SI 2 "nds32_rimm15s_operand" " In05,In03,Iu05,Iu03, r,l,Is10,IU06, Is15, r")))] "" { switch (which_alternative) { case 0: /* addi Rt4,Rt4,-x ==> subi45 Rt4,x - where 0 <= x <= 31 */ + where 0 <= x <= 31 */ operands[2] = gen_int_mode (-INTVAL (operands[2]), SImode); return "subi45\t%0, %2"; case 1: /* addi Rt3,Ra3,-x ==> subi333 Rt3,Ra3,x - where 0 <= x <= 7 */ + where 0 <= x <= 7 */ operands[2] = gen_int_mode (-INTVAL (operands[2]), SImode); return "subi333\t%0, %1, %2"; case 2: @@ -298,19 +467,20 @@ gcc_unreachable (); } } - [(set_attr "type" "alu,alu,alu,alu,alu,alu,alu,alu,alu,alu") - (set_attr "length" " 2, 2, 2, 2, 2, 2, 2, 2, 4, 4")]) - -(define_insn "sub3" - [(set (match_operand:QIHISI 0 "register_operand" "=d, l, r, r") - (minus:QIHISI (match_operand:QIHISI 1 "nds32_rimm15s_operand" " 0, l, Is15, r") - (match_operand:QIHISI 2 "register_operand" " r, l, r, r")))] + [(set_attr "type" "alu,alu,alu,alu,alu,alu,alu,alu,alu,alu") + (set_attr "length" " 2, 2, 2, 2, 2, 2, 2, 2, 4, 4") + (set_attr "feature" " v1, v1, v1, v1, v1, v1, v2, v1, v1, v1")]) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=d, l, r, r") + (minus:SI (match_operand:SI 1 "nds32_rimm15s_operand" " 0, l, Is15, r") + (match_operand:SI 2 "register_operand" " r, l, r, r")))] "" "@ - sub45\t%0, %2 - sub333\t%0, %1, %2 - subri\t%0, %2, %1 - sub\t%0, %1, %2" + sub45\t%0, %2 + sub333\t%0, %1, %2 + subri\t%0, %2, %1 + sub\t%0, %1, %2" [(set_attr "type" "alu,alu,alu,alu") (set_attr "length" " 2, 2, 4, 4")]) @@ -320,10 +490,10 @@ ;; and needs to ensure it is exact_log2 value. (define_insn "*add_slli" [(set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (mult:SI (match_operand:SI 1 "register_operand" " r") + (plus:SI (mult:SI (match_operand:SI 1 "register_operand" " r") (match_operand:SI 2 "immediate_operand" " i")) (match_operand:SI 3 "register_operand" " r")))] - "TARGET_ISA_V3 + "TARGET_ISA_V3 && (TARGET_PIPELINE_PANTHER || optimize_size) && (exact_log2 (INTVAL (operands[2])) != -1) && (exact_log2 (INTVAL (operands[2])) <= 31)" { @@ -333,18 +503,20 @@ return "add_slli\t%0, %3, %1, %2"; } - [(set_attr "type" "alu") - (set_attr "length" "4")]) + [(set_attr "type" "alu_shift") + (set_attr "combo" "2") + (set_attr "length" "4")]) (define_insn "*add_srli" - [(set (match_operand:SI 0 "register_operand" "= r") - (plus:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:SI 2 "immediate_operand" " Iu05")) - (match_operand:SI 3 "register_operand" " r")))] - "TARGET_ISA_V3" + [(set (match_operand:SI 0 "register_operand" "= r") + (plus:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "nds32_imm5u_operand" " Iu05")) + (match_operand:SI 3 "register_operand" " r")))] + "TARGET_ISA_V3 && (TARGET_PIPELINE_PANTHER || optimize_size)" "add_srli\t%0, %3, %1, %2" - [(set_attr "type" "alu") - (set_attr "length" "4")]) + [(set_attr "type" "alu_shift") + (set_attr "combo" "2") + (set_attr "length" "4")]) ;; GCC intends to simplify (minus (reg) (ashift ...)) @@ -355,7 +527,7 @@ (minus:SI (match_operand:SI 1 "register_operand" " r") (mult:SI (match_operand:SI 2 "register_operand" " r") (match_operand:SI 3 "immediate_operand" " i"))))] - "TARGET_ISA_V3 + "TARGET_ISA_V3 && (TARGET_PIPELINE_PANTHER || optimize_size) && (exact_log2 (INTVAL (operands[3])) != -1) && (exact_log2 (INTVAL (operands[3])) <= 31)" { @@ -365,32 +537,35 @@ return "sub_slli\t%0, %1, %2, %3"; } - [(set_attr "type" "alu") - (set_attr "length" "4")]) + [(set_attr "type" "alu_shift") + (set_attr "combo" "2") + (set_attr "length" "4")]) (define_insn "*sub_srli" - [(set (match_operand:SI 0 "register_operand" "= r") - (minus:SI (match_operand:SI 1 "register_operand" " r") - (lshiftrt:SI (match_operand:SI 2 "register_operand" " r") - (match_operand:SI 3 "immediate_operand" " Iu05"))))] - "TARGET_ISA_V3" + [(set (match_operand:SI 0 "register_operand" "= r") + (minus:SI (match_operand:SI 1 "register_operand" " r") + (lshiftrt:SI (match_operand:SI 2 "register_operand" " r") + (match_operand:SI 3 "nds32_imm5u_operand" " Iu05"))))] + "TARGET_ISA_V3 && (TARGET_PIPELINE_PANTHER || optimize_size)" "sub_srli\t%0, %1, %2, %3" - [(set_attr "type" "alu") - (set_attr "length" "4")]) + [(set_attr "type" "alu_shift") + (set_attr "combo" "2") + (set_attr "length" "4")]) ;; Multiplication instructions. (define_insn "mulsi3" - [(set (match_operand:SI 0 "register_operand" "=w, r") + [(set (match_operand:SI 0 "register_operand" "=l, r") (mult:SI (match_operand:SI 1 "register_operand" "%0, r") - (match_operand:SI 2 "register_operand" " w, r")))] + (match_operand:SI 2 "register_operand" " l, r")))] "" "@ - mul33\t%0, %2 - mul\t%0, %1, %2" - [(set_attr "type" "alu,alu") - (set_attr "length" " 2, 4")]) + mul33\t%0, %2 + mul\t%0, %1, %2" + [(set_attr "type" "mul,mul") + (set_attr "length" " 2, 4") + (set_attr "feature" "v3m, v1")]) (define_insn "mulsidi3" [(set (match_operand:DI 0 "register_operand" "=r") @@ -398,7 +573,7 @@ (sign_extend:DI (match_operand:SI 2 "register_operand" " r"))))] "TARGET_ISA_V2 || TARGET_ISA_V3" "mulsr64\t%0, %1, %2" - [(set_attr "type" "alu") + [(set_attr "type" "mul") (set_attr "length" "4")]) (define_insn "umulsidi3" @@ -407,7 +582,7 @@ (zero_extend:DI (match_operand:SI 2 "register_operand" " r"))))] "TARGET_ISA_V2 || TARGET_ISA_V3" "mulr64\t%0, %1, %2" - [(set_attr "type" "alu") + [(set_attr "type" "mul") (set_attr "length" "4")]) @@ -415,32 +590,32 @@ (define_insn "*maddr32_0" [(set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (match_operand:SI 3 "register_operand" " 0") - (mult:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:SI 2 "register_operand" " r"))))] + (plus:SI (match_operand:SI 3 "register_operand" " 0") + (mult:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "register_operand" " r"))))] "" "maddr32\t%0, %1, %2" - [(set_attr "type" "alu") + [(set_attr "type" "mac") (set_attr "length" "4")]) (define_insn "*maddr32_1" [(set (match_operand:SI 0 "register_operand" "=r") - (plus:SI (mult:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:SI 2 "register_operand" " r")) - (match_operand:SI 3 "register_operand" " 0")))] + (plus:SI (mult:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "register_operand" " r")) + (match_operand:SI 3 "register_operand" " 0")))] "" "maddr32\t%0, %1, %2" - [(set_attr "type" "alu") + [(set_attr "type" "mac") (set_attr "length" "4")]) (define_insn "*msubr32" [(set (match_operand:SI 0 "register_operand" "=r") - (minus:SI (match_operand:SI 3 "register_operand" " 0") - (mult:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:SI 2 "register_operand" " r"))))] + (minus:SI (match_operand:SI 3 "register_operand" " 0") + (mult:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "register_operand" " r"))))] "" "msubr32\t%0, %1, %2" - [(set_attr "type" "alu") + [(set_attr "type" "mac") (set_attr "length" "4")]) @@ -448,26 +623,46 @@ (define_insn "divmodsi4" [(set (match_operand:SI 0 "register_operand" "=r") - (div:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:SI 2 "register_operand" " r"))) + (div:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "register_operand" " r"))) (set (match_operand:SI 3 "register_operand" "=r") - (mod:SI (match_dup 1) (match_dup 2)))] + (mod:SI (match_dup 1) (match_dup 2)))] "" "divsr\t%0, %3, %1, %2" - [(set_attr "type" "alu") + [(set_attr "type" "div") (set_attr "length" "4")]) (define_insn "udivmodsi4" [(set (match_operand:SI 0 "register_operand" "=r") - (udiv:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:SI 2 "register_operand" " r"))) + (udiv:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "register_operand" " r"))) (set (match_operand:SI 3 "register_operand" "=r") - (umod:SI (match_dup 1) (match_dup 2)))] + (umod:SI (match_dup 1) (match_dup 2)))] "" "divr\t%0, %3, %1, %2" - [(set_attr "type" "alu") + [(set_attr "type" "div") + (set_attr "length" "4")]) + +;; divsr/divr will keep quotient only when quotient and remainder is the same +;; register in our ISA spec, it's can reduce 1 register presure if we don't +;; want remainder. +(define_insn "divsi4" + [(set (match_operand:SI 0 "register_operand" "=r") + (div:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "register_operand" " r")))] + "" + "divsr\t%0, %0, %1, %2" + [(set_attr "type" "div") (set_attr "length" "4")]) +(define_insn "udivsi4" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "register_operand" " r")))] + "" + "divr\t%0, %0, %1, %2" + [(set_attr "type" "div") + (set_attr "length" "4")]) ;; ---------------------------------------------------------------------------- @@ -488,14 +683,28 @@ (set_attr "length" "4")] ) -(define_insn "andsi3" - [(set (match_operand:SI 0 "register_operand" "=w, r, l, l, l, l, l, l, r, r, r, r, r") - (and:SI (match_operand:SI 1 "register_operand" "%0, r, l, l, l, l, 0, 0, r, r, r, r, r") - (match_operand:SI 2 "general_operand" " w, r, Izeb, Izeh, Ixls, Ix11, Ibms, Ifex, Izeb, Izeh, Iu15, Ii15, Ic15")))] +(define_expand "andsi3" + [(set (match_operand:SI 0 "register_operand" "") + (and:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nds32_reg_constant_operand" "")))] + "" +{ + if (CONST_INT_P (operands[2]) + && !nds32_and_operand (operands[2], SImode)) + { + nds32_expand_constant (SImode, INTVAL (operands[2]), + operands[0], operands[1]); + DONE; + } +}) + +(define_insn "*andsi3" + [(set (match_operand:SI 0 "register_operand" "=l, r, l, l, l, l, l, l, r, r, r, r, r") + (and:SI (match_operand:SI 1 "register_operand" "%0, r, l, l, l, l, 0, 0, r, r, r, r, r") + (match_operand:SI 2 "nds32_and_operand" " l, r,Izeb,Izeh,Ixls,Ix11,Ibms,Ifex, Izeb, Izeh, Iu15, Ii15, Ic15")))] "" { HOST_WIDE_INT mask = INTVAL (operands[2]); - int zero_position; /* 16-bit andi instructions: andi Rt3,Ra3,0xff -> zeb33 Rt3,Ra3 @@ -520,8 +729,7 @@ case 5: return "x11b33\t%0, %1"; case 6: - operands[2] = GEN_INT (floor_log2 (mask)); - return "bmski33\t%0, %2"; + return "bmski33\t%0, %B2"; case 7: operands[2] = GEN_INT (floor_log2 (mask + 1) - 1); return "fexti33\t%0, %2"; @@ -535,47 +743,35 @@ operands[2] = GEN_INT (~mask); return "bitci\t%0, %1, %2"; case 12: - /* If we reach this alternative, - it must pass the nds32_can_use_bclr_p() test, - so that we can guarantee there is only one 0-bit - within the immediate value. */ - for (zero_position = 31; zero_position >= 0; zero_position--) - { - if ((INTVAL (operands[2]) & (1 << zero_position)) == 0) - { - /* Found the 0-bit position. */ - operands[2] = GEN_INT (zero_position); - break; - } - } - return "bclr\t%0, %1, %2"; + return "bclr\t%0, %1, %b2"; default: gcc_unreachable (); } } - [(set_attr "type" "alu,alu,alu,alu,alu,alu,alu,alu,alu,alu,alu,alu,alu") - (set_attr "length" " 2, 4, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4")]) + [(set_attr "type" "alu,alu,alu,alu,alu,alu,alu,alu,alu,alu,alu,alu,alu") + (set_attr "length" " 2, 4, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4") + (set_attr "feature" "v3m, v1, v1, v1, v1, v1,v3m,v3m, v1, v1, v1, v3,pe1")]) (define_insn "*and_slli" - [(set (match_operand:SI 0 "register_operand" "= r") - (and:SI (ashift:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:SI 2 "immediate_operand" " Iu05")) - (match_operand:SI 3 "register_operand" " r")))] - "TARGET_ISA_V3" + [(set (match_operand:SI 0 "register_operand" "= r") + (and:SI (ashift:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "nds32_imm5u_operand" " Iu05")) + (match_operand:SI 3 "register_operand" " r")))] + "TARGET_ISA_V3 && (TARGET_PIPELINE_PANTHER || optimize_size)" "and_slli\t%0, %3, %1, %2" - [(set_attr "type" "alu") - (set_attr "length" "4")]) + [(set_attr "type" "alu_shift") + (set_attr "length" "4")]) (define_insn "*and_srli" - [(set (match_operand:SI 0 "register_operand" "= r") - (and:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:SI 2 "immediate_operand" " Iu05")) - (match_operand:SI 3 "register_operand" " r")))] - "TARGET_ISA_V3" + [(set (match_operand:SI 0 "register_operand" "= r") + (and:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "nds32_imm5u_operand" " Iu05")) + (match_operand:SI 3 "register_operand" " r")))] + "TARGET_ISA_V3 && (TARGET_PIPELINE_PANTHER || optimize_size)" "and_srli\t%0, %3, %1, %2" - [(set_attr "type" "alu") - (set_attr "length" "4")]) + [(set_attr "type" "alu_shift") + (set_attr "length" "4")]) ;; ---------------------------------------------------------------------------- @@ -584,58 +780,50 @@ ;; For V3/V3M ISA, we have 'or33' instruction. ;; So we can identify 'or Rt3,Rt3,Ra3' case and set its length to be 2. -(define_insn "iorsi3" - [(set (match_operand:SI 0 "register_operand" "=w, r, r, r") - (ior:SI (match_operand:SI 1 "register_operand" "%0, r, r, r") - (match_operand:SI 2 "general_operand" " w, r, Iu15, Ie15")))] + +(define_expand "iorsi3" + [(set (match_operand:SI 0 "register_operand" "") + (ior:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "general_operand" "")))] "" { - int one_position; - - switch (which_alternative) - { - case 0: - return "or33\t%0, %2"; - case 1: - return "or\t%0, %1, %2"; - case 2: - return "ori\t%0, %1, %2"; - case 3: - /* If we reach this alternative, - it must pass the nds32_can_use_bset_p() test, - so that we can guarantee there is only one 1-bit - within the immediate value. */ - /* Use exact_log2() to search the 1-bit position. */ - one_position = exact_log2 (INTVAL (operands[2])); - operands[2] = GEN_INT (one_position); - return "bset\t%0, %1, %2"; + if (!nds32_ior_operand (operands[2], SImode)) + operands[2] = force_reg (SImode, operands[2]); +}) - default: - gcc_unreachable (); - } -} - [(set_attr "type" "alu,alu,alu,alu") - (set_attr "length" " 2, 4, 4, 4")]) +(define_insn "*iorsi3" + [(set (match_operand:SI 0 "register_operand" "=l, r, r, r") + (ior:SI (match_operand:SI 1 "register_operand" "%0, r, r, r") + (match_operand:SI 2 "nds32_ior_operand" " l, r, Iu15, Ie15")))] + "" + "@ + or33\t%0, %2 + or\t%0, %1, %2 + ori\t%0, %1, %2 + bset\t%0, %1, %B2" + [(set_attr "type" "alu,alu,alu,alu") + (set_attr "length" " 2, 4, 4, 4") + (set_attr "feature" "v3m, v1, v1,pe1")]) (define_insn "*or_slli" - [(set (match_operand:SI 0 "register_operand" "= r") - (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:SI 2 "immediate_operand" " Iu05")) - (match_operand:SI 3 "register_operand" " r")))] - "TARGET_ISA_V3" + [(set (match_operand:SI 0 "register_operand" "= r") + (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "nds32_imm5u_operand" " Iu05")) + (match_operand:SI 3 "register_operand" " r")))] + "TARGET_ISA_V3 && (TARGET_PIPELINE_PANTHER || optimize_size)" "or_slli\t%0, %3, %1, %2" - [(set_attr "type" "alu") - (set_attr "length" "4")]) + [(set_attr "type" "alu_shift") + (set_attr "length" "4")]) (define_insn "*or_srli" - [(set (match_operand:SI 0 "register_operand" "= r") - (ior:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:SI 2 "immediate_operand" " Iu05")) - (match_operand:SI 3 "register_operand" " r")))] - "TARGET_ISA_V3" + [(set (match_operand:SI 0 "register_operand" "= r") + (ior:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "nds32_imm5u_operand" " Iu05")) + (match_operand:SI 3 "register_operand" " r")))] + "TARGET_ISA_V3 && (TARGET_PIPELINE_PANTHER || optimize_size)" "or_srli\t%0, %3, %1, %2" - [(set_attr "type" "alu") - (set_attr "length" "4")]) + [(set_attr "type" "alu_shift") + (set_attr "length" "4")]) ;; ---------------------------------------------------------------------------- @@ -644,71 +832,64 @@ ;; For V3/V3M ISA, we have 'xor33' instruction. ;; So we can identify 'xor Rt3,Rt3,Ra3' case and set its length to be 2. -(define_insn "xorsi3" - [(set (match_operand:SI 0 "register_operand" "=w, r, r, r") - (xor:SI (match_operand:SI 1 "register_operand" "%0, r, r, r") - (match_operand:SI 2 "general_operand" " w, r, Iu15, It15")))] + +(define_expand "xorsi3" + [(set (match_operand:SI 0 "register_operand" "") + (xor:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "general_operand" "")))] "" { - int one_position; - - switch (which_alternative) - { - case 0: - return "xor33\t%0, %2"; - case 1: - return "xor\t%0, %1, %2"; - case 2: - return "xori\t%0, %1, %2"; - case 3: - /* If we reach this alternative, - it must pass the nds32_can_use_btgl_p() test, - so that we can guarantee there is only one 1-bit - within the immediate value. */ - /* Use exact_log2() to search the 1-bit position. */ - one_position = exact_log2 (INTVAL (operands[2])); - operands[2] = GEN_INT (one_position); - return "btgl\t%0, %1, %2"; + if (!nds32_xor_operand (operands[2], SImode)) + operands[2] = force_reg (SImode, operands[2]); +}) - default: - gcc_unreachable (); - } -} - [(set_attr "type" "alu,alu,alu,alu") - (set_attr "length" " 2, 4, 4, 4")]) +(define_insn "*xorsi3" + [(set (match_operand:SI 0 "register_operand" "=l, r, r, r") + (xor:SI (match_operand:SI 1 "register_operand" "%0, r, r, r") + (match_operand:SI 2 "nds32_xor_operand" " l, r, Iu15, It15")))] + "" + "@ + xor33\t%0, %2 + xor\t%0, %1, %2 + xori\t%0, %1, %2 + btgl\t%0, %1, %B2" + [(set_attr "type" "alu,alu,alu,alu") + (set_attr "length" " 2, 4, 4, 4") + (set_attr "feature" "v3m, v1, v1,pe1")]) (define_insn "*xor_slli" [(set (match_operand:SI 0 "register_operand" "= r") (xor:SI (ashift:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:SI 2 "immediate_operand" " Iu05")) + (match_operand:SI 2 "nds32_imm5u_operand" " Iu05")) (match_operand:SI 3 "register_operand" " r")))] - "TARGET_ISA_V3" + "TARGET_ISA_V3 && (TARGET_PIPELINE_PANTHER || optimize_size)" "xor_slli\t%0, %3, %1, %2" - [(set_attr "type" "alu") - (set_attr "length" "4")]) + [(set_attr "type" "alu_shift") + (set_attr "length" "4")]) (define_insn "*xor_srli" - [(set (match_operand:SI 0 "register_operand" "= r") - (xor:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:SI 2 "immediate_operand" " Iu05")) - (match_operand:SI 3 "register_operand" " r")))] - "TARGET_ISA_V3" + [(set (match_operand:SI 0 "register_operand" "= r") + (xor:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "nds32_imm5u_operand" " Iu05")) + (match_operand:SI 3 "register_operand" " r")))] + "TARGET_ISA_V3 && (TARGET_PIPELINE_PANTHER || optimize_size)" "xor_srli\t%0, %3, %1, %2" - [(set_attr "type" "alu") - (set_attr "length" "4")]) + [(set_attr "type" "alu_shift") + (set_attr "length" "4")]) ;; Rotate Right Instructions. -(define_insn "rotrsi3" - [(set (match_operand:SI 0 "register_operand" "= r, r") - (rotatert:SI (match_operand:SI 1 "register_operand" " r, r") - (match_operand:SI 2 "nonmemory_operand" " Iu05, r")))] +(define_insn "*rotrsi3" + [(set (match_operand:SI 0 "register_operand" "= r, r") + (rotatert:SI (match_operand:SI 1 "register_operand" " r, r") + (match_operand:SI 2 "nds32_rimm5u_operand" " Iu05, r")))] "" "@ - rotri\t%0, %1, %2 - rotr\t%0, %1, %2" - [(set_attr "type" "alu,alu") - (set_attr "length" " 4, 4")]) + rotri\t%0, %1, %2 + rotr\t%0, %1, %2" + [(set_attr "type" " alu, alu") + (set_attr "subtype" "shift,shift") + (set_attr "length" " 4, 4")]) ;; ---------------------------------------------------------------------------- @@ -720,14 +901,95 @@ ;; And for V2 ISA, there is NO 'neg33' instruction. ;; The only option is to use 'subri A,B,0' (its semantic is 'A = 0 - B'). (define_insn "negsi2" - [(set (match_operand:SI 0 "register_operand" "=w, r") - (neg:SI (match_operand:SI 1 "register_operand" " w, r")))] + [(set (match_operand:SI 0 "register_operand" "=l, r") + (neg:SI (match_operand:SI 1 "register_operand" " l, r")))] "" "@ neg33\t%0, %1 subri\t%0, %1, 0" - [(set_attr "type" "alu,alu") - (set_attr "length" " 2, 4")]) + [(set_attr "type" "alu,alu") + (set_attr "length" " 2, 4") + (set_attr "feature" "v3m, v1")]) + +(define_expand "negsf2" + [(set (match_operand:SF 0 "register_operand" "") + (neg:SF (match_operand:SF 1 "register_operand" "")))] + "" +{ + if (!TARGET_FPU_SINGLE && !TARGET_EXT_PERF) + { + rtx new_dst = simplify_gen_subreg (SImode, operands[0], SFmode, 0); + rtx new_src = simplify_gen_subreg (SImode, operands[1], SFmode, 0); + + emit_insn (gen_xorsi3 (new_dst, + new_src, + gen_int_mode (0x80000000, SImode))); + + DONE; + } +}) + +(define_expand "negdf2" + [(set (match_operand:DF 0 "register_operand" "") + (neg:DF (match_operand:DF 1 "register_operand" "")))] + "" +{ +}) + +(define_insn_and_split "soft_negdf2" + [(set (match_operand:DF 0 "register_operand" "") + (neg:DF (match_operand:DF 1 "register_operand" "")))] + "!TARGET_FPU_DOUBLE" + "#" + "!TARGET_FPU_DOUBLE" + [(const_int 1)] +{ + rtx src = operands[1]; + rtx dst = operands[0]; + rtx ori_dst = operands[0]; + + bool need_extra_move_for_dst_p; + /* FPU register can't change mode to SI directly, so we need create a + tmp register to handle it, and FPU register can't do `xor` or btgl. */ + if (HARD_REGISTER_P (src) + && TEST_HARD_REG_BIT (reg_class_contents[FP_REGS], REGNO (src))) + { + rtx tmp = gen_reg_rtx (DFmode); + emit_move_insn (tmp, src); + src = tmp; + } + + if (HARD_REGISTER_P (dst) + && TEST_HARD_REG_BIT (reg_class_contents[FP_REGS], REGNO (dst))) + { + need_extra_move_for_dst_p = true; + rtx tmp = gen_reg_rtx (DFmode); + dst = tmp; + } + + rtx dst_high_part = simplify_gen_subreg ( + SImode, dst, + DFmode, subreg_highpart_offset (SImode, DFmode)); + rtx dst_low_part = simplify_gen_subreg ( + SImode, dst, + DFmode, subreg_lowpart_offset (SImode, DFmode)); + rtx src_high_part = simplify_gen_subreg ( + SImode, src, + DFmode, subreg_highpart_offset (SImode, DFmode)); + rtx src_low_part = simplify_gen_subreg ( + SImode, src, + DFmode, subreg_lowpart_offset (SImode, DFmode)); + + emit_insn (gen_xorsi3 (dst_high_part, + src_high_part, + gen_int_mode (0x80000000, SImode))); + emit_move_insn (dst_low_part, src_low_part); + + if (need_extra_move_for_dst_p) + emit_move_insn (ori_dst, dst); + + DONE; +}) ;; ---------------------------------------------------------------------------- @@ -737,55 +999,72 @@ ;; For V3/V3M ISA, we have 'not33' instruction. ;; So we can identify 'not Rt3,Ra3' case and set its length to be 2. (define_insn "one_cmplsi2" - [(set (match_operand:SI 0 "register_operand" "=w, r") - (not:SI (match_operand:SI 1 "register_operand" " w, r")))] + [(set (match_operand:SI 0 "register_operand" "=l, r") + (not:SI (match_operand:SI 1 "register_operand" " l, r")))] "" "@ not33\t%0, %1 nor\t%0, %1, %1" - [(set_attr "type" "alu,alu") - (set_attr "length" " 2, 4")]) + [(set_attr "type" "alu,alu") + (set_attr "length" " 2, 4") + (set_attr "feature" "v3m, v1")]) ;; ---------------------------------------------------------------------------- ;; Shift instructions. -(define_insn "ashlsi3" - [(set (match_operand:SI 0 "register_operand" "= l, r, r") - (ashift:SI (match_operand:SI 1 "register_operand" " l, r, r") - (match_operand:SI 2 "nonmemory_operand" " Iu03, Iu05, r")))] +(define_expand "si3" + [(set (match_operand:SI 0 "register_operand" "") + (shift_rotate:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nds32_rimm5u_operand" "")))] "" - "@ - slli333\t%0, %1, %2 - slli\t%0, %1, %2 - sll\t%0, %1, %2" - [(set_attr "type" "alu,alu,alu") - (set_attr "length" " 2, 4, 4")]) +{ + if (operands[2] == const0_rtx) + { + emit_move_insn (operands[0], operands[1]); + DONE; + } +}) -(define_insn "ashrsi3" - [(set (match_operand:SI 0 "register_operand" "= d, r, r") - (ashiftrt:SI (match_operand:SI 1 "register_operand" " 0, r, r") - (match_operand:SI 2 "nonmemory_operand" " Iu05, Iu05, r")))] +(define_insn "*ashlsi3" + [(set (match_operand:SI 0 "register_operand" "= l, r, r") + (ashift:SI (match_operand:SI 1 "register_operand" " l, r, r") + (match_operand:SI 2 "nds32_rimm5u_operand" " Iu03, Iu05, r")))] "" "@ - srai45\t%0, %2 - srai\t%0, %1, %2 - sra\t%0, %1, %2" - [(set_attr "type" "alu,alu,alu") - (set_attr "length" " 2, 4, 4")]) - -(define_insn "lshrsi3" - [(set (match_operand:SI 0 "register_operand" "= d, r, r") - (lshiftrt:SI (match_operand:SI 1 "register_operand" " 0, r, r") - (match_operand:SI 2 "nonmemory_operand" " Iu05, Iu05, r")))] + slli333\t%0, %1, %2 + slli\t%0, %1, %2 + sll\t%0, %1, %2" + [(set_attr "type" " alu, alu, alu") + (set_attr "subtype" "shift,shift,shift") + (set_attr "length" " 2, 4, 4")]) + +(define_insn "*ashrsi3" + [(set (match_operand:SI 0 "register_operand" "= d, r, r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" " 0, r, r") + (match_operand:SI 2 "nds32_rimm5u_operand" " Iu05, Iu05, r")))] + "" + "@ + srai45\t%0, %2 + srai\t%0, %1, %2 + sra\t%0, %1, %2" + [(set_attr "type" " alu, alu, alu") + (set_attr "subtype" "shift,shift,shift") + (set_attr "length" " 2, 4, 4")]) + +(define_insn "*lshrsi3" + [(set (match_operand:SI 0 "register_operand" "= d, r, r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" " 0, r, r") + (match_operand:SI 2 "nds32_rimm5u_operand" " Iu05, Iu05, r")))] "" "@ - srli45\t%0, %2 - srli\t%0, %1, %2 - srl\t%0, %1, %2" - [(set_attr "type" "alu,alu,alu") - (set_attr "length" " 2, 4, 4")]) + srli45\t%0, %2 + srli\t%0, %1, %2 + srl\t%0, %1, %2" + [(set_attr "type" " alu, alu, alu") + (set_attr "subtype" "shift,shift,shift") + (set_attr "length" " 2, 4, 4")]) ;; ---------------------------------------------------------------------------- @@ -794,148 +1073,65 @@ ;; Conditional Move patterns ;; ---------------------------------------------------------------------------- -(define_expand "movsicc" - [(set (match_operand:SI 0 "register_operand" "") - (if_then_else:SI (match_operand 1 "comparison_operator" "") - (match_operand:SI 2 "register_operand" "") - (match_operand:SI 3 "register_operand" "")))] - "TARGET_CMOV" +(define_expand "movcc" + [(set (match_operand:QIHISI 0 "register_operand" "") + (if_then_else:QIHISI (match_operand 1 "nds32_movecc_comparison_operator" "") + (match_operand:QIHISI 2 "register_operand" "") + (match_operand:QIHISI 3 "register_operand" "")))] + "TARGET_CMOV && !optimize_size" { - if ((GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE) - && GET_MODE (XEXP (operands[1], 0)) == SImode - && XEXP (operands[1], 1) == const0_rtx) - { - /* If the operands[1] rtx is already (eq X 0) or (ne X 0), - we have gcc generate original template rtx. */ - goto create_template; - } - else + enum nds32_expand_result_type result = nds32_expand_movcc (operands); + switch (result) { - /* Since there is only 'slt'(Set when Less Than) instruction for - comparison in Andes ISA, the major strategy we use here is to - convert conditional move into 'LT + EQ' or 'LT + NE' rtx combination. - We design constraints properly so that the reload phase will assist - to make one source operand to use same register as result operand. - Then we can use cmovz/cmovn to catch the other source operand - which has different register. */ - enum rtx_code code = GET_CODE (operands[1]); - enum rtx_code new_code = code; - rtx cmp_op0 = XEXP (operands[1], 0); - rtx cmp_op1 = XEXP (operands[1], 1); - rtx tmp; - int reverse = 0; - - /* Main Goal: Use 'LT + EQ' or 'LT + NE' to target "then" part - Strategy : Reverse condition and swap comparison operands - - For example: - - a <= b ? P : Q (LE or LEU) - --> a > b ? Q : P (reverse condition) - --> b < a ? Q : P (swap comparison operands to achieve 'LT/LTU') - - a >= b ? P : Q (GE or GEU) - --> a < b ? Q : P (reverse condition to achieve 'LT/LTU') - - a < b ? P : Q (LT or LTU) - --> (NO NEED TO CHANGE, it is already 'LT/LTU') - - a > b ? P : Q (GT or GTU) - --> b < a ? P : Q (swap comparison operands to achieve 'LT/LTU') */ - switch (code) - { - case NE: - /* (a != b ? P : Q) - can be expressed as - (a == b ? Q : P) - so, fall through to reverse condition */ - case GE: case GEU: case LE: case LEU: - new_code = reverse_condition (code); - reverse = 1; - break; - case EQ: case GT: case GTU: case LT: case LTU: - /* no need to reverse condition */ - break; - default: - FAIL; - } - - /* For '>' comparison operator, we swap operands - so that we can have 'LT/LTU' operator. */ - if (new_code == GT || new_code == GTU) - { - tmp = cmp_op0; - cmp_op0 = cmp_op1; - cmp_op1 = tmp; - - new_code = swap_condition (new_code); - } - - /* Use a temporary register to store slt/slts result. */ - tmp = gen_reg_rtx (SImode); - - /* Split EQ and NE because we don't have direct comparison of EQ and NE. - If we don't split it, the conditional move transformation will fail - when producing (SET A (EQ B C)) or (SET A (NE B C)). */ - if (new_code == EQ) - { - emit_insn (gen_xorsi3 (tmp, cmp_op0, cmp_op1)); - emit_insn (gen_slt_compare (tmp, tmp, GEN_INT (1))); - } - else if (new_code == NE) - { - emit_insn (gen_xorsi3 (tmp, cmp_op0, cmp_op1)); - emit_insn (gen_slt_compare (tmp, GEN_INT (0), tmp)); - } - else - /* This emit_insn will create corresponding 'slt/slts' insturction. */ - emit_insn (gen_rtx_SET (tmp, gen_rtx_fmt_ee (new_code, SImode, - cmp_op0, cmp_op1))); - - /* Change comparison semantic into (eq X 0) or (ne X 0) behavior - so that cmovz or cmovn will be matched later. - - For reverse condition cases, we want to create a semantic that: - (eq X 0) --> pick up "else" part - For normal cases, we want to create a semantic that: - (ne X 0) --> pick up "then" part - - Later we will have cmovz/cmovn instruction pattern to - match corresponding behavior and output instruction. */ - operands[1] = gen_rtx_fmt_ee (reverse ? EQ : NE, - VOIDmode, tmp, const0_rtx); + case EXPAND_DONE: + DONE; + break; + case EXPAND_FAIL: + FAIL; + break; + case EXPAND_CREATE_TEMPLATE: + break; + default: + gcc_unreachable (); } - -create_template: - do {} while(0); /* dummy line */ }) -(define_insn "cmovz" - [(set (match_operand:SI 0 "register_operand" "=r, r") - (if_then_else:SI (eq (match_operand:SI 1 "register_operand" " r, r") +(define_insn "cmovz" + [(set (match_operand:QIHISI 0 "register_operand" "=r, r") + (if_then_else:QIHISI (eq (match_operand:SI 1 "register_operand" " r, r") (const_int 0)) - (match_operand:SI 2 "register_operand" " r, 0") - (match_operand:SI 3 "register_operand" " 0, r")))] + (match_operand:QIHISI 2 "register_operand" " r, 0") + (match_operand:QIHISI 3 "register_operand" " 0, r")))] "TARGET_CMOV" "@ cmovz\t%0, %2, %1 cmovn\t%0, %3, %1" - [(set_attr "type" "move") + [(set_attr "type" "alu") (set_attr "length" "4")]) -(define_insn "cmovn" - [(set (match_operand:SI 0 "register_operand" "=r, r") - (if_then_else:SI (ne (match_operand:SI 1 "register_operand" " r, r") +(define_insn "cmovn" + [(set (match_operand:QIHISI 0 "register_operand" "=r, r") + (if_then_else:QIHISI (ne (match_operand:SI 1 "register_operand" " r, r") (const_int 0)) - (match_operand:SI 2 "register_operand" " r, 0") - (match_operand:SI 3 "register_operand" " 0, r")))] + (match_operand:QIHISI 2 "register_operand" " r, 0") + (match_operand:QIHISI 3 "register_operand" " 0, r")))] "TARGET_CMOV" "@ cmovn\t%0, %2, %1 cmovz\t%0, %3, %1" - [(set_attr "type" "move") + [(set_attr "type" "alu") (set_attr "length" "4")]) +;; A hotfix to help RTL combiner to merge a cmovn insn and a zero_extend insn. +;; It should be removed once after we change the expansion form of the cmovn. +(define_insn "*cmovn_simplified_" + [(set (match_operand:QIHISI 0 "register_operand" "=r") + (if_then_else:QIHISI (match_operand:SI 1 "register_operand" "r") + (match_operand:QIHISI 2 "register_operand" "r") + (match_operand:QIHISI 3 "register_operand" "0")))] + "" + "cmovn\t%0, %2, %1" + [(set_attr "type" "alu")]) ;; ---------------------------------------------------------------------------- ;; Conditional Branch patterns @@ -950,573 +1146,188 @@ create_template: (pc)))] "" { - rtx tmp_reg; - enum rtx_code code; - - code = GET_CODE (operands[0]); - - /* If operands[2] is (const_int 0), - we can use beqz,bnez,bgtz,bgez,bltz,or blez instructions. - So we have gcc generate original template rtx. */ - if (GET_CODE (operands[2]) == CONST_INT) - if (INTVAL (operands[2]) == 0) - if ((code != GTU) - && (code != GEU) - && (code != LTU) - && (code != LEU)) - goto create_template; - - /* For other comparison, NDS32 ISA only has slt (Set-on-Less-Than) - behavior for the comparison, we might need to generate other - rtx patterns to achieve same semantic. */ - switch (code) + enum nds32_expand_result_type result = nds32_expand_cbranch (operands); + switch (result) { - case GT: - case GTU: - if (GET_CODE (operands[2]) == CONST_INT) - { - /* GT reg_A, const_int => !(LT reg_A, const_int + 1) */ - tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); - - /* We want to plus 1 into the integer value - of operands[2] to create 'slt' instruction. - This caculation is performed on the host machine, - which may be 64-bit integer. - So the meaning of caculation result may be - different from the 32-bit nds32 target. - - For example: - 0x7fffffff + 0x1 -> 0x80000000, - this value is POSITIVE on 64-bit machine, - but the expected value on 32-bit nds32 target - should be NEGATIVE value. - - Hence, instead of using GEN_INT(), we use gen_int_mode() to - explicitly create SImode constant rtx. */ - operands[2] = gen_int_mode (INTVAL (operands[2]) + 1, SImode); - - if (code == GT) - { - /* GT, use slts instruction */ - emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2])); - } - else - { - /* GTU, use slt instruction */ - emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2])); - } - - PUT_CODE (operands[0], EQ); - operands[1] = tmp_reg; - operands[2] = const0_rtx; - emit_insn (gen_cbranchsi4 (operands[0], operands[1], - operands[2], operands[3])); - - DONE; - } - else - { - /* GT reg_A, reg_B => LT reg_B, reg_A */ - tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); - - if (code == GT) - { - /* GT, use slts instruction */ - emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1])); - } - else - { - /* GTU, use slt instruction */ - emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1])); - } - - PUT_CODE (operands[0], NE); - operands[1] = tmp_reg; - operands[2] = const0_rtx; - emit_insn (gen_cbranchsi4 (operands[0], operands[1], - operands[2], operands[3])); - - DONE; - } - - case GE: - case GEU: - /* GE reg_A, reg_B => !(LT reg_A, reg_B) */ - /* GE reg_A, const_int => !(LT reg_A, const_int) */ - tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); - - if (code == GE) - { - /* GE, use slts instruction */ - emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2])); - } - else - { - /* GEU, use slt instruction */ - emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2])); - } - - PUT_CODE (operands[0], EQ); - operands[1] = tmp_reg; - operands[2] = const0_rtx; - emit_insn (gen_cbranchsi4 (operands[0], operands[1], - operands[2], operands[3])); - + case EXPAND_DONE: DONE; - - case LT: - case LTU: - /* LT reg_A, reg_B => LT reg_A, reg_B */ - /* LT reg_A, const_int => LT reg_A, const_int */ - tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); - - if (code == LT) - { - /* LT, use slts instruction */ - emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2])); - } - else - { - /* LTU, use slt instruction */ - emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2])); - } - - PUT_CODE (operands[0], NE); - operands[1] = tmp_reg; - operands[2] = const0_rtx; - emit_insn (gen_cbranchsi4 (operands[0], operands[1], - operands[2], operands[3])); - - DONE; - - case LE: - case LEU: - if (GET_CODE (operands[2]) == CONST_INT) - { - /* LE reg_A, const_int => LT reg_A, const_int + 1 */ - tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); - - /* Note that (le:SI X INT_MAX) is not the same as (lt:SI X INT_MIN). - We better have an assert here in case GCC does not properly - optimize it away. The INT_MAX here is 0x7fffffff for target. */ - gcc_assert (code != LE || INTVAL (operands[2]) != 0x7fffffff); - operands[2] = gen_int_mode (INTVAL (operands[2]) + 1, SImode); - - if (code == LE) - { - /* LE, use slts instruction */ - emit_insn (gen_slts_compare (tmp_reg, operands[1], operands[2])); - } - else - { - /* LEU, use slt instruction */ - emit_insn (gen_slt_compare (tmp_reg, operands[1], operands[2])); - } - - PUT_CODE (operands[0], NE); - operands[1] = tmp_reg; - operands[2] = const0_rtx; - emit_insn (gen_cbranchsi4 (operands[0], operands[1], - operands[2], operands[3])); - - DONE; - } - else - { - /* LE reg_A, reg_B => !(LT reg_B, reg_A) */ - tmp_reg = gen_rtx_REG (SImode, TA_REGNUM); - - if (code == LE) - { - /* LE, use slts instruction */ - emit_insn (gen_slts_compare (tmp_reg, operands[2], operands[1])); - } - else - { - /* LEU, use slt instruction */ - emit_insn (gen_slt_compare (tmp_reg, operands[2], operands[1])); - } - - PUT_CODE (operands[0], EQ); - operands[1] = tmp_reg; - operands[2] = const0_rtx; - emit_insn (gen_cbranchsi4 (operands[0], operands[1], - operands[2], operands[3])); - - DONE; - } - - case EQ: - case NE: - /* NDS32 ISA has various form for eq/ne behavior no matter - what kind of the operand is. - So just generate original template rtx. */ - goto create_template; - - default: + break; + case EXPAND_FAIL: FAIL; + break; + case EXPAND_CREATE_TEMPLATE: + break; + default: + gcc_unreachable (); } - -create_template: - do {} while(0); /* dummy line */ }) -(define_insn "*cbranchsi4_equality_zero" +(define_insn "cbranchsi4_equality_zero" [(set (pc) (if_then_else (match_operator 0 "nds32_equality_comparison_operator" - [(match_operand:SI 1 "register_operand" "t, l, r") + [(match_operand:SI 1 "register_operand" "t,l, r") (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc)))] "" { - enum rtx_code code; - - code = GET_CODE (operands[0]); - - /* This zero-comparison conditional branch has two forms: - 32-bit instruction => beqz/bnez imm16s << 1 - 16-bit instruction => beqzs8/bnezs8/beqz38/bnez38 imm8s << 1 - - For 32-bit case, - we assume it is always reachable. (but check range -65500 ~ 65500) - - For 16-bit case, - it must satisfy { 255 >= (label - pc) >= -256 } condition. - However, since the $pc for nds32 is at the beginning of the instruction, - we should leave some length space for current insn. - So we use range -250 ~ 250. */ - - switch (get_attr_length (insn)) - { - case 2: - if (which_alternative == 0) - { - /* constraint: t */ - return (code == EQ) ? "beqzs8\t%2" : "bnezs8\t%2"; - } - else if (which_alternative == 1) - { - /* constraint: l */ - return (code == EQ) ? "beqz38\t%1, %2" : "bnez38\t%1, %2"; - } - else - { - /* constraint: r */ - /* For which_alternative==2, it should not be here. */ - gcc_unreachable (); - } - case 4: - /* including constraints: t, l, and r */ - return (code == EQ) ? "beqz\t%1, %2" : "bnez\t%1, %2"; - case 6: - if (which_alternative == 0) - { - /* constraint: t */ - if (code == EQ) - { - /* beqzs8 .L0 - => - bnezs8 .LCB0 - j .L0 - .LCB0: - */ - return "bnezs8\t.LCB%=\;j\t%2\n.LCB%=:"; - } - else - { - /* bnezs8 .L0 - => - beqzs8 .LCB0 - j .L0 - .LCB0: - */ - return "beqzs8\t.LCB%=\;j\t%2\n.LCB%=:"; - } - } - else if (which_alternative == 1) - { - /* constraint: l */ - if (code == EQ) - { - /* beqz38 $r0, .L0 - => - bnez38 $r0, .LCB0 - j .L0 - .LCB0: - */ - return "bnez38\t%1, .LCB%=\;j\t%2\n.LCB%=:"; - } - else - { - /* bnez38 $r0, .L0 - => - beqz38 $r0, .LCB0 - j .L0 - .LCB0: - */ - return "beqz38\t%1, .LCB%=\;j\t%2\n.LCB%=:"; - } - } - else - { - /* constraint: r */ - /* For which_alternative==2, it should not be here. */ - gcc_unreachable (); - } - case 8: - /* constraint: t, l, r. */ - if (code == EQ) - { - /* beqz $r8, .L0 - => - bnez $r8, .LCB0 - j .L0 - .LCB0: - */ - return "bnez\t%1, .LCB%=\;j\t%2\n.LCB%=:"; - } - else - { - /* bnez $r8, .L0 - => - beqz $r8, .LCB0 - j .L0 - .LCB0: - */ - return "beqz\t%1, .LCB%=\;j\t%2\n.LCB%=:"; - } - default: - gcc_unreachable (); - } + return nds32_output_cbranchsi4_equality_zero (insn, operands); } [(set_attr "type" "branch") - (set_attr "enabled" "1") + (set_attr_alternative "enabled" + [ + ;; Alternative 0 + (if_then_else (match_test "TARGET_16_BIT") + (const_string "yes") + (const_string "no")) + ;; Alternative 1 + (if_then_else (match_test "TARGET_16_BIT") + (const_string "yes") + (const_string "no")) + ;; Alternative 2 + (const_string "yes") + ]) (set_attr_alternative "length" [ ;; Alternative 0 - (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -250)) - (le (minus (match_dup 2) (pc)) (const_int 250))) - (if_then_else (match_test "TARGET_16_BIT") - (const_int 2) - (const_int 4)) - (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500)) - (le (minus (match_dup 2) (pc)) (const_int 65500))) - (const_int 4) + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") + (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -250)) + (le (minus (match_dup 2) (pc)) (const_int 250))) (if_then_else (match_test "TARGET_16_BIT") - (const_int 6) - (const_int 8)))) + (const_int 2) + (const_int 4)) + (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500)) + (le (minus (match_dup 2) (pc)) (const_int 65500))) + (const_int 4) + (if_then_else (match_test "TARGET_16_BIT") + (const_int 8) + (const_int 10)))) + (const_int 10)) ;; Alternative 1 - (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -250)) - (le (minus (match_dup 2) (pc)) (const_int 250))) - (if_then_else (match_test "TARGET_16_BIT") - (const_int 2) - (const_int 4)) + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") + (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -250)) + (le (minus (match_dup 2) (pc)) (const_int 250))) + (if_then_else (match_test "TARGET_16_BIT") + (const_int 2) + (const_int 4)) + (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500)) + (le (minus (match_dup 2) (pc)) (const_int 65500))) + (const_int 4) + (if_then_else (match_test "TARGET_16_BIT") + (const_int 8) + (const_int 10)))) + (const_int 10)) + ;; Alternative 2 + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500)) (le (minus (match_dup 2) (pc)) (const_int 65500))) (const_int 4) - (if_then_else (match_test "TARGET_16_BIT") - (const_int 6) - (const_int 8)))) - ;; Alternative 2 - (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500)) - (le (minus (match_dup 2) (pc)) (const_int 65500))) - (const_int 4) - (const_int 8)) + (const_int 10)) + (const_int 10)) ])]) ;; This pattern is dedicated to V2 ISA, ;; because V2 DOES NOT HAVE beqc/bnec instruction. -(define_insn "*cbranchsi4_equality_reg" +(define_insn "cbranchsi4_equality_reg" [(set (pc) (if_then_else (match_operator 0 "nds32_equality_comparison_operator" - [(match_operand:SI 1 "register_operand" "r") - (match_operand:SI 2 "nds32_reg_constant_operand" "r")]) + [(match_operand:SI 1 "register_operand" "v, r") + (match_operand:SI 2 "register_operand" "l, r")]) (label_ref (match_operand 3 "" "")) (pc)))] "TARGET_ISA_V2" { - enum rtx_code code; - - code = GET_CODE (operands[0]); - - /* This register-comparison conditional branch has one form: - 32-bit instruction => beq/bne imm14s << 1 - - For 32-bit case, - we assume it is always reachable. (but check range -16350 ~ 16350). */ - - switch (code) - { - case EQ: - /* r, r */ - switch (get_attr_length (insn)) - { - case 4: - return "beq\t%1, %2, %3"; - case 8: - /* beq $r0, $r1, .L0 - => - bne $r0, $r1, .LCB0 - j .L0 - .LCB0: - */ - return "bne\t%1, %2, .LCB%=\;j\t%3\n.LCB%=:"; - default: - gcc_unreachable (); - } - - case NE: - /* r, r */ - switch (get_attr_length (insn)) - { - case 4: - return "bne\t%1, %2, %3"; - case 8: - /* bne $r0, $r1, .L0 - => - beq $r0, $r1, .LCB0 - j .L0 - .LCB0: - */ - return "beq\t%1, %2, .LCB%=\;j\t%3\n.LCB%=:"; - default: - gcc_unreachable (); - } - - default: - gcc_unreachable (); - } + return nds32_output_cbranchsi4_equality_reg (insn, operands); } [(set_attr "type" "branch") - (set (attr "length") - (if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -16350)) - (le (minus (match_dup 3) (pc)) (const_int 16350))) - (const_int 4) - (const_int 8)))]) + (set_attr_alternative "enabled" + [ + ;; Alternative 0 + (if_then_else (match_test "TARGET_16_BIT") + (const_string "yes") + (const_string "no")) + ;; Alternative 1 + (const_string "yes") + ]) + (set_attr_alternative "length" + [ + ;; Alternative 0 + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") + (if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -250)) + (le (minus (match_dup 3) (pc)) (const_int 250))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 3) (pc)) + (const_int -16350)) + (le (minus (match_dup 3) (pc)) + (const_int 16350))) + (const_int 4) + (const_int 8))) + (const_int 8)) + ;; Alternative 1 + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") + (if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -16350)) + (le (minus (match_dup 3) (pc)) (const_int 16350))) + (const_int 4) + (const_int 10)) + (const_int 10)) + ])]) ;; This pattern is dedicated to V3/V3M, ;; because V3/V3M DO HAVE beqc/bnec instruction. -(define_insn "*cbranchsi4_equality_reg_or_const_int" +(define_insn "cbranchsi4_equality_reg_or_const_int" [(set (pc) (if_then_else (match_operator 0 "nds32_equality_comparison_operator" - [(match_operand:SI 1 "register_operand" "r, r") - (match_operand:SI 2 "nds32_reg_constant_operand" "r, Is11")]) + [(match_operand:SI 1 "register_operand" "v, r, r") + (match_operand:SI 2 "nds32_rimm11s_operand" "l, r, Is11")]) (label_ref (match_operand 3 "" "")) (pc)))] "TARGET_ISA_V3 || TARGET_ISA_V3M" { - enum rtx_code code; - - code = GET_CODE (operands[0]); - - /* This register-comparison conditional branch has one form: - 32-bit instruction => beq/bne imm14s << 1 - 32-bit instruction => beqc/bnec imm8s << 1 - - For 32-bit case, we assume it is always reachable. - (but check range -16350 ~ 16350 and -250 ~ 250). */ - - switch (code) - { - case EQ: - if (which_alternative == 0) - { - /* r, r */ - switch (get_attr_length (insn)) - { - case 4: - return "beq\t%1, %2, %3"; - case 8: - /* beq $r0, $r1, .L0 - => - bne $r0, $r1, .LCB0 - j .L0 - .LCB0: - */ - return "bne\t%1, %2, .LCB%=\;j\t%3\n.LCB%=:"; - default: - gcc_unreachable (); - } - } - else - { - /* r, Is11 */ - switch (get_attr_length (insn)) - { - case 4: - return "beqc\t%1, %2, %3"; - case 8: - /* beqc $r0, constant, .L0 - => - bnec $r0, constant, .LCB0 - j .L0 - .LCB0: - */ - return "bnec\t%1, %2, .LCB%=\;j\t%3\n.LCB%=:"; - default: - gcc_unreachable (); - } - } - case NE: - if (which_alternative == 0) - { - /* r, r */ - switch (get_attr_length (insn)) - { - case 4: - return "bne\t%1, %2, %3"; - case 8: - /* bne $r0, $r1, .L0 - => - beq $r0, $r1, .LCB0 - j .L0 - .LCB0: - */ - return "beq\t%1, %2, .LCB%=\;j\t%3\n.LCB%=:"; - default: - gcc_unreachable (); - } - } - else - { - /* r, Is11 */ - switch (get_attr_length (insn)) - { - case 4: - return "bnec\t%1, %2, %3"; - case 8: - /* bnec $r0, constant, .L0 - => - beqc $r0, constant, .LCB0 - j .L0 - .LCB0: - */ - return "beqc\t%1, %2, .LCB%=\;j\t%3\n.LCB%=:"; - default: - gcc_unreachable (); - } - } - default: - gcc_unreachable (); - } + return nds32_output_cbranchsi4_equality_reg_or_const_int (insn, operands); } [(set_attr "type" "branch") + (set_attr_alternative "enabled" + [ + ;; Alternative 0 + (if_then_else (match_test "TARGET_16_BIT") + (const_string "yes") + (const_string "no")) + ;; Alternative 1 + (const_string "yes") + ;; Alternative 2 + (const_string "yes") + ]) (set_attr_alternative "length" [ ;; Alternative 0 - (if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -16350)) - (le (minus (match_dup 3) (pc)) (const_int 16350))) - (const_int 4) - (const_int 8)) + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") + (if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -250)) + (le (minus (match_dup 3) (pc)) (const_int 250))) + (const_int 2) + (if_then_else (and (ge (minus (match_dup 3) (pc)) + (const_int -16350)) + (le (minus (match_dup 3) (pc)) + (const_int 16350))) + (const_int 4) + (const_int 8))) + (const_int 8)) ;; Alternative 1 - (if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -250)) - (le (minus (match_dup 3) (pc)) (const_int 250))) - (const_int 4) - (const_int 8)) + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") + (if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -16350)) + (le (minus (match_dup 3) (pc)) (const_int 16350))) + (const_int 4) + (const_int 10)) + (const_int 10)) + ;; Alternative 2 + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") + (if_then_else (and (ge (minus (match_dup 3) (pc)) (const_int -250)) + (le (minus (match_dup 3) (pc)) (const_int 250))) + (const_int 4) + (const_int 10)) + (const_int 10)) ])]) @@ -1529,80 +1340,16 @@ create_template: (pc)))] "" { - enum rtx_code code; - - code = GET_CODE (operands[0]); - - /* This zero-greater-less-comparison conditional branch has one form: - 32-bit instruction => bgtz/bgez/bltz/blez imm16s << 1 - - For 32-bit case, we assume it is always reachable. - (but check range -65500 ~ 65500). */ - - if (get_attr_length (insn) == 8) - { - /* The branch target is too far to simply use one - bgtz/bgez/bltz/blez instruction. - We need to reverse condition and use 'j' to jump to the target. */ - switch (code) - { - case GT: - /* bgtz $r8, .L0 - => - blez $r8, .LCB0 - j .L0 - .LCB0: - */ - return "blez\t%1, .LCB%=\;j\t%2\n.LCB%=:"; - case GE: - /* bgez $r8, .L0 - => - bltz $r8, .LCB0 - j .L0 - .LCB0: - */ - return "bltz\t%1, .LCB%=\;j\t%2\n.LCB%=:"; - case LT: - /* bltz $r8, .L0 - => - bgez $r8, .LCB0 - j .L0 - .LCB0: - */ - return "bgez\t%1, .LCB%=\;j\t%2\n.LCB%=:"; - case LE: - /* blez $r8, .L0 - => - bgtz $r8, .LCB0 - j .L0 - .LCB0: - */ - return "bgtz\t%1, .LCB%=\;j\t%2\n.LCB%=:"; - default: - gcc_unreachable (); - } - } - - switch (code) - { - case GT: - return "bgtz\t%1, %2"; - case GE: - return "bgez\t%1, %2"; - case LT: - return "bltz\t%1, %2"; - case LE: - return "blez\t%1, %2"; - default: - gcc_unreachable (); - } + return nds32_output_cbranchsi4_greater_less_zero (insn, operands); } [(set_attr "type" "branch") (set (attr "length") - (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500)) - (le (minus (match_dup 2) (pc)) (const_int 65500))) - (const_int 4) - (const_int 8)))]) + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") + (if_then_else (and (ge (minus (match_dup 2) (pc)) (const_int -65500)) + (le (minus (match_dup 2) (pc)) (const_int 65500))) + (const_int 4) + (const_int 10)) + (const_int 10)))]) (define_expand "cstoresi4" @@ -1612,237 +1359,85 @@ create_template: (match_operand:SI 3 "nonmemory_operand" "")]))] "" { - rtx tmp_reg; - enum rtx_code code; - - code = GET_CODE (operands[1]); - - switch (code) + enum nds32_expand_result_type result = nds32_expand_cstore (operands); + switch (result) { - case EQ: - if (GET_CODE (operands[3]) == CONST_INT) - { - /* reg_R = (reg_A == const_int_B) - --> addi reg_C, reg_A, -const_int_B - slti reg_R, reg_C, const_int_1 */ - tmp_reg = gen_reg_rtx (SImode); - operands[3] = gen_int_mode (-INTVAL (operands[3]), SImode); - /* If the integer value is not in the range of imm15s, - we need to force register first because our addsi3 pattern - only accept nds32_rimm15s_operand predicate. */ - if (!satisfies_constraint_Is15 (operands[3])) - operands[3] = force_reg (SImode, operands[3]); - emit_insn (gen_addsi3 (tmp_reg, operands[2], operands[3])); - emit_insn (gen_slt_compare (operands[0], tmp_reg, const1_rtx)); - - DONE; - } - else - { - /* reg_R = (reg_A == reg_B) - --> xor reg_C, reg_A, reg_B - slti reg_R, reg_C, const_int_1 */ - tmp_reg = gen_reg_rtx (SImode); - emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3])); - emit_insn (gen_slt_compare (operands[0], tmp_reg, const1_rtx)); - - DONE; - } - - case NE: - if (GET_CODE (operands[3]) == CONST_INT) - { - /* reg_R = (reg_A != const_int_B) - --> addi reg_C, reg_A, -const_int_B - slti reg_R, const_int_0, reg_C */ - tmp_reg = gen_reg_rtx (SImode); - operands[3] = gen_int_mode (-INTVAL (operands[3]), SImode); - /* If the integer value is not in the range of imm15s, - we need to force register first because our addsi3 pattern - only accept nds32_rimm15s_operand predicate. */ - if (!satisfies_constraint_Is15 (operands[3])) - operands[3] = force_reg (SImode, operands[3]); - emit_insn (gen_addsi3 (tmp_reg, operands[2], operands[3])); - emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg)); - - DONE; - } - else - { - /* reg_R = (reg_A != reg_B) - --> xor reg_C, reg_A, reg_B - slti reg_R, const_int_0, reg_C */ - tmp_reg = gen_reg_rtx (SImode); - emit_insn (gen_xorsi3 (tmp_reg, operands[2], operands[3])); - emit_insn (gen_slt_compare (operands[0], const0_rtx, tmp_reg)); - - DONE; - } - - case GT: - case GTU: - /* reg_R = (reg_A > reg_B) --> slt reg_R, reg_B, reg_A */ - /* reg_R = (reg_A > const_int_B) --> slt reg_R, const_int_B, reg_A */ - if (code == GT) - { - /* GT, use slts instruction */ - emit_insn (gen_slts_compare (operands[0], operands[3], operands[2])); - } - else - { - /* GTU, use slt instruction */ - emit_insn (gen_slt_compare (operands[0], operands[3], operands[2])); - } - + case EXPAND_DONE: DONE; - - case GE: - case GEU: - if (GET_CODE (operands[3]) == CONST_INT) - { - /* reg_R = (reg_A >= const_int_B) - --> movi reg_C, const_int_B - 1 - slt reg_R, reg_C, reg_A */ - tmp_reg = gen_reg_rtx (SImode); - - emit_insn (gen_movsi (tmp_reg, - gen_int_mode (INTVAL (operands[3]) - 1, - SImode))); - if (code == GE) - { - /* GE, use slts instruction */ - emit_insn (gen_slts_compare (operands[0], tmp_reg, operands[2])); - } - else - { - /* GEU, use slt instruction */ - emit_insn (gen_slt_compare (operands[0], tmp_reg, operands[2])); - } - - DONE; - } - else - { - /* reg_R = (reg_A >= reg_B) - --> slt reg_R, reg_A, reg_B - xori reg_R, reg_R, const_int_1 */ - if (code == GE) - { - /* GE, use slts instruction */ - emit_insn (gen_slts_compare (operands[0], - operands[2], operands[3])); - } - else - { - /* GEU, use slt instruction */ - emit_insn (gen_slt_compare (operands[0], - operands[2], operands[3])); - } - - /* perform 'not' behavior */ - emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx)); - - DONE; - } - - case LT: - case LTU: - /* reg_R = (reg_A < reg_B) --> slt reg_R, reg_A, reg_B */ - /* reg_R = (reg_A < const_int_B) --> slt reg_R, reg_A, const_int_B */ - if (code == LT) - { - /* LT, use slts instruction */ - emit_insn (gen_slts_compare (operands[0], operands[2], operands[3])); - } - else - { - /* LTU, use slt instruction */ - emit_insn (gen_slt_compare (operands[0], operands[2], operands[3])); - } - - DONE; - - case LE: - case LEU: - if (GET_CODE (operands[3]) == CONST_INT) - { - /* reg_R = (reg_A <= const_int_B) - --> movi reg_C, const_int_B + 1 - slt reg_R, reg_A, reg_C */ - tmp_reg = gen_reg_rtx (SImode); - - emit_insn (gen_movsi (tmp_reg, - gen_int_mode (INTVAL (operands[3]) + 1, - SImode))); - if (code == LE) - { - /* LE, use slts instruction */ - emit_insn (gen_slts_compare (operands[0], operands[2], tmp_reg)); - } - else - { - /* LEU, use slt instruction */ - emit_insn (gen_slt_compare (operands[0], operands[2], tmp_reg)); - } - - DONE; - } - else - { - /* reg_R = (reg_A <= reg_B) --> slt reg_R, reg_B, reg_A - xori reg_R, reg_R, const_int_1 */ - if (code == LE) - { - /* LE, use slts instruction */ - emit_insn (gen_slts_compare (operands[0], - operands[3], operands[2])); - } - else - { - /* LEU, use slt instruction */ - emit_insn (gen_slt_compare (operands[0], - operands[3], operands[2])); - } - - /* perform 'not' behavior */ - emit_insn (gen_xorsi3 (operands[0], operands[0], const1_rtx)); - - DONE; - } - - + break; + case EXPAND_FAIL: + FAIL; + break; + case EXPAND_CREATE_TEMPLATE: + break; default: gcc_unreachable (); } }) -(define_insn "slts_compare" - [(set (match_operand:SI 0 "register_operand" "=t, t, r, r") - (lt:SI (match_operand:SI 1 "nonmemory_operand" " d, d, r, r") - (match_operand:SI 2 "nonmemory_operand" " r, Iu05, r, Is15")))] +(define_expand "slts_compare" + [(set (match_operand:SI 0 "register_operand" "") + (lt:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" +{ + if (!REG_P (operands[1])) + operands[1] = force_reg (SImode, operands[1]); + + if (!REG_P (operands[2]) && !satisfies_constraint_Is15 (operands[2])) + operands[2] = force_reg (SImode, operands[2]); +}) + +(define_insn "slts_compare_impl" + [(set (match_operand:SI 0 "register_operand" "=t, t, r, r") + (lt:SI (match_operand:SI 1 "register_operand" " d, d, r, r") + (match_operand:SI 2 "nds32_rimm15s_operand" " r,Iu05, r, Is15")))] "" "@ slts45\t%1, %2 sltsi45\t%1, %2 slts\t%0, %1, %2 sltsi\t%0, %1, %2" - [(set_attr "type" "compare,compare,compare,compare") - (set_attr "length" " 2, 2, 4, 4")]) + [(set_attr "type" "alu, alu, alu, alu") + (set_attr "length" " 2, 2, 4, 4")]) + +(define_insn "slt_eq0" + [(set (match_operand:SI 0 "register_operand" "=t, r") + (eq:SI (match_operand:SI 1 "register_operand" " d, r") + (const_int 0)))] + "" + "@ + slti45\t%1, 1 + slti\t%0, %1, 1" + [(set_attr "type" "alu, alu") + (set_attr "length" " 2, 4")]) + +(define_expand "slt_compare" + [(set (match_operand:SI 0 "register_operand" "") + (ltu:SI (match_operand:SI 1 "general_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" +{ + if (!REG_P (operands[1])) + operands[1] = force_reg (SImode, operands[1]); -(define_insn "slt_compare" - [(set (match_operand:SI 0 "register_operand" "=t, t, r, r") - (ltu:SI (match_operand:SI 1 "nonmemory_operand" " d, d, r, r") - (match_operand:SI 2 "nonmemory_operand" " r, Iu05, r, Is15")))] + if (!REG_P (operands[2]) && !satisfies_constraint_Is15 (operands[2])) + operands[2] = force_reg (SImode, operands[2]); +}) + +(define_insn "slt_compare_impl" + [(set (match_operand:SI 0 "register_operand" "=t, t, r, r") + (ltu:SI (match_operand:SI 1 "register_operand" " d, d, r, r") + (match_operand:SI 2 "nds32_rimm15s_operand" " r,Iu05, r, Is15")))] "" "@ slt45\t%1, %2 slti45\t%1, %2 slt\t%0, %1, %2 slti\t%0, %1, %2" - [(set_attr "type" "compare,compare,compare,compare") - (set_attr "length" " 2, 2, 4, 4")]) - + [(set_attr "type" "alu, alu, alu, alu") + (set_attr "length" " 2, 2, 4, 4")]) ;; ---------------------------------------------------------------------------- @@ -1874,12 +1469,14 @@ create_template: } } [(set_attr "type" "branch") - (set_attr "enabled" "1") + (set_attr "enabled" "yes") (set (attr "length") - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -250)) - (le (minus (match_dup 0) (pc)) (const_int 250))) - (if_then_else (match_test "TARGET_16_BIT") - (const_int 2) + (if_then_else (match_test "!CROSSING_JUMP_P (insn)") + (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -250)) + (le (minus (match_dup 0) (pc)) (const_int 250))) + (if_then_else (match_test "TARGET_16_BIT") + (const_int 2) + (const_int 4)) (const_int 4)) (const_int 4)))]) @@ -1887,14 +1484,27 @@ create_template: [(set (pc) (match_operand:SI 0 "register_operand" "r, r"))] "" "@ - jr5\t%0 - jr\t%0" + jr5\t%0 + jr\t%0" [(set_attr "type" "branch,branch") (set_attr "length" " 2, 4")]) +(define_insn "*cond_indirect_jump" + [(cond_exec (ne (match_operand:SI 0 "register_operand" "r") + (const_int 0)) + (set (pc) (match_operand:SI 1 "register_operand" "0")))] + "" + "jrnez\t%0" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +;; ---------------------------------------------------------------------------- + +;; Normal call patterns. + ;; Subroutine call instruction returning no value. ;; operands[0]: It should be a mem RTX whose address is -;; the address of the function. +;; the the address of the function. ;; operands[1]: It is the number of bytes of arguments pushed as a const_int. ;; operands[2]: It is the number of registers used as operands. @@ -1904,39 +1514,114 @@ create_template: (clobber (reg:SI LP_REGNUM)) (clobber (reg:SI TA_REGNUM))])] "" - "" + { + rtx insn; + rtx sym = XEXP (operands[0], 0); + + if (TARGET_ICT_MODEL_LARGE + && nds32_indirect_call_referenced_p (sym)) + { + rtx reg = gen_reg_rtx (Pmode); + emit_move_insn (reg, sym); + operands[0] = gen_const_mem (Pmode, reg); + } + + if (flag_pic) + { + insn = emit_call_insn (gen_call_internal + (XEXP (operands[0], 0), GEN_INT (0))); + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx); + DONE; + } + } ) -(define_insn "*call_register" - [(parallel [(call (mem (match_operand:SI 0 "register_operand" "r, r")) - (match_operand 1)) - (clobber (reg:SI LP_REGNUM)) - (clobber (reg:SI TA_REGNUM))])] - "" - "@ - jral5\t%0 - jral\t%0" - [(set_attr "type" "branch,branch") - (set_attr "length" " 2, 4")]) - -(define_insn "*call_immediate" - [(parallel [(call (mem (match_operand:SI 0 "immediate_operand" "i")) +(define_insn "call_internal" + [(parallel [(call (mem (match_operand:SI 0 "nds32_call_address_operand" "r, i")) (match_operand 1)) (clobber (reg:SI LP_REGNUM)) (clobber (reg:SI TA_REGNUM))])] "" { - if (TARGET_CMODEL_LARGE) - return "bal\t%0"; - else - return "jal\t%0"; + rtx_insn *next_insn = next_active_insn (insn); + bool align_p = (!(next_insn && get_attr_length (next_insn) == 2)) + && NDS32_ALIGN_P (); + switch (which_alternative) + { + case 0: + if (TARGET_16_BIT) + { + if (align_p) + return "jral5\t%0\;.align 2"; + else + return "jral5\t%0"; + } + else + { + if (align_p) + return "jral\t%0\;.align 2"; + else + return "jral\t%0"; + } + case 1: + return nds32_output_call (insn, operands, operands[0], + "bal\t%0", "jal\t%0", align_p); + default: + gcc_unreachable (); + } } - [(set_attr "type" "branch") - (set (attr "length") - (if_then_else (match_test "TARGET_CMODEL_LARGE") - (const_int 12) - (const_int 4)))]) + [(set_attr "enabled" "yes") + (set_attr "type" "branch") + (set_attr_alternative "length" + [ + ;; Alternative 0 + (if_then_else (match_test "TARGET_16_BIT") + (const_int 2) + (const_int 4)) + ;; Alternative 1 + (if_then_else (match_test "flag_pic") + (const_int 16) + (if_then_else (match_test "nds32_long_call_p (operands[0])") + (const_int 12) + (const_int 4))) + ])] +) +(define_insn "*cond_call_register" + [(cond_exec (ne (match_operand:SI 0 "register_operand" "r") + (const_int 0)) + (parallel [(call (mem (match_operand:SI 1 "register_operand" "0")) + (match_operand 2)) + (clobber (reg:SI LP_REGNUM)) + (clobber (reg:SI TA_REGNUM))]))] + "TARGET_ISA_V3" + "jralnez\t%0" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*cond_call_immediate" + [(cond_exec (match_operator 0 "nds32_conditional_call_comparison_operator" + [(match_operand:SI 1 "register_operand" "r") + (const_int 0)]) + (parallel [(call (mem (match_operand:SI 2 "nds32_symbolic_operand" "i")) + (match_operand 3)) + (clobber (reg:SI LP_REGNUM)) + (clobber (reg:SI TA_REGNUM))]))] + "!flag_pic && !TARGET_CMODEL_LARGE + && nds32_indirect_call_referenced_p (operands[2])" +{ + switch (GET_CODE (operands[0])) + { + case LT: + return "bltzal\t%1, %2"; + case GE: + return "bgezal\t%1, %2"; + default: + gcc_unreachable (); + } +} + [(set_attr "type" "branch") + (set_attr "length" "4")]) ;; Subroutine call instruction returning a value. ;; operands[0]: It is the hard regiser in which the value is returned. @@ -1951,49 +1636,152 @@ create_template: (clobber (reg:SI LP_REGNUM)) (clobber (reg:SI TA_REGNUM))])] "" - "" + { + rtx insn; + rtx sym = XEXP (operands[1], 0); + + if (TARGET_ICT_MODEL_LARGE + && nds32_indirect_call_referenced_p (sym)) + { + rtx reg = gen_reg_rtx (Pmode); + emit_move_insn (reg, sym); + operands[1] = gen_const_mem (Pmode, reg); + } + + if (flag_pic) + { + insn = + emit_call_insn (gen_call_value_internal + (operands[0], XEXP (operands[1], 0), GEN_INT (0))); + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx); + DONE; + } + } ) -(define_insn "*call_value_register" +(define_insn "call_value_internal" [(parallel [(set (match_operand 0) - (call (mem (match_operand:SI 1 "register_operand" "r, r")) + (call (mem (match_operand:SI 1 "nds32_call_address_operand" "r, i")) (match_operand 2))) (clobber (reg:SI LP_REGNUM)) (clobber (reg:SI TA_REGNUM))])] "" - "@ - jral5\t%1 - jral\t%1" - [(set_attr "type" "branch,branch") - (set_attr "length" " 2, 4")]) - -(define_insn "*call_value_immediate" - [(parallel [(set (match_operand 0) - (call (mem (match_operand:SI 1 "immediate_operand" "i")) - (match_operand 2))) - (clobber (reg:SI LP_REGNUM)) - (clobber (reg:SI TA_REGNUM))])] - "" { - if (TARGET_CMODEL_LARGE) - return "bal\t%1"; - else - return "jal\t%1"; + rtx_insn *next_insn = next_active_insn (insn); + bool align_p = (!(next_insn && get_attr_length (next_insn) == 2)) + && NDS32_ALIGN_P (); + switch (which_alternative) + { + case 0: + if (TARGET_16_BIT) + { + if (align_p) + return "jral5\t%1\;.align 2"; + else + return "jral5\t%1"; + } + else + { + if (align_p) + return "jral\t%1\;.align 2"; + else + return "jral\t%1"; + } + case 1: + return nds32_output_call (insn, operands, operands[1], + "bal\t%1", "jal\t%1", align_p); + default: + gcc_unreachable (); + } +} + [(set_attr "enabled" "yes") + (set_attr "type" "branch") + (set_attr_alternative "length" + [ + ;; Alternative 0 + (if_then_else (match_test "TARGET_16_BIT") + (const_int 2) + (const_int 4)) + ;; Alternative 1 + (if_then_else (match_test "flag_pic") + (const_int 16) + (if_then_else (match_test "nds32_long_call_p (operands[1])") + (const_int 12) + (const_int 4))) + ])] +) + +(define_insn "*cond_call_value_register" + [(cond_exec (ne (match_operand:SI 0 "register_operand" "r") + (const_int 0)) + (parallel [(set (match_operand 1) + (call (mem (match_operand:SI 2 "register_operand" "0")) + (match_operand 3))) + (clobber (reg:SI LP_REGNUM)) + (clobber (reg:SI TA_REGNUM))]))] + "TARGET_ISA_V3" + "jralnez\t%0" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*cond_call_value_immediate" + [(cond_exec (match_operator 0 "nds32_conditional_call_comparison_operator" + [(match_operand:SI 1 "register_operand" "r") + (const_int 0)]) + (parallel [(set (match_operand 2) + (call (mem (match_operand:SI 3 "nds32_symbolic_operand" "i")) + (match_operand 4))) + (clobber (reg:SI LP_REGNUM)) + (clobber (reg:SI TA_REGNUM))]))] + "!flag_pic && !TARGET_CMODEL_LARGE + && nds32_indirect_call_referenced_p (operands[3])" +{ + switch (GET_CODE (operands[0])) + { + case LT: + return "bltzal\t%1, %3"; + case GE: + return "bgezal\t%1, %3"; + default: + gcc_unreachable (); + } } [(set_attr "type" "branch") - (set (attr "length") - (if_then_else (match_test "TARGET_CMODEL_LARGE") - (const_int 12) - (const_int 4)))]) + (set_attr "length" "4")]) + +;; Call subroutine returning any type. + +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" +{ + int i; + + emit_call_insn (gen_call (operands[0], const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + DONE; +}) ;; ---------------------------------------------------------------------------- ;; The sibcall patterns. ;; sibcall -;; sibcall_register -;; sibcall_immediate +;; sibcall_internal (define_expand "sibcall" [(parallel [(call (match_operand 0 "memory_operand" "") @@ -2001,41 +1789,60 @@ create_template: (clobber (reg:SI TA_REGNUM)) (return)])] "" - "" -) - -(define_insn "*sibcall_register" - [(parallel [(call (mem (match_operand:SI 0 "register_operand" "r, r")) - (match_operand 1)) - (clobber (reg:SI TA_REGNUM)) - (return)])] - "" - "@ - jr5\t%0 - jr\t%0" - [(set_attr "type" "branch,branch") - (set_attr "length" " 2, 4")]) +{ + rtx sym = XEXP (operands[0], 0); + + if (TARGET_ICT_MODEL_LARGE + && nds32_indirect_call_referenced_p (sym)) + { + rtx reg = gen_reg_rtx (Pmode); + emit_move_insn (reg, sym); + operands[0] = gen_const_mem (Pmode, reg); + } +}) -(define_insn "*sibcall_immediate" - [(parallel [(call (mem (match_operand:SI 0 "immediate_operand" "i")) +(define_insn "sibcall_internal" + [(parallel [(call (mem (match_operand:SI 0 "nds32_call_address_operand" "r, i")) (match_operand 1)) (clobber (reg:SI TA_REGNUM)) (return)])] "" { - if (TARGET_CMODEL_LARGE) - return "b\t%0"; - else - return "j\t%0"; + switch (which_alternative) + { + case 0: + if (TARGET_16_BIT) + return "jr5\t%0"; + else + return "jr\t%0"; + case 1: + if (nds32_long_call_p (operands[0])) + return "b\t%0"; + else + return "j\t%0"; + default: + gcc_unreachable (); + } } - [(set_attr "type" "branch") - (set (attr "length") - (if_then_else (match_test "TARGET_CMODEL_LARGE") - (const_int 12) - (const_int 4)))]) + [(set_attr "enabled" "yes") + (set_attr "type" "branch") + (set_attr_alternative "length" + [ + ;; Alternative 0 + (if_then_else (match_test "TARGET_16_BIT") + (const_int 2) + (const_int 4)) + ;; Alternative 1 + (if_then_else (match_test "flag_pic") + (const_int 16) + (if_then_else (match_test "nds32_long_call_p (operands[0])") + (const_int 12) + (const_int 4))) + ])] +) ;; sibcall_value -;; sibcall_value_register +;; sibcall_value_internal ;; sibcall_value_immediate (define_expand "sibcall_value" @@ -2045,73 +1852,106 @@ create_template: (clobber (reg:SI TA_REGNUM)) (return)])] "" - "" -) - -(define_insn "*sibcall_value_register" - [(parallel [(set (match_operand 0) - (call (mem (match_operand:SI 1 "register_operand" "r, r")) - (match_operand 2))) - (clobber (reg:SI TA_REGNUM)) - (return)])] - "" - "@ - jr5\t%1 - jr\t%1" - [(set_attr "type" "branch,branch") - (set_attr "length" " 2, 4")]) +{ + rtx sym = XEXP (operands[1], 0); + + if (TARGET_ICT_MODEL_LARGE + && nds32_indirect_call_referenced_p (sym)) + { + rtx reg = gen_reg_rtx (Pmode); + emit_move_insn (reg, sym); + operands[1] = gen_const_mem (Pmode, reg); + } +}) -(define_insn "*sibcall_value_immediate" +(define_insn "sibcall_value_internal" [(parallel [(set (match_operand 0) - (call (mem (match_operand:SI 1 "immediate_operand" "i")) + (call (mem (match_operand:SI 1 "nds32_call_address_operand" "r, i")) (match_operand 2))) (clobber (reg:SI TA_REGNUM)) (return)])] "" { - if (TARGET_CMODEL_LARGE) - return "b\t%1"; - else - return "j\t%1"; + switch (which_alternative) + { + case 0: + if (TARGET_16_BIT) + return "jr5\t%1"; + else + return "jr\t%1"; + case 1: + if (nds32_long_call_p (operands[1])) + return "b\t%1"; + else + return "j\t%1"; + default: + gcc_unreachable (); + } } - [(set_attr "type" "branch") - (set (attr "length") - (if_then_else (match_test "TARGET_CMODEL_LARGE") - (const_int 12) - (const_int 4)))]) - + [(set_attr "enabled" "yes") + (set_attr "type" "branch") + (set_attr_alternative "length" + [ + ;; Alternative 0 + (if_then_else (match_test "TARGET_16_BIT") + (const_int 2) + (const_int 4)) + ;; Alternative 1 + (if_then_else (match_test "flag_pic") + (const_int 16) + (if_then_else (match_test "nds32_long_call_p (operands[1])") + (const_int 12) + (const_int 4))) + ])] +) ;; ---------------------------------------------------------------------------- -;; prologue and epilogue. +;; The prologue and epilogue. (define_expand "prologue" [(const_int 0)] "" { /* Note that only under V3/V3M ISA, we could use v3push prologue. - In addition, we do not want to use v3push for isr function - and variadic function. */ - if (TARGET_V3PUSH - && !nds32_isr_function_p (current_function_decl) - && (cfun->machine->va_args_size == 0)) + In addition, we need to check if v3push is indeed available. */ + if (NDS32_V3PUSH_AVAILABLE_P) nds32_expand_prologue_v3push (); else nds32_expand_prologue (); + + /* If cfun->machine->fp_as_gp_p is true, we can generate special + directive to guide linker doing fp-as-gp optimization. + However, for a naked function, which means + it should not have prologue/epilogue, + using fp-as-gp still requires saving $fp by push/pop behavior and + there is no benefit to use fp-as-gp on such small function. + So we need to make sure this function is NOT naked as well. */ + if (cfun->machine->fp_as_gp_p && !cfun->machine->naked_p) + emit_insn (gen_omit_fp_begin (gen_rtx_REG (SImode, FP_REGNUM))); + DONE; }) (define_expand "epilogue" [(const_int 0)] "" { + /* If cfun->machine->fp_as_gp_p is true, we can generate special + directive to guide linker doing fp-as-gp optimization. + However, for a naked function, which means + it should not have prologue/epilogue, + using fp-as-gp still requires saving $fp by push/pop behavior and + there is no benefit to use fp-as-gp on such small function. + So we need to make sure this function is NOT naked as well. */ + if (cfun->machine->fp_as_gp_p && !cfun->machine->naked_p) + emit_insn (gen_omit_fp_end (gen_rtx_REG (SImode, FP_REGNUM))); + /* Note that only under V3/V3M ISA, we could use v3pop epilogue. - In addition, we do not want to use v3pop for isr function - and variadic function. */ - if (TARGET_V3PUSH - && !nds32_isr_function_p (current_function_decl) - && (cfun->machine->va_args_size == 0)) + In addition, we need to check if v3push is indeed available. */ + if (NDS32_V3PUSH_AVAILABLE_P) nds32_expand_epilogue_v3pop (false); else nds32_expand_epilogue (false); + DONE; }) @@ -2121,15 +1961,11 @@ create_template: /* Pass true to indicate that this is sibcall epilogue and exit from a function without the final branch back to the calling function. */ - if (TARGET_V3PUSH && !nds32_isr_function_p (current_function_decl)) - nds32_expand_epilogue_v3pop (true); - else - nds32_expand_epilogue (true); + nds32_expand_epilogue (true); DONE; }) - ;; nop instruction. (define_insn "nop" @@ -2142,7 +1978,7 @@ create_template: return "nop"; } [(set_attr "type" "misc") - (set_attr "enabled" "1") + (set_attr "enabled" "yes") (set (attr "length") (if_then_else (match_test "TARGET_16_BIT") (const_int 2) @@ -2166,12 +2002,11 @@ create_template: { return nds32_output_stack_push (operands[0]); } - [(set_attr "type" "misc") - (set_attr "enabled" "1") + [(set_attr "type" "store_multiple") + (set_attr "combo" "12") + (set_attr "enabled" "yes") (set (attr "length") - (if_then_else (match_test "TARGET_V3PUSH - && !nds32_isr_function_p (cfun->decl) - && (cfun->machine->va_args_size == 0)") + (if_then_else (match_test "NDS32_V3PUSH_AVAILABLE_P") (const_int 2) (const_int 4)))]) @@ -2188,12 +2023,11 @@ create_template: { return nds32_output_stack_pop (operands[0]); } - [(set_attr "type" "misc") - (set_attr "enabled" "1") + [(set_attr "type" "load_multiple") + (set_attr "combo" "12") + (set_attr "enabled" "yes") (set (attr "length") - (if_then_else (match_test "TARGET_V3PUSH - && !nds32_isr_function_p (cfun->decl) - && (cfun->machine->va_args_size == 0)") + (if_then_else (match_test "NDS32_V3PUSH_AVAILABLE_P") (const_int 2) (const_int 4)))]) @@ -2205,34 +2039,64 @@ create_template: ;; Use this pattern to expand a return instruction ;; with simple_return rtx if no epilogue is required. (define_expand "return" - [(simple_return)] + [(parallel [(return) + (clobber (reg:SI FP_REGNUM))])] "nds32_can_use_return_insn ()" - "" -) +{ + /* Emit as the simple return. */ + if (!cfun->machine->fp_as_gp_p + && cfun->machine->naked_p + && (cfun->machine->va_args_size == 0)) + { + emit_jump_insn (gen_return_internal ()); + DONE; + } +}) ;; This pattern is expanded only by the shrink-wrapping optimization ;; on paths where the function prologue has not been executed. +;; However, such optimization may reorder the prologue/epilogue blocks +;; together with basic blocks within function body. +;; So we must disable this pattern if we have already decided +;; to perform fp_as_gp optimization, which requires prologue to be +;; first block and epilogue to be last block. (define_expand "simple_return" [(simple_return)] - "" + "!cfun->machine->fp_as_gp_p" "" ) +(define_insn "*nds32_return" + [(parallel [(return) + (clobber (reg:SI FP_REGNUM))])] + "" +{ + return nds32_output_return (); +} + [(set_attr "type" "branch") + (set_attr "enabled" "yes") + (set_attr "length" "4")]) + (define_insn "return_internal" [(simple_return)] "" { + if (nds32_isr_function_critical_p (current_function_decl)) + return "iret"; + if (TARGET_16_BIT) return "ret5"; else return "ret"; } [(set_attr "type" "branch") - (set_attr "enabled" "1") + (set_attr "enabled" "yes") (set (attr "length") - (if_then_else (match_test "TARGET_16_BIT") - (const_int 2) - (const_int 4)))]) + (if_then_else (match_test "nds32_isr_function_critical_p (current_function_decl)") + (const_int 4) + (if_then_else (match_test "TARGET_16_BIT") + (const_int 2) + (const_int 4))))]) ;; ---------------------------------------------------------------------------- @@ -2267,6 +2131,7 @@ create_template: { rtx add_tmp; rtx reg, test; + rtx tmp_reg; /* Step A: "k <-- (plus (operands[0]) (-operands[1]))". */ if (operands[1] != const0_rtx) @@ -2275,8 +2140,8 @@ create_template: add_tmp = gen_int_mode (-INTVAL (operands[1]), SImode); /* If the integer value is not in the range of imm15s, - we need to force register first because our addsi3 pattern - only accept nds32_rimm15s_operand predicate. */ + we need to force register first because our addsi3 pattern + only accept nds32_rimm15s_operand predicate. */ add_tmp = force_reg (SImode, add_tmp); emit_insn (gen_addsi3 (reg, operands[0], add_tmp)); @@ -2288,9 +2153,14 @@ create_template: emit_jump_insn (gen_cbranchsi4 (test, operands[0], operands[2], operands[4])); - /* Step C, D, E, and F, using another temporary register. */ - rtx tmp = gen_reg_rtx (SImode); - emit_jump_insn (gen_casesi_internal (operands[0], operands[3], tmp)); + tmp_reg = gen_reg_rtx (SImode); + /* Step C, D, E, and F, using another temporary register tmp_reg. */ + if (flag_pic) + emit_use (pic_offset_table_rtx); + + emit_jump_insn (gen_casesi_internal (operands[0], + operands[3], + tmp_reg)); DONE; }) @@ -2326,17 +2196,34 @@ create_template: else return nds32_output_casesi (operands); } - [(set_attr "length" "20") - (set_attr "type" "alu")]) + [(set_attr "type" "branch") + (set (attr "length") + (if_then_else (match_test "flag_pic") + (const_int 28) + (const_int 20)))]) ;; ---------------------------------------------------------------------------- ;; Performance Extension +; If -fwrapv option is issued, GCC expects there will be +; signed overflow situation. So the ABS(INT_MIN) is still INT_MIN +; (e.g. ABS(0x80000000)=0x80000000). +; However, the hardware ABS instruction of nds32 target +; always performs saturation: abs 0x80000000 -> 0x7fffffff. +; So that we can only enable abssi2 pattern if flag_wrapv is NOT presented. +(define_insn "abssi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (abs:SI (match_operand:SI 1 "register_operand" " r")))] + "TARGET_EXT_PERF && TARGET_HW_ABS && !flag_wrapv" + "abs\t%0, %1" + [(set_attr "type" "alu") + (set_attr "length" "4")]) + (define_insn "clzsi2" [(set (match_operand:SI 0 "register_operand" "=r") (clz:SI (match_operand:SI 1 "register_operand" " r")))] - "TARGET_PERF_EXT" + "TARGET_EXT_PERF" "clz\t%0, %1" [(set_attr "type" "alu") (set_attr "length" "4")]) @@ -2345,34 +2232,212 @@ create_template: [(set (match_operand:SI 0 "register_operand" "=r") (smax:SI (match_operand:SI 1 "register_operand" " r") (match_operand:SI 2 "register_operand" " r")))] - "TARGET_PERF_EXT" + "TARGET_EXT_PERF" "max\t%0, %1, %2" [(set_attr "type" "alu") (set_attr "length" "4")]) +(define_expand "uminqi3" + [(set (match_operand:QI 0 "register_operand" "") + (umin:QI (match_operand:QI 1 "register_operand" "") + (match_operand:QI 2 "register_operand" "")))] + "TARGET_EXT_PERF" +{ + rtx tmpop[3]; + tmpop[0] = gen_reg_rtx (SImode); + tmpop[1] = gen_reg_rtx (SImode); + tmpop[2] = gen_reg_rtx (SImode); + + emit_insn (gen_zero_extendqisi2 (tmpop[1], operands[1])); + emit_insn (gen_zero_extendqisi2 (tmpop[2], operands[2])); + emit_insn (gen_sminsi3 (tmpop[0], tmpop[1], tmpop[2])); + convert_move (operands[0], tmpop[0], false); + DONE; +}) + +(define_expand "sminqi3" + [(set (match_operand:QI 0 "register_operand" "") + (smin:QI (match_operand:QI 1 "register_operand" "") + (match_operand:QI 2 "register_operand" "")))] + "TARGET_EXT_PERF" +{ + rtx tmpop[3]; + tmpop[0] = gen_reg_rtx (SImode); + tmpop[1] = gen_reg_rtx (SImode); + tmpop[2] = gen_reg_rtx (SImode); + + emit_insn (gen_extendqisi2 (tmpop[1], operands[1])); + emit_insn (gen_extendqisi2 (tmpop[2], operands[2])); + emit_insn (gen_sminsi3 (tmpop[0], tmpop[1], tmpop[2])); + convert_move (operands[0], tmpop[0], false); + DONE; +}) + +(define_expand "uminhi3" + [(set (match_operand:HI 0 "register_operand" "") + (umin:HI (match_operand:HI 1 "register_operand" "") + (match_operand:HI 2 "register_operand" "")))] + "TARGET_EXT_PERF" +{ + rtx tmpop[3]; + tmpop[0] = gen_reg_rtx (SImode); + tmpop[1] = gen_reg_rtx (SImode); + tmpop[2] = gen_reg_rtx (SImode); + + emit_insn (gen_zero_extendhisi2 (tmpop[1], operands[1])); + emit_insn (gen_zero_extendhisi2 (tmpop[2], operands[2])); + emit_insn (gen_sminsi3 (tmpop[0], tmpop[1], tmpop[2])); + convert_move (operands[0], tmpop[0], false); + DONE; +}) + +(define_expand "sminhi3" + [(set (match_operand:HI 0 "register_operand" "") + (smin:HI (match_operand:HI 1 "register_operand" "") + (match_operand:HI 2 "register_operand" "")))] + "TARGET_EXT_PERF" +{ + rtx tmpop[3]; + tmpop[0] = gen_reg_rtx (SImode); + tmpop[1] = gen_reg_rtx (SImode); + tmpop[2] = gen_reg_rtx (SImode); + + emit_insn (gen_extendhisi2 (tmpop[1], operands[1])); + emit_insn (gen_extendhisi2 (tmpop[2], operands[2])); + emit_insn (gen_sminsi3 (tmpop[0], tmpop[1], tmpop[2])); + convert_move (operands[0], tmpop[0], false); + DONE; +}) + (define_insn "sminsi3" [(set (match_operand:SI 0 "register_operand" "=r") (smin:SI (match_operand:SI 1 "register_operand" " r") (match_operand:SI 2 "register_operand" " r")))] - "TARGET_PERF_EXT" + "TARGET_EXT_PERF" "min\t%0, %1, %2" [(set_attr "type" "alu") (set_attr "length" "4")]) -(define_insn "*btst" - [(set (match_operand:SI 0 "register_operand" "= r") - (zero_extract:SI (match_operand:SI 1 "register_operand" " r") +(define_insn "btst" + [(set (match_operand:SI 0 "register_operand" "= r") + (zero_extract:SI (match_operand:SI 1 "register_operand" " r") (const_int 1) - (match_operand:SI 2 "immediate_operand" " Iu05")))] - "TARGET_PERF_EXT" + (match_operand:SI 2 "nds32_imm5u_operand" " Iu05")))] + "TARGET_EXT_PERF" "btst\t%0, %1, %2" [(set_attr "type" "alu") (set_attr "length" "4")]) +(define_insn "ave" + [(set (match_operand:SI 0 "register_operand" "=r") + (truncate:SI + (ashiftrt:DI + (plus:DI + (plus:DI + (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) + (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))) + (const_int 1)) + (const_int 1))))] + "TARGET_EXT_PERF" + "ave\t%0, %1, %2" + [(set_attr "type" "alu") + (set_attr "length" "4")]) + ;; ---------------------------------------------------------------------------- ;; Pseudo NOPs +;; Structural hazards NOP +(define_insn "nop_res_dep" + [(unspec [(match_operand 0 "const_int_operand" "i")] UNSPEC_VOLATILE_RES_DEP)] + "" + "! structural dependency (%0 cycles)" + [(set_attr "length" "0")] +) + +;; Data hazards NOP +(define_insn "nop_data_dep" + [(unspec [(match_operand 0 "const_int_operand" "i")] UNSPEC_VOLATILE_DATA_DEP)] + "" + "! data dependency (%0 cycles)" + [(set_attr "length" "0")] +) + +(define_insn "relax_group" + [(unspec_volatile [(match_operand:SI 0 "immediate_operand" "i")] UNSPEC_VOLATILE_RELAX_GROUP)] + "" + ".relax_hint %0" + [(set_attr "length" "0")] +) + +(define_insn "innermost_loop_begin" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_INNERMOST_LOOP_BEGIN)] + "" + ".innermost_loop_begin" + [(set_attr "length" "0")] +) + +(define_insn "innermost_loop_end" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_INNERMOST_LOOP_END)] + "" + ".innermost_loop_end" + [(set_attr "length" "0")] +) + +(define_insn "no_ifc_begin" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_NO_IFC_BEGIN)] + "" + ".no_ifc_begin" + [(set_attr "length" "0")] +) + +(define_insn "no_ifc_end" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_NO_IFC_END)] + "" + ".no_ifc_end" + [(set_attr "length" "0")] +) + +(define_insn "no_ex9_begin" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_NO_EX9_BEGIN)] + "" + ".no_ex9_begin" + [(set_attr "length" "0")] +) + +(define_insn "no_ex9_end" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_NO_EX9_END)] + "" + ".no_ex9_end" + [(set_attr "length" "0")] +) + +(define_insn "hwloop_last_insn" + [(unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_HWLOOP_LAST_INSN)] + "" + "" + [(set_attr "length" "0")] +) + +;; Output .omit_fp_begin for fp-as-gp optimization. +;; Also we have to set $fp register. +(define_insn "omit_fp_begin" + [(set (match_operand:SI 0 "register_operand" "=x") + (unspec_volatile:SI [(const_int 0)] UNSPEC_VOLATILE_OMIT_FP_BEGIN))] + "" + "! -----\;.omit_fp_begin\;la\t$fp,_FP_BASE_\;! -----" + [(set_attr "length" "8")] +) + +;; Output .omit_fp_end for fp-as-gp optimization. +;; Claim that we have to use $fp register. +(define_insn "omit_fp_end" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "x")] UNSPEC_VOLATILE_OMIT_FP_END)] + "" + "! -----\;.omit_fp_end\;! -----" + [(set_attr "length" "0")] +) + (define_insn "pop25return" [(return) (unspec_volatile:SI [(reg:SI LP_REGNUM)] UNSPEC_VOLATILE_POP25_RETURN)] @@ -2381,4 +2446,262 @@ create_template: [(set_attr "length" "0")] ) +;; Add pc +(define_insn "add_pc" + [(set (match_operand:SI 0 "register_operand" "=r") + (plus:SI (match_operand:SI 1 "register_operand" "0") + (pc)))] + "TARGET_LINUX_ABI || flag_pic" + "add5.pc\t%0" + [(set_attr "type" "alu") + (set_attr "length" "4")] +) + +(define_expand "bswapsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (bswap:SI (match_operand:SI 1 "register_operand" "r")))] + "" +{ + emit_insn (gen_unspec_wsbh (operands[0], operands[1])); + emit_insn (gen_rotrsi3 (operands[0], operands[0], GEN_INT (16))); + DONE; +}) + +(define_insn "bswaphi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (bswap:HI (match_operand:HI 1 "register_operand" "r")))] + "" + "wsbh\t%0, %1" + [(set_attr "type" "alu") + (set_attr "length" "4")] +) + +;; Hardware loop + +; operand 0 is the loop count pseudo register +; operand 1 is the label to jump to at the top of the loop +(define_expand "doloop_end" + [(parallel [(set (pc) (if_then_else + (ne (match_operand:SI 0 "" "") + (const_int 1)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const_int -1))) + (unspec [(const_int 0)] UNSPEC_LOOP_END) + (clobber (match_dup 2))])] ; match_scratch + "NDS32_HW_LOOP_P ()" +{ + /* The loop optimizer doesn't check the predicates... */ + if (GET_MODE (operands[0]) != SImode) + FAIL; + operands[2] = gen_rtx_SCRATCH (SImode); +}) + +(define_insn "loop_end" + [(set (pc) + (if_then_else (ne (match_operand:SI 3 "nonimmediate_operand" "0, 0, *r, 0") + (const_int 1)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_operand:SI 0 "nonimmediate_operand" "=r, m, m, *f") + (plus:SI (match_dup 3) + (const_int -1))) + (unspec [(const_int 0)] UNSPEC_LOOP_END) + (clobber (match_scratch:SI 2 "=X, &r, &r, &r"))] + "NDS32_HW_LOOP_P ()" + "#" + [(set_attr "length" "12, 12, 12, 12")]) + +(define_split + [(set (pc) + (if_then_else (ne (match_operand:SI 3 "nonimmediate_operand" "") + (const_int 1)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_operand:SI 0 "fpu_reg_or_memory_operand" "") + (plus:SI (match_dup 3) + (const_int -1))) + (unspec [(const_int 0)] UNSPEC_LOOP_END) + (clobber (match_scratch:SI 2 ""))] + "NDS32_HW_LOOP_P ()" + [(set (match_dup 2) (plus:SI (match_dup 3) (const_int -1))) + (set (match_dup 0) (match_dup 2)) + (set (pc) + (if_then_else (ne (match_dup 2) (const_int 0)) + (label_ref (match_dup 1)) + (pc)))] +{ + if (fpu_reg_or_memory_operand (operands[3], SImode)) + { + emit_move_insn (operands[2], operands[3]); + operands[3] = operands[2]; + } +}) + +(define_insn "mtlbi_hint" + [(set (reg:SI LB_REGNUM) + (match_operand:SI 0 "nds32_label_operand" "i")) + (unspec [(match_operand 1 "const_int_operand" "i")] UNSPEC_LOOP_END)] + "NDS32_HW_LOOP_P ()" + "mtlbi\t%0" + [(set_attr "length" "4")]) + +(define_insn "mtlbi" + [(set (reg:SI LB_REGNUM) + (match_operand:SI 0 "nds32_label_operand" "i"))] + "NDS32_HW_LOOP_P ()" + "mtlbi\t%0" + [(set_attr "length" "4")]) + +(define_insn "mtlei" + [(set (reg:SI LE_REGNUM) + (match_operand:SI 0 "nds32_label_operand" "i"))] + "NDS32_HW_LOOP_P ()" + "mtlei\t%0" + [(set_attr "length" "4")]) + +(define_insn "init_lc" + [(set (reg:SI LC_REGNUM) + (match_operand:SI 0 "register_operand" "r")) + (unspec [(match_operand 1 "const_int_operand" "i")] UNSPEC_LOOP_END)] + "NDS32_HW_LOOP_P ()" + "mtusr\t%0, LC" + [(set_attr "length" "4")]) + +; After replace hwloop, use this is pattern to get right CFG +(define_insn "hwloop_cfg" + [(set (pc) + (if_then_else (ne (reg:SI LC_REGNUM) + (const_int 1)) + (match_operand:SI 1 "nds32_label_operand" "i") + (pc))) + (set (reg:SI LC_REGNUM) + (plus:SI (reg:SI LC_REGNUM) + (const_int -1))) + (use (reg:SI LB_REGNUM)) + (use (reg:SI LE_REGNUM)) + (use (reg:SI LC_REGNUM)) + (unspec [(match_operand 0 "const_int_operand" "i")] UNSPEC_LOOP_END)] + "TARGET_HWLOOP" + "" + [(set_attr "length" "0")]) +;; ---------------------------------------------------------------------------- + +;; Patterns for exception handling + +(define_expand "eh_return" + [(use (match_operand 0 "general_operand"))] + "" +{ + emit_insn (gen_nds32_eh_return (operands[0])); + DONE; +}) + +(define_insn_and_split "nds32_eh_return" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] UNSPEC_VOLATILE_EH_RETURN)] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + rtx place; + rtx addr; + + /* The operands[0] is the handler address. We need to assign it + to return address rtx so that we can jump to exception handler + when returning from current function. */ + + if (cfun->machine->lp_size == 0) + { + /* If $lp is not saved in the stack frame, we can take $lp directly. */ + place = gen_rtx_REG (SImode, LP_REGNUM); + } + else + { + /* Otherwise, we need to locate the stack slot of return address. + The return address is generally saved in [$fp-4] location. + However, DSE (dead store elimination) does not detect an alias + between [$fp-x] and [$sp+y]. This can result in a store to save + $lp introduced by builtin_eh_return() being incorrectly deleted + if it is based on $fp. The solution we take here is to compute + the offset relative to stack pointer and then use $sp to access + location so that the alias can be detected. + FIXME: What if the immediate value "offset" is too large to be + fit in a single addi instruction? */ + HOST_WIDE_INT offset; + + offset = (cfun->machine->fp_size + + cfun->machine->gp_size + + cfun->machine->lp_size + + cfun->machine->callee_saved_gpr_regs_size + + cfun->machine->callee_saved_area_gpr_padding_bytes + + cfun->machine->callee_saved_fpr_regs_size + + cfun->machine->eh_return_data_regs_size + + cfun->machine->local_size + + cfun->machine->out_args_size); + + addr = plus_constant (Pmode, stack_pointer_rtx, offset - 4); + place = gen_frame_mem (SImode, addr); + } + + emit_move_insn (place, operands[0]); + DONE; +}) + +;; ---------------------------------------------------------------------------- + +;; Patterns for TLS. +;; The following two tls patterns don't be expanded directly because the +;; intermediate value may be spilled into the stack. As a result, it is +;; hard to analyze the define-use chain in the relax_opt pass. + + +;; There is a unspec operand to record RELAX_GROUP number because each +;; emitted instruction need a relax_hint above it. +(define_insn "tls_desc" + [(set (reg:SI 0) + (call (unspec_volatile:SI [(match_operand:SI 0 "nds32_symbolic_operand" "i")] UNSPEC_TLS_DESC) + (const_int 1))) + (use (unspec [(match_operand:SI 1 "immediate_operand" "i")] UNSPEC_VOLATILE_RELAX_GROUP)) + (use (reg:SI GP_REGNUM)) + (clobber (reg:SI LP_REGNUM)) + (clobber (reg:SI TA_REGNUM))] + "" + { + return nds32_output_tls_desc (operands); + } + [(set_attr "length" "20") + (set_attr "type" "branch")] +) + +;; There is a unspec operand to record RELAX_GROUP number because each +;; emitted instruction need a relax_hint above it. +(define_insn "tls_ie" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "nds32_symbolic_operand" "i")] UNSPEC_TLS_IE)) + (use (unspec [(match_operand:SI 2 "immediate_operand" "i")] UNSPEC_VOLATILE_RELAX_GROUP)) + (use (reg:SI GP_REGNUM))] + "" + { + return nds32_output_tls_ie (operands); + } + [(set (attr "length") (if_then_else (match_test "flag_pic") + (const_int 12) + (const_int 8))) + (set_attr "type" "misc")] +) + +;; The pattern is for some relaxation groups that have to keep addsi3 in 32-bit mode. +(define_insn "addsi3_32bit" + [(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_ADD32))] + "" + "add\t%0, %1, %2"; + [(set_attr "type" "alu") + (set_attr "length" "4") + (set_attr "feature" "v1")]) + ;; ---------------------------------------------------------------------------- diff --git a/gcc/config/nds32/nds32.opt b/gcc/config/nds32/nds32.opt index 938136f..aa408f6 100644 --- a/gcc/config/nds32/nds32.opt +++ b/gcc/config/nds32/nds32.opt @@ -21,14 +21,67 @@ HeaderInclude config/nds32/nds32-opts.h -mbig-endian -Target Report RejectNegative Negative(mlittle-endian) Mask(BIG_ENDIAN) +; --------------------------------------------------------------- +; The following options are designed for aliasing and compatibility options. + +EB +Target RejectNegative Alias(mbig-endian) Generate code in big-endian mode. -mlittle-endian -Target Report RejectNegative Negative(mbig-endian) InverseMask(BIG_ENDIAN) +EL +Target RejectNegative Alias(mlittle-endian) Generate code in little-endian mode. +mfp-as-gp +Target RejectNegative Alias(mforce-fp-as-gp) +Force performing fp-as-gp optimization. + +mno-fp-as-gp +Target RejectNegative Alias(mforbid-fp-as-gp) +Forbid performing fp-as-gp optimization. + +m16bit +Target Undocumented Alias(m16-bit) +Generate 16-bit instructions. + +mcrt-arg=yes +Target Undocumented Alias(mcrt-arg) +Obsolete option. Users SHOULD NOT use this option in the command line. + +mreduce-regs +Target Undocumented Alias(mreduced-regs) +Use reduced-set registers for register allocation. + +mcache-line-size= +Target RejectNegative Joined UInteger Undocumented Alias(mcache-block-size=) +Alias of -mcache-block-size= + +; --------------------------------------------------------------- + +mabi= +Target RejectNegative Joined Enum(abi_type) Var(nds32_abi) Init(TARGET_DEFAULT_ABI) +Specify which ABI type to generate code for: 2, 2fp+. + +Enum +Name(abi_type) Type(enum abi_type) +Known ABIs (for use with the -mabi= option): + +EnumValue +Enum(abi_type) String(2) Value(NDS32_ABI_V2) + +EnumValue +Enum(abi_type) String(2fp+) Value(NDS32_ABI_V2_FP_PLUS) + +mfloat-abi=soft +Target RejectNegative Alias(mabi=, 2) +Specify use soft floating point ABI which mean alias to -mabi=2. + +mfloat-abi=hard +Target RejectNegative Alias(mabi=, 2fp+) +Specify use soft floating point ABI which mean alias to -mabi=2fp+. + +; --------------------------------------------------------------- + mreduced-regs Target Report RejectNegative Negative(mfull-regs) Mask(REDUCED_REGS) Use reduced-set registers for register allocation. @@ -37,14 +90,148 @@ mfull-regs Target Report RejectNegative Negative(mreduced-regs) InverseMask(REDUCED_REGS) Use full-set registers for register allocation. +; --------------------------------------------------------------- + +Os1 +Target +Optimize for size level 1. This option will disable IFC and EX9 to prevent performance drop. + +Os2 +Target +Optimize for size level 2. This option will disable IFC and EX9 for innermost loop to prevent performance drop. + +Os3 +Target +Optimize for size level 3 which mean don't care performance. + +malways-align +Target Mask(ALWAYS_ALIGN) +Always align function entry, jump target and return address. + +malign-functions +Target Mask(ALIGN_FUNCTION) +Align function entry to 4 byte. + +mbig-endian +Target Undocumented RejectNegative Negative(mlittle-endian) Mask(BIG_ENDIAN) +Generate code in big-endian mode. + +mlittle-endian +Target Undocumented RejectNegative Negative(mbig-endian) InverseMask(BIG_ENDIAN) +Generate code in little-endian mode. + +mforce-fp-as-gp +Target Undocumented Mask(FORCE_FP_AS_GP) +Prevent $fp being allocated during register allocation so that compiler is able to force performing fp-as-gp optimization. + +mforbid-fp-as-gp +Target Undocumented Mask(FORBID_FP_AS_GP) +Forbid using $fp to access static and global variables. This option strictly forbids fp-as-gp optimization regardless of '-mforce-fp-as-gp'. + +minline-strcpy +Target Undocumented Mask(INLINE_STRCPY) +Inlining strcpy function. + +mload-store-opt +Target Mask(LOAD_STORE_OPT) +Enable load store optimization. + +mregrename +Target Mask(REGRENAME_OPT) +Enable target dependent register rename optimization. + +mgcse +Target Mask(GCSE_OPT) +Enable target dependent global CSE optimization. + +mconst-remater +Target Var(flag_nds32_const_remater_opt) +Enable target dependent constant remeterialization optimization. + +msoft-fp-arith-comm +Target Mask(SOFT_FP_ARITH_COMM) +Enable operand commutative for soft floating point arithmetic optimization. + +msign-conversion +Target Var(flag_nds32_sign_conversion) +Enable the sign conversion in Gimple level. + +mscalbn-transform +Target Var(flag_nds32_scalbn_transform) +Enable the scalbn transform in Gimple level. + +mlmwsmw-opt +Target Var(flag_nds32_lmwsmw_opt) +Enable the load/store multiple optimization. + +mict-model= +Target Undocumented RejectNegative Joined Enum(nds32_ict_model_type) Var(nds32_ict_model) Init(ICT_MODEL_SMALL) +Specify the address generation strategy for ICT call's code model. + +Enum +Name(nds32_ict_model_type) Type(enum nds32_ict_model_type) +Known cmodel types (for use with the -mict-model= option): + +EnumValue +Enum(nds32_ict_model_type) String(small) Value(ICT_MODEL_SMALL) + +EnumValue +Enum(nds32_ict_model_type) String(large) Value(ICT_MODEL_LARGE) + +mlmwsmw-cost= +Target RejectNegative Joined Enum(lmwsmw_cost_type) Var(flag_lmwsmw_cost) Init(LMWSMW_OPT_AUTO) +Specify the load/store insn generate to lmw/smw. + +Enum +Name(lmwsmw_cost_type) Type(enum lmwsmw_cost_type) +Known lmwsmw cost type (for use with the -mlmwsmw-cost= option): + +EnumValue +Enum(lmwsmw_cost_type) String(size) Value(LMWSMW_OPT_SIZE) + +EnumValue +Enum(lmwsmw_cost_type) String(speed) Value(LMWSMW_OPT_SPEED) + +EnumValue +Enum(lmwsmw_cost_type) String(all) Value(LMWSMW_OPT_ALL) + +EnumValue +Enum(lmwsmw_cost_type) String(auto) Value(LMWSMW_OPT_AUTO) + +mabi-compatible +Target Var(flag_nds32_abi_compatible) +Enable the ABI compatible detection. + +mcprop-acc +Target Var(flag_nds32_cprop_acc) +Enable the copy propagation for accumulate style instructions. + +; --------------------------------------------------------------- + mcmov Target Report Mask(CMOV) Generate conditional move instructions. -mperf-ext -Target Report Mask(PERF_EXT) +mhw-abs +Target Report Mask(HW_ABS) +Generate hardware abs instructions. + +mext-perf +Target Report Mask(EXT_PERF) Generate performance extension instructions. +mext-perf2 +Target Report Mask(EXT_PERF2) +Generate performance extension version 2 instructions. + +mext-string +Target Report Mask(EXT_STRING) +Generate string extension instructions. + +mext-dsp +Target Report Mask(EXT_DSP) +Generate DSP extension instructions. + mv3push Target Report Mask(V3PUSH) Generate v3 push25/pop25 instructions. @@ -53,10 +240,22 @@ m16-bit Target Report Mask(16_BIT) Generate 16-bit instructions. +mrelax-hint +Target Report Mask(RELAX_HINT) +Insert relax hint for linker to do relaxation. + +mvh +Target Report Mask(VH) Condition(!TARGET_LINUX_ABI) +Enable Virtual Hosting support. + misr-vector-size= -Target RejectNegative Joined UInteger Var(nds32_isr_vector_size) Init(NDS32_DEFAULT_ISR_VECTOR_SIZE) +Target RejectNegative Joined UInteger Var(nds32_isr_vector_size) Init(NDS32_DEFAULT_ISR_VECTOR_SIZE) Condition(!TARGET_LINUX_ABI) Specify the size of each interrupt vector, which must be 4 or 16. +misr-secure= +Target RejectNegative Joined UInteger Var(nds32_isr_secure_level) Init(0) +Specify the security level of c-isr for the whole file. + mcache-block-size= Target RejectNegative Joined UInteger Var(nds32_cache_block_size) Init(NDS32_DEFAULT_CACHE_BLOCK_SIZE) Specify the size of each cache block, which must be a power of 2 between 4 and 512. @@ -73,32 +272,422 @@ EnumValue Enum(nds32_arch_type) String(v2) Value(ARCH_V2) EnumValue +Enum(nds32_arch_type) String(v2j) Value(ARCH_V2J) + +EnumValue Enum(nds32_arch_type) String(v3) Value(ARCH_V3) EnumValue +Enum(nds32_arch_type) String(v3j) Value(ARCH_V3J) + +EnumValue Enum(nds32_arch_type) String(v3m) Value(ARCH_V3M) -mcmodel= -Target RejectNegative Joined Enum(nds32_cmodel_type) Var(nds32_cmodel_option) Init(CMODEL_MEDIUM) -Specify the address generation strategy for code model. +EnumValue +Enum(nds32_arch_type) String(v3m+) Value(ARCH_V3M_PLUS) + +EnumValue +Enum(nds32_arch_type) String(v3f) Value(ARCH_V3F) + +EnumValue +Enum(nds32_arch_type) String(v3s) Value(ARCH_V3S) + +mcpu= +Target RejectNegative Joined Enum(nds32_cpu_type) Var(nds32_cpu_option) Init(CPU_N9) +Specify the cpu for pipeline model. + +Enum +Name(nds32_cpu_type) Type(enum nds32_cpu_type) +Known cpu types (for use with the -mcpu= option): + +EnumValue +Enum(nds32_cpu_type) String(n6) Value(CPU_N6) + +EnumValue +Enum(nds32_cpu_type) String(n650) Value(CPU_N6) + +EnumValue +Enum(nds32_cpu_type) String(n7) Value(CPU_N7) + +EnumValue +Enum(nds32_cpu_type) String(n705) Value(CPU_N7) + +EnumValue +Enum(nds32_cpu_type) String(n8) Value(CPU_N8) + +EnumValue +Enum(nds32_cpu_type) String(n801) Value(CPU_N8) + +EnumValue +Enum(nds32_cpu_type) String(sn8) Value(CPU_N8) + +EnumValue +Enum(nds32_cpu_type) String(sn801) Value(CPU_N8) + +EnumValue +Enum(nds32_cpu_type) String(s8) Value(CPU_N8) + +EnumValue +Enum(nds32_cpu_type) String(s801) Value(CPU_N8) + +EnumValue +Enum(nds32_cpu_type) String(e8) Value(CPU_E8) + +EnumValue +Enum(nds32_cpu_type) String(e801) Value(CPU_E8) + +EnumValue +Enum(nds32_cpu_type) String(n820) Value(CPU_E8) + +EnumValue +Enum(nds32_cpu_type) String(s830) Value(CPU_E8) + +EnumValue +Enum(nds32_cpu_type) String(e830) Value(CPU_E8) + +EnumValue +Enum(nds32_cpu_type) String(n9) Value(CPU_N9) + +EnumValue +Enum(nds32_cpu_type) String(n903) Value(CPU_N9) + +EnumValue +Enum(nds32_cpu_type) String(n903a) Value(CPU_N9) + +EnumValue +Enum(nds32_cpu_type) String(n968) Value(CPU_N9) + +EnumValue +Enum(nds32_cpu_type) String(n968a) Value(CPU_N9) + +EnumValue +Enum(nds32_cpu_type) String(n10) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(n1033) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(n1033a) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(n1033-fpu) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(n1033-spu) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(n1068) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(n1068a) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(n1068-fpu) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(n1068a-fpu) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(n1068-spu) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(n1068a-spu) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(d10) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(d1088) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(d1088-fpu) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) String(d1088-spu) Value(CPU_N10) + +EnumValue +Enum(nds32_cpu_type) Undocumented String(graywolf) Value(CPU_GRAYWOLF) + +EnumValue +Enum(nds32_cpu_type) String(n15) Value(CPU_GRAYWOLF) + +EnumValue +Enum(nds32_cpu_type) String(d15) Value(CPU_GRAYWOLF) + +EnumValue +Enum(nds32_cpu_type) String(n15s) Value(CPU_GRAYWOLF) + +EnumValue +Enum(nds32_cpu_type) String(d15s) Value(CPU_GRAYWOLF) + +EnumValue +Enum(nds32_cpu_type) String(n15f) Value(CPU_GRAYWOLF) + +EnumValue +Enum(nds32_cpu_type) String(d15f) Value(CPU_GRAYWOLF) + +EnumValue +Enum(nds32_cpu_type) String(n12) Value(CPU_N12) + +EnumValue +Enum(nds32_cpu_type) String(n1213) Value(CPU_N12) + +EnumValue +Enum(nds32_cpu_type) String(n1233) Value(CPU_N12) + +EnumValue +Enum(nds32_cpu_type) String(n1233-fpu) Value(CPU_N12) + +EnumValue +Enum(nds32_cpu_type) String(n1233-spu) Value(CPU_N12) + +EnumValue +Enum(nds32_cpu_type) String(n13) Value(CPU_N13) + +EnumValue +Enum(nds32_cpu_type) String(n1337) Value(CPU_N13) + +EnumValue +Enum(nds32_cpu_type) String(n1337-fpu) Value(CPU_N13) + +EnumValue +Enum(nds32_cpu_type) String(n1337-spu) Value(CPU_N13) + +EnumValue +Enum(nds32_cpu_type) Undocumented String(panther) Value(CPU_PANTHER) + +EnumValue +Enum(nds32_cpu_type) Undocumented String(simple) Value(CPU_SIMPLE) + +mcpu=n15 +Target RejectNegative Undocumented Alias(mcpu=, graywolf) +Alias for multi-lib work. + +mcpu=n15f +Target RejectNegative Undocumented Alias(mcpu=, graywolf) +Alias for multi-lib work. + +mcpu=n15s +Target RejectNegative Undocumented Alias(mcpu=, graywolf) +Alias for multi-lib work. + +mcpu=d15 +Target RejectNegative Undocumented Alias(mcpu=, graywolf) +Alias for multi-lib work. + +mcpu=d15s +Target RejectNegative Undocumented Alias(mcpu=, graywolf) +Alias for multi-lib work. + +mcpu=d15f +Target RejectNegative Undocumented Alias(mcpu=, graywolf) +Alias for multi-lib work. + +mgraywolf +Target RejectNegative Undocumented Alias(mcpu=, graywolf) +This alias is only for gcc parallel test. + +mv3m+ +Target RejectNegative Undocumented Alias(march=, v3m+) +This alias is only for gcc parallel test. + +mmemory-model= +Target RejectNegative Joined Enum(nds32_memory_model_type) Var(nds32_memory_model_option) Init(MEMORY_MODEL_FAST) +Specify the memory model, fast or slow memory. Enum -Name(nds32_cmodel_type) Type(enum nds32_cmodel_type) -Known cmodel types (for use with the -mcmodel= option): +Name(nds32_memory_model_type) Type(enum nds32_memory_model_type) EnumValue -Enum(nds32_cmodel_type) String(small) Value(CMODEL_SMALL) +Enum(nds32_memory_model_type) String(slow) Value(MEMORY_MODEL_SLOW) EnumValue -Enum(nds32_cmodel_type) String(medium) Value(CMODEL_MEDIUM) +Enum(nds32_memory_model_type) String(fast) Value(MEMORY_MODEL_FAST) + +mconfig-fpu= +Target RejectNegative Joined Enum(float_reg_number) Var(nds32_fp_regnum) Init(TARGET_CONFIG_FPU_DEFAULT) +Specify a fpu configuration value from 0 to 7; 0-3 is as FPU spec says, and 4-7 is corresponding to 0-3. + +Enum +Name(float_reg_number) Type(enum float_reg_number) +Known floating-point number of registers (for use with the -mconfig-fpu= option): + +EnumValue +Enum(float_reg_number) String(0) Value(NDS32_CONFIG_FPU_0) + +EnumValue +Enum(float_reg_number) String(1) Value(NDS32_CONFIG_FPU_1) + +EnumValue +Enum(float_reg_number) String(2) Value(NDS32_CONFIG_FPU_2) + +EnumValue +Enum(float_reg_number) String(3) Value(NDS32_CONFIG_FPU_3) + +EnumValue +Enum(float_reg_number) String(4) Value(NDS32_CONFIG_FPU_4) + +EnumValue +Enum(float_reg_number) String(5) Value(NDS32_CONFIG_FPU_5) + +EnumValue +Enum(float_reg_number) String(6) Value(NDS32_CONFIG_FPU_6) + +EnumValue +Enum(float_reg_number) String(7) Value(NDS32_CONFIG_FPU_7) + +mconfig-mul= +Target RejectNegative Joined Enum(nds32_mul_type) Var(nds32_mul_config) Init(MUL_TYPE_FAST_1) +Specify configuration of instruction mul: fast1, fast2 or slow. The default is fast1. + +Enum +Name(nds32_mul_type) Type(enum nds32_mul_type) + +EnumValue +Enum(nds32_mul_type) String(fast) Value(MUL_TYPE_FAST_1) + +EnumValue +Enum(nds32_mul_type) String(fast1) Value(MUL_TYPE_FAST_1) + +EnumValue +Enum(nds32_mul_type) String(fast2) Value(MUL_TYPE_FAST_2) + +EnumValue +Enum(nds32_mul_type) String(slow) Value(MUL_TYPE_SLOW) + +mconfig-register-ports= +Target RejectNegative Joined Enum(nds32_register_ports) Var(nds32_register_ports_config) Init(REG_PORT_3R2W) +Specify how many read/write ports for n9/n10 cores. The value should be 3r2w or 2r1w. + +Enum +Name(nds32_register_ports) Type(enum nds32_register_ports) EnumValue -Enum(nds32_cmodel_type) String(large) Value(CMODEL_LARGE) +Enum(nds32_register_ports) String(3r2w) Value(REG_PORT_3R2W) + +EnumValue +Enum(nds32_register_ports) String(2r1w) Value(REG_PORT_2R1W) + +mreorg-out-of-order +Target Report Var(flag_reorg_out_of_order) Init(0) +Allow out-of-order reorganization for multiple issue micro-architectures. + +mifc +Target Report Mask(IFC) +Use special directives to guide linker doing ifc optimization. + +mex9 +Target Report Mask(EX9) +Use special directives to guide linker doing ex9 optimization. + +mprint-stall-cycles +Target Report Mask(PRINT_STALLS) +Print stall cycles due to structural or data dependencies. It should be used with the option '-S'. +Note that stall cycles are determined by the compiler's pipeline model and it may not be precise. mctor-dtor Target Report Enable constructor/destructor feature. +mcrt-arg +Target Report +Enable argc/argv passed by simulator. + mrelax Target Report Guide linker to relax instructions. + +minnermost-loop +Target Report Mask(INNERMOST_LOOP) +Insert the innermost loop directive. + +mext-fpu-fma +Target Report Mask(EXT_FPU_FMA) +Generate floating-point multiply-accumulation instructions. + +mext-fpu-sp +Target Report Mask(FPU_SINGLE) +Generate single-precision floating-point instructions. + +mext-fpu-dp +Target Report Mask(FPU_DOUBLE) +Generate double-precision floating-point instructions. + +mext-zol +Target Report Mask(HWLOOP) +Insert the hardware loop directive. + +mforce-no-ext-zol +Target Undocumented Report Mask(FORCE_NO_HWLOOP) +Force disable hardware loop, even use -mext-zol. + +mforce-no-ext-dsp +Target Undocumented Report Mask(FORCE_NO_EXT_DSP) +Force disable hardware loop, even use -mext-dsp. + +mforce-memcpy-zol +Target Report Var(flag_force_memcpy_zol) Init(0) +Force enable hardware loop in memcpy function. + +msched-prolog-epilog +Target Var(flag_sched_prolog_epilog) Init(1) +Permit scheduling of a function's prologue and epilogue sequence. + +mret-in-naked-func +Target Var(flag_ret_in_naked_func) Init(1) +Generate return instruction in naked function. + +malways-save-lp +Target Var(flag_always_save_lp) Init(0) +Always save $lp in the stack. + +munaligned-access +Target Report Var(flag_unaligned_access) Init(0) +Enable unaligned word and halfword accesses to packed data. + +minline-asm-r15 +Target Report Var(flag_inline_asm_r15) Init(0) +Allow use r15 for inline ASM. + +; --------------------------------------------------------------- +; The following options are designed for compatibility issue. +; Hopefully these obsolete options will be removed one day. + +mg +Target Undocumented Warn(%qs is deprecated and has no effect) +Obsolete option. Users SHOULD NOT use this option in the command line. + +mdx-regs +Target Undocumented Warn(%qs is deprecated and has no effect) +Obsolete option. Users SHOULD NOT use this option in the command line. + +mexpand-isr +Target Undocumented Warn(%qs is deprecated and has no effect) +Obsolete option. Users SHOULD NOT use this option in the command line. + +mcrt-cpp=yes +Target Undocumented Warn(%qs is deprecated and has no effect, use -mctor-dtor instead) +Obsolete option. Users SHOULD NOT use this option in the command line. + +mcrt-exit=yes +Target Undocumented Warn(%qs is deprecated and has no effect, use -mctor-dtor instead) +Obsolete option. Users SHOULD NOT use this option in the command line. + +mlib= +Target RejectNegative Joined Undocumented Warn(%qs is deprecated and has no effect) +Obsolete option. Users SHOULD NOT use this option in the command line. + +; --------------------------------------------------------------- +; The following options are designed for compatibility issue. +; Hopefully these obsolete options will be removed one day. + +mace +Target RejectNegative +Compile with Andes ACE. + +mace-s2s= +Target Joined RejectNegative +Argument for pass to Andes's ACE source-to-source translator. + + +; --------------------------------------------------------------- diff --git a/gcc/config/nds32/nds32_init.inc b/gcc/config/nds32/nds32_init.inc new file mode 100644 index 0000000..1084ad0 --- /dev/null +++ b/gcc/config/nds32/nds32_init.inc @@ -0,0 +1,43 @@ +/* + * nds32_init.inc + * + * NDS32 architecture startup assembler header file + * + */ + +.macro nds32_init + + ! Initialize GP for data access + la $gp, _SDA_BASE_ + +#if defined(__NDS32_EXT_EX9__) + ! Check HW for EX9 + mfsr $r0, $MSC_CFG + li $r1, (1 << 24) + and $r2, $r0, $r1 + beqz $r2, 1f + + ! Initialize the table base of EX9 instruction + la $r0, _ITB_BASE_ + mtusr $r0, $ITB +1: +#endif + +#if defined(__NDS32_EXT_FPU_DP__) || defined(__NDS32_EXT_FPU_SP__) + ! Enable FPU + mfsr $r0, $FUCOP_CTL + ori $r0, $r0, #0x1 + mtsr $r0, $FUCOP_CTL + dsb + + ! Enable denormalized flush-to-Zero mode + fmfcsr $r0 + ori $r0,$r0,#0x1000 + fmtcsr $r0 + dsb +#endif + + ! Initialize default stack pointer + la $sp, _stack + +.endm diff --git a/gcc/config/nds32/nds32_intrinsic.h b/gcc/config/nds32/nds32_intrinsic.h index 3e868dc..fef727b 100644 --- a/gcc/config/nds32/nds32_intrinsic.h +++ b/gcc/config/nds32/nds32_intrinsic.h @@ -26,12 +26,1383 @@ #ifndef _NDS32_INTRINSIC_H #define _NDS32_INTRINSIC_H +typedef signed char int8x4_t __attribute ((vector_size(4))); +typedef short int16x2_t __attribute ((vector_size(4))); +typedef int int32x2_t __attribute__((vector_size(8))); +typedef unsigned char uint8x4_t __attribute__ ((vector_size (4))); +typedef unsigned short uint16x2_t __attribute__ ((vector_size (4))); +typedef unsigned int uint32x2_t __attribute__((vector_size(8))); + +/* General instrinsic register names. */ enum nds32_intrinsic_registers { - __NDS32_REG_PSW__ = 1024, + __NDS32_REG_CPU_VER__ = 1024, + __NDS32_REG_ICM_CFG__, + __NDS32_REG_DCM_CFG__, + __NDS32_REG_MMU_CFG__, + __NDS32_REG_MSC_CFG__, + __NDS32_REG_MSC_CFG2__, + __NDS32_REG_CORE_ID__, + __NDS32_REG_FUCOP_EXIST__, + + __NDS32_REG_PSW__, __NDS32_REG_IPSW__, + __NDS32_REG_P_IPSW__, + __NDS32_REG_IVB__, + __NDS32_REG_EVA__, + __NDS32_REG_P_EVA__, __NDS32_REG_ITYPE__, - __NDS32_REG_IPC__ + __NDS32_REG_P_ITYPE__, + + __NDS32_REG_MERR__, + __NDS32_REG_IPC__, + __NDS32_REG_P_IPC__, + __NDS32_REG_OIPC__, + __NDS32_REG_P_P0__, + __NDS32_REG_P_P1__, + + __NDS32_REG_INT_MASK__, + __NDS32_REG_INT_MASK2__, + __NDS32_REG_INT_MASK3__, + __NDS32_REG_INT_PEND__, + __NDS32_REG_INT_PEND2__, + __NDS32_REG_INT_PEND3__, + __NDS32_REG_SP_USR__, + __NDS32_REG_SP_PRIV__, + __NDS32_REG_INT_PRI__, + __NDS32_REG_INT_PRI2__, + __NDS32_REG_INT_PRI3__, + __NDS32_REG_INT_PRI4__, + __NDS32_REG_INT_CTRL__, + __NDS32_REG_INT_TRIGGER__, + __NDS32_REG_INT_TRIGGER2__, + __NDS32_REG_INT_GPR_PUSH_DIS__, + + __NDS32_REG_MMU_CTL__, + __NDS32_REG_L1_PPTB__, + __NDS32_REG_TLB_VPN__, + __NDS32_REG_TLB_DATA__, + __NDS32_REG_TLB_MISC__, + __NDS32_REG_VLPT_IDX__, + __NDS32_REG_ILMB__, + __NDS32_REG_DLMB__, + + __NDS32_REG_CACHE_CTL__, + __NDS32_REG_HSMP_SADDR__, + __NDS32_REG_HSMP_EADDR__, + __NDS32_REG_SDZ_CTL__, + __NDS32_REG_N12MISC_CTL__, + __NDS32_REG_MISC_CTL__, + __NDS32_REG_ECC_MISC__, + + __NDS32_REG_BPC0__, + __NDS32_REG_BPC1__, + __NDS32_REG_BPC2__, + __NDS32_REG_BPC3__, + __NDS32_REG_BPC4__, + __NDS32_REG_BPC5__, + __NDS32_REG_BPC6__, + __NDS32_REG_BPC7__, + + __NDS32_REG_BPA0__, + __NDS32_REG_BPA1__, + __NDS32_REG_BPA2__, + __NDS32_REG_BPA3__, + __NDS32_REG_BPA4__, + __NDS32_REG_BPA5__, + __NDS32_REG_BPA6__, + __NDS32_REG_BPA7__, + + __NDS32_REG_BPAM0__, + __NDS32_REG_BPAM1__, + __NDS32_REG_BPAM2__, + __NDS32_REG_BPAM3__, + __NDS32_REG_BPAM4__, + __NDS32_REG_BPAM5__, + __NDS32_REG_BPAM6__, + __NDS32_REG_BPAM7__, + + __NDS32_REG_BPV0__, + __NDS32_REG_BPV1__, + __NDS32_REG_BPV2__, + __NDS32_REG_BPV3__, + __NDS32_REG_BPV4__, + __NDS32_REG_BPV5__, + __NDS32_REG_BPV6__, + __NDS32_REG_BPV7__, + + __NDS32_REG_BPCID0__, + __NDS32_REG_BPCID1__, + __NDS32_REG_BPCID2__, + __NDS32_REG_BPCID3__, + __NDS32_REG_BPCID4__, + __NDS32_REG_BPCID5__, + __NDS32_REG_BPCID6__, + __NDS32_REG_BPCID7__, + + __NDS32_REG_EDM_CFG__, + __NDS32_REG_EDMSW__, + __NDS32_REG_EDM_CTL__, + __NDS32_REG_EDM_DTR__, + __NDS32_REG_BPMTC__, + __NDS32_REG_DIMBR__, + + __NDS32_REG_TECR0__, + __NDS32_REG_TECR1__, + __NDS32_REG_PFMC0__, + __NDS32_REG_PFMC1__, + __NDS32_REG_PFMC2__, + __NDS32_REG_PFM_CTL__, + __NDS32_REG_PFT_CTL__, + __NDS32_REG_HSP_CTL__, + __NDS32_REG_SP_BOUND__, + __NDS32_REG_SP_BOUND_PRIV__, + __NDS32_REG_SP_BASE__, + __NDS32_REG_SP_BASE_PRIV__, + __NDS32_REG_FUCOP_CTL__, + __NDS32_REG_PRUSR_ACC_CTL__, + + __NDS32_REG_DMA_CFG__, + __NDS32_REG_DMA_GCSW__, + __NDS32_REG_DMA_CHNSEL__, + __NDS32_REG_DMA_ACT__, + __NDS32_REG_DMA_SETUP__, + __NDS32_REG_DMA_ISADDR__, + __NDS32_REG_DMA_ESADDR__, + __NDS32_REG_DMA_TCNT__, + __NDS32_REG_DMA_STATUS__, + __NDS32_REG_DMA_2DSET__, + __NDS32_REG_DMA_2DSCTL__, + __NDS32_REG_DMA_RCNT__, + __NDS32_REG_DMA_HSTATUS__, + + __NDS32_REG_PC__, + __NDS32_REG_SP_USR1__, + __NDS32_REG_SP_USR2__, + __NDS32_REG_SP_USR3__, + __NDS32_REG_SP_PRIV1__, + __NDS32_REG_SP_PRIV2__, + __NDS32_REG_SP_PRIV3__, + __NDS32_REG_BG_REGION__, + __NDS32_REG_SFCR__, + __NDS32_REG_SIGN__, + __NDS32_REG_ISIGN__, + __NDS32_REG_P_ISIGN__, + __NDS32_REG_IFC_LP__, + __NDS32_REG_ITB__ }; +/* The cctl subtype for intrinsic. */ +enum nds32_cctl_valck +{ + __NDS32_CCTL_L1D_VA_FILLCK__, + __NDS32_CCTL_L1D_VA_ULCK__, + __NDS32_CCTL_L1I_VA_FILLCK__, + __NDS32_CCTL_L1I_VA_ULCK__ +}; + +enum nds32_cctl_idxwbinv +{ + __NDS32_CCTL_L1D_IX_WBINVAL__, + __NDS32_CCTL_L1D_IX_INVAL__, + __NDS32_CCTL_L1D_IX_WB__, + __NDS32_CCTL_L1I_IX_INVAL__ +}; + +enum nds32_cctl_vawbinv +{ + __NDS32_CCTL_L1D_VA_INVAL__, + __NDS32_CCTL_L1D_VA_WB__, + __NDS32_CCTL_L1D_VA_WBINVAL__, + __NDS32_CCTL_L1I_VA_INVAL__ +}; + +enum nds32_cctl_idxread +{ + __NDS32_CCTL_L1D_IX_RTAG__, + __NDS32_CCTL_L1D_IX_RWD__, + __NDS32_CCTL_L1I_IX_RTAG__, + __NDS32_CCTL_L1I_IX_RWD__ +}; + +enum nds32_cctl_idxwrite +{ + __NDS32_CCTL_L1D_IX_WTAG__, + __NDS32_CCTL_L1D_IX_WWD__, + __NDS32_CCTL_L1I_IX_WTAG__, + __NDS32_CCTL_L1I_IX_WWD__ +}; + +enum nds32_dpref +{ + __NDS32_DPREF_SRD__, + __NDS32_DPREF_MRD__, + __NDS32_DPREF_SWR__, + __NDS32_DPREF_MWR__, + __NDS32_DPREF_PTE__, + __NDS32_DPREF_CLWR__ +}; + +/* ------------------------------------------------------------------------ */ + +/* Define interrupt number for intrinsic function. */ +#define NDS32_INT_H0 0 +#define NDS32_INT_H1 1 +#define NDS32_INT_H2 2 +#define NDS32_INT_H3 3 +#define NDS32_INT_H4 4 +#define NDS32_INT_H5 5 +#define NDS32_INT_H6 6 +#define NDS32_INT_H7 7 +#define NDS32_INT_H8 8 +#define NDS32_INT_H9 9 +#define NDS32_INT_H10 10 +#define NDS32_INT_H11 11 +#define NDS32_INT_H12 12 +#define NDS32_INT_H13 13 +#define NDS32_INT_H14 14 +#define NDS32_INT_H15 15 +#define NDS32_INT_H16 16 +#define NDS32_INT_H17 17 +#define NDS32_INT_H18 18 +#define NDS32_INT_H19 19 +#define NDS32_INT_H20 20 +#define NDS32_INT_H21 21 +#define NDS32_INT_H22 22 +#define NDS32_INT_H23 23 +#define NDS32_INT_H24 24 +#define NDS32_INT_H25 25 +#define NDS32_INT_H26 26 +#define NDS32_INT_H27 27 +#define NDS32_INT_H28 28 +#define NDS32_INT_H29 29 +#define NDS32_INT_H30 30 +#define NDS32_INT_H31 31 +#define NDS32_INT_H32 32 +#define NDS32_INT_H33 33 +#define NDS32_INT_H34 34 +#define NDS32_INT_H35 35 +#define NDS32_INT_H36 36 +#define NDS32_INT_H37 37 +#define NDS32_INT_H38 38 +#define NDS32_INT_H39 39 +#define NDS32_INT_H40 40 +#define NDS32_INT_H41 41 +#define NDS32_INT_H42 42 +#define NDS32_INT_H43 43 +#define NDS32_INT_H44 44 +#define NDS32_INT_H45 45 +#define NDS32_INT_H46 46 +#define NDS32_INT_H47 47 +#define NDS32_INT_H48 48 +#define NDS32_INT_H49 49 +#define NDS32_INT_H50 50 +#define NDS32_INT_H51 51 +#define NDS32_INT_H52 52 +#define NDS32_INT_H53 53 +#define NDS32_INT_H54 54 +#define NDS32_INT_H55 55 +#define NDS32_INT_H56 56 +#define NDS32_INT_H57 57 +#define NDS32_INT_H58 58 +#define NDS32_INT_H59 59 +#define NDS32_INT_H60 60 +#define NDS32_INT_H61 61 +#define NDS32_INT_H62 62 +#define NDS32_INT_H63 63 +#define NDS32_INT_SWI 64 +#define NDS32_INT_ALZ 65 +#define NDS32_INT_IDIVZE 66 +#define NDS32_INT_DSSIM 67 + +/* ------------------------------------------------------------------------ */ + +/* Define intrinsic register name macro for compatibility. */ +#define NDS32_SR_CPU_VER __NDS32_REG_CPU_VER__ +#define NDS32_SR_ICM_CFG __NDS32_REG_ICM_CFG__ +#define NDS32_SR_DCM_CFG __NDS32_REG_DCM_CFG__ +#define NDS32_SR_MMU_CFG __NDS32_REG_MMU_CFG__ +#define NDS32_SR_MSC_CFG __NDS32_REG_MSC_CFG__ +#define NDS32_SR_MSC_CFG2 __NDS32_REG_MSC_CFG2__ +#define NDS32_SR_CORE_ID __NDS32_REG_CORE_ID__ +#define NDS32_SR_FUCOP_EXIST __NDS32_REG_FUCOP_EXIST__ +#define NDS32_SR_PSW __NDS32_REG_PSW__ +#define NDS32_SR_IPSW __NDS32_REG_IPSW__ +#define NDS32_SR_P_IPSW __NDS32_REG_P_IPSW__ +#define NDS32_SR_IVB __NDS32_REG_IVB__ +#define NDS32_SR_EVA __NDS32_REG_EVA__ +#define NDS32_SR_P_EVA __NDS32_REG_P_EVA__ +#define NDS32_SR_ITYPE __NDS32_REG_ITYPE__ +#define NDS32_SR_P_ITYPE __NDS32_REG_P_ITYPE__ +#define NDS32_SR_MERR __NDS32_REG_MERR__ +#define NDS32_SR_IPC __NDS32_REG_IPC__ +#define NDS32_SR_P_IPC __NDS32_REG_P_IPC__ +#define NDS32_SR_OIPC __NDS32_REG_OIPC__ +#define NDS32_SR_P_P0 __NDS32_REG_P_P0__ +#define NDS32_SR_P_P1 __NDS32_REG_P_P1__ +#define NDS32_SR_INT_MASK __NDS32_REG_INT_MASK__ +#define NDS32_SR_INT_MASK2 __NDS32_REG_INT_MASK2__ +#define NDS32_SR_INT_MASK3 __NDS32_REG_INT_MASK3__ +#define NDS32_SR_INT_PEND __NDS32_REG_INT_PEND__ +#define NDS32_SR_INT_PEND2 __NDS32_REG_INT_PEND2__ +#define NDS32_SR_INT_PEND3 __NDS32_REG_INT_PEND3__ +#define NDS32_SR_SP_USR __NDS32_REG_SP_USR__ +#define NDS32_SR_SP_PRIV __NDS32_REG_SP_PRIV__ +#define NDS32_SR_INT_PRI __NDS32_REG_INT_PRI__ +#define NDS32_SR_INT_PRI2 __NDS32_REG_INT_PRI2__ +#define NDS32_SR_INT_PRI3 __NDS32_REG_INT_PRI3__ +#define NDS32_SR_INT_PRI4 __NDS32_REG_INT_PRI4__ +#define NDS32_SR_INT_CTRL __NDS32_REG_INT_CTRL__ +#define NDS32_SR_INT_TRIGGER __NDS32_REG_INT_TRIGGER__ +#define NDS32_SR_INT_TRIGGER2 __NDS32_REG_INT_TRIGGER2__ +#define NDS32_SR_INT_GPR_PUSH_DIS __NDS32_REG_INT_GPR_PUSH_DIS__ +#define NDS32_SR_MMU_CTL __NDS32_REG_MMU_CTL__ +#define NDS32_SR_L1_PPTB __NDS32_REG_L1_PPTB__ +#define NDS32_SR_TLB_VPN __NDS32_REG_TLB_VPN__ +#define NDS32_SR_TLB_DATA __NDS32_REG_TLB_DATA__ +#define NDS32_SR_TLB_MISC __NDS32_REG_TLB_MISC__ +#define NDS32_SR_VLPT_IDX __NDS32_REG_VLPT_IDX__ +#define NDS32_SR_ILMB __NDS32_REG_ILMB__ +#define NDS32_SR_DLMB __NDS32_REG_DLMB__ +#define NDS32_SR_CACHE_CTL __NDS32_REG_CACHE_CTL__ +#define NDS32_SR_HSMP_SADDR __NDS32_REG_HSMP_SADDR__ +#define NDS32_SR_HSMP_EADDR __NDS32_REG_HSMP_EADDR__ +#define NDS32_SR_SDZ_CTL __NDS32_REG_SDZ_CTL__ +#define NDS32_SR_N12MISC_CTL __NDS32_REG_N12MISC_CTL__ +#define NDS32_SR_MISC_CTL __NDS32_REG_MISC_CTL__ +#define NDS32_SR_ECC_MISC __NDS32_REG_ECC_MISC__ +#define NDS32_SR_BPC0 __NDS32_REG_BPC0__ +#define NDS32_SR_BPC1 __NDS32_REG_BPC1__ +#define NDS32_SR_BPC2 __NDS32_REG_BPC2__ +#define NDS32_SR_BPC3 __NDS32_REG_BPC3__ +#define NDS32_SR_BPC4 __NDS32_REG_BPC4__ +#define NDS32_SR_BPC5 __NDS32_REG_BPC5__ +#define NDS32_SR_BPC6 __NDS32_REG_BPC6__ +#define NDS32_SR_BPC7 __NDS32_REG_BPC7__ +#define NDS32_SR_BPA0 __NDS32_REG_BPA0__ +#define NDS32_SR_BPA1 __NDS32_REG_BPA1__ +#define NDS32_SR_BPA2 __NDS32_REG_BPA2__ +#define NDS32_SR_BPA3 __NDS32_REG_BPA3__ +#define NDS32_SR_BPA4 __NDS32_REG_BPA4__ +#define NDS32_SR_BPA5 __NDS32_REG_BPA5__ +#define NDS32_SR_BPA6 __NDS32_REG_BPA6__ +#define NDS32_SR_BPA7 __NDS32_REG_BPA7__ +#define NDS32_SR_BPAM0 __NDS32_REG_BPAM0__ +#define NDS32_SR_BPAM1 __NDS32_REG_BPAM1__ +#define NDS32_SR_BPAM2 __NDS32_REG_BPAM2__ +#define NDS32_SR_BPAM3 __NDS32_REG_BPAM3__ +#define NDS32_SR_BPAM4 __NDS32_REG_BPAM4__ +#define NDS32_SR_BPAM5 __NDS32_REG_BPAM5__ +#define NDS32_SR_BPAM6 __NDS32_REG_BPAM6__ +#define NDS32_SR_BPAM7 __NDS32_REG_BPAM7__ +#define NDS32_SR_BPV0 __NDS32_REG_BPV0__ +#define NDS32_SR_BPV1 __NDS32_REG_BPV1__ +#define NDS32_SR_BPV2 __NDS32_REG_BPV2__ +#define NDS32_SR_BPV3 __NDS32_REG_BPV3__ +#define NDS32_SR_BPV4 __NDS32_REG_BPV4__ +#define NDS32_SR_BPV5 __NDS32_REG_BPV5__ +#define NDS32_SR_BPV6 __NDS32_REG_BPV6__ +#define NDS32_SR_BPV7 __NDS32_REG_BPV7__ +#define NDS32_SR_BPCID0 __NDS32_REG_BPCID0__ +#define NDS32_SR_BPCID1 __NDS32_REG_BPCID1__ +#define NDS32_SR_BPCID2 __NDS32_REG_BPCID2__ +#define NDS32_SR_BPCID3 __NDS32_REG_BPCID3__ +#define NDS32_SR_BPCID4 __NDS32_REG_BPCID4__ +#define NDS32_SR_BPCID5 __NDS32_REG_BPCID5__ +#define NDS32_SR_BPCID6 __NDS32_REG_BPCID6__ +#define NDS32_SR_BPCID7 __NDS32_REG_BPCID7__ +#define NDS32_SR_EDM_CFG __NDS32_REG_EDM_CFG__ +#define NDS32_SR_EDMSW __NDS32_REG_EDMSW__ +#define NDS32_SR_EDM_CTL __NDS32_REG_EDM_CTL__ +#define NDS32_SR_EDM_DTR __NDS32_REG_EDM_DTR__ +#define NDS32_SR_BPMTC __NDS32_REG_BPMTC__ +#define NDS32_SR_DIMBR __NDS32_REG_DIMBR__ +#define NDS32_SR_TECR0 __NDS32_REG_TECR0__ +#define NDS32_SR_TECR1 __NDS32_REG_TECR1__ +#define NDS32_SR_PFMC0 __NDS32_REG_PFMC0__ +#define NDS32_SR_PFMC1 __NDS32_REG_PFMC1__ +#define NDS32_SR_PFMC2 __NDS32_REG_PFMC2__ +#define NDS32_SR_PFM_CTL __NDS32_REG_PFM_CTL__ +#define NDS32_SR_HSP_CTL __NDS32_REG_HSP_CTL__ +#define NDS32_SR_SP_BOUND __NDS32_REG_SP_BOUND__ +#define NDS32_SR_SP_BOUND_PRIV __NDS32_REG_SP_BOUND_PRIV__ +#define NDS32_SR_SP_BASE __NDS32_REG_SP_BASE__ +#define NDS32_SR_SP_BASE_PRIV __NDS32_REG_SP_BASE_PRIV__ +#define NDS32_SR_FUCOP_CTL __NDS32_REG_FUCOP_CTL__ +#define NDS32_SR_PRUSR_ACC_CTL __NDS32_REG_PRUSR_ACC_CTL__ +#define NDS32_SR_DMA_CFG __NDS32_REG_DMA_CFG__ +#define NDS32_SR_DMA_GCSW __NDS32_REG_DMA_GCSW__ +#define NDS32_SR_DMA_CHNSEL __NDS32_REG_DMA_CHNSEL__ +#define NDS32_SR_DMA_ACT __NDS32_REG_DMA_ACT__ +#define NDS32_SR_DMA_SETUP __NDS32_REG_DMA_SETUP__ +#define NDS32_SR_DMA_ISADDR __NDS32_REG_DMA_ISADDR__ +#define NDS32_SR_DMA_ESADDR __NDS32_REG_DMA_ESADDR__ +#define NDS32_SR_DMA_TCNT __NDS32_REG_DMA_TCNT__ +#define NDS32_SR_DMA_STATUS __NDS32_REG_DMA_STATUS__ +#define NDS32_SR_DMA_2DSET __NDS32_REG_DMA_2DSET__ +#define NDS32_SR_DMA_2DSCTL __NDS32_REG_DMA_2DSCTL__ +#define NDS32_SR_DMA_RCNT __NDS32_REG_DMA_RCNT__ +#define NDS32_SR_DMA_HSTATUS __NDS32_REG_DMA_HSTATUS__ +#define NDS32_SR_SP_USR1 __NDS32_REG_SP_USR1__ +#define NDS32_SR_SP_USR2 __NDS32_REG_SP_USR2__ +#define NDS32_SR_SP_USR3 __NDS32_REG_SP_USR3__ +#define NDS32_SR_SP_PRIV1 __NDS32_REG_SP_PRIV1__ +#define NDS32_SR_SP_PRIV2 __NDS32_REG_SP_PRIV2__ +#define NDS32_SR_SP_PRIV3 __NDS32_REG_SP_PRIV3__ +#define NDS32_SR_BG_REGION __NDS32_REG_BG_REGION__ +#define NDS32_SR_SFCR __NDS32_REG_SFCR__ +#define NDS32_SR_SIGN __NDS32_REG_SIGN__ +#define NDS32_SR_ISIGN __NDS32_REG_ISIGN__ +#define NDS32_SR_P_ISIGN __NDS32_REG_P_ISIGN__ + +#define NDS32_USR_PC __NDS32_REG_PC__ +#define NDS32_USR_DMA_CFG __NDS32_REG_DMA_CFG__ +#define NDS32_USR_DMA_GCSW __NDS32_REG_DMA_GCSW__ +#define NDS32_USR_DMA_CHNSEL __NDS32_REG_DMA_CHNSEL__ +#define NDS32_USR_DMA_ACT __NDS32_REG_DMA_ACT__ +#define NDS32_USR_DMA_SETUP __NDS32_REG_DMA_SETUP__ +#define NDS32_USR_DMA_ISADDR __NDS32_REG_DMA_ISADDR__ +#define NDS32_USR_DMA_ESADDR __NDS32_REG_DMA_ESADDR__ +#define NDS32_USR_DMA_TCNT __NDS32_REG_DMA_TCNT__ +#define NDS32_USR_DMA_STATUS __NDS32_REG_DMA_STATUS__ +#define NDS32_USR_DMA_2DSET __NDS32_REG_DMA_2DSET__ +#define NDS32_USR_DMA_2DSCTL __NDS32_REG_DMA_2DSCTL__ +#define NDS32_USR_PFMC0 __NDS32_REG_PFMC0__ +#define NDS32_USR_PFMC1 __NDS32_REG_PFMC1__ +#define NDS32_USR_PFMC2 __NDS32_REG_PFMC2__ +#define NDS32_USR_PFM_CTL __NDS32_REG_PFM_CTL__ +#define NDS32_USR_IFC_LP __NDS32_REG_IFC_LP__ +#define NDS32_USR_ITB __NDS32_REG_ITB__ + +#define NDS32_CCTL_L1D_VA_FILLCK __NDS32_CCTL_L1D_VA_FILLCK__ +#define NDS32_CCTL_L1D_VA_ULCK __NDS32_CCTL_L1D_VA_ULCK__ +#define NDS32_CCTL_L1I_VA_FILLCK __NDS32_CCTL_L1I_VA_FILLCK__ +#define NDS32_CCTL_L1I_VA_ULCK __NDS32_CCTL_L1I_VA_ULCK__ + +#define NDS32_CCTL_L1D_IX_WBINVAL __NDS32_CCTL_L1D_IX_WBINVAL__ +#define NDS32_CCTL_L1D_IX_INVAL __NDS32_CCTL_L1D_IX_INVAL__ +#define NDS32_CCTL_L1D_IX_WB __NDS32_CCTL_L1D_IX_WB__ +#define NDS32_CCTL_L1I_IX_INVAL __NDS32_CCTL_L1I_IX_INVAL__ + +#define NDS32_CCTL_L1D_VA_INVAL __NDS32_CCTL_L1D_VA_INVAL__ +#define NDS32_CCTL_L1D_VA_WB __NDS32_CCTL_L1D_VA_WB__ +#define NDS32_CCTL_L1D_VA_WBINVAL __NDS32_CCTL_L1D_VA_WBINVAL__ +#define NDS32_CCTL_L1I_VA_INVAL __NDS32_CCTL_L1I_VA_INVAL__ + +#define NDS32_CCTL_L1D_IX_RTAG __NDS32_CCTL_L1D_IX_RTAG__ +#define NDS32_CCTL_L1D_IX_RWD __NDS32_CCTL_L1D_IX_RWD__ +#define NDS32_CCTL_L1I_IX_RTAG __NDS32_CCTL_L1I_IX_RTAG__ +#define NDS32_CCTL_L1I_IX_RWD __NDS32_CCTL_L1I_IX_RWD__ + +#define NDS32_CCTL_L1D_IX_WTAG __NDS32_CCTL_L1D_IX_WTAG__ +#define NDS32_CCTL_L1D_IX_WWD __NDS32_CCTL_L1D_IX_WWD__ +#define NDS32_CCTL_L1I_IX_WTAG __NDS32_CCTL_L1I_IX_WTAG__ +#define NDS32_CCTL_L1I_IX_WWD __NDS32_CCTL_L1I_IX_WWD__ + +#define NDS32_DPREF_SRD __NDS32_DPREF_SRD__ +#define NDS32_DPREF_MRD __NDS32_DPREF_MRD__ +#define NDS32_DPREF_SWR __NDS32_DPREF_SWR__ +#define NDS32_DPREF_MWR __NDS32_DPREF_MWR__ +#define NDS32_DPREF_PTE __NDS32_DPREF_PTE__ +#define NDS32_DPREF_CLWR __NDS32_DPREF_CLWR__ + +/* ------------------------------------------------------------------------ */ + +/* Define user friendly macro. */ +#define SIGNATURE_BEGIN __nds32__signature_begin () +#define SIGNATURE_END __nds32__signature_end () + +/* Map __nds32__xxx() to __builtin_xxx() functions for compatibility. */ +#define __nds32__llw(a) \ + (__builtin_nds32_llw ((a))) +#define __nds32__lwup(a) \ + (__builtin_nds32_lwup ((a))) +#define __nds32__lbup(a) \ + (__builtin_nds32_lbup ((a))) +#define __nds32__scw(a, b) \ + (__builtin_nds32_scw ((a), (b))) +#define __nds32__swup(a, b) \ + (__builtin_nds32_swup ((a), (b))) +#define __nds32__sbup(a, b) \ + (__builtin_nds32_sbup ((a), (b))) + +#define __nds32__mfsr(srname) \ + (__builtin_nds32_mfsr ((srname))) +#define __nds32__mfusr(usrname) \ + (__builtin_nds32_mfusr ((usrname))) +#define __nds32__mtsr(val, srname) \ + (__builtin_nds32_mtsr ((val), (srname))) +#define __nds32__mtsr_isb(val, srname) \ + (__builtin_nds32_mtsr_isb ((val), (srname))) +#define __nds32__mtsr_dsb(val, srname) \ + (__builtin_nds32_mtsr_dsb ((val), (srname))) +#define __nds32__mtusr(val, usrname) \ + (__builtin_nds32_mtusr ((val), (usrname))) + +#define __nds32__break(swid) \ + (__builtin_nds32_break(swid)) +#define __nds32__cctlva_lck(subtype, va) \ + (__builtin_nds32_cctl_va_lck ((subtype), (va))) +#define __nds32__cctlidx_wbinval(subtype, idx) \ + (__builtin_nds32_cctl_idx_wbinval ((subtype), (idx))) +#define __nds32__cctlva_wbinval_alvl(subtype, va) \ + (__builtin_nds32_cctl_va_wbinval_la ((subtype), (va))) +#define __nds32__cctlva_wbinval_one_lvl(subtype, va) \ + (__builtin_nds32_cctl_va_wbinval_l1 ((subtype), (va))) +#define __nds32__cctlidx_read(subtype, idx) \ + (__builtin_nds32_cctl_idx_read ((subtype), (idx))) +#define __nds32__cctlidx_write(subtype, b, idxw) \ + (__builtin_nds32_cctl_idx_write ((subtype), (b), (idxw))) +#define __nds32__cctl_l1d_invalall() \ + (__builtin_nds32_cctl_l1d_invalall()) +#define __nds32__cctl_l1d_wball_alvl() \ + (__builtin_nds32_cctl_l1d_wball_alvl()) +#define __nds32__cctl_l1d_wball_one_lvl() \ + (__builtin_nds32_cctl_l1d_wball_one_lvl()) + +#define __nds32__dsb() \ + (__builtin_nds32_dsb()) +#define __nds32__isb() \ + (__builtin_nds32_isb()) +#define __nds32__msync_store() \ + (__builtin_nds32_msync_store()) +#define __nds32__msync_all() \ + (__builtin_nds32_msync_all()) +#define __nds32__nop() \ + (__builtin_nds32_nop()) + +#define __nds32__standby_wait_done() \ + (__builtin_nds32_standby_wait_done()) +#define __nds32__standby_no_wake_grant() \ + (__builtin_nds32_standby_no_wake_grant()) +#define __nds32__standby_wake_grant() \ + (__builtin_nds32_standby_wake_grant()) +#define __nds32__schedule_barrier() \ + (__builtin_nds32_schedule_barrier()) +#define __nds32__setend_big() \ + (__builtin_nds32_setend_big()) +#define __nds32__setend_little() \ + (__builtin_nds32_setend_little()) +#define __nds32__setgie_en() \ + (__builtin_nds32_setgie_en()) +#define __nds32__setgie_dis() \ + (__builtin_nds32_setgie_dis()) + +#define __nds32__jr_itoff(a) \ + (__builtin_nds32_jr_itoff ((a))) +#define __nds32__jr_toff(a) \ + (__builtin_nds32_jr_toff ((a))) +#define __nds32__jral_iton(a) \ + (__builtin_nds32_jral_iton ((a))) +#define __nds32__jral_ton(a) \ + (__builtin_nds32_jral_ton ((a))) +#define __nds32__ret_itoff(a) \ + (__builtin_nds32_ret_itoff ((a))) +#define __nds32__ret_toff(a) \ + (__builtin_nds32_ret_toff ((a))) +#define __nds32__svs(a, b) \ + (__builtin_nds32_svs ((a), (b))) +#define __nds32__sva(a, b) \ + (__builtin_nds32_sva ((a), (b))) +#define __nds32__dpref_qw(a, b, subtype) \ + (__builtin_nds32_dpref_qw ((a), (b), (subtype))) +#define __nds32__dpref_hw(a, b, subtype) \ + (__builtin_nds32_dpref_hw ((a), (b), (subtype))) +#define __nds32__dpref_w(a, b, subtype) \ + (__builtin_nds32_dpref_w ((a), (b), (subtype))) +#define __nds32__dpref_dw(a, b, subtype) \ + (__builtin_nds32_dpref_dw ((a), (b), (subtype))) + +#define __nds32__teqz(a, swid) \ + (__builtin_nds32_teqz ((a), (swid))) +#define __nds32__tnez(a, swid) \ + ( __builtin_nds32_tnez ((a), (swid))) +#define __nds32__trap(swid) \ + (__builtin_nds32_trap ((swid))) +#define __nds32__isync(a) \ + (__builtin_nds32_isync ((a))) +#define __nds32__rotr(val, ror) \ + (__builtin_nds32_rotr ((val), (ror))) +#define __nds32__wsbh(a) \ + (__builtin_nds32_wsbh ((a))) +#define __nds32__syscall(a) \ + (__builtin_nds32_syscall ((a))) +#define __nds32__return_address() \ + (__builtin_nds32_return_address()) +#define __nds32__get_current_sp() \ + (__builtin_nds32_get_current_sp()) +#define __nds32__set_current_sp(a) \ + (__builtin_nds32_set_current_sp ((a))) +#define __nds32__abs(a) \ + (__builtin_nds32_pe_abs ((a))) +#define __nds32__ave(a, b) \ + (__builtin_nds32_pe_ave ((a), (b))) +#define __nds32__bclr(a, pos) \ + (__builtin_nds32_pe_bclr ((a), (pos))) +#define __nds32__bset(a, pos) \ + (__builtin_nds32_pe_bset ((a), (pos))) +#define __nds32__btgl(a, pos) \ + (__builtin_nds32_pe_btgl ((a), (pos))) +#define __nds32__btst(a, pos) \ + (__builtin_nds32_pe_btst ((a), (pos))) + +#define __nds32__clip(a, imm) \ + (__builtin_nds32_pe_clip ((a), (imm))) +#define __nds32__clips(a, imm) \ + (__builtin_nds32_pe_clips ((a), (imm))) +#define __nds32__clz(a) \ + (__builtin_nds32_pe_clz ((a))) +#define __nds32__clo(a) \ + (__builtin_nds32_pe_clo ((a))) +#define __nds32__bse(r, a, b) \ + (__builtin_nds32_pe2_bse ((r), (a), (b))) +#define __nds32__bsp(r, a, b) \ + (__builtin_nds32_pe2_bsp ((r), (a), (b))) +#define __nds32__pbsad(a, b) \ + (__builtin_nds32_pe2_pbsad ((a), (b))) +#define __nds32__pbsada(acc, a, b) \ + (__builtin_nds32_pe2_pbsada ((acc), (a), (b))) + +#define __nds32__ffb(a, b) \ + (__builtin_nds32_se_ffb ((a), (b))) +#define __nds32__ffmism(a, b) \ + (__builtin_nds32_se_ffmism ((a), (b))) +#define __nds32__flmism(a, b) \ + (__builtin_nds32_se_flmism ((a), (b))) +#define __nds32__fcpynsd(a, b) \ + (__builtin_nds32_fcpynsd ((a), (b))) +#define __nds32__fcpynss(a, b) \ + (__builtin_nds32_fcpynss ((a), (b))) +#define __nds32__fcpysd(a, b) \ + (__builtin_nds32_fcpysd ((a), (b))) +#define __nds32__fcpyss(a, b) \ + (__builtin_nds32_fcpyss ((a), (b))) +#define __nds32__fmfcsr() \ + (__builtin_nds32_fmfcsr()) +#define __nds32__fmtcsr(fpcsr) \ + (__builtin_nds32_fmtcsr ((fpcsr))) +#define __nds32__fmfcfg() \ + (__builtin_nds32_fmfcfg()) + +#define __nds32__tlbop_trd(a) \ + (__builtin_nds32_tlbop_trd ((a))) +#define __nds32__tlbop_twr(a) \ + (__builtin_nds32_tlbop_twr ((a))) +#define __nds32__tlbop_rwr(a) \ + (__builtin_nds32_tlbop_rwr ((a))) +#define __nds32__tlbop_rwlk(a) \ + (__builtin_nds32_tlbop_rwlk ((a))) +#define __nds32__tlbop_unlk(a) \ + (__builtin_nds32_tlbop_unlk ((a))) +#define __nds32__tlbop_pb(a) \ + (__builtin_nds32_tlbop_pb ((a))) +#define __nds32__tlbop_inv(a) \ + (__builtin_nds32_tlbop_inv ((a))) +#define __nds32__tlbop_flua() \ +(__builtin_nds32_tlbop_flua()) + +#define __nds32__kaddw(a, b) \ + (__builtin_nds32_kaddw ((a), (b))) +#define __nds32__kaddh(a, b) \ + (__builtin_nds32_kaddh ((a), (b))) +#define __nds32__ksubw(a, b) \ + (__builtin_nds32_ksubw ((a), (b))) +#define __nds32__ksubh(a, b) \ + (__builtin_nds32_ksubh ((a), (b))) +#define __nds32__kdmbb(a, b) \ + (__builtin_nds32_kdmbb ((a), (b))) +#define __nds32__v_kdmbb(a, b) \ + (__builtin_nds32_v_kdmbb ((a), (b))) +#define __nds32__kdmbt(a, b) \ + (__builtin_nds32_kdmbt ((a), (b))) +#define __nds32__v_kdmbt(a, b) \ + (__builtin_nds32_v_kdmbt ((a), (b))) +#define __nds32__kdmtb(a, b) \ + (__builtin_nds32_kdmtb ((a), (b))) +#define __nds32__v_kdmtb(a, b) \ + (__builtin_nds32_v_kdmtb ((a), (b))) +#define __nds32__kdmtt(a, b) \ + (__builtin_nds32_kdmtt ((a), (b))) +#define __nds32__v_kdmtt(a, b) \ + (__builtin_nds32_v_kdmtt ((a), (b))) +#define __nds32__khmbb(a, b) \ + (__builtin_nds32_khmbb ((a), (b))) +#define __nds32__v_khmbb(a, b) \ + (__builtin_nds32_v_khmbb ((a), (b))) +#define __nds32__khmbt(a, b) \ + (__builtin_nds32_khmbt ((a), (b))) +#define __nds32__v_khmbt(a, b) \ + (__builtin_nds32_v_khmbt ((a), (b))) +#define __nds32__khmtb(a, b) \ + (__builtin_nds32_khmtb ((a), (b))) +#define __nds32__v_khmtb(a, b) \ + (__builtin_nds32_v_khmtb ((a), (b))) +#define __nds32__khmtt(a, b) \ + (__builtin_nds32_khmtt ((a), (b))) +#define __nds32__v_khmtt(a, b) \ + (__builtin_nds32_v_khmtt ((a), (b))) +#define __nds32__kslraw(a, b) \ + (__builtin_nds32_kslraw ((a), (b))) +#define __nds32__kslraw_u(a, b) \ + (__builtin_nds32_kslraw_u ((a), (b))) + +#define __nds32__rdov() \ + (__builtin_nds32_rdov()) +#define __nds32__clrov() \ + (__builtin_nds32_clrov()) +#define __nds32__gie_dis() \ + (__builtin_nds32_gie_dis()) +#define __nds32__gie_en() \ + (__builtin_nds32_gie_en()) +#define __nds32__enable_int(a) \ + (__builtin_nds32_enable_int ((a))) +#define __nds32__disable_int(a) \ + (__builtin_nds32_disable_int ((a))) +#define __nds32__set_pending_swint() \ + (__builtin_nds32_set_pending_swint()) +#define __nds32__clr_pending_swint() \ + (__builtin_nds32_clr_pending_swint()) +#define __nds32__clr_pending_hwint(a) \ + (__builtin_nds32_clr_pending_hwint(a)) +#define __nds32__get_all_pending_int() \ + (__builtin_nds32_get_all_pending_int()) +#define __nds32__get_pending_int(a) \ + (__builtin_nds32_get_pending_int ((a))) +#define __nds32__set_int_priority(a, b) \ + (__builtin_nds32_set_int_priority ((a), (b))) +#define __nds32__get_int_priority(a) \ + (__builtin_nds32_get_int_priority ((a))) +#define __nds32__set_trig_type_level(a) \ + (__builtin_nds32_set_trig_level(a)) +#define __nds32__set_trig_type_edge(a) \ + (__builtin_nds32_set_trig_edge(a)) +#define __nds32__get_trig_type(a) \ + (__builtin_nds32_get_trig_type ((a))) + +#define __nds32__get_unaligned_hw(a) \ + (__builtin_nds32_unaligned_load_hw ((a))) +#define __nds32__get_unaligned_w(a) \ + (__builtin_nds32_unaligned_load_w ((a))) +#define __nds32__get_unaligned_dw(a) \ + (__builtin_nds32_unaligned_load_dw ((a))) +#define __nds32__put_unaligned_hw(a, data) \ + (__builtin_nds32_unaligned_store_hw ((a), (data))) +#define __nds32__put_unaligned_w(a, data) \ + (__builtin_nds32_unaligned_store_w ((a), (data))) +#define __nds32__put_unaligned_dw(a, data) \ + (__builtin_nds32_unaligned_store_dw ((a), (data))) + +#define __nds32__signature_begin() \ + (__builtin_nds32_signature_begin ()) +#define __nds32__signature_end() \ + (__builtin_nds32_signature_end ()) + +#define __nds32__add16(a, b) \ + (__builtin_nds32_add16 ((a), (b))) +#define __nds32__v_uadd16(a, b) \ + (__builtin_nds32_v_uadd16 ((a), (b))) +#define __nds32__v_sadd16(a, b) \ + (__builtin_nds32_v_sadd16 ((a), (b))) +#define __nds32__radd16(a, b) \ + (__builtin_nds32_radd16 ((a), (b))) +#define __nds32__v_radd16(a, b) \ + (__builtin_nds32_v_radd16 ((a), (b))) +#define __nds32__uradd16(a, b) \ + (__builtin_nds32_uradd16 ((a), (b))) +#define __nds32__v_uradd16(a, b) \ + (__builtin_nds32_v_uradd16 ((a), (b))) +#define __nds32__kadd16(a, b) \ + (__builtin_nds32_kadd16 ((a), (b))) +#define __nds32__v_kadd16(a, b) \ + (__builtin_nds32_v_kadd16 ((a), (b))) +#define __nds32__ukadd16(a, b) \ + (__builtin_nds32_ukadd16 ((a), (b))) +#define __nds32__v_ukadd16(a, b) \ + (__builtin_nds32_v_ukadd16 ((a), (b))) +#define __nds32__sub16(a, b) \ + (__builtin_nds32_sub16 ((a), (b))) +#define __nds32__v_usub16(a, b) \ + (__builtin_nds32_v_usub16 ((a), (b))) +#define __nds32__v_ssub16(a, b) \ + (__builtin_nds32_v_ssub16 ((a), (b))) +#define __nds32__rsub16(a, b) \ + (__builtin_nds32_rsub16 ((a), (b))) +#define __nds32__v_rsub16(a, b) \ + (__builtin_nds32_v_rsub16 ((a), (b))) +#define __nds32__ursub16(a, b) \ + (__builtin_nds32_ursub16 ((a), (b))) +#define __nds32__v_ursub16(a, b) \ + (__builtin_nds32_v_ursub16 ((a), (b))) +#define __nds32__ksub16(a, b) \ + (__builtin_nds32_ksub16 ((a), (b))) +#define __nds32__v_ksub16(a, b) \ + (__builtin_nds32_v_ksub16 ((a), (b))) +#define __nds32__uksub16(a, b) \ + (__builtin_nds32_uksub16 ((a), (b))) +#define __nds32__v_uksub16(a, b) \ + (__builtin_nds32_v_uksub16 ((a), (b))) +#define __nds32__cras16(a, b) \ + (__builtin_nds32_cras16 ((a), (b))) +#define __nds32__v_ucras16(a, b) \ + (__builtin_nds32_v_ucras16 ((a), (b))) +#define __nds32__v_scras16(a, b) \ + (__builtin_nds32_v_scras16 ((a), (b))) +#define __nds32__rcras16(a, b) \ + (__builtin_nds32_rcras16 ((a), (b))) +#define __nds32__v_rcras16(a, b) \ + (__builtin_nds32_v_rcras16 ((a), (b))) +#define __nds32__urcras16(a, b) \ + (__builtin_nds32_urcras16 ((a), (b))) +#define __nds32__v_urcras16(a, b) \ + (__builtin_nds32_v_urcras16 ((a), (b))) +#define __nds32__kcras16(a, b) \ + (__builtin_nds32_kcras16 ((a), (b))) +#define __nds32__v_kcras16(a, b) \ + (__builtin_nds32_v_kcras16 ((a), (b))) +#define __nds32__ukcras16(a, b) \ + (__builtin_nds32_ukcras16 ((a), (b))) +#define __nds32__v_ukcras16(a, b) \ + (__builtin_nds32_v_ukcras16 ((a), (b))) +#define __nds32__crsa16(a, b) \ + (__builtin_nds32_crsa16 ((a), (b))) +#define __nds32__v_ucrsa16(a, b) \ + (__builtin_nds32_v_ucrsa16 ((a), (b))) +#define __nds32__v_scrsa16(a, b) \ + (__builtin_nds32_v_scrsa16 ((a), (b))) +#define __nds32__rcrsa16(a, b) \ + (__builtin_nds32_rcrsa16 ((a), (b))) +#define __nds32__v_rcrsa16(a, b) \ + (__builtin_nds32_v_rcrsa16 ((a), (b))) +#define __nds32__urcrsa16(a, b) \ + (__builtin_nds32_urcrsa16 ((a), (b))) +#define __nds32__v_urcrsa16(a, b) \ + (__builtin_nds32_v_urcrsa16 ((a), (b))) +#define __nds32__kcrsa16(a, b) \ + (__builtin_nds32_kcrsa16 ((a), (b))) +#define __nds32__v_kcrsa16(a, b) \ + (__builtin_nds32_v_kcrsa16 ((a), (b))) +#define __nds32__ukcrsa16(a, b) \ + (__builtin_nds32_ukcrsa16 ((a), (b))) +#define __nds32__v_ukcrsa16(a, b) \ + (__builtin_nds32_v_ukcrsa16 ((a), (b))) + +#define __nds32__add8(a, b) \ + (__builtin_nds32_add8 ((a), (b))) +#define __nds32__v_uadd8(a, b) \ + (__builtin_nds32_v_uadd8 ((a), (b))) +#define __nds32__v_sadd8(a, b) \ + (__builtin_nds32_v_sadd8 ((a), (b))) +#define __nds32__radd8(a, b) \ + (__builtin_nds32_radd8 ((a), (b))) +#define __nds32__v_radd8(a, b) \ + (__builtin_nds32_v_radd8 ((a), (b))) +#define __nds32__uradd8(a, b) \ + (__builtin_nds32_uradd8 ((a), (b))) +#define __nds32__v_uradd8(a, b) \ + (__builtin_nds32_v_uradd8 ((a), (b))) +#define __nds32__kadd8(a, b) \ + (__builtin_nds32_kadd8 ((a), (b))) +#define __nds32__v_kadd8(a, b) \ + (__builtin_nds32_v_kadd8 ((a), (b))) +#define __nds32__ukadd8(a, b) \ + (__builtin_nds32_ukadd8 ((a), (b))) +#define __nds32__v_ukadd8(a, b) \ + (__builtin_nds32_v_ukadd8 ((a), (b))) +#define __nds32__sub8(a, b) \ + (__builtin_nds32_sub8 ((a), (b))) +#define __nds32__v_usub8(a, b) \ + (__builtin_nds32_v_usub8 ((a), (b))) +#define __nds32__v_ssub8(a, b) \ + (__builtin_nds32_v_ssub8 ((a), (b))) +#define __nds32__rsub8(a, b) \ + (__builtin_nds32_rsub8 ((a), (b))) +#define __nds32__v_rsub8(a, b) \ + (__builtin_nds32_v_rsub8 ((a), (b))) +#define __nds32__ursub8(a, b) \ + (__builtin_nds32_ursub8 ((a), (b))) +#define __nds32__v_ursub8(a, b) \ + (__builtin_nds32_v_ursub8 ((a), (b))) +#define __nds32__ksub8(a, b) \ + (__builtin_nds32_ksub8 ((a), (b))) +#define __nds32__v_ksub8(a, b) \ + (__builtin_nds32_v_ksub8 ((a), (b))) +#define __nds32__uksub8(a, b) \ + (__builtin_nds32_uksub8 ((a), (b))) +#define __nds32__v_uksub8(a, b) \ + (__builtin_nds32_v_uksub8 ((a), (b))) + +#define __nds32__sra16(a, b) \ + (__builtin_nds32_sra16 ((a), (b))) +#define __nds32__v_sra16(a, b) \ + (__builtin_nds32_v_sra16 ((a), (b))) +#define __nds32__sra16_u(a, b) \ + (__builtin_nds32_sra16_u ((a), (b))) +#define __nds32__v_sra16_u(a, b) \ + (__builtin_nds32_v_sra16_u ((a), (b))) +#define __nds32__srl16(a, b) \ + (__builtin_nds32_srl16 ((a), (b))) +#define __nds32__v_srl16(a, b) \ + (__builtin_nds32_v_srl16 ((a), (b))) +#define __nds32__srl16_u(a, b) \ + (__builtin_nds32_srl16_u ((a), (b))) +#define __nds32__v_srl16_u(a, b) \ + (__builtin_nds32_v_srl16_u ((a), (b))) +#define __nds32__sll16(a, b) \ + (__builtin_nds32_sll16 ((a), (b))) +#define __nds32__v_sll16(a, b) \ + (__builtin_nds32_v_sll16 ((a), (b))) +#define __nds32__ksll16(a, b) \ + (__builtin_nds32_ksll16 ((a), (b))) +#define __nds32__v_ksll16(a, b) \ + (__builtin_nds32_v_ksll16 ((a), (b))) +#define __nds32__kslra16(a, b) \ + (__builtin_nds32_kslra16 ((a), (b))) +#define __nds32__v_kslra16(a, b) \ + (__builtin_nds32_v_kslra16 ((a), (b))) +#define __nds32__kslra16_u(a, b) \ + (__builtin_nds32_kslra16_u ((a), (b))) +#define __nds32__v_kslra16_u(a, b) \ + (__builtin_nds32_v_kslra16_u ((a), (b))) + +#define __nds32__cmpeq16(a, b) \ + (__builtin_nds32_cmpeq16 ((a), (b))) +#define __nds32__v_scmpeq16(a, b) \ + (__builtin_nds32_v_scmpeq16 ((a), (b))) +#define __nds32__v_ucmpeq16(a, b) \ + (__builtin_nds32_v_ucmpeq16 ((a), (b))) +#define __nds32__scmplt16(a, b) \ + (__builtin_nds32_scmplt16 ((a), (b))) +#define __nds32__v_scmplt16(a, b) \ + (__builtin_nds32_v_scmplt16 ((a), (b))) +#define __nds32__scmple16(a, b) \ + (__builtin_nds32_scmple16 ((a), (b))) +#define __nds32__v_scmple16(a, b) \ + (__builtin_nds32_v_scmple16 ((a), (b))) +#define __nds32__ucmplt16(a, b) \ + (__builtin_nds32_ucmplt16 ((a), (b))) +#define __nds32__v_ucmplt16(a, b) \ + (__builtin_nds32_v_ucmplt16 ((a), (b))) +#define __nds32__ucmple16(a, b) \ + (__builtin_nds32_ucmple16 ((a), (b))) +#define __nds32__v_ucmple16(a, b) \ + (__builtin_nds32_v_ucmple16 ((a), (b))) + +#define __nds32__cmpeq8(a, b) \ + (__builtin_nds32_cmpeq8 ((a), (b))) +#define __nds32__v_scmpeq8(a, b) \ + (__builtin_nds32_v_scmpeq8 ((a), (b))) +#define __nds32__v_ucmpeq8(a, b) \ + (__builtin_nds32_v_ucmpeq8 ((a), (b))) +#define __nds32__scmplt8(a, b) \ + (__builtin_nds32_scmplt8 ((a), (b))) +#define __nds32__v_scmplt8(a, b) \ + (__builtin_nds32_v_scmplt8 ((a), (b))) +#define __nds32__scmple8(a, b) \ + (__builtin_nds32_scmple8 ((a), (b))) +#define __nds32__v_scmple8(a, b) \ + (__builtin_nds32_v_scmple8 ((a), (b))) +#define __nds32__ucmplt8(a, b) \ + (__builtin_nds32_ucmplt8 ((a), (b))) +#define __nds32__v_ucmplt8(a, b) \ + (__builtin_nds32_v_ucmplt8 ((a), (b))) +#define __nds32__ucmple8(a, b) \ + (__builtin_nds32_ucmple8 ((a), (b))) +#define __nds32__v_ucmple8(a, b) \ + (__builtin_nds32_v_ucmple8 ((a), (b))) + +#define __nds32__smin16(a, b) \ + (__builtin_nds32_smin16 ((a), (b))) +#define __nds32__v_smin16(a, b) \ + (__builtin_nds32_v_smin16 ((a), (b))) +#define __nds32__umin16(a, b) \ + (__builtin_nds32_umin16 ((a), (b))) +#define __nds32__v_umin16(a, b) \ + (__builtin_nds32_v_umin16 ((a), (b))) +#define __nds32__smax16(a, b) \ + (__builtin_nds32_smax16 ((a), (b))) +#define __nds32__v_smax16(a, b) \ + (__builtin_nds32_v_smax16 ((a), (b))) +#define __nds32__umax16(a, b) \ + (__builtin_nds32_umax16 ((a), (b))) +#define __nds32__v_umax16(a, b) \ + (__builtin_nds32_v_umax16 ((a), (b))) +#define __nds32__sclip16(a, b) \ + (__builtin_nds32_sclip16 ((a), (b))) +#define __nds32__v_sclip16(a, b) \ + (__builtin_nds32_v_sclip16 ((a), (b))) +#define __nds32__uclip16(a, b) \ + (__builtin_nds32_uclip16 ((a), (b))) +#define __nds32__v_uclip16(a, b) \ + (__builtin_nds32_v_uclip16 ((a), (b))) +#define __nds32__khm16(a, b) \ + (__builtin_nds32_khm16 ((a), (b))) +#define __nds32__v_khm16(a, b) \ + (__builtin_nds32_v_khm16 ((a), (b))) +#define __nds32__khmx16(a, b) \ + (__builtin_nds32_khmx16 ((a), (b))) +#define __nds32__v_khmx16(a, b) \ + (__builtin_nds32_v_khmx16 ((a), (b))) +#define __nds32__kabs16(a) \ + (__builtin_nds32_kabs16 ((a))) +#define __nds32__v_kabs16(a) \ + (__builtin_nds32_v_kabs16 ((a))) + +#define __nds32__smin8(a, b) \ + (__builtin_nds32_smin8 ((a), (b))) +#define __nds32__v_smin8(a, b) \ + (__builtin_nds32_v_smin8 ((a), (b))) +#define __nds32__umin8(a, b) \ + (__builtin_nds32_umin8 ((a), (b))) +#define __nds32__v_umin8(a, b) \ + (__builtin_nds32_v_umin8 ((a), (b))) +#define __nds32__smax8(a, b) \ + (__builtin_nds32_smax8 ((a), (b))) +#define __nds32__v_smax8(a, b) \ + (__builtin_nds32_v_smax8 ((a), (b))) +#define __nds32__umax8(a, b) \ + (__builtin_nds32_umax8 ((a), (b))) +#define __nds32__v_umax8(a, b) \ + (__builtin_nds32_v_umax8 ((a), (b))) +#define __nds32__kabs8(a) \ + (__builtin_nds32_kabs8 ((a))) +#define __nds32__v_kabs8(a) \ + (__builtin_nds32_v_kabs8 ((a))) + +#define __nds32__sunpkd810(a) \ + (__builtin_nds32_sunpkd810 ((a))) +#define __nds32__v_sunpkd810(a) \ + (__builtin_nds32_v_sunpkd810 ((a))) +#define __nds32__sunpkd820(a) \ + (__builtin_nds32_sunpkd820 ((a))) +#define __nds32__v_sunpkd820(a) \ + (__builtin_nds32_v_sunpkd820 ((a))) +#define __nds32__sunpkd830(a) \ + (__builtin_nds32_sunpkd830 ((a))) +#define __nds32__v_sunpkd830(a) \ + (__builtin_nds32_v_sunpkd830 ((a))) +#define __nds32__sunpkd831(a) \ + (__builtin_nds32_sunpkd831 ((a))) +#define __nds32__v_sunpkd831(a) \ + (__builtin_nds32_v_sunpkd831 ((a))) +#define __nds32__zunpkd810(a) \ + (__builtin_nds32_zunpkd810 ((a))) +#define __nds32__v_zunpkd810(a) \ + (__builtin_nds32_v_zunpkd810 ((a))) +#define __nds32__zunpkd820(a) \ + (__builtin_nds32_zunpkd820 ((a))) +#define __nds32__v_zunpkd820(a) \ + (__builtin_nds32_v_zunpkd820 ((a))) +#define __nds32__zunpkd830(a) \ + (__builtin_nds32_zunpkd830 ((a))) +#define __nds32__v_zunpkd830(a) \ + (__builtin_nds32_v_zunpkd830 ((a))) +#define __nds32__zunpkd831(a) \ + (__builtin_nds32_zunpkd831 ((a))) +#define __nds32__v_zunpkd831(a) \ + (__builtin_nds32_v_zunpkd831 ((a))) + +#define __nds32__raddw(a, b) \ + (__builtin_nds32_raddw ((a), (b))) +#define __nds32__uraddw(a, b) \ + (__builtin_nds32_uraddw ((a), (b))) +#define __nds32__rsubw(a, b) \ + (__builtin_nds32_rsubw ((a), (b))) +#define __nds32__ursubw(a, b) \ + (__builtin_nds32_ursubw ((a), (b))) + +#define __nds32__sra_u(a, b) \ + (__builtin_nds32_sra_u ((a), (b))) +#define __nds32__ksll(a, b) \ + (__builtin_nds32_ksll ((a), (b))) +#define __nds32__pkbb16(a, b) \ + (__builtin_nds32_pkbb16 ((a), (b))) +#define __nds32__v_pkbb16(a, b) \ + (__builtin_nds32_v_pkbb16 ((a), (b))) +#define __nds32__pkbt16(a, b) \ + (__builtin_nds32_pkbt16 ((a), (b))) +#define __nds32__v_pkbt16(a, b) \ + (__builtin_nds32_v_pkbt16 ((a), (b))) +#define __nds32__pktb16(a, b) \ + (__builtin_nds32_pktb16 ((a), (b))) +#define __nds32__v_pktb16(a, b) \ + (__builtin_nds32_v_pktb16 ((a), (b))) +#define __nds32__pktt16(a, b) \ + (__builtin_nds32_pktt16 ((a), (b))) +#define __nds32__v_pktt16(a, b) \ + (__builtin_nds32_v_pktt16 ((a), (b))) + +#define __nds32__smmul(a, b) \ + (__builtin_nds32_smmul ((a), (b))) +#define __nds32__smmul_u(a, b) \ + (__builtin_nds32_smmul_u ((a), (b))) +#define __nds32__kmmac(r, a, b) \ + (__builtin_nds32_kmmac ((r), (a), (b))) +#define __nds32__kmmac_u(r, a, b) \ + (__builtin_nds32_kmmac_u ((r), (a), (b))) +#define __nds32__kmmsb(r, a, b) \ + (__builtin_nds32_kmmsb ((r), (a), (b))) +#define __nds32__kmmsb_u(r, a, b) \ + (__builtin_nds32_kmmsb_u ((r), (a), (b))) +#define __nds32__kwmmul(a, b) \ + (__builtin_nds32_kwmmul ((a), (b))) +#define __nds32__kwmmul_u(a, b) \ + (__builtin_nds32_kwmmul_u ((a), (b))) + +#define __nds32__smmwb(a, b) \ + (__builtin_nds32_smmwb ((a), (b))) +#define __nds32__v_smmwb(a, b) \ + (__builtin_nds32_v_smmwb ((a), (b))) +#define __nds32__smmwb_u(a, b) \ + (__builtin_nds32_smmwb_u ((a), (b))) +#define __nds32__v_smmwb_u(a, b) \ + (__builtin_nds32_v_smmwb_u ((a), (b))) +#define __nds32__smmwt(a, b) \ + (__builtin_nds32_smmwt ((a), (b))) +#define __nds32__v_smmwt(a, b) \ + (__builtin_nds32_v_smmwt ((a), (b))) +#define __nds32__smmwt_u(a, b) \ + (__builtin_nds32_smmwt_u ((a), (b))) +#define __nds32__v_smmwt_u(a, b) \ + (__builtin_nds32_v_smmwt_u ((a), (b))) +#define __nds32__kmmawb(r, a, b) \ + (__builtin_nds32_kmmawb ((r), (a), (b))) +#define __nds32__v_kmmawb(r, a, b) \ + (__builtin_nds32_v_kmmawb ((r), (a), (b))) +#define __nds32__kmmawb_u(r, a, b) \ + (__builtin_nds32_kmmawb_u ((r), (a), (b))) +#define __nds32__v_kmmawb_u(r, a, b) \ + (__builtin_nds32_v_kmmawb_u ((r), (a), (b))) +#define __nds32__kmmawt(r, a, b) \ + (__builtin_nds32_kmmawt ((r), (a), (b))) +#define __nds32__v_kmmawt(r, a, b) \ + (__builtin_nds32_v_kmmawt ((r), (a), (b))) +#define __nds32__kmmawt_u(r, a, b) \ + (__builtin_nds32_kmmawt_u ((r), (a), (b))) +#define __nds32__v_kmmawt_u(r, a, b) \ + (__builtin_nds32_v_kmmawt_u ((r), (a), (b))) + +#define __nds32__smbb(a, b) \ + (__builtin_nds32_smbb ((a), (b))) +#define __nds32__v_smbb(a, b) \ + (__builtin_nds32_v_smbb ((a), (b))) +#define __nds32__smbt(a, b) \ + (__builtin_nds32_smbt ((a), (b))) +#define __nds32__v_smbt(a, b) \ + (__builtin_nds32_v_smbt ((a), (b))) +#define __nds32__smtt(a, b) \ + (__builtin_nds32_smtt ((a), (b))) +#define __nds32__v_smtt(a, b) \ + (__builtin_nds32_v_smtt ((a), (b))) +#define __nds32__kmda(a, b) \ + (__builtin_nds32_kmda ((a), (b))) +#define __nds32__v_kmda(a, b) \ + (__builtin_nds32_v_kmda ((a), (b))) +#define __nds32__kmxda(a, b) \ + (__builtin_nds32_kmxda ((a), (b))) +#define __nds32__v_kmxda(a, b) \ + (__builtin_nds32_v_kmxda ((a), (b))) +#define __nds32__smds(a, b) \ + (__builtin_nds32_smds ((a), (b))) +#define __nds32__v_smds(a, b) \ + (__builtin_nds32_v_smds ((a), (b))) +#define __nds32__smdrs(a, b) \ + (__builtin_nds32_smdrs ((a), (b))) +#define __nds32__v_smdrs(a, b) \ + (__builtin_nds32_v_smdrs ((a), (b))) +#define __nds32__smxds(a, b) \ + (__builtin_nds32_smxds ((a), (b))) +#define __nds32__v_smxds(a, b) \ + (__builtin_nds32_v_smxds ((a), (b))) +#define __nds32__kmabb(r, a, b) \ + (__builtin_nds32_kmabb ((r), (a), (b))) +#define __nds32__v_kmabb(r, a, b) \ + (__builtin_nds32_v_kmabb ((r), (a), (b))) +#define __nds32__kmabt(r, a, b) \ + (__builtin_nds32_kmabt ((r), (a), (b))) +#define __nds32__v_kmabt(r, a, b) \ + (__builtin_nds32_v_kmabt ((r), (a), (b))) +#define __nds32__kmatt(r, a, b) \ + (__builtin_nds32_kmatt ((r), (a), (b))) +#define __nds32__v_kmatt(r, a, b) \ + (__builtin_nds32_v_kmatt ((r), (a), (b))) +#define __nds32__kmada(r, a, b) \ + (__builtin_nds32_kmada ((r), (a), (b))) +#define __nds32__v_kmada(r, a, b) \ + (__builtin_nds32_v_kmada ((r), (a), (b))) +#define __nds32__kmaxda(r, a, b) \ + (__builtin_nds32_kmaxda ((r), (a), (b))) +#define __nds32__v_kmaxda(r, a, b) \ + (__builtin_nds32_v_kmaxda ((r), (a), (b))) +#define __nds32__kmads(r, a, b) \ + (__builtin_nds32_kmads ((r), (a), (b))) +#define __nds32__v_kmads(r, a, b) \ + (__builtin_nds32_v_kmads ((r), (a), (b))) +#define __nds32__kmadrs(r, a, b) \ + (__builtin_nds32_kmadrs ((r), (a), (b))) +#define __nds32__v_kmadrs(r, a, b) \ + (__builtin_nds32_v_kmadrs ((r), (a), (b))) +#define __nds32__kmaxds(r, a, b) \ + (__builtin_nds32_kmaxds ((r), (a), (b))) +#define __nds32__v_kmaxds(r, a, b) \ + (__builtin_nds32_v_kmaxds ((r), (a), (b))) +#define __nds32__kmsda(r, a, b) \ + (__builtin_nds32_kmsda ((r), (a), (b))) +#define __nds32__v_kmsda(r, a, b) \ + (__builtin_nds32_v_kmsda ((r), (a), (b))) +#define __nds32__kmsxda(r, a, b) \ + (__builtin_nds32_kmsxda ((r), (a), (b))) +#define __nds32__v_kmsxda(r, a, b) \ + (__builtin_nds32_v_kmsxda ((r), (a), (b))) + +#define __nds32__smal(a, b) \ + (__builtin_nds32_smal ((a), (b))) +#define __nds32__v_smal(a, b) \ + (__builtin_nds32_v_smal ((a), (b))) + +#define __nds32__bitrev(a, b) \ + (__builtin_nds32_bitrev ((a), (b))) +#define __nds32__wext(a, b) \ + (__builtin_nds32_wext ((a), (b))) +#define __nds32__bpick(r, a, b) \ + (__builtin_nds32_bpick ((r), (a), (b))) +#define __nds32__insb(r, a, b) \ + (__builtin_nds32_insb ((r), (a), (b))) + +#define __nds32__sadd64(a, b) \ + (__builtin_nds32_sadd64 ((a), (b))) +#define __nds32__uadd64(a, b) \ + (__builtin_nds32_uadd64 ((a), (b))) +#define __nds32__radd64(a, b) \ + (__builtin_nds32_radd64 ((a), (b))) +#define __nds32__uradd64(a, b) \ + (__builtin_nds32_uradd64 ((a), (b))) +#define __nds32__kadd64(a, b) \ + (__builtin_nds32_kadd64 ((a), (b))) +#define __nds32__ukadd64(a, b) \ + (__builtin_nds32_ukadd64 ((a), (b))) +#define __nds32__ssub64(a, b) \ + (__builtin_nds32_ssub64 ((a), (b))) +#define __nds32__usub64(a, b) \ + (__builtin_nds32_usub64 ((a), (b))) +#define __nds32__rsub64(a, b) \ + (__builtin_nds32_rsub64 ((a), (b))) +#define __nds32__ursub64(a, b) \ + (__builtin_nds32_ursub64 ((a), (b))) +#define __nds32__ksub64(a, b) \ + (__builtin_nds32_ksub64 ((a), (b))) +#define __nds32__uksub64(a, b) \ + (__builtin_nds32_uksub64 ((a), (b))) + +#define __nds32__smar64(r, a, b) \ + (__builtin_nds32_smar64 ((r), (a), (b))) +#define __nds32__smsr64(r, a, b) \ + (__builtin_nds32_smsr64 ((r), (a), (b))) +#define __nds32__umar64(r, a, b) \ + (__builtin_nds32_umar64 ((r), (a), (b))) +#define __nds32__umsr64(r, a, b) \ + (__builtin_nds32_umsr64 ((r), (a), (b))) +#define __nds32__kmar64(r, a, b) \ + (__builtin_nds32_kmar64 ((r), (a), (b))) +#define __nds32__kmsr64(r, a, b) \ + (__builtin_nds32_kmsr64 ((r), (a), (b))) +#define __nds32__ukmar64(r, a, b) \ + (__builtin_nds32_ukmar64 ((r), (a), (b))) +#define __nds32__ukmsr64(r, a, b) \ + (__builtin_nds32_ukmsr64 ((r), (a), (b))) + +#define __nds32__smalbb(r, a, b) \ + (__builtin_nds32_smalbb ((r), (a), (b))) +#define __nds32__v_smalbb(r, a, b) \ + (__builtin_nds32_v_smalbb ((r), (a), (b))) +#define __nds32__smalbt(r, a, b) \ + (__builtin_nds32_smalbt ((r), (a), (b))) +#define __nds32__v_smalbt(r, a, b) \ + (__builtin_nds32_v_smalbt ((r), (a), (b))) +#define __nds32__smaltt(r, a, b) \ + (__builtin_nds32_smaltt ((r), (a), (b))) +#define __nds32__v_smaltt(r, a, b) \ + (__builtin_nds32_v_smaltt ((r), (a), (b))) +#define __nds32__smalda(r, a, b) \ + (__builtin_nds32_smalda ((r), (a), (b))) +#define __nds32__v_smalda(r, a, b) \ + (__builtin_nds32_v_smalda ((r), (a), (b))) +#define __nds32__smalxda(r, a, b) \ + (__builtin_nds32_smalxda ((r), (a), (b))) +#define __nds32__v_smalxda(r, a, b) \ + (__builtin_nds32_v_smalxda ((r), (a), (b))) +#define __nds32__smalds(r, a, b) \ + (__builtin_nds32_smalds ((r), (a), (b))) +#define __nds32__v_smalds(r, a, b) \ + (__builtin_nds32_v_smalds ((r), (a), (b))) +#define __nds32__smaldrs(r, a, b) \ + (__builtin_nds32_smaldrs ((r), (a), (b))) +#define __nds32__v_smaldrs(r, a, b) \ + (__builtin_nds32_v_smaldrs ((r), (a), (b))) +#define __nds32__smalxds(r, a, b) \ + (__builtin_nds32_smalxds ((r), (a), (b))) +#define __nds32__v_smalxds(r, a, b) \ + (__builtin_nds32_v_smalxds ((r), (a), (b))) +#define __nds32__smslda(r, a, b) \ + (__builtin_nds32_smslda ((r), (a), (b))) +#define __nds32__v_smslda(r, a, b) \ + (__builtin_nds32_v_smslda ((r), (a), (b))) +#define __nds32__smslxda(r, a, b) \ + (__builtin_nds32_smslxda ((r), (a), (b))) +#define __nds32__v_smslxda(r, a, b) \ + (__builtin_nds32_v_smslxda ((r), (a), (b))) + +#define __nds32__smul16(a, b) \ + (__builtin_nds32_smul16 ((a), (b))) +#define __nds32__v_smul16(a, b) \ + (__builtin_nds32_v_smul16 ((a), (b))) +#define __nds32__smulx16(a, b) \ + (__builtin_nds32_smulx16 ((a), (b))) +#define __nds32__v_smulx16(a, b) \ + (__builtin_nds32_v_smulx16 ((a), (b))) +#define __nds32__umul16(a, b) \ + (__builtin_nds32_umul16 ((a), (b))) +#define __nds32__v_umul16(a, b) \ + (__builtin_nds32_v_umul16 ((a), (b))) +#define __nds32__umulx16(a, b) \ + (__builtin_nds32_umulx16 ((a), (b))) +#define __nds32__v_umulx16(a, b) \ + (__builtin_nds32_v_umulx16 ((a), (b))) + +#define __nds32__uclip32(a, imm) \ + (__builtin_nds32_uclip32 ((a), (imm))) +#define __nds32__sclip32(a, imm) \ + (__builtin_nds32_sclip32 ((a), (imm))) +#define __nds32__kabs(a) \ + (__builtin_nds32_kabs ((a))) + +#define __nds32__no_ext_zol() \ + (__builtin_nds32_no_ext_zol()) + +#define __nds32__unaligned_feature() \ + (__builtin_nds32_unaligned_feature()) +#define __nds32__enable_unaligned() \ + (__builtin_nds32_enable_unaligned()) +#define __nds32__disable_unaligned() \ + (__builtin_nds32_disable_unaligned()) + +#define __nds32__get_unaligned_u16x2(a) \ + (__builtin_nds32_get_unaligned_u16x2 ((a))) +#define __nds32__get_unaligned_s16x2(a) \ + (__builtin_nds32_get_unaligned_s16x2 ((a))) +#define __nds32__get_unaligned_u8x4(a) \ + (__builtin_nds32_get_unaligned_u8x4 ((a))) +#define __nds32__get_unaligned_s8x4(a) \ + (__builtin_nds32_get_unaligned_s8x4 ((a))) + +#define __nds32__put_unaligned_u16x2(a, data) \ + (__builtin_nds32_put_unaligned_u16x2 ((a), (data))) +#define __nds32__put_unaligned_s16x2(a, data) \ + (__builtin_nds32_put_unaligned_s16x2 ((a), (data))) +#define __nds32__put_unaligned_u8x4(a, data) \ + (__builtin_nds32_put_unaligned_u8x4 ((a), (data))) +#define __nds32__put_unaligned_s8x4(a, data) \ + (__builtin_nds32_put_unaligned_s8x4 ((a), (data))) + +#define NDS32ATTR_SIGNATURE __attribute__((signature)) + #endif /* nds32_intrinsic.h */ diff --git a/gcc/config/nds32/nds32_isr.h b/gcc/config/nds32/nds32_isr.h new file mode 100644 index 0000000..6fabd3e --- /dev/null +++ b/gcc/config/nds32/nds32_isr.h @@ -0,0 +1,526 @@ +/* Intrinsic definitions 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef _NDS32_ISR_H +#define _NDS32_ISR_H + +/* Attribute of a interrupt or exception handler: + + NDS32_READY_NESTED: This handler is interruptible if user re-enable GIE bit. + NDS32_NESTED : This handler is interruptible. This is not suitable + exception handler. + NDS32_NOT_NESTED : This handler is NOT interruptible. Users have to do + some work if nested is wanted + NDS32_CRITICAL : This handler is critical ISR, which means it is small + and efficient. */ +#define NDS32_READY_NESTED 0 +#define NDS32_NESTED 1 +#define NDS32_NOT_NESTED 2 +#define NDS32_CRITICAL 3 + +/* Attribute of a interrupt or exception handler: + + NDS32_SAVE_ALL_REGS : Save all registers in a table. + NDS32_SAVE_PARTIAL_REGS: Save partial registers. */ +#define NDS32_SAVE_CALLER_REGS 0 +#define NDS32_SAVE_ALL_REGS 1 + +/* There are two version of Register table for interrupt and exception handler, + one for 16-register CPU the other for 32-register CPU. These structures are + used for context switching or system call handling. The address of this + data can be get from the input argument of the handler functions. + + For system call handling, r0 to r5 are used to pass arguments. If more + arguments are used they are put into the stack and its starting address is + in sp. Return value of system call can be put into r0 and r1 upon exit from + system call handler. System call ID is in a system register and it can be + fetched via intrinsic function. For more information please read ABI and + other related documents. + + For context switching, at least 2 values need to saved in kernel. One is + IPC and the other is the stack address of current task. Use intrinsic + function to get IPC and the input argument of the handler functions + 8 to + get stack address of current task. To do context switching, you replace + new_sp with the stack address of new task and replace IPC system register + with IPC of new task, then, just return from handler. The context switching + will happen. */ + +/* Register table for exception handler; 32-register version. */ +typedef struct +{ + int r0; + int r1; + int r2; + int r3; + int r4; + int r5; + int r6; + int r7; + int r8; + int r9; + int r10; + int r11; + int r12; + int r13; + int r14; + int r15; + int r16; + int r17; + int r18; + int r19; + int r20; + int r21; + int r22; + int r23; + int r24; + int r25; + int r26; + int r27; + int fp; + int gp; + int lp; + int sp; +} NDS32_GPR32; + +/* Register table for exception handler; 16-register version. */ +typedef struct +{ + int r0; + int r1; + int r2; + int r3; + int r4; + int r5; + int r6; + int r7; + int r8; + int r9; + int r10; + int r15; + int fp; + int gp; + int lp; + int sp; +} NDS32_GPR16; + + +/* Use NDS32_REG32_TAB or NDS32_REG16_TAB in your program to + access register table. */ +typedef struct +{ + union + { + int reg_a[32] ; + NDS32_GPR32 reg_s ; + } u ; +} NDS32_REG32_TAB; + +typedef struct +{ + union + { + int reg_a[16] ; + NDS32_GPR16 reg_s ; + } u ; +} NDS32_REG16_TAB; + +typedef struct +{ + int d0lo; + int d0hi; + int d1lo; + int d1hi; +} NDS32_DX_TAB; + +typedef struct +{ +#ifdef __NDS32_EB__ + float fsr0; + float fsr1; + float fsr2; + float fsr3; + float fsr4; + float fsr5; + float fsr6; + float fsr7; +#else + float fsr1; + float fsr0; + float fsr3; + float fsr2; + float fsr5; + float fsr4; + float fsr7; + float fsr6; +#endif +} NDS32_FSR8; + +typedef struct +{ + double dsr0; + double dsr1; + double dsr2; + double dsr3; +} NDS32_DSR4; + +typedef struct +{ +#ifdef __NDS32_EB__ + float fsr0; + float fsr1; + float fsr2; + float fsr3; + float fsr4; + float fsr5; + float fsr6; + float fsr7; + float fsr8; + float fsr9; + float fsr10; + float fsr11; + float fsr12; + float fsr13; + float fsr14; + float fsr15; +#else + float fsr1; + float fsr0; + float fsr3; + float fsr2; + float fsr5; + float fsr4; + float fsr7; + float fsr6; + float fsr9; + float fsr8; + float fsr11; + float fsr10; + float fsr13; + float fsr12; + float fsr15; + float fsr14; +#endif +} NDS32_FSR16; + +typedef struct +{ + double dsr0; + double dsr1; + double dsr2; + double dsr3; + double dsr4; + double dsr5; + double dsr6; + double dsr7; +} NDS32_DSR8; + +typedef struct +{ +#ifdef __NDS32_EB__ + float fsr0; + float fsr1; + float fsr2; + float fsr3; + float fsr4; + float fsr5; + float fsr6; + float fsr7; + float fsr8; + float fsr9; + float fsr10; + float fsr11; + float fsr12; + float fsr13; + float fsr14; + float fsr15; + float fsr16; + float fsr17; + float fsr18; + float fsr19; + float fsr20; + float fsr21; + float fsr22; + float fsr23; + float fsr24; + float fsr25; + float fsr26; + float fsr27; + float fsr28; + float fsr29; + float fsr30; + float fsr31; +#else + float fsr1; + float fsr0; + float fsr3; + float fsr2; + float fsr5; + float fsr4; + float fsr7; + float fsr6; + float fsr9; + float fsr8; + float fsr11; + float fsr10; + float fsr13; + float fsr12; + float fsr15; + float fsr14; + float fsr17; + float fsr16; + float fsr19; + float fsr18; + float fsr21; + float fsr20; + float fsr23; + float fsr22; + float fsr25; + float fsr24; + float fsr27; + float fsr26; + float fsr29; + float fsr28; + float fsr31; + float fsr30; +#endif +} NDS32_FSR32; + +typedef struct +{ + double dsr0; + double dsr1; + double dsr2; + double dsr3; + double dsr4; + double dsr5; + double dsr6; + double dsr7; + double dsr8; + double dsr9; + double dsr10; + double dsr11; + double dsr12; + double dsr13; + double dsr14; + double dsr15; +} NDS32_DSR16; + +typedef struct +{ + double dsr0; + double dsr1; + double dsr2; + double dsr3; + double dsr4; + double dsr5; + double dsr6; + double dsr7; + double dsr8; + double dsr9; + double dsr10; + double dsr11; + double dsr12; + double dsr13; + double dsr14; + double dsr15; + double dsr16; + double dsr17; + double dsr18; + double dsr19; + double dsr20; + double dsr21; + double dsr22; + double dsr23; + double dsr24; + double dsr25; + double dsr26; + double dsr27; + double dsr28; + double dsr29; + double dsr30; + double dsr31; +} NDS32_DSR32; + +typedef struct +{ + union + { + NDS32_FSR8 fsr_s ; + NDS32_DSR4 dsr_s ; + } u ; +} NDS32_FPU8_TAB; + +typedef struct +{ + union + { + NDS32_FSR16 fsr_s ; + NDS32_DSR8 dsr_s ; + } u ; +} NDS32_FPU16_TAB; + +typedef struct +{ + union + { + NDS32_FSR32 fsr_s ; + NDS32_DSR16 dsr_s ; + } u ; +} NDS32_FPU32_TAB; + +typedef struct +{ + union + { + NDS32_FSR32 fsr_s ; + NDS32_DSR32 dsr_s ; + } u ; +} NDS32_FPU64_TAB; + +typedef struct +{ + int ipc; + int ipsw; +#if defined(NDS32_EXT_FPU_CONFIG_0) + NDS32_FPU8_TAB fpr; +#elif defined(NDS32_EXT_FPU_CONFIG_1) + NDS32_FPU16_TAB fpr; +#elif defined(NDS32_EXT_FPU_CONFIG_2) + NDS32_FPU32_TAB fpr; +#elif defined(NDS32_EXT_FPU_CONFIG_3) + NDS32_FPU64_TAB fpr; +#endif +#if __NDS32_DX_REGS__ + NDS32_DX_TAB dxr; +#endif +#if __NDS32_EXT_IFC__ + int ifc_lp; + int filler; +#endif +#if __NDS32_REDUCED_REGS__ || __NDS32_REDUCE_REGS + NDS32_REG16_TAB gpr; +#else + NDS32_REG32_TAB gpr; +#endif +} NDS32_CONTEXT; + +/* Predefined Vector Definition. + + For IVIC Mode: 9 to 14 are for hardware interrupt + and 15 is for software interrupt. + For EVIC Mode: 9 to 72 are for hardware interrupt + and software interrupt can be routed to any one of them. + + You may want to define your hardware interrupts in the following way + for easy maintainance. + + IVIC mode: + #define MY_HW_IVIC_TIMER NDS32_VECTOR_INTERRUPT_HW0 + 1 + #define MY_HW_IVIC_USB NDS32_VECTOR_INTERRUPT_HW0 + 3 + EVIC mode: + #define MY_HW_EVIC_DMA NDS32_VECTOR_INTERRUPT_HW0 + 2 + #define MY_HW_EVIC_SWI NDS32_VECTOR_INTERRUPT_HW0 + 10 */ +#define NDS32_VECTOR_RESET 0 +#define NDS32_VECTOR_TLB_FILL 1 +#define NDS32_VECTOR_PTE_NOT_PRESENT 2 +#define NDS32_VECTOR_TLB_MISC 3 +#define NDS32_VECTOR_TLB_VLPT_MISS 4 +#define NDS32_VECTOR_MACHINE_ERROR 5 +#define NDS32_VECTOR_DEBUG_RELATED 6 +#define NDS32_VECTOR_GENERAL_EXCEPTION 7 +#define NDS32_VECTOR_SYSCALL 8 +#define NDS32_VECTOR_INTERRUPT_HW0 9 +#define NDS32_VECTOR_INTERRUPT_HW1 10 +#define NDS32_VECTOR_INTERRUPT_HW2 11 +#define NDS32_VECTOR_INTERRUPT_HW3 12 +#define NDS32_VECTOR_INTERRUPT_HW4 13 +#define NDS32_VECTOR_INTERRUPT_HW5 14 +#define NDS32_VECTOR_INTERRUPT_HW6 15 +#define NDS32_VECTOR_SWI 15 /* THIS IS FOR IVIC MODE ONLY */ +#define NDS32_VECTOR_INTERRUPT_HW7 16 +#define NDS32_VECTOR_INTERRUPT_HW8 17 +#define NDS32_VECTOR_INTERRUPT_HW9 18 +#define NDS32_VECTOR_INTERRUPT_HW10 19 +#define NDS32_VECTOR_INTERRUPT_HW11 20 +#define NDS32_VECTOR_INTERRUPT_HW12 21 +#define NDS32_VECTOR_INTERRUPT_HW13 22 +#define NDS32_VECTOR_INTERRUPT_HW14 23 +#define NDS32_VECTOR_INTERRUPT_HW15 24 +#define NDS32_VECTOR_INTERRUPT_HW16 25 +#define NDS32_VECTOR_INTERRUPT_HW17 26 +#define NDS32_VECTOR_INTERRUPT_HW18 27 +#define NDS32_VECTOR_INTERRUPT_HW19 28 +#define NDS32_VECTOR_INTERRUPT_HW20 29 +#define NDS32_VECTOR_INTERRUPT_HW21 30 +#define NDS32_VECTOR_INTERRUPT_HW22 31 +#define NDS32_VECTOR_INTERRUPT_HW23 32 +#define NDS32_VECTOR_INTERRUPT_HW24 33 +#define NDS32_VECTOR_INTERRUPT_HW25 34 +#define NDS32_VECTOR_INTERRUPT_HW26 35 +#define NDS32_VECTOR_INTERRUPT_HW27 36 +#define NDS32_VECTOR_INTERRUPT_HW28 37 +#define NDS32_VECTOR_INTERRUPT_HW29 38 +#define NDS32_VECTOR_INTERRUPT_HW30 39 +#define NDS32_VECTOR_INTERRUPT_HW31 40 +#define NDS32_VECTOR_INTERRUPT_HW32 41 +#define NDS32_VECTOR_INTERRUPT_HW33 42 +#define NDS32_VECTOR_INTERRUPT_HW34 43 +#define NDS32_VECTOR_INTERRUPT_HW35 44 +#define NDS32_VECTOR_INTERRUPT_HW36 45 +#define NDS32_VECTOR_INTERRUPT_HW37 46 +#define NDS32_VECTOR_INTERRUPT_HW38 47 +#define NDS32_VECTOR_INTERRUPT_HW39 48 +#define NDS32_VECTOR_INTERRUPT_HW40 49 +#define NDS32_VECTOR_INTERRUPT_HW41 50 +#define NDS32_VECTOR_INTERRUPT_HW42 51 +#define NDS32_VECTOR_INTERRUPT_HW43 52 +#define NDS32_VECTOR_INTERRUPT_HW44 53 +#define NDS32_VECTOR_INTERRUPT_HW45 54 +#define NDS32_VECTOR_INTERRUPT_HW46 55 +#define NDS32_VECTOR_INTERRUPT_HW47 56 +#define NDS32_VECTOR_INTERRUPT_HW48 57 +#define NDS32_VECTOR_INTERRUPT_HW49 58 +#define NDS32_VECTOR_INTERRUPT_HW50 59 +#define NDS32_VECTOR_INTERRUPT_HW51 60 +#define NDS32_VECTOR_INTERRUPT_HW52 61 +#define NDS32_VECTOR_INTERRUPT_HW53 62 +#define NDS32_VECTOR_INTERRUPT_HW54 63 +#define NDS32_VECTOR_INTERRUPT_HW55 64 +#define NDS32_VECTOR_INTERRUPT_HW56 65 +#define NDS32_VECTOR_INTERRUPT_HW57 66 +#define NDS32_VECTOR_INTERRUPT_HW58 67 +#define NDS32_VECTOR_INTERRUPT_HW59 68 +#define NDS32_VECTOR_INTERRUPT_HW60 69 +#define NDS32_VECTOR_INTERRUPT_HW61 70 +#define NDS32_VECTOR_INTERRUPT_HW62 71 +#define NDS32_VECTOR_INTERRUPT_HW63 72 + +#define NDS32ATTR_RESET(option) __attribute__((reset(option))) +#define NDS32ATTR_EXCEPT(type) __attribute__((exception(type))) +#define NDS32ATTR_EXCEPTION(type) __attribute__((exception(type))) +#define NDS32ATTR_INTERRUPT(type) __attribute__((interrupt(type))) +#define NDS32ATTR_ISR(type) __attribute__((interrupt(type))) + +#endif /* nds32_isr.h */ diff --git a/gcc/config/nds32/pipelines.md b/gcc/config/nds32/pipelines.md index f7e2fa8..6cd854d 100644 --- a/gcc/config/nds32/pipelines.md +++ b/gcc/config/nds32/pipelines.md @@ -18,12 +18,65 @@ ;; along with GCC; see the file COPYING3. If not see ;; . -(define_automaton "nds32_machine") +;; ------------------------------------------------------------------------ +;; Include N7 pipeline settings. +;; ------------------------------------------------------------------------ +(include "nds32-n7.md") + + +;; ------------------------------------------------------------------------ +;; Include N8 pipeline settings. +;; ------------------------------------------------------------------------ +(include "nds32-n8.md") + + +;; ------------------------------------------------------------------------ +;; Include E8 pipeline settings. +;; ------------------------------------------------------------------------ +(include "nds32-e8.md") + + +;; ------------------------------------------------------------------------ +;; Include N9/N10 pipeline settings. +;; ------------------------------------------------------------------------ +(include "nds32-n9-3r2w.md") +(include "nds32-n9-2r1w.md") + + +;; ------------------------------------------------------------------------ +;; Include N10 pipeline settings. +;; ------------------------------------------------------------------------ +(include "nds32-n10.md") + + +;; ------------------------------------------------------------------------ +;; Include Graywolf pipeline settings. +;; ------------------------------------------------------------------------ +(include "nds32-graywolf.md") + + +;; ------------------------------------------------------------------------ +;; Include N12/N13 pipeline settings. +;; ------------------------------------------------------------------------ +(include "nds32-n13.md") + + +;; ------------------------------------------------------------------------ +;; Include Panther pipeline settings. +;; ------------------------------------------------------------------------ +(include "nds32-panther.md") + + +;; ------------------------------------------------------------------------ +;; Define simple pipeline settings. +;; ------------------------------------------------------------------------ + +(define_automaton "nds32_simple_machine") -(define_cpu_unit "general_unit" "nds32_machine") +(define_cpu_unit "simple_unit" "nds32_simple_machine") (define_insn_reservation "simple_insn" 1 - (eq_attr "type" "unknown,load,store,move,alu,compare,branch,call,misc") - "general_unit") + (eq_attr "pipeline_model" "simple") + "simple_unit") ;; ------------------------------------------------------------------------ diff --git a/gcc/config/nds32/predicates.md b/gcc/config/nds32/predicates.md index 05a039d..71a3615 100644 --- a/gcc/config/nds32/predicates.md +++ b/gcc/config/nds32/predicates.md @@ -24,25 +24,93 @@ (define_predicate "nds32_greater_less_comparison_operator" (match_code "gt,ge,lt,le")) +(define_predicate "nds32_float_comparison_operator" + (match_code "eq,ne,le,lt,ge,gt,ordered,unordered,ungt,unge,unlt,unle")) + +(define_predicate "nds32_movecc_comparison_operator" + (match_code "eq,ne,le,leu,ge,geu")) + (define_special_predicate "nds32_logical_binary_operator" (match_code "and,ior,xor")) +(define_special_predicate "nds32_conditional_call_comparison_operator" + (match_code "lt,ge")) + +(define_special_predicate "nds32_have_33_inst_operator" + (match_code "mult,and,ior,xor")) + (define_predicate "nds32_symbolic_operand" - (match_code "const,symbol_ref,label_ref")) + (and (match_code "const,symbol_ref,label_ref") + (match_test "!(TARGET_ICT_MODEL_LARGE + && nds32_indirect_call_referenced_p (op))"))) + +(define_predicate "nds32_nonunspec_symbolic_operand" + (and (match_code "const,symbol_ref,label_ref") + (match_test "!flag_pic && nds32_const_unspec_p (op) + && !(TARGET_ICT_MODEL_LARGE + && nds32_indirect_call_referenced_p (op))"))) + +(define_predicate "nds32_label_operand" + (match_code "label_ref")) (define_predicate "nds32_reg_constant_operand" - (ior (match_operand 0 "register_operand") - (match_operand 0 "const_int_operand"))) + (match_code "reg,const_int")) (define_predicate "nds32_rimm15s_operand" (ior (match_operand 0 "register_operand") (and (match_operand 0 "const_int_operand") (match_test "satisfies_constraint_Is15 (op)")))) +(define_predicate "nds32_rimm11s_operand" + (ior (match_operand 0 "register_operand") + (and (match_operand 0 "const_int_operand") + (match_test "satisfies_constraint_Is11 (op)")))) + +(define_predicate "nds32_imm_0_1_operand" + (and (match_operand 0 "const_int_operand") + (ior (match_test "satisfies_constraint_Iv00 (op)") + (match_test "satisfies_constraint_Iv01 (op)")))) + +(define_predicate "nds32_imm_1_2_operand" + (and (match_operand 0 "const_int_operand") + (ior (match_test "satisfies_constraint_Iv01 (op)") + (match_test "satisfies_constraint_Iv02 (op)")))) + +(define_predicate "nds32_imm_1_2_4_8_operand" + (and (match_operand 0 "const_int_operand") + (ior (ior (match_test "satisfies_constraint_Iv01 (op)") + (match_test "satisfies_constraint_Iv02 (op)")) + (ior (match_test "satisfies_constraint_Iv04 (op)") + (match_test "satisfies_constraint_Iv08 (op)"))))) + +(define_predicate "nds32_imm2u_operand" + (and (match_operand 0 "const_int_operand") + (match_test "satisfies_constraint_Iu02 (op)"))) + +(define_predicate "nds32_imm4u_operand" + (and (match_operand 0 "const_int_operand") + (match_test "satisfies_constraint_Iu04 (op)"))) + (define_predicate "nds32_imm5u_operand" (and (match_operand 0 "const_int_operand") (match_test "satisfies_constraint_Iu05 (op)"))) +(define_predicate "nds32_imm6u_operand" + (and (match_operand 0 "const_int_operand") + (match_test "satisfies_constraint_Iu06 (op)"))) + +(define_predicate "nds32_rimm4u_operand" + (ior (match_operand 0 "register_operand") + (match_operand 0 "nds32_imm4u_operand"))) + +(define_predicate "nds32_rimm5u_operand" + (ior (match_operand 0 "register_operand") + (match_operand 0 "nds32_imm5u_operand"))) + +(define_predicate "nds32_rimm6u_operand" + (ior (match_operand 0 "register_operand") + (match_operand 0 "nds32_imm6u_operand"))) + (define_predicate "nds32_move_operand" (and (match_operand 0 "general_operand") (not (match_code "high,const,symbol_ref,label_ref"))) @@ -57,12 +125,121 @@ return true; }) +(define_predicate "nds32_vmove_operand" + (and (match_operand 0 "general_operand") + (not (match_code "high,const,symbol_ref,label_ref"))) +{ + /* If the constant op does NOT satisfy Is20 nor Ihig, + we can not perform move behavior by a single instruction. */ + if (GET_CODE (op) == CONST_VECTOR + && !satisfies_constraint_CVs2 (op) + && !satisfies_constraint_CVhi (op)) + return false; + + return true; +}) + +(define_predicate "nds32_and_operand" + (match_code "reg,const_int") +{ + return (REG_P (op) && GET_MODE (op) == mode) + || satisfies_constraint_Izeb (op) + || satisfies_constraint_Izeh (op) + || satisfies_constraint_Ixls (op) + || satisfies_constraint_Ix11 (op) + || satisfies_constraint_Ibms (op) + || satisfies_constraint_Ifex (op) + || satisfies_constraint_Iu15 (op) + || satisfies_constraint_Ii15 (op) + || satisfies_constraint_Ic15 (op); +}) + +(define_predicate "nds32_ior_operand" + (match_code "reg,const_int") +{ + return (REG_P (op) && GET_MODE (op) == mode) + || satisfies_constraint_Iu15 (op) + || satisfies_constraint_Ie15 (op); +}) + +(define_predicate "nds32_xor_operand" + (match_code "reg,const_int") +{ + return (REG_P (op) && GET_MODE (op) == mode) + || GET_CODE (op) == SUBREG + || satisfies_constraint_Iu15 (op) + || satisfies_constraint_It15 (op); +}) + +(define_predicate "nds32_general_register_operand" + (match_code "reg,subreg") +{ + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + return (REG_P (op) + && (REGNO (op) >= FIRST_PSEUDO_REGISTER + || REGNO (op) <= NDS32_LAST_GPR_REGNUM)); +}) + +(define_predicate "nds32_fpu_register_operand" + (match_code "reg,subreg") +{ + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + return (REG_P (op) + && NDS32_IS_FPR_REGNUM (REGNO (op))); +}) + +(define_predicate "fpu_reg_or_memory_operand" + (ior (match_operand 0 "nds32_fpu_register_operand") + (match_operand 0 "memory_operand"))) + +(define_predicate "nds32_call_address_operand" + (ior (match_operand 0 "nds32_symbolic_operand") + (match_operand 0 "nds32_general_register_operand"))) + +(define_predicate "nds32_insv_operand" + (match_code "const_int") +{ + return INTVAL (op) == 0 + || INTVAL (op) == 8 + || INTVAL (op) == 16 + || INTVAL (op) == 24; +}) + +(define_predicate "nds32_lmw_smw_base_operand" + (and (match_code "mem") + (match_test "nds32_valid_smw_lwm_base_p (op)"))) + +(define_predicate "float_even_register_operand" + (and (match_code "reg") + (and (match_test "REGNO (op) >= NDS32_FIRST_FPR_REGNUM") + (match_test "REGNO (op) <= NDS32_LAST_FPR_REGNUM") + (match_test "(REGNO (op) & 1) == 0")))) + +(define_predicate "float_odd_register_operand" + (and (match_code "reg") + (and (match_test "REGNO (op) >= NDS32_FIRST_FPR_REGNUM") + (match_test "REGNO (op) <= NDS32_LAST_FPR_REGNUM") + (match_test "(REGNO (op) & 1) != 0")))) + (define_special_predicate "nds32_load_multiple_operation" (match_code "parallel") { /* To verify 'load' operation, pass 'true' for the second argument. See the implementation in nds32.c for details. */ - return nds32_valid_multiple_load_store (op, true); + return nds32_valid_multiple_load_store_p (op, true, false); +}) + +(define_special_predicate "nds32_load_multiple_and_update_address_operation" + (match_code "parallel") +{ + /* To verify 'load' operation, pass 'true' for the second argument. + to verify 'update address' operation, pass 'true' for the third argument + See the implementation in nds32.c for details. */ + return nds32_valid_multiple_load_store_p (op, true, true); }) (define_special_predicate "nds32_store_multiple_operation" @@ -70,7 +247,16 @@ { /* To verify 'store' operation, pass 'false' for the second argument. See the implementation in nds32.c for details. */ - return nds32_valid_multiple_load_store (op, false); + return nds32_valid_multiple_load_store_p (op, false, false); +}) + +(define_special_predicate "nds32_store_multiple_and_update_address_operation" + (match_code "parallel") +{ + /* To verify 'store' operation, pass 'false' for the second argument, + to verify 'update address' operation, pass 'true' for the third argument + See the implementation in nds32.c for details. */ + return nds32_valid_multiple_load_store_p (op, false, true); }) (define_special_predicate "nds32_stack_push_operation" diff --git a/gcc/config/nds32/t-elf b/gcc/config/nds32/t-elf new file mode 100644 index 0000000..a63a310 --- /dev/null +++ b/gcc/config/nds32/t-elf @@ -0,0 +1,42 @@ +# The multilib settings of Andes NDS32 cpu for GNU compiler +# Copyright (C) 2012-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 +# . + +# We also define a macro MULTILIB_DEFAULTS in nds32.h that tells the +# driver program which options are defaults for this target and thus +# do not need to be handled specially. +MULTILIB_OPTIONS += mcmodel=small/mcmodel=medium/mcmodel=large mvh + +ifneq ($(filter graywolf,$(TM_MULTILIB_CONFIG)),) +MULTILIB_OPTIONS += mcpu=graywolf +endif + +ifneq ($(filter dsp,$(TM_MULTILIB_CONFIG)),) +MULTILIB_OPTIONS += mext-dsp +endif + +ifneq ($(filter zol,$(TM_MULTILIB_CONFIG)),) +MULTILIB_OPTIONS += mext-zol +endif + +ifneq ($(filter v3m+,$(TM_MULTILIB_CONFIG)),) +MULTILIB_OPTIONS += march=v3m+ +endif + +# ------------------------------------------------------------------------ diff --git a/gcc/config/nds32/t-mlibs b/gcc/config/nds32/t-linux similarity index 94% rename from gcc/config/nds32/t-mlibs rename to gcc/config/nds32/t-linux index 5cb13f7..a4d8ab3 100644 --- a/gcc/config/nds32/t-mlibs +++ b/gcc/config/nds32/t-linux @@ -21,6 +21,6 @@ # We also define a macro MULTILIB_DEFAULTS in nds32.h that tells the # driver program which options are defaults for this target and thus # do not need to be handled specially. -MULTILIB_OPTIONS = mcmodel=small/mcmodel=medium/mcmodel=large +MULTILIB_OPTIONS += # ------------------------------------------------------------------------ diff --git a/gcc/config/nds32/t-nds32 b/gcc/config/nds32/t-nds32 index cf3aea6..e34b844 100644 --- a/gcc/config/nds32/t-nds32 +++ b/gcc/config/nds32/t-nds32 @@ -1,51 +1,294 @@ -# General rules that all nds32/ targets must have. +# Dependency rules rule 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 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. +# 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 # . -nds32-cost.o: $(srcdir)/config/nds32/nds32-cost.c - $(COMPILE) $< - $(POSTCOMPILE) -nds32-intrinsic.o: $(srcdir)/config/nds32/nds32-intrinsic.c - $(COMPILE) $< - $(POSTCOMPILE) +nds32-md-auxiliary.o: $(srcdir)/config/nds32/nds32-md-auxiliary.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-md-auxiliary.c -nds32-isr.o: $(srcdir)/config/nds32/nds32-isr.c - $(COMPILE) $< - $(POSTCOMPILE) +nds32-memory-manipulation.o: $(srcdir)/config/nds32/nds32-memory-manipulation.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-memory-manipulation.c -nds32-md-auxiliary.o: $(srcdir)/config/nds32/nds32-md-auxiliary.c - $(COMPILE) $< - $(POSTCOMPILE) +nds32-predicates.o: $(srcdir)/config/nds32/nds32-predicates.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-predicates.c -nds32-pipelines-auxiliary.o: $(srcdir)/config/nds32/nds32-pipelines-auxiliary.c - $(COMPILE) $< - $(POSTCOMPILE) +nds32-intrinsic.o: $(srcdir)/config/nds32/nds32-intrinsic.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-intrinsic.c -nds32-predicates.o: $(srcdir)/config/nds32/nds32-predicates.c - $(COMPILE) $< - $(POSTCOMPILE) +nds32-pipelines-auxiliary.o: \ + $(srcdir)/config/nds32/nds32-pipelines-auxiliary.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-pipelines-auxiliary.c -nds32-memory-manipulation.o: $(srcdir)/config/nds32/nds32-memory-manipulation.c - $(COMPILE) $< - $(POSTCOMPILE) +nds32-isr.o: \ + $(srcdir)/config/nds32/nds32-isr.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-isr.c -nds32-fp-as-gp.o: $(srcdir)/config/nds32/nds32-fp-as-gp.c - $(COMPILE) $< - $(POSTCOMPILE) +nds32-cost.o: \ + $(srcdir)/config/nds32/nds32-cost.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-cost.c + +nds32-fp-as-gp.o: \ + $(srcdir)/config/nds32/nds32-fp-as-gp.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-fp-as-gp.c + +nds32-load-store-opt.o: \ + $(srcdir)/config/nds32/nds32-load-store-opt.c \ + $(srcdir)/config/nds32/nds32-load-store-opt.h \ + $(srcdir)/config/nds32/nds32-reg-utils.h \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-load-store-opt.c + +nds32-soft-fp-comm.o: \ + $(srcdir)/config/nds32/nds32-soft-fp-comm.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-soft-fp-comm.c + +nds32-regrename.o: \ + $(srcdir)/config/nds32/nds32-regrename.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-regrename.c + +nds32-gcse.o: \ + $(srcdir)/config/nds32/nds32-gcse.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-gcse.c + +nds32-relax-opt.o: \ + $(srcdir)/config/nds32/nds32-relax-opt.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-relax-opt.c + +nds32-cprop-acc.o: \ + $(srcdir)/config/nds32/nds32-cprop-acc.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-cprop-acc.c + +nds32-sign-conversion.o: \ + $(srcdir)/config/nds32/nds32-sign-conversion.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(GIMPLE_H) $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-sign-conversion.c + +nds32-scalbn-transform.o: \ + $(srcdir)/config/nds32/nds32-scalbn-transform.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(GIMPLE_H) $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-scalbn-transform.c + +nds32-abi-compatible.o: \ + $(srcdir)/config/nds32/nds32-abi-compatible.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(GIMPLE_H) $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-abi-compatible.c + +nds32-lmwsmw.o: \ + $(srcdir)/config/nds32/nds32-lmwsmw.c \ + $(srcdir)/config/nds32/nds32-load-store-opt.h \ + $(srcdir)/config/nds32/nds32-reg-utils.h \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-lmwsmw.c + +nds32-reg-utils.o: \ + $(srcdir)/config/nds32/nds32-reg-utils.c \ + $(srcdir)/config/nds32/nds32-reg-utils.h \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-reg-utils.c + +nds32-const-remater.o: \ + $(srcdir)/config/nds32/nds32-const-remater.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-const-remater.c + +nds32-utils.o: \ + $(srcdir)/config/nds32/nds32-utils.c \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(RTL_H) $(TREE_H) $(HASH_TABLE_H) $(OBSTACK_H) $(REGS_H) hard-reg-set.h \ + insn-config.h conditions.h output.h dumpfile.h \ + $(INSN_ATTR_H) $(FLAGS_H) reload.h $(FUNCTION_H) \ + $(EXPR_H) $(OPTABS_H) $(RECOG_H) $(CGRAPH_H) \ + $(GGC_H) except.h $(C_PRAGMA_H) $(TM_P_H) \ + $(TARGET_H) $(TARGET_DEF_H) debug.h langhooks.h $(DF_H) \ + intl.h libfuncs.h $(PARAMS_H) $(OPTS_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/nds32/nds32-utils.c diff --git a/gcc/configure b/gcc/configure index 954673c..ca21885 100755 --- a/gcc/configure +++ b/gcc/configure @@ -27327,7 +27327,7 @@ esac # version to the per-target configury. case "$cpu_type" in aarch64 | alpha | arm | avr | bfin | cris | i386 | m32c | m68k | microblaze \ - | mips | nios2 | pa | rs6000 | score | sparc | spu | tilegx | tilepro \ + | mips | nds32 | nios2 | pa | rs6000 | score | sparc | spu | tilegx | tilepro \ | visium | xstormy16 | xtensa) insn="nop" ;; diff --git a/gcc/configure.ac b/gcc/configure.ac index 4c65d44..d7a5efc 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4667,7 +4667,7 @@ esac # version to the per-target configury. case "$cpu_type" in aarch64 | alpha | arm | avr | bfin | cris | i386 | m32c | m68k | microblaze \ - | mips | nios2 | pa | rs6000 | score | sparc | spu | tilegx | tilepro \ + | mips | nds32 | nios2 | pa | rs6000 | score | sparc | spu | tilegx | tilepro \ | visium | xstormy16 | xtensa) insn="nop" ;; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 1edfd98..bc0f2d0 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -13587,38 +13587,33 @@ builtin is exact. These built-in functions are available for the NDS32 target: -@deftypefn {Built-in Function} void __builtin_nds32_isync (int *@var{addr}) +@table @code +@item void __builtin_nds32_isync (int *@var{addr}) Insert an ISYNC instruction into the instruction stream where @var{addr} is an instruction address for serialization. -@end deftypefn -@deftypefn {Built-in Function} void __builtin_nds32_isb (void) +@item void __builtin_nds32_isb (void) Insert an ISB instruction into the instruction stream. -@end deftypefn -@deftypefn {Built-in Function} int __builtin_nds32_mfsr (int @var{sr}) +@item int __builtin_nds32_mfsr (int @var{sr}) Return the content of a system register which is mapped by @var{sr}. -@end deftypefn -@deftypefn {Built-in Function} int __builtin_nds32_mfusr (int @var{usr}) +@item int __builtin_nds32_mfusr (int @var{usr}) Return the content of a user space register which is mapped by @var{usr}. -@end deftypefn -@deftypefn {Built-in Function} void __builtin_nds32_mtsr (int @var{value}, int @var{sr}) +@item void __builtin_nds32_mtsr (int @var{value}, int @var{sr}) Move the @var{value} to a system register which is mapped by @var{sr}. -@end deftypefn -@deftypefn {Built-in Function} void __builtin_nds32_mtusr (int @var{value}, int @var{usr}) +@item void __builtin_nds32_mtusr (int @var{value}, int @var{usr}) Move the @var{value} to a user space register which is mapped by @var{usr}. -@end deftypefn -@deftypefn {Built-in Function} void __builtin_nds32_setgie_en (void) +@item void __builtin_nds32_setgie_en (void) Enable global interrupt. -@end deftypefn -@deftypefn {Built-in Function} void __builtin_nds32_setgie_dis (void) +@item void __builtin_nds32_setgie_dis (void) Disable global interrupt. -@end deftypefn + +@end table @node picoChip Built-in Functions @subsection picoChip Built-in Functions diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 5b6e2b7..6428350 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -2114,7 +2114,7 @@ supported since version 4.7.2 and is the default in 4.8.0 and newer. @item --with-nds32-lib=@var{library} Specifies that @var{library} setting is used for building @file{libgcc.a}. -Currently, the valid @var{library} is @samp{newlib} or @samp{mculib}. +Currently, the valid @var{library} are 'newlib' or 'mculib'. This option is only supported for the NDS32 target. @item --with-build-time-tools=@var{dir} diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 84a7cf8..267a9ba 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -904,13 +904,19 @@ Objective-C and Objective-C++ Dialects}. -mreduced-regs -mfull-regs @gol -mcmov -mno-cmov @gol -mperf-ext -mno-perf-ext @gol +-mperf2-ext -mno-perf2-ext @gol +-mstring-ext -mno-string-ext @gol -mv3push -mno-v3push @gol -m16bit -mno-16bit @gol +-mgp-direct -mno-gp-direct @gol -misr-vector-size=@var{num} @gol -mcache-block-size=@var{num} @gol -march=@var{arch} @gol --mcmodel=@var{code-model} @gol --mctor-dtor -mrelax} +-mcpu=@var{cpu} @gol +-mmemory-model=@var{cpu} @gol +-mconfig-register-ports=@var{ports} @gol +-mforce-fp-as-gp -mforbid-fp-as-gp @gol +-mex9 -mctor-dtor -mrelax} @emph{Nios II Options} @gccoptlist{-G @var{num} -mgpopt=@var{option} -mgpopt -mno-gpopt @gol @@ -5010,7 +5016,7 @@ example, warn if an unsigned variable is compared against zero with @opindex Wbad-function-cast @opindex Wno-bad-function-cast Warn when a function call is cast to a non-matching type. -For example, warn if a call to a function returning an integer type +For example, warn if a call to a function returning an integer type is cast to a pointer type. @item -Wc90-c99-compat @r{(C and Objective-C only)} @@ -19093,6 +19099,22 @@ Generate performance extension instructions. @opindex mno-perf-ext Do not generate performance extension instructions. +@item -mperf2-ext +@opindex mperf2-ext +Generate performance extension version 2 instructions. + +@item -mno-perf2-ext +@opindex mno-perf2-ext +Do not generate performance extension version 2 instructions. + +@item -mstring-ext +@opindex mstring-ext +Generate string extension instructions. + +@item -mno-string-ext +@opindex mno-string-ext +Do not generate string extension instructions. + @item -mv3push @opindex mv3push Generate v3 push25/pop25 instructions. @@ -19109,6 +19131,14 @@ Generate 16-bit instructions. @opindex mno-16-bit Do not generate 16-bit instructions. +@item -mgp-direct +@opindex mgp-direct +Generate GP base instructions directly. + +@item -mno-gp-direct +@opindex mno-gp-direct +Do no generate GP base instructions directly. + @item -misr-vector-size=@var{num} @opindex misr-vector-size Specify the size of each interrupt vector, which must be 4 or 16. @@ -19122,20 +19152,33 @@ which must be a power of 2 between 4 and 512. @opindex march Specify the name of the target architecture. -@item -mcmodel=@var{code-model} -@opindex mcmodel -Set the code model to one of -@table @asis -@item @samp{small} -All the data and read-only data segments must be within 512KB addressing space. -The text segment must be within 16MB addressing space. -@item @samp{medium} -The data segment must be within 512KB while the read-only data segment can be -within 4GB addressing space. The text segment should be still within 16MB -addressing space. -@item @samp{large} -All the text and data segments can be within 4GB addressing space. -@end table +@item -mcpu=@var{cpu} +@opindex mcpu +Specify the cpu for pipeline model. + +@item -mmemory-model=@var{cpu} +@opindex mmemory-model +Specify fast or slow memory model. + +@item -mconfig-register-ports=@var{ports} +@opindex mconfig-register-ports +Specify how many read/write ports for n9/n10 cores. +The value should be 3r2w or 2r1w. + +@item -mforce-fp-as-gp +@opindex mforce-fp-as-gp +Prevent $fp being allocated during register allocation so that compiler +is able to force performing fp-as-gp optimization. + +@item -mforbid-fp-as-gp +@opindex mforbid-fp-as-gp +Forbid using $fp to access static and global variables. +This option strictly forbids fp-as-gp optimization +regardless of @option{-mforce-fp-as-gp}. + +@item -mex9 +@opindex mex9 +Use special directives to guide linker doing ex9 optimization. @item -mctor-dtor @opindex mctor-dtor @@ -19163,55 +19206,15 @@ Put global and static objects less than or equal to @var{num} bytes into the small data or BSS sections instead of the normal data or BSS sections. The default value of @var{num} is 8. -@item -mgpopt=@var{option} @item -mgpopt @itemx -mno-gpopt @opindex mgpopt @opindex mno-gpopt -Generate (do not generate) GP-relative accesses. The following -@var{option} names are recognized: - -@table @samp - -@item none -Do not generate GP-relative accesses. - -@item local -Generate GP-relative accesses for small data objects that are not -external, weak, or uninitialized common symbols. -Also use GP-relative addressing for objects that -have been explicitly placed in a small data section via a @code{section} -attribute. - -@item global -As for @samp{local}, but also generate GP-relative accesses for -small data objects that are external, weak, or common. If you use this option, -you must ensure that all parts of your program (including libraries) are -compiled with the same @option{-G} setting. - -@item data -Generate GP-relative accesses for all data objects in the program. If you -use this option, the entire data and BSS segments -of your program must fit in 64K of memory and you must use an appropriate -linker script to allocate them within the addressable range of the -global pointer. - -@item all -Generate GP-relative addresses for function pointers as well as data -pointers. If you use this option, the entire text, data, and BSS segments -of your program must fit in 64K of memory and you must use an appropriate -linker script to allocate them within the addressable range of the -global pointer. - -@end table - -@option{-mgpopt} is equivalent to @option{-mgpopt=local}, and -@option{-mno-gpopt} is equivalent to @option{-mgpopt=none}. - -The default is @option{-mgpopt} except when @option{-fpic} or -@option{-fPIC} is specified to generate position-independent code. -Note that the Nios II ABI does not permit GP-relative accesses from -shared libraries. +Generate (do not generate) GP-relative accesses for objects in the +small data or BSS sections. The default is @option{-mgpopt} except +when @option{-fpic} or @option{-fPIC} is specified to generate +position-independent code. Note that the Nios II ABI does not permit +GP-relative accesses from shared libraries. You may need to specify @option{-mno-gpopt} explicitly when building programs that include large amounts of small data, including large diff --git a/gcc/gcc.c b/gcc/gcc.c index cfa074d..bfb1bb7 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -1288,7 +1288,7 @@ static const struct compiler default_compilers[] = {".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0}, {".go", "#Go", 0, 1, 0}, /* Next come the entries for C. */ - {".c", "@c", 0, 0, 1}, + {".c", "@nds32_c", 0, 0, 1}, {"@c", /* cc1 has an integrated ISO C preprocessor. We should invoke the external preprocessor if -save-temps is given. */ @@ -1303,6 +1303,38 @@ static const struct compiler default_compilers[] = %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\ cc1 %(cpp_unique_options) %(cc1_options)}}}\ %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 1}, + {"@nds32_c", + /* cc1 has an integrated ISO C preprocessor. We should invoke the + external preprocessor if -save-temps is given. */ + "%{E|M|MM:%(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)}\ + %{mace:\ + %{!E:%{!M:%{!MM:\ + %{traditional:\ +%eGNU C no longer supports -traditional without -E}\ + %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \ + %(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\ + cs2 %{mace-s2s*} %{save-temps*:%b.i} %{!save-temps*:%g.i} \ + -o %{save-temps*:%b.ace.i} %{!save-temps*:%g.ace.i} --\n\ + cc1 -fpreprocessed %{save-temps*:%b.ace.i} %{!save-temps*:%g.ace.i} \ + %(cc1_options)}\ + %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\ + %(trad_capable_cpp) %(cpp_options) -o %u.i\n}}}\ + %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\ + cs2 %{mace-s2s*} %U.i -o %u.ace.i --\n}}}\ + %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\ + cc1 -fpreprocessed %U.ace.i %(cc1_options)}}}\ + %{!fsyntax-only:%(invoke_as)}}}}}\ + %{!mace:\ + %{!E:%{!M:%{!MM:\ + %{traditional:\ +%eGNU C no longer supports -traditional without -E}\ + %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \ + %(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\ + cc1 -fpreprocessed %{save-temps*:%b.i} %{!save-temps*:%g.i} \ + %(cc1_options)}\ + %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\ + cc1 %(cpp_unique_options) %(cc1_options)}}}\ + %{!fsyntax-only:%(invoke_as)}}}}}", 0, 0, 1}, {"-", "%{!E:%e-E or -x required when input is from standard input}\ %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", 0, 0, 0}, diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c index 4d26e2f..60f934c 100644 --- a/gcc/loop-unroll.c +++ b/gcc/loop-unroll.c @@ -1132,7 +1132,9 @@ decide_unroll_stupid (struct loop *loop, int flags) of mispredicts. TODO: this heuristic needs tunning; call inside the loop body is also relatively good reason to not unroll. */ - if (num_loop_branches (loop) > 1) + unsigned branch_count = PARAM_VALUE (PARAM_MAX_LOOP_UNROLL_BRANCH); + + if (num_loop_branches (loop) > branch_count) { if (dump_file) fprintf (dump_file, ";; Not unrolling, contains branches\n"); diff --git a/gcc/opt-read.awk b/gcc/opt-read.awk index b304ccb..2e6e8df 100644 --- a/gcc/opt-read.awk +++ b/gcc/opt-read.awk @@ -99,6 +99,7 @@ BEGIN { val_flags = "0" val_flags = val_flags \ test_flag("Canonical", props, "| CL_ENUM_CANONICAL") \ + test_flag("Undocumented", props, "| CL_UNDOCUMENTED") \ test_flag("DriverOnly", props, "| CL_ENUM_DRIVER_ONLY") enum_data[enum_name] = enum_data[enum_name] \ " { " quote string quote ", " value ", " val_flags \ diff --git a/gcc/opts.c b/gcc/opts.c index 0f9431a..da75332 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1271,6 +1271,10 @@ print_filtered_help (unsigned int include_flags, { unsigned int len = strlen (cl_enums[i].values[j].arg); + /* Skip the undocument enum value */ + if (cl_enums[i].values[j].flags & CL_UNDOCUMENTED) + continue; + if (pos > 4 && pos + 1 + len <= columns) { printf (" %s", cl_enums[i].values[j].arg); diff --git a/gcc/params.def b/gcc/params.def index ce83aa7..1ab3880 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -297,6 +297,11 @@ DEFPARAM(PARAM_MAX_UNROLL_TIMES, "max-unroll-times", "The maximum number of unrollings of a single loop.", 8, 0, 0) +/* Maximum number of loop unroll loop branch count. */ +DEFPARAM (PARAM_MAX_LOOP_UNROLL_BRANCH, + "max-unroll-loop-branch", + "Maximum number of loop branch count", + 1, 1, 20) /* The maximum number of insns of a peeled loop. */ DEFPARAM(PARAM_MAX_PEELED_INSNS, "max-peeled-insns", diff --git a/gcc/testsuite/g++.dg/init/array15.C b/gcc/testsuite/g++.dg/init/array15.C index 17160d0..280fe69 100644 --- a/gcc/testsuite/g++.dg/init/array15.C +++ b/gcc/testsuite/g++.dg/init/array15.C @@ -1,4 +1,6 @@ // { dg-do run } +// { dg-require-effective-target nds32_full_addr_space { target nds32*-*-elf* } } +// { dg-options "-mcmodel=large" { target nds32*-*-elf* } } // Copyright (C) 2004 Free Software Foundation, Inc. // Contributed by Nathan Sidwell 8 Dec 2004 diff --git a/gcc/testsuite/g++.dg/init/array16.C b/gcc/testsuite/g++.dg/init/array16.C index 188d1a8..83c0d47 100644 --- a/gcc/testsuite/g++.dg/init/array16.C +++ b/gcc/testsuite/g++.dg/init/array16.C @@ -2,6 +2,7 @@ // have "compile" for some targets and "run" for others. // { dg-do run { target { ! mmix-*-* } } } // { dg-options "-mstructure-size-boundary=8" { target arm*-*-* } } +// { dg-skip-if "" { nds32_gp_direct } } // Copyright (C) 2004 Free Software Foundation, Inc. // Contributed by Nathan Sidwell 8 Dec 2004 diff --git a/gcc/testsuite/g++.dg/torture/type-generic-1.C b/gcc/testsuite/g++.dg/torture/type-generic-1.C index 4d82592..5ae789c 100644 --- a/gcc/testsuite/g++.dg/torture/type-generic-1.C +++ b/gcc/testsuite/g++.dg/torture/type-generic-1.C @@ -4,6 +4,7 @@ /* { dg-do run } */ /* { dg-add-options ieee } */ /* { dg-skip-if "No Inf/NaN support" { spu-*-* } } */ +/* { dg-skip-if "No Denormmalized support" { nds32_ext_fpu } } */ #include "../../gcc.dg/tg-tests.h" diff --git a/gcc/testsuite/gcc.c-torture/compile/limits-fndefn.c b/gcc/testsuite/gcc.c-torture/compile/limits-fndefn.c index 228c5d9..d2d3e51 100644 --- a/gcc/testsuite/gcc.c-torture/compile/limits-fndefn.c +++ b/gcc/testsuite/gcc.c-torture/compile/limits-fndefn.c @@ -1,4 +1,5 @@ /* { dg-skip-if "too complex for avr" { avr-*-* } { "*" } { "" } } */ +/* { dg-skip-if "lto may cause internal compiler error on cygwin with gcc-4.9" { nds32*-*-* } { "*" } { "" } } */ /* { dg-skip-if "ptxas times out" { nvptx-*-* } { "*" } { "" } } */ /* { dg-timeout-factor 4.0 } */ #define LIM1(x) x##0, x##1, x##2, x##3, x##4, x##5, x##6, x##7, x##8, x##9, diff --git a/gcc/testsuite/gcc.c-torture/execute/20010122-1.c b/gcc/testsuite/gcc.c-torture/execute/20010122-1.c index 4eeb8c7..6cd02bc 100644 --- a/gcc/testsuite/gcc.c-torture/execute/20010122-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/20010122-1.c @@ -1,4 +1,5 @@ /* { dg-skip-if "requires frame pointers" { *-*-* } "-fomit-frame-pointer" "" } */ +/* { dg-additional-options "-malways-save-lp" { target nds32*-*-* } } */ /* { dg-require-effective-target return_address } */ extern void exit (int); diff --git a/gcc/testsuite/gcc.c-torture/execute/920501-8.x b/gcc/testsuite/gcc.c-torture/execute/920501-8.x new file mode 100644 index 0000000..96f05bc --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/920501-8.x @@ -0,0 +1,11 @@ +# Please see Andes Bugzilla #11005 for the details. +if { [istarget "nds32*-*-*"] } { + # The nds32 mculib toolchains require + # "-u_printf_float" and "-u_scanf_float" options + # to fully support printf and scanf functionality. + # These options are supposed to be harmless to newlib toolchain. + set additional_flags "-u_printf_float -u_scanf_float" +} + +return 0 + diff --git a/gcc/testsuite/gcc.c-torture/execute/930513-1.x b/gcc/testsuite/gcc.c-torture/execute/930513-1.x new file mode 100644 index 0000000..96f05bc --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/930513-1.x @@ -0,0 +1,11 @@ +# Please see Andes Bugzilla #11005 for the details. +if { [istarget "nds32*-*-*"] } { + # The nds32 mculib toolchains require + # "-u_printf_float" and "-u_scanf_float" options + # to fully support printf and scanf functionality. + # These options are supposed to be harmless to newlib toolchain. + set additional_flags "-u_printf_float -u_scanf_float" +} + +return 0 + diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/ieee.exp b/gcc/testsuite/gcc.c-torture/execute/ieee/ieee.exp index 009984e..19cfcca 100644 --- a/gcc/testsuite/gcc.c-torture/execute/ieee/ieee.exp +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/ieee.exp @@ -30,6 +30,10 @@ load_lib c-torture.exp # Disable tests on machines with no hardware support for IEEE arithmetic. if { [istarget "vax-*-*"] || [ istarget "powerpc-*-*spe"] || [istarget "pdp11-*-*"] } { return } +# Since we cannot use dg-skip-if or dg-require-effective-target for individual +# test case under ieee category, we disable all ieee tests on nds32 fpu toolchains. +if { [istarget "nds32*-*-*"] && [check_effective_target_nds32_ext_fpu] } { return } + if $tracelevel then { strace $tracelevel } diff --git a/gcc/testsuite/gcc.c-torture/execute/pr60822.c b/gcc/testsuite/gcc.c-torture/execute/pr60822.c index dcd2447..a305df3 100644 --- a/gcc/testsuite/gcc.c-torture/execute/pr60822.c +++ b/gcc/testsuite/gcc.c-torture/execute/pr60822.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target int32plus } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ struct X { char fill0[800000]; int a; diff --git a/gcc/testsuite/gcc.c-torture/execute/struct-ret-1.x b/gcc/testsuite/gcc.c-torture/execute/struct-ret-1.x new file mode 100644 index 0000000..96f05bc --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/struct-ret-1.x @@ -0,0 +1,11 @@ +# Please see Andes Bugzilla #11005 for the details. +if { [istarget "nds32*-*-*"] } { + # The nds32 mculib toolchains require + # "-u_printf_float" and "-u_scanf_float" options + # to fully support printf and scanf functionality. + # These options are supposed to be harmless to newlib toolchain. + set additional_flags "-u_printf_float -u_scanf_float" +} + +return 0 + diff --git a/gcc/testsuite/gcc.dg/constructor-1.c b/gcc/testsuite/gcc.dg/constructor-1.c index 73e9fc3..827987e 100644 --- a/gcc/testsuite/gcc.dg/constructor-1.c +++ b/gcc/testsuite/gcc.dg/constructor-1.c @@ -1,6 +1,7 @@ /* { dg-do run } */ /* { dg-options "-O2" } */ /* { dg-skip-if "" { ! global_constructor } { "*" } { "" } } */ +/* { dg-options "-O2 -mctor-dtor" { target { nds32*-*-* } } } */ /* The ipa-split pass pulls the body of the if(!x) block into a separate function to make foo a better inlining diff --git a/gcc/testsuite/gcc.dg/graphite/interchange-0.c b/gcc/testsuite/gcc.dg/graphite/interchange-0.c index d56be46..b83535c 100644 --- a/gcc/testsuite/gcc.dg/graphite/interchange-0.c +++ b/gcc/testsuite/gcc.dg/graphite/interchange-0.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target size32plus } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ #define DEBUG 0 diff --git a/gcc/testsuite/gcc.dg/graphite/interchange-1.c b/gcc/testsuite/gcc.dg/graphite/interchange-1.c index b65d486..2d77f0e 100644 --- a/gcc/testsuite/gcc.dg/graphite/interchange-1.c +++ b/gcc/testsuite/gcc.dg/graphite/interchange-1.c @@ -1,4 +1,6 @@ /* { dg-require-effective-target size32plus } */ +/* { dg-require-effective-target nds32_full_addr_space { target nds32*-*-elf* } } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ /* Formerly known as ltrans-1.c */ diff --git a/gcc/testsuite/gcc.dg/graphite/interchange-10.c b/gcc/testsuite/gcc.dg/graphite/interchange-10.c index a955644..2021de2 100644 --- a/gcc/testsuite/gcc.dg/graphite/interchange-10.c +++ b/gcc/testsuite/gcc.dg/graphite/interchange-10.c @@ -1,4 +1,6 @@ /* { dg-require-effective-target size32plus } */ +/* { dg-require-effective-target nds32_full_addr_space { target nds32*-*-elf* } } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ #define DEBUG 0 #if DEBUG diff --git a/gcc/testsuite/gcc.dg/graphite/interchange-11.c b/gcc/testsuite/gcc.dg/graphite/interchange-11.c index 6102822..5abb316 100644 --- a/gcc/testsuite/gcc.dg/graphite/interchange-11.c +++ b/gcc/testsuite/gcc.dg/graphite/interchange-11.c @@ -1,4 +1,6 @@ /* { dg-require-effective-target size32plus } */ +/* { dg-require-effective-target nds32_full_addr_space { target nds32*-*-elf* } } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ #define DEBUG 0 #if DEBUG diff --git a/gcc/testsuite/gcc.dg/graphite/interchange-15.c b/gcc/testsuite/gcc.dg/graphite/interchange-15.c index 7410f29..1f71f06 100644 --- a/gcc/testsuite/gcc.dg/graphite/interchange-15.c +++ b/gcc/testsuite/gcc.dg/graphite/interchange-15.c @@ -1,4 +1,6 @@ /* { dg-require-effective-target size32plus } */ +/* { dg-require-effective-target nds32_full_addr_space { target nds32*-*-elf* } } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ #define DEBUG 0 #if DEBUG diff --git a/gcc/testsuite/gcc.dg/graphite/interchange-2.c b/gcc/testsuite/gcc.dg/graphite/interchange-2.c index 936ee00..0041649 100644 --- a/gcc/testsuite/gcc.dg/graphite/interchange-2.c +++ b/gcc/testsuite/gcc.dg/graphite/interchange-2.c @@ -1,4 +1,6 @@ /* { dg-require-effective-target size32plus } */ +/* { dg-require-effective-target nds32_full_addr_space { target nds32*-*-elf* } } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ /* Formerly known as ltrans-2.c */ diff --git a/gcc/testsuite/gcc.dg/graphite/interchange-3.c b/gcc/testsuite/gcc.dg/graphite/interchange-3.c index 4aec824..6635529 100644 --- a/gcc/testsuite/gcc.dg/graphite/interchange-3.c +++ b/gcc/testsuite/gcc.dg/graphite/interchange-3.c @@ -1,4 +1,6 @@ /* { dg-require-effective-target size32plus } */ +/* { dg-require-effective-target nds32_full_addr_space { target nds32*-*-elf* } } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ /* Formerly known as ltrans-3.c */ diff --git a/gcc/testsuite/gcc.dg/graphite/interchange-4.c b/gcc/testsuite/gcc.dg/graphite/interchange-4.c index 463ecb5..359f0ac 100644 --- a/gcc/testsuite/gcc.dg/graphite/interchange-4.c +++ b/gcc/testsuite/gcc.dg/graphite/interchange-4.c @@ -1,4 +1,6 @@ /* { dg-require-effective-target size32plus } */ +/* { dg-require-effective-target nds32_full_addr_space { target nds32*-*-elf* } } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ /* Formerly known as ltrans-4.c */ diff --git a/gcc/testsuite/gcc.dg/graphite/interchange-5.c b/gcc/testsuite/gcc.dg/graphite/interchange-5.c index e5aaa64..892257e 100644 --- a/gcc/testsuite/gcc.dg/graphite/interchange-5.c +++ b/gcc/testsuite/gcc.dg/graphite/interchange-5.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target size32plus } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ /* Formerly known as ltrans-5.c */ diff --git a/gcc/testsuite/gcc.dg/graphite/interchange-mvt.c b/gcc/testsuite/gcc.dg/graphite/interchange-mvt.c index c6543ec..51c6ee5 100644 --- a/gcc/testsuite/gcc.dg/graphite/interchange-mvt.c +++ b/gcc/testsuite/gcc.dg/graphite/interchange-mvt.c @@ -1,4 +1,6 @@ /* { dg-require-effective-target size32plus } */ +/* { dg-require-effective-target nds32_full_addr_space { target nds32*-*-elf* } } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ #define DEBUG 0 #if DEBUG diff --git a/gcc/testsuite/gcc.dg/graphite/pr46185.c b/gcc/testsuite/gcc.dg/graphite/pr46185.c index 36d46a4..738c9a8 100644 --- a/gcc/testsuite/gcc.dg/graphite/pr46185.c +++ b/gcc/testsuite/gcc.dg/graphite/pr46185.c @@ -1,5 +1,7 @@ /* { dg-do run } */ +/* { dg-require-effective-target nds32_full_addr_space { target nds32*-*-elf* } } */ /* { dg-options "-O2 -floop-interchange -ffast-math -fno-ipa-cp" } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ #define DEBUG 0 #if DEBUG diff --git a/gcc/testsuite/gcc.dg/graphite/uns-interchange-15.c b/gcc/testsuite/gcc.dg/graphite/uns-interchange-15.c index fe2669f..dd77aa3 100644 --- a/gcc/testsuite/gcc.dg/graphite/uns-interchange-15.c +++ b/gcc/testsuite/gcc.dg/graphite/uns-interchange-15.c @@ -1,4 +1,6 @@ /* { dg-require-effective-target size32plus } */ +/* { dg-require-effective-target nds32_full_addr_space { target nds32*-*-elf* } } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ #define DEBUG 0 #if DEBUG diff --git a/gcc/testsuite/gcc.dg/graphite/uns-interchange-mvt.c b/gcc/testsuite/gcc.dg/graphite/uns-interchange-mvt.c index 211c9ab..c7defb4 100644 --- a/gcc/testsuite/gcc.dg/graphite/uns-interchange-mvt.c +++ b/gcc/testsuite/gcc.dg/graphite/uns-interchange-mvt.c @@ -1,4 +1,6 @@ /* { dg-require-effective-target size32plus } */ +/* { dg-require-effective-target nds32_full_addr_space { target nds32*-*-elf* } } */ +/* { dg-additional-options "-mcmodel=large" { target nds32*-*-elf* } } */ #define DEBUG 0 #if DEBUG diff --git a/gcc/testsuite/gcc.dg/initpri1.c b/gcc/testsuite/gcc.dg/initpri1.c index 794ea2b..10b3a24 100644 --- a/gcc/testsuite/gcc.dg/initpri1.c +++ b/gcc/testsuite/gcc.dg/initpri1.c @@ -1,4 +1,5 @@ /* { dg-do run { target init_priority } } */ +/* { dg-options "-mctor-dtor" { target { nds32*-*-* } } } */ extern void abort (); diff --git a/gcc/testsuite/gcc.dg/initpri2.c b/gcc/testsuite/gcc.dg/initpri2.c index fa9fda0..1418411 100644 --- a/gcc/testsuite/gcc.dg/initpri2.c +++ b/gcc/testsuite/gcc.dg/initpri2.c @@ -1,4 +1,5 @@ /* { dg-do compile { target init_priority } } */ +/* { dg-options "-mctor-dtor" { target { nds32*-*-* } } } */ /* Priorities must be in the range [0, 65535]. */ void c1() diff --git a/gcc/testsuite/gcc.dg/initpri3.c b/gcc/testsuite/gcc.dg/initpri3.c index 1633da0..e1b8cf6 100644 --- a/gcc/testsuite/gcc.dg/initpri3.c +++ b/gcc/testsuite/gcc.dg/initpri3.c @@ -1,6 +1,7 @@ /* { dg-do run { target init_priority } } */ /* { dg-require-effective-target lto } */ /* { dg-options "-flto -O3" } */ +/* { dg-options "-flto -O3 -mctor-dtor" { target { nds32*-*-* } } } */ extern void abort (); diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-1.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-1.c index 4db904b..2290d8b 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-sra-1.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-1.c @@ -1,5 +1,6 @@ /* { dg-do run } */ /* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */ +/* { dg-additional-options "-u_printf_float -u_scanf_float" { target nds32*-*-* } } */ struct bovid { diff --git a/gcc/testsuite/gcc.dg/lower-subreg-1.c b/gcc/testsuite/gcc.dg/lower-subreg-1.c index 47057fe..25439b1 100644 --- a/gcc/testsuite/gcc.dg/lower-subreg-1.c +++ b/gcc/testsuite/gcc.dg/lower-subreg-1.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target { ! { mips64 || { aarch64*-*-* arm*-*-* ia64-*-* sparc*-*-* spu-*-* tilegx-*-* } } } } } */ +/* { dg-do compile { target { ! { mips64 || { aarch64*-*-* arm*-*-* ia64-*-* sparc*-*-* spu-*-* tilegx-*-* nds32*-*-* } } } } } */ /* { dg-options "-O -fdump-rtl-subreg1" } */ /* { dg-additional-options "-mno-stv" { target ia32 } } */ /* { dg-skip-if "" { { i?86-*-* x86_64-*-* } && x32 } { "*" } { "" } } */ diff --git a/gcc/testsuite/gcc.dg/pr28796-2.c b/gcc/testsuite/gcc.dg/pr28796-2.c index f56a5d4..fff71bc 100644 --- a/gcc/testsuite/gcc.dg/pr28796-2.c +++ b/gcc/testsuite/gcc.dg/pr28796-2.c @@ -2,6 +2,7 @@ /* { dg-options "-O2 -funsafe-math-optimizations -fno-finite-math-only -DUNSAFE" } */ /* { dg-add-options ieee } */ /* { dg-skip-if "No Inf/NaN support" { spu-*-* } } */ +/* { dg-skip-if "No Denormmalized support" { nds32_ext_fpu } } */ #include "tg-tests.h" diff --git a/gcc/testsuite/gcc.dg/sibcall-10.c b/gcc/testsuite/gcc.dg/sibcall-10.c index d98b43a..bb0e24c 100644 --- a/gcc/testsuite/gcc.dg/sibcall-10.c +++ b/gcc/testsuite/gcc.dg/sibcall-10.c @@ -5,7 +5,7 @@ Copyright (C) 2002 Free Software Foundation Inc. Contributed by Hans-Peter Nilsson */ -/* { dg-do run { xfail { { cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* mcore-*-* mn10300-*-* msp430*-*-* nds32*-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */ +/* { dg-do run { xfail { { cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* mcore-*-* mn10300-*-* msp430*-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */ /* -mlongcall disables sibcall patterns. */ /* { dg-skip-if "" { powerpc*-*-* } { "-mlongcall" } { "" } } */ /* { dg-options "-O2 -foptimize-sibling-calls" } */ diff --git a/gcc/testsuite/gcc.dg/sibcall-3.c b/gcc/testsuite/gcc.dg/sibcall-3.c index eafe8dd..f188a18 100644 --- a/gcc/testsuite/gcc.dg/sibcall-3.c +++ b/gcc/testsuite/gcc.dg/sibcall-3.c @@ -5,7 +5,7 @@ Copyright (C) 2002 Free Software Foundation Inc. Contributed by Hans-Peter Nilsson */ -/* { dg-do run { xfail { { cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* mcore-*-* mn10300-*-* msp430*-*-* nds32*-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */ +/* { dg-do run { xfail { { cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* mcore-*-* mn10300-*-* msp430*-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */ /* -mlongcall disables sibcall patterns. */ /* { dg-skip-if "" { powerpc*-*-* } { "-mlongcall" } { "" } } */ /* { dg-options "-O2 -foptimize-sibling-calls" } */ diff --git a/gcc/testsuite/gcc.dg/sibcall-4.c b/gcc/testsuite/gcc.dg/sibcall-4.c index 1e039c6..a8c844a 100644 --- a/gcc/testsuite/gcc.dg/sibcall-4.c +++ b/gcc/testsuite/gcc.dg/sibcall-4.c @@ -5,7 +5,7 @@ Copyright (C) 2002 Free Software Foundation Inc. Contributed by Hans-Peter Nilsson */ -/* { dg-do run { xfail { { cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* mcore-*-* mn10300-*-* msp430*-*-* nds32*-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */ +/* { dg-do run { xfail { { cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* mcore-*-* mn10300-*-* msp430*-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */ /* -mlongcall disables sibcall patterns. */ /* { dg-skip-if "" { powerpc*-*-* } { "-mlongcall" } { "" } } */ /* { dg-options "-O2 -foptimize-sibling-calls" } */ diff --git a/gcc/testsuite/gcc.dg/sibcall-9.c b/gcc/testsuite/gcc.dg/sibcall-9.c index 34e7053..71c3251 100644 --- a/gcc/testsuite/gcc.dg/sibcall-9.c +++ b/gcc/testsuite/gcc.dg/sibcall-9.c @@ -5,7 +5,7 @@ Copyright (C) 2002 Free Software Foundation Inc. Contributed by Hans-Peter Nilsson */ -/* { dg-do run { xfail { { cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* mcore-*-* mn10300-*-* msp430*-*-* nds32*-*-* nvptx-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */ +/* { dg-do run { xfail { { cris-*-* crisv32-*-* h8300-*-* hppa*64*-*-* m32r-*-* mcore-*-* mn10300-*-* msp430*-*-* nvptx-*-* xstormy16-*-* v850*-*-* vax-*-* xtensa*-*-* } || { arm*-*-* && { ! arm32 } } } } } */ /* -mlongcall disables sibcall patterns. */ /* { dg-skip-if "" { powerpc*-*-* } { "-mlongcall" } { "" } } */ /* { dg-options "-O2 -foptimize-sibling-calls" } */ diff --git a/gcc/testsuite/gcc.dg/stack-usage-1.c b/gcc/testsuite/gcc.dg/stack-usage-1.c index 7864c6a..c768ca2 100644 --- a/gcc/testsuite/gcc.dg/stack-usage-1.c +++ b/gcc/testsuite/gcc.dg/stack-usage-1.c @@ -2,6 +2,7 @@ /* { dg-options "-fstack-usage" } */ /* nvptx doesn't have a reg allocator, and hence no stack usage data. */ /* { dg-skip-if "" { nvptx-*-* } { "*" } { "" } } */ +/* { dg-options "-fstack-usage -fno-omit-frame-pointer" { target { nds32*-*-* } } } */ /* This is aimed at testing basic support for -fstack-usage in the back-ends. See the SPARC back-end for example (grep flag_stack_usage_info in sparc.c). diff --git a/gcc/testsuite/gcc.dg/torture/type-generic-1.c b/gcc/testsuite/gcc.dg/torture/type-generic-1.c index 3897818..6815e8b 100644 --- a/gcc/testsuite/gcc.dg/torture/type-generic-1.c +++ b/gcc/testsuite/gcc.dg/torture/type-generic-1.c @@ -3,6 +3,7 @@ /* { dg-do run } */ /* { dg-skip-if "No Inf/NaN support" { spu-*-* } } */ +/* { dg-skip-if "No Denormmalized support" { nds32_ext_fpu } } */ /* { dg-options "-DUNSAFE" { target tic6x*-*-* visium-*-* } } */ /* { dg-add-options ieee } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-2.c index 1a4bfe6..78c948a 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-2.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-2.c @@ -25,4 +25,4 @@ foo () but the loop reads only one element at a time, and DOM cannot resolve these. The same happens on powerpc depending on the SIMD support available. */ -/* { dg-final { scan-tree-dump "return 28;" "optimized" { xfail { { alpha*-*-* hppa*64*-*-* powerpc64*-*-* } || { sparc*-*-* && lp64 } } } } } */ +/* { dg-final { scan-tree-dump "return 28;" "optimized" { xfail { { alpha*-*-* hppa*64*-*-* powerpc64*-*-* nds32*-*-*} || { sparc*-*-* && lp64 } } } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp88.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp88.c index f70b311..8a1081c 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp88.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp88.c @@ -33,6 +33,6 @@ bitmap_single_bit_set_p (const_bitmap a) } /* Verify that VRP simplified an "if" statement. */ -/* { dg-final { scan-tree-dump "Folded into: if.*" "vrp1"} } */ +/* { dg-final { scan-tree-dump "Folded into: if.*" "vrp1" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.target/nds32/basic-main.c b/gcc/testsuite/gcc.target/nds32/basic-main.c index 6fdbc35..7341fb5 100644 --- a/gcc/testsuite/gcc.target/nds32/basic-main.c +++ b/gcc/testsuite/gcc.target/nds32/basic-main.c @@ -1,9 +1,10 @@ /* This is a basic main function test program. */ -/* { dg-do run } */ -/* { dg-options "-O0" } */ +/* { dg-do run } */ +/* { dg-options "-O0" } */ -int main(void) +int +main (void) { return 0; } diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE1-abs.c b/gcc/testsuite/gcc.target/nds32/builtin-PE1-abs.c new file mode 100644 index 0000000..8cadcfd --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE1-abs.c @@ -0,0 +1,20 @@ +/* This is a test program for abs instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf } */ + +#include +#include + +int +main () +{ + int a = -4; + int abs = __nds32__abs (a); + + if (abs != 4) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE1-ave.c b/gcc/testsuite/gcc.target/nds32/builtin-PE1-ave.c new file mode 100644 index 0000000..d2c87db --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE1-ave.c @@ -0,0 +1,21 @@ +/* This is a test program for ave instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf } */ + +#include +#include + +int +main () +{ + int a = 4; + int b = 2; + int ave = __nds32__ave (a, b); + + if (ave != 3) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE1-bclr.c b/gcc/testsuite/gcc.target/nds32/builtin-PE1-bclr.c new file mode 100644 index 0000000..0e6c1e0 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE1-bclr.c @@ -0,0 +1,20 @@ +/* This is a test program for bclr instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf } */ + +#include +#include + +int +main () +{ + int a = 1; + int c = __nds32__bclr (a, 0); + + if (c != 0) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE1-bset.c b/gcc/testsuite/gcc.target/nds32/builtin-PE1-bset.c new file mode 100644 index 0000000..1bd8513 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE1-bset.c @@ -0,0 +1,20 @@ +/* This is a test program for bset instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf } */ + +#include +#include + +int +main () +{ + int c = 0; + c = __nds32__bset (c, 0); + + if (c != 1) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE1-btgl.c b/gcc/testsuite/gcc.target/nds32/builtin-PE1-btgl.c new file mode 100644 index 0000000..a1dbc00 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE1-btgl.c @@ -0,0 +1,20 @@ +/* This is a test program for btgl instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf } */ + +#include +#include + +int +main () +{ + int a = 1; + int c = __nds32__btgl (1, 0); + + if (c != 0) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE1-btst.c b/gcc/testsuite/gcc.target/nds32/builtin-PE1-btst.c new file mode 100644 index 0000000..c001f94 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE1-btst.c @@ -0,0 +1,20 @@ +/* This is a test program for btst instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf } */ + +#include +#include + +int +main () +{ + int c = 1; + c = __nds32__btst (c, 0); + + if (c != 1) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE1-clip.c b/gcc/testsuite/gcc.target/nds32/builtin-PE1-clip.c new file mode 100644 index 0000000..d63b298 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE1-clip.c @@ -0,0 +1,20 @@ +/* This is a test program for clip instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf } */ + +#include +#include + +int +main () +{ + int c = 33; + c = __nds32__clip (c, 5); + + if (c != 31) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE1-clips.c b/gcc/testsuite/gcc.target/nds32/builtin-PE1-clips.c new file mode 100644 index 0000000..3e3f663 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE1-clips.c @@ -0,0 +1,20 @@ +/* This is a test program for clips instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf } */ + +#include +#include + +int +main () +{ + int a = -33; + int c = __nds32__clips (a, 5); + + if (c != -32) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE1-clo.c b/gcc/testsuite/gcc.target/nds32/builtin-PE1-clo.c new file mode 100644 index 0000000..d672a33 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE1-clo.c @@ -0,0 +1,20 @@ +/* This is a test program for clo instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf } */ + +#include +#include + +int +main () +{ + int c = 0xFFFF0000; + c = __nds32__clo (c); + + if (c != 16) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE1-clz.c b/gcc/testsuite/gcc.target/nds32/builtin-PE1-clz.c new file mode 100644 index 0000000..17e6318 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE1-clz.c @@ -0,0 +1,20 @@ +/* This is a test program for clz instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf } */ + +#include +#include + +int +main () +{ + int c = 0x0000FFFF; + c = __nds32__clz (c); + + if (c != 16) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE2-bse.c b/gcc/testsuite/gcc.target/nds32/builtin-PE2-bse.c new file mode 100644 index 0000000..c769fea --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE2-bse.c @@ -0,0 +1,28 @@ +/* This is a test program for bse instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf2 } */ + +#include +#include + +int +main () +{ + unsigned int a = 0xF0F0F0F0; + unsigned int b = 0x00000300; + unsigned int r = 0; + + unsigned int verify_b = 0x00000300; + unsigned int verify_r = 0; + + __nds32__bse (&r, a, &b); + a = 0xF0F0F0F0; + asm volatile ("bse %0, %2, %1": "+&r" (verify_r), "+&r" (verify_b) : "r" (a)); + + if ((verify_b == b) && (verify_r == r)) + exit (0); + else + abort (); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE2-bsp.c b/gcc/testsuite/gcc.target/nds32/builtin-PE2-bsp.c new file mode 100644 index 0000000..d798719 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE2-bsp.c @@ -0,0 +1,26 @@ +/* This is a test program for bsp instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf2 } */ + +#include +#include + +int +main () +{ + unsigned int a = 0x0000000F; + unsigned int b = 0x00000300; + unsigned int r = 0; + unsigned int verify_b = 0x00000300; + unsigned int verify_r = 0; + + __nds32__bsp (&r, a, &b); + asm volatile ("bsp %0, %2, %1": "+&r" (verify_r), "+&r" (verify_b) : "r" (a)); + + if ((verify_b == b) && (verify_r == r)) + exit (0); + else + abort (); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE2-pbsad.c b/gcc/testsuite/gcc.target/nds32/builtin-PE2-pbsad.c new file mode 100644 index 0000000..bc4fe42 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE2-pbsad.c @@ -0,0 +1,21 @@ +/* This is a test program for pbsad instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf2 } */ + +#include +#include + +int +main () +{ + unsigned int a = 0x09070605; + unsigned int b = 0x04020301; + unsigned int r = __nds32__pbsad (a, b); + + if (r != 17) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-PE2-pbsada.c b/gcc/testsuite/gcc.target/nds32/builtin-PE2-pbsada.c new file mode 100644 index 0000000..6ed1b08 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-PE2-pbsada.c @@ -0,0 +1,23 @@ +/* This is a test program for pbsada instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_perf2 } */ + +#include +#include + +int +main () +{ + unsigned int a = 0x09070605; + unsigned int b = 0x04020301; + unsigned int r = 1; + + r = __nds32__pbsada(r, a, b); + + if (r != 18) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-add16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-add16.c new file mode 100644 index 0000000..0eec324 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-add16.c @@ -0,0 +1,49 @@ +/* This is a test program for add16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int add16 (unsigned int ra, unsigned int rb) +{ + return __nds32__add16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_uadd16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_uadd16 (ra, rb); +} + +static __attribute__ ((noinline)) +int16x2_t v_sadd16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_sadd16 (ra, rb); +} + +int +main () +{ + unsigned int a = add16 (0x0001f000, 0x00011000); + uint16x2_t v_ua = v_uadd16 ((uint16x2_t) {0xf000, 0xf000}, + (uint16x2_t) {0x1000, 0x2000}); + int16x2_t v_sa = v_sadd16 ((int16x2_t) {0xf777, 0xf111}, + (int16x2_t) {0x1000, 0x2000}); + + if (a != 0x00020000) + abort (); + else if (v_ua[0] != 0x0000 + || v_ua[1] != 0x1000) + abort (); + else if (v_sa[0] != 0x0777 + || v_sa[1] != 0x1111) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-add64.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-add64.c new file mode 100644 index 0000000..b761b7f --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-add64.c @@ -0,0 +1,36 @@ +/* This is a test program for add64 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long sadd64 (long long ra, long long rb) +{ + return __nds32__sadd64 (ra, rb); +} + +static __attribute__ ((noinline)) +unsigned long long uadd64 (unsigned long long ra, unsigned long long rb) +{ + return __nds32__uadd64 (ra, rb); +} + +int +main () +{ + long long sa = sadd64 (0x1122334400000000ll, 0x55667788ll); + unsigned long long ua = uadd64 (0xffff00000000ull, 0x55667788ull); + + if (sa != 0x1122334455667788ll) + abort (); + else if (ua != 0xffff55667788ull) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-add8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-add8.c new file mode 100644 index 0000000..77e686c --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-add8.c @@ -0,0 +1,53 @@ +/* This is a test program for add8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int add8 (unsigned int ra, unsigned int rb) +{ + return __nds32__add8 (ra, rb); +} + +static __attribute__ ((noinline)) +uint8x4_t v_uadd8 (uint8x4_t ra, uint8x4_t rb) +{ + return __nds32__v_uadd8 (ra, rb); +} + +static __attribute__ ((noinline)) +int8x4_t v_sadd8 (int8x4_t ra, int8x4_t rb) +{ + return __nds32__v_sadd8 (ra, rb); +} + +int +main () +{ + unsigned int a = add8 (0x11223344, 0x55667788); + uint8x4_t v_ua = v_uadd8 ((uint8x4_t) {0xff, 0xee, 0xdd, 0xcc}, + (uint8x4_t) {0x1, 0xee, 0xdd, 0xcc}); + int8x4_t v_sa = v_sadd8 ((int8x4_t) {0x80, 0x7f, 0xbb, 0xaa}, + (int8x4_t) {0x80, 0x7f, 0xbb, 0xaa}); + + if (a != 0x6688aacc) + abort (); + else if (v_ua[0] != 0 + || v_ua[1] != 0xdc + || v_ua[2] != 0xba + || v_ua[3] != 0x98) + abort (); + else if (v_sa[0] != 0 + || v_sa[1] != (char) 0xfe + || v_sa[2] != 0x76 + || v_sa[3] != 0x54) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-bitrev.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-bitrev.c new file mode 100644 index 0000000..2c8c297 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-bitrev.c @@ -0,0 +1,27 @@ +/* This is a test program for bitrev instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int bitrev (unsigned int ra, unsigned int rb) +{ + return __nds32__bitrev (ra, rb); +} + +int +main () +{ + unsigned int a = bitrev (0xd, 1); + + if (a != 0x2) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-bpick.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-bpick.c new file mode 100644 index 0000000..78893cb --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-bpick.c @@ -0,0 +1,27 @@ +/* This is a test program for bpick instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int bpick (unsigned int ra, unsigned int rb, unsigned int rc) +{ + return __nds32__bpick (ra, rb, rc); +} + +int +main () +{ + unsigned int a = bpick (0x11223344, 0x11332244, 0); + + if (a != 0x11332244) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-cmpeq16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-cmpeq16.c new file mode 100644 index 0000000..c37abf4 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-cmpeq16.c @@ -0,0 +1,49 @@ +/* This is a test program for cmpeq16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int cmpeq16 (unsigned int ra, unsigned int rb) +{ + return __nds32__cmpeq16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_scmpeq16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_scmpeq16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_ucmpeq16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_ucmpeq16 (ra, rb); +} + +int +main () +{ + unsigned int a = cmpeq16 (0xffff0000, 0xffff0001); + uint16x2_t v_sa = v_scmpeq16 ((int16x2_t) {0x7fff, 0x8000}, + (int16x2_t) {0x8000, 0x8000}); + uint16x2_t v_ua = v_ucmpeq16 ((uint16x2_t) {0x7fff, 0x8000}, + (uint16x2_t) {0x8000, 0x8000}); + + if (a != 0xffff0000) + abort (); + else if (v_sa[0] != 0 + || v_sa[1] != 0xffff) + abort (); + else if (v_ua[0] != 0 + || v_ua[1] != 0xffff) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-cmpeq8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-cmpeq8.c new file mode 100644 index 0000000..a692dac --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-cmpeq8.c @@ -0,0 +1,53 @@ +/* This is a test program for cmpeq8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int cmpeq8 (unsigned int ra, unsigned int rb) +{ + return __nds32__cmpeq8 (ra, rb); +} + +static __attribute__ ((noinline)) +uint8x4_t v_scmpeq8 (int8x4_t ra, int8x4_t rb) +{ + return __nds32__v_scmpeq8 (ra, rb); +} + +static __attribute__ ((noinline)) +uint8x4_t v_ucmpeq8 (uint8x4_t ra, uint8x4_t rb) +{ + return __nds32__v_ucmpeq8 (ra, rb); +} + +int +main () +{ + unsigned int a = cmpeq8 (0xffff0000, 0xffff0101); + uint8x4_t v_sa = v_scmpeq8 ((int8x4_t) { 0x7f, 0x7f, 0x01, 0x01}, + (int8x4_t) { 0x7f, 0x7f, 0x00, 0x00}); + uint8x4_t v_ua = v_ucmpeq8 ((uint8x4_t) { 0x7f, 0x7f, 0x01, 0x01}, + (uint8x4_t) { 0x7f, 0x7f, 0x00, 0x00}); + + if (a != 0xffff0000) + abort (); + else if (v_sa[0] != 0xff + || v_sa[1] != 0xff + || v_sa[2] != 0 + || v_sa[3] != 0) + abort (); + else if (v_ua[0] != 0xff + || v_ua[1] != 0xff + || v_ua[2] != 0 + || v_ua[3] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-cras16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-cras16.c new file mode 100644 index 0000000..7d6da46 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-cras16.c @@ -0,0 +1,58 @@ +/* This is a test program for cras16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int cras16 (unsigned int ra, unsigned int rb) +{ + return __nds32__cras16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_ucras16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_ucras16 (ra, rb); +} + +static __attribute__ ((noinline)) +int16x2_t v_scras16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_scras16 (ra, rb); +} + +int +main () +{ + +#ifdef __NDS32_EL__ + uint16x2_t v_ua_p = {1, 0}; + int16x2_t v_sa_p = {0x1000, 0x111}; +#else + uint16x2_t v_ua_p = {0x2469, 0xe000}; + int16x2_t v_sa_p = {0x3000, 0xe111}; +#endif + + unsigned int a = cras16 (0x0001f000, 0x0001f000); + uint16x2_t v_ua = v_ucras16 ((uint16x2_t) {0x1235, 0xf000}, + (uint16x2_t) {0x1000, 0x1234}); + int16x2_t v_sa = v_scras16 ((int16x2_t) {0x2000, 0xf111}, + (int16x2_t) {0x1000, 0x1000}); + + if (a != 0xf001efff) + abort (); + else if (v_ua[0] != v_ua_p[0] + || v_ua[1] != v_ua_p[1]) + abort (); + else if (v_sa[0] != v_sa_p[0] + || v_sa[1] != v_sa_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-crsa16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-crsa16.c new file mode 100644 index 0000000..de99c3a --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-crsa16.c @@ -0,0 +1,57 @@ +/* This is a test program for crsa16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int crsa16 (unsigned int ra, unsigned int rb) +{ + return __nds32__crsa16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_ucrsa16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_ucrsa16 (ra, rb); +} + +static __attribute__ ((noinline)) +int16x2_t v_scrsa16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_scrsa16 (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + uint16x2_t v_ua_p = {0x2469, 0xe000}; + int16x2_t v_sa_p = {0x3000, 0x110}; +#else + uint16x2_t v_ua_p = {1, 0}; + int16x2_t v_sa_p = {0x1000, 0x112}; +#endif + + unsigned int a = crsa16 (0x0001f000, 0x0001f000); + uint16x2_t v_ua = v_ucrsa16 ((uint16x2_t) {0x1235, 0xf000}, + (uint16x2_t) {0x1000, 0x1234}); + int16x2_t v_sa = v_scrsa16 ((int16x2_t) {0x2000, 0x0111}, + (int16x2_t) {0x0001, 0x1000}); + + if (a != 0x1001f001) + abort (); + else if (v_ua[0] != v_ua_p[0] + || v_ua[1] != v_ua_p[1]) + abort (); + else if (v_sa[0] != v_sa_p[0] + || v_sa[1] != v_sa_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-insb.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-insb.c new file mode 100644 index 0000000..ebd0348 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-insb.c @@ -0,0 +1,27 @@ +/* This is a test program for insb instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int insb (unsigned int ra, unsigned int rb) +{ + return __nds32__insb (ra, rb, 1); +} + +int +main () +{ + unsigned int a = insb (0x11220044, 0x33); + + if (a != 0x11223344) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-pkbb16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-pkbb16.c new file mode 100644 index 0000000..23d92e9 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-pkbb16.c @@ -0,0 +1,44 @@ +/* This is a test program for pkbb16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int pkbb16 (unsigned int ra, unsigned int rb) +{ + return __nds32__pkbb16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_pkbb16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_pkbb16 (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + uint16x2_t va_p = {0xcccc, 0xaaaa}; +#else + uint16x2_t va_p = {0xbbbb, 0xdddd}; +#endif + + unsigned int a = pkbb16 (0x11223344, 0x55667788); + uint16x2_t va = v_pkbb16 ((uint16x2_t) {0xaaaa, 0xbbbb}, + (uint16x2_t) {0xcccc, 0xdddd}); + + if (a != 0x33447788) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-pkbt16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-pkbt16.c new file mode 100644 index 0000000..6c34420 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-pkbt16.c @@ -0,0 +1,44 @@ +/* This is a test program for pkbt16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int pkbt16 (unsigned int ra, unsigned int rb) +{ + return __nds32__pkbt16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_pkbt16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_pkbt16 (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + uint16x2_t va_p = {0xdddd, 0xaaaa}; +#else + uint16x2_t va_p = {0xbbbb, 0xcccc}; +#endif + + unsigned int a = pkbt16 (0x11223344, 0x55667788); + uint16x2_t va = v_pkbt16 ((uint16x2_t) {0xaaaa, 0xbbbb}, + (uint16x2_t) {0xcccc, 0xdddd}); + + if (a != 0x33445566) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-pktb16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-pktb16.c new file mode 100644 index 0000000..0aab5df --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-pktb16.c @@ -0,0 +1,44 @@ +/* This is a test program for pktb16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int pktb16 (unsigned int ra, unsigned int rb) +{ + return __nds32__pktb16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_pktb16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_pktb16 (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + uint16x2_t va_p = {0xcccc, 0xbbbb}; +#else + uint16x2_t va_p = {0xaaaa, 0xdddd}; +#endif + + unsigned int a = pktb16 (0x11223344, 0x55667788); + uint16x2_t va = v_pktb16 ((uint16x2_t) {0xaaaa, 0xbbbb}, + (uint16x2_t) {0xcccc, 0xdddd}); + + if (a != 0x11227788) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-pktt16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-pktt16.c new file mode 100644 index 0000000..745cde5 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-pktt16.c @@ -0,0 +1,44 @@ +/* This is a test program for pktt16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int pktt16 (unsigned int ra, unsigned int rb) +{ + return __nds32__pktt16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_pktt16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_pktt16 (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + uint16x2_t va_p = {0xdddd, 0xbbbb}; +#else + uint16x2_t va_p = {0xaaaa, 0xcccc}; +#endif + + unsigned int a = pktt16 (0x11223344, 0x55667788); + uint16x2_t va = v_pktt16 ((uint16x2_t) {0xaaaa, 0xbbbb}, + (uint16x2_t) {0xcccc, 0xdddd}); + + if (a != 0x11225566) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-radd16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-radd16.c new file mode 100644 index 0000000..5271b41 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-radd16.c @@ -0,0 +1,38 @@ +/* This is a test program for radd16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int radd16 (unsigned int ra, unsigned int rb) +{ + return __nds32__radd16 (ra, rb); +} + +static __attribute__ ((noinline)) +int16x2_t v_radd16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_radd16 (ra, rb); +} + +int +main () +{ + unsigned int a = radd16 (0x7fff7fff, 0x7fff7fff); + int16x2_t va = v_radd16 ((int16x2_t) {0x8000, 0x4000}, + (int16x2_t) {0x8000, 0x8000}); + + if (a != 0x7fff7fff) + abort (); + else if (va[0] != (short) 0x8000 + || va[1] != (short) 0xe000) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-radd64.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-radd64.c new file mode 100644 index 0000000..3e82ff5 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-radd64.c @@ -0,0 +1,27 @@ +/* This is a test program for radd64 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long radd64 (long long ra, long long rb) +{ + return __nds32__radd64 (ra, rb); +} + +int +main () +{ + long long a = radd64 (0xf000000000000000ll, 0xf000000000000000ll); + + if (a != 0xf000000000000000ll) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-radd8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-radd8.c new file mode 100644 index 0000000..10735a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-radd8.c @@ -0,0 +1,40 @@ +/* This is a test program for radd8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int radd8 (unsigned int ra, unsigned int rb) +{ + return __nds32__radd8 (ra, rb); +} + +static __attribute__ ((noinline)) +int8x4_t v_radd8 (int8x4_t ra, int8x4_t rb) +{ + return __nds32__v_radd8 (ra, rb); +} + +int +main () +{ + unsigned int a = radd8 (0x11223344, 0x55667788); + int8x4_t va = v_radd8 ((int8x4_t) {0x7f, 0x80, 0x80, 0xaa}, + (int8x4_t) {0x7f, 0x80, 0x40, 0xaa}); + + if (a != 0x334455e6) + abort (); + else if (va[0] != 0x7f + || va[1] != (char) 0x80 + || va[2] != (char) 0xe0 + || va[3] != (char) 0xaa) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-raddw.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-raddw.c new file mode 100644 index 0000000..190a477 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-raddw.c @@ -0,0 +1,27 @@ +/* This is a test program for raddw instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int raddw (int ra, int rb) +{ + return __nds32__raddw (ra, rb); +} + +int +main () +{ + int a = raddw (0x80000000, 0x80000000); + + if (a != 0x80000000) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-rcras16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-rcras16.c new file mode 100644 index 0000000..2a2288a --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-rcras16.c @@ -0,0 +1,44 @@ +/* This is a test program for rcras16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int rcras16 (unsigned int ra, unsigned int rb) +{ + return __nds32__rcras16 (ra, rb); +} + +static __attribute__ ((noinline)) +int16x2_t v_rcras16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_rcras16 (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int16x2_t va_p = {0x7fff, 0x8000}; +#else + int16x2_t va_p = {0xffff, 0}; +#endif + + unsigned int a = rcras16 (0x0fff0000, 0x00000fff); + int16x2_t va = v_rcras16 ((int16x2_t) {0x7fff, 0x8000}, + (int16x2_t) {0x8000, 0x8000}); + + if (a != 0x0fff0000) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-rcrsa16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-rcrsa16.c new file mode 100644 index 0000000..ebcc0f6 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-rcrsa16.c @@ -0,0 +1,44 @@ +/* This is a test program for rcrsa16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int rcrsa16 (unsigned int ra, unsigned int rb) +{ + return __nds32__rcrsa16 (ra, rb); +} + +static __attribute__ ((noinline)) +int16x2_t v_rcrsa16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_rcrsa16 (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int16x2_t va_p = {0x8000, 0x8000}; +#else + int16x2_t va_p = {0, 0xffff}; +#endif + + unsigned int a = rcrsa16 (0x7fff7fff, 0x7fff8000); + int16x2_t va = v_rcrsa16 ((int16x2_t) {0x8000, 0x8000}, + (int16x2_t) {0x7fff, 0x8000}); + + if (a != 0x7fff7fff) + abort (); + else if (va[0] != va_p [0] + || va[1] != va_p [1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-rsub16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-rsub16.c new file mode 100644 index 0000000..f9fcc86 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-rsub16.c @@ -0,0 +1,38 @@ +/* This is a test program for rsub16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int rsub16 (unsigned int ra, unsigned int rb) +{ + return __nds32__rsub16 (ra, rb); +} + +static __attribute__ ((noinline)) +int16x2_t v_rsub16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_rsub16 (ra, rb); +} + +int +main () +{ + unsigned int a = rsub16 (0x7fff7fff, 0x80008000); + int16x2_t va = v_rsub16 ((int16x2_t) {0x8000, 0x8000}, + (int16x2_t) {0x7fff, 0x4000}); + + if (a != 0x7fff7fff) + abort (); + else if (va[0] != (short) 0x8000 + || va[1] != (short) 0xa000) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-rsub64.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-rsub64.c new file mode 100644 index 0000000..227eba7 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-rsub64.c @@ -0,0 +1,27 @@ +/* This is a test program for rsub64 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long rsub64 (long long ra, long long rb) +{ + return __nds32__rsub64 (ra, rb); +} + +int +main () +{ + long long a = rsub64 (0xe, 0xf); + + if (a != 0xffffffffffffffff) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-rsub8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-rsub8.c new file mode 100644 index 0000000..0f1dddc5 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-rsub8.c @@ -0,0 +1,40 @@ +/* This is a test program for rsub8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int rsub8 (unsigned int ra, unsigned int rb) +{ + return __nds32__rsub8 (ra, rb); +} + +static __attribute__ ((noinline)) +int8x4_t v_rsub8 (int8x4_t ra, int8x4_t rb) +{ + return __nds32__v_rsub8 (ra, rb); +} + +int +main () +{ + unsigned int a = rsub8 (0x55667788, 0x11223344); + int8x4_t va = v_rsub8 ((int8x4_t) {0x7f, 0x80, 0x80, 0xaa}, + (int8x4_t) {0x80, 0x7f, 0x40, 0xaa}); + + if (a != 0x222222a2) + abort (); + else if (va[0] != 0x7f + || va[1] != (char) 0x80 + || va[2] != (char) 0xa0 + || va[3] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-rsubw.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-rsubw.c new file mode 100644 index 0000000..b70a229 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-rsubw.c @@ -0,0 +1,27 @@ +/* This is a test program for rsubw instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int rsubw (int ra, int rb) +{ + return __nds32__rsubw (ra, rb); +} + +int +main () +{ + int a = rsubw (0x80000000, 0x7fffffff); + + if (a != 0x80000000) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-scmple16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-scmple16.c new file mode 100644 index 0000000..95251d6 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-scmple16.c @@ -0,0 +1,37 @@ +/* This is a test program for scmple16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int scmple16 (unsigned int ra, unsigned int rb) +{ + return __nds32__scmple16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_scmple16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_scmple16 (ra, rb); +} + +int +main () +{ + unsigned int a = scmple16 (0xfffe0001, 0xffff0000); + uint16x2_t va = v_scmple16 ((int16x2_t) {0x7fff, 0x7ffe}, + (int16x2_t) {0x7ffe, 0x7fff}); + if (a != 0xffff0000) + abort (); + else if (va[0] != 0 + || va[1] != 0xffff) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-scmple8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-scmple8.c new file mode 100644 index 0000000..6c0033d --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-scmple8.c @@ -0,0 +1,40 @@ +/* This is a test program for scmple8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int scmple8 (unsigned int ra, unsigned int rb) +{ + return __nds32__scmple8 (ra, rb); +} + +static __attribute__ ((noinline)) +uint8x4_t v_scmple8 (int8x4_t ra, int8x4_t rb) +{ + return __nds32__v_scmple8 (ra, rb); +} + +int +main () +{ + unsigned int a = scmple8 (0xfefe0101, 0xffff0000); + uint8x4_t va = v_scmple8 ((int8x4_t) {0x7e, 0x7e, 0x01, 0x01}, + (int8x4_t) {0x7f, 0x7f, 0x00, 0x00}); + + if (a != 0xffff0000) + abort (); + else if (va[0] != 0xff + || va[1] != 0xff + || va[2] != 0 + || va[3] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-scmplt16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-scmplt16.c new file mode 100644 index 0000000..5797711 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-scmplt16.c @@ -0,0 +1,38 @@ +/* This is a test program for scmplt16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int scmplt16 (unsigned int ra, unsigned int rb) +{ + return __nds32__scmplt16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_scmplt16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_scmplt16 (ra, rb); +} + +int +main () +{ + unsigned int a = scmplt16 (0xfffe0001, 0xffff0000); + uint16x2_t va = v_scmplt16 ((int16x2_t) {0x7fff, 0x7ffe}, + (int16x2_t) {0x7ffe, 0x7fff}); + + if (a != 0xffff0000) + abort (); + else if (va[0] != 0 + || va[1] != 0xffff) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-scmplt8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-scmplt8.c new file mode 100644 index 0000000..3e52006 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-scmplt8.c @@ -0,0 +1,40 @@ +/* This is a test program for scmplt8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int scmplt8 (unsigned int ra, unsigned int rb) +{ + return __nds32__scmplt8 (ra, rb); +} + +static __attribute__ ((noinline)) +uint8x4_t v_scmplt8 (int8x4_t ra, int8x4_t rb) +{ + return __nds32__v_scmplt8 (ra, rb); +} + +int +main () +{ + unsigned int a = scmplt8 (0xfefe0101, 0xffff0000); + uint8x4_t va = v_scmplt8 ((int8x4_t) {0x7e, 0x7e, 0x01, 0x01}, + (int8x4_t) {0x7f, 0x7f, 0x00, 0x00}); + + if (a != 0xffff0000) + abort (); + else if (va[0] != 0xff + || va[1] != 0xff + || va[2] != 0 + || va[3] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-sll16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sll16.c new file mode 100644 index 0000000..5ab9506 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sll16.c @@ -0,0 +1,37 @@ +/* This is a test program for sll16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int sll16 (unsigned int ra, unsigned int rb) +{ + return __nds32__sll16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_sll16 (uint16x2_t ra, unsigned int rb) +{ + return __nds32__v_sll16 (ra, rb); +} + +int +main () +{ + unsigned int a = sll16 (0x0f00f000, 4); + uint16x2_t va = v_sll16 ((uint16x2_t) {0x7fff, 0x8000}, 4); + + if (a != 0xf0000000) + abort (); + else if (va[0] != 0xfff0 + || va[1] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smal.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smal.c new file mode 100644 index 0000000..f7e54b7 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smal.c @@ -0,0 +1,36 @@ +/* This is a test program for smal instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smal (long long ra, unsigned int rb) +{ + return __nds32__smal (ra, rb); +} + +static __attribute__ ((noinline)) +long long v_smal (long long ra, int16x2_t rb) +{ + return __nds32__v_smal (ra, rb); +} + +int +main () +{ + long long a = smal (0xfffff0000ll, 0x0001ffff); + long long va = v_smal (0xffffff0000ll, + (int16x2_t) {0x0002, 0xffff}); + if (a != 0xffffeffffll) + abort (); + else if (va != 0xfffffefffell) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalbb.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalbb.c new file mode 100644 index 0000000..c39a889 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalbb.c @@ -0,0 +1,45 @@ +/* This is a test program for smalbb instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smalbb (long long t, unsigned int a, unsigned int b) +{ + return __nds32__smalbb (t, a, b); +} + +static __attribute__ ((noinline)) +long long v_smalbb (long long t, int16x2_t a, int16x2_t b) +{ + return __nds32__v_smalbb (t, a, b); +} + + +int +main () +{ +#ifdef __NDS32_EL__ + long long a_p = 0x12345679075ca9d3ll; + long long va_p = 0x12345679075ca9d3ll; +#else + long long a_p = 0x12345679075ca9d3ll; + long long va_p = 0x12345678ffffffffll; +#endif + + long long a = smalbb (0x12345678ffffffffll,0x00006789, 0x00001234); + long long va = v_smalbb (0x12345678ffffffffll, (int16x2_t) {0x6789, 0}, + (int16x2_t) {0x1234, 0}); + if (a != a_p) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalbt.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalbt.c new file mode 100644 index 0000000..06577fd --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalbt.c @@ -0,0 +1,45 @@ +/* This is a test program for smalbt instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smalbt (long long t, unsigned int a, unsigned int b) +{ + return __nds32__smalbt (t, a, b); +} + +static __attribute__ ((noinline)) +long long v_smalbt (long long t, int16x2_t a, int16x2_t b) +{ + return __nds32__v_smalbt (t, a, b); +} + + +int +main () +{ +#ifdef __NDS32_EL__ + long long a_p = 0x12345679075ca9d3ll; + long long va_p = 0x12345679075ca9d3ll; +#else + long long a_p = 0x12345679075ca9d3ll; + long long va_p = 0x12345678ffffffffll; +#endif + + long long a = smalbt (0x12345678ffffffffll, 0x00006789, 0x12340000); + long long va = v_smalbt (0x12345678ffffffffll, (int16x2_t) {0x6789, 0}, + (int16x2_t) {0, 0x1234}); + if (a != a_p) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalda.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalda.c new file mode 100644 index 0000000..33b4b3f --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalda.c @@ -0,0 +1,38 @@ +/* This is a test program for smalda instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smalda (long long t, unsigned int a, unsigned int b) +{ + return __nds32__smalda (t, a, b); +} + +static __attribute__ ((noinline)) +long long v_smalda (long long t, int16x2_t a, int16x2_t b) +{ + return __nds32__v_smalda (t, a, b); +} + + +int +main () +{ + long long a = smalda (0x12345678ffffffffll, 0x67890000, 0x12340000); + long long va = v_smalda (0x12345678ffffffffll, (int16x2_t) {0, 0x6789}, + (int16x2_t) {0, 0x1234}); + + if (a != 0x12345679075CA9D3ll) + abort (); + else if (va != 0x12345679075CA9D3ll) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smaldrs.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smaldrs.c new file mode 100644 index 0000000..48255b1 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smaldrs.c @@ -0,0 +1,46 @@ +/* This is a test program for smaldrs instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smaldrs (long long t, unsigned int a, unsigned int b) +{ + return __nds32__smaldrs (t, a, b); +} + +static __attribute__ ((noinline)) +long long v_smaldrs (long long t, int16x2_t a, int16x2_t b) +{ + return __nds32__v_smaldrs (t, a, b); +} + + +int +main () +{ +#ifdef __NDS32_EL__ + long long a_p = 0x12345678ffffaaaall; + long long va_p = 0x12345678ffffaaaall; +#else + long long a_p = 0x12345678ffffaaaall; + long long va_p = 0x1234567900005554ll; +#endif + + long long a = smaldrs (0x12345678ffffffffll, 0x67890001, 0x00011234); + long long va = v_smaldrs (0x12345678ffffffffll, (int16x2_t) {0x0001, 0x6789}, + (int16x2_t) {0x1234, 0x0001}); + + if (a != a_p) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalds.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalds.c new file mode 100644 index 0000000..5a89ea6 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalds.c @@ -0,0 +1,46 @@ +/* This is a test program for smalds instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smalds (long long t, unsigned int a, unsigned int b) +{ + return __nds32__smalds (t, a, b); +} + +static __attribute__ ((noinline)) +long long v_smalds (long long t, int16x2_t a, int16x2_t b) +{ + return __nds32__v_smalds (t, a, b); +} + + +int +main () +{ +#ifdef __NDS32_EL__ + long long a_p = 0x12345678ffffaaaall; + long long va_p = 0x12345678ffffaaaall; +#else + long long a_p = 0x12345678ffffaaaall; + long long va_p = 0x1234567900005554ll; +#endif + + long long a = smalds (0x12345678ffffffffll, 0x12340001, 0x00016789); + long long va = v_smalds (0x12345678ffffffffll, (int16x2_t) {0x0001, 0x1234}, + (int16x2_t) {0x6789, 0x0001}); + + if (a != a_p) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smaltt.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smaltt.c new file mode 100644 index 0000000..709607a --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smaltt.c @@ -0,0 +1,46 @@ +/* This is a test program for smaltt instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smaltt (long long t, unsigned int a, unsigned int b) +{ + return __nds32__smaltt (t, a, b); +} + +static __attribute__ ((noinline)) +long long v_smaltt (long long t, int16x2_t a, int16x2_t b) +{ + return __nds32__v_smaltt (t, a, b); +} + + +int +main () +{ +#ifdef __NDS32_EL__ + long long a_p = 0x12345679075ca9d3ll; + long long va_p = 0x12345679075ca9d3ll; +#else + long long a_p = 0x12345679075ca9d3ll; + long long va_p = 0x12345678ffffffffll; +#endif + + long long a = smaltt (0x12345678ffffffffll, 0x67890000, 0x12340000); + long long va = v_smaltt (0x12345678ffffffffll, (int16x2_t) {0, 0x6789}, + (int16x2_t) {0, 0x1234}); + + if (a != a_p) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalxda.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalxda.c new file mode 100644 index 0000000..0f90250 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalxda.c @@ -0,0 +1,38 @@ +/* This is a test program for smalxda instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smalxda (long long t, unsigned int a, unsigned int b) +{ + return __nds32__smalxda (t, a, b); +} + +static __attribute__ ((noinline)) +long long v_smalxda (long long t, int16x2_t a, int16x2_t b) +{ + return __nds32__v_smalxda (t, a, b); +} + + +int +main () +{ + long long a = smalxda (0x12345678ffffffffll, 0x67890000, 0x00001234); + long long va = v_smalxda (0x12345678ffffffffll, (int16x2_t) {0, 0x6789}, + (int16x2_t) {0x1234, 0}); + + if (a != 0x12345679075CA9D3) + abort (); + else if (va != 0x12345679075CA9D3) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalxds.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalxds.c new file mode 100644 index 0000000..ee2e098 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smalxds.c @@ -0,0 +1,46 @@ +/* This is a test program for smalxds instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smalxds (long long t, unsigned int a, unsigned int b) +{ + return __nds32__smalxds (t, a, b); +} + +static __attribute__ ((noinline)) +long long v_smalxds (long long t, int16x2_t a, int16x2_t b) +{ + return __nds32__v_smalxds (t, a, b); +} + + +int +main () +{ +#ifdef __NDS32_EL__ + long long a_p = 0x12345678ffffaaaall; + long long va_p = 0x12345678ffffaaaall; +#else + long long a_p = 0x12345678ffffaaaall; + long long va_p = 0x1234567900005554ll; +#endif + + long long a = smalxds (0x12345678ffffffffll, 0x12340001, 0x67890001); + long long va = v_smalxds (0x12345678ffffffffll, (int16x2_t) {0x0001, 0x1234}, + (int16x2_t) {0x0001, 0x6789}); + + if (a != a_p) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smar64.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smar64.c new file mode 100644 index 0000000..59c6f1f --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smar64.c @@ -0,0 +1,27 @@ +/* This is a test program for smar64 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smar64 (long long t, int a, int b) +{ + return __nds32__smar64 (t, a, b); +} + +int +main () +{ + long long a = smar64 (0xf000000000000000ll, 0x12345678, 0x23); + + if (a != 0xf00000027d27d268ll) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smax16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smax16.c new file mode 100644 index 0000000..72bf957 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smax16.c @@ -0,0 +1,37 @@ +/* This is a test program for smax16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int smax16 (unsigned int ra, unsigned int rb) +{ + return __nds32__smax16 (ra, rb); +} + +static __attribute__ ((noinline)) +int16x2_t v_smax16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_smax16 (ra, rb); +} + +int +main () +{ + unsigned int a = smax16 (0xfffe0001, 0xffff0000); + int16x2_t va = v_smax16 ((int16x2_t) {0x7fff, 0}, + (int16x2_t) {0x7ffe, 1}); + if (a != 0xffff0001) + abort (); + else if (va[0] != 0x7fff + || va[1] != 1) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smax8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smax8.c new file mode 100644 index 0000000..128bf19 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smax8.c @@ -0,0 +1,41 @@ +/* This is a test program for smax8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int smax8 (unsigned int ra, unsigned int rb) +{ + return __nds32__smax8 (ra, rb); +} + +static __attribute__ ((noinline)) +int8x4_t v_smax8 (int8x4_t ra, int8x4_t rb) +{ + return __nds32__v_smax8 (ra, rb); +} + + +int +main () +{ + unsigned int a = smax8 (0xffff0000, 0xfefe0001); + int8x4_t va = v_smax8 ((int8x4_t) {0x7f, 0x7f, 0x01, 0x01}, + (int8x4_t) {0x7e, 0x7e, 0x00, 0x00}); + + if (a != 0xffff0001) + abort (); + else if (va[0] != 0x7f + || va[1] != 0x7f + || va[2] != 1 + || va[3] != 1) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smbb.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smbb.c new file mode 100644 index 0000000..25759bd --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smbb.c @@ -0,0 +1,44 @@ +/* This is a test program for smbb instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int smbb (unsigned int ra, unsigned int rb) +{ + return __nds32__smbb (ra, rb); +} + +static __attribute__ ((noinline)) +int v_smbb (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_smbb (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int va_p = 1; +#else + int va_p = 2; +#endif + + int a = smbb (0x80000002, 0x80000001); + + int va = v_smbb ((int16x2_t) {0xffff, 0x0002}, + (int16x2_t) {0xffff, 0x0001}); + + if (a != 2) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smbt.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smbt.c new file mode 100644 index 0000000..7ed2c22 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smbt.c @@ -0,0 +1,44 @@ +/* This is a test program for smbt instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int smbt (unsigned int ra, unsigned int rb) +{ + return __nds32__smbt (ra, rb); +} + +static __attribute__ ((noinline)) +int v_smbt (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_smbt (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int va_p = 0xffffffff; +#else + int va_p = 0xfffffffe; +#endif + + int a = smbt (0x80000002, 0x80000001); + + int va = v_smbt ((int16x2_t) {0xffff, 0x0002}, + (int16x2_t) {0xffff, 0x0001}); + + if (a != 0xffff0000) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smdrs.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smdrs.c new file mode 100644 index 0000000..4224b04 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smdrs.c @@ -0,0 +1,43 @@ +/* This is a test program for smdrs instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int smdrs (unsigned int ra, unsigned int rb) +{ + return __nds32__smdrs (ra, rb); +} + +static __attribute__ ((noinline)) +int v_smdrs (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_smdrs (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int va_p = 0xffffffff; +#else + int va_p = 1; +#endif + + int a = smdrs (0x80000002, 0x80000001); + int va = v_smdrs ((int16x2_t) {0xffff, 0x0002}, + (int16x2_t) {0xffff, 0x0001}); + + if (a != 0xc0000002) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smds.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smds.c new file mode 100644 index 0000000..9875efb --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smds.c @@ -0,0 +1,43 @@ +/* This is a test program for smds instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int smds (unsigned int ra, unsigned int rb) +{ + return __nds32__smds (ra, rb); +} + +static __attribute__ ((noinline)) +int v_smds (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_smds (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int va_p = 1; +#else + int va_p = 0xffffffff; +#endif + + int a = smds (0x80000002, 0x80000001); + int va = v_smds ((int16x2_t) {0xffff, 0x0002}, + (int16x2_t) {0xffff, 0x0001}); + + if (a != 0x3ffffffe) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smin16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smin16.c new file mode 100644 index 0000000..60deb4b --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smin16.c @@ -0,0 +1,37 @@ +/* This is a test program for smin16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int smin16 (unsigned int ra, unsigned int rb) +{ + return __nds32__smin16 (ra, rb); +} + +static __attribute__ ((noinline)) +int16x2_t v_smin16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_smin16 (ra, rb); +} + +int +main () +{ + unsigned int a = smin16 (0xfffe0001, 0xffff0000); + int16x2_t v_sa = v_smin16 ((int16x2_t) {0x7fff, 0}, + (int16x2_t) {0x7ffe, 1}); + if (a != 0xfffe0000) + abort (); + else if (v_sa[0] != 0x7ffe + || v_sa[1] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmul.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmul.c new file mode 100644 index 0000000..5735efa --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmul.c @@ -0,0 +1,27 @@ +/* This is a test program for smmul instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int smmul (int ra, int rb) +{ + return __nds32__smmul (ra, rb); +} + +int +main () +{ + int a = smmul (0x80000000, 0x80000000); + + if (a != 0x40000000) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmulu.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmulu.c new file mode 100644 index 0000000..fbe0b15 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmulu.c @@ -0,0 +1,27 @@ +/* This is a test program for smmul.u instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int smmul_u (int ra, int rb) +{ + return __nds32__smmul_u (ra, rb); +} + +int +main () +{ + int a = smmul_u (0x80000002, 0x80000001); + + if (a != 0x3fffffff) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmwb.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmwb.c new file mode 100644 index 0000000..9160b9a --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmwb.c @@ -0,0 +1,43 @@ +/* This is a test program for smmwb instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int smmwb (int ra, unsigned int rb) +{ + return __nds32__smmwb (ra, rb); +} + +static __attribute__ ((noinline)) +int v_smmwb (int ra, int16x2_t rb) +{ + return __nds32__v_smmwb (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int va_p = 0; +#else + int va_p = 0xffffffff; +#endif + + int a = smmwb (0x80000002, 0x80000001); + + int va = v_smmwb (0xffff0002, (int16x2_t) {0xffff, 0x0001}); + + if (a != 0xffff8000) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmwbu.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmwbu.c new file mode 100644 index 0000000..46ebed2 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmwbu.c @@ -0,0 +1,43 @@ +/* This is a test program for smmwb.u instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int smmwb_u (int ra, unsigned int rb) +{ + return __nds32__smmwb_u (ra, rb); +} + +static __attribute__ ((noinline)) +int v_smmwb_u (int ra, int16x2_t rb) +{ + return __nds32__v_smmwb_u (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int va_p = 1; +#else + int va_p = 0xffffffff; +#endif + + int a = smmwb_u (0x80000002, 0x80000001); + + int va = v_smmwb_u (0xffff0002, (int16x2_t) {0xffff, 0x0001}); + + if (a != 0xffff8000) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmwt.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmwt.c new file mode 100644 index 0000000..45d4792 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmwt.c @@ -0,0 +1,43 @@ +/* This is a test program for smmwt instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int smmwt (int ra, unsigned int rb) +{ + return __nds32__smmwt (ra, rb); +} + +static __attribute__ ((noinline)) +int v_smmwt (int ra, int16x2_t rb) +{ + return __nds32__v_smmwt (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int va_p = 0xffffffff; +#else + int va_p = 0; +#endif + + int a = smmwt (0x80000002, 0x80000001); + + int va = v_smmwt (0xffff0002, (int16x2_t) {0xffff, 0x0001}); + + if (a != 0x3fffffff) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmwtu.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmwtu.c new file mode 100644 index 0000000..3b4b487 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smmwtu.c @@ -0,0 +1,43 @@ +/* This is a test program for smmwt.u instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int smmwt_u (int ra, unsigned int rb) +{ + return __nds32__smmwt_u (ra, rb); +} + +static __attribute__ ((noinline)) +int v_smmwt_u (int ra, int16x2_t rb) +{ + return __nds32__v_smmwt_u (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int va_p = 0xffffffff; +#else + int va_p = 1; +#endif + + int a = smmwt_u (0x80000002, 0x80000001); + + int va = v_smmwt_u (0xffff0002, (int16x2_t) {0xffff, 0x0001}); + + if (a != 0x3fffffff) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smslda.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smslda.c new file mode 100644 index 0000000..be2ac27 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smslda.c @@ -0,0 +1,37 @@ +/* This is a test program for smslda instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smslda (long long rt, unsigned int ra, unsigned int rb) +{ + return __nds32__smslda (rt, ra, rb); +} + +static __attribute__ ((noinline)) +long long v_smslda (long long rt, int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_smslda (rt, ra, rb); +} + +int +main () +{ + long long a = smslda (0xff0000000000ll, 0xffffffff, 0x2); + long long va = v_smslda (0x100000000ll, + (int16x2_t) {0xf000, 0}, (int16x2_t) {0, 3}); + + if (a != 0xff0000000002ll) + abort (); + else if (va != 0x100000000ll) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smslxda.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smslxda.c new file mode 100644 index 0000000..f276a2e --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smslxda.c @@ -0,0 +1,37 @@ +/* This is a test program for smslxda instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smslxda (long long rt, unsigned int ra, unsigned int rb) +{ + return __nds32__smslxda (rt, ra, rb); +} + +static __attribute__ ((noinline)) +long long v_smslxda (long long rt, int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_smslxda (rt, ra, rb); +} + +int +main () +{ + long long a = smslxda (0xff0000000000ll, 0xffffffff, 0x2); + long long va = v_smslxda (0x100000000ll, + (int16x2_t) {0xf000, 0}, (int16x2_t) {0, 3}); + + if (a != 0xff0000000002ll) + abort (); + else if (va != 0x100003000ll) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smsr64.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smsr64.c new file mode 100644 index 0000000..64a84e9 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smsr64.c @@ -0,0 +1,27 @@ +/* This is a test program for smsr64 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long smsr64 (long long t, int a, int b) +{ + return __nds32__smsr64 (t, a, b); +} + +int +main () +{ + long long a = smsr64 (0x5000000300000000ll, 0x12345678, 0x23); + + if (a != 0x5000000082D82D98ll) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smtt.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smtt.c new file mode 100644 index 0000000..bfb30f2 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smtt.c @@ -0,0 +1,44 @@ +/* This is a test program for smtt instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int smtt (unsigned int ra, unsigned int rb) +{ + return __nds32__smtt (ra, rb); +} + +static __attribute__ ((noinline)) +int v_smtt (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_smtt (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int va_p = 2; +#else + int va_p = 1; +#endif + + int a = smtt (0x80000002, 0x80000001); + + int va = v_smtt ((int16x2_t) {0xffff, 0x0002}, + (int16x2_t) {0xffff, 0x0001}); + + if (a != 0x40000000) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smul16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smul16.c new file mode 100644 index 0000000..bb3fad4 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smul16.c @@ -0,0 +1,38 @@ +/* This is a test program for smul16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned long long smul16 (unsigned int ra, unsigned int rb) +{ + return __nds32__smul16 (ra, rb); +} + +static __attribute__ ((noinline)) +int32x2_t v_smul16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_smul16 (ra, rb); +} + +int +main () +{ + unsigned long long a = smul16 (0xffff0000, 0x0001ffff); + int32x2_t va = v_smul16 ((int16x2_t) {0xffff, 0}, + (int16x2_t) {0x0001, 0xffff}); + + if (a != 0xffffffff00000000) + abort (); + else if (va[0] != 0xffffffff + || va[1] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smulx16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smulx16.c new file mode 100644 index 0000000..0e65a2a --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smulx16.c @@ -0,0 +1,37 @@ +/* This is a test program for smulx16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned long long smulx16 (unsigned int ra, unsigned int rb) +{ + return __nds32__smulx16 (ra, rb); +} + +static __attribute__ ((noinline)) +int32x2_t v_smulx16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_smulx16 (ra, rb); +} + +int +main () +{ + unsigned long long a = smulx16 (0xffff0000, 0xffff0001); + int32x2_t va = v_smulx16 ((int16x2_t) {0xffff, 0xffff}, + (int16x2_t) {1, 0}); + if (a != 0xffffffff00000000) + abort (); + else if (va[0] != 0 + || va[1] != 0xffffffff) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-smxds.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smxds.c new file mode 100644 index 0000000..e429aa3 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-smxds.c @@ -0,0 +1,45 @@ +/* This is a test program for smxds instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int smxds (unsigned int ra, unsigned int rb) +{ + return __nds32__smxds (ra, rb); +} + +static __attribute__ ((noinline)) +int v_smxds (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_smxds (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int a_p = 0x8000; + int va_p = 0xffffffff; +#else + int a_p = 0x8000; + int va_p = 1; +#endif + + int a = smxds (0x80000002, 0x80000001); + int va = v_smxds ((int16x2_t) {0xffff, 0x0002}, + (int16x2_t) {0xffff, 0x0001}); + + if (a != a_p) + abort (); + else if (va != va_p) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-sra16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sra16.c new file mode 100644 index 0000000..7d85032 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sra16.c @@ -0,0 +1,37 @@ +/* This is a test program for sra16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int sra16 (unsigned int ra, unsigned int rb) +{ + return __nds32__sra16 (ra, rb); +} + +static __attribute__ ((noinline)) +int16x2_t v_sra16 (int16x2_t ra, unsigned int rb) +{ + return __nds32__v_sra16 (ra, rb); +} + +int +main () +{ + unsigned int a = sra16 (0x0ffff000, 4); + int16x2_t va = v_sra16 ((int16x2_t) {0x7fff, 0x8000}, 4); + + if (a != 0x00ffff00) + abort (); + else if (va[0] != 0x7ff + || va[1] != (short) 0xf800) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-sra16u.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sra16u.c new file mode 100644 index 0000000..5bc127c --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sra16u.c @@ -0,0 +1,37 @@ +/* This is a test program for sra16.u instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int sra16u (unsigned int ra, unsigned int rb) +{ + return __nds32__sra16_u (ra, rb); +} + +static __attribute__ ((noinline)) +int16x2_t v_sra16u (int16x2_t ra, unsigned int rb) +{ + return __nds32__v_sra16_u (ra, rb); +} + +int +main () +{ + unsigned int a = sra16u (0x0ffff000, 4); + int16x2_t va = v_sra16u ((int16x2_t) {0x7fff, 0x8000}, 4); + + if (a != 0x100ff00) + abort (); + else if (va[0] != 0x800 + || va[1] != (short) 0xf800) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-srai16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srai16.c new file mode 100644 index 0000000..f3c6e16 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srai16.c @@ -0,0 +1,39 @@ +/* This is a test program for srai16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int srai16 (unsigned int ra) +{ + return __nds32__sra16 (ra, 4); +} + +static __attribute__ ((noinline)) +int16x2_t v_srai16 (int16x2_t ra) +{ + return __nds32__v_sra16 (ra, 4); +} + +int +main () +{ + unsigned int a = srai16 (0x0ffff000); + + int16x2_t aa; + int16x2_t va = v_srai16 ((int16x2_t) {0x7fff, 0x8000}); + + if (a != 0x00ffff00) + abort (); + else if (va[0] != 0x7ff + || va[1] != (short) 0xf800) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-srai16u.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srai16u.c new file mode 100644 index 0000000..380bd2e --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srai16u.c @@ -0,0 +1,37 @@ +/* This is a test program for srai16.u instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int srai16u (unsigned int ra) +{ + return __nds32__sra16_u (ra, 4); +} + +static __attribute__ ((noinline)) +int16x2_t v_srai16u (int16x2_t ra) +{ + return __nds32__v_sra16_u (ra, 4); +} + +int +main () +{ + unsigned int a = srai16u (0x0ffff000); + int16x2_t va = v_srai16u ((int16x2_t) {0x7fff, 0x8000}); + + if (a != 0x100ff00) + abort (); + else if (va[0] != 0x800 + || va[1] != (short) 0xf800) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-sraiu.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sraiu.c new file mode 100644 index 0000000..4090762 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sraiu.c @@ -0,0 +1,27 @@ +/* This is a test program for srai.u instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int sraiu (int ra) +{ + return __nds32__sra_u (ra, 8); +} + +int +main () +{ + int a = sraiu (0xf00ff); + + if (a != 0xf01) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-srau.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srau.c new file mode 100644 index 0000000..e3a3137 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srau.c @@ -0,0 +1,27 @@ +/* This is a test program for sra.u instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +int srau (int ra, unsigned int rb) +{ + return __nds32__sra_u (ra, rb); +} + +int +main () +{ + int a = srau (0xf00ff, 8); + + if (a != 0xf01) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-srl16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srl16.c new file mode 100644 index 0000000..8aa9c59 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srl16.c @@ -0,0 +1,37 @@ +/* This is a test program for srl16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int srl16 (unsigned int ra, unsigned int rb) +{ + return __nds32__srl16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_srl16 (uint16x2_t ra, unsigned int rb) +{ + return __nds32__v_srl16 (ra, rb); +} + +int +main () +{ + unsigned int a = srl16 (0x0f00f000, 4); + uint16x2_t va = v_srl16 ((uint16x2_t) {0x7fff, 0x8000}, 4); + + if (a != 0xf00f00) + abort (); + else if (va[0] != 0x7ff + || va[1] != 0x0800) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-srl16u.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srl16u.c new file mode 100644 index 0000000..3f4ac5b --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srl16u.c @@ -0,0 +1,37 @@ +/* This is a test program for srl16.u instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int srl16_u (unsigned int ra, unsigned int rb) +{ + return __nds32__srl16_u (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_srl16_u (uint16x2_t ra, unsigned int rb) +{ + return __nds32__v_srl16_u (ra, rb); +} + +int +main () +{ + unsigned int a = srl16_u (0x0f00f000, 4); + uint16x2_t va = v_srl16_u ((uint16x2_t) {0x7fff, 0x8000}, 4); + + if (a != 0xf00f00) + abort (); + else if (va[0] != 0x800 + || va[1] != 0x800) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-srli16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srli16.c new file mode 100644 index 0000000..200bf8c --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srli16.c @@ -0,0 +1,37 @@ +/* This is a test program for srli16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int srli16 (unsigned int ra) +{ + return __nds32__srl16 (ra, 4); +} + +static __attribute__ ((noinline)) +uint16x2_t v_srli16 (uint16x2_t ra) +{ + return __nds32__v_srl16 (ra, 4); +} + +int +main () +{ + unsigned int a = srli16 (0x0f00f000); + uint16x2_t va = v_srli16 ((uint16x2_t) {0x7fff, 0x8000}); + + if (a != 0xf00f00) + abort (); + else if (va[0] != 0x7ff + || va[1] != 0x0800) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-srli16u.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srli16u.c new file mode 100644 index 0000000..808319b --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-srli16u.c @@ -0,0 +1,37 @@ +/* This is a test program for sril16.u instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int srli16_u (unsigned int ra) +{ + return __nds32__srl16_u (ra, 4); +} + +static __attribute__ ((noinline)) +uint16x2_t v_srli16_u (uint16x2_t ra) +{ + return __nds32__v_srl16_u (ra, 4); +} + +int +main () +{ + unsigned int a = srli16_u (0x0f00f000); + uint16x2_t va = v_srli16_u ((uint16x2_t) {0x7fff, 0x8000}); + + if (a != 0xf00f00) + abort (); + else if (va[0] != 0x800 + || va[1] != 0x800) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-sub16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sub16.c new file mode 100644 index 0000000..eff5f92 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sub16.c @@ -0,0 +1,49 @@ +/* This is a test program for sub16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int sub16 (unsigned int ra, unsigned int rb) +{ + return __nds32__sub16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_usub16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_usub16 (ra, rb); +} + +static __attribute__ ((noinline)) +int16x2_t v_ssub16 (int16x2_t ra, int16x2_t rb) +{ + return __nds32__v_ssub16 (ra, rb); +} + +int +main () +{ + unsigned int a = sub16 (0x00010000, 0x00010001); + uint16x2_t v_ua = v_usub16 ((uint16x2_t) {0x1000, 0x0001}, + (uint16x2_t) {0xf000, 0x0000}); + int16x2_t v_sa = v_ssub16 ((int16x2_t) {0x7777, 0x2111}, + (int16x2_t) {0x1000, 0x2000}); + + if (a != 0x0000ffff) + abort (); + else if (v_ua[0] != 0x2000 + || v_ua[1] != 0x0001) + abort (); + else if (v_sa[0] != 0x6777 + || v_sa[1] != 0x0111) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-sub64.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sub64.c new file mode 100644 index 0000000..efdd879 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sub64.c @@ -0,0 +1,36 @@ +/* This is a test program for sub64 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +long long ssub64 (long long ra, long long rb) +{ + return __nds32__ssub64 (ra, rb); +} + +static __attribute__ ((noinline)) +unsigned long long usub64 (unsigned long long ra, unsigned long long rb) +{ + return __nds32__usub64 (ra, rb); +} + +int +main () +{ + long long sa = ssub64 (0x100000000ll, 0xffffffffll); + unsigned long long ua = usub64 (0xf00000000ull, 0x1111ull); + + if (sa != 1ll) + abort (); + else if (ua != 0xeffffeeefull) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-sub8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sub8.c new file mode 100644 index 0000000..b21f8a5 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sub8.c @@ -0,0 +1,53 @@ +/* This is a test program for sub8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int sub8 (unsigned int ra, unsigned int rb) +{ + return __nds32__sub8 (ra, rb); +} + +static __attribute__ ((noinline)) +uint8x4_t v_usub8 (uint8x4_t ra, uint8x4_t rb) +{ + return __nds32__v_usub8 (ra, rb); +} + +static __attribute__ ((noinline)) +int8x4_t v_ssub8 (int8x4_t ra, int8x4_t rb) +{ + return __nds32__v_ssub8 (ra, rb); +} + +int +main () +{ + unsigned int a = sub8 (0x55667788, 0x11223344); + uint8x4_t v_ua = v_usub8 ((uint8x4_t) {0xff, 0xee, 0xee, 0xcc}, + (uint8x4_t) {0x1, 0xee, 0xdd, 0xdd}); + int8x4_t v_sa = v_ssub8 ((int8x4_t) {0x81, 0x0, 0xdd, 0xaa}, + (int8x4_t) {0x80, 0x1, 0xcc, 0xaa}); + + if (a != 0x44444444) + abort (); + else if (v_ua[0] != 0xfe + || v_ua[1] != 0 + || v_ua[2] != 0x11 + || v_ua[3] != 0xef) + abort (); + else if (v_sa[0] != 1 + || v_sa[1] != (char) 0xff + || v_sa[2] != 0x11 + || v_sa[3] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-sunpkd810.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sunpkd810.c new file mode 100644 index 0000000..29fff3a --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sunpkd810.c @@ -0,0 +1,43 @@ +/* This is a test program for sunpkd810 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int sunpkd810 (unsigned int a) +{ + return __nds32__sunpkd810 (a); +} + +static __attribute__ ((noinline)) +int16x2_t v_sunpkd810 (int8x4_t a) +{ + return __nds32__v_sunpkd810 (a); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int16x2_t va_p = {0xfff8, 0x56}; +#else + int16x2_t va_p = {0, 0}; +#endif + + unsigned int a = sunpkd810 (0x000056f8); + int16x2_t va = v_sunpkd810 ((int8x4_t) {0xf8, 0x56, 0, 0}); + + if (a != 0x0056fff8) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-sunpkd820.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sunpkd820.c new file mode 100644 index 0000000..43f969a --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sunpkd820.c @@ -0,0 +1,43 @@ +/* This is a test program for sunpkd820 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int sunpkd820 (unsigned int a) +{ + return __nds32__sunpkd820 (a); +} + +static __attribute__ ((noinline)) +int16x2_t v_sunpkd820 (int8x4_t a) +{ + return __nds32__v_sunpkd820 (a); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int16x2_t va_p = {0xfff8, 0x34}; +#else + int16x2_t va_p = {0, 0}; +#endif + + unsigned int a = sunpkd820 (0x003400f8); + int16x2_t va = v_sunpkd820 ((int8x4_t) {0xf8, 0, 0x34, 0}); + + if (a != 0x0034fff8) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-sunpkd830.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sunpkd830.c new file mode 100644 index 0000000..76540b5 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sunpkd830.c @@ -0,0 +1,37 @@ +/* This is a test program for sunpkd830 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int sunpkd830 (unsigned int a) +{ + return __nds32__sunpkd830 (a); +} + +static __attribute__ ((noinline)) +int16x2_t v_sunpkd830 (int8x4_t a) +{ + return __nds32__v_sunpkd830 (a); +} + +int +main () +{ + unsigned int a = sunpkd830 (0x120000f8); + int16x2_t va = v_sunpkd830 ((int8x4_t) {0xf8, 0x00, 0, 0x12}); + + if (a != 0x0012fff8) + abort (); + else if (va[0] != (short) 0xfff8 + || va[1] != 0x0012) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-sunpkd831.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sunpkd831.c new file mode 100644 index 0000000..05149e6 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-sunpkd831.c @@ -0,0 +1,43 @@ +/* This is a test program for sunpkd831 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int sunpkd831 (unsigned int a) +{ + return __nds32__sunpkd831 (a); +} + +static __attribute__ ((noinline)) +int16x2_t v_sunpkd831 (int8x4_t a) +{ + return __nds32__v_sunpkd831 (a); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int16x2_t va_p = {0xfff8, 0x12}; +#else + int16x2_t va_p = {0, 0}; +#endif + + unsigned int a = sunpkd831 (0x1200f800); + int16x2_t va = v_sunpkd831 ((int8x4_t) {0, 0xf8, 0, 0x12}); + + if (a != 0x0012fff8) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-ucmple16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ucmple16.c new file mode 100644 index 0000000..17b5344 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ucmple16.c @@ -0,0 +1,37 @@ +/* This is a test program for ucmple16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int ucmple16 (unsigned int ra, unsigned int rb) +{ + return __nds32__ucmple16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_ucmple16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_ucmple16 (ra, rb); +} + +int +main () +{ + unsigned int a = ucmple16 (0xfffe0001, 0xffff0000); + uint16x2_t va = v_ucmple16 ((uint16x2_t) {0x7fff, 0x7ffe}, + (uint16x2_t) {0x7ffe, 0x7fff}); + if (a != 0xffff0000) + abort (); + else if (va[0] != 0 + || va[1] != 0xffff) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-ucmple8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ucmple8.c new file mode 100644 index 0000000..561b500 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ucmple8.c @@ -0,0 +1,40 @@ +/* This is a test program for ucmple8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int ucmple8 (unsigned int ra, unsigned int rb) +{ + return __nds32__ucmple8 (ra, rb); +} + +static __attribute__ ((noinline)) +uint8x4_t v_ucmple8 (uint8x4_t ra, uint8x4_t rb) +{ + return __nds32__v_ucmple8 (ra, rb); +} + +int +main () +{ + unsigned int a = ucmple8 (0xfefe0101, 0xffff0000); + uint8x4_t va = v_ucmple8 ((uint8x4_t) {0x7e, 0x7e, 0x01, 0x01}, + (uint8x4_t) {0x7f, 0x7f, 0x00, 0x00}); + + if (a != 0xffff0000) + abort (); + else if (va[0] != 0xff + || va[1] != 0xff + || va[2] != 0 + || va[3] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-ucmplt16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ucmplt16.c new file mode 100644 index 0000000..820ce1e --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ucmplt16.c @@ -0,0 +1,37 @@ +/* This is a test program for ucmplt16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int ucmplt16 (unsigned int ra, unsigned int rb) +{ + return __nds32__ucmplt16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_ucmplt16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_ucmplt16 (ra, rb); +} + +int +main () +{ + unsigned int a = ucmplt16 (0xfffe0001, 0xffff0000); + uint16x2_t va = v_ucmplt16 ((uint16x2_t) {0x7fff, 0x7ffe}, + (uint16x2_t) {0x7ffe, 0x7fff}); + if (a != 0xffff0000) + abort (); + else if (va[0] != 0 + || va[1] != 0xffff) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-ucmplt8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ucmplt8.c new file mode 100644 index 0000000..8001586 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ucmplt8.c @@ -0,0 +1,40 @@ +/* This is a test program for ucmplt8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int ucmplt8 (unsigned int ra, unsigned int rb) +{ + return __nds32__ucmplt8 (ra, rb); +} + +static __attribute__ ((noinline)) +uint8x4_t v_ucmplt8 (uint8x4_t ra, uint8x4_t rb) +{ + return __nds32__v_ucmplt8 (ra, rb); +} + +int +main () +{ + unsigned int a = ucmplt8 (0xfefe0101, 0xffff0000); + uint8x4_t va = v_ucmplt8 ((uint8x4_t) {0x7e, 0x7e, 0x01, 0x01}, + (uint8x4_t) {0x7f, 0x7f, 0x00, 0x00}); + + if (a != 0xffff0000) + abort (); + else if (va[0] != 0xff + || va[1] != 0xff + || va[2] != 0 + || va[3] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-umar64.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umar64.c new file mode 100644 index 0000000..ac32ae1 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umar64.c @@ -0,0 +1,27 @@ +/* This is a test program for umar64 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned long long umar64 (unsigned long long t,unsigned int a,unsigned int b) +{ + return __nds32__umar64 (t, a, b); +} + +int +main () +{ + unsigned long long a = umar64 (0xf000000000000000ull, 0x12345678, 0x23); + + if (a != 0xf00000027d27d268ull) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-umax16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umax16.c new file mode 100644 index 0000000..99a43d2 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umax16.c @@ -0,0 +1,37 @@ +/* This is a test program for umax16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int umax16 (unsigned int ra, unsigned int rb) +{ + return __nds32__umax16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_umax16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_umax16 (ra, rb); +} + +int +main () +{ + unsigned int a = umax16 (0xfffe0001, 0xffff0000); + uint16x2_t va = v_umax16 ((uint16x2_t) {0xffff, 0}, + (uint16x2_t) {0xfffe, 1}); + if (a != 0xffff0001) + abort (); + else if (va[0] != 0xffff + || va[1] != 1) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-umax8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umax8.c new file mode 100644 index 0000000..23904b2 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umax8.c @@ -0,0 +1,41 @@ +/* This is a test program for umax8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int umax8 (unsigned int ra, unsigned int rb) +{ + return __nds32__umax8 (ra, rb); +} + +static __attribute__ ((noinline)) +uint8x4_t v_umax8 (uint8x4_t ra, uint8x4_t rb) +{ + return __nds32__v_umax8 (ra, rb); +} + + +int +main () +{ + unsigned int a = umax8 (0xffff0000, 0xfffe0001); + uint8x4_t va = v_umax8 ((uint8x4_t) {0xff, 0xff, 0x01, 0x01}, + (uint8x4_t) {0xfe, 0xfe, 0x00, 0x00}); + + if (a != 0xffff0001) + abort (); + else if (va[0] != 0xff + || va[1] != 0xff + || va[2] != 1 + || va[3] != 1) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-umin16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umin16.c new file mode 100644 index 0000000..eec7058 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umin16.c @@ -0,0 +1,37 @@ +/* This is a test program for umin16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int umin16 (unsigned int ra, unsigned int rb) +{ + return __nds32__umin16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_umin16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_umin16 (ra, rb); +} + +int +main () +{ + unsigned int a = umin16 (0xfffe0001, 0xffff0000); + uint16x2_t va = v_umin16 ((uint16x2_t) {0x7fff, 0}, + (uint16x2_t) {0x7ffe, 1}); + if (a != 0xfffe0000) + abort (); + else if (va[0] != 0x7ffe + || va[1] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-umsr64.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umsr64.c new file mode 100644 index 0000000..3fb20bf --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umsr64.c @@ -0,0 +1,27 @@ +/* This is a test program for umsr64 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned long long umsr64 (unsigned long long t, unsigned int a, unsigned int b) +{ + return __nds32__umsr64 (t, a, b); +} + +int +main () +{ + unsigned long long a = umsr64 (0x5000000300000000ull, 0x12345678, 0x23); + + if (a != 0x5000000082D82D98ull) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-umul16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umul16.c new file mode 100644 index 0000000..ddfb6be --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umul16.c @@ -0,0 +1,37 @@ +/* This is a test program for umul16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned long long umul16 (unsigned int ra, unsigned int rb) +{ + return __nds32__umul16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint32x2_t v_umul16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_umul16 (ra, rb); +} + +int +main () +{ + unsigned long long a = umul16 (0xffff0000, 0x0001ffff); + uint32x2_t va = v_umul16 ((uint16x2_t) {0xffff, 0}, + (uint16x2_t) {0x0001, 0xffff}); + if (a != 0xffff00000000) + abort (); + else if (va[0] != 0xffff + || va[1] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-umulx16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umulx16.c new file mode 100644 index 0000000..c57d304 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-umulx16.c @@ -0,0 +1,37 @@ +/* This is a test program for umulx16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned long long umulx16 (unsigned int ra, unsigned int rb) +{ + return __nds32__umulx16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint32x2_t v_umulx16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_umulx16 (ra, rb); +} + +int +main () +{ + unsigned long long a = umulx16 (0xffff0000, 0xffff0001); + uint32x2_t va = v_umulx16 ((uint16x2_t) {0xffff, 0xffff}, + (uint16x2_t) {1, 0}); + if (a != 0xffff00000000) + abort (); + else if (va[0] != 0 + || va[1] != 0xffff) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-uradd16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-uradd16.c new file mode 100644 index 0000000..82c7be7 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-uradd16.c @@ -0,0 +1,38 @@ +/* This is a test program for uradd16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int uradd16 (unsigned int ra, unsigned int rb) +{ + return __nds32__uradd16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_uradd16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_uradd16 (ra, rb); +} + +int +main () +{ + unsigned int a = uradd16 (0x7fff7fff, 0x7fff7fff); + uint16x2_t va = v_uradd16 ((uint16x2_t) {0x8000, 0x4000}, + (uint16x2_t) {0x8000, 0x8000}); + + if (a != 0x7fff7fff) + abort (); + else if (va[0] != 0x8000 + || va[1] != 0x6000) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-uradd64.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-uradd64.c new file mode 100644 index 0000000..51ee961 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-uradd64.c @@ -0,0 +1,27 @@ +/* This is a test program for uradd64 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned long long uradd64 (unsigned long long ra, unsigned long long rb) +{ + return __nds32__uradd64 (ra, rb); +} + +int +main () +{ + unsigned long long a = uradd64 (0xf000000000000000ull, 0xf000000000000000ull); + + if (a != 0xf000000000000000ull) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-uradd8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-uradd8.c new file mode 100644 index 0000000..d4f91d6 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-uradd8.c @@ -0,0 +1,40 @@ +/* This is a test program for uradd8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int uradd8 (unsigned int ra, unsigned int rb) +{ + return __nds32__uradd8 (ra, rb); +} + +static __attribute__ ((noinline)) +uint8x4_t v_uradd8 (uint8x4_t ra, uint8x4_t rb) +{ + return __nds32__v_uradd8 (ra, rb); +} + +int +main () +{ + unsigned int a = uradd8 (0x11223344, 0x55667788); + uint8x4_t va = v_uradd8 ((uint8x4_t) {0x7f, 0x80, 0x40, 0xaa}, + (uint8x4_t) {0x7f, 0x80, 0x80, 0xaa}); + + if (a != 0x33445566) + abort (); + else if (va[0] != 0x7f + || va[1] != 0x80 + || va[2] != 0x60 + || va[3] != 0xaa) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-uraddw.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-uraddw.c new file mode 100644 index 0000000..9fc76b0 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-uraddw.c @@ -0,0 +1,27 @@ +/* This is a test program for uraddw instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int uraddw (unsigned int ra, unsigned int rb) +{ + return __nds32__uraddw (ra, rb); +} + +unsigned int +main () +{ + unsigned int a = uraddw (0x80000000, 0x80000000); + + if (a != 0x80000000) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-urcras16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-urcras16.c new file mode 100644 index 0000000..1330374 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-urcras16.c @@ -0,0 +1,44 @@ +/* This is a test program for urcras16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int urcras16 (unsigned int ra, unsigned int rb) +{ + return __nds32__urcras16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_urcras16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_urcras16 (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + uint16x2_t va_p = {0xffff, 0x8000}; +#else + uint16x2_t va_p = {0x7fff, 0}; +#endif + + unsigned int a = urcras16 (0x7fff7fff, 0x80007fff); + uint16x2_t va = v_urcras16 ((uint16x2_t) {0x7fff, 0x8000}, + (uint16x2_t) {0x8000, 0x8000}); + + if (a != 0x7fffffff) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-urcrsa16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-urcrsa16.c new file mode 100644 index 0000000..806fa7a --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-urcrsa16.c @@ -0,0 +1,44 @@ +/* This is a test program for urcrsa16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int urcrsa16 (unsigned int ra, unsigned int rb) +{ + return __nds32__urcrsa16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_urcrsa16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_urcrsa16 (ra, rb); +} + +int +main () +{ +#ifdef __NDS32_EL__ + uint16x2_t va_p = {0x8000, 0xffff}; +#else + uint16x2_t va_p = {0, 0x7fff}; +#endif + + unsigned int a = urcrsa16 (0x7fff7fff, 0x7fff8000); + uint16x2_t va = v_urcrsa16 ((uint16x2_t) {0x8000, 0x7fff}, + (uint16x2_t) {0x8000, 0x8000}); + + if (a != 0xffff7fff) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-ursub16.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ursub16.c new file mode 100644 index 0000000..9e87234 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ursub16.c @@ -0,0 +1,38 @@ +/* This is a test program for ursub16 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int ursub16 (unsigned int ra, unsigned int rb) +{ + return __nds32__ursub16 (ra, rb); +} + +static __attribute__ ((noinline)) +uint16x2_t v_ursub16 (uint16x2_t ra, uint16x2_t rb) +{ + return __nds32__v_ursub16 (ra, rb); +} + +int +main () +{ + unsigned int a = ursub16 (0x7fff7fff, 0x80008000); + uint16x2_t va = v_ursub16 ((uint16x2_t) {0x8000, 0x8000}, + (uint16x2_t) {0x7fff, 0x4000}); + + if (a != 0xffffffff) + abort (); + else if (va[0] != 0 + || va[1] != 0x2000) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-ursub64.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ursub64.c new file mode 100644 index 0000000..e1f7b15 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ursub64.c @@ -0,0 +1,27 @@ +/* This is a test program for ursub64 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned long long ursub64 (unsigned long long ra, unsigned long long rb) +{ + return __nds32__ursub64 (ra, rb); +} + +int +main () +{ + unsigned long long a = ursub64 (0xeull, 0xfull); + + if (a != 0xffffffffffffffffull) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-ursub8.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ursub8.c new file mode 100644 index 0000000..f5e3ff6 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ursub8.c @@ -0,0 +1,40 @@ +/* This is a test program for ursub8 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int ursub8 (unsigned int ra, unsigned int rb) +{ + return __nds32__ursub8 (ra, rb); +} + +static __attribute__ ((noinline)) +uint8x4_t v_ursub8 (uint8x4_t ra, uint8x4_t rb) +{ + return __nds32__v_ursub8 (ra, rb); +} + +int +main () +{ + unsigned int a = ursub8 (0x55667788, 0x11223344); + uint8x4_t va = v_ursub8 ((uint8x4_t) {0x7f, 0x80, 0x80, 0xaa}, + (uint8x4_t) {0x80, 0x7f, 0x40, 0xaa}); + + if (a != 0x22222222) + abort (); + else if (va[0] != 0xff + || va[1] != 0 + || va[2] != 0x20 + || va[3] != 0) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-ursubw.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ursubw.c new file mode 100644 index 0000000..b12afb0 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-ursubw.c @@ -0,0 +1,27 @@ +/* This is a test program for ursubw instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int ursubw (unsigned int ra,unsigned int rb) +{ + return __nds32__ursubw (ra, rb); +} + +int +main () +{ + unsigned int a = ursubw (0x80000000, 0x40000000); + + if (a != 0x20000000) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-wext.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-wext.c new file mode 100644 index 0000000..d86fb8f --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-wext.c @@ -0,0 +1,27 @@ +/* This is a test program for wext instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int wext (long long ra, unsigned int rb) +{ + return __nds32__wext (ra, rb); +} + +int +main () +{ + unsigned int a = wext (0x1234ffff0000ll, 16); + + if (a != 0x1234ffff) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-wexti.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-wexti.c new file mode 100644 index 0000000..8f09423 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-wexti.c @@ -0,0 +1,27 @@ +/* This is a test program for wexti instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int wexti (long long ra) +{ + return __nds32__wext (ra, 16); +} + +int +main () +{ + unsigned int a = wexti (0x1234ffff0000ll); + + if (a != 0x1234ffff) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-zunpkd810.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-zunpkd810.c new file mode 100644 index 0000000..7b3aebb --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-zunpkd810.c @@ -0,0 +1,43 @@ +/* This is a test program for zunpkd810 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int zunpkd810 (unsigned int a) +{ + return __nds32__zunpkd810 (a); +} + +static __attribute__ ((noinline)) +uint16x2_t v_zunpkd810 (uint8x4_t a) +{ + return __nds32__v_zunpkd810 (a); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int16x2_t va_p = {0xf8, 0x56}; +#else + int16x2_t va_p = {0, 0}; +#endif + + unsigned int a = zunpkd810 (0x000056f8); + uint16x2_t va = v_zunpkd810 ((uint8x4_t) {0xf8, 0x56, 0, 0}); + + if (a != 0x005600f8) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-zunpkd820.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-zunpkd820.c new file mode 100644 index 0000000..dc37a3d --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-zunpkd820.c @@ -0,0 +1,43 @@ +/* This is a test program for zunpkd820 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int zunpkd820 (unsigned int a) +{ + return __nds32__zunpkd820 (a); +} + +static __attribute__ ((noinline)) +uint16x2_t v_zunpkd820 (uint8x4_t a) +{ + return __nds32__v_zunpkd820 (a); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int16x2_t va_p = {0xf8, 0x34}; +#else + int16x2_t va_p = {0, 0}; +#endif + + unsigned int a = zunpkd820 (0x003400f8); + uint16x2_t va = v_zunpkd820 ((uint8x4_t) {0xf8, 0, 0x34, 0}); + + if (a != 0x003400f8) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-zunpkd830.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-zunpkd830.c new file mode 100644 index 0000000..8f5a224 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-zunpkd830.c @@ -0,0 +1,37 @@ +/* This is a test program for zunpkd830 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int zunpkd830 (unsigned int a) +{ + return __nds32__zunpkd830 (a); +} + +static __attribute__ ((noinline)) +uint16x2_t v_zunpkd830 (uint8x4_t a) +{ + return __nds32__v_zunpkd830 (a); +} + +int +main () +{ + unsigned int a = zunpkd830 (0x120000f8); + uint16x2_t va = v_zunpkd830 ((uint8x4_t) { 0xf8, 0x00, 0, 0x12}); + + if (a != 0x001200f8) + abort (); + else if (va[0] != 0x00f8 + || va[1] != 0x0012) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-dsp-zunpkd831.c b/gcc/testsuite/gcc.target/nds32/builtin-dsp-zunpkd831.c new file mode 100644 index 0000000..6878cd3 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-dsp-zunpkd831.c @@ -0,0 +1,43 @@ +/* This is a test program for zunpkd831 instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +static __attribute__ ((noinline)) +unsigned int zunpkd831 (unsigned int a) +{ + return __nds32__zunpkd831 (a); +} + +static __attribute__ ((noinline)) +uint16x2_t v_zunpkd831 (uint8x4_t a) +{ + return __nds32__v_zunpkd831 (a); +} + +int +main () +{ +#ifdef __NDS32_EL__ + int16x2_t va_p = {0xf8, 0x12}; +#else + int16x2_t va_p = {0, 0}; +#endif + + unsigned int a = zunpkd831 (0x1200f800); + uint16x2_t va = v_zunpkd831 ((uint8x4_t) {0, 0xf8, 0, 0x12}); + + if (a != 0x001200f8) + abort (); + else if (va[0] != va_p[0] + || va[1] != va_p[1]) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-fpu-fcpyd.c b/gcc/testsuite/gcc.target/nds32/builtin-fpu-fcpyd.c new file mode 100644 index 0000000..4ee7e5e --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-fpu-fcpyd.c @@ -0,0 +1,21 @@ +/* This is a test program for fcpysd instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_fpu_dp } */ + +#include +#include + +int +main () +{ + double da = -1.5; + double db = 1.3; + double dr = __nds32__fcpysd (da, db); + + if (dr != 1.5) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-fpu-fcpynd.c b/gcc/testsuite/gcc.target/nds32/builtin-fpu-fcpynd.c new file mode 100644 index 0000000..804410b --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-fpu-fcpynd.c @@ -0,0 +1,21 @@ +/* This is a test program for fcpynsd instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_fpu_dp } */ + +#include +#include + +int +main () +{ + double da = -1.5; + double db = -1.3; + double dr = __nds32__fcpynsd (da, db); + + if (dr != 1.5) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-fpu-fcpyns.c b/gcc/testsuite/gcc.target/nds32/builtin-fpu-fcpyns.c new file mode 100644 index 0000000..0d86734 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-fpu-fcpyns.c @@ -0,0 +1,21 @@ +/* This is a test program for fcpynss instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_fpu_sp } */ + +#include +#include + +int +main () +{ + float a = -1.5; + float b = -1.3; + float r = __nds32__fcpynss (a, b); + + if (r != 1.5) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-fpu-fcpys.c b/gcc/testsuite/gcc.target/nds32/builtin-fpu-fcpys.c new file mode 100644 index 0000000..4bccf57 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-fpu-fcpys.c @@ -0,0 +1,21 @@ +/* This is a test program for fcpyss instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_fpu_sp } */ + +#include +#include + +int +main () +{ + float a = -1.5; + float b = 1.3; + float r = __nds32__fcpyss (a, b); + + if (r != 1.5) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-fpu-fmfcfg.c b/gcc/testsuite/gcc.target/nds32/builtin-fpu-fmfcfg.c new file mode 100644 index 0000000..83e65ed --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-fpu-fmfcfg.c @@ -0,0 +1,23 @@ +/* This is a test program for fmfcfg instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_fpu } */ + +#include +#include + +int +main () +{ + unsigned int intrinsic_fmfcfg = -1; + unsigned int inline_assemble_fmfcfg = -2; + + intrinsic_fmfcfg = __nds32__fmfcfg (); + __asm volatile ("fmfcfg %0" : "=r" (inline_assemble_fmfcfg)); + + if (intrinsic_fmfcfg == inline_assemble_fmfcfg) + exit (0); + else + abort (); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-fpu-fpcsr.c b/gcc/testsuite/gcc.target/nds32/builtin-fpu-fpcsr.c new file mode 100644 index 0000000..787b430 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-fpu-fpcsr.c @@ -0,0 +1,35 @@ +/* This is a test program for fmtcsr/fmfcsr instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_fpu } */ + +#include +#include + +int +main () +{ + unsigned int fpcsr; + unsigned int real_fpcsr; + + /* Keep real fpcsr value. */ + real_fpcsr = __nds32__fmfcsr (); + + /* write fpcsr */ + fpcsr = 3; + __nds32__fmtcsr (fpcsr); + + /* read fpcsr */ + fpcsr = 0; + fpcsr = __nds32__fmfcsr (); + fpcsr = fpcsr & 0x00001fff; + + /* Recover fpcsr value. */ + __nds32__fmtcsr (real_fpcsr); + + if (fpcsr == 3) + exit (0); + else + abort (); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-get-lp.c b/gcc/testsuite/gcc.target/nds32/builtin-get-lp.c new file mode 100644 index 0000000..80b4921 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-get-lp.c @@ -0,0 +1,22 @@ +/* Verify the return address with builtin function. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ + +#include +#include + +int main() +{ + unsigned int intrinsic_lp = -1; + unsigned int inline_assemble_lp = -2; + + intrinsic_lp = __nds32__return_address (); + + __asm volatile ("mov55 %0, $lp" : "=r" (inline_assemble_lp)); + + if (intrinsic_lp != inline_assemble_lp) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-isb.c b/gcc/testsuite/gcc.target/nds32/builtin-isb.c deleted file mode 100644 index e65061b..0000000 --- a/gcc/testsuite/gcc.target/nds32/builtin-isb.c +++ /dev/null @@ -1,11 +0,0 @@ -/* Verify that we generate isb instruction with builtin function. */ - -/* { dg-do compile } */ -/* { dg-options "-O0" } */ -/* { dg-final { scan-assembler "\\tisb" } } */ - -void -test (void) -{ - __builtin_nds32_isb (); -} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-isync.c b/gcc/testsuite/gcc.target/nds32/builtin-isync.c deleted file mode 100644 index 3160e4a..0000000 --- a/gcc/testsuite/gcc.target/nds32/builtin-isync.c +++ /dev/null @@ -1,12 +0,0 @@ -/* Verify that we generate isync instruction with builtin function. */ - -/* { dg-do compile } */ -/* { dg-options "-O0" } */ -/* { dg-final { scan-assembler "\\tisync" } } */ - -void -test (void) -{ - int *addr = (int *) 0x53000000; - __builtin_nds32_isync (addr); -} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-mfsr-mtsr.c b/gcc/testsuite/gcc.target/nds32/builtin-mfsr-mtsr.c deleted file mode 100644 index db4c558..0000000 --- a/gcc/testsuite/gcc.target/nds32/builtin-mfsr-mtsr.c +++ /dev/null @@ -1,17 +0,0 @@ -/* Verify that we generate mfsr/mtsr instruction with builtin function. */ - -/* { dg-do compile } */ -/* { dg-options "-O0" } */ -/* { dg-final { scan-assembler "\\tmfsr" } } */ -/* { dg-final { scan-assembler "\\tmtsr" } } */ - -#include - -void -test (void) -{ - int ipsw_value; - - ipsw_value = __builtin_nds32_mfsr (__NDS32_REG_IPSW__); - __builtin_nds32_mtsr (ipsw_value, __NDS32_REG_IPSW__); -} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-mfusr-mtusr.c b/gcc/testsuite/gcc.target/nds32/builtin-mfusr-mtusr.c deleted file mode 100644 index 3cfaab9..0000000 --- a/gcc/testsuite/gcc.target/nds32/builtin-mfusr-mtusr.c +++ /dev/null @@ -1,17 +0,0 @@ -/* Verify that we generate mfusr/mtusr instruction with builtin function. */ - -/* { dg-do compile } */ -/* { dg-options "-O0" } */ -/* { dg-final { scan-assembler "\\tmfusr" } } */ -/* { dg-final { scan-assembler "\\tmtusr" } } */ - -#include - -void -test (void) -{ - int itype_value; - - itype_value = __builtin_nds32_mfusr (__NDS32_REG_ITYPE__); - __builtin_nds32_mtusr (itype_value, __NDS32_REG_ITYPE__); -} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-rotr.c b/gcc/testsuite/gcc.target/nds32/builtin-rotr.c new file mode 100644 index 0000000..a295cb2 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-rotr.c @@ -0,0 +1,19 @@ +/* This is a test program for rotr instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O0" } */ + +#include +#include + +int +main () +{ + unsigned int a = 1; + a = __nds32__rotr (a, 30); + + if (a != 4) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-setgie-dis.c b/gcc/testsuite/gcc.target/nds32/builtin-setgie-dis.c deleted file mode 100644 index 2dceed9..0000000 --- a/gcc/testsuite/gcc.target/nds32/builtin-setgie-dis.c +++ /dev/null @@ -1,11 +0,0 @@ -/* Verify that we generate setgie.d instruction with builtin function. */ - -/* { dg-do compile } */ -/* { dg-options "-O0" } */ -/* { dg-final { scan-assembler "\\tsetgie.d" } } */ - -void -test (void) -{ - __builtin_nds32_setgie_dis (); -} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-setgie-en.c b/gcc/testsuite/gcc.target/nds32/builtin-setgie-en.c deleted file mode 100644 index 8928870..0000000 --- a/gcc/testsuite/gcc.target/nds32/builtin-setgie-en.c +++ /dev/null @@ -1,11 +0,0 @@ -/* Verify that we generate setgie.e instruction with builtin function. */ - -/* { dg-do compile } */ -/* { dg-options "-O0" } */ -/* { dg-final { scan-assembler "\\tsetgie.e" } } */ - -void -test (void) -{ - __builtin_nds32_setgie_en (); -} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-setgie_mtsr_mfsr.c b/gcc/testsuite/gcc.target/nds32/builtin-setgie_mtsr_mfsr.c new file mode 100644 index 0000000..b353909 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-setgie_mtsr_mfsr.c @@ -0,0 +1,43 @@ +/* This is a test program for checking gie with + mtsr/mfsr instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O0" } */ + +#include +#include + +int +main () +{ + unsigned int psw; + unsigned int gie; + unsigned int pfm_ctl; + unsigned int real_psw; + + /* Keep PSW value. */ + real_psw = __nds32__mfsr (NDS32_SR_PSW); + + __nds32__setgie_en (); + __nds32__dsb(); /* This is needed for waiting pipeline. */ + psw = __nds32__mfsr (NDS32_SR_PSW); + + gie = psw & 0x00000001; + + if (gie != 1) + abort (); + + psw = psw & 0xFFFFFFFE; + __nds32__mtsr (psw, NDS32_SR_PSW); + __nds32__dsb(); /* This is needed for waiting pipeline. */ + psw = __nds32__mfsr (NDS32_SR_PSW); + gie = psw & 0x00000001; + + /* Recover PSW value. */ + __nds32__mtsr (real_psw, NDS32_SR_PSW); + + if (gie != 0) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-sp.c b/gcc/testsuite/gcc.target/nds32/builtin-sp.c new file mode 100644 index 0000000..2e5499d --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-sp.c @@ -0,0 +1,33 @@ +/* This is a test program for sp intrinsic usage. + Because we want to use frame pointer to access local variable, + we need to use -fno-omit-frame-pointer to make sure the existence + of frame pointer. */ + +/* { dg-do run } */ +/* { dg-options "-O0 -fno-omit-frame-pointer" } */ + +#include +#include + +int +main () +{ + unsigned int old_sp, new_sp; + + old_sp = __nds32__get_current_sp (); + new_sp = old_sp - 4; + __nds32__set_current_sp (new_sp); + new_sp = __nds32__get_current_sp (); + + if (new_sp != (old_sp - 4)) + abort (); + + new_sp = new_sp + 4; + __nds32__set_current_sp (new_sp); + new_sp = __nds32__get_current_sp (); + + if (new_sp != old_sp) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-string-ffb.c b/gcc/testsuite/gcc.target/nds32/builtin-string-ffb.c new file mode 100644 index 0000000..cf02434 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-string-ffb.c @@ -0,0 +1,28 @@ +/* This is a test program for ffb instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_string } */ + +#include +#include + +int +main () +{ + unsigned int a = 0x1b2a3d4c; + unsigned int b = 0x0000003d; + int r; + + r = __nds32__ffb (a, b); + +#ifdef __NDS32_EL__ + if (r != -3) + abort (); +#else + if (r != -2) + abort (); +#endif + + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-string-ffmism.c b/gcc/testsuite/gcc.target/nds32/builtin-string-ffmism.c new file mode 100644 index 0000000..b2fb008 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-string-ffmism.c @@ -0,0 +1,28 @@ +/* This is a test program for ffmism instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_string } */ + +#include +#include + +int +main () +{ + unsigned int a = 0x1b2a3d4c; + unsigned int b = 0x112a334c; + int r; + + r = __nds32__ffmism (a, b); + +#ifdef __NDS32_EL__ + if (r != -3) + abort (); +#else + if (r != -4) + abort (); +#endif + + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-string-flmism.c b/gcc/testsuite/gcc.target/nds32/builtin-string-flmism.c new file mode 100644 index 0000000..105fce5 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-string-flmism.c @@ -0,0 +1,28 @@ +/* This is a test program for flmism instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O1" } */ +/* { dg-require-effective-target nds32_ext_string } */ + +#include +#include + +int +main () +{ + unsigned int a = 0x1b2a3d4c; + unsigned int b = 0x112a334c; + int r; + + r = __nds32__flmism (a, b); + +#ifdef __NDS32_EL__ + if (r != -1) + abort (); +#else + if (r != -2) + abort (); +#endif + + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-unaligned-s16x2.c b/gcc/testsuite/gcc.target/nds32/builtin-unaligned-s16x2.c new file mode 100644 index 0000000..5a2e8b7 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-unaligned-s16x2.c @@ -0,0 +1,36 @@ +/* This is a test program for smbb instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +int +main (void) +{ + char data[] = {0x55,0x66,0x77,0x88}; + short* short_data = (short*)& data[1]; + int16x2_t test_short = {0x1111, 0xaaaa}; + int16x2_t vecdata = __nds32__get_unaligned_s16x2 (short_data); + +#ifdef __NDS32_EL__ + if (vecdata[0] != 0x7766) + abort (); +#else + if (vecdata[0] != 0x6677) + abort (); +#endif + + __nds32__put_unaligned_s16x2 (short_data, test_short); + vecdata = __nds32__get_unaligned_s16x2 (short_data); + + if (vecdata[0] != 0x1111 + & vecdata[1] != 0xaaaa) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-unaligned-s8x4.c b/gcc/testsuite/gcc.target/nds32/builtin-unaligned-s8x4.c new file mode 100644 index 0000000..f6cb4c9 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-unaligned-s8x4.c @@ -0,0 +1,36 @@ +/* This is a test program for smbb instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +int +main (void) +{ + char data[] = {0x55,0x66,0x77,0x88}; + char* char_data = (char*)& data[1]; + int8x4_t test_char = {0x11, 0x22, 0xaa, 0xbb}; + int8x4_t vecdata = __nds32__get_unaligned_s8x4 (char_data); + +#ifdef __NDS32_EL__ + if (vecdata[0] != 0x66) + abort (); +#else + if (vecdata[0] != 0x66) + abort (); +#endif + + __nds32__put_unaligned_s8x4 (char_data, test_char); + vecdata = __nds32__get_unaligned_s8x4 (char_data); + + if (vecdata[0] != 0x11 + & vecdata[3] != 0xaa) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-unaligned-u16x2.c b/gcc/testsuite/gcc.target/nds32/builtin-unaligned-u16x2.c new file mode 100644 index 0000000..63ebd40 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-unaligned-u16x2.c @@ -0,0 +1,36 @@ +/* This is a test program for smbb instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +int +main (void) +{ + unsigned char data[] = {0x55,0x66,0x77,0x88}; + unsigned short* short_data = (unsigned short*)& data[1]; + uint16x2_t test_short = {0x1111, 0xaaaa}; + uint16x2_t vecdata = __nds32__get_unaligned_u16x2 (short_data); + +#ifdef __NDS32_EL__ + if (vecdata[0] != 0x7766) + abort (); +#else + if (vecdata[0] != 0x6677) + abort (); +#endif + + __nds32__put_unaligned_u16x2 (short_data, test_short); + vecdata = __nds32__get_unaligned_u16x2 (short_data); + + if (vecdata[0] != 0x1111 + & vecdata[1] != 0xaaaa) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-unaligned-u8x4.c b/gcc/testsuite/gcc.target/nds32/builtin-unaligned-u8x4.c new file mode 100644 index 0000000..7b48274 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-unaligned-u8x4.c @@ -0,0 +1,36 @@ +/* This is a test program for smbb instruction. */ + +/* { dg-do run } */ + +#include +#include + +#ifdef __NDS32_EXT_DSP__ +int +main (void) +{ + char data[] = {0x55,0x66,0x77,0x88}; + unsigned char* char_data = (char*)& data[1]; + uint8x4_t test_char = {0x11, 0x22, 0xaa, 0xbb}; + uint8x4_t vecdata = __nds32__get_unaligned_u8x4 (char_data); + +#ifdef __NDS32_EL__ + if (vecdata[0] != 0x66) + abort (); +#else + if (vecdata[0] != 0x66) + abort (); +#endif + + __nds32__put_unaligned_u8x4 (char_data, test_char); + vecdata = __nds32__get_unaligned_u8x4 (char_data); + + if (vecdata[0] != 0x11 + & vecdata[3] != 0xaa) + abort (); + else + exit (0); +} +#else +int main(){return 0;} +#endif diff --git a/gcc/testsuite/gcc.target/nds32/builtin-unaligned_dw.c b/gcc/testsuite/gcc.target/nds32/builtin-unaligned_dw.c new file mode 100644 index 0000000..42640b4 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-unaligned_dw.c @@ -0,0 +1,31 @@ +/* This is a test program for unaligned double word access. */ + +/* { dg-do run } */ +/* { dg-options "-O0 -std=c99" } */ + +#include +#include + +int +main () +{ + unsigned char data[] = {0x55, 0x66, 0x77, 0x88, 0xAA, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; + unsigned long long* long_long_data = (unsigned long long*) & data[1]; + unsigned long long test_long_long = 0x1122334455667788LL; + +#ifdef __NDS32_EL__ + if (__nds32__get_unaligned_dw (long_long_data) != 0xEEDDCCBBAA887766LL) + abort (); +#else + if (__nds32__get_unaligned_dw (long_long_data) != 0x667788AABBCCDDEELL) + abort (); +#endif + + __nds32__put_unaligned_dw (long_long_data, test_long_long); + + if (__nds32__get_unaligned_dw (long_long_data) != 0x1122334455667788LL) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-unaligned_hw.c b/gcc/testsuite/gcc.target/nds32/builtin-unaligned_hw.c new file mode 100644 index 0000000..f9e1ceb --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-unaligned_hw.c @@ -0,0 +1,30 @@ +/* This is a test program for unaligned half word access. */ + +/* { dg-do run } */ +/* { dg-options "-O0" } */ + +#include +#include + +int +main () +{ + unsigned char data[] = {0x55,0x66,0x77,0x88}; + unsigned short* short_data = (unsigned short*)& data[1]; + unsigned short test_short = 0x5566; + +#ifdef __NDS32_EL__ + if (__nds32__get_unaligned_hw (short_data) != 0x7766) + abort (); +#else + if (__nds32__get_unaligned_hw (short_data) != 0x6677) + abort (); +#endif + + __nds32__put_unaligned_hw (short_data, test_short); + + if (__nds32__get_unaligned_hw (short_data) != 0x5566) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-unaligned_w.c b/gcc/testsuite/gcc.target/nds32/builtin-unaligned_w.c new file mode 100644 index 0000000..40d8711 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-unaligned_w.c @@ -0,0 +1,30 @@ +/* This is a test program for unaligned word access. */ + +/* { dg-do run } */ +/* { dg-options "-O0 -std=c99" } */ + +#include +#include + +int +main () +{ + unsigned char data[] = {0x55,0x66,0x77,0x88,0xAA,0xBB,0xCC,0xDD}; + unsigned int* int_data = (unsigned int*)& data[1]; + unsigned int test_int = 0x55667788; + +#ifdef __NDS32_EL__ + if (__nds32__get_unaligned_w (int_data) != 0xAA887766) + abort (); +#else + if (__nds32__get_unaligned_w (int_data) != 0x667788AA) + abort (); +#endif + + __nds32__put_unaligned_w (int_data, test_int); + + if (__nds32__get_unaligned_w (int_data) != 0x55667788) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/builtin-wsbh.c b/gcc/testsuite/gcc.target/nds32/builtin-wsbh.c new file mode 100644 index 0000000..1cee2ed --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/builtin-wsbh.c @@ -0,0 +1,21 @@ +/* This is a test program for wsbh instruction. */ + +/* { dg-do run } */ +/* { dg-options "-O0" } */ + +#include +#include + +int +main () +{ + unsigned int a = 0x03020100; + unsigned int b; + + b = __nds32__wsbh (a); + + if (b != 0x02030001) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-all-pending.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-all-pending.c new file mode 100644 index 0000000..0e57831 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-all-pending.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include + +int +main (void) +{ + int a = __nds32__get_all_pending_int (); + return a; +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-cctl.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-cctl.c new file mode 100644 index 0000000..2af55f5 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-cctl.c @@ -0,0 +1,29 @@ +/* Verify that we generate cache control instruction with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "L1D_VA_INVAL" } } */ +/* { dg-final { scan-assembler "L1D_VA_INVAL" } } */ +/* { dg-final { scan-assembler "L1D_INVALALL" } } */ +/* { dg-final { scan-assembler "L1D_IX_WWD" } } */ +/* { dg-final { scan-assembler "L1D_IX_RWD" } } */ +/* { dg-final { scan-assembler "PFM_CTL" } } */ +/* { dg-final { scan-assembler "PFM_CTL" } } */ + +#include + +void +test (void) +{ + unsigned int va = 0; + + __nds32__cctlva_lck (NDS32_CCTL_L1D_VA_FILLCK, &va); + __nds32__cctlidx_wbinval (NDS32_CCTL_L1D_IX_WBINVAL, va); + __nds32__cctlva_wbinval_alvl (NDS32_CCTL_L1D_VA_INVAL, &va); + __nds32__cctlva_wbinval_one_lvl (NDS32_CCTL_L1D_VA_INVAL, &va); + __nds32__cctl_l1d_invalall (); + __nds32__cctlidx_write (NDS32_CCTL_L1D_IX_WWD, va, 1); + __nds32__cctlidx_read (NDS32_CCTL_L1D_IX_RWD, 1); + __nds32__mtusr (0, NDS32_USR_PFM_CTL); + __nds32__mfusr (NDS32_USR_PFM_CTL); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-clr-pending-hw.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-clr-pending-hw.c new file mode 100644 index 0000000..fce90e9 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-clr-pending-hw.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include + +void +main (void) +{ + __nds32__clr_pending_hwint (NDS32_INT_H0); + __nds32__clr_pending_hwint (NDS32_INT_H1); + __nds32__clr_pending_hwint (NDS32_INT_H2); + + __nds32__clr_pending_hwint (NDS32_INT_H15); + __nds32__clr_pending_hwint (NDS32_INT_H16); + __nds32__clr_pending_hwint (NDS32_INT_H31); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-clr-pending.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-clr-pending.c new file mode 100644 index 0000000..08e1dd0 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-clr-pending.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include + +void +main (void) +{ + __nds32__clr_pending_swint (); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-disable.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-disable.c new file mode 100644 index 0000000..a3a1f44 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-disable.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include + +void +main (void) +{ + __nds32__disable_int (NDS32_INT_H15); + __nds32__disable_int (NDS32_INT_H16); + __nds32__disable_int (NDS32_INT_H31); + __nds32__disable_int (NDS32_INT_SWI); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-dpref.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-dpref.c new file mode 100644 index 0000000..38cf822 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-dpref.c @@ -0,0 +1,24 @@ +/* Verify that we generate data prefetch instruction with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "dpref\\tSRD" } } */ +/* { dg-final { scan-assembler "dpref\\tSRD" } } */ +/* { dg-final { scan-assembler "dpref\\tSRD" } } */ +/* { dg-final { scan-assembler "dpref\\tSRD" } } */ + +#include + +void +test (void) +{ + unsigned char dpref_q = 0; + unsigned short dpref_h = 0; + unsigned int dpref_w = 0; + unsigned long long dpref_dw = 0; + + __nds32__dpref_qw (&dpref_q, 0, NDS32_DPREF_SRD); + __nds32__dpref_hw (&dpref_h, 0, NDS32_DPREF_SRD); + __nds32__dpref_w (&dpref_w, 0, NDS32_DPREF_SRD); + __nds32__dpref_dw (&dpref_dw, 0, NDS32_DPREF_SRD); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-enable.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-enable.c new file mode 100644 index 0000000..e18ed7a --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-enable.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include + +void +main (void) +{ + __nds32__enable_int (NDS32_INT_H15); + __nds32__enable_int (NDS32_INT_H16); + __nds32__enable_int (NDS32_INT_H31); + __nds32__enable_int (NDS32_INT_SWI); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-get-pending-int.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-get-pending-int.c new file mode 100644 index 0000000..4ced0a5 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-get-pending-int.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include + +int +main (void) +{ + int a = __nds32__get_pending_int (NDS32_INT_H15); + int b = __nds32__get_pending_int (NDS32_INT_SWI); + int c = __nds32__get_pending_int (NDS32_INT_H16); + + return a + b + c; +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-get-trig.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-get-trig.c new file mode 100644 index 0000000..a394a60 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-get-trig.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include + +int +main (void) +{ + int a = __nds32__get_trig_type (NDS32_INT_H0); + int b = __nds32__get_trig_type (NDS32_INT_H15); + int c = __nds32__get_trig_type (NDS32_INT_H16); + int d = __nds32__get_trig_type (NDS32_INT_H31); + return a + b + c + d; +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-isb.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-isb.c new file mode 100644 index 0000000..c699966 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-isb.c @@ -0,0 +1,13 @@ +/* Verify that we generate isb instruction with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "\\tisb" } } */ + +#include + +void +test (void) +{ + __nds32__isb (); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-isync.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-isync.c new file mode 100644 index 0000000..0c312e4 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-isync.c @@ -0,0 +1,14 @@ +/* Verify that we generate isync instruction with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "\\tisync" } } */ + +#include + +void +test (void) +{ + int *addr = (int *) 0x53000000; + __nds32__isync (addr); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-load-store.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-load-store.c new file mode 100644 index 0000000..fc15716 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-load-store.c @@ -0,0 +1,25 @@ +/* Verify that we generate llw/lwup/scw/swup instruction + with builtin function. */ + +/* { dg-do compile } */ +/* { dg-require-effective-target nds32_no_v3m } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "\\tllw" } } */ +/* { dg-final { scan-assembler "\\tlwup" } } */ +/* { dg-final { scan-assembler "\\tscw" } } */ +/* { dg-final { scan-assembler "\\tswup" } } */ + +#include + +void +test (void) +{ + int a = 0; + int b = 0; + unsigned int cc = 0; + + __nds32__llw (&a); + cc = __nds32__lwup (&a); + __nds32__scw (&a, b); + __nds32__swup (&a, b); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-lto.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-lto.c new file mode 100644 index 0000000..fbebcb6 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-lto.c @@ -0,0 +1,28 @@ +/* Verify that we use -flto option to generate instructions + with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0 -flto" } */ +/* { dg-final { scan-assembler "\\tdsb" } } */ +/* { dg-final { scan-assembler "\\tisb" } } */ +/* { dg-final { scan-assembler "\\tmsync\\tall" } } */ +/* { dg-final { scan-assembler "\\tmsync\\tstore" } } */ +/* { dg-final { scan-assembler "\\tnop" } } */ +/* { dg-final { scan-assembler "\\tstandby\\tno_wake_grant" } } */ +/* { dg-final { scan-assembler "\\tstandby\\twake_grant" } } */ +/* { dg-final { scan-assembler "\\tstandby\\twait_done" } } */ + +#include + +void +test (void) +{ + __nds32__dsb (); + __nds32__isb (); + __nds32__msync_all (); + __nds32__msync_store (); + __nds32__nop (); + __nds32__standby_no_wake_grant (); + __nds32__standby_wake_grant (); + __nds32__standby_wait_done (); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-machine-sva.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-machine-sva.c new file mode 100644 index 0000000..f927c72 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-machine-sva.c @@ -0,0 +1,16 @@ +/* Verify that we generate sva instruction with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "\\tsva" } } */ + +#include + +void +test (void) +{ + int a, b; + char c; + + c = __nds32__sva (a, b); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-machine-svs.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-machine-svs.c new file mode 100644 index 0000000..f998491 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-machine-svs.c @@ -0,0 +1,16 @@ +/* Verify that we generate svs instruction with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "\\tsvs" } } */ + +#include + +void +test (void) +{ + int a, b; + char c; + + c = __nds32__svs (a, b); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-mfsr-mtsr.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-mfsr-mtsr.c new file mode 100644 index 0000000..f069507 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-mfsr-mtsr.c @@ -0,0 +1,17 @@ +/* Verify that we generate mfsr/mtsr instruction with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "\\tmfsr" } } */ +/* { dg-final { scan-assembler "\\tmtsr" } } */ + +#include + +void +test (void) +{ + int ipsw_value; + + ipsw_value = __nds32__mfsr (__NDS32_REG_IPSW__); + __nds32__mtsr (ipsw_value, __NDS32_REG_IPSW__); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-mfusr-mtusr.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-mfusr-mtusr.c new file mode 100644 index 0000000..d6d069b --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-mfusr-mtusr.c @@ -0,0 +1,17 @@ +/* Verify that we generate mfusr/mtusr instruction with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "\\tmfusr" } } */ +/* { dg-final { scan-assembler "\\tmtusr" } } */ + +#include + +void +test (void) +{ + int itype_value; + + itype_value = __nds32__mfusr (__NDS32_REG_ITYPE__); + __nds32__mtusr (itype_value, __NDS32_REG_ITYPE__); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-misc.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-misc.c new file mode 100644 index 0000000..a11f6d9 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-misc.c @@ -0,0 +1,39 @@ +/* Verify that we generate other instructions with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "\\tbreak" } } */ +/* { dg-final { scan-assembler "\\tdsb" } } */ +/* { dg-final { scan-assembler "\\tisb" } } */ +/* { dg-final { scan-assembler "\\tisync" } } */ +/* { dg-final { scan-assembler "\\tmsync\\tall" } } */ +/* { dg-final { scan-assembler "\\tmsync\\tstore" } } */ +/* { dg-final { scan-assembler "\\tnop" } } */ +/* { dg-final { scan-assembler "\\tstandby\\tno_wake_grant" } } */ +/* { dg-final { scan-assembler "\\tstandby\\twake_grant" } } */ +/* { dg-final { scan-assembler "\\tstandby\\twait_done" } } */ +/* { dg-final { scan-assembler "\\tteqz" } } */ +/* { dg-final { scan-assembler "\\ttnez" } } */ +/* { dg-final { scan-assembler "\\ttrap" } } */ + +#include + +void +test (void) +{ + int a = 0; + + __nds32__break (2); + __nds32__dsb (); + __nds32__isb (); + __nds32__isync (&a); + __nds32__msync_all (); + __nds32__msync_store (); + __nds32__nop (); + __nds32__standby_no_wake_grant (); + __nds32__standby_wake_grant (); + __nds32__standby_wait_done (); + __nds32__teqz (a, 2); + __nds32__tnez (a, 2); + __nds32__trap (2); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-mtsr-dsb.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-mtsr-dsb.c new file mode 100644 index 0000000..226d627 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-mtsr-dsb.c @@ -0,0 +1,14 @@ +/* Verify that we generate mtsr and dsb instruction with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "\\tmtsr" } } */ +/* { dg-final { scan-assembler "\\tdsb" } } */ + +#include + +void +main (void) +{ + __nds32__mtsr_dsb (1, NDS32_SR_ILMB); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-mtsr-isb.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-mtsr-isb.c new file mode 100644 index 0000000..e8b1f98 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-mtsr-isb.c @@ -0,0 +1,14 @@ +/* Verify that we generate mtsr and isb instruction with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "\\tmtsr" } } */ +/* { dg-final { scan-assembler "\\tisb" } } */ + +#include + +void +main (void) +{ + __nds32__mtsr_isb (1, NDS32_SR_ILMB); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-priority.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-priority.c new file mode 100644 index 0000000..c2ec6f6 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-priority.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include + +int +main (void) +{ + __nds32__set_int_priority (NDS32_INT_H0, 0); + __nds32__set_int_priority (NDS32_INT_H15, 3); + __nds32__set_int_priority (NDS32_INT_H31, 3); + + int a = __nds32__get_int_priority (NDS32_INT_H0); + int b = __nds32__get_int_priority (NDS32_INT_H15); + int c = __nds32__get_int_priority (NDS32_INT_H31); + + return a + b + c; +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-set-pending.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-set-pending.c new file mode 100644 index 0000000..f10b83d --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-set-pending.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include + +int +main (void) +{ + __nds32__set_pending_swint (); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-set-trig-edge.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-set-trig-edge.c new file mode 100644 index 0000000..bd8178c --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-set-trig-edge.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include + +void +main (void) +{ + __nds32__set_trig_type_edge (NDS32_INT_H0); + __nds32__set_trig_type_edge (NDS32_INT_H15); + __nds32__set_trig_type_edge (NDS32_INT_H16); + __nds32__set_trig_type_edge (NDS32_INT_H31); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-set-trig-level.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-set-trig-level.c new file mode 100644 index 0000000..1780543 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-set-trig-level.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include + +void +main (void) +{ + __nds32__set_trig_type_level (NDS32_INT_H0); + __nds32__set_trig_type_level (NDS32_INT_H15); + __nds32__set_trig_type_level (NDS32_INT_H16); + __nds32__set_trig_type_level (NDS32_INT_H31); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-setgie-dis.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-setgie-dis.c new file mode 100644 index 0000000..e143d3f --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-setgie-dis.c @@ -0,0 +1,13 @@ +/* Verify that we generate setgie.d instruction with builtin function. */ + +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "\\tsetgie.d" } } */ + +#include + +void +test (void) +{ + __nds32__setgie_dis (); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-setgie-en.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-setgie-en.c new file mode 100644 index 0000000..ed95782 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-setgie-en.c @@ -0,0 +1,13 @@ +/* Verify that we generate setgie.e instruction with builtin function. */ + +/* { dg-do compile */ +/* { dg-options "-O0" } */ +/* { dg-final { scan-assembler "\\tsetgie.e" } } */ + +#include + +void +test (void) +{ + __nds32__setgie_en (); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-add16.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-add16.c new file mode 100644 index 0000000..49fca46 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-add16.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "kadd16" } } */ +/* { dg-final { scan-assembler "kadd16" } } */ +/* { dg-final { scan-assembler "ukadd16" } } */ +/* { dg-final { scan-assembler "ukadd16" } } */ + +#include + +void +test (void) +{ + unsigned int r, a, b; + int16x2_t vr, va, vb; + uint16x2_t v_ur, v_ua, v_ub; + + r = __nds32__kadd16 (a, b); + vr = __nds32__v_kadd16 (va, vb); + + r = __nds32__ukadd16 (a, b); + v_ur = __nds32__v_ukadd16 (v_ua, v_ub); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-add64.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-add64.c new file mode 100644 index 0000000..1f33a42 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-add64.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "kadd64" } } */ +/* { dg-final { scan-assembler "ukadd64" } } */ + +#include + +void +test (void) +{ + long long r, a, b; + unsigned long long ur, ua, ub; + + r = __nds32__kadd64 (a, b); + ur = __nds32__ukadd64 (ua, ub); + +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-add8.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-add8.c new file mode 100644 index 0000000..1f2d226 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-add8.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "kadd8" } } */ +/* { dg-final { scan-assembler "kadd8" } } */ +/* { dg-final { scan-assembler "ukadd8" } } */ +/* { dg-final { scan-assembler "ukadd8" } } */ + +#include + +void +test (void) +{ + unsigned int r, a, b; + int8x4_t vr, va, vb; + uint8x4_t v_ur, v_ua, v_ub; + + r = __nds32__kadd8 (a, b); + vr = __nds32__v_kadd8 (va, vb); + + r = __nds32__ukadd8 (a, b); + v_ur = __nds32__v_ukadd8 (v_ua, v_ub); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-cras16.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-cras16.c new file mode 100644 index 0000000..89c7e6d --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-cras16.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "kcras16" } } */ +/* { dg-final { scan-assembler "kcras16" } } */ +/* { dg-final { scan-assembler "ukcras16" } } */ +/* { dg-final { scan-assembler "ukcras16" } } */ + +#include + +void +test (void) +{ + unsigned int r, a, b; + int16x2_t vr, va, vb; + uint16x2_t v_ur, v_ua, v_ub; + + r = __nds32__kcras16 (a, b); + vr = __nds32__v_kcras16 (va, vb); + + r = __nds32__ukcras16 (a, b); + v_ur = __nds32__v_ukcras16 (v_ua, v_ub); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-crsa16.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-crsa16.c new file mode 100644 index 0000000..beaa69a --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-crsa16.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "kcrsa16" } } */ +/* { dg-final { scan-assembler "kcrsa16" } } */ +/* { dg-final { scan-assembler "ukcrsa16" } } */ +/* { dg-final { scan-assembler "ukcrsa16" } } */ + +#include + +void +test (void) +{ + unsigned int r, a, b; + int16x2_t vr, va, vb; + uint16x2_t v_ur, v_ua, v_ub; + + r = __nds32__kcrsa16 (a, b); + vr = __nds32__v_kcrsa16 (va, vb); + + r = __nds32__ukcrsa16 (a, b); + v_ur = __nds32__v_ukcrsa16 (v_ua, v_ub); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-kabs8.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-kabs8.c new file mode 100644 index 0000000..de2e3c3 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-kabs8.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "kabs8" } } */ +/* { dg-final { scan-assembler "kabs8" } } */ + +#include + +void +test (void) +{ + unsigned int r, a; + int8x4_t vr, va; + + r = __nds32__kabs8 (a); + vr = __nds32__v_kabs8 (va); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-ksll.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-ksll.c new file mode 100644 index 0000000..316b10c --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-ksll.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "ksll" } } */ +/* { dg-final { scan-assembler "kslli" } } */ + +#include + +void +test (void) +{ + int r, a; + unsigned int b; + + r = __nds32__ksll (a, b); + r = __nds32__ksll (a, 0); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-ksll16.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-ksll16.c new file mode 100644 index 0000000..be9a08e --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-ksll16.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "ksll16" } } */ +/* { dg-final { scan-assembler "ksll16" } } */ +/* { dg-final { scan-assembler "kslli16" } } */ +/* { dg-final { scan-assembler "kslli16" } } */ + +#include + +void +test (void) +{ + unsigned int r, a, b; + int16x2_t vr, va; + + r = __nds32__ksll16 (a, b); + vr = __nds32__v_ksll16 (va, b); + + r = __nds32__ksll16 (a, 0); + vr = __nds32__v_ksll16 (va, 0); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-kslrawu.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-kslrawu.c new file mode 100644 index 0000000..4eb03e5 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-kslrawu.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "kslraw.u" } } */ + +#include + +void +test (void) +{ + int r, a; + unsigned int b; + + r = __nds32__kslraw_u (a, b); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-mar64.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-mar64.c new file mode 100644 index 0000000..79a3eb3 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-mar64.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "kmar64" } } */ +/* { dg-final { scan-assembler "ukmar64" } } */ + +#include + +void +test (void) +{ + long long r, a, b; + unsigned long long ur, ua, ub; + + r = __nds32__kmar64 (r, a, b); + ur = __nds32__ukmar64 (ur, ua, ub); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-misc16.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-misc16.c new file mode 100644 index 0000000..272e922 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-misc16.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "sclip16" } } */ +/* { dg-final { scan-assembler "sclip16" } } */ +/* { dg-final { scan-assembler "uclip16" } } */ +/* { dg-final { scan-assembler "uclip16" } } */ +/* { dg-final { scan-assembler "khm16" } } */ +/* { dg-final { scan-assembler "khm16" } } */ +/* { dg-final { scan-assembler "khmx16" } } */ +/* { dg-final { scan-assembler "khmx16" } } */ +/* { dg-final { scan-assembler "kabs16" } } */ +/* { dg-final { scan-assembler "kabs16" } } */ + +#include + +void +test (void) +{ + unsigned int r, a, b; + int16x2_t vr, va, vb; + + r = __nds32__sclip16 (a, 0); + vr = __nds32__v_sclip16 (va, 0); + + r = __nds32__uclip16 (a, 0); + vr = __nds32__v_uclip16 (va, 0); + + r = __nds32__khm16 (a, b); + vr = __nds32__v_khm16 (va, vb); + + r = __nds32__khmx16 (a, b); + vr = __nds32__v_khmx16 (va, vb); + + r = __nds32__kabs16 (a); + vr = __nds32__v_kabs16 (va); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-msr64.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-msr64.c new file mode 100644 index 0000000..2ad64fa --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-msr64.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "kmsr64" } } */ +/* { dg-final { scan-assembler "ukmsr64" } } */ + +#include + +void +test (void) +{ + long long r, a, b; + unsigned long long ur, ua, ub; + + r = __nds32__kmsr64 (r, a, b); + ur = __nds32__ukmsr64 (ur, ua, ub); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-msw16.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-msw16.c new file mode 100644 index 0000000..d7ccecb --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-msw16.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "kmmawb" } } */ +/* { dg-final { scan-assembler "kmmawb" } } */ +/* { dg-final { scan-assembler "kmmawb.u" } } */ +/* { dg-final { scan-assembler "kmmawb.u" } } */ +/* { dg-final { scan-assembler "kmmawt" } } */ +/* { dg-final { scan-assembler "kmmawt" } } */ +/* { dg-final { scan-assembler "kmmawt.u" } } */ +/* { dg-final { scan-assembler "kmmawt.u" } } */ + +#include + +void +test (void) +{ + int r, a; + unsigned int b; + int16x2_t vb; + + r = __nds32__kmmawb (r, a, b); + r = __nds32__v_kmmawb (r, a, vb); + + r = __nds32__kmmawb_u (r, a, b); + r = __nds32__v_kmmawb_u (r, a, vb); + + r = __nds32__kmmawt (r, a, b); + r = __nds32__v_kmmawt (r, a, vb); + + r = __nds32__kmmawt_u (r, a, b); + r = __nds32__v_kmmawt_u (r, a, vb); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-msw32.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-msw32.c new file mode 100644 index 0000000..64d8d4a --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-msw32.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "kmmac" } } */ +/* { dg-final { scan-assembler "kmmac.u" } } */ +/* { dg-final { scan-assembler "kmmsb" } } */ +/* { dg-final { scan-assembler "kmmsb.u" } } */ +/* { dg-final { scan-assembler "kwmmul" } } */ +/* { dg-final { scan-assembler "kwmmul.u" } } */ + +#include + +void +test (void) +{ + int r, a, b; + r = __nds32__kmmac (r, a, b); + r = __nds32__kmmac_u (r, a, b); + + r = __nds32__kmmsb (r, a, b); + r = __nds32__kmmsb_u (r, a, b); + + r = __nds32__kwmmul (a, b); + r = __nds32__kwmmul_u (a, b); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-smul16x32.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-smul16x32.c new file mode 100644 index 0000000..0d2b87f --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-smul16x32.c @@ -0,0 +1,72 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "kmda" } } */ +/* { dg-final { scan-assembler "kmda" } } */ +/* { dg-final { scan-assembler "kmxda" } } */ +/* { dg-final { scan-assembler "kmxda" } } */ +/* { dg-final { scan-assembler "kmabb" } } */ +/* { dg-final { scan-assembler "kmabb" } } */ +/* { dg-final { scan-assembler "kmabt" } } */ +/* { dg-final { scan-assembler "kmabt" } } */ +/* { dg-final { scan-assembler "kmatt" } } */ +/* { dg-final { scan-assembler "kmatt" } } */ +/* { dg-final { scan-assembler "kmada" } } */ +/* { dg-final { scan-assembler "kmada" } } */ +/* { dg-final { scan-assembler "kmaxda" } } */ +/* { dg-final { scan-assembler "kmaxda" } } */ +/* { dg-final { scan-assembler "kmads" } } */ +/* { dg-final { scan-assembler "kmads" } } */ +/* { dg-final { scan-assembler "kmadrs" } } */ +/* { dg-final { scan-assembler "kmadrs" } } */ +/* { dg-final { scan-assembler "kmaxds" } } */ +/* { dg-final { scan-assembler "kmaxds" } } */ +/* { dg-final { scan-assembler "kmsda" } } */ +/* { dg-final { scan-assembler "kmsda" } } */ +/* { dg-final { scan-assembler "kmsxda" } } */ +/* { dg-final { scan-assembler "kmsxda" } } */ + +#include + +void +test (void) +{ + int r; + unsigned int a, b; + int16x2_t va, vb; + + r = __nds32__kmda (a, b); + r = __nds32__v_kmda (va, vb); + + r = __nds32__kmxda (a, b); + r = __nds32__v_kmxda (va, vb); + + r = __nds32__kmabb (r, a, b); + r = __nds32__v_kmabb (r, va, vb); + + r = __nds32__kmabt (r, a, b); + r = __nds32__v_kmabt (r, va, vb); + + r = __nds32__kmatt (r, a, b); + r = __nds32__v_kmatt (r, va, vb); + + r = __nds32__kmada (r, a, b); + r = __nds32__v_kmada (r, va, vb); + + r = __nds32__kmaxda (r, a, b); + r = __nds32__v_kmaxda (r, va, vb); + + r = __nds32__kmads (r, a, b); + r = __nds32__v_kmads (r, va, vb); + + r = __nds32__kmadrs (r, a, b); + r = __nds32__v_kmadrs (r, va, vb); + + r = __nds32__kmaxds (r, a, b); + r = __nds32__v_kmaxds (r, va, vb); + + r = __nds32__kmsda (r, a, b); + r = __nds32__v_kmsda (r, va, vb); + + r = __nds32__kmsxda (r, a, b); + r = __nds32__v_kmsxda (r, va, vb); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-sub16.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-sub16.c new file mode 100644 index 0000000..ecea7bb --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-sub16.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "ksub16" } } */ +/* { dg-final { scan-assembler "ksub16" } } */ +/* { dg-final { scan-assembler "uksub16" } } */ +/* { dg-final { scan-assembler "uksub16" } } */ + +#include + +void +test (void) +{ + unsigned int r, a, b; + int16x2_t vr, va, vb; + uint16x2_t v_ur, v_ua, v_ub; + + r = __nds32__ksub16 (a, b); + vr = __nds32__v_ksub16 (va, vb); + + r = __nds32__uksub16 (a, b); + v_ur = __nds32__v_uksub16 (v_ua, v_ub); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-sub64.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-sub64.c new file mode 100644 index 0000000..fae30e9 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-sub64.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "ksub64" } } */ +/* { dg-final { scan-assembler "uksub64" } } */ + +#include + +void +test (void) +{ + long long r, a, b; + unsigned long long ur, ua, ub; + + r = __nds32__ksub64 (a, b); + ur = __nds32__uksub64 (ua, ub); + +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-sub8.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-sub8.c new file mode 100644 index 0000000..5e343e9 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-stura-sub8.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-mext-dsp" } */ +/* { dg-final { scan-assembler "ksub8" } } */ +/* { dg-final { scan-assembler "ksub8" } } */ +/* { dg-final { scan-assembler "uksub8" } } */ +/* { dg-final { scan-assembler "uksub8" } } */ + +#include + +void +test (void) +{ + unsigned int r, a, b; + int8x4_t vr, va, vb; + uint8x4_t v_ur, v_ua, v_ub; + + r = __nds32__ksub8 (a, b); + vr = __nds32__v_ksub8 (va, vb); + + r = __nds32__uksub8 (a, b); + v_ur = __nds32__v_uksub8 (v_ua, v_ub); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/builtin-unaligned-feature.c b/gcc/testsuite/gcc.target/nds32/compile/builtin-unaligned-feature.c new file mode 100644 index 0000000..6199109 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/builtin-unaligned-feature.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +#include + +int +main () +{ + unsigned unalign = __nds32__unaligned_feature (); + __nds32__enable_unaligned (); + __nds32__disable_unaligned (); + return unalign; +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/dsp-add-sub.c b/gcc/testsuite/gcc.target/nds32/compile/dsp-add-sub.c new file mode 100644 index 0000000..704610e --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/dsp-add-sub.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mext-dsp" } */ +/* { dg-final { scan-assembler "add8" } } */ +/* { dg-final { scan-assembler "add16" } } */ +/* { dg-final { scan-assembler "add64" } } */ +/* { dg-final { scan-assembler "sub8" } } */ +/* { dg-final { scan-assembler "sub16" } } */ +/* { dg-final { scan-assembler "sub64" } } */ + +typedef signed char v4qi __attribute__ ((vector_size (4))); +typedef short v2hi __attribute__ ((vector_size (4))); + +v4qi __attribute__ ((noinline)) +add8 (v4qi a, v4qi b) +{ + return a + b; +} + +v4qi __attribute__ ((noinline)) +sub8 (v4qi a, v4qi b) +{ + return a - b; +} + +v2hi __attribute__ ((noinline)) +add16 (v2hi a, v2hi b) +{ + return a + b; +} + +v2hi __attribute__ ((noinline)) +sub16 (v2hi a, v2hi b) +{ + return a - b; +} + +long long +add64 (long long a, long long b) +{ + return a + b; +} + +long long +sub64 (long long a, long long b) +{ + return a - b; +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/dsp-bpick.c b/gcc/testsuite/gcc.target/nds32/compile/dsp-bpick.c new file mode 100644 index 0000000..5f9d7de --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/dsp-bpick.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mext-dsp" } */ +/* { dg-final { scan-assembler "bpick" } } */ + +int bpick(int a, int b, int mask) +{ + return (a & mask) | (b & ~mask); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/dsp-mmul.c b/gcc/testsuite/gcc.target/nds32/compile/dsp-mmul.c new file mode 100644 index 0000000..5c9cdeb --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/dsp-mmul.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mext-dsp" } */ +/* { dg-final { scan-assembler "smmul" } } */ + +typedef signed char v4qi __attribute__ ((vector_size (4))); +typedef short v2hi __attribute__ ((vector_size (4))); + +int smmul(int a, int b) +{ + long long tmp = (long long)a * b; + return (int)((tmp >> 32) & 0xffffffffll); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/dsp-mulhisi.c b/gcc/testsuite/gcc.target/nds32/compile/dsp-mulhisi.c new file mode 100644 index 0000000..856530b --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/dsp-mulhisi.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mext-dsp" } */ +/* { dg-final { scan-assembler "smbb" } } */ +/* { dg-final { scan-assembler "smbt" } } */ +/* { dg-final { scan-assembler "smtt" } } */ + +typedef signed char v4qi __attribute__ ((vector_size (4))); +typedef short v2hi __attribute__ ((vector_size (4))); + +int smbb(v2hi a, v2hi b) +{ + return a[0] * b[0]; +} + +int smbt(v2hi a, v2hi b) +{ + return a[0] * b[1]; +} + +int smtt(v2hi a, v2hi b) +{ + return a[1] * b[1]; +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/dsp-raddsub.c b/gcc/testsuite/gcc.target/nds32/compile/dsp-raddsub.c new file mode 100644 index 0000000..4817637 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/dsp-raddsub.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mext-dsp" } */ +/* { dg-final { scan-assembler "raddw" } } */ +/* { dg-final { scan-assembler "rsubw" } } */ +/* { dg-final { scan-assembler "uraddw" } } */ +/* { dg-final { scan-assembler "ursubw" } } */ + +int raddw(int a, int b) +{ + return (a + b) >> 1; +} + +int rsubw(int a, int b) +{ + return (a - b) >> 1; +} + +unsigned uraddw(unsigned a, unsigned b) +{ + return (a + b) >> 1; +} + +unsigned ursubw(unsigned a, unsigned b) +{ + return (a - b) >> 1; +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/dsp-smals.c b/gcc/testsuite/gcc.target/nds32/compile/dsp-smals.c new file mode 100644 index 0000000..f1dc684 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/dsp-smals.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mext-dsp" } */ +/* { dg-final { scan-assembler "smalbb" } } */ +/* { dg-final { scan-assembler "smalbt" } } */ +/* { dg-final { scan-assembler "smaltt" } } */ +/* { dg-final { scan-assembler "smal" } } */ + +typedef signed char v4qi __attribute__ ((vector_size (4))); +typedef short v2hi __attribute__ ((vector_size (4))); + + +long long smalbb(long long acc, v2hi a, v2hi b) +{ + return acc + a[0] * b[0]; +} + +long long smalbt(long long acc, v2hi a, v2hi b) +{ + return acc + a[1] * b[0]; +} + +long long smaltt(long long acc, v2hi a, v2hi b) +{ + return acc + a[1] * b[1]; +} + +long long smal(v2hi a, long long b) +{ + return b + (long long)(a[0] * a[1]); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/dsp-smalxda.c b/gcc/testsuite/gcc.target/nds32/compile/dsp-smalxda.c new file mode 100644 index 0000000..2fe606b --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/dsp-smalxda.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mext-dsp" } */ +/* { dg-final { scan-assembler "smalxda" } } */ +/* { dg-final { scan-assembler "smalxds" } } */ + +typedef signed char v4qi __attribute__ ((vector_size (4))); +typedef short v2hi __attribute__ ((vector_size (4))); + +long long smalxda(long long acc, v2hi a, v2hi b) +{ + return acc + (a[0] * b[1] + a[1] * b[0]); +} + +long long smalxds(long long acc, v2hi a, v2hi b) +{ + return acc + (a[1] * b[0] - a[0] * b[1]); +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/dsp-unpkd.c b/gcc/testsuite/gcc.target/nds32/compile/dsp-unpkd.c new file mode 100644 index 0000000..2de7107 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/dsp-unpkd.c @@ -0,0 +1,79 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mext-dsp" } */ +/* { dg-final { scan-assembler "sunpkd810" } } */ +/* { dg-final { scan-assembler "sunpkd820" } } */ +/* { dg-final { scan-assembler "sunpkd830" } } */ +/* { dg-final { scan-assembler "sunpkd831" } } */ +/* { dg-final { scan-assembler "zunpkd810" } } */ +/* { dg-final { scan-assembler "zunpkd820" } } */ +/* { dg-final { scan-assembler "zunpkd830" } } */ +/* { dg-final { scan-assembler "zunpkd831" } } */ + +typedef signed char v4qi __attribute__ ((vector_size (4))); +typedef short v2hi __attribute__ ((vector_size (4))); +typedef unsigned char uv4qi __attribute__ ((vector_size (4))); +typedef unsigned short uv2hi __attribute__ ((vector_size (4))); + +v2hi sunpkd810(v4qi v) +{ + v2hi ret; + ret[0] = v[0]; + ret[1] = v[1]; + return ret; +} + +v2hi sunpkd820(v4qi v) +{ + v2hi ret; + ret[0] = v[0]; + ret[1] = v[2]; + return ret; +} + +v2hi sunpkd830(v4qi v) +{ + v2hi ret; + ret[0] = v[0]; + ret[1] = v[3]; + return ret; +} + +v2hi sunpkd831(v4qi v) +{ + v2hi ret; + ret[0] = v[1]; + ret[1] = v[3]; + return ret; +} + +uv2hi zunpkd810(uv4qi v) +{ + uv2hi ret; + ret[0] = v[0]; + ret[1] = v[1]; + return ret; +} + +uv2hi zunpkd820(uv4qi v) +{ + uv2hi ret; + ret[0] = v[0]; + ret[1] = v[2]; + return ret; +} + +uv2hi zunpkd830(uv4qi v) +{ + uv2hi ret; + ret[0] = v[0]; + ret[1] = v[3]; + return ret; +} + +uv2hi zunpkd831(uv4qi v) +{ + uv2hi ret; + ret[0] = v[1]; + ret[1] = v[3]; + return ret; +} diff --git a/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-1.c b/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-1.c new file mode 100644 index 0000000..d456fa5 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-1.c @@ -0,0 +1,21 @@ +/* Verify scalbn transform pass for normal case. */ + +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-all -lm" } */ +/* { dg-require-effective-target nds32_soft_fp } */ + +float test_scalbnf (float x) +{ + return x * 128; +} + +double test_scalbn (double x) +{ + return x * 256; +} + +/* { dg-final { scan-tree-dump "(_\[0-9\]+) = __builtin_scalbnf \\(x_\[0-9\]+\\(D\\), 7\\);\\s*_\[0-9\]+ = \\(float\\) \\1;" "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump "(_\[0-9\]+) = __builtin_scalbn \\(x_\[0-9\]+\\(D\\), 8\\);\\s*_\[0-9\]+ = \\(double\\) \\1;" "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump-not " \\* 1.28e\\+2" "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump-not " \\* 2.56e\\+2" "scalbn_transform" } } */ +/* { dg-final { cleanup-tree-dump "*" } } */ diff --git a/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-2.c b/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-2.c new file mode 100644 index 0000000..480cf23 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-2.c @@ -0,0 +1,14 @@ +/* Verify scalbn transform pass for negative number case. */ + +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-all" } */ +/* { dg-require-effective-target nds32_soft_fp } */ + +double test_neg_scalbn (double x) +{ + return x * -8; +} + +/* { dg-final { scan-tree-dump "(_\[0-9\]+) = __builtin_scalbn \\(x_\[0-9\]+\\(D\\), 3\\);\\s*_\[0-9\]+ = -\\1;" "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump-not " \\* -8.0e\\+0" "scalbn_transform" } } */ +/* { dg-final { cleanup-tree-dump "*" } } */ diff --git a/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-3.c b/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-3.c new file mode 100644 index 0000000..256f31a --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-3.c @@ -0,0 +1,14 @@ +/* Verify scalbn transform pass for negative-exponent case. */ + +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-all" } */ +/* { dg-require-effective-target nds32_soft_fp } */ + +double test_neg_exp_scalbnf (double x) +{ + return x * 0.0625; +} + +/* { dg-final { scan-tree-dump "(_\[0-9\]+) = __builtin_scalbn \\(x_\[0-9\]+\\(D\\), -4\\);\\s*_\[0-9\]+ = \\(double\\) \\1;" "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump-not " \\* 6.25e\\-2" "scalbn_transform" } } */ +/* { dg-final { cleanup-tree-dump "*" } } */ diff --git a/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-4.c b/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-4.c new file mode 100644 index 0000000..b6ba596 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-4.c @@ -0,0 +1,52 @@ +/* Verify scalbn transform pass for cases that can't be optimized. */ + +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-all" } */ +/* { dg-require-effective-target nds32_soft_fp } */ + +#include "math.h" + +double test_filter_condition_1 (double x) +{ + return x * 0; +} + +double test_filter_condition_2 (double x) +{ + return x * -0; +} + +double test_filter_condition_3 (double x) +{ + return x * 485; +} + +double test_filter_condition_4 (double x) +{ + return x * -85; +} + +double test_filter_condition_5 (double x) +{ + return x * 0.12; +} + +double test_filter_condition_6 (double x) +{ + return x * -INFINITY; +} + +double test_filter_condition_7 (double x) +{ + return x * NAN; +} + +/* { dg-final { scan-tree-dump-times "x_\[0-9\]+\\(D\\) \\* 0.0" 2 "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump " \\* 4.85e\\+2" "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump " \\* -8.5e\\+1" "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump " \\* 1.19999" "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump " \\* -Inf" "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump " \\* Nan" "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump-not "__builtin_scalbn" "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump-times "No multiplication stmt is transformed" 7 "scalbn_transform" } } */ +/* { dg-final { cleanup-tree-dump "*" } } */ diff --git a/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-5.c b/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-5.c new file mode 100644 index 0000000..874170e --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/compile/scalbn-transform-5.c @@ -0,0 +1,20 @@ +/* Verify scalbn transform pass for bug 11424 case. */ + +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-all" } */ +/* { dg-require-effective-target nds32_soft_fp } */ + +typedef float float32_t; +float32_t test_case (float32_t *pIn) +{ + float32_t in; + in = *pIn++; + in = (in * 128); + in += in > 0.0f ? 0.5f : -0.5f; + + return in; +} + +/* { dg-final { scan-tree-dump "(_\[0-9\]+) = __builtin_scalbnf \\(in_\[0-9\]+, 7\\);\\s*in_\[0-9\]+ = \\(float32_t\\) \\1;" "scalbn_transform" } } */ +/* { dg-final { scan-tree-dump-not "in_\[0-9\]+ = in_\[0-9\]+ \\* 1.28e\\+2" "scalbn_transform" } } */ +/* { dg-final { cleanup-tree-dump "*" } } */ diff --git a/gcc/testsuite/gcc.target/nds32/dsp-v2hi-packing00.c b/gcc/testsuite/gcc.target/nds32/dsp-v2hi-packing00.c new file mode 100644 index 0000000..d1c61b7 --- /dev/null +++ b/gcc/testsuite/gcc.target/nds32/dsp-v2hi-packing00.c @@ -0,0 +1,127 @@ +/* { dg-do run } */ + +#include + +int16x2_t packing01(int16x2_t x, int16x2_t y) __attribute__ ((noinline)); +int16x2_t packing01(int16x2_t x, int16x2_t y) +{ + int16x2_t ret; + ret[0] = x[0]; + ret[1] = y[1]; + return ret; +} + +int16x2_t packing10(int16x2_t x, int16x2_t y) __attribute__ ((noinline)); +int16x2_t packing10(int16x2_t x, int16x2_t y) +{ + int16x2_t ret; + ret[0] = x[1]; + ret[1] = y[0]; + return ret; +} + +int16x2_t packing00(int16x2_t x, int16x2_t y) __attribute__ ((noinline)); +int16x2_t packing00(int16x2_t x, int16x2_t y) +{ + int16x2_t ret; + ret[0] = x[0]; + ret[1] = y[0]; + return ret; +} + +int16x2_t packing0cv0(int16x2_t x) __attribute__ ((noinline)); +int16x2_t packing0cv0(int16x2_t x) +{ + int16x2_t ret = {0, 0}; + ret[0] = x[0]; + return ret; +} + +int16x2_t packingcv00(int16x2_t x) __attribute__ ((noinline)); +int16x2_t packingcv00(int16x2_t x) +{ + int16x2_t ret = {0, 0}; + ret[1] = x[0]; + return ret; +} + +int16x2_t packing11(int16x2_t x, int16x2_t y) __attribute__ ((noinline)); +int16x2_t packing11(int16x2_t x, int16x2_t y) +{ + int16x2_t ret; + ret[0] = x[1]; + ret[1] = y[1]; + return ret; +} +int16x2_t packing1cv0(int16x2_t x) __attribute__ ((noinline)); +int16x2_t packing1cv0(int16x2_t x) +{ + int16x2_t ret = {0, 0}; + ret[0] = x[1]; + return ret; +} + +int16x2_t packingcv01(int16x2_t x) __attribute__ ((noinline)); +int16x2_t packingcv01(int16x2_t x) +{ + int16x2_t ret = {0, 0}; + ret[1] = x[1]; + return ret; +} + +int main() { + int16x2_t a = {0x11, 0x22}; + int16x2_t b = {0x33, 0x44}; + + int16x2_t ret00, ret01, ret10, ret11; + int16x2_t ret0cv0, retcv00, ret1cv0, retcv01; + ret00 = packing00 (a, b); + + if (ret00[0] != 0x11 + || ret00[1] != 0x33) + return 1; + + ret0cv0 = packing0cv0 (a); + + if (ret0cv0[0] != 0x11 + || ret0cv0[1] != 0) + return 1; + + retcv00 = packingcv00 (a); + + if (retcv00[0] != 0 + || retcv00[1] != 0x11) + return 1; + + ret11 = packing11 (a, b); + + if (ret11[0] != 0x22 + || ret11[1] != 0x44) + return 1; + + ret1cv0 = packing1cv0 (a); + + if (ret1cv0[0] != 0x22 + || ret1cv0[1] != 0) + return 1; + + retcv01 = packingcv01 (a); + + if (retcv01[0] != 0 + || retcv01[1] != 0x22) + return 1; + + ret01 = packing01 (a, b); + + if (ret01[0] != 0x11 + || ret01[1] != 0x44) + return 1; + + ret10 = packing10 (a, b); + + if (ret10[0] != 0x22 + || ret10[1] != 0x33) + return 1; + + return 0; +} diff --git a/gcc/testsuite/gcc.target/nds32/nds32.exp b/gcc/testsuite/gcc.target/nds32/nds32.exp index 1c245f6..2f5a150 100644 --- a/gcc/testsuite/gcc.target/nds32/nds32.exp +++ b/gcc/testsuite/gcc.target/nds32/nds32.exp @@ -38,8 +38,10 @@ if ![info exists DEFAULT_CFLAGS] then { dg-init # Main loop. -dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \ +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/compile/*.\[cS\]]] \ "" $DEFAULT_CFLAGS +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \ + "" "" # All done. dg-finish diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 6142ed9..45a6c17 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -487,6 +487,10 @@ proc check_effective_target_trampolines { } { || [istarget hppa64-hp-hpux11.23] } { return 0; } + if { [istarget nds32*-*-*] + && [check_effective_target_nds32_reduced_regs] } { + return 0; + } return 1 } @@ -500,7 +504,7 @@ proc check_effective_target_keeps_null_pointer_checks { } { if [target_info exists keeps_null_pointer_checks] { return 1 } - if { [istarget avr-*-*] } { + if { [istarget avr-*-*] || [istarget nds32*-*-elf] } { return 1; } return 0 @@ -3605,6 +3609,125 @@ proc check_effective_target_arm_prefer_ldrd_strd { } { } "-O2 -mthumb" ] } +# If board info says it only has 16M addressing space, return 0. +# Otherwise, return 1. +proc check_effective_target_nds32_full_addr_space { } { + if [board_info target exists addr16m] { + return 0 + } + return 1; +} + +# Return 1 if gp direct is enable by default. +proc check_effective_target_nds32_gp_direct { } { + return [check_no_compiler_messages gp_direct object { + #ifdef __NDS32_GP_DIRECT__ + int dummy; + #else + #error no GP_DIRECT + #endif + }] +} + +# Return 1 if this is a nds32 target supporting -mext-perf. +proc check_effective_target_nds32_ext_perf { } { + return [check_no_compiler_messages ext_perf object { + #ifdef __NDS32_EXT_PERF__ + int dummy; + #else + #error no EXT_PERF + #endif + }] +} + +# Return 1 if this is a nds32 target supporting -mext-perf2. +proc check_effective_target_nds32_ext_perf2 { } { + return [check_no_compiler_messages ext_perf2 object { + #ifdef __NDS32_EXT_PERF2__ + int dummy; + #else + #error no EXT_PERF2 + #endif + }] +} + +# Return 1 if this is a nds32 target supporting -mext-string. +proc check_effective_target_nds32_ext_string { } { + return [check_no_compiler_messages ext_string object { + #ifdef __NDS32_EXT_STRING__ + int dummy; + #else + #error no EXT_STRING + #endif + }] +} + +# Return 1 if this is a nds32 target supporting -mext-fpu-sp or -mext-fpu-dp. +proc check_effective_target_nds32_ext_fpu { } { + return [check_no_compiler_messages ext_fpu object { + #if defined(__NDS32_EXT_FPU_SP__) || defined(__NDS32_EXT_FPU_DP__) + int dummy; + #else + #error no support FPU + #endif + }] +} + +# Return 1 if this is a nds32 target not supporting -mext-fpu-sp or -mext-fpu-dp. +proc check_effective_target_nds32_soft_fp { } { + return [check_no_compiler_messages soft_fp object { + #if defined(__NDS32_EXT_FPU_SP__) || defined(__NDS32_EXT_FPU_DP__) + #error Hard FP + #else + int dummy; + #endif + }] +} + +# Return 1 if this is a nds32 target supporting -mext-fpu-sp. +proc check_effective_target_nds32_ext_fpu_sp { } { + return [check_no_compiler_messages ext_fpu_sp object { + #ifdef __NDS32_EXT_FPU_SP__ + int dummy; + #else + #error no EXT_FPU_SP + #endif + }] +} + +# Return 1 if this is a nds32 target supporting -mext-fpu-dp. +proc check_effective_target_nds32_ext_fpu_dp { } { + return [check_no_compiler_messages ext_fpu_dp object { + #ifdef __NDS32_EXT_FPU_DP__ + int dummy; + #else + #error no EXT_FPU_DP + #endif + }] +} + +# Return 1 if this is a nds32 target supporting -mreduced-regs. +proc check_effective_target_nds32_reduced_regs { } { + return [check_no_compiler_messages reduced_regs object { + #ifdef __NDS32_REDUCED_REGS__ + int dummy; + #else + #error no REDUCED_REGS + #endif + }] +} + +# Return 1 if this is a nds32 target not supporting v3m ISA. +proc check_effective_target_nds32_no_v3m { } { + return [check_no_compiler_messages no_v3m object { + #if !defined(__NDS32_BASELINE_V3M__) + int dummy; + #else + #error Support V3M ISA + #endif + }] +} + # Return 1 if this is a PowerPC target supporting -meabi. proc check_effective_target_powerpc_eabi_ok { } { @@ -6905,6 +7028,7 @@ proc check_effective_target_logical_op_short_circuit {} { || [istarget avr*-*-*] || [istarget crisv32-*-*] || [istarget cris-*-*] || [istarget mmix-*-*] + || [istarget nds32*-*-*] || [istarget s390*-*-*] || [istarget powerpc*-*-*] || [istarget nios2*-*-*] diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index f37b21c..d7afbee 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -9560,6 +9560,7 @@ simplify_cond_using_ranges (gcond *stmt) used for the comparison directly if we just massage the constant in the comparison. */ if (TREE_CODE (op0) == SSA_NAME + && has_single_use (op0) && TREE_CODE (op1) == INTEGER_CST) { gimple *def_stmt = SSA_NAME_DEF_STMT (op0); diff --git a/libgcc/config.host b/libgcc/config.host index 2b139b8..b711e37 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -951,6 +951,23 @@ msp430*-*-elf) tmake_file="$tm_file t-crtstuff t-fdpbit msp430/t-msp430" extra_parts="$extra_parts libmul_none.a libmul_16.a libmul_32.a libmul_f5.a" ;; +nds32*-linux*) + # Basic makefile fragment and extra_parts for crt stuff. + # We also append c-isr library implementation. + tmake_file="${tmake_file} t-slibgcc-libgcc" + tmake_file="${tmake_file} nds32/t-nds32-glibc nds32/t-crtstuff t-softfp-sfdf t-softfp" + # The header file of defining MD_FALLBACK_FRAME_STATE_FOR. + md_unwind_header=nds32/linux-unwind.h + # Append library definition makefile fragment according to --with-nds32-lib=X setting. + case "${with_nds32_lib}" in + "" | glibc | uclibc ) + ;; + *) + echo "Cannot accept --with-nds32-lib=$with_nds32_lib, available values are: glibc uclibc" 1>&2 + exit 1 + ;; + esac + ;; nds32*-elf*) # Basic makefile fragment and extra_parts for crt stuff. # We also append c-isr library implementation. @@ -964,9 +981,19 @@ nds32*-elf*) tmake_file="${tmake_file} nds32/t-nds32-newlib t-softfp-sfdf t-softfp" ;; mculib) - # Append library definition makefile fragment t-nds32-mculib. + case "${with_arch}" in + "" | v2 | v2j | v3 | v3j | v3m) + # Append library definition makefile fragment t-nds32-mculib-generic. # The software floating point library is included in mculib. - tmake_file="${tmake_file} nds32/t-nds32-mculib" + tmake_file="${tmake_file} nds32/t-nds32-mculib-generic" + ;; + v3f | v3s) + # Append library definition makefile fragment t-nds32-mculib-softfp. + # Append mculib do not support ABI2FP_PLUS, + # so using'soft-fp' software floating point make rule fragment provided by gcc. + tmake_file="${tmake_file} nds32/t-nds32-mculib-softfp t-softfp-sfdf t-softfp" + ;; + esac ;; *) echo "Cannot accept --with-nds32-lib=$with_nds32_lib, available values are: newlib mculib" 1>&2 diff --git a/libgcc/config/nds32/crtzero.S b/libgcc/config/nds32/crtzero.S deleted file mode 100644 index 9898525..0000000 --- a/libgcc/config/nds32/crtzero.S +++ /dev/null @@ -1,103 +0,0 @@ -/* The startup code sample 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -!!============================================================================== -!! -!! crtzero.S -!! -!! This is JUST A SAMPLE of nds32 startup code !! -!! You can refer this content and implement -!! the actual one in newlib/mculib. -!! -!!============================================================================== - -!!------------------------------------------------------------------------------ -!! Jump to start up code -!!------------------------------------------------------------------------------ - .section .nds32_init, "ax" - j _start - -!!------------------------------------------------------------------------------ -!! Startup code implementation -!!------------------------------------------------------------------------------ - .section .text - .global _start - .weak _SDA_BASE_ - .weak _FP_BASE_ - .align 2 - .func _start - .type _start, @function -_start: -.L_fp_gp_lp_init: - la $fp, _FP_BASE_ ! init $fp - la $gp, _SDA_BASE_ ! init $gp for small data access - movi $lp, 0 ! init $lp - -.L_stack_init: - la $sp, _stack ! init $sp - movi $r0, -8 ! align $sp to 8-byte (use 0xfffffff8) - and $sp, $sp, $r0 ! align $sp to 8-byte (filter out lower 3-bit) - -.L_bss_init: - ! clear BSS, this process can be 4 time faster if data is 4 byte aligned - ! if so, use swi.p instead of sbi.p - ! the related stuff are defined in linker script - la $r0, _edata ! get the starting addr of bss - la $r2, _end ! get ending addr of bss - beq $r0, $r2, .L_call_main ! if no bss just do nothing - movi $r1, 0 ! should be cleared to 0 -.L_clear_bss: - sbi.p $r1, [$r0], 1 ! Set 0 to bss - bne $r0, $r2, .L_clear_bss ! Still bytes left to set - -!.L_stack_heap_check: -! la $r0, _end ! init heap_end -! s.w $r0, heap_end ! save it - - -!.L_init_argc_argv: -! ! argc/argv initialization if necessary; default implementation is in crt1.o -! la $r9, _arg_init ! load address of _arg_init? -! beqz $r9, .L4 ! has _arg_init? no, go check main() -! addi $sp, $sp, -512 ! allocate space for command line + arguments -! move $r6, $sp ! r6 = buffer addr of cmd line -! move $r0, $r6 ! r0 = buffer addr of cmd line -! syscall 6002 ! get cmd line -! move $r0, $r6 ! r0 = buffer addr of cmd line -! addi $r1, $r6, 256 ! r1 = argv -! jral $r9 ! init argc/argv -! addi $r1, $r6, 256 ! r1 = argv - -.L_call_main: - ! call main() if main() is provided - la $r15, main ! load address of main - jral $r15 ! call main - -.L_terminate_program: - syscall 0x1 ! use syscall 0x1 to terminate program - .size _start, .-_start - .end - -!! ------------------------------------------------------------------------ diff --git a/libgcc/config/nds32/initfini.c b/libgcc/config/nds32/initfini.c index 0aa33f5..34406f0 100644 --- a/libgcc/config/nds32/initfini.c +++ b/libgcc/config/nds32/initfini.c @@ -25,6 +25,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ +#include +/* Need header file for `struct object' type. */ +#include "../libgcc/unwind-dw2-fde.h" + /* Declare a pointer to void function type. */ typedef void (*func_ptr) (void); @@ -42,11 +46,59 @@ typedef void (*func_ptr) (void); refer to only the __CTOR_END__ symbol in crtfini.o and the __DTOR_LIST__ symbol in crtinit.o, where they are defined. */ -static func_ptr __CTOR_LIST__[1] __attribute__ ((section (".ctors"))) - = { (func_ptr) (-1) }; +static func_ptr __CTOR_LIST__[1] __attribute__ ((section (".ctors"), used)) + = { (func_ptr) 0 }; + +static func_ptr __DTOR_LIST__[1] __attribute__ ((section (".dtors"), used)) + = { (func_ptr) 0 }; + + +#ifdef SUPPORT_UNWINDING_DWARF2 +/* Preparation of exception handling with dwar2 mechanism registration. */ -static func_ptr __DTOR_LIST__[1] __attribute__ ((section (".dtors"))) - = { (func_ptr) (-1) }; +asm ("\n\ + .section .eh_frame,\"aw\",@progbits\n\ + .global __EH_FRAME_BEGIN__\n\ + .type __EH_FRAME_BEGIN__, @object\n\ + .align 2\n\ +__EH_FRAME_BEGIN__:\n\ + ! Beginning location of eh_frame section\n\ + .previous\n\ +"); + +extern func_ptr __EH_FRAME_BEGIN__[]; + + +/* Note that the following two functions are going to be chained into + constructor and destructor list, repectively. So these two declarations + must be placed after __CTOR_LIST__ and __DTOR_LIST. */ +extern void __nds32_register_eh(void) __attribute__((constructor, used)); +extern void __nds32_deregister_eh(void) __attribute__((destructor, used)); + +/* Register the exception handling table as the first constructor. */ +void +__nds32_register_eh (void) +{ + static struct object object; + if (__register_frame_info) + __register_frame_info (__EH_FRAME_BEGIN__, &object); +} + +/* Unregister the exception handling table as a deconstructor. */ +void +__nds32_deregister_eh (void) +{ + static int completed = 0; + + if (completed) + return; + + if (__deregister_frame_info) + __deregister_frame_info (__EH_FRAME_BEGIN__); + + completed = 1; +} +#endif /* Run all the global destructors on exit from the program. */ @@ -63,7 +115,7 @@ static func_ptr __DTOR_LIST__[1] __attribute__ ((section (".dtors"))) same particular root executable or shared library file. */ static void __do_global_dtors (void) -asm ("__do_global_dtors") __attribute__ ((section (".text"))); +asm ("__do_global_dtors") __attribute__ ((section (".text"), used)); static void __do_global_dtors (void) @@ -116,23 +168,37 @@ void *__dso_handle = 0; last, these words naturally end up at the very ends of the two lists contained in these two sections. */ -static func_ptr __CTOR_END__[1] __attribute__ ((section (".ctors"))) +static func_ptr __CTOR_END__[1] __attribute__ ((section (".ctors"), used)) = { (func_ptr) 0 }; -static func_ptr __DTOR_END__[1] __attribute__ ((section (".dtors"))) +static func_ptr __DTOR_END__[1] __attribute__ ((section (".dtors"), used)) = { (func_ptr) 0 }; +#ifdef SUPPORT_UNWINDING_DWARF2 +/* ZERO terminator in .eh_frame section. */ +asm ("\n\ + .section .eh_frame,\"aw\",@progbits\n\ + .global __EH_FRAME_END__\n\ + .type __EH_FRAME_END__, @object\n\ + .align 2\n\ +__EH_FRAME_END__:\n\ + ! End location of eh_frame section with ZERO terminator\n\ + .word 0\n\ + .previous\n\ +"); +#endif + /* Run all global constructors for the program. Note that they are run in reverse order. */ static void __do_global_ctors (void) -asm ("__do_global_ctors") __attribute__ ((section (".text"))); +asm ("__do_global_ctors") __attribute__ ((section (".text"), used)); static void __do_global_ctors (void) { func_ptr *p; - for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--) + for (p = __CTOR_END__ - 1; *p; p--) (*p) (); } diff --git a/libgcc/config/nds32/isr-library/adj_intr_lvl.inc b/libgcc/config/nds32/isr-library/adj_intr_lvl.inc index 3e978b4..a519df8 100644 --- a/libgcc/config/nds32/isr-library/adj_intr_lvl.inc +++ b/libgcc/config/nds32/isr-library/adj_intr_lvl.inc @@ -26,13 +26,26 @@ .macro ADJ_INTR_LVL #if defined(NDS32_NESTED) /* Nested handler. */ mfsr $r3, $PSW + /* By substracting 1 from $PSW, we can lower PSW.INTL + and enable GIE simultaneously. */ addi $r3, $r3, #-0x1 + #if __NDS32_EXT_ZOL__ || __NDS32_EXT_DSP__ + ori $r3, $r3, 0x2000 /* Set PSW.AEN(b'13) */ + #endif mtsr $r3, $PSW #elif defined(NDS32_NESTED_READY) /* Nested ready handler. */ /* Save ipc and ipsw and lower INT level. */ mfsr $r3, $PSW addi $r3, $r3, #-0x2 + #if __NDS32_EXT_ZOL__ || __NDS32_EXT_DSP__ + ori $r3, $r3, 0x2000 /* Set PSW.AEN(b'13) */ + #endif mtsr $r3, $PSW #else /* Not nested handler. */ + #if __NDS32_EXT_ZOL__ || __NDS32_EXT_DSP__ + mfsr $r3, $PSW + ori $r3, $r3, 0x2000 /* Set PSW.AEN(b'13) */ + mtsr $r3, $PSW + #endif #endif .endm diff --git a/libgcc/config/nds32/isr-library/excp_isr.S b/libgcc/config/nds32/isr-library/excp_isr.S index 6179a98..f1a3b59 100644 --- a/libgcc/config/nds32/isr-library/excp_isr.S +++ b/libgcc/config/nds32/isr-library/excp_isr.S @@ -23,6 +23,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ +#include "save_usr_regs.inc" #include "save_mac_regs.inc" #include "save_fpu_regs.inc" #include "save_fpu_regs_00.inc" @@ -32,35 +33,33 @@ #include "save_all.inc" #include "save_partial.inc" #include "adj_intr_lvl.inc" -#include "restore_mac_regs.inc" #include "restore_fpu_regs_00.inc" #include "restore_fpu_regs_01.inc" #include "restore_fpu_regs_02.inc" #include "restore_fpu_regs_03.inc" #include "restore_fpu_regs.inc" +#include "restore_mac_regs.inc" +#include "restore_usr_regs.inc" #include "restore_all.inc" #include "restore_partial.inc" + .section .nds32_isr, "ax" /* Put it in the section of 1st level handler. */ .align 1 -/* - First Level Handlers - 1. First Level Handlers are invokded in vector section via jump instruction - with specific names for different configurations. - 2. Naming Format: _nds32_e_SR_NT for exception handlers. - _nds32_i_SR_NT for interrupt handlers. - 2.1 All upper case letters are replaced with specific lower case letters encodings. - 2.2 SR: Saved Registers - sa: Save All regs (context) - ps: Partial Save (all caller-saved regs) - 2.3 NT: Nested Type - ns: nested - nn: not nested - nr: nested ready -*/ - -/* - This is original 16-byte vector size version. -*/ + +/* First Level Handlers + 1. First Level Handlers are invokded in vector section via jump instruction + with specific names for different configurations. + 2. Naming Format: _nds32_e_SR_NT for exception handlers. + _nds32_i_SR_NT for interrupt handlers. + 2.1 All upper case letters are replaced with specific lower case letters encodings. + 2.2 SR -- Saved Registers + sa: Save All regs (context) + ps: Partial Save (all caller-saved regs) + 2.3 NT -- Nested Type + ns: nested + nn: not nested + nr: nested ready */ + #ifdef NDS32_SAVE_ALL_REGS #if defined(NDS32_NESTED) .globl _nds32_e_sa_ns @@ -91,21 +90,26 @@ _nds32_e_ps_nn: #endif /* endif for Nest Type */ #endif /* not NDS32_SAVE_ALL_REGS */ -/* - This is 16-byte vector size version. - The vector id was restored into $r0 in vector by compiler. -*/ + +/* For 4-byte vector size version, the vector id is + extracted from $ITYPE and is set into $r0 by library. + For 16-byte vector size version, the vector id + is set into $r0 in vector section by compiler. */ + +/* Save used registers. */ #ifdef NDS32_SAVE_ALL_REGS SAVE_ALL #else SAVE_PARTIAL #endif + /* Prepare to call 2nd level handler. */ la $r2, _nds32_jmptbl_00 lw $r2, [$r2 + $r0 << #2] ADJ_INTR_LVL /* Adjust INTR level. $r3 is clobbered. */ jral $r2 - /* Restore used registers. */ + +/* Restore used registers. */ #ifdef NDS32_SAVE_ALL_REGS RESTORE_ALL #else @@ -113,6 +117,7 @@ _nds32_e_ps_nn: #endif iret + #ifdef NDS32_SAVE_ALL_REGS #if defined(NDS32_NESTED) .size _nds32_e_sa_ns, .-_nds32_e_sa_ns diff --git a/libgcc/config/nds32/isr-library/excp_isr_4b.S b/libgcc/config/nds32/isr-library/excp_isr_4b.S deleted file mode 100644 index af70c7a..0000000 --- a/libgcc/config/nds32/isr-library/excp_isr_4b.S +++ /dev/null @@ -1,133 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -#include "save_mac_regs.inc" -#include "save_fpu_regs.inc" -#include "save_fpu_regs_00.inc" -#include "save_fpu_regs_01.inc" -#include "save_fpu_regs_02.inc" -#include "save_fpu_regs_03.inc" -#include "save_all.inc" -#include "save_partial.inc" -#include "adj_intr_lvl.inc" -#include "restore_mac_regs.inc" -#include "restore_fpu_regs_00.inc" -#include "restore_fpu_regs_01.inc" -#include "restore_fpu_regs_02.inc" -#include "restore_fpu_regs_03.inc" -#include "restore_fpu_regs.inc" -#include "restore_all.inc" -#include "restore_partial.inc" - .section .nds32_isr, "ax" /* Put it in the section of 1st level handler. */ - .align 1 -/* - First Level Handlers - 1. First Level Handlers are invokded in vector section via jump instruction - with specific names for different configurations. - 2. Naming Format: _nds32_e_SR_NT for exception handlers. - _nds32_i_SR_NT for interrupt handlers. - 2.1 All upper case letters are replaced with specific lower case letters encodings. - 2.2 SR: Saved Registers - sa: Save All regs (context) - ps: Partial Save (all caller-saved regs) - 2.3 NT: Nested Type - ns: nested - nn: not nested - nr: nested ready -*/ - -/* - This is 4-byte vector size version. - The "_4b" postfix was added for 4-byte version symbol. -*/ -#ifdef NDS32_SAVE_ALL_REGS -#if defined(NDS32_NESTED) - .globl _nds32_e_sa_ns_4b - .type _nds32_e_sa_ns_4b, @function -_nds32_e_sa_ns_4b: -#elif defined(NDS32_NESTED_READY) - .globl _nds32_e_sa_nr_4b - .type _nds32_e_sa_nr_4b, @function -_nds32_e_sa_nr_4b: -#else /* Not nested handler. */ - .globl _nds32_e_sa_nn_4b - .type _nds32_e_sa_nn_4b, @function -_nds32_e_sa_nn_4b: -#endif /* endif for Nest Type */ -#else /* not NDS32_SAVE_ALL_REGS */ -#if defined(NDS32_NESTED) - .globl _nds32_e_ps_ns_4b - .type _nds32_e_ps_ns_4b, @function -_nds32_e_ps_ns_4b: -#elif defined(NDS32_NESTED_READY) - .globl _nds32_e_ps_nr_4b - .type _nds32_e_ps_nr_4b, @function -_nds32_e_ps_nr_4b: -#else /* Not nested handler. */ - .globl _nds32_e_ps_nn_4b - .type _nds32_e_ps_nn_4b, @function -_nds32_e_ps_nn_4b: -#endif /* endif for Nest Type */ -#endif /* not NDS32_SAVE_ALL_REGS */ - -/* - This is 4-byte vector size version. - The vector id was restored into $lp in vector by compiler. -*/ -#ifdef NDS32_SAVE_ALL_REGS - SAVE_ALL_4B -#else - SAVE_PARTIAL_4B -#endif - /* Prepare to call 2nd level handler. */ - la $r2, _nds32_jmptbl_00 - lw $r2, [$r2 + $r0 << #2] - ADJ_INTR_LVL /* Adjust INTR level. $r3 is clobbered. */ - jral $r2 - /* Restore used registers. */ -#ifdef NDS32_SAVE_ALL_REGS - RESTORE_ALL -#else - RESTORE_PARTIAL -#endif - iret - -#ifdef NDS32_SAVE_ALL_REGS -#if defined(NDS32_NESTED) - .size _nds32_e_sa_ns_4b, .-_nds32_e_sa_ns_4b -#elif defined(NDS32_NESTED_READY) - .size _nds32_e_sa_nr_4b, .-_nds32_e_sa_nr_4b -#else /* Not nested handler. */ - .size _nds32_e_sa_nn_4b, .-_nds32_e_sa_nn_4b -#endif /* endif for Nest Type */ -#else /* not NDS32_SAVE_ALL_REGS */ -#if defined(NDS32_NESTED) - .size _nds32_e_ps_ns_4b, .-_nds32_e_ps_ns_4b -#elif defined(NDS32_NESTED_READY) - .size _nds32_e_ps_nr_4b, .-_nds32_e_ps_nr_4b -#else /* Not nested handler. */ - .size _nds32_e_ps_nn_4b, .-_nds32_e_ps_nn_4b -#endif /* endif for Nest Type */ -#endif /* not NDS32_SAVE_ALL_REGS */ diff --git a/libgcc/config/nds32/isr-library/intr_isr.S b/libgcc/config/nds32/isr-library/intr_isr.S index c55da1c..90c5c25 100644 --- a/libgcc/config/nds32/isr-library/intr_isr.S +++ b/libgcc/config/nds32/isr-library/intr_isr.S @@ -23,6 +23,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ +#include "save_usr_regs.inc" #include "save_mac_regs.inc" #include "save_fpu_regs.inc" #include "save_fpu_regs_00.inc" @@ -32,35 +33,33 @@ #include "save_all.inc" #include "save_partial.inc" #include "adj_intr_lvl.inc" -#include "restore_mac_regs.inc" #include "restore_fpu_regs_00.inc" #include "restore_fpu_regs_01.inc" #include "restore_fpu_regs_02.inc" #include "restore_fpu_regs_03.inc" #include "restore_fpu_regs.inc" +#include "restore_mac_regs.inc" +#include "restore_usr_regs.inc" #include "restore_all.inc" #include "restore_partial.inc" + .section .nds32_isr, "ax" /* Put it in the section of 1st level handler. */ .align 1 -/* - First Level Handlers - 1. First Level Handlers are invokded in vector section via jump instruction - with specific names for different configurations. - 2. Naming Format: _nds32_e_SR_NT for exception handlers. - _nds32_i_SR_NT for interrupt handlers. - 2.1 All upper case letters are replaced with specific lower case letters encodings. - 2.2 SR: Saved Registers - sa: Save All regs (context) - ps: Partial Save (all caller-saved regs) - 2.3 NT: Nested Type - ns: nested - nn: not nested - nr: nested ready -*/ - -/* - This is original 16-byte vector size version. -*/ + +/* First Level Handlers + 1. First Level Handlers are invokded in vector section via jump instruction + with specific names for different configurations. + 2. Naming Format: _nds32_e_SR_NT for exception handlers. + _nds32_i_SR_NT for interrupt handlers. + 2.1 All upper case letters are replaced with specific lower case letters encodings. + 2.2 SR -- Saved Registers + sa: Save All regs (context) + ps: Partial Save (all caller-saved regs) + 2.3 NT -- Nested Type + ns: nested + nn: not nested + nr: nested ready */ + #ifdef NDS32_SAVE_ALL_REGS #if defined(NDS32_NESTED) .globl _nds32_i_sa_ns @@ -91,21 +90,36 @@ _nds32_i_ps_nn: #endif /* endif for Nest Type */ #endif /* not NDS32_SAVE_ALL_REGS */ -/* - This is 16-byte vector size version. - The vector id was restored into $r0 in vector by compiler. -*/ + +/* For 4-byte vector size version, the vector id is + extracted from $ITYPE and is set into $r0 by library. + For 16-byte vector size version, the vector id + is set into $r0 in vector section by compiler. */ + +/* Save used registers first. */ #ifdef NDS32_SAVE_ALL_REGS SAVE_ALL #else SAVE_PARTIAL #endif - /* Prepare to call 2nd level handler. */ + +/* According to vector size, we need to have different implementation. */ +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* Prepare to call 2nd level handler. */ + la $r2, _nds32_jmptbl_00 + lw $r2, [$r2 + $r0 << #2] + addi $r0, $r0, #-9 /* Make interrput vector id zero-based. */ + ADJ_INTR_LVL /* Adjust INTR level. $r3 is clobbered. */ + jral $r2 +#else /* not __NDS32_ISR_VECTOR_SIZE_4__ */ + /* Prepare to call 2nd level handler. */ la $r2, _nds32_jmptbl_09 /* For zero-based vcetor id. */ lw $r2, [$r2 + $r0 << #2] ADJ_INTR_LVL /* Adjust INTR level. $r3 is clobbered. */ jral $r2 - /* Restore used registers. */ +#endif /* not __NDS32_ISR_VECTOR_SIZE_4__ */ + +/* Restore used registers. */ #ifdef NDS32_SAVE_ALL_REGS RESTORE_ALL #else @@ -113,6 +127,7 @@ _nds32_i_ps_nn: #endif iret + #ifdef NDS32_SAVE_ALL_REGS #if defined(NDS32_NESTED) .size _nds32_i_sa_ns, .-_nds32_i_sa_ns diff --git a/libgcc/config/nds32/isr-library/intr_isr_4b.S b/libgcc/config/nds32/isr-library/intr_isr_4b.S deleted file mode 100644 index d82c007..0000000 --- a/libgcc/config/nds32/isr-library/intr_isr_4b.S +++ /dev/null @@ -1,134 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -#include "save_mac_regs.inc" -#include "save_fpu_regs.inc" -#include "save_fpu_regs_00.inc" -#include "save_fpu_regs_01.inc" -#include "save_fpu_regs_02.inc" -#include "save_fpu_regs_03.inc" -#include "save_all.inc" -#include "save_partial.inc" -#include "adj_intr_lvl.inc" -#include "restore_mac_regs.inc" -#include "restore_fpu_regs_00.inc" -#include "restore_fpu_regs_01.inc" -#include "restore_fpu_regs_02.inc" -#include "restore_fpu_regs_03.inc" -#include "restore_fpu_regs.inc" -#include "restore_all.inc" -#include "restore_partial.inc" - .section .nds32_isr, "ax" /* Put it in the section of 1st level handler. */ - .align 1 -/* - First Level Handlers - 1. First Level Handlers are invokded in vector section via jump instruction - with specific names for different configurations. - 2. Naming Format: _nds32_e_SR_NT for exception handlers. - _nds32_i_SR_NT for interrupt handlers. - 2.1 All upper case letters are replaced with specific lower case letters encodings. - 2.2 SR: Saved Registers - sa: Save All regs (context) - ps: Partial Save (all caller-saved regs) - 2.3 NT: Nested Type - ns: nested - nn: not nested - nr: nested ready -*/ - -/* - This is 4-byte vector size version. - The "_4b" postfix was added for 4-byte version symbol. -*/ -#ifdef NDS32_SAVE_ALL_REGS -#if defined(NDS32_NESTED) - .globl _nds32_i_sa_ns_4b - .type _nds32_i_sa_ns_4b, @function -_nds32_i_sa_ns_4b: -#elif defined(NDS32_NESTED_READY) - .globl _nds32_i_sa_nr_4b - .type _nds32_i_sa_nr_4b, @function -_nds32_i_sa_nr_4b: -#else /* Not nested handler. */ - .globl _nds32_i_sa_nn_4b - .type _nds32_i_sa_nn_4b, @function -_nds32_i_sa_nn_4b: -#endif /* endif for Nest Type */ -#else /* not NDS32_SAVE_ALL_REGS */ -#if defined(NDS32_NESTED) - .globl _nds32_i_ps_ns_4b - .type _nds32_i_ps_ns_4b, @function -_nds32_i_ps_ns_4b: -#elif defined(NDS32_NESTED_READY) - .globl _nds32_i_ps_nr_4b - .type _nds32_i_ps_nr_4b, @function -_nds32_i_ps_nr_4b: -#else /* Not nested handler. */ - .globl _nds32_i_ps_nn_4b - .type _nds32_i_ps_nn_4b, @function -_nds32_i_ps_nn_4b: -#endif /* endif for Nest Type */ -#endif /* not NDS32_SAVE_ALL_REGS */ - -/* - This is 4-byte vector size version. - The vector id was restored into $lp in vector by compiler. -*/ -#ifdef NDS32_SAVE_ALL_REGS - SAVE_ALL_4B -#else - SAVE_PARTIAL_4B -#endif - /* Prepare to call 2nd level handler. */ - la $r2, _nds32_jmptbl_00 - lw $r2, [$r2 + $r0 << #2] - addi $r0, $r0, #-9 /* Make interrput vector id zero-based. */ - ADJ_INTR_LVL /* Adjust INTR level. $r3 is clobbered. */ - jral $r2 - /* Restore used registers. */ -#ifdef NDS32_SAVE_ALL_REGS - RESTORE_ALL -#else - RESTORE_PARTIAL -#endif - iret - -#ifdef NDS32_SAVE_ALL_REGS -#if defined(NDS32_NESTED) - .size _nds32_i_sa_ns_4b, .-_nds32_i_sa_ns_4b -#elif defined(NDS32_NESTED_READY) - .size _nds32_i_sa_nr_4b, .-_nds32_i_sa_nr_4b -#else /* Not nested handler. */ - .size _nds32_i_sa_nn_4b, .-_nds32_i_sa_nn_4b -#endif /* endif for Nest Type */ -#else /* not NDS32_SAVE_ALL_REGS */ -#if defined(NDS32_NESTED) - .size _nds32_i_ps_ns_4b, .-_nds32_i_ps_ns_4b -#elif defined(NDS32_NESTED_READY) - .size _nds32_i_ps_nr_4b, .-_nds32_i_ps_nr_4b -#else /* Not nested handler. */ - .size _nds32_i_ps_nn_4b, .-_nds32_i_ps_nn_4b -#endif /* endif for Nest Type */ -#endif /* not NDS32_SAVE_ALL_REGS */ diff --git a/libgcc/config/nds32/isr-library/reset.S b/libgcc/config/nds32/isr-library/reset.S index 961d731..8b9ccf5 100644 --- a/libgcc/config/nds32/isr-library/reset.S +++ b/libgcc/config/nds32/isr-library/reset.S @@ -26,22 +26,18 @@ .section .nds32_isr, "ax" /* Put it in the section of 1st level handler. */ .align 1 .weak _SDA_BASE_ /* For reset handler only. */ - .weak _FP_BASE_ /* For reset handler only. */ .weak _nds32_init_mem /* User defined memory initialization function. */ .globl _start .globl _nds32_reset .type _nds32_reset, @function _nds32_reset: _start: -#ifdef NDS32_EXT_EX9 - .no_ex9_begin -#endif /* Handle NMI and warm boot if any of them exists. */ beqz $sp, 1f /* Reset, NMI or warm boot? */ /* Either NMI or warm boot; save all regs. */ /* Preserve registers for context-switching. */ -#ifdef __NDS32_REDUCED_REGS__ +#if __NDS32_REDUCED_REGS__ || __NDS32_REDUCE_REGS /* For 16-reg mode. */ smw.adm $r0, [$sp], $r10, #0x0 smw.adm $r15, [$sp], $r15, #0xf @@ -49,10 +45,9 @@ _start: /* For 32-reg mode. */ smw.adm $r0, [$sp], $r27, #0xf #endif -#ifdef NDS32_EXT_IFC +#if __NDS32_EXT_IFC__ mfusr $r1, $IFC_LP - smw.adm $r1, [$sp], $r2, #0x0 /* Save extra $r2 to keep - stack 8-byte alignment. */ + smw.adm $r1, [$sp], $r2, #0x0 /* Save extra $r2 to keep stack 8-byte alignment. */ #endif la $gp, _SDA_BASE_ /* Init GP for small data access. */ @@ -71,12 +66,11 @@ _start: bnez $r0, 1f /* If fail to resume, do cold boot. */ /* Restore registers for context-switching. */ -#ifdef NDS32_EXT_IFC - lmw.bim $r1, [$sp], $r2, #0x0 /* Restore extra $r2 to keep - stack 8-byte alignment. */ +#if __NDS32_EXT_IFC__ + lmw.bim $r1, [$sp], $r2, #0x0 /* Restore extra $r2 to keep stack 8-byte alignment. */ mtusr $r1, $IFC_LP #endif -#ifdef __NDS32_REDUCED_REGS__ +#if __NDS32_REDUCED_REGS__ || __NDS32_REDUCE_REGS /* For 16-reg mode. */ lmw.bim $r15, [$sp], $r15, #0xf lmw.bim $r0, [$sp], $r10, #0x0 @@ -88,6 +82,17 @@ _start: 1: /* Cold boot. */ +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* With vector ID feature for v3 architecture, default vector size is 4-byte. */ + /* Set IVB.ESZ = 0 (vector table entry size = 4 bytes) */ + mfsr $r0, $IVB + li $r1, #0xc000 + or $r0, $r0, $r1 + xor $r0, $r0, $r1 + mtsr $r0, $IVB + dsb +#else + /* There is no vector ID feature, so the vector size must be 16-byte. */ /* Set IVB.ESZ = 1 (vector table entry size = 16 bytes) */ mfsr $r0, $IVB li $r1, #0xffff3fff @@ -95,36 +100,54 @@ _start: ori $r0, $r0, #0x4000 mtsr $r0, $IVB dsb +#endif la $gp, _SDA_BASE_ /* Init $gp. */ - la $fp, _FP_BASE_ /* Init $fp. */ la $sp, _stack /* Init $sp. */ -#ifdef NDS32_EXT_EX9 -/* - * Initialize the table base of EX9 instruction - * ex9 generation needs to disable before the ITB is set - */ - mfsr $r0, $MSC_CFG /* Check if HW support of EX9. */ + +#if __NDS32_EXT_EX9__ +.L_init_itb: + /* Initialization for Instruction Table Base (ITB). + The symbol _ITB_BASE_ is determined by Linker. + Set $ITB only if MSC_CFG.EIT (cr4.b'24) is set. */ + mfsr $r0, $MSC_CFG srli $r0, $r0, 24 andi $r0, $r0, 0x1 - beqz $r0, 4f /* Zero means HW does not support EX9. */ - la $r0, _ITB_BASE_ /* Init $ITB. */ + beqz $r0, 4f /* Fall through ? */ + la $r0, _ITB_BASE_ mtusr $r0, $ITB - .no_ex9_end 4: #endif - la $r15, _nds32_init_mem /* Call DRAM init. _nds32_init_mem - may written by C language. */ + +#if __NDS32_EXT_FPU_SP__ || __NDS32_EXT_FPU_DP__ +.L_init_fpu: + /* Initialize FPU + Set FUCOP_CTL.CP0EN (fucpr.b'0). */ + mfsr $r0, $FUCOP_CTL + ori $r0, $r0, 0x1 + mtsr $r0, $FUCOP_CTL + dsb + /* According to [bugzilla #9425], set flush-to-zero mode. + That is, set $FPCSR.DNZ(b'12) = 1. */ + FMFCSR $r0 + ori $r0, $r0, 0x1000 + FMTCSR $r0 + dsb +#endif + + /* Call DRAM init. _nds32_init_mem may written by C language. */ + la $r15, _nds32_init_mem beqz $r15, 6f jral $r15 6: l.w $r15, _nds32_jmptbl_00 /* Load reset handler. */ jral $r15 -/* Reset handler() should never return in a RTOS or non-OS system. - In case it does return, an exception will be generated. - This exception will be caught either by default break handler or by EDM. - Default break handle may just do an infinite loop. - EDM will notify GDB and GDB will regain control when the ID is 0x7fff. */ + + /* Reset handler() should never return in a RTOS or non-OS system. + In case it does return, an exception will be generated. + This exception will be caught either by default break handler or by EDM. + Default break handle may just do an infinite loop. + EDM will notify GDB and GDB will regain control when the ID is 0x7fff. */ 5: break #0x7fff .size _nds32_reset, .-_nds32_reset diff --git a/libgcc/config/nds32/isr-library/reset_4b.S b/libgcc/config/nds32/isr-library/reset_4b.S deleted file mode 100644 index 792e655..0000000 --- a/libgcc/config/nds32/isr-library/reset_4b.S +++ /dev/null @@ -1,131 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_isr, "ax" /* Put it in the section of 1st level handler. */ - .align 1 - .weak _SDA_BASE_ /* For reset handler only. */ - .weak _FP_BASE_ /* For reset handler only. */ - .weak _nds32_init_mem /* User defined memory initialization function. */ - .globl _start - .globl _nds32_reset_4b - .type _nds32_reset_4b, @function -_nds32_reset_4b: -_start: -#ifdef NDS32_EXT_EX9 - .no_ex9_begin -#endif - /* Handle NMI and warm boot if any of them exists. */ - beqz $sp, 1f /* Reset, NMI or warm boot? */ - /* Either NMI or warm boot; save all regs. */ - - /* Preserve registers for context-switching. */ -#ifdef __NDS32_REDUCED_REGS__ - /* For 16-reg mode. */ - smw.adm $r0, [$sp], $r10, #0x0 - smw.adm $r15, [$sp], $r15, #0xf -#else - /* For 32-reg mode. */ - smw.adm $r0, [$sp], $r27, #0xf -#endif -#ifdef NDS32_EXT_IFC - mfusr $r1, $IFC_LP - smw.adm $r1, [$sp], $r2, #0x0 /* Save extra $r2 to keep - stack 8-byte alignment. */ -#endif - - la $gp, _SDA_BASE_ /* Init GP for small data access. */ - move $r0, $sp /* Init parameter. */ - mfsr $r1, $ITYPE /* Check ITYPE for NMI or warm boot. */ - andi $r1, $r1, #0xf - addi $r1, $r1, #-1 - beqz $r1, 2f /* Warm boot if true. */ - l.w $r15, _nds32_nmih /* Load NMI handler. */ - j 3f -2: - l.w $r15, _nds32_wrh /* Load warm boot handler. */ -3: - beqz $r15, 1f /* If no handler, do cold boot. */ - jral $r15 /* Call handler. */ - bnez $r0, 1f /* If fail to resume, do cold boot. */ - - /* Restore registers for context-switching. */ -#ifdef NDS32_EXT_IFC - lmw.bim $r1, [$sp], $r2, #0x0 /* Restore extra $r2 to keep - stack 8-byte alignment. */ - mtusr $r1, $IFC_LP -#endif -#ifdef __NDS32_REDUCED_REGS__ - /* For 16-reg mode. */ - lmw.bim $r15, [$sp], $r15, #0xf - lmw.bim $r0, [$sp], $r10, #0x0 -#else - /* For 32-reg mode. */ - lmw.bim $r0, [$sp], $r27, #0xf -#endif - iret /* Resume operation. */ - - -1: /* Cold boot. */ - /* With vector ID feature, set default vector size to 4B. */ - /* Set IVB.ESZ = 0 (vector table entry size = 4 bytes) */ - mfsr $r0, $IVB - li $r1, #0xc000 - or $r0, $r0, $r1 - xor $r0, $r0, $r1 - mtsr $r0, $IVB - dsb - - la $gp, _SDA_BASE_ /* Init $gp. */ - la $fp, _FP_BASE_ /* Init $fp. */ - la $sp, _stack /* Init $sp. */ -#ifdef NDS32_EXT_EX9 -/* - * Initialize the table base of EX9 instruction - * ex9 generation needs to disable before the ITB is set - */ - mfsr $r0, $MSC_CFG /* Check if HW support of EX9. */ - srli $r0, $r0, 24 - andi $r0, $r0, 0x1 - beqz $r0, 4f /* Zero means HW does not support EX9. */ - la $r0, _ITB_BASE_ /* Init $ITB. */ - mtusr $r0, $ITB - .no_ex9_end -4: -#endif - la $r15, _nds32_init_mem /* Call DRAM init. _nds32_init_mem - may written by C language. */ - beqz $r15, 6f - jral $r15 -6: - l.w $r15, _nds32_jmptbl_00 /* Load reset handler. */ - jral $r15 -/* Reset handler() should never return in a RTOS or non-OS system. - In case it does return, an exception will be generated. - This exception will be caught either by default break handler or by EDM. - Default break handle may just do an infinite loop. - EDM will notify GDB and GDB will regain control when the ID is 0x7fff. */ -5: - break #0x7fff - .size _nds32_reset_4b, .-_nds32_reset_4b diff --git a/libgcc/config/nds32/isr-library/restore_all.inc b/libgcc/config/nds32/isr-library/restore_all.inc index c25b46e..96f87ec 100644 --- a/libgcc/config/nds32/isr-library/restore_all.inc +++ b/libgcc/config/nds32/isr-library/restore_all.inc @@ -31,15 +31,11 @@ mtsr $r2, $IPSW RESTORE_FPU_REGS RESTORE_MAC_REGS -#ifdef NDS32_EXT_IFC - lmw.bim $r1, [$sp], $r2, #0x0 /* Restore extra $r2 to keep - stack 8-byte alignment. */ - mtusr $r1, $IFC_LP -#endif -#ifdef __NDS32_REDUCED_REGS__ + RESTORE_USR_REGS +#if __NDS32_REDUCED_REGS__ || __NDS32_REDUCE_REGS lmw.bim $r0, [$sp], $r10, #0x0 /* Restore all regs. */ lmw.bim $r15, [$sp], $r15, #0xf -#else /* not __NDS32_REDUCED_REGS__ */ +#else lmw.bim $r0, [$sp], $r27, #0xf /* Restore all regs. */ #endif .endm diff --git a/libgcc/config/nds32/isr-library/restore_mac_regs.inc b/libgcc/config/nds32/isr-library/restore_mac_regs.inc index 0ffc980..a15024c 100644 --- a/libgcc/config/nds32/isr-library/restore_mac_regs.inc +++ b/libgcc/config/nds32/isr-library/restore_mac_regs.inc @@ -24,7 +24,7 @@ . */ .macro RESTORE_MAC_REGS -#ifdef NDS32_DX_REGS +#if __NDS32_DX_REGS__ lmw.bim $r1, [$sp], $r4, #0x0 mtusr $r1, $d0.lo mtusr $r2, $d0.hi diff --git a/libgcc/config/nds32/isr-library/restore_partial.inc b/libgcc/config/nds32/isr-library/restore_partial.inc index 70d5421..c07d30e 100644 --- a/libgcc/config/nds32/isr-library/restore_partial.inc +++ b/libgcc/config/nds32/isr-library/restore_partial.inc @@ -31,15 +31,11 @@ mtsr $r1, $IPC /* Set IPC. */ mtsr $r2, $IPSW /* Set IPSW. */ #endif - RESTORE_FPU_REGS - RESTORE_MAC_REGS -#ifdef NDS32_EXT_IFC - lmw.bim $r1, [$sp], $r2, #0x0 /* Restore extra $r2 to keep - stack 8-byte alignment. */ - mtusr $r1, $IFC_LP -#endif + RESTORE_FPU_REGS + RESTORE_MAC_REGS + RESTORE_USR_REGS lmw.bim $r0, [$sp], $r5, #0x0 /* Restore all regs. */ -#ifdef __NDS32_REDUCED_REGS__ +#if __NDS32_REDUCED_REGS__ || __NDS32_REDUCE_REGS lmw.bim $r15, [$sp], $r15, #0x2 #else lmw.bim $r15, [$sp], $r27, #0x2 /* Restore all regs. */ diff --git a/libgcc/config/nds32/isr-library/vec_vid03_4b.S b/libgcc/config/nds32/isr-library/restore_usr_regs.inc similarity index 72% rename from libgcc/config/nds32/isr-library/vec_vid03_4b.S rename to libgcc/config/nds32/isr-library/restore_usr_regs.inc index cd30906..c8f6e4a 100644 --- a/libgcc/config/nds32/isr-library/vec_vid03_4b.S +++ b/libgcc/config/nds32/isr-library/restore_usr_regs.inc @@ -23,12 +23,20 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ - .section .nds32_vector.03, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_03_4b - .type _nds32_vector_03_4b, @function -_nds32_vector_03_4b: -1: - j 1b - .size _nds32_vector_03_4b, .-_nds32_vector_03_4b +.macro RESTORE_USR_REGS +#if __NDS32_EXT_IFC__ && (__NDS32_EXT_ZOL__ || __NDS32_EXT_DSP__) + lmw.bim $r1, [$sp], $r4, #0x0 + mtusr $r1, $IFC_LP + mtusr $r2, $LB + mtusr $r3, $LE + mtusr $r4, $LC +#elif __NDS32_EXT_IFC__ + lmw.bim $r1, [$sp], $r2, #0x0 + mtusr $r1, $IFC_LP +#elif __NDS32_EXT_ZOL__ || __NDS32_EXT_DSP__ + lmw.bim $r1, [$sp], $r4, #0x0 + mtusr $r1, $LB + mtusr $r2, $LE + mtusr $r3, $LC +#endif +.endm diff --git a/libgcc/config/nds32/isr-library/save_all.inc b/libgcc/config/nds32/isr-library/save_all.inc index 20eb29d..c926664 100644 --- a/libgcc/config/nds32/isr-library/save_all.inc +++ b/libgcc/config/nds32/isr-library/save_all.inc @@ -23,45 +23,42 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ -.macro SAVE_ALL_4B -#ifdef __NDS32_REDUCED_REGS__ +#if __NDS32_ISR_VECTOR_SIZE_4__ + +/* If vector size is 4-byte, we have to save registers + in the macro implementation. */ +.macro SAVE_ALL +#if __NDS32_REDUCED_REGS__ || __NDS32_REDUCE_REGS smw.adm $r15, [$sp], $r15, #0xf smw.adm $r0, [$sp], $r10, #0x0 -#else /* not __NDS32_REDUCED_REGS__ */ +#else smw.adm $r0, [$sp], $r27, #0xf -#endif /* not __NDS32_REDUCED_REGS__ */ -#ifdef NDS32_EXT_IFC - mfusr $r1, $IFC_LP - smw.adm $r1, [$sp], $r2, #0x0 /* Save extra $r2 to keep - stack 8-byte alignment. */ #endif - SAVE_MAC_REGS - SAVE_FPU_REGS + SAVE_USR_REGS + SAVE_MAC_REGS + SAVE_FPU_REGS mfsr $r1, $IPC /* Get IPC. */ mfsr $r2, $IPSW /* Get IPSW. */ smw.adm $r1, [$sp], $r2, #0x0 /* Push IPC, IPSW. */ move $r1, $sp /* $r1 is ptr to NDS32_CONTEXT. */ mfsr $r0, $ITYPE /* Get VID to $r0. */ srli $r0, $r0, #5 -#ifdef __NDS32_ISA_V2__ andi $r0, $r0, #127 -#else - fexti33 $r0, #6 -#endif .endm +#else /* not __NDS32_ISR_VECTOR_SIZE_4__ */ + +/* If vector size is 16-byte, some works can be done in + the vector section generated by compiler, so that we + can implement less in the macro. */ .macro SAVE_ALL -/* SAVE_REG_TBL code has been moved to - vector table generated by compiler. */ -#ifdef NDS32_EXT_IFC - mfusr $r1, $IFC_LP - smw.adm $r1, [$sp], $r2, #0x0 /* Save extra $r2 to keep - stack 8-byte alignment. */ -#endif - SAVE_MAC_REGS - SAVE_FPU_REGS + SAVE_USR_REGS + SAVE_MAC_REGS + SAVE_FPU_REGS mfsr $r1, $IPC /* Get IPC. */ mfsr $r2, $IPSW /* Get IPSW. */ smw.adm $r1, [$sp], $r2, #0x0 /* Push IPC, IPSW. */ move $r1, $sp /* $r1 is ptr to NDS32_CONTEXT. */ .endm + +#endif /* not __NDS32_ISR_VECTOR_SIZE_4__ */ diff --git a/libgcc/config/nds32/isr-library/save_mac_regs.inc b/libgcc/config/nds32/isr-library/save_mac_regs.inc index ddb5e77..2d79d70 100644 --- a/libgcc/config/nds32/isr-library/save_mac_regs.inc +++ b/libgcc/config/nds32/isr-library/save_mac_regs.inc @@ -24,7 +24,7 @@ . */ .macro SAVE_MAC_REGS -#ifdef NDS32_DX_REGS +#if __NDS32_DX_REGS__ mfusr $r1, $d0.lo mfusr $r2, $d0.hi mfusr $r3, $d1.lo diff --git a/libgcc/config/nds32/isr-library/save_partial.inc b/libgcc/config/nds32/isr-library/save_partial.inc index ee514c4..0c6d481 100644 --- a/libgcc/config/nds32/isr-library/save_partial.inc +++ b/libgcc/config/nds32/isr-library/save_partial.inc @@ -23,20 +23,20 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ -.macro SAVE_PARTIAL_4B -#ifdef __NDS32_REDUCED_REGS__ +#if __NDS32_ISR_VECTOR_SIZE_4__ + +/* If vector size is 4-byte, we have to save registers + in the macro implementation. */ +.macro SAVE_PARTIAL +#if __NDS32_REDUCED_REGS__ || __NDS32_REDUCE_REGS smw.adm $r15, [$sp], $r15, #0x2 -#else /* not __NDS32_REDUCED_REGS__ */ +#else smw.adm $r15, [$sp], $r27, #0x2 -#endif /* not __NDS32_REDUCED_REGS__ */ - smw.adm $r0, [$sp], $r5, #0x0 -#ifdef NDS32_EXT_IFC - mfusr $r1, $IFC_LP - smw.adm $r1, [$sp], $r2, #0x0 /* Save extra $r2 to keep - stack 8-byte alignment. */ #endif - SAVE_MAC_REGS - SAVE_FPU_REGS + smw.adm $r0, [$sp], $r5, #0x0 + SAVE_USR_REGS + SAVE_MAC_REGS + SAVE_FPU_REGS #if defined(NDS32_NESTED) || defined(NDS32_NESTED_READY) mfsr $r1, $IPC /* Get IPC. */ mfsr $r2, $IPSW /* Get IPSW. */ @@ -44,26 +44,24 @@ #endif mfsr $r0, $ITYPE /* Get VID to $r0. */ srli $r0, $r0, #5 -#ifdef __NDS32_ISA_V2__ andi $r0, $r0, #127 -#else - fexti33 $r0, #6 -#endif .endm +#else /* not __NDS32_ISR_VECTOR_SIZE_4__ */ + +/* If vector size is 16-byte, some works can be done in + the vector section generated by compiler, so that we + can implement less in the macro. */ + .macro SAVE_PARTIAL -/* SAVE_CALLER_REGS code has been moved to - vector table generated by compiler. */ -#ifdef NDS32_EXT_IFC - mfusr $r1, $IFC_LP - smw.adm $r1, [$sp], $r2, #0x0 /* Save extra $r2 to keep - stack 8-byte alignment. */ -#endif - SAVE_MAC_REGS - SAVE_FPU_REGS + SAVE_USR_REGS + SAVE_MAC_REGS + SAVE_FPU_REGS #if defined(NDS32_NESTED) || defined(NDS32_NESTED_READY) mfsr $r1, $IPC /* Get IPC. */ mfsr $r2, $IPSW /* Get IPSW. */ smw.adm $r1, [$sp], $r2, #0x0 /* Push IPC, IPSW. */ #endif .endm + +#endif /* not __NDS32_ISR_VECTOR_SIZE_4__ */ diff --git a/libgcc/config/nds32/isr-library/vec_vid00_4b.S b/libgcc/config/nds32/isr-library/save_usr_regs.inc similarity index 61% rename from libgcc/config/nds32/isr-library/vec_vid00_4b.S rename to libgcc/config/nds32/isr-library/save_usr_regs.inc index e1a37b4..b6807d7 100644 --- a/libgcc/config/nds32/isr-library/vec_vid00_4b.S +++ b/libgcc/config/nds32/isr-library/save_usr_regs.inc @@ -23,12 +23,22 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ - .section .nds32_vector.00, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_00_4b - .type _nds32_vector_00_4b, @function -_nds32_vector_00_4b: -1: - j 1b - .size _nds32_vector_00_4b, .-_nds32_vector_00_4b +.macro SAVE_USR_REGS +/* Store User Special Registers according to supported ISA extension + !!! WATCH OUT !!! Take care of 8-byte alignment issue. */ +#if __NDS32_EXT_IFC__ && (__NDS32_EXT_ZOL__ || __NDS32_EXT_DSP__) + mfusr $r1, $IFC_LP + mfusr $r2, $LB + mfusr $r3, $LE + mfusr $r4, $LC + smw.adm $r1, [$sp], $r4, #0x0 /* Save even. Ok! */ +#elif __NDS32_EXT_IFC__ + mfusr $r1, $IFC_LP + smw.adm $r1, [$sp], $r2, #0x0 /* Save extra $r2 to keep stack 8-byte aligned. */ +#elif (__NDS32_EXT_ZOL__ || __NDS32_EXT_DSP__) + mfusr $r1, $LB + mfusr $r2, $LE + mfusr $r3, $LC + smw.adm $r1, [$sp], $r4, #0x0 /* Save extra $r4 to keep stack 8-byte aligned. */ +#endif +.endm diff --git a/libgcc/config/nds32/isr-library/vec_vid00.S b/libgcc/config/nds32/isr-library/vec_vid00.S index ccdbd19..f02e92c 100644 --- a/libgcc/config/nds32/isr-library/vec_vid00.S +++ b/libgcc/config/nds32/isr-library/vec_vid00.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.00, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_00 .type _nds32_vector_00, @function _nds32_vector_00: diff --git a/libgcc/config/nds32/isr-library/vec_vid01.S b/libgcc/config/nds32/isr-library/vec_vid01.S index ed5a88e..542fcf8 100644 --- a/libgcc/config/nds32/isr-library/vec_vid01.S +++ b/libgcc/config/nds32/isr-library/vec_vid01.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.01, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_01 .type _nds32_vector_01, @function _nds32_vector_01: diff --git a/libgcc/config/nds32/isr-library/vec_vid01_4b.S b/libgcc/config/nds32/isr-library/vec_vid01_4b.S deleted file mode 100644 index 239bd75..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid01_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.01, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_01_4b - .type _nds32_vector_01_4b, @function -_nds32_vector_01_4b: -1: - j 1b - .size _nds32_vector_01_4b, .-_nds32_vector_01_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid02.S b/libgcc/config/nds32/isr-library/vec_vid02.S index 1a95a57..72b8b56 100644 --- a/libgcc/config/nds32/isr-library/vec_vid02.S +++ b/libgcc/config/nds32/isr-library/vec_vid02.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.02, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_02 .type _nds32_vector_02, @function _nds32_vector_02: diff --git a/libgcc/config/nds32/isr-library/vec_vid02_4b.S b/libgcc/config/nds32/isr-library/vec_vid02_4b.S deleted file mode 100644 index c532e62..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid02_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.02, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_02_4b - .type _nds32_vector_02_4b, @function -_nds32_vector_02_4b: -1: - j 1b - .size _nds32_vector_02_4b, .-_nds32_vector_02_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid03.S b/libgcc/config/nds32/isr-library/vec_vid03.S index 9bc572a..b0f8a60 100644 --- a/libgcc/config/nds32/isr-library/vec_vid03.S +++ b/libgcc/config/nds32/isr-library/vec_vid03.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.03, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_03 .type _nds32_vector_03, @function _nds32_vector_03: diff --git a/libgcc/config/nds32/isr-library/vec_vid04.S b/libgcc/config/nds32/isr-library/vec_vid04.S index e8d4e10..d76ef73 100644 --- a/libgcc/config/nds32/isr-library/vec_vid04.S +++ b/libgcc/config/nds32/isr-library/vec_vid04.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.04, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_04 .type _nds32_vector_04, @function _nds32_vector_04: diff --git a/libgcc/config/nds32/isr-library/vec_vid04_4b.S b/libgcc/config/nds32/isr-library/vec_vid04_4b.S deleted file mode 100644 index 21fc77e..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid04_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.04, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_04_4b - .type _nds32_vector_04_4b, @function -_nds32_vector_04_4b: -1: - j 1b - .size _nds32_vector_04_4b, .-_nds32_vector_04_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid05.S b/libgcc/config/nds32/isr-library/vec_vid05.S index 1621a9d..ed5a5bb 100644 --- a/libgcc/config/nds32/isr-library/vec_vid05.S +++ b/libgcc/config/nds32/isr-library/vec_vid05.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.05, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_05 .type _nds32_vector_05, @function _nds32_vector_05: diff --git a/libgcc/config/nds32/isr-library/vec_vid05_4b.S b/libgcc/config/nds32/isr-library/vec_vid05_4b.S deleted file mode 100644 index b86fe19..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid05_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.05, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_05_4b - .type _nds32_vector_05_4b, @function -_nds32_vector_05_4b: -1: - j 1b - .size _nds32_vector_05_4b, .-_nds32_vector_05_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid06.S b/libgcc/config/nds32/isr-library/vec_vid06.S index 934f0b1..834c7de 100644 --- a/libgcc/config/nds32/isr-library/vec_vid06.S +++ b/libgcc/config/nds32/isr-library/vec_vid06.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.06, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_06 .type _nds32_vector_06, @function _nds32_vector_06: diff --git a/libgcc/config/nds32/isr-library/vec_vid06_4b.S b/libgcc/config/nds32/isr-library/vec_vid06_4b.S deleted file mode 100644 index 3624cfd..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid06_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.06, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_06_4b - .type _nds32_vector_06_4b, @function -_nds32_vector_06_4b: -1: - j 1b - .size _nds32_vector_06_4b, .-_nds32_vector_06_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid07.S b/libgcc/config/nds32/isr-library/vec_vid07.S index 0b0484d..cb3b33a 100644 --- a/libgcc/config/nds32/isr-library/vec_vid07.S +++ b/libgcc/config/nds32/isr-library/vec_vid07.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.07, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_07 .type _nds32_vector_07, @function _nds32_vector_07: diff --git a/libgcc/config/nds32/isr-library/vec_vid07_4b.S b/libgcc/config/nds32/isr-library/vec_vid07_4b.S deleted file mode 100644 index 997ca75..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid07_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.07, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_07_4b - .type _nds32_vector_07_4b, @function -_nds32_vector_07_4b: -1: - j 1b - .size _nds32_vector_07_4b, .-_nds32_vector_07_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid08.S b/libgcc/config/nds32/isr-library/vec_vid08.S index 2a30375..b4ae947 100644 --- a/libgcc/config/nds32/isr-library/vec_vid08.S +++ b/libgcc/config/nds32/isr-library/vec_vid08.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.08, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_08 .type _nds32_vector_08, @function _nds32_vector_08: diff --git a/libgcc/config/nds32/isr-library/vec_vid08_4b.S b/libgcc/config/nds32/isr-library/vec_vid08_4b.S deleted file mode 100644 index 83546d1..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid08_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.08, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_08_4b - .type _nds32_vector_08_4b, @function -_nds32_vector_08_4b: -1: - j 1b - .size _nds32_vector_08_4b, .-_nds32_vector_08_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid09.S b/libgcc/config/nds32/isr-library/vec_vid09.S index 9aeaf78..47fa5c1 100644 --- a/libgcc/config/nds32/isr-library/vec_vid09.S +++ b/libgcc/config/nds32/isr-library/vec_vid09.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.09, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_09 .type _nds32_vector_09, @function _nds32_vector_09: diff --git a/libgcc/config/nds32/isr-library/vec_vid09_4b.S b/libgcc/config/nds32/isr-library/vec_vid09_4b.S deleted file mode 100644 index 2d1944f..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid09_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.09, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_09_4b - .type _nds32_vector_09_4b, @function -_nds32_vector_09_4b: -1: - j 1b - .size _nds32_vector_09_4b, .-_nds32_vector_09_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid10.S b/libgcc/config/nds32/isr-library/vec_vid10.S index 411edd7..6bf2c7c 100644 --- a/libgcc/config/nds32/isr-library/vec_vid10.S +++ b/libgcc/config/nds32/isr-library/vec_vid10.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.10, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_10 .type _nds32_vector_10, @function _nds32_vector_10: diff --git a/libgcc/config/nds32/isr-library/vec_vid10_4b.S b/libgcc/config/nds32/isr-library/vec_vid10_4b.S deleted file mode 100644 index 04761ab..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid10_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.10, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_10_4b - .type _nds32_vector_10_4b, @function -_nds32_vector_10_4b: -1: - j 1b - .size _nds32_vector_10_4b, .-_nds32_vector_10_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid11.S b/libgcc/config/nds32/isr-library/vec_vid11.S index 8de45a4..86975ea 100644 --- a/libgcc/config/nds32/isr-library/vec_vid11.S +++ b/libgcc/config/nds32/isr-library/vec_vid11.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.11, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_11 .type _nds32_vector_11, @function _nds32_vector_11: diff --git a/libgcc/config/nds32/isr-library/vec_vid11_4b.S b/libgcc/config/nds32/isr-library/vec_vid11_4b.S deleted file mode 100644 index 328c1e6..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid11_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.11, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_11_4b - .type _nds32_vector_11_4b, @function -_nds32_vector_11_4b: -1: - j 1b - .size _nds32_vector_11_4b, .-_nds32_vector_11_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid12.S b/libgcc/config/nds32/isr-library/vec_vid12.S index ff5c6df..07cb7de 100644 --- a/libgcc/config/nds32/isr-library/vec_vid12.S +++ b/libgcc/config/nds32/isr-library/vec_vid12.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.12, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_12 .type _nds32_vector_12, @function _nds32_vector_12: diff --git a/libgcc/config/nds32/isr-library/vec_vid12_4b.S b/libgcc/config/nds32/isr-library/vec_vid12_4b.S deleted file mode 100644 index 52b7d23..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid12_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.12, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_12_4b - .type _nds32_vector_12_4b, @function -_nds32_vector_12_4b: -1: - j 1b - .size _nds32_vector_12_4b, .-_nds32_vector_12_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid13.S b/libgcc/config/nds32/isr-library/vec_vid13.S index 66014c3..5ac1a83 100644 --- a/libgcc/config/nds32/isr-library/vec_vid13.S +++ b/libgcc/config/nds32/isr-library/vec_vid13.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.13, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_13 .type _nds32_vector_13, @function _nds32_vector_13: diff --git a/libgcc/config/nds32/isr-library/vec_vid13_4b.S b/libgcc/config/nds32/isr-library/vec_vid13_4b.S deleted file mode 100644 index 59029ad..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid13_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.13, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_13_4b - .type _nds32_vector_13_4b, @function -_nds32_vector_13_4b: -1: - j 1b - .size _nds32_vector_13_4b, .-_nds32_vector_13_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid14.S b/libgcc/config/nds32/isr-library/vec_vid14.S index ca6f66f..5116f2f 100644 --- a/libgcc/config/nds32/isr-library/vec_vid14.S +++ b/libgcc/config/nds32/isr-library/vec_vid14.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.14, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_14 .type _nds32_vector_14, @function _nds32_vector_14: diff --git a/libgcc/config/nds32/isr-library/vec_vid14_4b.S b/libgcc/config/nds32/isr-library/vec_vid14_4b.S deleted file mode 100644 index 0d2afe4..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid14_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.14, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_14_4b - .type _nds32_vector_14_4b, @function -_nds32_vector_14_4b: -1: - j 1b - .size _nds32_vector_14_4b, .-_nds32_vector_14_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid15.S b/libgcc/config/nds32/isr-library/vec_vid15.S index c94b42a..03449c0 100644 --- a/libgcc/config/nds32/isr-library/vec_vid15.S +++ b/libgcc/config/nds32/isr-library/vec_vid15.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.15, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_15 .type _nds32_vector_15, @function _nds32_vector_15: diff --git a/libgcc/config/nds32/isr-library/vec_vid15_4b.S b/libgcc/config/nds32/isr-library/vec_vid15_4b.S deleted file mode 100644 index 60799d7..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid15_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.15, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_15_4b - .type _nds32_vector_15_4b, @function -_nds32_vector_15_4b: -1: - j 1b - .size _nds32_vector_15_4b, .-_nds32_vector_15_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid16.S b/libgcc/config/nds32/isr-library/vec_vid16.S index f19454d..b01d673 100644 --- a/libgcc/config/nds32/isr-library/vec_vid16.S +++ b/libgcc/config/nds32/isr-library/vec_vid16.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.16, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_16 .type _nds32_vector_16, @function _nds32_vector_16: diff --git a/libgcc/config/nds32/isr-library/vec_vid16_4b.S b/libgcc/config/nds32/isr-library/vec_vid16_4b.S deleted file mode 100644 index 6791204..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid16_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.16, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_16_4b - .type _nds32_vector_16_4b, @function -_nds32_vector_16_4b: -1: - j 1b - .size _nds32_vector_16_4b, .-_nds32_vector_16_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid17.S b/libgcc/config/nds32/isr-library/vec_vid17.S index 486a0aa..c6ed785 100644 --- a/libgcc/config/nds32/isr-library/vec_vid17.S +++ b/libgcc/config/nds32/isr-library/vec_vid17.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.17, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_17 .type _nds32_vector_17, @function _nds32_vector_17: diff --git a/libgcc/config/nds32/isr-library/vec_vid17_4b.S b/libgcc/config/nds32/isr-library/vec_vid17_4b.S deleted file mode 100644 index 04f4285..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid17_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.17, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_17_4b - .type _nds32_vector_17_4b, @function -_nds32_vector_17_4b: -1: - j 1b - .size _nds32_vector_17_4b, .-_nds32_vector_17_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid18.S b/libgcc/config/nds32/isr-library/vec_vid18.S index 137511f..e0e7b7e 100644 --- a/libgcc/config/nds32/isr-library/vec_vid18.S +++ b/libgcc/config/nds32/isr-library/vec_vid18.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.18, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_18 .type _nds32_vector_18, @function _nds32_vector_18: diff --git a/libgcc/config/nds32/isr-library/vec_vid18_4b.S b/libgcc/config/nds32/isr-library/vec_vid18_4b.S deleted file mode 100644 index 4d80192..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid18_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.18, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_18_4b - .type _nds32_vector_18_4b, @function -_nds32_vector_18_4b: -1: - j 1b - .size _nds32_vector_18_4b, .-_nds32_vector_18_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid19.S b/libgcc/config/nds32/isr-library/vec_vid19.S index 791e135..ef7075f 100644 --- a/libgcc/config/nds32/isr-library/vec_vid19.S +++ b/libgcc/config/nds32/isr-library/vec_vid19.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.19, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_19 .type _nds32_vector_19, @function _nds32_vector_19: diff --git a/libgcc/config/nds32/isr-library/vec_vid19_4b.S b/libgcc/config/nds32/isr-library/vec_vid19_4b.S deleted file mode 100644 index 87d4c7c..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid19_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.19, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_19_4b - .type _nds32_vector_19_4b, @function -_nds32_vector_19_4b: -1: - j 1b - .size _nds32_vector_19_4b, .-_nds32_vector_19_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid20.S b/libgcc/config/nds32/isr-library/vec_vid20.S index e7ab0e3..99bcf01 100644 --- a/libgcc/config/nds32/isr-library/vec_vid20.S +++ b/libgcc/config/nds32/isr-library/vec_vid20.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.20, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_20 .type _nds32_vector_20, @function _nds32_vector_20: diff --git a/libgcc/config/nds32/isr-library/vec_vid20_4b.S b/libgcc/config/nds32/isr-library/vec_vid20_4b.S deleted file mode 100644 index 308385a..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid20_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.20, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_20_4b - .type _nds32_vector_20_4b, @function -_nds32_vector_20_4b: -1: - j 1b - .size _nds32_vector_20_4b, .-_nds32_vector_20_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid21.S b/libgcc/config/nds32/isr-library/vec_vid21.S index 315ae56..8c66bef 100644 --- a/libgcc/config/nds32/isr-library/vec_vid21.S +++ b/libgcc/config/nds32/isr-library/vec_vid21.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.21, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_21 .type _nds32_vector_21, @function _nds32_vector_21: diff --git a/libgcc/config/nds32/isr-library/vec_vid21_4b.S b/libgcc/config/nds32/isr-library/vec_vid21_4b.S deleted file mode 100644 index 16cf02a..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid21_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.21, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_21_4b - .type _nds32_vector_21_4b, @function -_nds32_vector_21_4b: -1: - j 1b - .size _nds32_vector_21_4b, .-_nds32_vector_21_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid22.S b/libgcc/config/nds32/isr-library/vec_vid22.S index 6f9de85..5c442ce 100644 --- a/libgcc/config/nds32/isr-library/vec_vid22.S +++ b/libgcc/config/nds32/isr-library/vec_vid22.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.22, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_22 .type _nds32_vector_22, @function _nds32_vector_22: diff --git a/libgcc/config/nds32/isr-library/vec_vid22_4b.S b/libgcc/config/nds32/isr-library/vec_vid22_4b.S deleted file mode 100644 index 587ee7f..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid22_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.22, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_22_4b - .type _nds32_vector_22_4b, @function -_nds32_vector_22_4b: -1: - j 1b - .size _nds32_vector_22_4b, .-_nds32_vector_22_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid23.S b/libgcc/config/nds32/isr-library/vec_vid23.S index 956b585..c5d73df 100644 --- a/libgcc/config/nds32/isr-library/vec_vid23.S +++ b/libgcc/config/nds32/isr-library/vec_vid23.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.23, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_23 .type _nds32_vector_23, @function _nds32_vector_23: diff --git a/libgcc/config/nds32/isr-library/vec_vid23_4b.S b/libgcc/config/nds32/isr-library/vec_vid23_4b.S deleted file mode 100644 index 5e4b643..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid23_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.23, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_23_4b - .type _nds32_vector_23_4b, @function -_nds32_vector_23_4b: -1: - j 1b - .size _nds32_vector_23_4b, .-_nds32_vector_23_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid24.S b/libgcc/config/nds32/isr-library/vec_vid24.S index 57086e9..fe7dada 100644 --- a/libgcc/config/nds32/isr-library/vec_vid24.S +++ b/libgcc/config/nds32/isr-library/vec_vid24.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.24, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_24 .type _nds32_vector_24, @function _nds32_vector_24: diff --git a/libgcc/config/nds32/isr-library/vec_vid24_4b.S b/libgcc/config/nds32/isr-library/vec_vid24_4b.S deleted file mode 100644 index 43495f9..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid24_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.24, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_24_4b - .type _nds32_vector_24_4b, @function -_nds32_vector_24_4b: -1: - j 1b - .size _nds32_vector_24_4b, .-_nds32_vector_24_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid25.S b/libgcc/config/nds32/isr-library/vec_vid25.S index 61fa526..ada24e4 100644 --- a/libgcc/config/nds32/isr-library/vec_vid25.S +++ b/libgcc/config/nds32/isr-library/vec_vid25.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.25, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_25 .type _nds32_vector_25, @function _nds32_vector_25: diff --git a/libgcc/config/nds32/isr-library/vec_vid25_4b.S b/libgcc/config/nds32/isr-library/vec_vid25_4b.S deleted file mode 100644 index 1ce6cf3..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid25_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.25, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_25_4b - .type _nds32_vector_25_4b, @function -_nds32_vector_25_4b: -1: - j 1b - .size _nds32_vector_25_4b, .-_nds32_vector_25_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid26.S b/libgcc/config/nds32/isr-library/vec_vid26.S index 3d9191d..1f97945 100644 --- a/libgcc/config/nds32/isr-library/vec_vid26.S +++ b/libgcc/config/nds32/isr-library/vec_vid26.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.26, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_26 .type _nds32_vector_26, @function _nds32_vector_26: diff --git a/libgcc/config/nds32/isr-library/vec_vid26_4b.S b/libgcc/config/nds32/isr-library/vec_vid26_4b.S deleted file mode 100644 index 5803247..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid26_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.26, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_26_4b - .type _nds32_vector_26_4b, @function -_nds32_vector_26_4b: -1: - j 1b - .size _nds32_vector_26_4b, .-_nds32_vector_26_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid27.S b/libgcc/config/nds32/isr-library/vec_vid27.S index ff12cfb..f440a8b 100644 --- a/libgcc/config/nds32/isr-library/vec_vid27.S +++ b/libgcc/config/nds32/isr-library/vec_vid27.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.27, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_27 .type _nds32_vector_27, @function _nds32_vector_27: diff --git a/libgcc/config/nds32/isr-library/vec_vid27_4b.S b/libgcc/config/nds32/isr-library/vec_vid27_4b.S deleted file mode 100644 index d61e3f9..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid27_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.27, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_27_4b - .type _nds32_vector_27_4b, @function -_nds32_vector_27_4b: -1: - j 1b - .size _nds32_vector_27_4b, .-_nds32_vector_27_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid28.S b/libgcc/config/nds32/isr-library/vec_vid28.S index 6b7610e..e1621c7 100644 --- a/libgcc/config/nds32/isr-library/vec_vid28.S +++ b/libgcc/config/nds32/isr-library/vec_vid28.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.28, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_28 .type _nds32_vector_28, @function _nds32_vector_28: diff --git a/libgcc/config/nds32/isr-library/vec_vid28_4b.S b/libgcc/config/nds32/isr-library/vec_vid28_4b.S deleted file mode 100644 index a39d015..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid28_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.28, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_28_4b - .type _nds32_vector_28_4b, @function -_nds32_vector_28_4b: -1: - j 1b - .size _nds32_vector_28_4b, .-_nds32_vector_28_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid29.S b/libgcc/config/nds32/isr-library/vec_vid29.S index b995841..4fa29c1 100644 --- a/libgcc/config/nds32/isr-library/vec_vid29.S +++ b/libgcc/config/nds32/isr-library/vec_vid29.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.29, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_29 .type _nds32_vector_29, @function _nds32_vector_29: diff --git a/libgcc/config/nds32/isr-library/vec_vid29_4b.S b/libgcc/config/nds32/isr-library/vec_vid29_4b.S deleted file mode 100644 index 803f323..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid29_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.29, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_29_4b - .type _nds32_vector_29_4b, @function -_nds32_vector_29_4b: -1: - j 1b - .size _nds32_vector_29_4b, .-_nds32_vector_29_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid30.S b/libgcc/config/nds32/isr-library/vec_vid30.S index 57d1507..214e67b 100644 --- a/libgcc/config/nds32/isr-library/vec_vid30.S +++ b/libgcc/config/nds32/isr-library/vec_vid30.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.30, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_30 .type _nds32_vector_30, @function _nds32_vector_30: diff --git a/libgcc/config/nds32/isr-library/vec_vid30_4b.S b/libgcc/config/nds32/isr-library/vec_vid30_4b.S deleted file mode 100644 index a2a1e3e..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid30_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.30, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_30_4b - .type _nds32_vector_30_4b, @function -_nds32_vector_30_4b: -1: - j 1b - .size _nds32_vector_30_4b, .-_nds32_vector_30_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid31.S b/libgcc/config/nds32/isr-library/vec_vid31.S index f9aee4e..b758b8c 100644 --- a/libgcc/config/nds32/isr-library/vec_vid31.S +++ b/libgcc/config/nds32/isr-library/vec_vid31.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.31, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_31 .type _nds32_vector_31, @function _nds32_vector_31: diff --git a/libgcc/config/nds32/isr-library/vec_vid31_4b.S b/libgcc/config/nds32/isr-library/vec_vid31_4b.S deleted file mode 100644 index 989645f..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid31_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.31, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_31_4b - .type _nds32_vector_31_4b, @function -_nds32_vector_31_4b: -1: - j 1b - .size _nds32_vector_31_4b, .-_nds32_vector_31_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid32.S b/libgcc/config/nds32/isr-library/vec_vid32.S index fc26cad..58234d5 100644 --- a/libgcc/config/nds32/isr-library/vec_vid32.S +++ b/libgcc/config/nds32/isr-library/vec_vid32.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.32, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_32 .type _nds32_vector_32, @function _nds32_vector_32: diff --git a/libgcc/config/nds32/isr-library/vec_vid32_4b.S b/libgcc/config/nds32/isr-library/vec_vid32_4b.S deleted file mode 100644 index 1ac7e31..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid32_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.32, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_32_4b - .type _nds32_vector_32_4b, @function -_nds32_vector_32_4b: -1: - j 1b - .size _nds32_vector_32_4b, .-_nds32_vector_32_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid33.S b/libgcc/config/nds32/isr-library/vec_vid33.S index dd655e6..d920352 100644 --- a/libgcc/config/nds32/isr-library/vec_vid33.S +++ b/libgcc/config/nds32/isr-library/vec_vid33.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.33, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_33 .type _nds32_vector_33, @function _nds32_vector_33: diff --git a/libgcc/config/nds32/isr-library/vec_vid33_4b.S b/libgcc/config/nds32/isr-library/vec_vid33_4b.S deleted file mode 100644 index 3c99412..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid33_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.33, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_33_4b - .type _nds32_vector_33_4b, @function -_nds32_vector_33_4b: -1: - j 1b - .size _nds32_vector_33_4b, .-_nds32_vector_33_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid34.S b/libgcc/config/nds32/isr-library/vec_vid34.S index a6b8517..01999b4 100644 --- a/libgcc/config/nds32/isr-library/vec_vid34.S +++ b/libgcc/config/nds32/isr-library/vec_vid34.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.34, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_34 .type _nds32_vector_34, @function _nds32_vector_34: diff --git a/libgcc/config/nds32/isr-library/vec_vid34_4b.S b/libgcc/config/nds32/isr-library/vec_vid34_4b.S deleted file mode 100644 index 77c07b9..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid34_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.34, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_34_4b - .type _nds32_vector_34_4b, @function -_nds32_vector_34_4b: -1: - j 1b - .size _nds32_vector_34_4b, .-_nds32_vector_34_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid35.S b/libgcc/config/nds32/isr-library/vec_vid35.S index 65ceeab..7ab0536 100644 --- a/libgcc/config/nds32/isr-library/vec_vid35.S +++ b/libgcc/config/nds32/isr-library/vec_vid35.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.35, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_35 .type _nds32_vector_35, @function _nds32_vector_35: diff --git a/libgcc/config/nds32/isr-library/vec_vid35_4b.S b/libgcc/config/nds32/isr-library/vec_vid35_4b.S deleted file mode 100644 index 432873a..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid35_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.35, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_35_4b - .type _nds32_vector_35_4b, @function -_nds32_vector_35_4b: -1: - j 1b - .size _nds32_vector_35_4b, .-_nds32_vector_35_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid36.S b/libgcc/config/nds32/isr-library/vec_vid36.S index 688dbb9..5da079d 100644 --- a/libgcc/config/nds32/isr-library/vec_vid36.S +++ b/libgcc/config/nds32/isr-library/vec_vid36.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.36, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_36 .type _nds32_vector_36, @function _nds32_vector_36: diff --git a/libgcc/config/nds32/isr-library/vec_vid36_4b.S b/libgcc/config/nds32/isr-library/vec_vid36_4b.S deleted file mode 100644 index dadd381..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid36_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.36, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_36_4b - .type _nds32_vector_36_4b, @function -_nds32_vector_36_4b: -1: - j 1b - .size _nds32_vector_36_4b, .-_nds32_vector_36_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid37.S b/libgcc/config/nds32/isr-library/vec_vid37.S index 712bbe8..704d6b8 100644 --- a/libgcc/config/nds32/isr-library/vec_vid37.S +++ b/libgcc/config/nds32/isr-library/vec_vid37.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.37, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_37 .type _nds32_vector_37, @function _nds32_vector_37: diff --git a/libgcc/config/nds32/isr-library/vec_vid37_4b.S b/libgcc/config/nds32/isr-library/vec_vid37_4b.S deleted file mode 100644 index ec845e1..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid37_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.37, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_37_4b - .type _nds32_vector_37_4b, @function -_nds32_vector_37_4b: -1: - j 1b - .size _nds32_vector_37_4b, .-_nds32_vector_37_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid38.S b/libgcc/config/nds32/isr-library/vec_vid38.S index b6e4979..fdfc4a9 100644 --- a/libgcc/config/nds32/isr-library/vec_vid38.S +++ b/libgcc/config/nds32/isr-library/vec_vid38.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.38, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_38 .type _nds32_vector_38, @function _nds32_vector_38: diff --git a/libgcc/config/nds32/isr-library/vec_vid38_4b.S b/libgcc/config/nds32/isr-library/vec_vid38_4b.S deleted file mode 100644 index 84919ed..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid38_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.38, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_38_4b - .type _nds32_vector_38_4b, @function -_nds32_vector_38_4b: -1: - j 1b - .size _nds32_vector_38_4b, .-_nds32_vector_38_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid39.S b/libgcc/config/nds32/isr-library/vec_vid39.S index 2dee269..00dd245 100644 --- a/libgcc/config/nds32/isr-library/vec_vid39.S +++ b/libgcc/config/nds32/isr-library/vec_vid39.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.39, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_39 .type _nds32_vector_39, @function _nds32_vector_39: diff --git a/libgcc/config/nds32/isr-library/vec_vid39_4b.S b/libgcc/config/nds32/isr-library/vec_vid39_4b.S deleted file mode 100644 index 8f2f634..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid39_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.39, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_39_4b - .type _nds32_vector_39_4b, @function -_nds32_vector_39_4b: -1: - j 1b - .size _nds32_vector_39_4b, .-_nds32_vector_39_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid40.S b/libgcc/config/nds32/isr-library/vec_vid40.S index fe7508c..82b579f 100644 --- a/libgcc/config/nds32/isr-library/vec_vid40.S +++ b/libgcc/config/nds32/isr-library/vec_vid40.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.40, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_40 .type _nds32_vector_40, @function _nds32_vector_40: diff --git a/libgcc/config/nds32/isr-library/vec_vid40_4b.S b/libgcc/config/nds32/isr-library/vec_vid40_4b.S deleted file mode 100644 index 0aab8f4..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid40_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.40, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_40_4b - .type _nds32_vector_40_4b, @function -_nds32_vector_40_4b: -1: - j 1b - .size _nds32_vector_40_4b, .-_nds32_vector_40_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid41.S b/libgcc/config/nds32/isr-library/vec_vid41.S index 711fcd5..721c735 100644 --- a/libgcc/config/nds32/isr-library/vec_vid41.S +++ b/libgcc/config/nds32/isr-library/vec_vid41.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.41, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_41 .type _nds32_vector_41, @function _nds32_vector_41: diff --git a/libgcc/config/nds32/isr-library/vec_vid41_4b.S b/libgcc/config/nds32/isr-library/vec_vid41_4b.S deleted file mode 100644 index e8a8527..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid41_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.41, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_41_4b - .type _nds32_vector_41_4b, @function -_nds32_vector_41_4b: -1: - j 1b - .size _nds32_vector_41_4b, .-_nds32_vector_41_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid42.S b/libgcc/config/nds32/isr-library/vec_vid42.S index 0c6a849..307b51d 100644 --- a/libgcc/config/nds32/isr-library/vec_vid42.S +++ b/libgcc/config/nds32/isr-library/vec_vid42.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.42, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_42 .type _nds32_vector_42, @function _nds32_vector_42: diff --git a/libgcc/config/nds32/isr-library/vec_vid42_4b.S b/libgcc/config/nds32/isr-library/vec_vid42_4b.S deleted file mode 100644 index cfe184c..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid42_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.42, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_42_4b - .type _nds32_vector_42_4b, @function -_nds32_vector_42_4b: -1: - j 1b - .size _nds32_vector_42_4b, .-_nds32_vector_42_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid43.S b/libgcc/config/nds32/isr-library/vec_vid43.S index 2b4681a..c0ce02d 100644 --- a/libgcc/config/nds32/isr-library/vec_vid43.S +++ b/libgcc/config/nds32/isr-library/vec_vid43.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.43, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_43 .type _nds32_vector_43, @function _nds32_vector_43: diff --git a/libgcc/config/nds32/isr-library/vec_vid43_4b.S b/libgcc/config/nds32/isr-library/vec_vid43_4b.S deleted file mode 100644 index 3edd606..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid43_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.43, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_43_4b - .type _nds32_vector_43_4b, @function -_nds32_vector_43_4b: -1: - j 1b - .size _nds32_vector_43_4b, .-_nds32_vector_43_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid44.S b/libgcc/config/nds32/isr-library/vec_vid44.S index 232ef41..c2a384c 100644 --- a/libgcc/config/nds32/isr-library/vec_vid44.S +++ b/libgcc/config/nds32/isr-library/vec_vid44.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.44, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_44 .type _nds32_vector_44, @function _nds32_vector_44: diff --git a/libgcc/config/nds32/isr-library/vec_vid44_4b.S b/libgcc/config/nds32/isr-library/vec_vid44_4b.S deleted file mode 100644 index 0f2b8a3..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid44_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.44, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_44_4b - .type _nds32_vector_44_4b, @function -_nds32_vector_44_4b: -1: - j 1b - .size _nds32_vector_44_4b, .-_nds32_vector_44_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid45.S b/libgcc/config/nds32/isr-library/vec_vid45.S index e2f9863..e13c52b 100644 --- a/libgcc/config/nds32/isr-library/vec_vid45.S +++ b/libgcc/config/nds32/isr-library/vec_vid45.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.45, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_45 .type _nds32_vector_45, @function _nds32_vector_45: diff --git a/libgcc/config/nds32/isr-library/vec_vid45_4b.S b/libgcc/config/nds32/isr-library/vec_vid45_4b.S deleted file mode 100644 index 7358ec1..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid45_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.45, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_45_4b - .type _nds32_vector_45_4b, @function -_nds32_vector_45_4b: -1: - j 1b - .size _nds32_vector_45_4b, .-_nds32_vector_45_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid46.S b/libgcc/config/nds32/isr-library/vec_vid46.S index f3b93aa..71bfb53 100644 --- a/libgcc/config/nds32/isr-library/vec_vid46.S +++ b/libgcc/config/nds32/isr-library/vec_vid46.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.46, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_46 .type _nds32_vector_46, @function _nds32_vector_46: diff --git a/libgcc/config/nds32/isr-library/vec_vid46_4b.S b/libgcc/config/nds32/isr-library/vec_vid46_4b.S deleted file mode 100644 index 2782e86..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid46_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.46, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_46_4b - .type _nds32_vector_46_4b, @function -_nds32_vector_46_4b: -1: - j 1b - .size _nds32_vector_46_4b, .-_nds32_vector_46_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid47.S b/libgcc/config/nds32/isr-library/vec_vid47.S index 130c8d7..d1f2131 100644 --- a/libgcc/config/nds32/isr-library/vec_vid47.S +++ b/libgcc/config/nds32/isr-library/vec_vid47.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.47, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_47 .type _nds32_vector_47, @function _nds32_vector_47: diff --git a/libgcc/config/nds32/isr-library/vec_vid47_4b.S b/libgcc/config/nds32/isr-library/vec_vid47_4b.S deleted file mode 100644 index f237577..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid47_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.47, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_47_4b - .type _nds32_vector_47_4b, @function -_nds32_vector_47_4b: -1: - j 1b - .size _nds32_vector_47_4b, .-_nds32_vector_47_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid48.S b/libgcc/config/nds32/isr-library/vec_vid48.S index f3bca05..4ba5eb9 100644 --- a/libgcc/config/nds32/isr-library/vec_vid48.S +++ b/libgcc/config/nds32/isr-library/vec_vid48.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.48, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_48 .type _nds32_vector_48, @function _nds32_vector_48: diff --git a/libgcc/config/nds32/isr-library/vec_vid48_4b.S b/libgcc/config/nds32/isr-library/vec_vid48_4b.S deleted file mode 100644 index 3e35f68..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid48_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.48, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_48_4b - .type _nds32_vector_48_4b, @function -_nds32_vector_48_4b: -1: - j 1b - .size _nds32_vector_48_4b, .-_nds32_vector_48_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid49.S b/libgcc/config/nds32/isr-library/vec_vid49.S index 0b32691..dd3d35e 100644 --- a/libgcc/config/nds32/isr-library/vec_vid49.S +++ b/libgcc/config/nds32/isr-library/vec_vid49.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.49, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_49 .type _nds32_vector_49, @function _nds32_vector_49: diff --git a/libgcc/config/nds32/isr-library/vec_vid49_4b.S b/libgcc/config/nds32/isr-library/vec_vid49_4b.S deleted file mode 100644 index a510bbb..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid49_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.49, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_49_4b - .type _nds32_vector_49_4b, @function -_nds32_vector_49_4b: -1: - j 1b - .size _nds32_vector_49_4b, .-_nds32_vector_49_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid50.S b/libgcc/config/nds32/isr-library/vec_vid50.S index 48334feb..8f801ec 100644 --- a/libgcc/config/nds32/isr-library/vec_vid50.S +++ b/libgcc/config/nds32/isr-library/vec_vid50.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.50, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_50 .type _nds32_vector_50, @function _nds32_vector_50: diff --git a/libgcc/config/nds32/isr-library/vec_vid50_4b.S b/libgcc/config/nds32/isr-library/vec_vid50_4b.S deleted file mode 100644 index 1f42b73..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid50_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.50, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_50_4b - .type _nds32_vector_50_4b, @function -_nds32_vector_50_4b: -1: - j 1b - .size _nds32_vector_50_4b, .-_nds32_vector_50_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid51.S b/libgcc/config/nds32/isr-library/vec_vid51.S index 4c27f27..445abf9 100644 --- a/libgcc/config/nds32/isr-library/vec_vid51.S +++ b/libgcc/config/nds32/isr-library/vec_vid51.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.51, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_51 .type _nds32_vector_51, @function _nds32_vector_51: diff --git a/libgcc/config/nds32/isr-library/vec_vid51_4b.S b/libgcc/config/nds32/isr-library/vec_vid51_4b.S deleted file mode 100644 index 7bb8abe..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid51_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.51, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_51_4b - .type _nds32_vector_51_4b, @function -_nds32_vector_51_4b: -1: - j 1b - .size _nds32_vector_51_4b, .-_nds32_vector_51_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid52.S b/libgcc/config/nds32/isr-library/vec_vid52.S index 4c44811..7283975 100644 --- a/libgcc/config/nds32/isr-library/vec_vid52.S +++ b/libgcc/config/nds32/isr-library/vec_vid52.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.52, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_52 .type _nds32_vector_52, @function _nds32_vector_52: diff --git a/libgcc/config/nds32/isr-library/vec_vid52_4b.S b/libgcc/config/nds32/isr-library/vec_vid52_4b.S deleted file mode 100644 index 4cb89f6..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid52_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.52, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_52_4b - .type _nds32_vector_52_4b, @function -_nds32_vector_52_4b: -1: - j 1b - .size _nds32_vector_52_4b, .-_nds32_vector_52_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid53.S b/libgcc/config/nds32/isr-library/vec_vid53.S index 2882583..299c645 100644 --- a/libgcc/config/nds32/isr-library/vec_vid53.S +++ b/libgcc/config/nds32/isr-library/vec_vid53.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.53, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_53 .type _nds32_vector_53, @function _nds32_vector_53: diff --git a/libgcc/config/nds32/isr-library/vec_vid53_4b.S b/libgcc/config/nds32/isr-library/vec_vid53_4b.S deleted file mode 100644 index 9abc839..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid53_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.53, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_53_4b - .type _nds32_vector_53_4b, @function -_nds32_vector_53_4b: -1: - j 1b - .size _nds32_vector_53_4b, .-_nds32_vector_53_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid54.S b/libgcc/config/nds32/isr-library/vec_vid54.S index a014c72..ae99390 100644 --- a/libgcc/config/nds32/isr-library/vec_vid54.S +++ b/libgcc/config/nds32/isr-library/vec_vid54.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.54, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_54 .type _nds32_vector_54, @function _nds32_vector_54: diff --git a/libgcc/config/nds32/isr-library/vec_vid54_4b.S b/libgcc/config/nds32/isr-library/vec_vid54_4b.S deleted file mode 100644 index f736ba8..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid54_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.54, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_54_4b - .type _nds32_vector_54_4b, @function -_nds32_vector_54_4b: -1: - j 1b - .size _nds32_vector_54_4b, .-_nds32_vector_54_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid55.S b/libgcc/config/nds32/isr-library/vec_vid55.S index 44d820c..e75d24a 100644 --- a/libgcc/config/nds32/isr-library/vec_vid55.S +++ b/libgcc/config/nds32/isr-library/vec_vid55.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.55, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_55 .type _nds32_vector_55, @function _nds32_vector_55: diff --git a/libgcc/config/nds32/isr-library/vec_vid55_4b.S b/libgcc/config/nds32/isr-library/vec_vid55_4b.S deleted file mode 100644 index d09c665..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid55_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.55, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_55_4b - .type _nds32_vector_55_4b, @function -_nds32_vector_55_4b: -1: - j 1b - .size _nds32_vector_55_4b, .-_nds32_vector_55_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid56.S b/libgcc/config/nds32/isr-library/vec_vid56.S index d5cb362..cc4904e 100644 --- a/libgcc/config/nds32/isr-library/vec_vid56.S +++ b/libgcc/config/nds32/isr-library/vec_vid56.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.56, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_56 .type _nds32_vector_56, @function _nds32_vector_56: diff --git a/libgcc/config/nds32/isr-library/vec_vid56_4b.S b/libgcc/config/nds32/isr-library/vec_vid56_4b.S deleted file mode 100644 index 86b4103..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid56_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.56, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_56_4b - .type _nds32_vector_56_4b, @function -_nds32_vector_56_4b: -1: - j 1b - .size _nds32_vector_56_4b, .-_nds32_vector_56_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid57.S b/libgcc/config/nds32/isr-library/vec_vid57.S index 5fb3ce9c..a17ed45 100644 --- a/libgcc/config/nds32/isr-library/vec_vid57.S +++ b/libgcc/config/nds32/isr-library/vec_vid57.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.57, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_57 .type _nds32_vector_57, @function _nds32_vector_57: diff --git a/libgcc/config/nds32/isr-library/vec_vid57_4b.S b/libgcc/config/nds32/isr-library/vec_vid57_4b.S deleted file mode 100644 index 45c5d29..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid57_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.57, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_57_4b - .type _nds32_vector_57_4b, @function -_nds32_vector_57_4b: -1: - j 1b - .size _nds32_vector_57_4b, .-_nds32_vector_57_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid58.S b/libgcc/config/nds32/isr-library/vec_vid58.S index d420d68..629bf1a 100644 --- a/libgcc/config/nds32/isr-library/vec_vid58.S +++ b/libgcc/config/nds32/isr-library/vec_vid58.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.58, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_58 .type _nds32_vector_58, @function _nds32_vector_58: diff --git a/libgcc/config/nds32/isr-library/vec_vid58_4b.S b/libgcc/config/nds32/isr-library/vec_vid58_4b.S deleted file mode 100644 index 812470c..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid58_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.58, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_58_4b - .type _nds32_vector_58_4b, @function -_nds32_vector_58_4b: -1: - j 1b - .size _nds32_vector_58_4b, .-_nds32_vector_58_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid59.S b/libgcc/config/nds32/isr-library/vec_vid59.S index 78a1885..540e02e 100644 --- a/libgcc/config/nds32/isr-library/vec_vid59.S +++ b/libgcc/config/nds32/isr-library/vec_vid59.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.59, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_59 .type _nds32_vector_59, @function _nds32_vector_59: diff --git a/libgcc/config/nds32/isr-library/vec_vid59_4b.S b/libgcc/config/nds32/isr-library/vec_vid59_4b.S deleted file mode 100644 index fa3a467..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid59_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.59, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_59_4b - .type _nds32_vector_59_4b, @function -_nds32_vector_59_4b: -1: - j 1b - .size _nds32_vector_59_4b, .-_nds32_vector_59_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid60.S b/libgcc/config/nds32/isr-library/vec_vid60.S index a6f704d..8658249 100644 --- a/libgcc/config/nds32/isr-library/vec_vid60.S +++ b/libgcc/config/nds32/isr-library/vec_vid60.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.60, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_60 .type _nds32_vector_60, @function _nds32_vector_60: diff --git a/libgcc/config/nds32/isr-library/vec_vid60_4b.S b/libgcc/config/nds32/isr-library/vec_vid60_4b.S deleted file mode 100644 index 505da2a..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid60_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.60, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_60_4b - .type _nds32_vector_60_4b, @function -_nds32_vector_60_4b: -1: - j 1b - .size _nds32_vector_60_4b, .-_nds32_vector_60_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid61.S b/libgcc/config/nds32/isr-library/vec_vid61.S index 4e79bde..376acb9 100644 --- a/libgcc/config/nds32/isr-library/vec_vid61.S +++ b/libgcc/config/nds32/isr-library/vec_vid61.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.61, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_61 .type _nds32_vector_61, @function _nds32_vector_61: diff --git a/libgcc/config/nds32/isr-library/vec_vid61_4b.S b/libgcc/config/nds32/isr-library/vec_vid61_4b.S deleted file mode 100644 index 9a0cce5..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid61_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.61, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_61_4b - .type _nds32_vector_61_4b, @function -_nds32_vector_61_4b: -1: - j 1b - .size _nds32_vector_61_4b, .-_nds32_vector_61_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid62.S b/libgcc/config/nds32/isr-library/vec_vid62.S index 5eef0a6..5ab06a8 100644 --- a/libgcc/config/nds32/isr-library/vec_vid62.S +++ b/libgcc/config/nds32/isr-library/vec_vid62.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.62, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_62 .type _nds32_vector_62, @function _nds32_vector_62: diff --git a/libgcc/config/nds32/isr-library/vec_vid62_4b.S b/libgcc/config/nds32/isr-library/vec_vid62_4b.S deleted file mode 100644 index da8ba28..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid62_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.62, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_62_4b - .type _nds32_vector_62_4b, @function -_nds32_vector_62_4b: -1: - j 1b - .size _nds32_vector_62_4b, .-_nds32_vector_62_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid63.S b/libgcc/config/nds32/isr-library/vec_vid63.S index 0a8c0ad..6646bcc 100644 --- a/libgcc/config/nds32/isr-library/vec_vid63.S +++ b/libgcc/config/nds32/isr-library/vec_vid63.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.63, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_63 .type _nds32_vector_63, @function _nds32_vector_63: diff --git a/libgcc/config/nds32/isr-library/vec_vid63_4b.S b/libgcc/config/nds32/isr-library/vec_vid63_4b.S deleted file mode 100644 index 8f1045e..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid63_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.63, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_63_4b - .type _nds32_vector_63_4b, @function -_nds32_vector_63_4b: -1: - j 1b - .size _nds32_vector_63_4b, .-_nds32_vector_63_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid64.S b/libgcc/config/nds32/isr-library/vec_vid64.S index b3f034b..f892aec 100644 --- a/libgcc/config/nds32/isr-library/vec_vid64.S +++ b/libgcc/config/nds32/isr-library/vec_vid64.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.64, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_64 .type _nds32_vector_64, @function _nds32_vector_64: diff --git a/libgcc/config/nds32/isr-library/vec_vid64_4b.S b/libgcc/config/nds32/isr-library/vec_vid64_4b.S deleted file mode 100644 index 81d9679..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid64_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.64, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_64_4b - .type _nds32_vector_64_4b, @function -_nds32_vector_64_4b: -1: - j 1b - .size _nds32_vector_64_4b, .-_nds32_vector_64_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid65.S b/libgcc/config/nds32/isr-library/vec_vid65.S index 72db454..03f79a5 100644 --- a/libgcc/config/nds32/isr-library/vec_vid65.S +++ b/libgcc/config/nds32/isr-library/vec_vid65.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.65, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_65 .type _nds32_vector_65, @function _nds32_vector_65: diff --git a/libgcc/config/nds32/isr-library/vec_vid65_4b.S b/libgcc/config/nds32/isr-library/vec_vid65_4b.S deleted file mode 100644 index aa9ad2b..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid65_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.65, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_65_4b - .type _nds32_vector_65_4b, @function -_nds32_vector_65_4b: -1: - j 1b - .size _nds32_vector_65_4b, .-_nds32_vector_65_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid66.S b/libgcc/config/nds32/isr-library/vec_vid66.S index 75469e7..ff805bd 100644 --- a/libgcc/config/nds32/isr-library/vec_vid66.S +++ b/libgcc/config/nds32/isr-library/vec_vid66.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.66, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_66 .type _nds32_vector_66, @function _nds32_vector_66: diff --git a/libgcc/config/nds32/isr-library/vec_vid66_4b.S b/libgcc/config/nds32/isr-library/vec_vid66_4b.S deleted file mode 100644 index 9830fe2..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid66_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.66, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_66_4b - .type _nds32_vector_66_4b, @function -_nds32_vector_66_4b: -1: - j 1b - .size _nds32_vector_66_4b, .-_nds32_vector_66_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid67.S b/libgcc/config/nds32/isr-library/vec_vid67.S index 4b076cd..f592aba 100644 --- a/libgcc/config/nds32/isr-library/vec_vid67.S +++ b/libgcc/config/nds32/isr-library/vec_vid67.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.67, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_67 .type _nds32_vector_67, @function _nds32_vector_67: diff --git a/libgcc/config/nds32/isr-library/vec_vid67_4b.S b/libgcc/config/nds32/isr-library/vec_vid67_4b.S deleted file mode 100644 index c7e31dd..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid67_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.67, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_67_4b - .type _nds32_vector_67_4b, @function -_nds32_vector_67_4b: -1: - j 1b - .size _nds32_vector_67_4b, .-_nds32_vector_67_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid68.S b/libgcc/config/nds32/isr-library/vec_vid68.S index 7df1cdd..ee2702a 100644 --- a/libgcc/config/nds32/isr-library/vec_vid68.S +++ b/libgcc/config/nds32/isr-library/vec_vid68.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.68, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_68 .type _nds32_vector_68, @function _nds32_vector_68: diff --git a/libgcc/config/nds32/isr-library/vec_vid68_4b.S b/libgcc/config/nds32/isr-library/vec_vid68_4b.S deleted file mode 100644 index 0d6fcb5..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid68_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.68, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_68_4b - .type _nds32_vector_68_4b, @function -_nds32_vector_68_4b: -1: - j 1b - .size _nds32_vector_68_4b, .-_nds32_vector_68_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid69.S b/libgcc/config/nds32/isr-library/vec_vid69.S index e30e5bf..c152015 100644 --- a/libgcc/config/nds32/isr-library/vec_vid69.S +++ b/libgcc/config/nds32/isr-library/vec_vid69.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.69, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_69 .type _nds32_vector_69, @function _nds32_vector_69: diff --git a/libgcc/config/nds32/isr-library/vec_vid69_4b.S b/libgcc/config/nds32/isr-library/vec_vid69_4b.S deleted file mode 100644 index 3508162..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid69_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.69, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_69_4b - .type _nds32_vector_69_4b, @function -_nds32_vector_69_4b: -1: - j 1b - .size _nds32_vector_69_4b, .-_nds32_vector_69_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid70.S b/libgcc/config/nds32/isr-library/vec_vid70.S index d436ac5..a3578d6 100644 --- a/libgcc/config/nds32/isr-library/vec_vid70.S +++ b/libgcc/config/nds32/isr-library/vec_vid70.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.70, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_70 .type _nds32_vector_70, @function _nds32_vector_70: diff --git a/libgcc/config/nds32/isr-library/vec_vid70_4b.S b/libgcc/config/nds32/isr-library/vec_vid70_4b.S deleted file mode 100644 index f3f0dd6..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid70_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.70, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_70_4b - .type _nds32_vector_70_4b, @function -_nds32_vector_70_4b: -1: - j 1b - .size _nds32_vector_70_4b, .-_nds32_vector_70_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid71.S b/libgcc/config/nds32/isr-library/vec_vid71.S index d7d7ab3..6790888 100644 --- a/libgcc/config/nds32/isr-library/vec_vid71.S +++ b/libgcc/config/nds32/isr-library/vec_vid71.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.71, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_71 .type _nds32_vector_71, @function _nds32_vector_71: diff --git a/libgcc/config/nds32/isr-library/vec_vid71_4b.S b/libgcc/config/nds32/isr-library/vec_vid71_4b.S deleted file mode 100644 index 505c79e..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid71_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.71, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_71_4b - .type _nds32_vector_71_4b, @function -_nds32_vector_71_4b: -1: - j 1b - .size _nds32_vector_71_4b, .-_nds32_vector_71_4b diff --git a/libgcc/config/nds32/isr-library/vec_vid72.S b/libgcc/config/nds32/isr-library/vec_vid72.S index 08652d2..32984a0 100644 --- a/libgcc/config/nds32/isr-library/vec_vid72.S +++ b/libgcc/config/nds32/isr-library/vec_vid72.S @@ -24,8 +24,15 @@ . */ .section .nds32_vector.72, "ax" +#if __NDS32_ISR_VECTOR_SIZE_4__ + /* The vector size is default 4-byte for v3 architecture. */ + .vec_size 4 + .align 2 +#else + /* The vector size is default 16-byte for other architectures. */ .vec_size 16 .align 4 +#endif .weak _nds32_vector_72 .type _nds32_vector_72, @function _nds32_vector_72: diff --git a/libgcc/config/nds32/isr-library/vec_vid72_4b.S b/libgcc/config/nds32/isr-library/vec_vid72_4b.S deleted file mode 100644 index 1083c03..0000000 --- a/libgcc/config/nds32/isr-library/vec_vid72_4b.S +++ /dev/null @@ -1,34 +0,0 @@ -/* c-isr library stuff 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .nds32_vector.72, "ax" - .vec_size 4 - .align 2 - .weak _nds32_vector_72_4b - .type _nds32_vector_72_4b, @function -_nds32_vector_72_4b: -1: - j 1b - .size _nds32_vector_72_4b, .-_nds32_vector_72_4b diff --git a/libgcc/config/nds32/lib1asmsrc-mculib.S b/libgcc/config/nds32/lib1asmsrc-mculib.S deleted file mode 100644 index bdbcd74..0000000 --- a/libgcc/config/nds32/lib1asmsrc-mculib.S +++ /dev/null @@ -1,5213 +0,0 @@ -/* mculib libgcc routines 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - - .section .mdebug.abi_nds32 - .previous - - -/* ------------------------------------------- */ -/* FPBIT floating point operations for libgcc */ -/* ------------------------------------------- */ - -#ifdef L_addsub_sf - - .text - .align 2 - .global __subsf3 - .type __subsf3, @function -__subsf3: - push $lp - pushm $r6, $r9 - - move $r2, #0x80000000 - xor $r1, $r1, $r2 - - j .Lsfpadd - - .global __addsf3 - .type __addsf3, @function -__addsf3: - push $lp - pushm $r6, $r9 -.Lsfpadd: - srli $r5, $r0, #23 - andi $r5, $r5, #0xff - srli $r7, $r1, #23 - andi $r7, $r7, #0xff - move $r3, #0x80000000 - slli $r4, $r0, #8 - or $r4, $r4, $r3 - slli $r6, $r1, #8 - or $r6, $r6, $r3 - - addi $r9, $r5, #-1 - slti $r15, $r9, #0xfe - beqzs8 .LEspecA - -.LElab1: - addi $r9, $r7, #-1 - slti $r15, $r9, #0xfe - beqzs8 .LEspecB - -.LElab2: - sub $r8, $r5, $r7 - sltsi $r15, $r8, #0 - bnezs8 .Li1 - sltsi $r15, $r8, #0x20 - bnezs8 .Li2 - move $r6, #2 - j .Le1 -.Li2: - move $r2, $r6 - srl $r6, $r6, $r8 - sll $r9, $r6, $r8 - beq $r9, $r2, .Le1 - ori $r6, $r6, #2 - j .Le1 -.Li1: - move $r5, $r7 - subri $r8, $r8, #0 - sltsi $r15, $r8, #0x20 - bnezs8 .Li4 - move $r4, #2 - j .Le1 -.Li4: - move $r2, $r4 - srl $r4, $r4, $r8 - sll $r9, $r4, $r8 - beq $r9, $r2, .Le1 - ori $r4, $r4, #2 - -.Le1: - and $r8, $r0, $r3 - xor $r9, $r8, $r1 - sltsi $r15, $r9, #0 - bnezs8 .LEsub1 - - #ADD($r4, $r6) - add $r4, $r4, $r6 - slt $r15, $r4, $r6 - beqzs8 .LEres - andi $r9, $r4, #1 - beqz $r9, .Li7 - ori $r4, $r4, #2 -.Li7: - srli $r4, $r4, #1 - addi $r5, $r5, #1 - subri $r15, $r5, #0xff - bnezs8 .LEres - move $r4, #0 - j .LEres - -.LEsub1: - #SUB($r4, $r6) - move $r15, $r4 - sub $r4, $r4, $r6 - slt $r15, $r15, $r4 - beqzs8 .Li9 - subri $r4, $r4, #0 - xor $r8, $r8, $r3 - j .Le9 -.Li9: - beqz $r4, .LEzer -.Le9: -#ifdef __NDS32_PERF_EXT__ - clz $r2, $r4 -#else - pushm $r0, $r1 - pushm $r3, $r5 - move $r0, $r4 - bal __clzsi2 - move $r2, $r0 - popm $r3, $r5 - popm $r0, $r1 -#endif - sub $r5, $r5, $r2 - sll $r4, $r4, $r2 - -.LEres: - blez $r5, .LEund - -.LElab12: - #ADD($r4, $0x80) - move $r15, #0x80 - add $r4, $r4, $r15 - slt $r15, $r4, $r15 - - #ADDC($r5, $0x0) - add $r5, $r5, $r15 - srli $r9, $r4, #8 - andi $r9, $r9, #1 - sub $r4, $r4, $r9 - slli $r4, $r4, #1 - srli $r4, $r4, #9 - slli $r9, $r5, #23 - or $r4, $r4, $r9 - or $r0, $r4, $r8 - -.LE999: - popm $r6, $r9 - pop $lp - ret5 $lp - -.LEund: - subri $r2, $r5, #1 - slti $r15, $r2, #0x20 - beqzs8 .LEzer - move $r9, #0x80000000 - or $r4, $r4, $r9 - subri $r9, $r2, #0x20 - sll $r5, $r4, $r9 - srl $r4, $r4, $r2 - beqz $r5, .Li10 - ori $r4, $r4, #1 -.Li10: - move $r5, #0 - addi $r9, $r4, #0x80 - sltsi $r15, $r9, #0 - beqzs8 .LElab12 - move $r5, #1 - j .LElab12 - -.LEspecA: - bnez $r5, .Li12 - add $r4, $r4, $r4 - beqz $r4, .Li13 -#ifdef __NDS32_PERF_EXT__ - clz $r8, $r4 -#else - pushm $r0, $r5 - move $r0, $r4 - bal __clzsi2 - move $r8, $r0 - popm $r0, $r5 -#endif - sub $r5, $r5, $r8 - sll $r4, $r4, $r8 - j .LElab1 -.Li13: - subri $r15, $r7, #0xff - beqzs8 .LEspecB - move $r9, #0x80000000 - bne $r1, $r9, .LEretB -.Li12: - add $r9, $r4, $r4 - bnez $r9, .LEnan - subri $r15, $r7, #0xff - bnezs8 .LEretA - xor $r9, $r0, $r1 - sltsi $r15, $r9, #0 - bnezs8 .LEnan - j .LEretB - -.LEspecB: - bnez $r7, .Li15 - add $r6, $r6, $r6 - beqz $r6, .LEretA -#ifdef __NDS32_PERF_EXT__ - clz $r8, $r6 -#else - pushm $r0, $r5 - move $r0, $r6 - bal __clzsi2 - move $r8, $r0 - popm $r0, $r5 -#endif - sub $r7, $r7, $r8 - sll $r6, $r6, $r8 - j .LElab2 -.Li15: - add $r9, $r6, $r6 - bnez $r9, .LEnan - -.LEretB: - move $r0, $r1 - j .LE999 - -.LEretA: - j .LE999 - -.LEzer: - move $r0, #0 - j .LE999 - -.LEnan: - move $r0, #0xffc00000 - j .LE999 - .size __subsf3, .-__subsf3 - .size __addsf3, .-__addsf3 -#endif /* L_addsub_sf */ - - - -#ifdef L_sf_to_si - - .text - .align 2 - .global __fixsfsi - .type __fixsfsi, @function -__fixsfsi: - push $lp - - slli $r1, $r0, #8 - move $r3, #0x80000000 - or $r1, $r1, $r3 - srli $r3, $r0, #23 - andi $r3, $r3, #0xff - subri $r2, $r3, #0x9e - blez $r2, .LJspec - sltsi $r15, $r2, #0x20 - bnezs8 .Li42 - move $r0, #0 - j .LJ999 -.Li42: - srl $r1, $r1, $r2 - sltsi $r15, $r0, #0 - beqzs8 .Li43 - subri $r1, $r1, #0 -.Li43: - move $r0, $r1 - -.LJ999: - pop $lp - ret5 $lp - -.LJspec: - move $r3, #0x7f800000 - slt $r15, $r3, $r0 - beqzs8 .Li44 - move $r0, #0x80000000 - j .LJ999 -.Li44: - move $r0, #0x7fffffff - j .LJ999 - .size __fixsfsi, .-__fixsfsi -#endif /* L_sf_to_si */ - - - -#ifdef L_divsi3 - - .text - .align 2 - .globl __divsi3 - .type __divsi3, @function -__divsi3: - ! --------------------------------------------------------------------- - ! neg = 0; - ! if (a < 0) - ! { a = -a; - ! neg = !neg; - ! } - ! --------------------------------------------------------------------- - sltsi $r5, $r0, 0 ! $r5 <- neg = (a < 0) ? 1 : 0 - subri $r4, $r0, 0 ! $r4 <- a = -a - cmovn $r0, $r4, $r5 ! $r0 <- a = neg ? -a : a -.L2: - ! --------------------------------------------------------------------- - ! if (b < 0) - ! --------------------------------------------------------------------- - bgez $r1, .L3 ! if b >= 0, skip - ! --------------------------------------------------------------------- - ! { b=-b; - ! neg=!neg; - ! } - ! --------------------------------------------------------------------- - subri $r1, $r1, 0 ! $r1 <- b = -b - subri $r5, $r5, 1 ! $r5 <- neg = !neg -.L3: - ! --------------------------------------------------------------------- - !!res = udivmodsi4 (a, b, 1); - ! res = 0; - ! if (den != 0) - ! --------------------------------------------------------------------- - movi $r2, 0 ! $r2 <- res = 0 - beqz $r1, .L1 ! if den == 0, skip - ! --------------------------------------------------------------------- - ! bit = 1; - ! --------------------------------------------------------------------- - movi $r4, 1 ! $r4 <- bit = 1 -#ifndef __OPTIMIZE_SIZE__ -.L6: -#endif - ! --------------------------------------------------------------------- - ! while (den < num && bit && !(den & (1L << 31))) - ! --------------------------------------------------------------------- - slt $ta, $r1, $r0 ! $ta <- den < num ? - beqz $ta, .L5 ! if no, skip - ! --------------------------------------------------------------------- - ! { den << = 1; - ! bit << = 1; - ! } - ! --------------------------------------------------------------------- -#if defined (__OPTIMIZE_SIZE__) && !defined (__NDS32_ISA_V3M__) - clz $r3, $r1 ! $r3 <- leading zero count for den - clz $ta, $r0 ! $ta <- leading zero count for num - sub $r3, $r3, $ta ! $r3 <- number of bits to shift - sll $r1, $r1, $r3 ! $r1 <- den - sll $r4, $r4, $r3 ! $r2 <- bit -#else - slli $r1, $r1, 1 ! $r1 <- den << = 1 - slli $r4, $r4, 1 ! $r4 <- bit << = 1 - b .L6 ! continue loop -#endif -.L5: - ! --------------------------------------------------------------------- - ! while (bit) - ! { if (num >= den) - ! --------------------------------------------------------------------- - slt $ta, $r0, $r1 ! $ta <- num < den ? - bnez $ta, .L9 ! if yes, skip - ! --------------------------------------------------------------------- - ! { num -= den; - ! res |= bit; - ! } - ! --------------------------------------------------------------------- - sub $r0, $r0, $r1 ! $r0 <- num -= den - or $r2, $r2, $r4 ! $r2 <- res |= bit -.L9: - ! --------------------------------------------------------------------- - ! bit >> = 1; - ! den >> = 1; - ! } - !!if (modwanted) - !! return num; - !!return res; - ! --------------------------------------------------------------------- - srli $r4, $r4, 1 ! $r4 <- bit >> = 1 - srli $r1, $r1, 1 ! $r1 <- den >> = 1 - bnez $r4, .L5 ! if bit != 0, continue loop -.L1: - ! --------------------------------------------------------------------- - ! if (neg) - ! res = -res; - ! return res; - ! --------------------------------------------------------------------- - subri $r0, $r2, 0 ! $r0 <- -res - cmovz $r0, $r2, $r5 ! $r0 <- neg ? -res : res - ! --------------------------------------------------------------------- - ret - .size __divsi3, .-__divsi3 -#endif /* L_divsi3 */ - - - -#ifdef L_divdi3 - - !-------------------------------------- - #ifdef __big_endian__ - #define V1H $r0 - #define V1L $r1 - #define V2H $r2 - #define V2L $r3 - #else - #define V1H $r1 - #define V1L $r0 - #define V2H $r3 - #define V2L $r2 - #endif - !-------------------------------------- - .text - .align 2 - .globl __divdi3 - .type __divdi3, @function -__divdi3: - ! prologue -#ifdef __NDS32_ISA_V3M__ - push25 $r10, 0 -#else - smw.adm $r6, [$sp], $r10, 2 -#endif - ! end of prologue - move $r8, V1L - move $r9, V1H - move $r6, V2L - move $r7, V2H - movi $r10, 0 - bgez V1H, .L80 - bal __negdi2 - move $r8, V1L - move $r9, V1H - movi $r10, -1 -.L80: - bgez $r7, .L81 - move V1L, $r6 - move V1H, $r7 - bal __negdi2 - move $r6, V1L - move $r7, V1H - nor $r10, $r10, $r10 -.L81: - move V2L, $r6 - move V2H, $r7 - move V1L, $r8 - move V1H, $r9 - movi $r4, 0 - bal __udivmoddi4 - beqz $r10, .L82 - bal __negdi2 -.L82: - ! epilogue -#ifdef __NDS32_ISA_V3M__ - pop25 $r10, 0 -#else - lmw.bim $r6, [$sp], $r10, 2 - ret -#endif - .size __divdi3, .-__divdi3 -#endif /* L_divdi3 */ - - - -#ifdef L_modsi3 - - .text - .align 2 - .globl __modsi3 - .type __modsi3, @function -__modsi3: - ! --------------------------------------------------------------------- - ! neg=0; - ! if (a<0) - ! { a=-a; - ! neg=1; - ! } - ! --------------------------------------------------------------------- - sltsi $r5, $r0, 0 ! $r5 <- neg < 0 ? 1 : 0 - subri $r4, $r0, 0 ! $r4 <- -a - cmovn $r0, $r4, $r5 ! $r0 <- |a| - ! --------------------------------------------------------------------- - ! if (b < 0) -#ifndef __NDS32_PERF_EXT__ - ! --------------------------------------------------------------------- - bgez $r1, .L3 ! if b >= 0, skip - ! --------------------------------------------------------------------- - ! b = -b; - ! --------------------------------------------------------------------- - subri $r1, $r1, 0 ! $r1 <- |b| -.L3: - ! --------------------------------------------------------------------- - !!res = udivmodsi4 (a, b, 1); - ! if (den != 0) - ! --------------------------------------------------------------------- -#else /* __NDS32_PERF_EXT__ */ - ! b = -b; - !!res = udivmodsi4 (a, b, 1); - ! if (den != 0) - ! --------------------------------------------------------------------- - abs $r1, $r1 ! $r1 <- |b| -#endif /* __NDS32_PERF_EXT__ */ - beqz $r1, .L1 ! if den == 0, skip - ! --------------------------------------------------------------------- - ! { bit = 1; - ! res = 0; - ! --------------------------------------------------------------------- - movi $r4, 1 ! $r4 <- bit = 1 -#ifndef __OPTIMIZE_SIZE__ -.L6: -#endif - ! --------------------------------------------------------------------- - ! while (den < num&&bit && !(den & (1L << 31))) - ! --------------------------------------------------------------------- - slt $ta, $r1, $r0 ! $ta <- den < num ? - beqz $ta, .L5 ! if no, skip - ! --------------------------------------------------------------------- - ! { den << = 1; - ! bit << = 1; - ! } - ! --------------------------------------------------------------------- -#if defined (__OPTIMIZE_SIZE__) && ! defined (__NDS32_ISA_V3M__) - clz $r3, $r1 ! $r3 <- leading zero count for den - clz $ta, $r0 ! $ta <- leading zero count for num - sub $r3, $r3, $ta ! $r3 <- number of bits to shift - sll $r1, $r1, $r3 ! $r1 <- den - sll $r4, $r4, $r3 ! $r2 <- bit -#else - slli $r1, $r1, 1 ! $r1 <- den << = 1 - slli $r4, $r4, 1 ! $r4 <- bit << = 1 - b .L6 ! continue loop -#endif -.L5: - ! --------------------------------------------------------------------- - ! while (bit) - ! { if (num >= den) - ! { num -= den; - ! res |= bit; - ! } - ! bit >> = 1; - ! den >> = 1; - ! } - ! } - !!if (modwanted) - !! return num; - !!return res; - ! --------------------------------------------------------------------- - sub $r2, $r0, $r1 ! $r2 <- num - den - slt $ta, $r0, $r1 ! $ta <- num < den ? - srli $r4, $r4, 1 ! $r4 <- bit >> = 1 - cmovz $r0, $r2, $ta ! $r0 <- num = (num < den) ? num : num - den - srli $r1, $r1, 1 ! $r1 <- den >> = 1 - bnez $r4, .L5 ! if bit != 0, continue loop -.L1: - ! --------------------------------------------------------------------- - ! if (neg) - ! res = -res; - ! return res; - ! --------------------------------------------------------------------- - subri $r3, $r0, 0 ! $r3 <- -res - cmovn $r0, $r3, $r5 ! $r0 <- neg ? -res : res - ! --------------------------------------------------------------------- - ret - .size __modsi3, .-__modsi3 -#endif /* L_modsi3 */ - - - -#ifdef L_moddi3 - - !-------------------------------------- - #ifdef __big_endian__ - #define V1H $r0 - #define V1L $r1 - #define V2H $r2 - #define V2L $r3 - #else - #define V1H $r1 - #define V1L $r0 - #define V2H $r3 - #define V2L $r2 - #endif - !-------------------------------------- - .text - .align 2 - .globl __moddi3 - .type __moddi3, @function -__moddi3: - ! ===================================================================== - ! stack allocation: - ! sp+32 +-----------------------+ - ! | $lp | - ! sp+28 +-----------------------+ - ! | $r6 - $r10 | - ! sp+8 +-----------------------+ - ! | | - ! sp+4 +-----------------------+ - ! | | - ! sp +-----------------------+ - ! ===================================================================== - ! prologue -#ifdef __NDS32_ISA_V3M__ - push25 $r10, 8 -#else - smw.adm $r6, [$sp], $r10, 2 - addi $sp, $sp, -8 -#endif - ! end of prologue - !------------------------------------------ - ! __moddi3 (DWtype u, DWtype v) - ! { - ! word_type c = 0; - ! DWunion uu = {.ll = u}; - ! DWunion vv = {.ll = v}; - ! DWtype w; - ! if (uu.s.high < 0) - ! c = ~c, - ! uu.ll = -uu.ll; - !--------------------------------------------- - move $r8, V1L - move $r9, V1H - move $r6, V2L - move $r7, V2H - movi $r10, 0 ! r10 = c = 0 - bgez V1H, .L80 ! if u > 0 , go L80 - bal __negdi2 - move $r8, V1L - move $r9, V1H - movi $r10, -1 ! r10 = c = ~c - !------------------------------------------------ - ! if (vv.s.high < 0) - ! vv.ll = -vv.ll; - !---------------------------------------------- -.L80: - bgez $r7, .L81 ! if v > 0 , go L81 - move V1L, $r6 - move V1H, $r7 - bal __negdi2 - move $r6, V1L - move $r7, V1H - !------------------------------------------ - ! (void) __udivmoddi4 (uu.ll, vv.ll, &w); - ! if (c) - ! w = -w; - ! return w; - !----------------------------------------- -.L81: - move V2L, $r6 - move V2H, $r7 - move V1L, $r8 - move V1H, $r9 - addi $r4, $sp, 0 - bal __udivmoddi4 - lwi $r0, [$sp+(0)] ! le: sp + 0 is low, be: sp + 0 is high - lwi $r1, [$sp+(4)] ! le: sp + 4 is low, be: sp + 4 is high - beqz $r10, .L82 - bal __negdi2 -.L82: - ! epilogue -#ifdef __NDS32_ISA_V3M__ - pop25 $r10, 8 -#else - addi $sp, $sp, 8 - lmw.bim $r6, [$sp], $r10, 2 - ret -#endif - .size __moddi3, .-__moddi3 -#endif /* L_moddi3 */ - - - -#ifdef L_mulsi3 - - .text - .align 2 - .globl __mulsi3 - .type __mulsi3, @function -__mulsi3: - ! --------------------------------------------------------------------- - ! r = 0; - ! while (a) - ! $r0: r - ! $r1: b - ! $r2: a - ! --------------------------------------------------------------------- - beqz $r0, .L7 ! if a == 0, done - move $r2, $r0 ! $r2 <- a - movi $r0, 0 ! $r0 <- r <- 0 -.L8: - ! --------------------------------------------------------------------- - ! { if (a & 1) - ! r += b; - ! a >> = 1; - ! b << = 1; - ! } - ! $r0: r - ! $r1: b - ! $r2: a - ! $r3: scratch - ! $r4: scratch - ! --------------------------------------------------------------------- - andi $r3, $r2, 1 ! $r3 <- a & 1 - add $r4, $r0, $r1 ! $r4 <- r += b - cmovn $r0, $r4, $r3 ! $r0 <- r - srli $r2, $r2, 1 ! $r2 <- a >> = 1 - slli $r1, $r1, 1 ! $r1 <- b << = 1 - bnez $r2, .L8 ! if a != 0, continue loop -.L7: - ! --------------------------------------------------------------------- - ! $r0: return code - ! --------------------------------------------------------------------- - ret - .size __mulsi3, .-__mulsi3 -#endif /* L_mulsi3 */ - - - -#ifdef L_udivsi3 - - .text - .align 2 - .globl __udivsi3 - .type __udivsi3, @function -__udivsi3: - ! --------------------------------------------------------------------- - !!res=udivmodsi4(a,b,0); - ! res=0; - ! if (den!=0) - ! --------------------------------------------------------------------- - movi $r2, 0 ! $r2 <- res=0 - beqz $r1, .L1 ! if den==0, skip - ! --------------------------------------------------------------------- - ! { bit=1; - ! --------------------------------------------------------------------- - movi $r4, 1 ! $r4 <- bit=1 -#ifndef __OPTIMIZE_SIZE__ -.L6: -#endif - ! --------------------------------------------------------------------- - ! while (den=den) - ! --------------------------------------------------------------------- - slt $ta, $r0, $r1 ! $ta <- num>=1; - ! den>>=1; - ! } - ! } - !!if (modwanted) - !! return num; - !!return res; - ! --------------------------------------------------------------------- - srli $r4, $r4, 1 ! $r4 <- bit>>=1 - srli $r1, $r1, 1 ! $r1 <- den>>=1 - bnez $r4, .L5 ! if bit!=0, continue loop -.L1: - ! --------------------------------------------------------------------- - ! return res; - ! --------------------------------------------------------------------- - move $r0, $r2 ! $r0 <- return value - ! --------------------------------------------------------------------- - ! --------------------------------------------------------------------- - ret - .size __udivsi3, .-__udivsi3 -#endif /* L_udivsi3 */ - - - -#ifdef L_udivdi3 - - !-------------------------------------- - #ifdef __big_endian__ - #define V1H $r0 - #define V1L $r1 - #define V2H $r2 - #define V2L $r3 - #else - #define V1H $r1 - #define V1L $r0 - #define V2H $r3 - #define V2L $r2 - #endif - !-------------------------------------- - - .text - .align 2 - .globl __udivdi3 - .type __udivdi3, @function -__udivdi3: - ! prologue -#ifdef __NDS32_ISA_V3M__ - push25 $r8, 0 -#else - smw.adm $r6, [$sp], $r8, 2 -#endif - ! end of prologue - movi $r4, 0 - bal __udivmoddi4 - ! epilogue -#ifdef __NDS32_ISA_V3M__ - pop25 $r8, 0 -#else - lmw.bim $r6, [$sp], $r8, 2 - ret -#endif - .size __udivdi3, .-__udivdi3 -#endif /* L_udivdi3 */ - - - -#ifdef L_udivmoddi4 - - .text - .align 2 - .globl fudiv_qrnnd - .type fudiv_qrnnd, @function - #ifdef __big_endian__ - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 - #define W6H $r4 - #define W6L $r5 - #define OFFSET_L 4 - #define OFFSET_H 0 - #else - #define P1H $r1 - #define P1L $r0 - #define P2H $r3 - #define P2L $r2 - #define W6H $r5 - #define W6L $r4 - #define OFFSET_L 0 - #define OFFSET_H 4 - #endif -fudiv_qrnnd: - !------------------------------------------------------ - ! function: fudiv_qrnnd(quotient, remainder, high_numerator, low_numerator, denominator) - ! divides a UDWtype, composed by the UWtype integers,HIGH_NUMERATOR (from $r4) - ! and LOW_NUMERATOR(from $r5) by DENOMINATOR(from $r6), and places the quotient - ! in $r7 and the remainder in $r8. - !------------------------------------------------------ - ! in reg:$r4(n1), $r5(n0), $r6(d0) - ! __d1 = ((USItype) (d) >> ((4 * 8) / 2)); - ! __d0 = ((USItype) (d) & (((USItype) 1 << ((4 * 8) / 2)) - 1)); - ! __r1 = (n1) % __d1; - ! __q1 = (n1) / __d1; - ! __m = (USItype) __q1 * __d0; - ! __r1 = __r1 * ((USItype) 1 << ((4 * 8) / 2)) | ((USItype) (n0) >> ((4 * 8) / 2)); - ! if (__r1 < __m) - ! { - !------------------------------------------------------ - smw.adm $r0, [$sp], $r4, 2 ! store $lp, when use BASELINE_V1,and must store $r0-$r3 - srli $r7, $r6, 16 ! $r7 = d1 =__ll_highpart (d) - movi $ta, 65535 - and $r8, $r6, $ta ! $r8 = d0 = __ll_lowpart (d) - - divr $r9, $r10, $r4, $r7 ! $r9 = q1, $r10 = r1 - and $r4, $r5, $ta ! $r4 = __ll_lowpart (n0) - slli $r10, $r10, 16 ! $r10 = r1 << 16 - srli $ta, $r5, 16 ! $ta = __ll_highpart (n0) - - or $r10, $r10, $ta ! $r10 <- $r0|$r3=__r1 - mul $r5, $r9, $r8 ! $r5 = m = __q1*__d0 - slt $ta, $r10, $r5 ! $ta <- __r1<__m - beqz $ta, .L2 !if yes,skip - !------------------------------------------------------ - ! __q1--, __r1 += (d); - ! if (__r1 >= (d)) - ! { - !------------------------------------------------------ - - add $r10, $r10, $r6 !$r10 <- __r1+d=__r1 - addi $r9, $r9, -1 !$r9 <- __q1--=__q1 - slt $ta, $r10, $r6 !$ta <- __r1= (d)) - ! { - !------------------------------------------------------ - - add $r10, $r10, $r6 !$r10 <- __r0+d=__r0 - addi $r7, $r7, -1 !$r7 <- __q0--=__q0 - slt $ta, $r10, $r6 !$ta <- __r0 n1) - ! { - !------------------------------------------------------ - - slt $ta, P1H, P2L !$ta <- n1> ((4 * 8) - bm)); - ! n0 = n0 << bm; - ! } - !------------------------------------------------------ - - subri $r5, $r7, 32 !$r5 <- 32-bm - srl $r5, P1L, $r5 !$r5 <- n0>>$r5 - sll $r6, P1H, $r7 !$r6 <- n1< n1) - !------------------------------------------------------ - - move $r4,P1H ! give fudiv_qrnnd args - move $r5,P1L ! - move $r6,P2L ! - bal fudiv_qrnnd !calcaulte q0 n0 - movi $r6, 0 !P1L <- 0 - swi $r7,[$sp+32] !q0 - swi $r6,[$sp+36] !q1 - move P1L,$r8 !n0 - b .L19 -.L10: - !------------------------------------------------------ - ! else #if (d0 > n1) - ! { - ! if(d0 == 0) - !------------------------------------------------------ - - bnez P2L, .L20 !if yes,skip - !------------------------------------------------------ - ! d0 = 1 / d0; - !------------------------------------------------------ - - movi $r4, 1 !P1L <- 1 - divr P2L, $r4, $r4, P2L !$r9=1/d0,P1L=1%d0 -.L20: - -#ifndef __NDS32_PERF_EXT__ - smw.adm $r0, [$sp], $r5, 0 - move $r0, P2L - bal __clzsi2 - move $r7, $r0 - lmw.bim $r0, [$sp], $r5, 0 -#else - clz $r7, P2L -#endif - swi $r7,[$sp+(28)] ! store bm - beqz $r7, .L28 ! if yes,skip - !------------------------------------------------------ - ! b = (4 * 8) - bm; - ! d0 = d0 << bm; - ! n2 = n1 >> b; - ! n1 = (n1 << bm) | (n0 >> b); - ! n0 = n0 << bm; - ! fudiv_qrnnd (&q1, &n1, n2, n1, d0); - ! } - !------------------------------------------------------ - - subri $r10, $r7, 32 !$r10 <- 32-bm=b - srl $r4, P1L, $r10 !$r4 <- n0>>b - sll $r5, P1H, $r7 !$r5 <- n1<>b=n2 !for fun - - move $r6,P2L !for fun - bal fudiv_qrnnd !caculate q1, n1 - - swi $r7,[$sp+(36)] ! q1 store - move P1H,$r8 ! n1 store - - move $r4,$r8 ! prepare for next fudiv_qrnnd() - move $r5,P1L - move $r6,P2L - b .L29 -.L28: - !------------------------------------------------------ - ! else // bm != 0 - ! { - ! n1 -= d0; - ! q1 = 1; - ! - !------------------------------------------------------ - - sub P1H, P1H, P2L !P1L <- n1-d0=n1 - movi $ta, 1 ! - swi $ta, [$sp+(36)] !1 -> [$sp+(36)] - - move $r4,P1H ! give fudiv_qrnnd args - move $r5,P1L - move $r6,P2L -.L29: - !------------------------------------------------------ - ! fudiv_qrnnd (&q0, &n0, n1, n0, d0); - !------------------------------------------------------ - - bal fudiv_qrnnd !calcuate q0, n0 - swi $r7,[$sp+(32)] !q0 store - move P1L,$r8 !n0 -.L19: - !------------------------------------------------------ - ! if (rp != 0) - ! { - !------------------------------------------------------ - - beqz $fp, .L31 !if yes,skip - !------------------------------------------------------ - ! rr.s.low = n0 >> bm; - ! rr.s.high = 0; - ! *rp = rr.ll; - ! } - !------------------------------------------------------ - - movi $r5, 0 !$r5 <- 0 - lwi $r7,[$sp+(28)] !load bm - srl $r4, P1L, $r7 !$r4 <- n0>>bm - swi $r4, [$fp+OFFSET_L] !r0 !$r4 -> [$sp+(48)] - swi $r5, [$fp+OFFSET_H] !r1 !0 -> [$sp+(52)] - b .L31 -.L9: - !------------------------------------------------------ - ! else # d1 == 0 - ! { - ! if(d1 > n1) - ! { - !------------------------------------------------------ - - slt $ta, P1H, P2H !$ta <- n1 [$sp+(40)]=q1 - swi $r5, [$sp+(36)] !q1 !0 -> [$sp+(32)]=q0 - beqz $fp, .L31 !if yes,skip - !------------------------------------------------------ - ! rr.s.low = n0; - ! rr.s.high = n1; - ! *rp = rr.ll; - ! } - !------------------------------------------------------ - - swi P1L, [$fp+OFFSET_L] !P1L -> [rp] - swi P1H, [$fp+OFFSET_H] !P1H -> [rp+4] - b .L31 -.L32: -#ifndef __NDS32_PERF_EXT__ - smw.adm $r0, [$sp], $r5, 0 - move $r0, P2H - bal __clzsi2 - move $r7, $r0 - lmw.bim $r0, [$sp], $r5, 0 -#else - clz $r7,P2H -#endif - swi $r7,[$sp+(28)] !$r7=bm store - beqz $r7, .L42 !if yes,skip - !------------------------------------------------------ - ! USItype m1, m0; - ! b = (4 * 8) - bm; - ! d1 = (d0 >> b) | (d1 << bm); - ! d0 = d0 << bm; - ! n2 = n1 >> b; - ! n1 = (n0 >> b) | (n1 << bm); - ! n0 = n0 << bm; - ! fudiv_qrnnd (&q0, &n1, n2, n1, d1); - !------------------------------------------------------ - - subri $r10, $r7, 32 !$r10 <- 32-bm=b - srl $r5, P2L, $r10 !$r5 <- d0>>b - sll $r6, P2H, $r7 !$r6 <- d1<>b=n2 !!! func - srl $r8, P1L, $r10 !$r8 <- n0>>b !!$r8 - sll $r9, P1H, $r7 !$r9 <- n1<> ((4 * 8) / 2)); - ! __vl = ((USItype) (d0) & (((USItype) 1 << ((4 * 8) / 2)) - 1)); - ! __vh = ((USItype) (d0) >> ((4 * 8) / 2)); - ! __x0 = (USItype) __ul * __vl; - ! __x1 = (USItype) __ul * __vh; - ! __x2 = (USItype) __uh * __vl; - ! __x3 = (USItype) __uh * __vh; - ! __x1 += ((USItype) (__x0) >> ((4 * 8) / 2)); - ! __x1 += __x2; - ! if (__x1 < __x2) - ! __x3 += ((USItype) 1 << ((4 * 8) / 2)); - ! (m1) = __x3 + ((USItype) (__x1) >> ((4 * 8) / 2)); - ! (m0) = (USItype)(q0*d0); - ! } - ! if (m1 > n1) - !--------------------------------------------------- -#ifdef __NDS32_ISA_V3M__ - !mulr64 $r4, P2L, $r6 - smw.adm $r0, [$sp], $r3, 0 - move P1L, P2L - move P2L, $r6 - movi P1H, 0 - movi P2H, 0 - bal __muldi3 - movd44 $r4, $r0 - lmw.bim $r0, [$sp], $r3, 0 - move $r8, W6H - move $r5, W6L -#else - mulr64 $r4, P2L, $r6 - move $r8, W6H - move $r5, W6L -#endif - slt $ta, P1H, $r8 !$ta <- n1 n0) - !------------------------------------------------------ - - slt $ta, P1L, $r5 !$ta <- n0 (m0)); - ! (m0) = __x; - ! } - ! } - !------------------------------------------------------ - - sub $r4, $r5, P2L !$r4 <- m0-d0=__x - addi $r6, $r6, -1 !$r6 <- q0--=q0 - sub $r8, $r8, P2H !$r8 <- m1-d1 - swi $r6, [$sp+(32)] ! q0 !$r6->[$sp+(32)] - slt $ta, $r5, $r4 !$ta <- m0<__x - sub $r8, $r8, $ta !$r8 <- P1H-P1L=m1 - move $r5, $r4 !$r5 <- __x=m0 -.L45: - !------------------------------------------------------ - ! q1 = 0; - ! if (rp != 0) - ! { - !------------------------------------------------------ - - movi $r4, 0 !$r4 <- 0 - swi $r4, [$sp+(36)] !0 -> [$sp+(40)]=q1 - beqz $fp, .L31 !if yes,skip - !------------------------------------------------------ - ! # sub_ddmmss (n1, n0, n1, n0, m1, m0); - ! do - ! { USItype __x; - ! __x = (n0) - (m0); - ! (n1) = (n1) - (m1) - (__x > (n0)); - ! (n0) = __x; - ! } - ! rr.s.low = (n1 << b) | (n0 >> bm); - ! rr.s.high = n1 >> bm; - ! *rp = rr.ll; - !------------------------------------------------------ - - sub $r4, P1H, $r8 !$r4 <- n1-m1 - sub $r6, P1L, $r5 !$r6 <- n0-m0=__x=n0 - slt $ta, P1L, $r6 !$ta <- n0<__x - sub P1H, $r4, $ta !P1H <- $r4-$ta=n1 - move P1L, $r6 - - lwi $r7,[$sp+(28)] ! load bm - subri $r10,$r7,32 - sll $r4, P1H, $r10 !$r4 <- n1<>bm - or $r6, $r5, $r4 !$r6 <- $r5|$r4=rr.s.low - srl $r8, P1H, $r7 !$r8 <- n1>>bm =rr.s.high - swi $r6, [$fp+OFFSET_L] ! - swi $r8, [$fp+OFFSET_H] ! - b .L31 -.L42: - !------------------------------------------------------ - ! else - ! { - ! if(n1 > d1) - !------------------------------------------------------ - - slt $ta, P2H, P1H !$ta <- P2H= d0) - !------------------------------------------------------ - - slt $ta, P1L, P2L !$ta <- P1L (n0)); - ! (n0) = __x; - ! } - !------------------------------------------------------ -.L52: - sub $r4, P1H, P2H !$r4 <- P1H-P2H - sub $r6, P1L, P2L !$r6 <- no-d0=__x=n0 - slt $ta, P1L, $r6 !$ta <- no<__x - sub P1H, $r4, $ta !P1H <- $r4-$ta=n1 - move P1L, $r6 !n0 - movi $r5, 1 ! - swi $r5, [$sp+(32)] !1 -> [$sp+(32)]=q0 - b .L54 -.L51: - !------------------------------------------------------ - ! q0 = 0; - !------------------------------------------------------ - - movi $r5,0 - swi $r5, [$sp+(32)] !$r5=0 -> [$sp+(32)] -.L54: - !------------------------------------------------------ - ! q1 = 0; - ! if (rp != 0) - ! { - !------------------------------------------------------ - - movi $r5, 0 ! - swi $r5, [$sp+(36)] !0 -> [$sp+(36)] - beqz $fp, .L31 - !------------------------------------------------------ - ! rr.s.low = n0; - ! rr.s.high = n1; - ! *rp = rr.ll; - ! } - !------------------------------------------------------ - - swi P1L, [$fp+OFFSET_L] !remainder - swi P1H, [$fp+OFFSET_H] ! -.L31: - !------------------------------------------------------ - ! const DWunion ww = {{.low = q0, .high = q1}}; - ! return ww.ll; - !} - !------------------------------------------------------ - - lwi P1L, [$sp+(32)] !quotient - lwi P1H, [$sp+(36)] - lmw.bim $r6, [$sp], $r10, 10 - addi $sp, $sp, 12 - ret - .size __udivmoddi4, .-__udivmoddi4 -#endif /* L_udivmoddi4 */ - - - -#ifdef L_umodsi3 - - ! ===================================================================== - .text - .align 2 - .globl __umodsi3 - .type __umodsi3, @function -__umodsi3: - ! --------------------------------------------------------------------- - !!res=udivmodsi4(a,b,1); - ! if (den==0) - ! return num; - ! --------------------------------------------------------------------- - beqz $r1, .L1 ! if den==0, skip - ! --------------------------------------------------------------------- - ! bit=1; - ! res=0; - ! --------------------------------------------------------------------- - movi $r4, 1 ! $r4 <- bit=1 -#ifndef __OPTIMIZE_SIZE__ -.L6: -#endif - ! --------------------------------------------------------------------- - ! while (den=den) - ! { num-=den; - ! res|=bit; - ! } - ! bit>>=1; - ! den>>=1; - ! } - !!if (modwanted) - !! return num; - !!return res; - ! --------------------------------------------------------------------- - sub $r2, $r0, $r1 ! $r2 <- num-den - slt $ta, $r0, $r1 ! $ta <- num>=1 - cmovz $r0, $r2, $ta ! $r0 <- num=(num>=1 - bnez $r4, .L5 ! if bit!=0, continue loop -.L1: - ! --------------------------------------------------------------------- - ! return res; - ! --------------------------------------------------------------------- - ret - .size __umodsi3, .-__umodsi3 -#endif /* L_umodsi3 */ - - - -#ifdef L_umoddi3 - - !-------------------------------------- - #ifdef __big_endian__ - #define V1H $r0 - #define V1L $r1 - #define V2H $r2 - #define V2L $r3 - #else - #define V1H $r1 - #define V1L $r0 - #define V2H $r3 - #define V2L $r2 - #endif - !-------------------------------------- - .text - .align 2 - .globl __umoddi3 - .type __umoddi3, @function -__umoddi3: - ! prologue - addi $sp, $sp, -12 - swi $lp, [$sp+(0)] - ! end of prologue - addi $r4, $sp, 4 - bal __udivmoddi4 - lwi $r0, [$sp+(4)] ! __udivmoddi4 return low when LE mode or return high when BE mode - lwi $r1, [$sp+(8)] ! -.L82: - ! epilogue - lwi $lp, [$sp+(0)] - addi $sp, $sp, 12 - ret - .size __umoddi3, .-__umoddi3 -#endif /* L_umoddi3 */ - - - -#ifdef L_muldi3 - -#ifdef __big_endian__ - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 - - #define V2H $r4 - #define V2L $r5 -#else - #define P1H $r1 - #define P1L $r0 - #define P2H $r3 - #define P2L $r2 - - #define V2H $r5 - #define V2L $r4 -#endif - - ! ==================================================================== - .text - .align 2 - .globl __muldi3 - .type __muldi3, @function -__muldi3: - ! parameter passing for libgcc functions normally involves 2 doubles - !--------------------------------------- -#ifdef __NDS32_ISA_V3M__ - ! There is no mulr64 instruction in Andes ISA V3M. - ! So we must provide a sequence of calculations to complete the job. - smw.adm $r6, [$sp], $r9, 0x0 - zeh33 $r4, P1L - srli $r7, P1L, 16 - zeh33 $r5, P2L - mul $r6, $r5, $r4 - mul33 $r5, $r7 - srli $r8, P2L, 16 - mov55 $r9, $r5 - maddr32 $r9, $r8, $r4 - srli $r4, $r6, 16 - add $r4, $r9, $r4 - slt45 $r4, $r5 - slli $r5, $r15, 16 - maddr32 $r5, $r8, $r7 - mul P2L, P1H, P2L - srli $r7, $r4, 16 - maddr32 P2L, P2H, P1L - add333 P1H, $r5, $r7 - slli $r4, $r4, 16 - zeh33 $r6, $r6 - add333 P1L, $r4, $r6 - add333 P1H, P2L, P1H - lmw.bim $r6, [$sp], $r9, 0x0 - ret -#else /* not __NDS32_ISA_V3M__ */ - mul $ta, P1L, P2H - mulr64 $r4, P1L, P2L - maddr32 $ta, P1H, P2L - move P1L, V2L - add P1H, $ta, V2H - ret -#endif /* not __NDS32_ISA_V3M__ */ - .size __muldi3, .-__muldi3 -#endif /* L_muldi3 */ - - - -#ifdef L_addsub_df - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 - #define P2L $r2 - #define P2H $r3 - #define P3L $r4 - #define P3H $r5 - #define O1L $r7 - #define O1H $r8 -#else - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 - #define P3H $r4 - #define P3L $r5 - #define O1H $r7 - #define O1L $r8 -#endif - .text - .align 2 - .global __subdf3 - .type __subdf3, @function -__subdf3: - push $lp - pushm $r6, $r10 - - move $r4, #0x80000000 - xor P2H, P2H, $r4 - - j .Lsdpadd - - .global __adddf3 - .type __adddf3, @function -__adddf3: - push $lp - pushm $r6, $r10 -.Lsdpadd: - slli $r6, P1H, #1 - srli $r6, $r6, #21 - slli P3H, P1H, #11 - srli $r10, P1L, #21 - or P3H, P3H, $r10 - slli P3L, P1L, #11 - move O1L, #0x80000000 - or P3H, P3H, O1L - slli $r9, P2H, #1 - srli $r9, $r9, #21 - slli O1H, P2H, #11 - srli $r10, P2L, #21 - or O1H, O1H, $r10 - or O1H, O1H, O1L - slli O1L, P2L, #11 - - addi $r10, $r6, #-1 - slti $r15, $r10, #0x7fe - beqzs8 .LEspecA - -.LElab1: - addi $r10, $r9, #-1 - slti $r15, $r10, #0x7fe - beqzs8 .LEspecB - -.LElab2: - #NORMd($r4, P2L, P1L) - bnez P3H, .LL1 - bnez P3L, .LL2 - move $r6, #0 - j .LL3 -.LL2: - move P3H, P3L - move P3L, #0 - move P2L, #32 - sub $r6, $r6, P2L -.LL1: -#ifndef __big_endian__ -#ifdef __NDS32_PERF_EXT__ - clz $r2, $r5 -#else - pushm $r0, $r1 - pushm $r3, $r5 - move $r0, $r5 - bal __clzsi2 - move $r2, $r0 - popm $r3, $r5 - popm $r0, $r1 -#endif -#else /* __big_endian__ */ -#ifdef __NDS32_PERF_EXT__ - clz $r3, $r4 -#else - pushm $r0, $r2 - pushm $r4, $r5 - move $r0, $r4 - bal __clzsi2 - move $r3, $r0 - popm $r4, $r5 - popm $r0, $r2 -#endif -#endif /* __big_endian__ */ - beqz P2L, .LL3 - sub $r6, $r6, P2L - subri P1L, P2L, #32 - srl P1L, P3L, P1L - sll P3L, P3L, P2L - sll P3H, P3H, P2L - or P3H, P3H, P1L -.LL3: - #NORMd End - - #NORMd($r7, P2L, P1L) - bnez O1H, .LL4 - bnez O1L, .LL5 - move $r9, #0 - j .LL6 -.LL5: - move O1H, O1L - move O1L, #0 - move P2L, #32 - sub $r9, $r9, P2L -.LL4: -#ifndef __big_endian__ -#ifdef __NDS32_PERF_EXT__ - clz $r2, O1H -#else - pushm $r0, $r1 - pushm $r3, $r5 - move $r0, O1H - bal __clzsi2 - move $r2, $r0 - popm $r3, $r5 - popm $r0, $r1 -#endif -#else /* __big_endian__ */ -#ifdef __NDS32_PERF_EXT__ - clz $r3, O1H -#else - pushm $r0, $r2 - pushm $r4, $r5 - move $r0, O1H - bal __clzsi2 - move $r3, $r0 - popm $r4, $r5 - popm $r0, $r2 -#endif -#endif /* __big_endian__ */ - beqz P2L, .LL6 - sub $r9, $r9, P2L - subri P1L, P2L, #32 - srl P1L, O1L, P1L - sll O1L, O1L, P2L - sll O1H, O1H, P2L - or O1H, O1H, P1L -.LL6: - #NORMd End - - move $r10, #0x80000000 - and P1H, P1H, $r10 - - beq $r6, $r9, .LEadd3 - slts $r15, $r9, $r6 - beqzs8 .Li1 - sub $r9, $r6, $r9 - move P2L, #0 -.LL7: - move $r10, #0x20 - slt $r15, $r9, $r10 - bnezs8 .LL8 - or P2L, P2L, O1L - move O1L, O1H - move O1H, #0 - addi $r9, $r9, #0xffffffe0 - bnez O1L, .LL7 -.LL8: - beqz $r9, .LEadd3 - move P1L, O1H - move $r10, O1L - srl O1L, O1L, $r9 - srl O1H, O1H, $r9 - subri $r9, $r9, #0x20 - sll P1L, P1L, $r9 - or O1L, O1L, P1L - sll $r10, $r10, $r9 - or P2L, P2L, $r10 - beqz P2L, .LEadd3 - ori O1L, O1L, #1 - j .LEadd3 -.Li1: - move $r15, $r6 - move $r6, $r9 - sub $r9, $r9, $r15 - move P2L, #0 -.LL10: - move $r10, #0x20 - slt $r15, $r9, $r10 - bnezs8 .LL11 - or P2L, P2L, P3L - move P3L, P3H - move P3H, #0 - addi $r9, $r9, #0xffffffe0 - bnez P3L, .LL10 -.LL11: - beqz $r9, .LEadd3 - move P1L, P3H - move $r10, P3L - srl P3L, P3L, $r9 - srl P3H, P3H, $r9 - subri $r9, $r9, #0x20 - sll P1L, P1L, $r9 - or P3L, P3L, P1L - sll $r10, $r10, $r9 - or P2L, P2L, $r10 - beqz P2L, .LEadd3 - ori P3L, P3L, #1 - -.LEadd3: - xor $r10, P1H, P2H - sltsi $r15, $r10, #0 - bnezs8 .LEsub1 - - #ADD(P3L, O1L) - add P3L, P3L, O1L - slt $r15, P3L, O1L - - #ADDCC(P3H, O1H) - beqzs8 .LL13 - add P3H, P3H, O1H - slt $r15, P3H, O1H - beqzs8 .LL14 - addi P3H, P3H, #0x1 - j .LL15 -.LL14: - move $r15, #1 - add P3H, P3H, $r15 - slt $r15, P3H, $r15 - j .LL15 -.LL13: - add P3H, P3H, O1H - slt $r15, P3H, O1H -.LL15: - - beqzs8 .LEres - andi $r10, P3L, #1 - beqz $r10, .Li3 - ori P3L, P3L, #2 -.Li3: - srli P3L, P3L, #1 - slli $r10, P3H, #31 - or P3L, P3L, $r10 - srli P3H, P3H, #1 - move $r10, #0x80000000 - or P3H, P3H, $r10 - addi $r6, $r6, #1 - subri $r15, $r6, #0x7ff - bnezs8 .LEres - move $r10, #0x7ff00000 - or P1H, P1H, $r10 - move P1L, #0 - j .LEretA - -.LEsub1: - #SUB(P3L, O1L) - move $r15, P3L - sub P3L, P3L, O1L - slt $r15, $r15, P3L - - #SUBCC(P3H, O1H) - beqzs8 .LL16 - move $r15, P3H - sub P3H, P3H, O1H - slt $r15, $r15, P3H - beqzs8 .LL17 - subi333 P3H, P3H, #1 - j .LL18 -.LL17: - move $r15, P3H - subi333 P3H, P3H, #1 - slt $r15, $r15, P3H - j .LL18 -.LL16: - move $r15, P3H - sub P3H, P3H, O1H - slt $r15, $r15, P3H -.LL18: - - beqzs8 .Li5 - move $r10, #0x80000000 - xor P1H, P1H, $r10 - - subri P3H, P3H, #0 - beqz P3L, .LL19 - subri P3L, P3L, #0 - subi45 P3H, #1 -.LL19: - -.Li5: - #NORMd($r4, $r9, P1L) - bnez P3H, .LL20 - bnez P3L, .LL21 - move $r6, #0 - j .LL22 -.LL21: - move P3H, P3L - move P3L, #0 - move $r9, #32 - sub $r6, $r6, $r9 -.LL20: -#ifdef __NDS32_PERF_EXT__ - clz $r9, P3H -#else - pushm $r0, $r5 - move $r0, P3H - bal __clzsi2 - move $r9, $r0 - popm $r0, $r5 -#endif - beqz $r9, .LL22 - sub $r6, $r6, $r9 - subri P1L, $r9, #32 - srl P1L, P3L, P1L - sll P3L, P3L, $r9 - sll P3H, P3H, $r9 - or P3H, P3H, P1L -.LL22: - #NORMd End - - or $r10, P3H, P3L - bnez $r10, .LEres - move P1H, #0 - -.LEres: - blez $r6, .LEund - -.LElab8: - #ADD(P3L, $0x400) - move $r15, #0x400 - add P3L, P3L, $r15 - slt $r15, P3L, $r15 - - #ADDCC(P3H, $0x0) - beqzs8 .LL25 - add P3H, P3H, $r15 - slt $r15, P3H, $r15 -.LL25: - - #ADDC($r6, $0x0) - add $r6, $r6, $r15 - srli $r10, P3L, #11 - andi $r10, $r10, #1 - sub P3L, P3L, $r10 - srli P1L, P3L, #11 - slli $r10, P3H, #21 - or P1L, P1L, $r10 - slli $r10, P3H, #1 - srli $r10, $r10, #12 - or P1H, P1H, $r10 - slli $r10, $r6, #20 - or P1H, P1H, $r10 - -.LEretA: -.LE999: - popm $r6, $r10 - pop $lp - ret5 $lp - -.LEspecA: - #ADD(P3L, P3L) - move $r15, P3L - add P3L, P3L, P3L - slt $r15, P3L, $r15 - - #ADDC(P3H, P3H) - add P3H, P3H, P3H - add P3H, P3H, $r15 - bnez $r6, .Li7 - or $r10, P3H, P3L - beqz $r10, .Li8 - j .LElab1 -.Li8: - subri $r15, $r9, #0x7ff - beqzs8 .LEspecB - add P3L, P2H, P2H - or $r10, P3L, P2L - bnez $r10, .LEretB - sltsi $r15, P2H, #0 - bnezs8 .LEretA - -.LEretB: - move P1L, P2L - move P1H, P2H - j .LE999 -.Li7: - or $r10, P3H, P3L - bnez $r10, .LEnan - subri $r15, $r9, #0x7ff - bnezs8 .LEretA - xor $r10, P1H, P2H - sltsi $r15, $r10, #0 - bnezs8 .LEnan - j .LEretB - -.LEspecB: - #ADD(O1L, O1L) - move $r15, O1L - add O1L, O1L, O1L - slt $r15, O1L, $r15 - - #ADDC(O1H, O1H) - add O1H, O1H, O1H - add O1H, O1H, $r15 - bnez $r9, .Li11 - or $r10, O1H, O1L - beqz $r10, .LEretA - j .LElab2 -.Li11: - or $r10, O1H, O1L - beqz $r10, .LEretB - -.LEnan: - move P1H, #0xfff80000 - move P1L, #0 - j .LEretA - -.LEund: - subri $r9, $r6, #1 - move P2L, #0 -.LL26: - move $r10, #0x20 - slt $r15, $r9, $r10 - bnezs8 .LL27 - or P2L, P2L, P3L - move P3L, P3H - move P3H, #0 - addi $r9, $r9, #0xffffffe0 - bnez P3L, .LL26 -.LL27: - beqz $r9, .LL28 - move P1L, P3H - move $r10, P3L - srl P3L, P3L, $r9 - srl P3H, P3H, $r9 - subri $r9, $r9, #0x20 - sll P1L, P1L, $r9 - or P3L, P3L, P1L - sll $r10, $r10, $r9 - or P2L, P2L, $r10 - beqz P2L, .LL28 - ori P3L, P3L, #1 -.LL28: - move $r6, #0 - j .LElab8 - .size __subdf3, .-__subdf3 - .size __adddf3, .-__adddf3 -#endif /* L_addsub_df */ - - - -#ifdef L_mul_sf - -#if !defined (__big_endian__) - #define P1L $r0 - #define P1H $r1 - #define P2L $r2 - #define P2H $r3 -#else - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 -#endif - .text - .align 2 - .global __mulsf3 - .type __mulsf3, @function -__mulsf3: - push $lp - pushm $r6, $r10 - - srli $r3, $r0, #23 - andi $r3, $r3, #0xff - srli $r5, $r1, #23 - andi $r5, $r5, #0xff - move $r6, #0x80000000 - slli $r2, $r0, #8 - or $r2, $r2, $r6 - slli $r4, $r1, #8 - or $r4, $r4, $r6 - xor $r8, $r0, $r1 - and $r6, $r6, $r8 - - addi $r8, $r3, #-1 - slti $r15, $r8, #0xfe - beqzs8 .LFspecA - -.LFlab1: - addi $r8, $r5, #-1 - slti $r15, $r8, #0xfe - beqzs8 .LFspecB - -.LFlab2: - move $r10, $r3 -/* This is a 64-bit multiple. ($r2, $r7) is (high, low). */ -#ifndef __NDS32_ISA_V3M__ - mulr64 $r2, $r2, $r4 -#else - pushm $r0, $r1 - pushm $r4, $r5 - move P1L, $r2 - movi P1H, #0 - move P2L, $r4 - movi P2H, #0 - bal __muldi3 - movd44 $r2, $r0 - popm $r4, $r5 - popm $r0, $r1 -#endif -#ifndef __big_endian__ - move $r7, $r2 - move $r2, $r3 -#else - move $r7, $r3 -#endif - move $r3, $r10 - - beqz $r7, .Li17 - ori $r2, $r2, #1 - -.Li17: - sltsi $r15, $r2, #0 - bnezs8 .Li18 - slli $r2, $r2, #1 - addi $r3, $r3, #-1 -.Li18: - addi $r8, $r5, #0xffffff82 - add $r3, $r3, $r8 - addi $r8, $r3, #-1 - slti $r15, $r8, #0xfe - beqzs8 .LFoveund - -.LFlab8: - #ADD($r2, $0x80) - move $r15, #0x80 - add $r2, $r2, $r15 - slt $r15, $r2, $r15 - - #ADDC($r3, $0x0) - add $r3, $r3, $r15 - srli $r8, $r2, #8 - andi $r8, $r8, #1 - sub $r2, $r2, $r8 - slli $r2, $r2, #1 - srli $r2, $r2, #9 - slli $r8, $r3, #23 - or $r2, $r2, $r8 - or $r0, $r2, $r6 - -.LF999: - popm $r6, $r10 - pop $lp - ret5 $lp - -.LFspecA: - bnez $r3, .Li19 - add $r2, $r2, $r2 - beqz $r2, .Li20 -#ifdef __NDS32_PERF_EXT__ - clz $r7, $r2 -#else - pushm $r0, $r5 - move $r0, $r2 - bal __clzsi2 - move $r7, $r0 - popm $r0, $r5 -#endif - sub $r3, $r3, $r7 - sll $r2, $r2, $r7 - j .LFlab1 -.Li20: - subri $r15, $r5, #0xff - beqzs8 .LFnan - j .LFzer -.Li19: - add $r8, $r2, $r2 - bnez $r8, .LFnan - bnez $r5, .Li21 - add $r8, $r4, $r4 - beqz $r8, .LFnan -.Li21: - subri $r15, $r5, #0xff - bnezs8 .LFinf - -.LFspecB: - bnez $r5, .Li22 - add $r4, $r4, $r4 - beqz $r4, .LFzer -#ifdef __NDS32_PERF_EXT__ - clz $r7, $r4 -#else - pushm $r0, $r5 - move $r0, $r4 - bal __clzsi2 - move $r7, $r0 - popm $r0, $r5 -#endif - sub $r5, $r5, $r7 - sll $r4, $r4, $r7 - j .LFlab2 - -.LFzer: - move $r0, $r6 - j .LF999 -.Li22: - add $r8, $r4, $r4 - bnez $r8, .LFnan - -.LFinf: - move $r8, #0x7f800000 - or $r0, $r6, $r8 - j .LF999 - -.LFnan: - move $r0, #0xffc00000 - j .LF999 - -.LFoveund: - bgtz $r3, .LFinf - subri $r7, $r3, #1 - slti $r15, $r7, #0x20 - beqzs8 .LFzer - subri $r8, $r7, #0x20 - sll $r3, $r2, $r8 - srl $r2, $r2, $r7 - beqz $r3, .Li25 - ori $r2, $r2, #2 -.Li25: - move $r3, #0 - addi $r8, $r2, #0x80 - sltsi $r15, $r8, #0 - beqzs8 .LFlab8 - move $r3, #1 - j .LFlab8 - .size __mulsf3, .-__mulsf3 -#endif /* L_mul_sf */ - - - -#ifdef L_mul_df - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 - #define P2L $r2 - #define P2H $r3 - #define P3L $r4 - #define P3H $r5 - #define O1L $r7 - #define O1H $r8 -#else - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 - #define P3H $r4 - #define P3L $r5 - #define O1H $r7 - #define O1L $r8 -#endif - .text - .align 2 - .global __muldf3 - .type __muldf3, @function -__muldf3: - push $lp - pushm $r6, $r10 - - slli $r6, P1H, #1 - srli $r6, $r6, #21 - slli P3H, P1H, #11 - srli $r10, P1L, #21 - or P3H, P3H, $r10 - slli P3L, P1L, #11 - move O1L, #0x80000000 - or P3H, P3H, O1L - slli $r9, P2H, #1 - srli $r9, $r9, #21 - slli O1H, P2H, #11 - srli $r10, P2L, #21 - or O1H, O1H, $r10 - or O1H, O1H, O1L - xor P1H, P1H, P2H - and P1H, P1H, O1L - slli O1L, P2L, #11 - - addi $r10, $r6, #-1 - slti $r15, $r10, #0x7fe - beqzs8 .LFspecA - -.LFlab1: - addi $r10, $r9, #-1 - slti $r15, $r10, #0x7fe - beqzs8 .LFspecB - -.LFlab2: - addi $r10, $r9, #0xfffffc02 - add $r6, $r6, $r10 - - move $r10, $r8 -/* This is a 64-bit multiple. */ -#ifndef __big_endian__ -/* For little endian: ($r9, $r3) is (high, low). */ -#ifndef __NDS32_ISA_V3M__ - mulr64 $r8, $r5, $r8 -#else - pushm $r0, $r5 - move $r0, $r5 - movi $r1, #0 - move $r2, $r8 - movi $r3, #0 - bal __muldi3 - movd44 $r8, $r0 - popm $r0, $r5 -#endif - move $r3, $r8 -#else /* __big_endian__ */ -/* For big endain: ($r9, $r2) is (high, low). */ -#ifndef __NDS32_ISA_V3M__ - mulr64 $r8, $r4, $r7 -#else - pushm $r0, $r5 - move $r1, $r4 - movi $r0, #0 - move $r3, $r7 - movi $r2, #0 - bal __muldi3 - movd44 $r8, $r0 - popm $r0, $r5 -#endif - move $r2, $r9 - move $r9, $r8 -#endif /* __big_endian__ */ - move $r8, $r10 - - move $r10, P1H -/* This is a 64-bit multiple. */ -#ifndef __big_endian__ -/* For little endian: ($r0, $r2) is (high, low). */ -#ifndef __NDS32_ISA_V3M__ - mulr64 $r0, $r4, $r8 -#else - pushm $r2, $r5 - move $r0, $r4 - movi $r1, #0 - move $r2, $r8 - movi $r3, #0 - bal __muldi3 - popm $r2, $r5 -#endif - move $r2, $r0 - move $r0, $r1 -#else /* __big_endian__ */ -/* For big endain: ($r1, $r3) is (high, low). */ -#ifndef __NDS32_ISA_V3M__ - mulr64 $r0, $r5, $r7 -#else - pushm $r2, $r5 - move $r1, $r5 - movi $r0, #0 - move $r3, $r7 - movi $r2, #0 - bal __muldi3 - popm $r2, $r5 -#endif - move $r3, $r1 - move $r1, $r0 -#endif /* __big_endian__ */ - move P1H, $r10 - - #ADD(P2H, P1L) - add P2H, P2H, P1L - slt $r15, P2H, P1L - - #ADDC($r9, $0x0) - add $r9, $r9, $r15 - - move $r10, P1H -/* This is a 64-bit multiple. */ -#ifndef __big_endian__ -/* For little endian: ($r0, $r8) is (high, low). */ -#ifndef __NDS32_ISA_V3M__ - mulr64 $r0, $r5, $r7 -#else - pushm $r2, $r5 - move $r0, $r5 - movi $r1, #0 - move $r2, $r7 - movi $r3, #0 - bal __muldi3 - popm $r2, $r5 -#endif - move $r8, $r0 - move $r0, $r1 -#else /* __big_endian__ */ -/* For big endian: ($r1, $r7) is (high, low). */ -#ifndef __NDS32_ISA_V3M__ - mulr64 $r0, $r4, $r8 -#else - pushm $r2, $r5 - move $r1, $r4 - movi $r0, #0 - move $r3, $r8 - movi $r2, #0 - bal __muldi3 - popm $r2, $r5 -#endif - move $r7, $r1 - move $r1, $r0 -#endif /* __big_endian__ */ - move P1H, $r10 - - #ADD(P2L, O1H) - add P2L, P2L, O1H - slt $r15, P2L, O1H - - - #ADDCC(P2H, P1L) - beqzs8 .LL29 - add P2H, P2H, P1L - slt $r15, P2H, P1L - beqzs8 .LL30 - addi P2H, P2H, #0x1 - j .LL31 -.LL30: - move $r15, #1 - add P2H, P2H, $r15 - slt $r15, P2H, $r15 - j .LL31 -.LL29: - add P2H, P2H, P1L - slt $r15, P2H, P1L -.LL31: - - #ADDC($r9, $0x0) - add $r9, $r9, $r15 - -/* This is a 64-bit multiple. */ -#ifndef __big_endian__ -/* For little endian: ($r8, $r0) is (high, low). */ - move $r10, $r9 -#ifndef __NDS32_ISA_V3M__ - mulr64 $r8, $r4, $r7 -#else - pushm $r0, $r5 - move $r0, $r4 - movi $r1, #0 - move $r2, $r7 - movi $r3, #0 - bal __muldi3 - movd44 $r8, $r0 - popm $r0, $r5 -#endif - move $r0, $r8 - move $r8, $r9 - move $r9, $r10 -#else /* __big_endian__ */ -/* For big endian: ($r7, $r1) is (high, low). */ - move $r10, $r6 -#ifndef __NDS32_ISA_V3M__ - mulr64 $r6, $r5, $r8 -#else - pushm $r0, $r5 - move $r1, $r5 - movi $r0, #0 - move $r3, $r8 - movi $r2, #0 - bal __muldi3 - movd44 $r6, $r0 - popm $r0, $r5 -#endif - move $r1, $r7 - move $r7, $r6 - move $r6, $r10 -#endif /* __big_endian__ */ - - #ADD(P2L, O1H) - add P2L, P2L, O1H - slt $r15, P2L, O1H - - - #ADDCC(P2H, $0x0) - beqzs8 .LL34 - add P2H, P2H, $r15 - slt $r15, P2H, $r15 -.LL34: - - #ADDC($r9, $0x0) - add $r9, $r9, $r15 - or $r10, P1L, P2L - beqz $r10, .Li13 - ori P2H, P2H, #1 -.Li13: - move P3H, $r9 - move P3L, P2H - sltsi $r15, P3H, #0 - bnezs8 .Li14 - - move $r15, P3L - add P3L, P3L, P3L - slt $r15, P3L, $r15 - add P3H, P3H, P3H - add P3H, P3H, $r15 - addi $r6, $r6, #-1 -.Li14: - addi $r10, $r6, #-1 - slti $r15, $r10, #0x7fe - beqzs8 .LFoveund - - #ADD(P3L, $0x400) - move $r15, #0x400 - add P3L, P3L, $r15 - slt $r15, P3L, $r15 - - - #ADDCC(P3H, $0x0) - beqzs8 .LL37 - add P3H, P3H, $r15 - slt $r15, P3H, $r15 -.LL37: - - #ADDC($r6, $0x0) - add $r6, $r6, $r15 - -.LFlab8: - srli $r10, P3L, #11 - andi $r10, $r10, #1 - sub P3L, P3L, $r10 - srli P1L, P3L, #11 - slli $r10, P3H, #21 - or P1L, P1L, $r10 - slli $r10, P3H, #1 - srli $r10, $r10, #12 - or P1H, P1H, $r10 - slli $r10, $r6, #20 - or P1H, P1H, $r10 - -.LFret: -.LF999: - popm $r6, $r10 - pop $lp - ret5 $lp - -.LFspecA: - #ADD(P3L, P3L) - move $r15, P3L - add P3L, P3L, P3L - slt $r15, P3L, $r15 - - #ADDC(P3H, P3H) - add P3H, P3H, P3H - add P3H, P3H, $r15 - bnez $r6, .Li15 - or $r10, P3H, P3L - beqz $r10, .Li16 - - - #NORMd($r4, P1L, P2H) - bnez P3H, .LL38 - bnez P3L, .LL39 - move $r6, #0 - j .LL40 -.LL39: - move P3H, P3L - move P3L, #0 - move P1L, #32 - sub $r6, $r6, P1L -.LL38: -#ifndef __big_endian__ -#ifdef __NDS32_PERF_EXT__ - clz $r0, P3H -#else - pushm $r1, P3H - move $r0, P3H - bal __clzsi2 - popm $r1, $r5 -#endif -#else /* __big_endian__ */ -#ifdef __NDS32_PERF_EXT__ - clz $r1, $r4 -#else - push $r0 - pushm $r2, $r5 - move $r0, $r4 - bal __clzsi2 - move $r1, $r0 - popm $r2, $r5 - pop $r0 -#endif -#endif /* __big_endian__ */ - beqz P1L, .LL40 - sub $r6, $r6, P1L - subri P2H, P1L, #32 - srl P2H, P3L, P2H - sll P3L, P3L, P1L - sll P3H, P3H, P1L - or P3H, P3H, P2H -.LL40: - #NORMd End - - j .LFlab1 -.Li16: - subri $r15, $r9, #0x7ff - beqzs8 .LFnan - j .LFret -.Li15: - or $r10, P3H, P3L - bnez $r10, .LFnan - bnez $r9, .Li17 - slli $r10, O1H, #1 - or $r10, $r10, O1L - beqz $r10, .LFnan -.Li17: - subri $r15, $r9, #0x7ff - bnezs8 .LFinf - -.LFspecB: - #ADD(O1L, O1L) - move $r15, O1L - add O1L, O1L, O1L - slt $r15, O1L, $r15 - - #ADDC(O1H, O1H) - add O1H, O1H, O1H - add O1H, O1H, $r15 - bnez $r9, .Li18 - or $r10, O1H, O1L - beqz $r10, .Li19 - - - #NORMd($r7, P2L, P1L) - bnez O1H, .LL41 - bnez O1L, .LL42 - move $r9, #0 - j .LL43 -.LL42: - move O1H, O1L - move O1L, #0 - move P2L, #32 - sub $r9, $r9, P2L -.LL41: -#ifndef __big_endian__ -#ifdef __NDS32_PERF_EXT__ - clz $r2, $r8 -#else - pushm $r0, $r1 - pushm $r3, $r5 - move $r0, $r8 - bal __clzsi2 - move $r2, $r0 - popm $r3, $r5 - popm $r0, $r1 -#endif -#else /* __big_endian__ */ -#ifdef __NDS32_PERF_EXT__ - clz $r3, $r7 -#else - pushm $r0, $r2 - pushm $r4, $r5 - move $r0, $r7 - bal __clzsi2 - move $r3, $r0 - popm $r4, $r5 - popm $r0, $r2 -#endif -#endif /* __big_endian__ */ - beqz P2L, .LL43 - sub $r9, $r9, P2L - subri P1L, P2L, #32 - srl P1L, O1L, P1L - sll O1L, O1L, P2L - sll O1H, O1H, P2L - or O1H, O1H, P1L -.LL43: - #NORMd End - - j .LFlab2 -.Li19: - move P1L, #0 - j .LFret -.Li18: - or $r10, O1H, O1L - bnez $r10, .LFnan - -.LFinf: - move $r10, #0x7ff00000 - or P1H, P1H, $r10 - move P1L, #0 - j .LFret - -.LFnan: - move P1H, #0xfff80000 - move P1L, #0 - j .LFret - -.LFoveund: - bgtz $r6, .LFinf - subri P1L, $r6, #1 - move P2L, #0 -.LL44: - move $r10, #0x20 - slt $r15, P1L, $r10 - bnezs8 .LL45 - or P2L, P2L, P3L - move P3L, P3H - move P3H, #0 - addi P1L, P1L, #0xffffffe0 - bnez P3L, .LL44 -.LL45: - beqz P1L, .LL46 - move P2H, P3H - move $r10, P3L - srl P3L, P3L, P1L - srl P3H, P3H, P1L - subri P1L, P1L, #0x20 - sll P2H, P2H, P1L - or P3L, P3L, P2H - sll $r10, $r10, P1L - or P2L, P2L, $r10 - beqz P2L, .LL46 - ori P3L, P3L, #1 -.LL46: - #ADD(P3L, $0x400) - move $r15, #0x400 - add P3L, P3L, $r15 - slt $r15, P3L, $r15 - - #ADDC(P3H, $0x0) - add P3H, P3H, $r15 - srli $r6, P3H, #31 - j .LFlab8 - .size __muldf3, .-__muldf3 -#endif /* L_mul_df */ - - - -#ifdef L_div_sf - - .text - .align 2 - .global __divsf3 - .type __divsf3, @function -__divsf3: - push $lp - pushm $r6, $r10 - - move $r7, #0x80000000 - srli $r4, $r0, #23 - andi $r4, $r4, #0xff - srli $r6, $r1, #23 - andi $r6, $r6, #0xff - slli $r3, $r0, #8 - or $r3, $r3, $r7 - slli $r5, $r1, #8 - or $r5, $r5, $r7 - xor $r10, $r0, $r1 - and $r7, $r7, $r10 - - addi $r10, $r4, #-1 - slti $r15, $r10, #0xfe - beqzs8 .LGspecA - -.LGlab1: - addi $r10, $r6, #-1 - slti $r15, $r10, #0xfe - beqzs8 .LGspecB - -.LGlab2: - slt $r15, $r3, $r5 - bnezs8 .Li27 - srli $r3, $r3, #1 - addi $r4, $r4, #1 -.Li27: - srli $r8, $r5, #14 - divr $r0, $r2, $r3, $r8 - andi $r9, $r5, #0x3fff - mul $r1, $r9, $r0 - slli $r2, $r2, #14 - - #SUB($r2, $r1) - move $r15, $r2 - sub $r2, $r2, $r1 - slt $r15, $r15, $r2 - beqzs8 .Li28 - addi $r0, $r0, #-1 - - #ADD($r2, $r5) - add $r2, $r2, $r5 - slt $r15, $r2, $r5 -.Li28: - divr $r3, $r2, $r2, $r8 - mul $r1, $r9, $r3 - slli $r2, $r2, #14 - - #SUB($r2, $r1) - move $r15, $r2 - sub $r2, $r2, $r1 - slt $r15, $r15, $r2 - beqzs8 .Li29 - addi $r3, $r3, #-1 - - #ADD($r2, $r5) - add $r2, $r2, $r5 - slt $r15, $r2, $r5 -.Li29: - slli $r10, $r0, #14 - add $r3, $r3, $r10 - slli $r3, $r3, #4 - beqz $r2, .Li30 - ori $r3, $r3, #1 -.Li30: - subri $r10, $r6, #0x7e - add $r4, $r4, $r10 - addi $r10, $r4, #-1 - slti $r15, $r10, #0xfe - beqzs8 .LGoveund - -.LGlab8: - #ADD($r3, $0x80) - move $r15, #0x80 - add $r3, $r3, $r15 - slt $r15, $r3, $r15 - - #ADDC($r4, $0x0) - add $r4, $r4, $r15 - srli $r10, $r3, #8 - andi $r10, $r10, #1 - sub $r3, $r3, $r10 - slli $r3, $r3, #1 - srli $r3, $r3, #9 - slli $r10, $r4, #23 - or $r3, $r3, $r10 - or $r0, $r3, $r7 - -.LG999: - popm $r6, $r10 - pop $lp - ret5 $lp - -.LGspecA: - bnez $r4, .Li31 - add $r3, $r3, $r3 - beqz $r3, .Li31 -#ifdef __NDS32_PERF_EXT__ - clz $r8, $r3 -#else - pushm $r0, $r5 - move $r0, $r3 - bal __clzsi2 - move $r8, $r0 - popm $r0, $r5 -#endif - sub $r4, $r4, $r8 - sll $r3, $r3, $r8 - j .LGlab1 -.Li31: - bne $r6, $r4, .Li33 - add $r10, $r5, $r5 - beqz $r10, .LGnan -.Li33: - subri $r15, $r6, #0xff - beqzs8 .LGspecB - beqz $r4, .LGzer - add $r10, $r3, $r3 - bnez $r10, .LGnan - j .LGinf - -.LGspecB: - bnez $r6, .Li34 - add $r5, $r5, $r5 - beqz $r5, .LGinf -#ifdef __NDS32_PERF_EXT__ - clz $r8, $r5 -#else - pushm $r0, $r5 - move $r0, $r5 - bal __clzsi2 - move $r8, $r0 - popm $r0, $r5 -#endif - sub $r6, $r6, $r8 - sll $r5, $r5, $r8 - j .LGlab2 -.Li34: - add $r10, $r5, $r5 - bnez $r10, .LGnan - -.LGzer: - move $r0, $r7 - j .LG999 - -.LGoveund: - bgtz $r4, .LGinf - subri $r8, $r4, #1 - slti $r15, $r8, #0x20 - beqzs8 .LGzer - subri $r10, $r8, #0x20 - sll $r4, $r3, $r10 - srl $r3, $r3, $r8 - beqz $r4, .Li37 - ori $r3, $r3, #2 -.Li37: - move $r4, #0 - addi $r10, $r3, #0x80 - sltsi $r15, $r10, #0 - beqzs8 .LGlab8 - move $r4, #1 - j .LGlab8 - -.LGinf: - move $r10, #0x7f800000 - or $r0, $r7, $r10 - j .LG999 - -.LGnan: - move $r0, #0xffc00000 - j .LG999 - .size __divsf3, .-__divsf3 -#endif /* L_div_sf */ - - - -#ifdef L_div_df - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 - #define P2L $r2 - #define P2H $r3 - #define P3L $r4 - #define P3H $r5 - #define O1L $r7 - #define O1H $r8 -#else - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 - #define P3H $r4 - #define P3L $r5 - #define O1H $r7 - #define O1L $r8 -#endif - .text - .align 2 - .global __divdf3 - .type __divdf3, @function -__divdf3: - push $lp - pushm $r6, $r10 - - slli $r6, P1H, #1 - srli $r6, $r6, #21 - slli P3H, P1H, #11 - srli $r10, P1L, #21 - or P3H, P3H, $r10 - slli P3L, P1L, #11 - move O1L, #0x80000000 - or P3H, P3H, O1L - slli $r9, P2H, #1 - srli $r9, $r9, #21 - slli O1H, P2H, #11 - srli $r10, P2L, #21 - or O1H, O1H, $r10 - or O1H, O1H, O1L - xor P1H, P1H, P2H - and P1H, P1H, O1L - slli O1L, P2L, #11 - - addi $r10, $r6, #-1 - slti $r15, $r10, #0x7fe - beqzs8 .LGspecA - -.LGlab1: - addi $r10, $r9, #-1 - slti $r15, $r10, #0x7fe - beqzs8 .LGspecB - -.LGlab2: - sub $r6, $r6, $r9 - addi $r6, $r6, #0x3ff - srli P3L, P3L, #1 - slli $r10, P3H, #31 - or P3L, P3L, $r10 - srli P3H, P3H, #1 - srli $r9, O1H, #16 - divr P2H, P3H, P3H, $r9 - move $r10, #0xffff - and P2L, O1H, $r10 - mul P1L, P2L, P2H - slli P3H, P3H, #16 - srli $r10, P3L, #16 - or P3H, P3H, $r10 - - #SUB(P3H, P1L) - move $r15, P3H - sub P3H, P3H, P1L - slt $r15, $r15, P3H - beqzs8 .Li20 - -.Lb21: - addi P2H, P2H, #-1 - add P3H, P3H, O1H - slt $r15, P3H, O1H - beqzs8 .Lb21 -.Li20: - divr $r9, P3H, P3H, $r9 - mul P1L, P2L, $r9 - slli P3H, P3H, #16 - move $r15, #0xffff - and $r10, P3L, $r15 - or P3H, P3H, $r10 - - #SUB(P3H, P1L) - move $r15, P3H - sub P3H, P3H, P1L - slt $r15, $r15, P3H - beqzs8 .Li22 - -.Lb23: - addi $r9, $r9, #-1 - add P3H, P3H, O1H - slt $r15, P3H, O1H - beqzs8 .Lb23 -.Li22: - slli P2H, P2H, #16 - add P2H, P2H, $r9 - -/* This is a 64-bit multiple. */ -#ifndef __big_endian__ -/* For little endian: ($r0, $r9) is (high, low). */ - move $r10, $r1 -#ifndef __NDS32_ISA_V3M__ - mulr64 $r0, $r3, $r7 -#else - pushm $r2, $r5 - move $r0, $r3 - movi $r1, #0 - move $r2, $r7 - movi $r3, #0 - bal __muldi3 - popm $r2, $r5 -#endif - move $r9, $r0 - move $r0, $r1 - move $r1, $r10 -#else /* __big_endian__ */ -/* For big endian: ($r1, $r9) is (high, low). */ - move $r10, $r0 -#ifndef __NDS32_ISA_V3M__ - mulr64 $r0, $r2, $r8 -#else - pushm $r2, $r5 - move $r1, $r2 - movi $r0, #0 - move $r3, $r8 - movi $r2, #0 - bal __muldi3 - popm $r2, $r5 -#endif - move $r9, $r1 - move $r1, $r0 - move $r0, $r10 -#endif /* __big_endian__ */ - - move P3L, #0 - - #SUB(P3L, $r9) - move $r15, P3L - sub P3L, P3L, $r9 - slt $r15, $r15, P3L - - - #SUBCC(P3H, P1L) - beqzs8 .LL47 - move $r15, P3H - sub P3H, P3H, P1L - slt $r15, $r15, P3H - beqzs8 .LL48 - subi333 P3H, P3H, #1 - j .LL49 -.LL48: - move $r15, P3H - subi333 P3H, P3H, #1 - slt $r15, $r15, P3H - j .LL49 -.LL47: - move $r15, P3H - sub P3H, P3H, P1L - slt $r15, $r15, P3H -.LL49: - - beqzs8 .Li24 - -.LGlab3: - addi P2H, P2H, #-1 - - #ADD(P3L, O1L) - add P3L, P3L, O1L - slt $r15, P3L, O1L - - - #ADDCC(P3H, O1H) - beqzs8 .LL50 - add P3H, P3H, O1H - slt $r15, P3H, O1H - beqzs8 .LL51 - addi P3H, P3H, #0x1 - j .LL52 -.LL51: - move $r15, #1 - add P3H, P3H, $r15 - slt $r15, P3H, $r15 - j .LL52 -.LL50: - add P3H, P3H, O1H - slt $r15, P3H, O1H -.LL52: - - beqzs8 .LGlab3 -.Li24: - bne P3H, O1H, .Li25 - move P1L, O1L - move P3H, P3L - move $r9, #0 - move P2L, $r9 - j .Le25 -.Li25: - srli P2L, O1H, #16 - divr $r9, P3H, P3H, P2L - move $r10, #0xffff - and $r10, O1H, $r10 - mul P1L, $r10, $r9 - slli P3H, P3H, #16 - srli $r15, P3L, #16 - or P3H, P3H, $r15 - - #SUB(P3H, P1L) - move $r15, P3H - sub P3H, P3H, P1L - slt $r15, $r15, P3H - beqzs8 .Li26 - -.Lb27: - addi $r9, $r9, #-1 - add P3H, P3H, O1H - slt $r15, P3H, O1H - beqzs8 .Lb27 -.Li26: - divr P2L, P3H, P3H, P2L - mul P1L, $r10, P2L - slli P3H, P3H, #16 - move $r10, #0xffff - and $r10, P3L, $r10 - or P3H, P3H, $r10 - - #SUB(P3H, P1L) - move $r15, P3H - sub P3H, P3H, P1L - slt $r15, $r15, P3H - beqzs8 .Li28 - -.Lb29: - addi P2L, P2L, #-1 - add P3H, P3H, O1H - slt $r15, P3H, O1H - beqzs8 .Lb29 -.Li28: - slli $r9, $r9, #16 - add $r9, $r9, P2L - -/* This is a 64-bit multiple. */ -#ifndef __big_endian__ -/* For little endian: ($r0, $r2) is (high, low). */ - move $r10, $r1 -#ifndef __NDS32_ISA_V3M__ - mulr64 $r0, $r9, $r7 -#else - pushm $r2, $r5 - move $r0, $r9 - movi $r1, #0 - move $r2, $r7 - movi $r3, #0 - bal __muldi3 - popm $r2, $r5 -#endif - move $r2, $r0 - move $r0, $r1 - move $r1, $r10 -#else /* __big_endian__ */ -/* For big endian: ($r1, $r3) is (high, low). */ - move $r10, $r0 -#ifndef __NDS32_ISA_V3M__ - mulr64 $r0, $r9, $r8 -#else - pushm $r2, $r5 - move $r0, $r9 - movi $r1, #0 - move $r2, $r7 - movi $r3, #0 - bal __muldi3 - popm $r2, $r5 -#endif - move $r3, $r1 - move $r1, $r0 - move $r0, $r10 -#endif /* __big_endian__ */ - -.Le25: - move P3L, #0 - - #SUB(P3L, P2L) - move $r15, P3L - sub P3L, P3L, P2L - slt $r15, $r15, P3L - - - #SUBCC(P3H, P1L) - beqzs8 .LL53 - move $r15, P3H - sub P3H, P3H, P1L - slt $r15, $r15, P3H - beqzs8 .LL54 - subi333 P3H, P3H, #1 - j .LL55 -.LL54: - move $r15, P3H - subi333 P3H, P3H, #1 - slt $r15, $r15, P3H - j .LL55 -.LL53: - move $r15, P3H - sub P3H, P3H, P1L - slt $r15, $r15, P3H -.LL55: - - beqzs8 .Li30 - -.LGlab4: - addi $r9, $r9, #-1 - - #ADD(P3L, O1L) - add P3L, P3L, O1L - slt $r15, P3L, O1L - - - #ADDCC(P3H, O1H) - beqzs8 .LL56 - add P3H, P3H, O1H - slt $r15, P3H, O1H - beqzs8 .LL57 - addi P3H, P3H, #0x1 - j .LL58 -.LL57: - move $r15, #1 - add P3H, P3H, $r15 - slt $r15, P3H, $r15 - j .LL58 -.LL56: - add P3H, P3H, O1H - slt $r15, P3H, O1H -.LL58: - - beqzs8 .LGlab4 -.Li30: - sltsi $r15, P2H, #0 - bnezs8 .Li31 - - #ADD($r9, $r9) - move $r15, $r9 - add $r9, $r9, $r9 - slt $r15, $r9, $r15 - - #ADDC(P2H, P2H) - add P2H, P2H, P2H - add P2H, P2H, $r15 - addi $r6, $r6, #-1 -.Li31: - or $r10, P3H, P3L - beqz $r10, .Li32 - ori $r9, $r9, #1 -.Li32: - move P3H, P2H - move P3L, $r9 - addi $r10, $r6, #-1 - slti $r15, $r10, #0x7fe - beqzs8 .LGoveund - - #ADD(P3L, $0x400) - move $r15, #0x400 - add P3L, P3L, $r15 - slt $r15, P3L, $r15 - - - #ADDCC(P3H, $0x0) - beqzs8 .LL61 - add P3H, P3H, $r15 - slt $r15, P3H, $r15 -.LL61: - - #ADDC($r6, $0x0) - add $r6, $r6, $r15 - -.LGlab8: - srli $r10, P3L, #11 - andi $r10, $r10, #1 - sub P3L, P3L, $r10 - srli P1L, P3L, #11 - slli $r10, P3H, #21 - or P1L, P1L, $r10 - slli $r10, P3H, #1 - srli $r10, $r10, #12 - or P1H, P1H, $r10 - slli $r10, $r6, #20 - or P1H, P1H, $r10 - -.LGret: -.LG999: - popm $r6, $r10 - pop $lp - ret5 $lp - -.LGoveund: - bgtz $r6, .LGinf - subri P2H, $r6, #1 - move P1L, #0 -.LL62: - move $r10, #0x20 - slt $r15, P2H, $r10 - bnezs8 .LL63 - or P1L, P1L, P3L - move P3L, P3H - move P3H, #0 - addi P2H, P2H, #0xffffffe0 - bnez P3L, .LL62 -.LL63: - beqz P2H, .LL64 - move P2L, P3H - move $r10, P3L - srl P3L, P3L, P2H - srl P3H, P3H, P2H - subri P2H, P2H, #0x20 - sll P2L, P2L, P2H - or P3L, P3L, P2L - sll $r10, $r10, P2H - or P1L, P1L, $r10 - beqz P1L, .LL64 - ori P3L, P3L, #1 -.LL64: - #ADD(P3L, $0x400) - move $r15, #0x400 - add P3L, P3L, $r15 - slt $r15, P3L, $r15 - - #ADDC(P3H, $0x0) - add P3H, P3H, $r15 - srli $r6, P3H, #31 - j .LGlab8 - -.LGspecA: - #ADD(P3L, P3L) - move $r15, P3L - add P3L, P3L, P3L - slt $r15, P3L, $r15 - - #ADDC(P3H, P3H) - add P3H, P3H, P3H - add P3H, P3H, $r15 - bnez $r6, .Li33 - or $r10, P3H, P3L - beqz $r10, .Li33 - - - #NORMd($r4, P2H, P2L) - bnez P3H, .LL65 - bnez P3L, .LL66 - move $r6, #0 - j .LL67 -.LL66: - move P3H, P3L - move P3L, #0 - move P2H, #32 - sub $r6, $r6, P2H -.LL65: -#ifndef __big_endian__ -#ifdef __NDS32_PERF_EXT__ - clz $r3, $r5 -#else - pushm $r0, $r2 - pushm $r4, $r5 - move $r0, $r5 - bal __clzsi2 - move $r3, $r0 - popm $r4, $r5 - popm $r0, $r2 -#endif -#else /* __big_endian__ */ -#ifdef __NDS32_PERF_EXT__ - clz $r2, $r4 -#else - pushm $r0, $r1 - pushm $r3, $r5 - move $r0, $r4 - bal __clzsi2 - move $r2, $r0 - popm $r3, $r5 - popm $r0, $r1 -#endif -#endif /* __big_endian_ */ - beqz P2H, .LL67 - sub $r6, $r6, P2H - subri P2L, P2H, #32 - srl P2L, P3L, P2L - sll P3L, P3L, P2H - sll P3H, P3H, P2H - or P3H, P3H, P2L -.LL67: - #NORMd End - - j .LGlab1 -.Li33: - bne $r6, $r9, .Li35 - slli $r10, O1H, #1 - or $r10, $r10, O1L - beqz $r10, .LGnan -.Li35: - subri $r15, $r9, #0x7ff - beqzs8 .LGspecB - beqz $r6, .LGret - or $r10, P3H, P3L - bnez $r10, .LGnan - -.LGinf: - move $r10, #0x7ff00000 - or P1H, P1H, $r10 - move P1L, #0 - j .LGret - -.LGspecB: - #ADD(O1L, O1L) - move $r15, O1L - add O1L, O1L, O1L - slt $r15, O1L, $r15 - - #ADDC(O1H, O1H) - add O1H, O1H, O1H - add O1H, O1H, $r15 - bnez $r9, .Li36 - or $r10, O1H, O1L - beqz $r10, .LGinf - - - #NORMd($r7, P2H, P2L) - bnez O1H, .LL68 - bnez O1L, .LL69 - move $r9, #0 - j .LL70 -.LL69: - move O1H, O1L - move O1L, #0 - move P2H, #32 - sub $r9, $r9, P2H -.LL68: -#ifndef __big_endian__ -#ifdef __NDS32_PERF_EXT__ - clz $r3, $r8 -#else - pushm $r0, $r2 - pushm $r4, $r5 - move $r0, $r8 - bal __clzsi2 - move $r3, $r0 - popm $r4, $r5 - popm $r0, $r2 -#endif -#else /* __big_endian__ */ -#ifdef __NDS32_PERF_EXT__ - clz $r2, $r7 -#else - pushm $r0, $r1 - pushm $r3, $r5 - move $r0, $r7 - bal __clzsi2 - move $r2, $r0 - popm $r3, $r5 - popm $r0, $r1 -#endif -#endif /* __big_endian__ */ - beqz P2H, .LL70 - sub $r9, $r9, P2H - subri P2L, P2H, #32 - srl P2L, O1L, P2L - sll O1L, O1L, P2H - sll O1H, O1H, P2H - or O1H, O1H, P2L -.LL70: - #NORMd End - - j .LGlab2 -.Li36: - or $r10, O1H, O1L - beqz $r10, .Li38 - -.LGnan: - move P1H, #0xfff80000 -.Li38: - move P1L, #0 - j .LGret - .size __divdf3, .-__divdf3 -#endif /* L_div_df */ - - - -#ifdef L_negate_sf - - .text - .align 2 - .global __negsf2 - .type __negsf2, @function -__negsf2: - push $lp - - move $r1, #0x80000000 - xor $r0, $r0, $r1 - -.LN999: - pop $lp - ret5 $lp - .size __negsf2, .-__negsf2 -#endif /* L_negate_sf */ - - - -#ifdef L_negate_df - -#ifndef __big_endian__ - #define P1H $r1 -#else - #define P1H $r0 -#endif - .text - .align 2 - .global __negdf2 - .type __negdf2, @function -__negdf2: - push $lp - - move $r2, #0x80000000 - xor P1H, P1H, $r2 - -.LP999: - pop $lp - ret5 $lp - .size __negdf2, .-__negdf2 -#endif /* L_negate_df */ - - - -#ifdef L_sf_to_df - -#ifndef __big_endian__ - #define O1L $r1 - #define O1H $r2 -#else - #define O1H $r1 - #define O1L $r2 -#endif - .text - .align 2 - .global __extendsfdf2 - .type __extendsfdf2, @function -__extendsfdf2: - push $lp - - srli $r3, $r0, #23 - andi $r3, $r3, #0xff - move $r5, #0x80000000 - and O1H, $r0, $r5 - addi $r5, $r3, #-1 - slti $r15, $r5, #0xfe - beqzs8 .LJspec - -.LJlab1: - addi $r3, $r3, #0x380 - slli $r5, $r0, #9 - srli $r5, $r5, #12 - or O1H, O1H, $r5 - slli O1L, $r0, #29 - -.LJret: - slli $r5, $r3, #20 - or O1H, O1H, $r5 - move $r0, $r1 - move $r1, $r2 - -.LJ999: - pop $lp - ret5 $lp - -.LJspec: - move O1L, #0 - add $r0, $r0, $r0 - beqz $r0, .LJret - bnez $r3, .Li42 - -.Lb43: - addi $r3, $r3, #-1 - add $r0, $r0, $r0 - move $r5, #0x800000 - slt $r15, $r0, $r5 - bnezs8 .Lb43 - j .LJlab1 -.Li42: - move $r3, #0x7ff - move $r5, #0xff000000 - slt $r15, $r5, $r0 - beqzs8 .LJret - move O1H, #0xfff80000 - j .LJret - .size __extendsfdf2, .-__extendsfdf2 -#endif /* L_sf_to_df */ - - - -#ifdef L_df_to_sf - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 - #define P2L $r2 - #define P2H $r3 -#else - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 -#endif - .text - .align 2 - .global __truncdfsf2 - .type __truncdfsf2, @function -__truncdfsf2: - push $lp - pushm $r6, $r8 - - slli P2H, P1H, #11 - srli $r7, P1L, #21 - or P2H, P2H, $r7 - slli P2L, P1L, #11 - move $r7, #0x80000000 - or P2H, P2H, $r7 - and $r5, P1H, $r7 - slli $r4, P1H, #1 - srli $r4, $r4, #21 - addi $r4, $r4, #0xfffffc80 - addi $r7, $r4, #-1 - slti $r15, $r7, #0xfe - beqzs8 .LKspec - -.LKlab1: - beqz P2L, .Li45 - ori P2H, P2H, #1 -.Li45: - #ADD(P2H, $0x80) - move $r15, #0x80 - add P2H, P2H, $r15 - slt $r15, P2H, $r15 - - #ADDC($r4, $0x0) - add $r4, $r4, $r15 - srli $r7, P2H, #8 - andi $r7, $r7, #1 - sub P2H, P2H, $r7 - slli P2H, P2H, #1 - srli P2H, P2H, #9 - slli $r7, $r4, #23 - or P2H, P2H, $r7 - or $r0, P2H, $r5 - -.LK999: - popm $r6, $r8 - pop $lp - ret5 $lp - -.LKspec: - subri $r15, $r4, #0x47f - bnezs8 .Li46 - slli $r7, P2H, #1 - or $r7, $r7, P2L - beqz $r7, .Li46 - move $r0, #0xffc00000 - j .LK999 -.Li46: - sltsi $r15, $r4, #0xff - bnezs8 .Li48 - move $r7, #0x7f800000 - or $r0, $r5, $r7 - j .LK999 -.Li48: - subri $r6, $r4, #1 - move $r7, #0x20 - slt $r15, $r6, $r7 - bnezs8 .Li49 - move $r0, $r5 - j .LK999 -.Li49: - subri $r8, $r6, #0x20 - sll $r7, P2H, $r8 - or P2L, P2L, $r7 - srl P2H, P2H, $r6 - move $r4, #0 - move $r7, #0x80000000 - or P2H, P2H, $r7 - j .LKlab1 - .size __truncdfsf2, .-__truncdfsf2 -#endif /* L_df_to_sf */ - - - -#ifdef L_df_to_si - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 -#else - #define P1H $r0 - #define P1L $r1 -#endif - .global __fixdfsi - .type __fixdfsi, @function -__fixdfsi: - push $lp - pushm $r6, $r6 - - slli $r3, P1H, #11 - srli $r6, P1L, #21 - or $r3, $r3, $r6 - move $r6, #0x80000000 - or $r3, $r3, $r6 - slli $r6, P1H, #1 - srli $r6, $r6, #21 - subri $r2, $r6, #0x41e - blez $r2, .LLnaninf - move $r6, #0x20 - slt $r15, $r2, $r6 - bnezs8 .LL72 - move $r3, #0 -.LL72: - srl $r3, $r3, $r2 - sltsi $r15, P1H, #0 - beqzs8 .Li50 - subri $r3, $r3, #0 -.Li50: - move $r0, $r3 - -.LL999: - popm $r6, $r6 - pop $lp - ret5 $lp - -.LLnaninf: - beqz P1L, .Li51 - ori P1H, P1H, #1 -.Li51: - move $r6, #0x7ff00000 - slt $r15, $r6, P1H - beqzs8 .Li52 - move $r0, #0x80000000 - j .LL999 -.Li52: - move $r0, #0x7fffffff - j .LL999 - .size __fixdfsi, .-__fixdfsi -#endif /* L_df_to_si */ - - - -#ifdef L_fixsfdi - -#ifndef __big_endian__ - #define O1L $r1 - #define O1H $r2 -#else - #define O1H $r1 - #define O1L $r2 -#endif - .text - .align 2 - .global __fixsfdi - .type __fixsfdi, @function -__fixsfdi: - push $lp - - srli $r3, $r0, #23 - andi $r3, $r3, #0xff - slli O1H, $r0, #8 - move $r5, #0x80000000 - or O1H, O1H, $r5 - move O1L, #0 - sltsi $r15, $r3, #0xbe - beqzs8 .LCinfnan - subri $r3, $r3, #0xbe -.LL8: - move $r5, #0x20 - slt $r15, $r3, $r5 - bnezs8 .LL9 - move O1L, O1H - move O1H, #0 - addi $r3, $r3, #0xffffffe0 - bnez O1L, .LL8 -.LL9: - beqz $r3, .LL10 - move $r4, O1H - srl O1L, O1L, $r3 - srl O1H, O1H, $r3 - subri $r3, $r3, #0x20 - sll $r4, $r4, $r3 - or O1L, O1L, $r4 -.LL10: - sltsi $r15, $r0, #0 - beqzs8 .LCret - - subri O1H, O1H, #0 - beqz O1L, .LL11 - subri O1L, O1L, #0 - subi45 O1H, #1 -.LL11: - -.LCret: - move $r0, $r1 - move $r1, $r2 - -.LC999: - pop $lp - ret5 $lp - -.LCinfnan: - sltsi $r15, $r0, #0 - bnezs8 .LCret3 - subri $r15, $r3, #0xff - bnezs8 .Li7 - slli $r5, O1H, #1 - beqz $r5, .Li7 - -.LCret3: - move O1H, #0x80000000 - j .LCret -.Li7: - move O1H, #0x7fffffff - move O1L, #-1 - j .LCret - .size __fixsfdi, .-__fixsfdi -#endif /* L_fixsfdi */ - - - -#ifdef L_fixdfdi - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 - #define O1L $r3 - #define O1H $r4 -#else - #define P1H $r0 - #define P1L $r1 - #define O1H $r3 - #define O1L $r4 -#endif - .text - .align 2 - .global __fixdfdi - .type __fixdfdi, @function -__fixdfdi: - push $lp - pushm $r6, $r6 - - slli $r5, P1H, #1 - srli $r5, $r5, #21 - slli O1H, P1H, #11 - srli $r6, P1L, #21 - or O1H, O1H, $r6 - slli O1L, P1L, #11 - move $r6, #0x80000000 - or O1H, O1H, $r6 - slti $r15, $r5, #0x43e - beqzs8 .LCnaninf - subri $r2, $r5, #0x43e -.LL14: - move $r6, #0x20 - slt $r15, $r2, $r6 - bnezs8 .LL15 - move O1L, O1H - move O1H, #0 - addi $r2, $r2, #0xffffffe0 - bnez O1L, .LL14 -.LL15: - beqz $r2, .LL16 - move P1L, O1H - srl O1L, O1L, $r2 - srl O1H, O1H, $r2 - subri $r2, $r2, #0x20 - sll P1L, P1L, $r2 - or O1L, O1L, P1L -.LL16: - sltsi $r15, P1H, #0 - beqzs8 .LCret - - subri O1H, O1H, #0 - beqz O1L, .LL17 - subri O1L, O1L, #0 - subi45 O1H, #1 -.LL17: - -.LCret: - move P1L, O1L - move P1H, O1H - -.LC999: - popm $r6, $r6 - pop $lp - ret5 $lp - -.LCnaninf: - sltsi $r15, P1H, #0 - bnezs8 .LCret3 - subri $r15, $r5, #0x7ff - bnezs8 .Li5 - slli $r6, O1H, #1 - or $r6, $r6, O1L - beqz $r6, .Li5 - -.LCret3: - move O1H, #0x80000000 - move O1L, #0 - j .LCret -.Li5: - move O1H, #0x7fffffff - move O1L, #-1 - j .LCret - .size __fixdfdi, .-__fixdfdi -#endif /* L_fixdfdi */ - - - -#ifdef L_fixunssfsi - - .global __fixunssfsi - .type __fixunssfsi, @function -__fixunssfsi: - push $lp - - slli $r1, $r0, #8 - move $r3, #0x80000000 - or $r1, $r1, $r3 - srli $r3, $r0, #23 - andi $r3, $r3, #0xff - subri $r2, $r3, #0x9e - sltsi $r15, $r2, #0 - bnezs8 .LLspec - sltsi $r15, $r2, #0x20 - bnezs8 .Li45 - move $r0, #0 - j .LL999 -.Li45: - srl $r1, $r1, $r2 - sltsi $r15, $r0, #0 - beqzs8 .Li46 - subri $r1, $r1, #0 -.Li46: - move $r0, $r1 - -.LL999: - pop $lp - ret5 $lp - -.LLspec: - move $r3, #0x7f800000 - slt $r15, $r3, $r0 - beqzs8 .Li47 - move $r0, #0x80000000 - j .LL999 -.Li47: - move $r0, #-1 - j .LL999 - .size __fixunssfsi, .-__fixunssfsi -#endif /* L_fixunssfsi */ - - - -#ifdef L_fixunsdfsi - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 -#else - #define P1H $r0 - #define P1L $r1 -#endif - .text - .align 2 - .global __fixunsdfsi - .type __fixunsdfsi, @function -__fixunsdfsi: - push $lp - pushm $r6, $r6 - - slli $r3, P1H, #11 - srli $r6, P1L, #21 - or $r3, $r3, $r6 - move $r6, #0x80000000 - or $r3, $r3, $r6 - slli $r6, P1H, #1 - srli $r6, $r6, #21 - subri $r2, $r6, #0x41e - sltsi $r15, $r2, #0 - bnezs8 .LNnaninf - move $r6, #0x20 - slt $r15, $r2, $r6 - bnezs8 .LL73 - move $r3, #0 -.LL73: - srl $r3, $r3, $r2 - sltsi $r15, P1H, #0 - beqzs8 .Li53 - subri $r3, $r3, #0 -.Li53: - move $r0, $r3 - -.LN999: - popm $r6, $r6 - pop $lp - ret5 $lp - -.LNnaninf: - beqz P1L, .Li54 - ori P1H, P1H, #1 -.Li54: - move $r6, #0x7ff00000 - slt $r15, $r6, P1H - beqzs8 .Li55 - move $r0, #0x80000000 - j .LN999 -.Li55: - move $r0, #-1 - j .LN999 - .size __fixunsdfsi, .-__fixunsdfsi -#endif /* L_fixunsdfsi */ - - - -#ifdef L_fixunssfdi - -#ifndef __big_endian__ - #define O1L $r1 - #define O1H $r2 -#else - #define O1H $r1 - #define O1L $r2 -#endif - .text - .align 2 - .global __fixunssfdi - .type __fixunssfdi, @function -__fixunssfdi: - push $lp - - srli $r3, $r0, #23 - andi $r3, $r3, #0xff - slli O1H, $r0, #8 - move $r5, #0x80000000 - or O1H, O1H, $r5 - move O1L, #0 - sltsi $r15, $r3, #0xbe - beqzs8 .LDinfnan - subri $r3, $r3, #0xbe -.LL12: - move $r5, #0x20 - slt $r15, $r3, $r5 - bnezs8 .LL13 - move O1L, O1H - move O1H, #0 - addi $r3, $r3, #0xffffffe0 - bnez O1L, .LL12 -.LL13: - beqz $r3, .LL14 - move $r4, O1H - srl O1L, O1L, $r3 - srl O1H, O1H, $r3 - subri $r3, $r3, #0x20 - sll $r4, $r4, $r3 - or O1L, O1L, $r4 -.LL14: - sltsi $r15, $r0, #0 - beqzs8 .LDret - - subri O1H, O1H, #0 - beqz O1L, .LL15 - subri O1L, O1L, #0 - subi45 O1H, #1 -.LL15: - -.LDret: - move $r0, $r1 - move $r1, $r2 - -.LD999: - pop $lp - ret5 $lp - -.LDinfnan: - move O1H, #0x80000000 - move O1L, #0 - j .LDret - .size __fixunssfdi, .-__fixunssfdi -#endif /* L_fixunssfdi */ - - - -#ifdef L_fixunsdfdi - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 - #define O1L $r3 - #define O1H $r4 -#else - #define P1H $r0 - #define P1L $r1 - #define O1H $r3 - #define O1L $r4 -#endif - .text - .align 2 - .global __fixunsdfdi - .type __fixunsdfdi, @function -__fixunsdfdi: - push $lp - pushm $r6, $r6 - - slli $r5, P1H, #1 - srli $r5, $r5, #21 - slli O1H, P1H, #11 - srli $r6, P1L, #21 - or O1H, O1H, $r6 - slli O1L, P1L, #11 - move $r6, #0x80000000 - or O1H, O1H, $r6 - slti $r15, $r5, #0x43e - beqzs8 .LDnaninf - subri $r2, $r5, #0x43e -.LL18: - move $r6, #0x20 - slt $r15, $r2, $r6 - bnezs8 .LL19 - move O1L, O1H - move O1H, #0 - addi $r2, $r2, #0xffffffe0 - bnez O1L, .LL18 -.LL19: - beqz $r2, .LL20 - move P1L, O1H - srl O1L, O1L, $r2 - srl O1H, O1H, $r2 - subri $r2, $r2, #0x20 - sll P1L, P1L, $r2 - or O1L, O1L, P1L -.LL20: - sltsi $r15, P1H, #0 - beqzs8 .LDret - - subri O1H, O1H, #0 - beqz O1L, .LL21 - subri O1L, O1L, #0 - subi45 O1H, #1 -.LL21: - -.LDret: - move P1L, O1L - move P1H, O1H - -.LD999: - popm $r6, $r6 - pop $lp - ret5 $lp - -.LDnaninf: - move O1H, #0x80000000 - move O1L, #0 - j .LDret - .size __fixunsdfdi, .-__fixunsdfdi -#endif /* L_fixunsdfdi */ - - - -#ifdef L_si_to_sf - - .text - .align 2 - .global __floatsisf - .type __floatsisf, @function -__floatsisf: - push $lp - - move $r4, #0x80000000 - and $r2, $r0, $r4 - beqz $r0, .Li39 - sltsi $r15, $r0, #0 - beqzs8 .Li40 - subri $r0, $r0, #0 -.Li40: - move $r1, #0x9e -#ifdef __NDS32_PERF_EXT__ - clz $r3, $r0 -#else - pushm $r0, $r2 - pushm $r4, $r5 - bal __clzsi2 - move $r3, $r0 - popm $r4, $r5 - popm $r0, $r2 -#endif - sub $r1, $r1, $r3 - sll $r0, $r0, $r3 - - #ADD($r0, $0x80) - move $r15, #0x80 - add $r0, $r0, $r15 - slt $r15, $r0, $r15 - - #ADDC($r1, $0x0) - add $r1, $r1, $r15 - srai $r4, $r0, #8 - andi $r4, $r4, #1 - sub $r0, $r0, $r4 - slli $r0, $r0, #1 - srli $r0, $r0, #9 - slli $r4, $r1, #23 - or $r0, $r0, $r4 -.Li39: - or $r0, $r0, $r2 - -.LH999: - pop $lp - ret5 $lp - .size __floatsisf, .-__floatsisf -#endif /* L_si_to_sf */ - - - -#ifdef L_si_to_df - -#ifndef __big_endian__ - #define O1L $r1 - #define O1H $r2 - #define O2L $r4 - #define O2H $r5 -#else - #define O1H $r1 - #define O1L $r2 - #define O2H $r4 - #define O2L $r5 -#endif - .text - .align 2 - .global __floatsidf - .type __floatsidf, @function -__floatsidf: - push $lp - pushm $r6, $r6 - - move O1L, #0 - move O2H, O1L - move $r3, O1L - move O1H, $r0 - beqz O1H, .Li39 - sltsi $r15, O1H, #0 - beqzs8 .Li40 - move O2H, #0x80000000 - - subri O1H, O1H, #0 - beqz O1L, .LL71 - subri O1L, O1L, #0 - subi45 O1H, #1 -.LL71: -.Li40: - move $r3, #0x41e -#ifndef __big_endian__ -#ifdef __NDS32_PERF_EXT__ - clz $r4, $r2 -#else - pushm $r0, $r3 - push $r5 - move $r0, $r2 - bal __clzsi2 - move $r4, $r0 - pop $r5 - popm $r0, $r3 -#endif -#else /* __big_endian__ */ -#ifdef __NDS32_PERF_EXT__ - clz $r5, $r1 -#else - pushm $r0, $r4 - move $r0, $r1 - bal __clzsi2 - move $r5, $r0 - popm $r0, $r4 -#endif -#endif /* __big_endian__ */ - sub $r3, $r3, O2L - sll O1H, O1H, O2L -.Li39: - srli O2L, O1L, #11 - slli $r6, O1H, #21 - or O2L, O2L, $r6 - slli $r6, O1H, #1 - srli $r6, $r6, #12 - or O2H, O2H, $r6 - slli $r6, $r3, #20 - or O2H, O2H, $r6 - move $r0, $r4 - move $r1, $r5 - -.LH999: - popm $r6, $r6 - pop $lp - ret5 $lp - .size __floatsidf, .-__floatsidf -#endif /* L_si_to_df */ - - - -#ifdef L_floatdisf - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 - #define P2L $r2 - #define P2H $r3 -#else - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 -#endif - .text - .align 2 - .global __floatdisf - .type __floatdisf, @function -__floatdisf: - push $lp - pushm $r6, $r7 - - move $r7, #0x80000000 - and $r5, P1H, $r7 - move P2H, P1H - move P2L, P1L - or $r7, P1H, P1L - beqz $r7, .Li1 - sltsi $r15, P1H, #0 - beqzs8 .Li2 - - subri P2H, P2H, #0 - beqz P2L, .LL1 - subri P2L, P2L, #0 - subi45 P2H, #1 -.LL1: -.Li2: - move $r4, #0xbe - - - #NORMd($r2, $r6, P1L) - bnez P2H, .LL2 - bnez P2L, .LL3 - move $r4, #0 - j .LL4 -.LL3: - move P2H, P2L - move P2L, #0 - move $r6, #32 - sub $r4, $r4, $r6 -.LL2: -#ifdef __NDS32_PERF_EXT__ - clz $r6, P2H -#else - pushm $r0, $r5 - move $r0, P2H - bal __clzsi2 - move $r6, $r0 - popm $r0, $r5 -#endif - beqz $r6, .LL4 - sub $r4, $r4, $r6 - subri P1L, $r6, #32 - srl P1L, P2L, P1L - sll P2L, P2L, $r6 - sll P2H, P2H, $r6 - or P2H, P2H, P1L -.LL4: - #NORMd End - - beqz P2L, .Li3 - ori P2H, P2H, #1 -.Li3: - #ADD(P2H, $0x80) - move $r15, #0x80 - add P2H, P2H, $r15 - slt $r15, P2H, $r15 - - #ADDC($r4, $0x0) - add $r4, $r4, $r15 - srli $r7, P2H, #8 - andi $r7, $r7, #1 - sub P2H, P2H, $r7 - slli P2H, P2H, #1 - srli P2H, P2H, #9 - slli $r7, $r4, #23 - or P2H, P2H, $r7 -.Li1: - or $r0, P2H, $r5 - -.LA999: - popm $r6, $r7 - pop $lp - ret5 $lp - .size __floatdisf, .-__floatdisf -#endif /* L_floatdisf */ - - - -#ifdef L_floatdidf - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 - #define P2L $r2 - #define P2H $r3 - #define O1L $r5 - #define O1H $r6 -#else - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 - #define O1H $r5 - #define O1L $r6 -#endif - .text - .align 2 - .global __floatdidf - .type __floatdidf, @function -__floatdidf: - push $lp - pushm $r6, $r8 - - move $r4, #0 - move $r7, $r4 - move P2H, P1H - move P2L, P1L - or $r8, P1H, P1L - beqz $r8, .Li1 - move $r4, #0x43e - sltsi $r15, P1H, #0 - beqzs8 .Li2 - move $r7, #0x80000000 - - subri P2H, P2H, #0 - beqz P2L, .LL1 - subri P2L, P2L, #0 - subi45 P2H, #1 -.LL1: - -.Li2: - #NORMd($r2, O1H, O1L) - bnez P2H, .LL2 - bnez P2L, .LL3 - move $r4, #0 - j .LL4 -.LL3: - move P2H, P2L - move P2L, #0 - move O1H, #32 - sub $r4, $r4, O1H -.LL2: -#ifdef __NDS32_PERF_EXT__ - clz O1H, P2H -#else /* not __NDS32_PERF_EXT__ */ -/* - Replace clz with function call. - clz O1H, P2H - EL: clz $r6, $r3 - EB: clz $r5, $r2 -*/ -#ifndef __big_endian__ - pushm $r0, $r5 - move $r0, $r3 - bal __clzsi2 - move $r6, $r0 - popm $r0, $r5 -#else - pushm $r0, $r4 - move $r0, $r2 - bal __clzsi2 - move $r5, $r0 - popm $r0, $r4 -#endif -#endif /* not __NDS32_PERF_EXT__ */ - beqz O1H, .LL4 - sub $r4, $r4, O1H - subri O1L, O1H, #32 - srl O1L, P2L, O1L - sll P2L, P2L, O1H - sll P2H, P2H, O1H - or P2H, P2H, O1L -.LL4: - #NORMd End - - #ADD(P2L, $0x400) - move $r15, #0x400 - add P2L, P2L, $r15 - slt $r15, P2L, $r15 - - - #ADDCC(P2H, $0x0) - beqzs8 .LL7 - add P2H, P2H, $r15 - slt $r15, P2H, $r15 -.LL7: - - #ADDC($r4, $0x0) - add $r4, $r4, $r15 - srli $r8, P2L, #11 - andi $r8, $r8, #1 - sub P2L, P2L, $r8 -.Li1: - srli O1L, P2L, #11 - slli $r8, P2H, #21 - or O1L, O1L, $r8 - slli O1H, P2H, #1 - srli O1H, O1H, #12 - slli $r8, $r4, #20 - or O1H, O1H, $r8 - or O1H, O1H, $r7 - move P1L, O1L - move P1H, O1H - -.LA999: - popm $r6, $r8 - pop $lp - ret5 $lp - .size __floatdidf, .-__floatdidf -#endif /* L_floatdidf */ - - - -#ifdef L_floatunsisf - - .text - .align 2 - .global __floatunsisf - .type __floatunsisf, @function -__floatunsisf: - push $lp - - beqz $r0, .Li41 - move $r2, #0x9e -#ifdef __NDS32_PERF_EXT__ - clz $r1, $r0 -#else - push $r0 - pushm $r2, $r5 - bal __clzsi2 - move $r1, $r0 - popm $r2, $r5 - pop $r0 -#endif - - sub $r2, $r2, $r1 - sll $r0, $r0, $r1 - - #ADD($r0, $0x80) - move $r15, #0x80 - add $r0, $r0, $r15 - slt $r15, $r0, $r15 - - #ADDC($r2, $0x0) - add $r2, $r2, $r15 - srli $r3, $r0, #8 - andi $r3, $r3, #1 - sub $r0, $r0, $r3 - slli $r0, $r0, #1 - srli $r0, $r0, #9 - slli $r3, $r2, #23 - or $r0, $r0, $r3 - -.Li41: -.LI999: - pop $lp - ret5 $lp - .size __floatunsisf, .-__floatunsisf -#endif /* L_floatunsisf */ - - - -#ifdef L_floatunsidf - -#ifndef __big_endian__ - #define O1L $r1 - #define O1H $r2 - #define O2L $r4 - #define O2H $r5 -#else - #define O1H $r1 - #define O1L $r2 - #define O2H $r4 - #define O2L $r5 -#endif - .text - .align 2 - .global __floatunsidf - .type __floatunsidf, @function -__floatunsidf: - push $lp - pushm $r6, $r6 - - move O1L, #0 - move $r3, O1L - move O1H, $r0 - beqz O1H, .Li41 - move $r3, #0x41e -#ifndef __big_endian__ -#ifdef __NDS32_PERF_EXT__ - clz $r5, $r2 -#else - pushm $r0, $r4 - move $r0, $r2 - bal __clzsi2 - move $r5, $r0 - popm $r0, $r4 -#endif -#else /* __big_endian__ */ -#ifdef __NDS32_PERF_EXT__ - clz $r4, $r1 -#else - pushm $r0, $r3 - push $r5 - move $r0, $r1 - bal __clzsi2 - move $r4, $r0 - pop $r5 - popm $r0, $r3 -#endif -#endif /* __big_endian__ */ - sub $r3, $r3, O2H - sll O1H, O1H, O2H -.Li41: - srli O2L, O1L, #11 - slli $r6, O1H, #21 - or O2L, O2L, $r6 - slli O2H, O1H, #1 - srli O2H, O2H, #12 - slli $r6, $r3, #20 - or O2H, O2H, $r6 - move $r0, $r4 - move $r1, $r5 - -.LI999: - popm $r6, $r6 - pop $lp - ret5 $lp - .size __floatunsidf, .-__floatunsidf -#endif /* L_floatunsidf */ - - - -#ifdef L_floatundisf - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 - #define P2L $r2 - #define P2H $r3 -#else - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 -#endif - .text - .align 2 - .global __floatundisf - .type __floatundisf, @function -__floatundisf: - push $lp - pushm $r6, $r6 - - move P2H, P1H - move P2L, P1L - or $r6, P1H, P1L - beqz $r6, .Li4 - move $r4, #0xbe - - - #NORMd($r2, $r5, P1L) - bnez P2H, .LL5 - bnez P2L, .LL6 - move $r4, #0 - j .LL7 -.LL6: - move P2H, P2L - move P2L, #0 - move $r5, #32 - sub $r4, $r4, $r5 -.LL5: -#ifdef __NDS32_PERF_EXT__ - clz $r5, P2H -#else - pushm $r0, $r4 - move $r0, P2H - bal __clzsi2 - move $r5, $r0 - popm $r0, $r4 -#endif - beqz $r5, .LL7 - sub $r4, $r4, $r5 - subri P1L, $r5, #32 - srl P1L, P2L, P1L - sll P2L, P2L, $r5 - sll P2H, P2H, $r5 - or P2H, P2H, P1L -.LL7: - #NORMd End - - beqz P2L, .Li5 - ori P2H, P2H, #1 -.Li5: - #ADD(P2H, $0x80) - move $r15, #0x80 - add P2H, P2H, $r15 - slt $r15, P2H, $r15 - - #ADDC($r4, $0x0) - add $r4, $r4, $r15 - srli $r6, P2H, #8 - andi $r6, $r6, #1 - sub P2H, P2H, $r6 - slli P2H, P2H, #1 - srli P2H, P2H, #9 - slli $r6, $r4, #23 - or P2H, P2H, $r6 -.Li4: - move $r0, P2H - -.LB999: - popm $r6, $r6 - pop $lp - ret5 $lp - .size __floatundisf, .-__floatundisf -#endif /* L_floatundisf */ - - - -#ifdef L_floatundidf - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 - #define P2L $r2 - #define P2H $r3 - #define O1L $r5 - #define O1H $r6 -#else - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 - #define O1H $r5 - #define O1L $r6 -#endif - .text - .align 2 - .global __floatundidf - .type __floatundidf, @function -__floatundidf: - push $lp - pushm $r6, $r7 - - move $r4, #0 - move P2H, P1H - move P2L, P1L - or $r7, P1H, P1L - beqz $r7, .Li3 - move $r4, #0x43e - - - #NORMd($r2, O1H, O1L) - bnez P2H, .LL8 - bnez P2L, .LL9 - move $r4, #0 - j .LL10 -.LL9: - move P2H, P2L - move P2L, #0 - move O1H, #32 - sub $r4, $r4, O1H -.LL8: -#ifdef __NDS32_PERF_EXT__ - clz O1H, P2H -#else /* not __NDS32_PERF_EXT__ */ -/* - Replace clz with function call. - clz O1H, P2H - EL: clz $r6, $r3 - EB: clz $r5, $r2 -*/ -#ifndef __big_endian__ - pushm $r0, $r5 - move $r0, $r3 - bal __clzsi2 - move $r6, $r0 - popm $r0, $r5 -#else - pushm $r0, $r4 - move $r0, $r2 - bal __clzsi2 - move $r5, $r0 - popm $r0, $r4 -#endif -#endif /* not __NDS32_PERF_EXT__ */ - beqz O1H, .LL10 - sub $r4, $r4, O1H - subri O1L, O1H, #32 - srl O1L, P2L, O1L - sll P2L, P2L, O1H - sll P2H, P2H, O1H - or P2H, P2H, O1L -.LL10: - #NORMd End - - #ADD(P2L, $0x400) - move $r15, #0x400 - add P2L, P2L, $r15 - slt $r15, P2L, $r15 - - - #ADDCC(P2H, $0x0) - beqzs8 .LL13 - add P2H, P2H, $r15 - slt $r15, P2H, $r15 -.LL13: - - #ADDC($r4, $0x0) - add $r4, $r4, $r15 - srli $r7, P2L, #11 - andi $r7, $r7, #1 - sub P2L, P2L, $r7 -.Li3: - srli O1L, P2L, #11 - slli $r7, P2H, #21 - or O1L, O1L, $r7 - slli O1H, P2H, #1 - srli O1H, O1H, #12 - slli $r7, $r4, #20 - or O1H, O1H, $r7 - move P1L, O1L - move P1H, O1H - -.LB999: - popm $r6, $r7 - pop $lp - ret5 $lp - .size __floatundidf, .-__floatundidf -#endif /* L_floatundidf */ - - - -#ifdef L_compare_sf - - .text - .align 2 - .global __cmpsf2 - .type __cmpsf2, @function -__cmpsf2: - .global __eqsf2 - .type __eqsf2, @function -__eqsf2: - .global __ltsf2 - .type __ltsf2, @function -__ltsf2: - .global __lesf2 - .type __lesf2, @function -__lesf2: - .global __nesf2 - .type __nesf2, @function -__nesf2: - move $r4, #1 - j .LA - - .global __gesf2 - .type __gesf2, @function -__gesf2: - .global __gtsf2 - .type __gtsf2, @function -__gtsf2: - move $r4, #-1 -.LA: - push $lp - - slli $r2, $r0, #1 - slli $r3, $r1, #1 - or $r5, $r2, $r3 - beqz $r5, .LMequ - move $r5, #0xff000000 - slt $r15, $r5, $r2 - bnezs8 .LMnan - slt $r15, $r5, $r3 - bnezs8 .LMnan - srli $r2, $r2, #1 - sltsi $r15, $r0, #0 - beqzs8 .Li48 - subri $r2, $r2, #0 -.Li48: - srli $r3, $r3, #1 - sltsi $r15, $r1, #0 - beqzs8 .Li49 - subri $r3, $r3, #0 -.Li49: - slts $r15, $r2, $r3 - beqzs8 .Li50 - move $r0, #-1 - j .LM999 -.Li50: - slts $r15, $r3, $r2 - beqzs8 .LMequ - move $r0, #1 - j .LM999 - -.LMequ: - move $r0, #0 - -.LM999: - pop $lp - ret5 $lp - -.LMnan: - move $r0, $r4 - j .LM999 - .size __cmpsf2, .-__cmpsf2 - .size __eqsf2, .-__eqsf2 - .size __ltsf2, .-__ltsf2 - .size __lesf2, .-__lesf2 - .size __nesf2, .-__nesf2 - .size __gesf2, .-__gesf2 - .size __gtsf2, .-__gtsf2 -#endif /* L_compare_sf */ - - - -#ifdef L_compare_df - -#ifdef __big_endian__ - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 -#else - #define P1H $r1 - #define P1L $r0 - #define P2H $r3 - #define P2L $r2 -#endif - .align 2 - .globl __gtdf2 - .globl __gedf2 - .globl __ltdf2 - .globl __ledf2 - .globl __eqdf2 - .globl __nedf2 - .globl __cmpdf2 - .type __gtdf2, @function - .type __gedf2, @function - .type __ltdf2, @function - .type __ledf2, @function - .type __eqdf2, @function - .type __nedf2, @function - .type __cmpdf2, @function -__gtdf2: -__gedf2: - movi $r4, -1 - b .L1 - -__ltdf2: -__ledf2: -__cmpdf2: -__nedf2: -__eqdf2: - movi $r4, 1 -.L1: -#if defined (__NDS32_ISA_V3M__) - push25 $r10, 0 -#else - smw.adm $r6, [$sp], $r9, 0 -#endif - - sethi $r5, 0x7ff00 - and $r6, P1H, $r5 ! r6=aExp - and $r7, P2H, $r5 ! r7=bExp - slli $r8, P1H, 12 ! r8=aSig0 - slli $r9, P2H, 12 ! r9=bSig0 - beq $r6, $r5, .L11 ! aExp==0x7ff - beq $r7, $r5, .L12 ! bExp==0x7ff -.L2: - slli $ta, P1H, 1 ! ta=ahigh<<1 - or $ta, P1L, $ta ! - xor $r5, P1H, P2H ! r5=ahigh^bhigh - beqz $ta, .L3 ! if(ahigh<<1)==0,go .L3 - !------------------------------- - ! (ahigh<<1)!=0 || (bhigh<<1)!=0 - !------------------------------- -.L4: - beqz $r5, .L5 ! ahigh==bhigh, go .L5 - !-------------------- - ! a != b - !-------------------- -.L6: - bltz $r5, .L7 ! if(aSign!=bSign), go .L7 - !-------------------- - ! aSign==bSign - !-------------------- - slt $ta, $r6, $r7 ! ta=(aExp|b|), go .L10 - nor $r0, P2H, P2H ! if(|a|<|b|),return (~yh) -.L14: -#if defined (__NDS32_ISA_V3M__) - pop25 $r10, 0 -#else - lmw.bim $r6, [$sp], $r9, 0 - ret -#endif -.L10: - ori $r0, P2H, 1 ! return (yh|1) - b .L14 - !-------------------- - ! (ahigh<<1)=0 - !-------------------- -.L3: - slli $ta, P2H, 1 ! ta=bhigh<<1 - or $ta, P2L, $ta ! - bnez $ta, .L4 ! ta=(bhigh<<1)!=0,go .L4 -.L5: - xor $ta, P1L, P2L ! ta=alow^blow - bnez $ta, .L6 ! alow!=blow,go .L6 - movi $r0, 0 ! a==b, return 0 - b .L14 - !-------------------- - ! aExp=0x7ff; - !-------------------- -.L11: - or P1L, P1L, $r8 ! x1=(aSig0|aSig1) - bnez P1L, .L13 ! if(a=nan), go.L13 - xor $ta, $r7, $r5 ! ta=(bExp^0x7ff) - bnez $ta, .L2 ! if(bExp!=0x7ff), go .L2 - !-------------------- - ! bExp=0x7ff; - !-------------------- -.L12: - or $ta, P2L, $r9 ! ta=(bSig0|bSig1) - beqz $ta, .L2 ! if(b!=nan), go .L2 -.L13: - move $r0, $r4 - b .L14 - !-------------------- - ! aSign!=bSign - !-------------------- -.L7: - ori $r0, P1H, 1 ! if(aSign!=bSign), return (ahigh|1) - b .L14 - - .size __gtdf2, .-__gtdf2 - .size __gedf2, .-__gedf2 - .size __ltdf2, .-__ltdf2 - .size __ledf2, .-__ledf2 - .size __eqdf2, .-__eqdf2 - .size __nedf2, .-__nedf2 - .size __cmpdf2, .-__cmpdf2 -#endif /* L_compare_df */ - - - -#ifdef L_unord_sf - - .text - .align 2 - .global __unordsf2 - .type __unordsf2, @function -__unordsf2: - push $lp - - slli $r2, $r0, #1 - move $r3, #0xff000000 - slt $r15, $r3, $r2 - beqzs8 .Li52 - move $r0, #1 - j .LP999 -.Li52: - slli $r2, $r1, #1 - move $r3, #0xff000000 - slt $r15, $r3, $r2 - beqzs8 .Li53 - move $r0, #1 - j .LP999 -.Li53: - move $r0, #0 - -.LP999: - pop $lp - ret5 $lp - .size __unordsf2, .-__unordsf2 -#endif /* L_unord_sf */ - - - -#ifdef L_unord_df - -#ifndef __big_endian__ - #define P1L $r0 - #define P1H $r1 - #define P2L $r2 - #define P2H $r3 -#else - #define P1H $r0 - #define P1L $r1 - #define P2H $r2 - #define P2L $r3 -#endif - .text - .align 2 - .global __unorddf2 - .type __unorddf2, @function -__unorddf2: - push $lp - - slli $r4, P1H, #1 - beqz P1L, .Li66 - addi $r4, $r4, #1 -.Li66: - move $r5, #0xffe00000 - slt $r15, $r5, $r4 - beqzs8 .Li67 - move $r0, #1 - j .LR999 -.Li67: - slli $r4, P2H, #1 - beqz P2L, .Li68 - addi $r4, $r4, #1 -.Li68: - move $r5, #0xffe00000 - slt $r15, $r5, $r4 - beqzs8 .Li69 - move $r0, #1 - j .LR999 -.Li69: - move $r0, #0 - -.LR999: - pop $lp - ret5 $lp - .size __unorddf2, .-__unorddf2 -#endif /* L_unord_df */ -/* ------------------------------------------- */ -/* DPBIT floating point operations for libgcc */ -/* ------------------------------------------- */ diff --git a/libgcc/config/nds32/lib2csrc-mculib/_clzdi2.c b/libgcc/config/nds32/lib2csrc-mculib/_clzdi2.c deleted file mode 100644 index 6afd6ab..0000000 --- a/libgcc/config/nds32/lib2csrc-mculib/_clzdi2.c +++ /dev/null @@ -1,38 +0,0 @@ -/* mculib libgcc routines 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -extern int __clzsi2 (int val); -int -__clzdi2 (long long val) -{ - if (val >> 32) - { - return __clzsi2 (val >> 32); - } - else - { - return __clzsi2 (val) + 32; - } -} diff --git a/libgcc/config/nds32/lib2csrc-mculib/_clzsi2.c b/libgcc/config/nds32/lib2csrc-mculib/_clzsi2.c deleted file mode 100644 index 407caaf..0000000 --- a/libgcc/config/nds32/lib2csrc-mculib/_clzsi2.c +++ /dev/null @@ -1,49 +0,0 @@ -/* mculib libgcc routines 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -int -__clzsi2 (int val) -{ - int i = 32; - int j = 16; - int temp; - - for (; j; j >>= 1) - { - if (temp = val >> j) - { - if (j == 1) - { - return (i - 2); - } - else - { - i -= j; - val = temp; - } - } - } - return (i - val); -} diff --git a/libgcc/config/nds32/linux-atomic.c b/libgcc/config/nds32/linux-atomic.c new file mode 100644 index 0000000..69f589b --- /dev/null +++ b/libgcc/config/nds32/linux-atomic.c @@ -0,0 +1,282 @@ +/* Linux-specific atomic operations for NDS32 Linux. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3, or (at your option) any +later version. + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +/* We implement byte, short and int versions of each atomic operation + using the kernel helper defined below. There is no support for + 64-bit operations yet. */ + +/* This function copy form NDS32 Linux-kernal. */ +static inline int +__kernel_cmpxchg (int oldval, int newval, int *mem) +{ + int temp1, temp2, temp3, offset; + + asm volatile ("msync\tall\n" + "movi\t%0, #0\n" + "1:\n" + "\tllw\t%1, [%4+%0]\n" + "\tsub\t%3, %1, %6\n" + "\tcmovz\t%2, %5, %3\n" + "\tcmovn\t%2, %1, %3\n" + "\tscw\t%2, [%4+%0]\n" + "\tbeqz\t%2, 1b\n" + : "=&r" (offset), "=&r" (temp3), "=&r" (temp2), "=&r" (temp1) + : "r" (mem), "r" (newval), "r" (oldval) : "memory"); + + return temp1; +} + +#define HIDDEN __attribute__ ((visibility ("hidden"))) + +#ifdef __NDS32_EL__ +#define INVERT_MASK_1 0 +#define INVERT_MASK_2 0 +#else +#define INVERT_MASK_1 24 +#define INVERT_MASK_2 16 +#endif + +#define MASK_1 0xffu +#define MASK_2 0xffffu + +#define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP) \ + int HIDDEN \ + __sync_fetch_and_##OP##_4 (int *ptr, int val) \ + { \ + int failure, tmp; \ + \ + do { \ + tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ + failure = __kernel_cmpxchg (tmp, PFX_OP (tmp INF_OP val), ptr); \ + } while (failure != 0); \ + \ + return tmp; \ + } + +FETCH_AND_OP_WORD (add, , +) +FETCH_AND_OP_WORD (sub, , -) +FETCH_AND_OP_WORD (or, , |) +FETCH_AND_OP_WORD (and, , &) +FETCH_AND_OP_WORD (xor, , ^) +FETCH_AND_OP_WORD (nand, ~, &) + +#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH +#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH + +/* Implement both __sync__and_fetch and __sync_fetch_and_ for + subword-sized quantities. */ + +#define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN) \ + TYPE HIDDEN \ + NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val) \ + { \ + int *wordptr = (int *) ((unsigned long) ptr & ~3); \ + unsigned int mask, shift, oldval, newval; \ + int failure; \ + \ + shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ + mask = MASK_##WIDTH << shift; \ + \ + do { \ + oldval = __atomic_load_n (wordptr, __ATOMIC_SEQ_CST); \ + newval = ((PFX_OP (((oldval & mask) >> shift) \ + INF_OP (unsigned int) val)) << shift) & mask; \ + newval |= oldval & ~mask; \ + failure = __kernel_cmpxchg (oldval, newval, wordptr); \ + } while (failure != 0); \ + \ + return (RETURN & mask) >> shift; \ + } + + +SUBWORD_SYNC_OP (add, , +, unsigned short, 2, oldval) +SUBWORD_SYNC_OP (sub, , -, unsigned short, 2, oldval) +SUBWORD_SYNC_OP (or, , |, unsigned short, 2, oldval) +SUBWORD_SYNC_OP (and, , &, unsigned short, 2, oldval) +SUBWORD_SYNC_OP (xor, , ^, unsigned short, 2, oldval) +SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, oldval) + +SUBWORD_SYNC_OP (add, , +, unsigned char, 1, oldval) +SUBWORD_SYNC_OP (sub, , -, unsigned char, 1, oldval) +SUBWORD_SYNC_OP (or, , |, unsigned char, 1, oldval) +SUBWORD_SYNC_OP (and, , &, unsigned char, 1, oldval) +SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, oldval) +SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, oldval) + +#define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP) \ + int HIDDEN \ + __sync_##OP##_and_fetch_4 (int *ptr, int val) \ + { \ + int tmp, failure; \ + \ + do { \ + tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); \ + failure = __kernel_cmpxchg (tmp, PFX_OP (tmp INF_OP val), ptr); \ + } while (failure != 0); \ + \ + return PFX_OP (tmp INF_OP val); \ + } + +OP_AND_FETCH_WORD (add, , +) +OP_AND_FETCH_WORD (sub, , -) +OP_AND_FETCH_WORD (or, , |) +OP_AND_FETCH_WORD (and, , &) +OP_AND_FETCH_WORD (xor, , ^) +OP_AND_FETCH_WORD (nand, ~, &) + +SUBWORD_SYNC_OP (add, , +, unsigned short, 2, newval) +SUBWORD_SYNC_OP (sub, , -, unsigned short, 2, newval) +SUBWORD_SYNC_OP (or, , |, unsigned short, 2, newval) +SUBWORD_SYNC_OP (and, , &, unsigned short, 2, newval) +SUBWORD_SYNC_OP (xor, , ^, unsigned short, 2, newval) +SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, newval) + +SUBWORD_SYNC_OP (add, , +, unsigned char, 1, newval) +SUBWORD_SYNC_OP (sub, , -, unsigned char, 1, newval) +SUBWORD_SYNC_OP (or, , |, unsigned char, 1, newval) +SUBWORD_SYNC_OP (and, , &, unsigned char, 1, newval) +SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, newval) +SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, newval) + +int HIDDEN +__sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval) +{ + int actual_oldval, fail; + + while (1) + { + actual_oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); + + if (oldval != actual_oldval) + return actual_oldval; + + fail = __kernel_cmpxchg (actual_oldval, newval, ptr); + + if (!fail) + return oldval; + } +} + +#define SUBWORD_VAL_CAS(TYPE, WIDTH) \ + TYPE HIDDEN \ + __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ + TYPE newval) \ + { \ + int *wordptr = (int *)((unsigned long) ptr & ~3), fail; \ + unsigned int mask, shift, actual_oldval, actual_newval; \ + \ + shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ + mask = MASK_##WIDTH << shift; \ + \ + while (1) \ + { \ + actual_oldval = __atomic_load_n (wordptr, __ATOMIC_SEQ_CST); \ + \ + if (((actual_oldval & mask) >> shift) != (unsigned int) oldval) \ + return (actual_oldval & mask) >> shift; \ + \ + actual_newval = (actual_oldval & ~mask) \ + | (((unsigned int) newval << shift) & mask); \ + \ + fail = __kernel_cmpxchg (actual_oldval, actual_newval, \ + wordptr); \ + \ + if (!fail) \ + return oldval; \ + } \ + } + +SUBWORD_VAL_CAS (unsigned short, 2) +SUBWORD_VAL_CAS (unsigned char, 1) + +typedef unsigned char bool; + +bool HIDDEN +__sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval) +{ + int failure = __kernel_cmpxchg (oldval, newval, ptr); + return (failure == 0); +} + +#define SUBWORD_BOOL_CAS(TYPE, WIDTH) \ + bool HIDDEN \ + __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ + TYPE newval) \ + { \ + TYPE actual_oldval \ + = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval); \ + return (oldval == actual_oldval); \ + } + +SUBWORD_BOOL_CAS (unsigned short, 2) +SUBWORD_BOOL_CAS (unsigned char, 1) + +int HIDDEN +__sync_lock_test_and_set_4 (int *ptr, int val) +{ + int failure, oldval; + + do { + oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST); + failure = __kernel_cmpxchg (oldval, val, ptr); + } while (failure != 0); + + return oldval; +} + +#define SUBWORD_TEST_AND_SET(TYPE, WIDTH) \ + TYPE HIDDEN \ + __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \ + { \ + int failure; \ + unsigned int oldval, newval, shift, mask; \ + int *wordptr = (int *) ((unsigned long) ptr & ~3); \ + \ + shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ + mask = MASK_##WIDTH << shift; \ + \ + do { \ + oldval = __atomic_load_n (wordptr, __ATOMIC_SEQ_CST); \ + newval = (oldval & ~mask) \ + | (((unsigned int) val << shift) & mask); \ + failure = __kernel_cmpxchg (oldval, newval, wordptr); \ + } while (failure != 0); \ + \ + return (oldval & mask) >> shift; \ + } + +SUBWORD_TEST_AND_SET (unsigned short, 2) +SUBWORD_TEST_AND_SET (unsigned char, 1) + +#define SYNC_LOCK_RELEASE(TYPE, WIDTH) \ + void HIDDEN \ + __sync_lock_release_##WIDTH (TYPE *ptr) \ + { \ + /* All writes before this point must be seen before we release \ + the lock itself. */ \ + __builtin_nds32_msync_all (); \ + *ptr = 0; \ + } + +SYNC_LOCK_RELEASE (int, 4) +SYNC_LOCK_RELEASE (short, 2) +SYNC_LOCK_RELEASE (char, 1) diff --git a/libgcc/config/nds32/linux-unwind.h b/libgcc/config/nds32/linux-unwind.h new file mode 100644 index 0000000..ddab425 --- /dev/null +++ b/libgcc/config/nds32/linux-unwind.h @@ -0,0 +1,156 @@ +/* DWARF2 EH unwinding support for NDS32 Linux signal frame. + Copyright (C) 2014-2015 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef inhibit_libc + +/* Do code reading to identify a signal frame, and set the frame + state data appropriately. See unwind-dw2.c for the structs. + The corresponding bits in the Linux kernel are in + arch/nds32/kernel/signal.c. */ + +#include +#include + +/* Exactly the same layout as the kernel structures, unique names. */ + +/* arch/nds32/kernel/signal.c */ +struct _sigframe { + struct ucontext uc; + unsigned long retcode; +}; + +struct _rt_sigframe { + siginfo_t info; + struct _sigframe sig; +}; +#define SIGRETURN 0xeb0e0a64 +#define RT_SIGRETURN 0x6b110064 + +#define MD_FALLBACK_FRAME_STATE_FOR nds32_fallback_frame_state + +/* This function is supposed to be invoked by uw_frame_state_for() + when there is no unwind data available. + + Generally, given the _Unwind_Context CONTEXT for a stack frame, + we need to look up its caller and decode information into FS. + However, if the exception handling happens within a signal handler, + the return address of signal handler is a special module, which + contains signal return syscall and has no FDE in the .eh_frame section. + We need to implement MD_FALLBACK_FRAME_STATE_FOR so that we can + unwind through signal frames. */ +static _Unwind_Reason_Code +nds32_fallback_frame_state (struct _Unwind_Context *context, + _Unwind_FrameState *fs) +{ + u_int32_t *pc = (u_int32_t *) context->ra; + struct sigcontext *sc_; + _Unwind_Ptr new_cfa; + +#ifdef __NDS32_EB__ +#error "Signal handler is not supported for force unwind." +#endif + + if ((_Unwind_Ptr) pc & 3) + return _URC_END_OF_STACK; + + /* Check if we are going through a signal handler. + See arch/nds32/kernel/signal.c implementation. + SWI_SYS_SIGRETURN -> (0xeb0e0a64) + SWI_SYS_RT_SIGRETURN -> (0x6b110064) + FIXME: Currently we only handle little endian (EL) case. */ + if (pc[0] == SIGRETURN) + { + /* Using '_sigfame' memory address to locate kernal's sigcontext. + The sigcontext structures in arch/nds32/include/asm/sigcontext.h. */ + struct _sigframe *rt_; + rt_ = context->cfa; + sc_ = &rt_->uc.uc_mcontext; + } + else if (pc[0] == RT_SIGRETURN) + { + /* Using '_sigfame' memory address to locate kernal's sigcontext. */ + struct _rt_sigframe *rt_; + rt_ = context->cfa; + sc_ = &rt_->sig.uc.uc_mcontext; + } + else + return _URC_END_OF_STACK; + + /* Update cfa from sigcontext. */ + new_cfa = (_Unwind_Ptr) sc_; + fs->regs.cfa_how = CFA_REG_OFFSET; + fs->regs.cfa_reg = STACK_POINTER_REGNUM; + fs->regs.cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa; + +#define NDS32_PUT_FS_REG(NUM, NAME) \ + (fs->regs.reg[NUM].how = REG_SAVED_OFFSET, \ + fs->regs.reg[NUM].loc.offset = (_Unwind_Ptr) &(sc_->NAME) - new_cfa) + + /* Restore all registers value. */ + NDS32_PUT_FS_REG (0, nds32_r0); + NDS32_PUT_FS_REG (1, nds32_r1); + NDS32_PUT_FS_REG (2, nds32_r2); + NDS32_PUT_FS_REG (3, nds32_r3); + NDS32_PUT_FS_REG (4, nds32_r4); + NDS32_PUT_FS_REG (5, nds32_r5); + NDS32_PUT_FS_REG (6, nds32_r6); + NDS32_PUT_FS_REG (7, nds32_r7); + NDS32_PUT_FS_REG (8, nds32_r8); + NDS32_PUT_FS_REG (9, nds32_r9); + NDS32_PUT_FS_REG (10, nds32_r10); + NDS32_PUT_FS_REG (11, nds32_r11); + NDS32_PUT_FS_REG (12, nds32_r12); + NDS32_PUT_FS_REG (13, nds32_r13); + NDS32_PUT_FS_REG (14, nds32_r14); + NDS32_PUT_FS_REG (15, nds32_r15); + NDS32_PUT_FS_REG (16, nds32_r16); + NDS32_PUT_FS_REG (17, nds32_r17); + NDS32_PUT_FS_REG (18, nds32_r18); + NDS32_PUT_FS_REG (19, nds32_r19); + NDS32_PUT_FS_REG (20, nds32_r20); + NDS32_PUT_FS_REG (21, nds32_r21); + NDS32_PUT_FS_REG (22, nds32_r22); + NDS32_PUT_FS_REG (23, nds32_r23); + NDS32_PUT_FS_REG (24, nds32_r24); + NDS32_PUT_FS_REG (25, nds32_r25); + + NDS32_PUT_FS_REG (28, nds32_fp); + NDS32_PUT_FS_REG (29, nds32_gp); + NDS32_PUT_FS_REG (30, nds32_lp); + NDS32_PUT_FS_REG (31, nds32_sp); + + /* Restore PC, point to trigger signal instruction. */ + NDS32_PUT_FS_REG (32, nds32_ipc); + +#undef NDS32_PUT_FS_REG + + /* The retaddr is PC, use PC to find FDE. */ + fs->retaddr_column = 32; + fs->signal_frame = 1; + + return _URC_NO_REASON; +} + +#endif diff --git a/libgcc/config/nds32/sfp-machine.h b/libgcc/config/nds32/sfp-machine.h index d822898..930a32e 100644 --- a/libgcc/config/nds32/sfp-machine.h +++ b/libgcc/config/nds32/sfp-machine.h @@ -76,6 +76,25 @@ typedef int __gcc_CMPtype __attribute__ ((mode (__libgcc_cmp_return__))); R##_c = FP_CLS_NAN; \ } while (0) +#ifdef NDS32_ABI_2FP_PLUS +#define FP_RND_NEAREST 0x0 +#define FP_RND_PINF 0x1 +#define FP_RND_MINF 0x2 +#define FP_RND_ZERO 0x3 +#define FP_RND_MASK 0x3 + +#define _FP_DECL_EX \ + unsigned long int _fcsr __attribute__ ((unused)) = FP_RND_NEAREST + +#define FP_INIT_ROUNDMODE \ + do { \ + _fcsr = __builtin_nds32_fmfcsr (); \ + } while (0) + +#define FP_ROUNDMODE (_fcsr & FP_RND_MASK) + +#endif + /* Not checked. */ #define _FP_TININESS_AFTER_ROUNDING 0 diff --git a/libgcc/config/nds32/t-nds32 b/libgcc/config/nds32/t-nds32 index 20c8a3f..4e58b1b 100644 --- a/libgcc/config/nds32/t-nds32 +++ b/libgcc/config/nds32/t-nds32 @@ -26,33 +26,22 @@ # Make sure the linker script include these two objects # for building .ctors/.dtors sections. -# Use -DCRT_BEGIN to create beginning parts of .init and .fini content -# Make sure you are building crtbegin1.o with -O0 optimization, -# otherwise the static function will be optimized out +# Use -DCRT_BEGIN to create beginning parts of .init and .fini content. crtbegin1.o: $(srcdir)/config/nds32/initfini.c $(GCC_PASSES) $(CONFIG_H) $(GCC_FOR_TARGET) $(INCLUDES) \ $(CFLAGS) \ -DCRT_BEGIN \ -finhibit-size-directive -fno-inline-functions \ - -O0 -c $(srcdir)/config/nds32/initfini.c -o crtbegin1.o + -fno-toplevel-reorder \ + -Os -c $(srcdir)/config/nds32/initfini.c -o crtbegin1.o -# Use -DCRT_END to create ending parts of .init and .fini content -# Make sure you are building crtend1.o with -O0 optimization, -# otherwise the static function will be optimized out +# Use -DCRT_END to create ending parts of .init and .fini content. crtend1.o: $(srcdir)/config/nds32/initfini.c $(GCC_PASSES) $(CONFIG_H) $(GCC_FOR_TARGET) $(INCLUDES) \ $(CFLAGS) \ -DCRT_END \ -finhibit-size-directive -fno-inline-functions \ - -O0 -c $(srcdir)/config/nds32/initfini.c -o crtend1.o - -# Use this rule if and only if your crt0.o does not come from library -# Also, be sure to add 'crtzero.o' in extra_parts in libgcc/config.host -# and change STARTFILE_SPEC in nds32.h -# -#crtzero.o: $(srcdir)/config/nds32/crtzero.S $(GCC_PASSES) $(CONFIG_H) -# $(GCC_FOR_TARGET) $(INCLUDES) \ -# -c $(srcdir)/config/nds32/crtzero.S -o crtzero.o - + -fno-toplevel-reorder \ + -Os -c $(srcdir)/config/nds32/initfini.c -o crtend1.o # ------------------------------------------------------------------------ diff --git a/libgcc/config/nds32/t-nds32-mculib b/libgcc/config/nds32/t-nds32-glibc similarity index 50% rename from libgcc/config/nds32/t-nds32-mculib rename to libgcc/config/nds32/t-nds32-glibc index b4f7b4c..385644b 100644 --- a/libgcc/config/nds32/t-nds32-mculib +++ b/libgcc/config/nds32/t-nds32-glibc @@ -1,4 +1,4 @@ -# Rules of mculib library makefile of Andes NDS32 cpu for GNU compiler +# Rules of glibc library makefile of Andes NDS32 cpu for GNU compiler # Copyright (C) 2012-2016 Free Software Foundation, Inc. # Contributed by Andes Technology Corporation. # @@ -19,59 +19,16 @@ # . # Compiler flags to use when compiling 'libgcc2.c' -HOST_LIBGCC2_CFLAGS = -Os +HOST_LIBGCC2_CFLAGS = -O2 -fPIC -fwrapv +LIB2ADD += $(srcdir)/config/nds32/linux-atomic.c - -LIB1ASMSRC = nds32/lib1asmsrc-mculib.S - -LIB1ASMFUNCS = \ - _addsub_sf \ - _sf_to_si \ - _divsi3 \ - _divdi3 \ - _modsi3 \ - _moddi3 \ - _mulsi3 \ - _udivsi3 \ - _udivdi3 \ - _udivmoddi4 \ - _umodsi3 \ - _umoddi3 \ - _muldi3 \ - _addsub_df \ - _mul_sf \ - _mul_df \ - _div_sf \ - _div_df \ - _negate_sf \ - _negate_df \ - _sf_to_df \ - _df_to_sf \ - _df_to_si \ - _fixsfdi \ - _fixdfdi \ - _fixunssfsi \ - _fixunsdfsi \ - _fixunssfdi \ - _fixunsdfdi \ - _si_to_sf \ - _si_to_df \ - _floatdisf \ - _floatdidf \ - _floatunsisf \ - _floatunsidf \ - _floatundisf \ - _floatundidf \ - _compare_sf \ - _compare_df \ - _unord_sf \ - _unord_df +#LIB1ASMSRC = nds32/lib1asmsrc-newlib.S +#LIB1ASMFUNCS = _divsi3 _modsi3 _udivsi3 _umodsi3 # List of functions not to build from libgcc2.c. -LIB2FUNCS_EXCLUDE = _clzsi2 _clzdi2 +#LIB2FUNCS_EXCLUDE = _clzsi2 # List of extra C and assembler files(*.S) to add to static libgcc2. -LIB2ADD_ST += $(srcdir)/config/nds32/lib2csrc-mculib/_clzsi2.c -LIB2ADD_ST += $(srcdir)/config/nds32/lib2csrc-mculib/_clzdi2.c +#LIB2ADD_ST += $(srcdir)/config/nds32/lib2csrc-newlib/_clzsi2.c # ------------------------------------------------------------------------ diff --git a/libgcc/config/nds32/t-nds32-isr b/libgcc/config/nds32/t-nds32-isr index 62b6867..6493838 100644 --- a/libgcc/config/nds32/t-nds32-isr +++ b/libgcc/config/nds32/t-nds32-isr @@ -23,11 +23,15 @@ # Makfile fragment rules for libnds32_isr.a to support ISR attribute extension ############################################################################### -# basic flags setting -ISR_CFLAGS = $(CFLAGS) -c - -# the object files we would like to create -LIBNDS32_ISR_16B_OBJS = \ +# Basic flags setting. +ifneq ($(filter -mext-dsp,$(CFLAGS)),) +ISR_CFLAGS = $(CFLAGS) -mno-force-no-ext-zol -mext-zol -c +else +ISR_CFLAGS = $(CFLAGS) -mno-force-no-ext-zol -c +endif + +# The object files we would like to create. +LIBNDS32_ISR_VEC_OBJS = \ vec_vid00.o vec_vid01.o vec_vid02.o vec_vid03.o \ vec_vid04.o vec_vid05.o vec_vid06.o vec_vid07.o \ vec_vid08.o vec_vid09.o vec_vid10.o vec_vid11.o \ @@ -46,40 +50,9 @@ LIBNDS32_ISR_16B_OBJS = \ vec_vid60.o vec_vid61.o vec_vid62.o vec_vid63.o \ vec_vid64.o vec_vid65.o vec_vid66.o vec_vid67.o \ vec_vid68.o vec_vid69.o vec_vid70.o vec_vid71.o \ - vec_vid72.o \ - excp_isr_ps_nn.o excp_isr_ps_ns.o excp_isr_ps_nr.o \ - excp_isr_sa_nn.o excp_isr_sa_ns.o excp_isr_sa_nr.o \ - intr_isr_ps_nn.o intr_isr_ps_ns.o intr_isr_ps_nr.o \ - intr_isr_sa_nn.o intr_isr_sa_ns.o intr_isr_sa_nr.o \ - reset.o - -LIBNDS32_ISR_4B_OBJS = \ - vec_vid00_4b.o vec_vid01_4b.o vec_vid02_4b.o vec_vid03_4b.o \ - vec_vid04_4b.o vec_vid05_4b.o vec_vid06_4b.o vec_vid07_4b.o \ - vec_vid08_4b.o vec_vid09_4b.o vec_vid10_4b.o vec_vid11_4b.o \ - vec_vid12_4b.o vec_vid13_4b.o vec_vid14_4b.o vec_vid15_4b.o \ - vec_vid16_4b.o vec_vid17_4b.o vec_vid18_4b.o vec_vid19_4b.o \ - vec_vid20_4b.o vec_vid21_4b.o vec_vid22_4b.o vec_vid23_4b.o \ - vec_vid24_4b.o vec_vid25_4b.o vec_vid26_4b.o vec_vid27_4b.o \ - vec_vid28_4b.o vec_vid29_4b.o vec_vid30_4b.o vec_vid31_4b.o \ - vec_vid32_4b.o vec_vid33_4b.o vec_vid34_4b.o vec_vid35_4b.o \ - vec_vid36_4b.o vec_vid37_4b.o vec_vid38_4b.o vec_vid39_4b.o \ - vec_vid40_4b.o vec_vid41_4b.o vec_vid42_4b.o vec_vid43_4b.o \ - vec_vid44_4b.o vec_vid45_4b.o vec_vid46_4b.o vec_vid47_4b.o \ - vec_vid48_4b.o vec_vid49_4b.o vec_vid50_4b.o vec_vid51_4b.o \ - vec_vid52_4b.o vec_vid53_4b.o vec_vid54_4b.o vec_vid55_4b.o \ - vec_vid56_4b.o vec_vid57_4b.o vec_vid58_4b.o vec_vid59_4b.o \ - vec_vid60_4b.o vec_vid61_4b.o vec_vid62_4b.o vec_vid63_4b.o \ - vec_vid64_4b.o vec_vid65_4b.o vec_vid66_4b.o vec_vid67_4b.o \ - vec_vid68_4b.o vec_vid69_4b.o vec_vid70_4b.o vec_vid71_4b.o \ - vec_vid72_4b.o \ - excp_isr_ps_nn_4b.o excp_isr_ps_ns_4b.o excp_isr_ps_nr_4b.o \ - excp_isr_sa_nn_4b.o excp_isr_sa_ns_4b.o excp_isr_sa_nr_4b.o \ - intr_isr_ps_nn_4b.o intr_isr_ps_ns_4b.o intr_isr_ps_nr_4b.o \ - intr_isr_sa_nn_4b.o intr_isr_sa_ns_4b.o intr_isr_sa_nr_4b.o \ - reset_4b.o + vec_vid72.o -LIBNDS32_ISR_COMMON_OBJS = \ +LIBNDS32_ISR_JMP_OBJS = \ jmptbl_vid00.o jmptbl_vid01.o jmptbl_vid02.o jmptbl_vid03.o \ jmptbl_vid04.o jmptbl_vid05.o jmptbl_vid06.o jmptbl_vid07.o \ jmptbl_vid08.o jmptbl_vid09.o jmptbl_vid10.o jmptbl_vid11.o \ @@ -98,29 +71,32 @@ LIBNDS32_ISR_COMMON_OBJS = \ jmptbl_vid60.o jmptbl_vid61.o jmptbl_vid62.o jmptbl_vid63.o \ jmptbl_vid64.o jmptbl_vid65.o jmptbl_vid66.o jmptbl_vid67.o \ jmptbl_vid68.o jmptbl_vid69.o jmptbl_vid70.o jmptbl_vid71.o \ - jmptbl_vid72.o \ + jmptbl_vid72.o + +LIBNDS32_ISR_COMMON_OBJS = \ + excp_isr_ps_nn.o excp_isr_ps_ns.o excp_isr_ps_nr.o \ + excp_isr_sa_nn.o excp_isr_sa_ns.o excp_isr_sa_nr.o \ + intr_isr_ps_nn.o intr_isr_ps_ns.o intr_isr_ps_nr.o \ + intr_isr_sa_nn.o intr_isr_sa_ns.o intr_isr_sa_nr.o \ + reset.o \ nmih.o \ wrh.o -LIBNDS32_ISR_COMPLETE_OBJS = $(LIBNDS32_ISR_16B_OBJS) $(LIBNDS32_ISR_4B_OBJS) $(LIBNDS32_ISR_COMMON_OBJS) - +LIBNDS32_ISR_COMPLETE_OBJS = $(LIBNDS32_ISR_VEC_OBJS) $(LIBNDS32_ISR_JMP_OBJS) $(LIBNDS32_ISR_COMMON_OBJS) -# Build common objects for ISR library -nmih.o: $(srcdir)/config/nds32/isr-library/nmih.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) $(srcdir)/config/nds32/isr-library/nmih.S -o nmih.o -wrh.o: $(srcdir)/config/nds32/isr-library/wrh.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) $(srcdir)/config/nds32/isr-library/wrh.S -o wrh.o -jmptbl_vid%.o: $(srcdir)/config/nds32/isr-library/jmptbl_vid%.S +# Build vector vid objects for ISR library. +vec_vid%.o: $(srcdir)/config/nds32/isr-library/vec_vid%.S $(GCC_FOR_TARGET) $(ISR_CFLAGS) $< -o $@ - -# Build 16b version objects for ISR library. (no "_4b" postfix string) -vec_vid%.o: $(srcdir)/config/nds32/isr-library/vec_vid%.S +# Build jump table objects for ISR library. +jmptbl_vid%.o: $(srcdir)/config/nds32/isr-library/jmptbl_vid%.S $(GCC_FOR_TARGET) $(ISR_CFLAGS) $< -o $@ + +# Build commen objects for ISR library. excp_isr_ps_nn.o: $(srcdir)/config/nds32/isr-library/excp_isr.S $(GCC_FOR_TARGET) $(ISR_CFLAGS) $(srcdir)/config/nds32/isr-library/excp_isr.S -o excp_isr_ps_nn.o @@ -160,48 +136,12 @@ intr_isr_sa_nr.o: $(srcdir)/config/nds32/isr-library/intr_isr.S reset.o: $(srcdir)/config/nds32/isr-library/reset.S $(GCC_FOR_TARGET) $(ISR_CFLAGS) $(srcdir)/config/nds32/isr-library/reset.S -o reset.o -# Build 4b version objects for ISR library. -vec_vid%_4b.o: $(srcdir)/config/nds32/isr-library/vec_vid%_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) $< -o $@ - -excp_isr_ps_nn_4b.o: $(srcdir)/config/nds32/isr-library/excp_isr_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) $(srcdir)/config/nds32/isr-library/excp_isr_4b.S -o excp_isr_ps_nn_4b.o - -excp_isr_ps_ns_4b.o: $(srcdir)/config/nds32/isr-library/excp_isr_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) -DNDS32_NESTED $(srcdir)/config/nds32/isr-library/excp_isr_4b.S -o excp_isr_ps_ns_4b.o - -excp_isr_ps_nr_4b.o: $(srcdir)/config/nds32/isr-library/excp_isr_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) -DNDS32_NESTED_READY $(srcdir)/config/nds32/isr-library/excp_isr_4b.S -o excp_isr_ps_nr_4b.o - -excp_isr_sa_nn_4b.o: $(srcdir)/config/nds32/isr-library/excp_isr_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) -DNDS32_SAVE_ALL_REGS $(srcdir)/config/nds32/isr-library/excp_isr_4b.S -o excp_isr_sa_nn_4b.o - -excp_isr_sa_ns_4b.o: $(srcdir)/config/nds32/isr-library/excp_isr_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) -DNDS32_SAVE_ALL_REGS -DNDS32_NESTED $(srcdir)/config/nds32/isr-library/excp_isr_4b.S -o excp_isr_sa_ns_4b.o - -excp_isr_sa_nr_4b.o: $(srcdir)/config/nds32/isr-library/excp_isr_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) -DNDS32_SAVE_ALL_REGS -DNDS32_NESTED_READY $(srcdir)/config/nds32/isr-library/excp_isr_4b.S -o excp_isr_sa_nr_4b.o - -intr_isr_ps_nn_4b.o: $(srcdir)/config/nds32/isr-library/intr_isr_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) $(srcdir)/config/nds32/isr-library/intr_isr_4b.S -o intr_isr_ps_nn_4b.o - -intr_isr_ps_ns_4b.o: $(srcdir)/config/nds32/isr-library/intr_isr_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) -DNDS32_NESTED $(srcdir)/config/nds32/isr-library/intr_isr_4b.S -o intr_isr_ps_ns_4b.o - -intr_isr_ps_nr_4b.o: $(srcdir)/config/nds32/isr-library/intr_isr_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) -DNDS32_NESTED_READY $(srcdir)/config/nds32/isr-library/intr_isr_4b.S -o intr_isr_ps_nr_4b.o - -intr_isr_sa_nn_4b.o: $(srcdir)/config/nds32/isr-library/intr_isr_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) -DNDS32_SAVE_ALL_REGS $(srcdir)/config/nds32/isr-library/intr_isr_4b.S -o intr_isr_sa_nn_4b.o - -intr_isr_sa_ns_4b.o: $(srcdir)/config/nds32/isr-library/intr_isr_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) -DNDS32_SAVE_ALL_REGS -DNDS32_NESTED $(srcdir)/config/nds32/isr-library/intr_isr_4b.S -o intr_isr_sa_ns_4b.o +nmih.o: $(srcdir)/config/nds32/isr-library/nmih.S + $(GCC_FOR_TARGET) $(ISR_CFLAGS) $(srcdir)/config/nds32/isr-library/nmih.S -o nmih.o -intr_isr_sa_nr_4b.o: $(srcdir)/config/nds32/isr-library/intr_isr_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) -DNDS32_SAVE_ALL_REGS -DNDS32_NESTED_READY $(srcdir)/config/nds32/isr-library/intr_isr_4b.S -o intr_isr_sa_nr_4b.o +wrh.o: $(srcdir)/config/nds32/isr-library/wrh.S + $(GCC_FOR_TARGET) $(ISR_CFLAGS) $(srcdir)/config/nds32/isr-library/wrh.S -o wrh.o -reset_4b.o: $(srcdir)/config/nds32/isr-library/reset_4b.S - $(GCC_FOR_TARGET) $(ISR_CFLAGS) $(srcdir)/config/nds32/isr-library/reset_4b.S -o reset_4b.o # The rule to create libnds32_isr.a file diff --git a/libgcc/config/nds32/t-nds32-newlib b/libgcc/config/nds32/t-nds32-newlib index e4af03e..c356b60 100644 --- a/libgcc/config/nds32/t-nds32-newlib +++ b/libgcc/config/nds32/t-nds32-newlib @@ -19,7 +19,7 @@ # . # Compiler flags to use when compiling 'libgcc2.c' -HOST_LIBGCC2_CFLAGS = -O2 +HOST_LIBGCC2_CFLAGS = -O2 -fwrapv #LIB1ASMSRC = nds32/lib1asmsrc-newlib.S