From: Julian Brown Date: Mon, 1 Aug 2011 12:41:30 +0000 (+0000) Subject: configure.ac (fixed-point): Add ARM support. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=655b30bfde9172bd40189a787b85b16e461ef1ef;p=gcc.git configure.ac (fixed-point): Add ARM support. gcc/ * configure.ac (fixed-point): Add ARM support. * configure: Regenerate. * config/arm/arm.c (arm_fixed_mode_set): New struct. (arm_set_fixed_optab_libfunc): New. (arm_set_fixed_conv_libfunc): New. (arm_init_libfuncs): Initialise fixed-point helper libfuncs with ARM-specific names. (aapcs_libcall_value): Return sub-word-size fixed-point libcall return values in SImode. (arm_return_in_msb): Return fixed-point types in the msb. (arm_pad_reg_upwards, arm_pad_arg_upwards): Pad fixed-point types upwards. (arm_scalar_mode_supported_p): Support fixed-point modes. (arm_vector_mode_supported_p): Support vector fixed-point modes. * config/arm/arm.h (SHORT_FRACT_TYPE_SIZE, FRACT_TYPE_SIZE) (LONG_FRACT_TYPE_SIZE, LONG_LONG_FRACT_TYPE_SIZE) (SHORT_ACCUM_TYPE_SIZE, ACCUM_TYPE_SIZE, LONG_ACCUM_TYPE_SIZE) (LONG_LONG_ACCUM_TYPE_SIZE, MAX_FIXED_MODE_SIZE): Define. * config/arm/iterators.md (FIXED, ADDSUB, UQADDSUB, QADDSUB, QMUL): New mode iterators. (qaddsub_suf): New mode attribute. * config/arm/arm-modes.def (FRACT, UFRACT, ACCUM, UACCUM): Declare vector modes. * config/arm/predicates.md (sat_shift_operator): New predicate. * config/arm/arm-fixed.md: New. * config/arm/arm.md: Include arm-fixed.md. * config/arm/t-arm (MD_INCLUDES): Add arm-fixed.md. libgcc/ * config.host (arm*-*-linux*, arm*-*-uclinux*, arm*-*-eabi*) (arm*-*-symbianelf*): Add t-fixedpoint-gnu-prefix makefile fragment. * config/arm/bpabi-lib.h (LIBGCC2_FIXEDBIT_GNU_PREFIX): Define. gcc/testsuite/ * gcc.target/arm/fixed-point-exec.c: New test. From-SVN: r177025 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 417807a970b..3880f963224 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,33 @@ +2011-08-01 Julian Brown + + * configure.ac (fixed-point): Add ARM support. + * configure: Regenerate. + * config/arm/arm.c (arm_fixed_mode_set): New struct. + (arm_set_fixed_optab_libfunc): New. + (arm_set_fixed_conv_libfunc): New. + (arm_init_libfuncs): Initialise fixed-point helper libfuncs with + ARM-specific names. + (aapcs_libcall_value): Return sub-word-size fixed-point libcall + return values in SImode. + (arm_return_in_msb): Return fixed-point types in the msb. + (arm_pad_reg_upwards, arm_pad_arg_upwards): Pad fixed-point types + upwards. + (arm_scalar_mode_supported_p): Support fixed-point modes. + (arm_vector_mode_supported_p): Support vector fixed-point modes. + * config/arm/arm.h (SHORT_FRACT_TYPE_SIZE, FRACT_TYPE_SIZE) + (LONG_FRACT_TYPE_SIZE, LONG_LONG_FRACT_TYPE_SIZE) + (SHORT_ACCUM_TYPE_SIZE, ACCUM_TYPE_SIZE, LONG_ACCUM_TYPE_SIZE) + (LONG_LONG_ACCUM_TYPE_SIZE, MAX_FIXED_MODE_SIZE): Define. + * config/arm/iterators.md (FIXED, ADDSUB, UQADDSUB, QADDSUB, QMUL): + New mode iterators. + (qaddsub_suf): New mode attribute. + * config/arm/arm-modes.def (FRACT, UFRACT, ACCUM, UACCUM): Declare + vector modes. + * config/arm/predicates.md (sat_shift_operator): New predicate. + * config/arm/arm-fixed.md: New. + * config/arm/arm.md: Include arm-fixed.md. + * config/arm/t-arm (MD_INCLUDES): Add arm-fixed.md. + 2011-08-01 Julian Brown * calls.c (emit_library_call_value_1): Support padding for libcall diff --git a/gcc/config/arm/arm-fixed.md b/gcc/config/arm/arm-fixed.md new file mode 100644 index 00000000000..bd33ce28b38 --- /dev/null +++ b/gcc/config/arm/arm-fixed.md @@ -0,0 +1,384 @@ +;; Copyright 2011 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 +;; . +;; +;; This file contains ARM instructions that support fixed-point operations. + +(define_insn "add3" + [(set (match_operand:FIXED 0 "s_register_operand" "=r") + (plus:FIXED (match_operand:FIXED 1 "s_register_operand" "r") + (match_operand:FIXED 2 "s_register_operand" "r")))] + "TARGET_32BIT" + "add%?\\t%0, %1, %2" + [(set_attr "predicable" "yes")]) + +(define_insn "add3" + [(set (match_operand:ADDSUB 0 "s_register_operand" "=r") + (plus:ADDSUB (match_operand:ADDSUB 1 "s_register_operand" "r") + (match_operand:ADDSUB 2 "s_register_operand" "r")))] + "TARGET_INT_SIMD" + "sadd%?\\t%0, %1, %2" + [(set_attr "predicable" "yes")]) + +(define_insn "usadd3" + [(set (match_operand:UQADDSUB 0 "s_register_operand" "=r") + (us_plus:UQADDSUB (match_operand:UQADDSUB 1 "s_register_operand" "r") + (match_operand:UQADDSUB 2 "s_register_operand" "r")))] + "TARGET_INT_SIMD" + "uqadd%?\\t%0, %1, %2" + [(set_attr "predicable" "yes")]) + +(define_insn "ssadd3" + [(set (match_operand:QADDSUB 0 "s_register_operand" "=r") + (ss_plus:QADDSUB (match_operand:QADDSUB 1 "s_register_operand" "r") + (match_operand:QADDSUB 2 "s_register_operand" "r")))] + "TARGET_INT_SIMD" + "qadd%?\\t%0, %1, %2" + [(set_attr "predicable" "yes")]) + +(define_insn "sub3" + [(set (match_operand:FIXED 0 "s_register_operand" "=r") + (minus:FIXED (match_operand:FIXED 1 "s_register_operand" "r") + (match_operand:FIXED 2 "s_register_operand" "r")))] + "TARGET_32BIT" + "sub%?\\t%0, %1, %2" + [(set_attr "predicable" "yes")]) + +(define_insn "sub3" + [(set (match_operand:ADDSUB 0 "s_register_operand" "=r") + (minus:ADDSUB (match_operand:ADDSUB 1 "s_register_operand" "r") + (match_operand:ADDSUB 2 "s_register_operand" "r")))] + "TARGET_INT_SIMD" + "ssub%?\\t%0, %1, %2" + [(set_attr "predicable" "yes")]) + +(define_insn "ussub3" + [(set (match_operand:UQADDSUB 0 "s_register_operand" "=r") + (us_minus:UQADDSUB + (match_operand:UQADDSUB 1 "s_register_operand" "r") + (match_operand:UQADDSUB 2 "s_register_operand" "r")))] + "TARGET_INT_SIMD" + "uqsub%?\\t%0, %1, %2" + [(set_attr "predicable" "yes")]) + +(define_insn "sssub3" + [(set (match_operand:QADDSUB 0 "s_register_operand" "=r") + (ss_minus:QADDSUB (match_operand:QADDSUB 1 "s_register_operand" "r") + (match_operand:QADDSUB 2 "s_register_operand" "r")))] + "TARGET_INT_SIMD" + "qsub%?\\t%0, %1, %2" + [(set_attr "predicable" "yes")]) + +;; Fractional multiplies. + +; Note: none of these do any rounding. + +(define_expand "mulqq3" + [(set (match_operand:QQ 0 "s_register_operand" "") + (mult:QQ (match_operand:QQ 1 "s_register_operand" "") + (match_operand:QQ 2 "s_register_operand" "")))] + "TARGET_DSP_MULTIPLY && arm_arch_thumb2" +{ + rtx tmp1 = gen_reg_rtx (HImode); + rtx tmp2 = gen_reg_rtx (HImode); + rtx tmp3 = gen_reg_rtx (SImode); + + emit_insn (gen_extendqihi2 (tmp1, gen_lowpart (QImode, operands[1]))); + emit_insn (gen_extendqihi2 (tmp2, gen_lowpart (QImode, operands[2]))); + emit_insn (gen_mulhisi3 (tmp3, tmp1, tmp2)); + emit_insn (gen_extv (gen_lowpart (SImode, operands[0]), tmp3, GEN_INT (8), + GEN_INT (7))); + DONE; +}) + +(define_expand "mulhq3" + [(set (match_operand:HQ 0 "s_register_operand" "") + (mult:HQ (match_operand:HQ 1 "s_register_operand" "") + (match_operand:HQ 2 "s_register_operand" "")))] + "TARGET_DSP_MULTIPLY && arm_arch_thumb2" +{ + rtx tmp = gen_reg_rtx (SImode); + + emit_insn (gen_mulhisi3 (tmp, gen_lowpart (HImode, operands[1]), + gen_lowpart (HImode, operands[2]))); + /* We're doing a s.15 * s.15 multiplication, getting an s.30 result. Extract + an s.15 value from that. This won't overflow/saturate for _Fract + values. */ + emit_insn (gen_extv (gen_lowpart (SImode, operands[0]), tmp, + GEN_INT (16), GEN_INT (15))); + DONE; +}) + +(define_expand "mulsq3" + [(set (match_operand:SQ 0 "s_register_operand" "") + (mult:SQ (match_operand:SQ 1 "s_register_operand" "") + (match_operand:SQ 2 "s_register_operand" "")))] + "TARGET_32BIT && arm_arch3m" +{ + rtx tmp1 = gen_reg_rtx (DImode); + rtx tmp2 = gen_reg_rtx (SImode); + rtx tmp3 = gen_reg_rtx (SImode); + + /* s.31 * s.31 -> s.62 multiplication. */ + emit_insn (gen_mulsidi3 (tmp1, gen_lowpart (SImode, operands[1]), + gen_lowpart (SImode, operands[2]))); + emit_insn (gen_lshrsi3 (tmp2, gen_lowpart (SImode, tmp1), GEN_INT (31))); + emit_insn (gen_ashlsi3 (tmp3, gen_highpart (SImode, tmp1), GEN_INT (1))); + emit_insn (gen_iorsi3 (gen_lowpart (SImode, operands[0]), tmp2, tmp3)); + + DONE; +}) + +;; Accumulator multiplies. + +(define_expand "mulsa3" + [(set (match_operand:SA 0 "s_register_operand" "") + (mult:SA (match_operand:SA 1 "s_register_operand" "") + (match_operand:SA 2 "s_register_operand" "")))] + "TARGET_32BIT && arm_arch3m" +{ + rtx tmp1 = gen_reg_rtx (DImode); + rtx tmp2 = gen_reg_rtx (SImode); + rtx tmp3 = gen_reg_rtx (SImode); + + emit_insn (gen_mulsidi3 (tmp1, gen_lowpart (SImode, operands[1]), + gen_lowpart (SImode, operands[2]))); + emit_insn (gen_lshrsi3 (tmp2, gen_lowpart (SImode, tmp1), GEN_INT (15))); + emit_insn (gen_ashlsi3 (tmp3, gen_highpart (SImode, tmp1), GEN_INT (17))); + emit_insn (gen_iorsi3 (gen_lowpart (SImode, operands[0]), tmp2, tmp3)); + + DONE; +}) + +(define_expand "mulusa3" + [(set (match_operand:USA 0 "s_register_operand" "") + (mult:USA (match_operand:USA 1 "s_register_operand" "") + (match_operand:USA 2 "s_register_operand" "")))] + "TARGET_32BIT && arm_arch3m" +{ + rtx tmp1 = gen_reg_rtx (DImode); + rtx tmp2 = gen_reg_rtx (SImode); + rtx tmp3 = gen_reg_rtx (SImode); + + emit_insn (gen_umulsidi3 (tmp1, gen_lowpart (SImode, operands[1]), + gen_lowpart (SImode, operands[2]))); + emit_insn (gen_lshrsi3 (tmp2, gen_lowpart (SImode, tmp1), GEN_INT (16))); + emit_insn (gen_ashlsi3 (tmp3, gen_highpart (SImode, tmp1), GEN_INT (16))); + emit_insn (gen_iorsi3 (gen_lowpart (SImode, operands[0]), tmp2, tmp3)); + + DONE; +}) + +;; The code sequence emitted by this insn pattern uses the Q flag, which GCC +;; doesn't generally know about, so we don't bother expanding to individual +;; instructions. It may be better to just use an out-of-line asm libcall for +;; this. + +(define_insn "ssmulsa3" + [(set (match_operand:SA 0 "s_register_operand" "=r") + (ss_mult:SA (match_operand:SA 1 "s_register_operand" "r") + (match_operand:SA 2 "s_register_operand" "r"))) + (clobber (match_scratch:DI 3 "=r")) + (clobber (match_scratch:SI 4 "=r")) + (clobber (reg:CC CC_REGNUM))] + "TARGET_32BIT && arm_arch6" +{ + /* s16.15 * s16.15 -> s32.30. */ + output_asm_insn ("smull\\t%Q3, %R3, %1, %2", operands); + + if (TARGET_ARM) + output_asm_insn ("msr\\tAPSR_nzcvq, #0", operands); + else + { + output_asm_insn ("mov\\t%4, #0", operands); + output_asm_insn ("msr\\tAPSR_nzcvq, %4", operands); + } + + /* We have: + 31 high word 0 31 low word 0 + + [ S i i .... i i i ] [ i f f f ... f f ] + | + v + [ S i ... i f ... f f ] + + Need 16 integral bits, so saturate at 15th bit of high word. */ + + output_asm_insn ("ssat\\t%R3, #15, %R3", operands); + output_asm_insn ("mrs\\t%4, APSR", operands); + output_asm_insn ("tst\\t%4, #1<<27", operands); + if (TARGET_THUMB2) + output_asm_insn ("it\\tne", operands); + output_asm_insn ("mvnne\\t%Q3, %R3, asr #32", operands); + output_asm_insn ("mov\\t%0, %Q3, lsr #15", operands); + output_asm_insn ("orr\\t%0, %0, %R3, asl #17", operands); + return ""; +} + [(set_attr "conds" "clob") + (set (attr "length") + (if_then_else (eq_attr "is_thumb" "yes") + (const_int 38) + (const_int 32)))]) + +;; Same goes for this. + +(define_insn "usmulusa3" + [(set (match_operand:USA 0 "s_register_operand" "=r") + (us_mult:USA (match_operand:USA 1 "s_register_operand" "r") + (match_operand:USA 2 "s_register_operand" "r"))) + (clobber (match_scratch:DI 3 "=r")) + (clobber (match_scratch:SI 4 "=r")) + (clobber (reg:CC CC_REGNUM))] + "TARGET_32BIT && arm_arch6" +{ + /* 16.16 * 16.16 -> 32.32. */ + output_asm_insn ("umull\\t%Q3, %R3, %1, %2", operands); + + if (TARGET_ARM) + output_asm_insn ("msr\\tAPSR_nzcvq, #0", operands); + else + { + output_asm_insn ("mov\\t%4, #0", operands); + output_asm_insn ("msr\\tAPSR_nzcvq, %4", operands); + } + + /* We have: + 31 high word 0 31 low word 0 + + [ i i i .... i i i ] [ f f f f ... f f ] + | + v + [ i i ... i f ... f f ] + + Need 16 integral bits, so saturate at 16th bit of high word. */ + + output_asm_insn ("usat\\t%R3, #16, %R3", operands); + output_asm_insn ("mrs\\t%4, APSR", operands); + output_asm_insn ("tst\\t%4, #1<<27", operands); + if (TARGET_THUMB2) + output_asm_insn ("it\\tne", operands); + output_asm_insn ("sbfxne\\t%Q3, %R3, #15, #1", operands); + output_asm_insn ("lsr\\t%0, %Q3, #16", operands); + output_asm_insn ("orr\\t%0, %0, %R3, asl #16", operands); + return ""; +} + [(set_attr "conds" "clob") + (set (attr "length") + (if_then_else (eq_attr "is_thumb" "yes") + (const_int 38) + (const_int 32)))]) + +(define_expand "mulha3" + [(set (match_operand:HA 0 "s_register_operand" "") + (mult:HA (match_operand:HA 1 "s_register_operand" "") + (match_operand:HA 2 "s_register_operand" "")))] + "TARGET_DSP_MULTIPLY && arm_arch_thumb2" +{ + rtx tmp = gen_reg_rtx (SImode); + + emit_insn (gen_mulhisi3 (tmp, gen_lowpart (HImode, operands[1]), + gen_lowpart (HImode, operands[2]))); + emit_insn (gen_extv (gen_lowpart (SImode, operands[0]), tmp, GEN_INT (16), + GEN_INT (7))); + + DONE; +}) + +(define_expand "muluha3" + [(set (match_operand:UHA 0 "s_register_operand" "") + (mult:UHA (match_operand:UHA 1 "s_register_operand" "") + (match_operand:UHA 2 "s_register_operand" "")))] + "TARGET_DSP_MULTIPLY" +{ + rtx tmp1 = gen_reg_rtx (SImode); + rtx tmp2 = gen_reg_rtx (SImode); + rtx tmp3 = gen_reg_rtx (SImode); + + /* 8.8 * 8.8 -> 16.16 multiply. */ + emit_insn (gen_zero_extendhisi2 (tmp1, gen_lowpart (HImode, operands[1]))); + emit_insn (gen_zero_extendhisi2 (tmp2, gen_lowpart (HImode, operands[2]))); + emit_insn (gen_mulsi3 (tmp3, tmp1, tmp2)); + emit_insn (gen_extzv (gen_lowpart (SImode, operands[0]), tmp3, + GEN_INT (16), GEN_INT (8))); + + DONE; +}) + +(define_expand "ssmulha3" + [(set (match_operand:HA 0 "s_register_operand" "") + (ss_mult:HA (match_operand:HA 1 "s_register_operand" "") + (match_operand:HA 2 "s_register_operand" "")))] + "TARGET_32BIT && TARGET_DSP_MULTIPLY && arm_arch6" +{ + rtx tmp = gen_reg_rtx (SImode); + rtx rshift; + + emit_insn (gen_mulhisi3 (tmp, gen_lowpart (HImode, operands[1]), + gen_lowpart (HImode, operands[2]))); + + rshift = gen_rtx_ASHIFTRT (SImode, tmp, GEN_INT (7)); + + emit_insn (gen_rtx_SET (VOIDmode, gen_lowpart (HImode, operands[0]), + gen_rtx_SS_TRUNCATE (HImode, rshift))); + + DONE; +}) + +(define_expand "usmuluha3" + [(set (match_operand:UHA 0 "s_register_operand" "") + (us_mult:UHA (match_operand:UHA 1 "s_register_operand" "") + (match_operand:UHA 2 "s_register_operand" "")))] + "TARGET_INT_SIMD" +{ + rtx tmp1 = gen_reg_rtx (SImode); + rtx tmp2 = gen_reg_rtx (SImode); + rtx tmp3 = gen_reg_rtx (SImode); + rtx rshift_tmp = gen_reg_rtx (SImode); + + /* Note: there's no smul[bt][bt] equivalent for unsigned multiplies. Use a + normal 32x32->32-bit multiply instead. */ + emit_insn (gen_zero_extendhisi2 (tmp1, gen_lowpart (HImode, operands[1]))); + emit_insn (gen_zero_extendhisi2 (tmp2, gen_lowpart (HImode, operands[2]))); + + emit_insn (gen_mulsi3 (tmp3, tmp1, tmp2)); + + /* The operand to "usat" is signed, so we cannot use the "..., asr #8" + form of that instruction since the multiplication result TMP3 may have the + top bit set, thus be negative and saturate to zero. Use a separate + logical right-shift instead. */ + emit_insn (gen_lshrsi3 (rshift_tmp, tmp3, GEN_INT (8))); + emit_insn (gen_arm_usatsihi (gen_lowpart (HImode, operands[0]), rshift_tmp)); + + DONE; +}) + +(define_insn "arm_ssatsihi_shift" + [(set (match_operand:HI 0 "s_register_operand" "=r") + (ss_truncate:HI (match_operator:SI 1 "sat_shift_operator" + [(match_operand:SI 2 "s_register_operand" "r") + (match_operand:SI 3 "immediate_operand" "I")])))] + "TARGET_32BIT && arm_arch6" + "ssat%?\\t%0, #16, %2%S1" + [(set_attr "predicable" "yes") + (set_attr "type" "alu_shift")]) + +(define_insn "arm_usatsihi" + [(set (match_operand:HI 0 "s_register_operand" "=r") + (us_truncate:HI (match_operand:SI 1 "s_register_operand")))] + "TARGET_INT_SIMD" + "usat%?\\t%0, #16, %1" + [(set_attr "predicable" "yes")]) diff --git a/gcc/config/arm/arm-modes.def b/gcc/config/arm/arm-modes.def index 24e3d90a583..7f19ebe3073 100644 --- a/gcc/config/arm/arm-modes.def +++ b/gcc/config/arm/arm-modes.def @@ -70,6 +70,12 @@ VECTOR_MODES (INT, 16); /* V16QI V8HI V4SI V2DI */ VECTOR_MODES (FLOAT, 8); /* V4HF V2SF */ VECTOR_MODES (FLOAT, 16); /* V8HF V4SF V2DF */ +/* Fraction and accumulator vector modes. */ +VECTOR_MODES (FRACT, 4); /* V4QQ V2HQ */ +VECTOR_MODES (UFRACT, 4); /* V4UQQ V2UHQ */ +VECTOR_MODES (ACCUM, 4); /* V2HA */ +VECTOR_MODES (UACCUM, 4); /* V2UHA */ + /* Opaque integer modes for 3, 4, 6 or 8 Neon double registers (2 is TImode). */ INT_MODE (EI, 24); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index e0b8c3dd4a0..28b34c28815 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -1038,6 +1038,49 @@ bit_count (unsigned long value) return count; } +typedef struct +{ + enum machine_mode mode; + const char *name; +} arm_fixed_mode_set; + +/* A small helper for setting fixed-point library libfuncs. */ + +static void +arm_set_fixed_optab_libfunc (optab optable, enum machine_mode mode, + const char *funcname, const char *modename, + int num_suffix) +{ + char buffer[50]; + + if (num_suffix == 0) + sprintf (buffer, "__gnu_%s%s", funcname, modename); + else + sprintf (buffer, "__gnu_%s%s%d", funcname, modename, num_suffix); + + set_optab_libfunc (optable, mode, buffer); +} + +static void +arm_set_fixed_conv_libfunc (convert_optab optable, enum machine_mode to, + enum machine_mode from, const char *funcname, + const char *toname, const char *fromname) +{ + char buffer[50]; + char *maybe_suffix_2 = ""; + + /* Follow the logic for selecting a "2" suffix in fixed-bit.h. */ + if (ALL_FIXED_POINT_MODE_P (from) && ALL_FIXED_POINT_MODE_P (to) + && UNSIGNED_FIXED_POINT_MODE_P (from) == UNSIGNED_FIXED_POINT_MODE_P (to) + && ALL_FRACT_MODE_P (from) == ALL_FRACT_MODE_P (to)) + maybe_suffix_2 = "2"; + + sprintf (buffer, "__gnu_%s%s%s%s", funcname, fromname, toname, + maybe_suffix_2); + + set_conv_libfunc (optable, to, from, buffer); +} + /* Set up library functions unique to ARM. */ static void @@ -1183,6 +1226,137 @@ arm_init_libfuncs (void) break; } + /* Use names prefixed with __gnu_ for fixed-point helper functions. */ + { + const arm_fixed_mode_set fixed_arith_modes[] = + { + { QQmode, "qq" }, + { UQQmode, "uqq" }, + { HQmode, "hq" }, + { UHQmode, "uhq" }, + { SQmode, "sq" }, + { USQmode, "usq" }, + { DQmode, "dq" }, + { UDQmode, "udq" }, + { TQmode, "tq" }, + { UTQmode, "utq" }, + { HAmode, "ha" }, + { UHAmode, "uha" }, + { SAmode, "sa" }, + { USAmode, "usa" }, + { DAmode, "da" }, + { UDAmode, "uda" }, + { TAmode, "ta" }, + { UTAmode, "uta" } + }; + const arm_fixed_mode_set fixed_conv_modes[] = + { + { QQmode, "qq" }, + { UQQmode, "uqq" }, + { HQmode, "hq" }, + { UHQmode, "uhq" }, + { SQmode, "sq" }, + { USQmode, "usq" }, + { DQmode, "dq" }, + { UDQmode, "udq" }, + { TQmode, "tq" }, + { UTQmode, "utq" }, + { HAmode, "ha" }, + { UHAmode, "uha" }, + { SAmode, "sa" }, + { USAmode, "usa" }, + { DAmode, "da" }, + { UDAmode, "uda" }, + { TAmode, "ta" }, + { UTAmode, "uta" }, + { QImode, "qi" }, + { HImode, "hi" }, + { SImode, "si" }, + { DImode, "di" }, + { TImode, "ti" }, + { SFmode, "sf" }, + { DFmode, "df" } + }; + unsigned int i, j; + + for (i = 0; i < ARRAY_SIZE (fixed_arith_modes); i++) + { + arm_set_fixed_optab_libfunc (add_optab, fixed_arith_modes[i].mode, + "add", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (ssadd_optab, fixed_arith_modes[i].mode, + "ssadd", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (usadd_optab, fixed_arith_modes[i].mode, + "usadd", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (sub_optab, fixed_arith_modes[i].mode, + "sub", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (sssub_optab, fixed_arith_modes[i].mode, + "sssub", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (ussub_optab, fixed_arith_modes[i].mode, + "ussub", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (smul_optab, fixed_arith_modes[i].mode, + "mul", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (ssmul_optab, fixed_arith_modes[i].mode, + "ssmul", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (usmul_optab, fixed_arith_modes[i].mode, + "usmul", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (sdiv_optab, fixed_arith_modes[i].mode, + "div", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (udiv_optab, fixed_arith_modes[i].mode, + "udiv", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (ssdiv_optab, fixed_arith_modes[i].mode, + "ssdiv", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (usdiv_optab, fixed_arith_modes[i].mode, + "usdiv", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (neg_optab, fixed_arith_modes[i].mode, + "neg", fixed_arith_modes[i].name, 2); + arm_set_fixed_optab_libfunc (ssneg_optab, fixed_arith_modes[i].mode, + "ssneg", fixed_arith_modes[i].name, 2); + arm_set_fixed_optab_libfunc (usneg_optab, fixed_arith_modes[i].mode, + "usneg", fixed_arith_modes[i].name, 2); + arm_set_fixed_optab_libfunc (ashl_optab, fixed_arith_modes[i].mode, + "ashl", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (ashr_optab, fixed_arith_modes[i].mode, + "ashr", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (lshr_optab, fixed_arith_modes[i].mode, + "lshr", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (ssashl_optab, fixed_arith_modes[i].mode, + "ssashl", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (usashl_optab, fixed_arith_modes[i].mode, + "usashl", fixed_arith_modes[i].name, 3); + arm_set_fixed_optab_libfunc (cmp_optab, fixed_arith_modes[i].mode, + "cmp", fixed_arith_modes[i].name, 2); + } + + for (i = 0; i < ARRAY_SIZE (fixed_conv_modes); i++) + for (j = 0; j < ARRAY_SIZE (fixed_conv_modes); j++) + { + if (i == j + || (!ALL_FIXED_POINT_MODE_P (fixed_conv_modes[i].mode) + && !ALL_FIXED_POINT_MODE_P (fixed_conv_modes[j].mode))) + continue; + + arm_set_fixed_conv_libfunc (fract_optab, fixed_conv_modes[i].mode, + fixed_conv_modes[j].mode, "fract", + fixed_conv_modes[i].name, + fixed_conv_modes[j].name); + arm_set_fixed_conv_libfunc (satfract_optab, + fixed_conv_modes[i].mode, + fixed_conv_modes[j].mode, "satfract", + fixed_conv_modes[i].name, + fixed_conv_modes[j].name); + arm_set_fixed_conv_libfunc (fractuns_optab, + fixed_conv_modes[i].mode, + fixed_conv_modes[j].mode, "fractuns", + fixed_conv_modes[i].name, + fixed_conv_modes[j].name); + arm_set_fixed_conv_libfunc (satfractuns_optab, + fixed_conv_modes[i].mode, + fixed_conv_modes[j].mode, "satfractuns", + fixed_conv_modes[i].name, + fixed_conv_modes[j].name); + } + } + if (TARGET_AAPCS_BASED) synchronize_libfunc = init_one_libfunc ("__sync_synchronize"); } @@ -4203,6 +4377,10 @@ aapcs_allocate_return_reg (enum machine_mode mode, const_tree type, rtx aapcs_libcall_value (enum machine_mode mode) { + if (BYTES_BIG_ENDIAN && ALL_FIXED_POINT_MODE_P (mode) + && GET_MODE_SIZE (mode) <= 4) + mode = SImode; + return aapcs_allocate_return_reg (mode, NULL_TREE, NULL_TREE); } @@ -9252,8 +9430,9 @@ arm_return_in_msb (const_tree valtype) { return (TARGET_AAPCS_BASED && BYTES_BIG_ENDIAN - && (AGGREGATE_TYPE_P (valtype) - || TREE_CODE (valtype) == COMPLEX_TYPE)); + && (AGGREGATE_TYPE_P (valtype) + || TREE_CODE (valtype) == COMPLEX_TYPE + || FIXED_POINT_TYPE_P (valtype))); } /* Returns TRUE if INSN is an "LDR REG, ADDR" instruction. @@ -11287,7 +11466,8 @@ arm_pad_reg_upward (enum machine_mode mode ATTRIBUTE_UNUSED, { if (TARGET_AAPCS_BASED && BYTES_BIG_ENDIAN - && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE) + && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE + || FIXED_POINT_TYPE_P (type)) && int_size_in_bytes (type) <= 4) return true; @@ -19433,6 +19613,8 @@ arm_scalar_mode_supported_p (enum machine_mode mode) { if (mode == HFmode) return (arm_fp16_format != ARM_FP16_FORMAT_NONE); + else if (ALL_FIXED_POINT_MODE_P (mode)) + return true; else return default_scalar_mode_supported_p (mode); } @@ -22552,6 +22734,11 @@ arm_vector_mode_supported_p (enum machine_mode mode) || (mode == V8QImode))) return true; + if (TARGET_INT_SIMD && (mode == V4UQQmode || mode == V4QQmode + || mode == V2UHQmode || mode == V2HQmode || mode == V2UHAmode + || mode == V2HAmode)) + return true; + return false; } diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 3810f9e8f61..869b9a94712 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -607,6 +607,20 @@ extern int arm_arch_thumb_hwdiv; #define WCHAR_TYPE_SIZE BITS_PER_WORD #endif +/* Sized for fixed-point types. */ + +#define SHORT_FRACT_TYPE_SIZE 8 +#define FRACT_TYPE_SIZE 16 +#define LONG_FRACT_TYPE_SIZE 32 +#define LONG_LONG_FRACT_TYPE_SIZE 64 + +#define SHORT_ACCUM_TYPE_SIZE 16 +#define ACCUM_TYPE_SIZE 32 +#define LONG_ACCUM_TYPE_SIZE 64 +#define LONG_LONG_ACCUM_TYPE_SIZE 64 + +#define MAX_FIXED_MODE_SIZE 64 + #ifndef SIZE_TYPE #define SIZE_TYPE (TARGET_AAPCS_BASED ? "unsigned int" : "long unsigned int") #endif diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 03ae72defa3..3d4dcfa42a5 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -10889,3 +10889,5 @@ (include "neon.md") ;; Synchronization Primitives (include "sync.md") +;; Fixed-point patterns +(include "arm-fixed.md") diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md index b11b112d7a1..219918c8064 100644 --- a/gcc/config/arm/iterators.md +++ b/gcc/config/arm/iterators.md @@ -140,7 +140,18 @@ ;; Modes with 8-bit, 16-bit and 32-bit elements. (define_mode_iterator VU [V16QI V8HI V4SI]) - + +;; Iterators used for fixed-point support. +(define_mode_iterator FIXED [QQ HQ SQ UQQ UHQ USQ HA SA UHA USA]) + +(define_mode_iterator ADDSUB [V4QQ V2HQ V2HA]) + +(define_mode_iterator UQADDSUB [V4UQQ V2UHQ UQQ UHQ V2UHA UHA]) + +(define_mode_iterator QADDSUB [V4QQ V2HQ QQ HQ V2HA HA SQ SA]) + +(define_mode_iterator QMUL [HQ HA]) + ;;---------------------------------------------------------------------------- ;; Code iterators ;;---------------------------------------------------------------------------- @@ -384,6 +395,12 @@ (QI "nonimmediate_operand")]) (define_mode_attr qhs_extenddi_cstr [(SI "r") (HI "rm") (QI "rm")]) +;; Mode attributes used for fixed-point support. +(define_mode_attr qaddsub_suf [(V4UQQ "8") (V2UHQ "16") (UQQ "8") (UHQ "16") + (V2UHA "16") (UHA "16") + (V4QQ "8") (V2HQ "16") (QQ "8") (HQ "16") + (V2HA "16") (HA "16") (SQ "") (SA "")]) + ;;---------------------------------------------------------------------------- ;; Code attributes ;;---------------------------------------------------------------------------- diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md index 678a31c86e6..cfe8d33696d 100644 --- a/gcc/config/arm/predicates.md +++ b/gcc/config/arm/predicates.md @@ -227,6 +227,13 @@ (match_code "ashift,ashiftrt,lshiftrt,rotatert")) (match_test "mode == GET_MODE (op)"))) +;; True for shift operators which can be used with saturation instructions. +(define_special_predicate "sat_shift_operator" + (and (match_code "ashift,ashiftrt") + (match_test "GET_CODE (XEXP (op, 1)) == CONST_INT + && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op, 1)) <= 32)") + (match_test "mode == GET_MODE (op)"))) + ;; True for MULT, to identify which variant of shift_operator is in use. (define_special_predicate "mult_operator" (match_code "mult")) diff --git a/gcc/config/arm/t-arm b/gcc/config/arm/t-arm index 826ec0af5c2..b970ec26a35 100644 --- a/gcc/config/arm/t-arm +++ b/gcc/config/arm/t-arm @@ -37,7 +37,8 @@ MD_INCLUDES= $(srcdir)/config/arm/arm-tune.md \ $(srcdir)/config/arm/iwmmxt.md \ $(srcdir)/config/arm/vfp.md \ $(srcdir)/config/arm/neon.md \ - $(srcdir)/config/arm/thumb2.md + $(srcdir)/config/arm/thumb2.md \ + $(srcdir)/config/arm/arm-fixed.md LIB1ASMSRC = arm/lib1funcs.asm LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \ diff --git a/gcc/configure b/gcc/configure index 1a4c1b70448..63e44c5e43d 100755 --- a/gcc/configure +++ b/gcc/configure @@ -6965,6 +6965,10 @@ if test "${enable_fixed_point+set}" = set; then : else case $target in + arm*) + enable_fixed_point=yes + ;; + mips*-*-*) case $host in mips*-sgi-irix*) @@ -17801,7 +17805,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 17804 "configure" +#line 17808 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -17907,7 +17911,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 17910 "configure" +#line 17914 "configure" #include "confdefs.h" #if HAVE_DLFCN_H diff --git a/gcc/configure.ac b/gcc/configure.ac index 9d7bb66be20..c71281cbeb2 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -638,6 +638,10 @@ AC_ARG_ENABLE(fixed-point, [], [ case $target in + arm*) + enable_fixed_point=yes + ;; + mips*-*-*) case $host in mips*-sgi-irix*) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e6beacd7f25..f5685bfc518 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2011-08-01 Julian Brown + + * gcc.target/arm/fixed-point-exec.c: New test. + 2011-07-31 Uros Bizjak PR target/49920 diff --git a/gcc/testsuite/gcc.target/arm/fixed-point-exec.c b/gcc/testsuite/gcc.target/arm/fixed-point-exec.c new file mode 100644 index 00000000000..6bc3b07d6af --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/fixed-point-exec.c @@ -0,0 +1,301 @@ +/* { dg-do run { target { fixed_point } } } */ +/* { dg-options "-std=gnu99" } */ + +/* Check basic arithmetic ops for ARM fixed-point/saturating operation support. + Not target-independent since we make various assumptions about precision and + magnitudes of various types. */ + +#include +#include +#include +#include + +#define TEST(TYPE, OP, NAME, SUFFIX) \ + TYPE NAME##SUFFIX (TYPE A, TYPE B) \ + { \ + return A OP B; \ + } + +#define VARIANTS(TYPE, OP, NAME) \ + TEST (short TYPE, OP, NAME, _short); \ + TEST (TYPE, OP, NAME, _regular); \ + TEST (long TYPE, OP, NAME, _long); \ + TEST (_Sat short TYPE, OP, NAME, _sat_short); \ + TEST (_Sat TYPE, OP, NAME, _sat_regular); \ + TEST (_Sat long TYPE, OP, NAME, _sat_long); \ + TEST (unsigned short TYPE, OP, NAME, _uns_short); \ + TEST (unsigned TYPE, OP, NAME, _uns_regular); \ + TEST (unsigned long TYPE, OP, NAME, _uns_long); \ + TEST (unsigned _Sat short TYPE, OP, NAME, _uns_sat_short); \ + TEST (unsigned _Sat TYPE, OP, NAME, _uns_sat_regular); \ + TEST (unsigned _Sat long TYPE, OP, NAME, _uns_sat_long) + +VARIANTS (_Fract, +, plus_fract); +VARIANTS (_Accum, +, plus_accum); +VARIANTS (_Fract, -, minus_fract); +VARIANTS (_Accum, -, minus_accum); +VARIANTS (_Fract, *, mult_fract); +VARIANTS (_Accum, *, mult_accum); +VARIANTS (_Accum, /, div_accum); + +/* Inputs for signed add, multiply fractional tests. */ +short _Fract sf_a = 0.9hr; +short _Fract sf_b = -0.8hr; +_Fract f_a = 0.9r; +_Fract f_b = -0.8r; +long _Fract lf_a = 0.9lr; +long _Fract lf_b = -0.8lr; + +/* Inputs for signed subtract fractional tests. */ +short _Fract sf_c = 0.7hr; +short _Fract sf_d = 0.9hr; +_Fract f_c = 0.7r; +_Fract f_d = 0.9r; +long _Fract lf_c = 0.7lr; +long _Fract lf_d = 0.9lr; + +/* Inputs for unsigned add, subtract, multiply fractional tests. */ +unsigned short _Fract usf_a = 0.4uhr; +unsigned short _Fract usf_b = 0.3uhr; +unsigned _Fract uf_a = 0.4ur; +unsigned _Fract uf_b = 0.3ur; +unsigned long _Fract ulf_a = 0.4ulr; +unsigned long _Fract ulf_b = 0.3ulr; + +/* Inputs for saturating signed add tests. */ +short _Sat _Fract sf_e = 0.8hr; +short _Sat _Fract sf_f = 0.8hr; +_Sat _Fract f_e = 0.8r; +_Sat _Fract f_f = 0.8r; +long _Sat _Fract lf_e = 0.8r; +long _Sat _Fract lf_f = 0.8r; + +short _Sat _Fract sf_g = -0.8hr; +short _Sat _Fract sf_h = -0.8hr; +_Sat _Fract f_g = -0.8r; +_Sat _Fract f_h = -0.8r; +long _Sat _Fract lf_g = -0.8r; +long _Sat _Fract lf_h = -0.8r; + +/* Inputs for saturating unsigned subtract tests. */ +unsigned short _Sat _Fract usf_c = 0.3uhr; +unsigned short _Sat _Fract usf_d = 0.4uhr; +unsigned _Sat _Fract uf_c = 0.3ur; +unsigned _Sat _Fract uf_d = 0.4ur; +unsigned long _Sat _Fract ulf_c = 0.3ulr; +unsigned long _Sat _Fract ulf_d = 0.4ulr; + +/* Inputs for signed accumulator tests. */ + +short _Accum sa_a = 1.25hk; +short _Accum sa_b = -1.5hk; +_Accum a_a = 100.25k; +_Accum a_b = -100.5k; +long _Accum la_a = 1000.25lk; +long _Accum la_b = -1000.5lk; + +/* Inputs for unsigned accumulator tests. */ + +unsigned short _Accum usa_a = 2.5uhk; +unsigned short _Accum usa_b = 1.75uhk; +unsigned _Accum ua_a = 255.5uk; +unsigned _Accum ua_b = 170.25uk; +unsigned long _Accum ula_a = 1550.5ulk; +unsigned long _Accum ula_b = 999.5ulk; + +/* Inputs for signed saturating accumulator tests. */ + +short _Sat _Accum sa_c = 240.0hk; +short _Sat _Accum sa_d = 250.0hk; +short _Sat _Accum sa_e = -240.0hk; +short _Sat _Accum sa_f = -250.0hk; +short _Sat _Accum sa_g = 0.5hk; + +_Sat _Accum a_c = 65000.0k; +_Sat _Accum a_d = 20000.0k; +_Sat _Accum a_e = -65000.0k; +_Sat _Accum a_f = -20000.0k; +_Sat _Accum a_g = 0.5k; + +long _Sat _Accum la_c = 3472883712.0lk; +long _Sat _Accum la_d = 3456106496.0lk; +long _Sat _Accum la_e = -3472883712.0lk; +long _Sat _Accum la_f = -3456106496.0lk; +long _Sat _Accum la_g = 0.5lk; + +/* Inputs for unsigned saturating accumulator tests. */ + +unsigned short _Sat _Accum usa_c = 250.0uhk; +unsigned short _Sat _Accum usa_d = 240.0uhk; +unsigned short _Sat _Accum usa_e = 0.5uhk; + +unsigned _Sat _Accum ua_c = 65000.0uk; +unsigned _Sat _Accum ua_d = 20000.0uk; +unsigned _Sat _Accum ua_e = 0.5uk; + +unsigned long _Sat _Accum ula_c = 3472883712.0ulk; +unsigned long _Sat _Accum ula_d = 3456106496.0ulk; +unsigned long _Sat _Accum ula_e = 0.5ulk; + +#define CHECK(FN, EXP) do { \ + if (fabs ((float) (FN) - (EXP)) > 0.05) \ + { \ + fprintf (stderr, "result for " #FN " (as float): %f\n", (double) (FN));\ + abort (); \ + } \ + } while (0) + +#define CHECK_EXACT(FN, EXP) do { \ + if ((FN) != (EXP)) \ + { \ + fprintf (stderr, "result for " #FN " (as float): %f, should be %f\n", \ + (double) (FN), (double) (EXP)); \ + abort (); \ + } \ + } while (0) + +int +main (int argc, char *argv[]) +{ + /* Fract/fract operations, non-saturating. */ + + CHECK (plus_fract_short (sf_a, sf_b), 0.1); + CHECK (plus_fract_regular (f_a, f_b), 0.1); + CHECK (plus_fract_long (lf_a, lf_b), 0.1); + + CHECK (plus_fract_uns_short (usf_a, usf_b), 0.7); + CHECK (plus_fract_uns_regular (uf_a, uf_b), 0.7); + CHECK (plus_fract_uns_long (ulf_a, ulf_b), 0.7); + + CHECK (minus_fract_short (sf_c, sf_d), -0.2); + CHECK (minus_fract_regular (f_c, f_d), -0.2); + CHECK (minus_fract_long (lf_c, lf_d), -0.2); + + CHECK (minus_fract_uns_short (usf_a, usf_b), 0.1); + CHECK (minus_fract_uns_regular (uf_a, uf_b), 0.1); + CHECK (minus_fract_uns_long (ulf_a, ulf_b), 0.1); + + CHECK (mult_fract_short (sf_a, sf_b), -0.72); + CHECK (mult_fract_regular (f_a, f_b), -0.72); + CHECK (mult_fract_long (lf_a, lf_b), -0.72); + + CHECK (mult_fract_uns_short (usf_a, usf_b), 0.12); + CHECK (mult_fract_uns_regular (uf_a, uf_b), 0.12); + CHECK (mult_fract_uns_long (ulf_a, ulf_b), 0.12); + + /* Fract/fract operations, saturating. */ + + CHECK (plus_fract_sat_short (sf_e, sf_f), 1.0); + CHECK (plus_fract_sat_regular (f_e, f_f), 1.0); + CHECK (plus_fract_sat_long (lf_e, lf_f), 1.0); + + CHECK (plus_fract_sat_short (sf_g, sf_h), -1.0); + CHECK (plus_fract_sat_regular (f_g, f_h), -1.0); + CHECK (plus_fract_sat_long (lf_g, lf_h), -1.0); + + CHECK (plus_fract_uns_sat_short (sf_e, sf_f), 1.0); + CHECK (plus_fract_uns_sat_regular (f_e, f_f), 1.0); + CHECK (plus_fract_uns_sat_long (lf_e, lf_f), 1.0); + + CHECK (plus_fract_sat_short (sf_a, sf_b), 0.1); + CHECK (plus_fract_sat_regular (f_a, f_b), 0.1); + CHECK (plus_fract_sat_long (lf_a, lf_b), 0.1); + + CHECK (plus_fract_uns_sat_short (usf_a, usf_b), 0.7); + CHECK (plus_fract_uns_sat_regular (uf_a, uf_b), 0.7); + CHECK (plus_fract_uns_sat_long (ulf_a, ulf_b), 0.7); + + CHECK (minus_fract_uns_sat_short (usf_c, usf_d), 0.0); + CHECK (minus_fract_uns_sat_regular (uf_c, uf_d), 0.0); + CHECK (minus_fract_uns_sat_short (ulf_c, ulf_d), 0.0); + + CHECK (minus_fract_sat_short (sf_c, sf_d), -0.2); + CHECK (minus_fract_sat_regular (f_c, f_d), -0.2); + CHECK (minus_fract_sat_long (lf_c, lf_d), -0.2); + + /* Accum/accum operations, non-saturating. */ + + CHECK (plus_accum_short (sa_a, sa_b), -0.25); + CHECK (plus_accum_regular (a_a, a_b), -0.25); + CHECK (plus_accum_long (la_a, la_b), -0.25); + + CHECK (minus_accum_short (sa_a, sa_b), 2.75); + CHECK (minus_accum_regular (a_a, a_b), 200.75); + CHECK (minus_accum_long (la_a, la_b), 2000.75); + + CHECK (mult_accum_short (sa_a, sa_b), -1.875); + CHECK (mult_accum_regular (a_a, a_b), -10075.125); + CHECK (mult_accum_long (la_a, la_b), -1000750.125); + + CHECK (div_accum_short (sa_a, sa_b), -1.25/1.5); + CHECK (div_accum_regular (a_a, a_b), -100.25/100.5); + CHECK (div_accum_long (la_a, la_b), -1000.25/1000.5); + + /* Unsigned accum/accum operations, non-saturating. */ + + CHECK (plus_accum_uns_short (usa_a, usa_b), 4.25); + CHECK (plus_accum_uns_regular (ua_a, ua_b), 425.75); + CHECK (plus_accum_uns_long (ula_a, ula_b), 2550.0); + + CHECK (minus_accum_uns_short (usa_a, usa_b), 0.75); + CHECK (minus_accum_uns_regular (ua_a, ua_b), 85.25); + CHECK (minus_accum_uns_long (ula_a, ula_b), 551.0); + + CHECK (mult_accum_uns_short (usa_a, usa_b), 4.375); + CHECK (mult_accum_uns_regular (ua_a, ua_b), 43498.875); + CHECK (mult_accum_uns_long (ula_a, ula_b), 1549724.75); + + CHECK (div_accum_uns_short (usa_a, usa_b), 2.5/1.75); + CHECK (div_accum_uns_regular (ua_a, ua_b), 255.5/170.25); + CHECK (div_accum_uns_long (ula_a, ula_b), 1550.5/999.5); + + /* Signed accum/accum operations, saturating. */ + + CHECK_EXACT (plus_accum_sat_short (sa_c, sa_d), SACCUM_MAX); + CHECK_EXACT (plus_accum_sat_short (sa_e, sa_f), SACCUM_MIN); + CHECK_EXACT (plus_accum_sat_regular (a_c, a_d), ACCUM_MAX); + CHECK_EXACT (plus_accum_sat_regular (a_e, a_f), ACCUM_MIN); + CHECK_EXACT (plus_accum_sat_long (la_c, la_d), LACCUM_MAX); + CHECK_EXACT (plus_accum_sat_long (la_e, la_f), LACCUM_MIN); + + CHECK_EXACT (minus_accum_sat_short (sa_e, sa_d), SACCUM_MIN); + CHECK_EXACT (minus_accum_sat_short (sa_c, sa_f), SACCUM_MAX); + CHECK_EXACT (minus_accum_sat_regular (a_e, a_d), ACCUM_MIN); + CHECK_EXACT (minus_accum_sat_regular (a_c, a_f), ACCUM_MAX); + CHECK_EXACT (minus_accum_sat_long (la_e, la_d), LACCUM_MIN); + CHECK_EXACT (minus_accum_sat_long (la_c, la_f), LACCUM_MAX); + + CHECK_EXACT (mult_accum_sat_short (sa_c, sa_d), SACCUM_MAX); + CHECK_EXACT (mult_accum_sat_short (sa_c, sa_e), SACCUM_MIN); + CHECK_EXACT (mult_accum_sat_regular (a_c, a_d), ACCUM_MAX); + CHECK_EXACT (mult_accum_sat_regular (a_c, a_e), ACCUM_MIN); + CHECK_EXACT (mult_accum_sat_long (la_c, la_d), LACCUM_MAX); + CHECK_EXACT (mult_accum_sat_long (la_c, la_e), LACCUM_MIN); + + CHECK_EXACT (div_accum_sat_short (sa_d, sa_g), SACCUM_MAX); + CHECK_EXACT (div_accum_sat_short (sa_e, sa_g), SACCUM_MIN); + CHECK_EXACT (div_accum_sat_regular (a_c, a_g), ACCUM_MAX); + CHECK_EXACT (div_accum_sat_regular (a_e, a_g), ACCUM_MIN); + CHECK_EXACT (div_accum_sat_long (la_d, la_g), LACCUM_MAX); + CHECK_EXACT (div_accum_sat_long (la_e, la_g), LACCUM_MIN); + + /* Unsigned accum/accum operations, saturating. */ + + CHECK_EXACT (plus_accum_uns_sat_short (usa_c, usa_d), USACCUM_MAX); + CHECK_EXACT (plus_accum_uns_sat_regular (ua_c, ua_d), UACCUM_MAX); + CHECK_EXACT (plus_accum_uns_sat_long (ula_c, ula_d), ULACCUM_MAX); + + CHECK_EXACT (minus_accum_uns_sat_short (usa_d, usa_c), 0uhk); + CHECK_EXACT (minus_accum_uns_sat_regular (ua_d, ua_c), 0uk); + CHECK_EXACT (minus_accum_uns_sat_long (ula_d, ula_c), 0ulk); + + CHECK_EXACT (mult_accum_uns_sat_short (usa_c, usa_d), USACCUM_MAX); + CHECK_EXACT (mult_accum_uns_sat_regular (ua_c, ua_d), UACCUM_MAX); + CHECK_EXACT (mult_accum_uns_sat_long (ula_c, ula_d), ULACCUM_MAX); + + CHECK_EXACT (div_accum_uns_sat_short (usa_c, usa_e), USACCUM_MAX); + CHECK_EXACT (div_accum_uns_sat_regular (ua_c, ua_e), UACCUM_MAX); + CHECK_EXACT (div_accum_uns_sat_long (ula_c, ula_e), ULACCUM_MAX); + + return 0; +} diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 70118f82971..9108e46c9f0 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,9 @@ +2011-08-01 Julian Brown + + * config.host (arm*-*-linux*, arm*-*-uclinux*, arm*-*-eabi*) + (arm*-*-symbianelf*): Add t-fixedpoint-gnu-prefix makefile fragment. + * config/arm/bpabi-lib.h (LIBGCC2_FIXEDBIT_GNU_PREFIX): Define. + 2011-08-01 Julian Brown * Makefile.in (LIBGCC_VER_FIXEDPOINT_GNU_PREFIX): New. diff --git a/libgcc/config.host b/libgcc/config.host index 11760d0bda4..f7c1b3bd035 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -264,12 +264,15 @@ arm*-*-freebsd*) arm*-*-netbsdelf*) ;; arm*-*-linux*) # ARM GNU/Linux with ELF + tmake_file="${tmake_file} t-fixedpoint-gnu-prefix" ;; arm*-*-uclinux*) # ARM ucLinux + tmake_file="${tmake_file} t-fixedpoint-gnu-prefix" ;; arm*-*-ecos-elf) ;; arm*-*-eabi* | arm*-*-symbianelf* ) + tmake_file="${tmake_file} t-fixedpoint-gnu-prefix" ;; arm*-*-rtems*) ;; diff --git a/libgcc/config/arm/bpabi-lib.h b/libgcc/config/arm/bpabi-lib.h index 49a28c3c202..cfa09cf6e69 100644 --- a/libgcc/config/arm/bpabi-lib.h +++ b/libgcc/config/arm/bpabi-lib.h @@ -78,3 +78,8 @@ #ifdef L_floatundisf #define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatundisf, ul2f) #endif + +/* For ARM bpabi, we only want to use a "__gnu_" prefix for the fixed-point + helper functions - not everything in libgcc - in the interests of + maintaining backward compatibility. */ +#define LIBGCC2_FIXEDBIT_GNU_PREFIX