diff options
-rw-r--r-- | gcc/ChangeLog | 26 | ||||
-rw-r--r-- | gcc/config/xtensa/lib1funcs.asm | 224 | ||||
-rw-r--r-- | gcc/config/xtensa/t-xtensa | 3 | ||||
-rw-r--r-- | gcc/config/xtensa/xtensa.c | 87 | ||||
-rw-r--r-- | gcc/config/xtensa/xtensa.h | 4 | ||||
-rw-r--r-- | gcc/config/xtensa/xtensa.md | 78 | ||||
-rw-r--r-- | gcc/longlong.h | 17 |
7 files changed, 418 insertions, 21 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4565b206b07..967d3c2db8e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2006-11-06 Bob Wilson <bob.wilson@acm.org> + + * longlong.h (__xtensa__): Add definitions for umul_ppmm, __umulsidi3, + count_leading_zeros, and count_trailing_zeros. + * config/xtensa/xtensa.c (TARGET_INIT_BUILTINS): Define. + (TARGET_FOLD_BUILTIN): Define. + (TARGET_EXPAND_BUILTIN): Define. + (xtensa_init_builtins): New. + (xtensa_fold_builtin): New. + (xtensa_expand_builtin): New. + (xtensa_rtx_costs): Add CTZ and CLZ. Adjust costs for MULT. + * config/xtensa/xtensa.h (TARGET_MUL32_HIGH): Define. + (CLZ_DEFINED_VALUE_AT_ZERO): Define. + (CTZ_DEFINED_VALUE_AT_ZERO): Define. + * config/xtensa/xtensa.md (UNSPEC_NSAU): Remove. + (any_extend): New code macro. + (u, su): New code attributes. + (<u>mulsidi3, <u>mulsi3_highpart, clzsi2, ctzsi2): New. + (nsau): Remove; replaced by clzsi2. + (ffssi2): Use clzsi2. + * config/xtensa/t-xtensa (LIB1ASMFUNCS): Add _umulsidi3, + _clzsi2, _ctzsi2, and _ffssi2. Rename _nsau to _clz. + * config/xtensa/lib1funcs.asm (__mulsi3): Support Mul32 option. + (__umulsidi3, __clzsi2, __ctzsi2, __ffssi2): New. + (__nsau_data): Guard with ifdef L_clz instead of L_nsau. + 2006-11-06 Vladimir Prus <vladimir@codesourcery.com> * config/arm/t-strongarm-pe: (TARGET_LIBGCC2_CFLAGS): Do no diff --git a/gcc/config/xtensa/lib1funcs.asm b/gcc/config/xtensa/lib1funcs.asm index 6392fa2a87f..69d51a7551c 100644 --- a/gcc/config/xtensa/lib1funcs.asm +++ b/gcc/config/xtensa/lib1funcs.asm @@ -99,7 +99,10 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA __mulsi3: leaf_entry sp, 16 -#if XCHAL_HAVE_MUL16 +#if XCHAL_HAVE_MUL32 + mull a2, a2, a3 + +#elif XCHAL_HAVE_MUL16 or a4, a2, a3 srai a4, a4, 16 bnez a4, .LMUL16 @@ -124,7 +127,7 @@ __mulsi3: slli a5, a5, 16 add a2, a4, a5 -#else /* !XCHAL_HAVE_MUL16 && !XCHAL_HAVE_MAC16 */ +#else /* !MUL32 && !MUL16 && !MAC16 */ /* Multiply one bit at a time, but unroll the loop 4x to better exploit the addx instructions and avoid overhead. @@ -188,7 +191,7 @@ __mulsi3: neg a3, a2 movltz a2, a3, a5 -#endif /* !XCHAL_HAVE_MUL16 && !XCHAL_HAVE_MAC16 */ +#endif /* !MUL32 && !MUL16 && !MAC16 */ leaf_return .size __mulsi3,.-__mulsi3 @@ -196,6 +199,170 @@ __mulsi3: #endif /* L_mulsi3 */ +#ifdef L_umulsidi3 + .align 4 + .global __umulsidi3 + .type __umulsidi3,@function +__umulsidi3: + leaf_entry sp, 32 +#if __XTENSA_CALL0_ABI__ + addi sp, sp, -32 + s32i a12, sp, 16 + s32i a13, sp, 20 + s32i a14, sp, 24 + s32i a15, sp, 28 +#endif + +#ifdef __XTENSA_EB__ +#define wh a2 +#define wl a3 +#else +#define wh a3 +#define wl a2 +#endif /* __XTENSA_EB__ */ + + /* This code is taken from the mulsf3 routine in ieee754-sf.S. + See more comments there. */ + +#if XCHAL_HAVE_MUL32_HIGH + mull a6, a2, a3 + muluh wh, a2, a3 + mov wl, a6 + +#else /* ! MUL32_HIGH */ + +#if !XCHAL_HAVE_MUL16 && !XCHAL_HAVE_MUL32 && !XCHAL_HAVE_MAC16 + /* a0 and a8 will be clobbered by calling the multiply function + but a8 is not used here and need not be saved. */ + s32i a0, sp, 0 +#endif + +#if XCHAL_HAVE_MUL16 || XCHAL_HAVE_MUL32 + +#define a2h a4 +#define a3h a5 + + /* Get the high halves of the inputs into registers. */ + srli a2h, a2, 16 + srli a3h, a3, 16 + +#define a2l a2 +#define a3l a3 + +#if XCHAL_HAVE_MUL32 && !XCHAL_HAVE_MUL16 + /* Clear the high halves of the inputs. This does not matter + for MUL16 because the high bits are ignored. */ + extui a2, a2, 0, 16 + extui a3, a3, 0, 16 +#endif +#endif /* MUL16 || MUL32 */ + + +#if XCHAL_HAVE_MUL16 + +#define do_mul(dst, xreg, xhalf, yreg, yhalf) \ + mul16u dst, xreg ## xhalf, yreg ## yhalf + +#elif XCHAL_HAVE_MUL32 + +#define do_mul(dst, xreg, xhalf, yreg, yhalf) \ + mull dst, xreg ## xhalf, yreg ## yhalf + +#elif XCHAL_HAVE_MAC16 + +/* The preprocessor insists on inserting a space when concatenating after + a period in the definition of do_mul below. These macros are a workaround + using underscores instead of periods when doing the concatenation. */ +#define umul_aa_ll umul.aa.ll +#define umul_aa_lh umul.aa.lh +#define umul_aa_hl umul.aa.hl +#define umul_aa_hh umul.aa.hh + +#define do_mul(dst, xreg, xhalf, yreg, yhalf) \ + umul_aa_ ## xhalf ## yhalf xreg, yreg; \ + rsr dst, ACCLO + +#else /* no multiply hardware */ + +#define set_arg_l(dst, src) \ + extui dst, src, 0, 16 +#define set_arg_h(dst, src) \ + srli dst, src, 16 + +#define do_mul(dst, xreg, xhalf, yreg, yhalf) \ + set_arg_ ## xhalf (a13, xreg); \ + set_arg_ ## yhalf (a14, yreg); \ + call0 .Lmul_mulsi3; \ + mov dst, a12 +#endif + + /* Add pp1 and pp2 into a6 with carry-out in a9. */ + do_mul(a6, a2, l, a3, h) /* pp 1 */ + do_mul(a11, a2, h, a3, l) /* pp 2 */ + movi a9, 0 + add a6, a6, a11 + bgeu a6, a11, 1f + addi a9, a9, 1 +1: + /* Shift the high half of a9/a6 into position in a9. Note that + this value can be safely incremented without any carry-outs. */ + ssai 16 + src a9, a9, a6 + + /* Compute the low word into a6. */ + do_mul(a11, a2, l, a3, l) /* pp 0 */ + sll a6, a6 + add a6, a6, a11 + bgeu a6, a11, 1f + addi a9, a9, 1 +1: + /* Compute the high word into wh. */ + do_mul(wh, a2, h, a3, h) /* pp 3 */ + add wh, wh, a9 + mov wl, a6 + +#endif /* !MUL32_HIGH */ + + leaf_return + +#if !XCHAL_HAVE_MUL16 && !XCHAL_HAVE_MUL32 && !XCHAL_HAVE_MAC16 + + /* For Xtensa processors with no multiply hardware, this simplified + version of _mulsi3 is used for multiplying 16-bit chunks of + the floating-point mantissas. It uses a custom ABI: the inputs + are passed in a13 and a14, the result is returned in a12, and + a8 and a15 are clobbered. */ + .align 4 +.Lmul_mulsi3: + movi a12, 0 +.Lmul_mult_loop: + add a15, a14, a12 + extui a8, a13, 0, 1 + movnez a12, a15, a8 + + do_addx2 a15, a14, a12, a15 + extui a8, a13, 1, 1 + movnez a12, a15, a8 + + do_addx4 a15, a14, a12, a15 + extui a8, a13, 2, 1 + movnez a12, a15, a8 + + do_addx8 a15, a14, a12, a15 + extui a8, a13, 3, 1 + movnez a12, a15, a8 + + srli a13, a13, 4 + slli a14, a14, 4 + bnez a13, .Lmul_mult_loop + ret +#endif /* !MUL16 && !MUL32 && !MAC16 */ + + .size __umulsidi3,.-__umulsidi3 + +#endif /* L_umulsidi3 */ + + /* Define a macro for the NSAU (unsigned normalize shift amount) instruction, which computes the number of leading zero bits, to handle cases where it is not included in the Xtensa processor @@ -225,7 +392,7 @@ __mulsi3: #endif /* !XCHAL_HAVE_NSA */ .endm -#ifdef L_nsau +#ifdef L_clz .section .rodata .align 4 .global __nsau_data @@ -251,7 +418,54 @@ __nsau_data: #endif /* !XCHAL_HAVE_NSA */ .size __nsau_data,.-__nsau_data .hidden __nsau_data -#endif /* L_nsau */ +#endif /* L_clz */ + + +#ifdef L_clzsi2 + .align 4 + .global __clzsi2 + .type __clzsi2,@function +__clzsi2: + leaf_entry sp, 16 + do_nsau a2, a2, a3, a4 + leaf_return + .size __clzsi2,.-__clzsi2 + +#endif /* L_clzsi2 */ + + +#ifdef L_ctzsi2 + .align 4 + .global __ctzsi2 + .type __ctzsi2,@function +__ctzsi2: + leaf_entry sp, 16 + neg a3, a2 + and a3, a3, a2 + do_nsau a2, a3, a4, a5 + neg a2, a2 + addi a2, a2, 31 + leaf_return + .size __ctzsi2,.-__ctzsi2 + +#endif /* L_ctzsi2 */ + + +#ifdef L_ffssi2 + .align 4 + .global __ffssi2 + .type __ffssi2,@function +__ffssi2: + leaf_entry sp, 16 + neg a3, a2 + and a3, a3, a2 + do_nsau a2, a3, a4, a5 + neg a2, a2 + addi a2, a2, 32 + leaf_return + .size __ffssi2,.-__ffssi2 + +#endif /* L_ffssi2 */ #ifdef L_udivsi3 diff --git a/gcc/config/xtensa/t-xtensa b/gcc/config/xtensa/t-xtensa index 6bcaa616c5e..efcfe255f3b 100644 --- a/gcc/config/xtensa/t-xtensa +++ b/gcc/config/xtensa/t-xtensa @@ -1,5 +1,6 @@ LIB1ASMSRC = xtensa/lib1funcs.asm -LIB1ASMFUNCS = _mulsi3 _nsau _divsi3 _modsi3 _udivsi3 _umodsi3 \ +LIB1ASMFUNCS = _mulsi3 _divsi3 _modsi3 _udivsi3 _umodsi3 \ + _umulsidi3 _clz _clzsi2 _ctzsi2 _ffssi2 \ _negsf2 _addsubsf3 _mulsf3 _divsf3 _cmpsf2 _fixsfsi _fixsfdi \ _fixunssfsi _fixunssfdi _floatsisf _floatunsisf \ _floatdisf _floatundisf \ diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c index 836ae2e1687..32c3ff2edbf 100644 --- a/gcc/config/xtensa/xtensa.c +++ b/gcc/config/xtensa/xtensa.c @@ -210,6 +210,9 @@ static bool xtensa_rtx_costs (rtx, int, int, int *); static tree xtensa_build_builtin_va_list (void); static bool xtensa_return_in_memory (tree, tree); static tree xtensa_gimplify_va_arg_expr (tree, tree, tree *, tree *); +static void xtensa_init_builtins (void); +static tree xtensa_fold_builtin (tree, tree, bool); +static rtx xtensa_expand_builtin (tree, rtx, rtx, enum machine_mode, int); static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] = REG_ALLOC_ORDER; @@ -265,6 +268,13 @@ static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] = #undef TARGET_RETURN_IN_MSB #define TARGET_RETURN_IN_MSB xtensa_return_in_msb +#undef TARGET_INIT_BUILTINS +#define TARGET_INIT_BUILTINS xtensa_init_builtins +#undef TARGET_FOLD_BUILTIN +#define TARGET_FOLD_BUILTIN xtensa_fold_builtin +#undef TARGET_EXPAND_BUILTIN +#define TARGET_EXPAND_BUILTIN xtensa_expand_builtin + struct gcc_target targetm = TARGET_INITIALIZER; @@ -2322,6 +2332,74 @@ xtensa_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, } +/* Builtins. */ + +enum xtensa_builtin +{ + XTENSA_BUILTIN_UMULSIDI3, + XTENSA_BUILTIN_max +}; + + +static void +xtensa_init_builtins (void) +{ + tree ftype; + + ftype = build_function_type_list (unsigned_intDI_type_node, + unsigned_intSI_type_node, + unsigned_intSI_type_node, NULL_TREE); + + add_builtin_function ("__builtin_umulsidi3", ftype, + XTENSA_BUILTIN_UMULSIDI3, BUILT_IN_MD, + "__umulsidi3", NULL_TREE); +} + + +static tree +xtensa_fold_builtin (tree fndecl, tree arglist, bool ignore ATTRIBUTE_UNUSED) +{ + unsigned int fcode = DECL_FUNCTION_CODE (fndecl); + tree arg0, arg1; + + if (fcode == XTENSA_BUILTIN_UMULSIDI3) + { + arg0 = TREE_VALUE (arglist); + arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + if ((TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) + || TARGET_MUL32_HIGH) + return fold_build2 (MULT_EXPR, unsigned_intDI_type_node, + fold_convert (unsigned_intDI_type_node, arg0), + fold_convert (unsigned_intDI_type_node, arg1)); + else + return NULL; + } + + internal_error ("bad builtin code"); + return NULL; +} + + +static rtx +xtensa_expand_builtin (tree exp, rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore) +{ + tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + unsigned int fcode = DECL_FUNCTION_CODE (fndecl); + + /* The umulsidi3 builtin is just a mechanism to avoid calling the real + __umulsidi3 function when the Xtensa configuration can directly + implement it. If not, just call the function. */ + if (fcode == XTENSA_BUILTIN_UMULSIDI3) + return expand_call (exp, target, ignore); + + internal_error ("bad builtin code"); + return NULL_RTX; +} + + enum reg_class xtensa_preferred_reload_class (rtx x, enum reg_class class, int isoutput) { @@ -2530,9 +2608,14 @@ xtensa_rtx_costs (rtx x, int code, int outer_code, int *total) } case FFS: + case CTZ: *total = COSTS_N_INSNS (TARGET_NSA ? 5 : 50); return true; + case CLZ: + *total = COSTS_N_INSNS (TARGET_NSA ? 1 : 50); + return true; + case NOT: *total = COSTS_N_INSNS ((GET_MODE (x) == DImode) ? 3 : 2); return true; @@ -2589,8 +2672,10 @@ xtensa_rtx_costs (rtx x, int code, int outer_code, int *total) enum machine_mode xmode = GET_MODE (x); if (xmode == SFmode) *total = COSTS_N_INSNS (TARGET_HARD_FLOAT ? 4 : 50); - else if (xmode == DFmode || xmode == DImode) + else if (xmode == DFmode) *total = COSTS_N_INSNS (50); + else if (xmode == DImode) + *total = COSTS_N_INSNS (TARGET_MUL32_HIGH ? 10 : 50); else if (TARGET_MUL32) *total = COSTS_N_INSNS (4); else if (TARGET_MAC16) diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h index d7f70102611..0f35da52cdb 100644 --- a/gcc/config/xtensa/xtensa.h +++ b/gcc/config/xtensa/xtensa.h @@ -48,6 +48,7 @@ extern unsigned xtensa_current_frame_size; #define TARGET_MAC16 XCHAL_HAVE_MAC16 #define TARGET_MUL16 XCHAL_HAVE_MUL16 #define TARGET_MUL32 XCHAL_HAVE_MUL32 +#define TARGET_MUL32_HIGH XCHAL_HAVE_MUL32_HIGH #define TARGET_DIV32 XCHAL_HAVE_DIV32 #define TARGET_NSA XCHAL_HAVE_NSA #define TARGET_MINMAX XCHAL_HAVE_MINMAX @@ -1069,6 +1070,9 @@ typedef struct xtensa_args is done just by pretending it is already truncated. */ #define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 +#define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = 32, 1) +#define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = -1, 1) + /* Specify the machine mode that pointers have. After generation of rtl, the compiler makes no further distinction between pointers and any other objects of this machine mode. */ diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index 0b2c146b4be..b08f6cbcf1c 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -1,5 +1,6 @@ ;; GCC machine description for Tensilica's Xtensa architecture. -;; Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. +;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 +;; Free Software Foundation, Inc. ;; Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica. ;; This file is part of GCC. @@ -26,7 +27,6 @@ (A7_REG 7) (A8_REG 8) - (UNSPEC_NSAU 1) (UNSPEC_NOP 2) (UNSPEC_PLT 3) (UNSPEC_RET_ADDR 4) @@ -34,6 +34,17 @@ (UNSPECV_ENTRY 2) ]) +;; This code macro allows signed and unsigned widening multiplications +;; to use the same template. +(define_code_macro any_extend [sign_extend zero_extend]) + +;; <u> expands to an empty string when doing a signed operation and +;; "u" when doing an unsigned operation. +(define_code_attr u [(sign_extend "") (zero_extend "u")]) + +;; <su> is like <u>, but the signed form expands to "s" rather than "". +(define_code_attr su [(sign_extend "s") (zero_extend "u")]) + ;; Attributes. @@ -292,6 +303,32 @@ ;; Multiplication. +(define_expand "<u>mulsidi3" + [(set (match_operand:DI 0 "register_operand") + (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand")) + (any_extend:DI (match_operand:SI 2 "register_operand"))))] + "TARGET_MUL32_HIGH" +{ + emit_insn (gen_mulsi3 (gen_lowpart (SImode, operands[0]), + operands[1], operands[2])); + emit_insn (gen_<u>mulsi3_highpart (gen_highpart (SImode, operands[0]), + operands[1], operands[2])); + DONE; +}) + +(define_insn "<u>mulsi3_highpart" + [(set (match_operand:SI 0 "register_operand" "=a") + (truncate:SI + (lshiftrt:DI + (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "%r")) + (any_extend:DI (match_operand:SI 2 "register_operand" "r"))) + (const_int 32))))] + "TARGET_MUL32_HIGH" + "mul<su>h\t%0, %1, %2" + [(set_attr "type" "mul32") + (set_attr "mode" "SI") + (set_attr "length" "3")]) + (define_insn "mulsi3" [(set (match_operand:SI 0 "register_operand" "=a") (mult:SI (match_operand:SI 1 "register_operand" "%r") @@ -541,7 +578,30 @@ (set_attr "length" "3")]) -;; Find first bit. +;; Count leading/trailing zeros and find first bit. + +(define_insn "clzsi2" + [(set (match_operand:SI 0 "register_operand" "=a") + (clz:SI (match_operand:SI 1 "register_operand" "r")))] + "TARGET_NSA" + "nsau\t%0, %1" + [(set_attr "type" "arith") + (set_attr "mode" "SI") + (set_attr "length" "3")]) + +(define_expand "ctzsi2" + [(set (match_operand:SI 0 "register_operand" "") + (ctz:SI (match_operand:SI 1 "register_operand" "")))] + "TARGET_NSA" +{ + rtx temp = gen_reg_rtx (SImode); + emit_insn (gen_negsi2 (temp, operands[1])); + emit_insn (gen_andsi3 (temp, temp, operands[1])); + emit_insn (gen_clzsi2 (temp, temp)); + emit_insn (gen_negsi2 (temp, temp)); + emit_insn (gen_addsi3 (operands[0], temp, GEN_INT (31))); + DONE; +}) (define_expand "ffssi2" [(set (match_operand:SI 0 "register_operand" "") @@ -551,22 +611,12 @@ rtx temp = gen_reg_rtx (SImode); emit_insn (gen_negsi2 (temp, operands[1])); emit_insn (gen_andsi3 (temp, temp, operands[1])); - emit_insn (gen_nsau (temp, temp)); + emit_insn (gen_clzsi2 (temp, temp)); emit_insn (gen_negsi2 (temp, temp)); emit_insn (gen_addsi3 (operands[0], temp, GEN_INT (32))); DONE; }) -;; There is no RTL operator corresponding to NSAU. -(define_insn "nsau" - [(set (match_operand:SI 0 "register_operand" "=a") - (unspec:SI [(match_operand:SI 1 "register_operand" "r")] UNSPEC_NSAU))] - "TARGET_NSA" - "nsau\t%0, %1" - [(set_attr "type" "arith") - (set_attr "mode" "SI") - (set_attr "length" "3")]) - ;; Negation and one's complement. diff --git a/gcc/longlong.h b/gcc/longlong.h index c4131c67b21..1325b31f0c9 100644 --- a/gcc/longlong.h +++ b/gcc/longlong.h @@ -1189,6 +1189,23 @@ UDItype __umulsidi3 (USItype, USItype); } while (0) #endif /* __vax__ */ +#if defined (__xtensa__) && W_TYPE_SIZE == 32 +/* This code is not Xtensa-configuration-specific, so rely on the compiler + to expand builtin functions depending on what configuration features + are available. This avoids library calls when the operation can be + performed in-line. */ +#define umul_ppmm(w1, w0, u, v) \ + do { \ + DWunion __w; \ + __w.ll = __builtin_umulsidi3 (u, v); \ + w1 = __w.s.high; \ + w0 = __w.s.low; \ + } while (0) +#define __umulsidi3(u, v) __builtin_umulsidi3 (u, v) +#define count_leading_zeros(COUNT, X) ((COUNT) = __builtin_clz (X)) +#define count_trailing_zeros(COUNT, X) ((COUNT) = __builtin_ctz (X)) +#endif /* __xtensa__ */ + #if defined (__z8000__) && W_TYPE_SIZE == 16 #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ __asm__ ("add %H1,%H5\n\tadc %H0,%H3" \ |