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
This commit is contained in:
parent
3d6c3bd710
commit
655b30bfde
@ -1,3 +1,33 @@
|
||||
2011-08-01 Julian Brown <julian@codesourcery.com>
|
||||
|
||||
* 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 <julian@codesourcery.com>
|
||||
|
||||
* calls.c (emit_library_call_value_1): Support padding for libcall
|
||||
|
384
gcc/config/arm/arm-fixed.md
Normal file
384
gcc/config/arm/arm-fixed.md
Normal file
@ -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
|
||||
;; <http://www.gnu.org/licenses/>.
|
||||
;;
|
||||
;; This file contains ARM instructions that support fixed-point operations.
|
||||
|
||||
(define_insn "add<mode>3"
|
||||
[(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 "add<mode>3"
|
||||
[(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<qaddsub_suf>%?\\t%0, %1, %2"
|
||||
[(set_attr "predicable" "yes")])
|
||||
|
||||
(define_insn "usadd<mode>3"
|
||||
[(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<qaddsub_suf>%?\\t%0, %1, %2"
|
||||
[(set_attr "predicable" "yes")])
|
||||
|
||||
(define_insn "ssadd<mode>3"
|
||||
[(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<qaddsub_suf>%?\\t%0, %1, %2"
|
||||
[(set_attr "predicable" "yes")])
|
||||
|
||||
(define_insn "sub<mode>3"
|
||||
[(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 "sub<mode>3"
|
||||
[(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<qaddsub_suf>%?\\t%0, %1, %2"
|
||||
[(set_attr "predicable" "yes")])
|
||||
|
||||
(define_insn "ussub<mode>3"
|
||||
[(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<qaddsub_suf>%?\\t%0, %1, %2"
|
||||
[(set_attr "predicable" "yes")])
|
||||
|
||||
(define_insn "sssub<mode>3"
|
||||
[(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<qaddsub_suf>%?\\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")])
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -10889,3 +10889,5 @@
|
||||
(include "neon.md")
|
||||
;; Synchronization Primitives
|
||||
(include "sync.md")
|
||||
;; Fixed-point patterns
|
||||
(include "arm-fixed.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
|
||||
;;----------------------------------------------------------------------------
|
||||
|
@ -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"))
|
||||
|
@ -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 \
|
||||
|
8
gcc/configure
vendored
8
gcc/configure
vendored
@ -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
|
||||
|
@ -638,6 +638,10 @@ AC_ARG_ENABLE(fixed-point,
|
||||
[],
|
||||
[
|
||||
case $target in
|
||||
arm*)
|
||||
enable_fixed_point=yes
|
||||
;;
|
||||
|
||||
mips*-*-*)
|
||||
case $host in
|
||||
mips*-sgi-irix*)
|
||||
|
@ -1,3 +1,7 @@
|
||||
2011-08-01 Julian Brown <julian@codesourcery.com>
|
||||
|
||||
* gcc.target/arm/fixed-point-exec.c: New test.
|
||||
|
||||
2011-07-31 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
PR target/49920
|
||||
|
301
gcc/testsuite/gcc.target/arm/fixed-point-exec.c
Normal file
301
gcc/testsuite/gcc.target/arm/fixed-point-exec.c
Normal file
@ -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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdfix.h>
|
||||
|
||||
#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;
|
||||
}
|
@ -1,3 +1,9 @@
|
||||
2011-08-01 Julian Brown <julian@codesourcery.com>
|
||||
|
||||
* 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 <julian@codesourcery.com>
|
||||
|
||||
* Makefile.in (LIBGCC_VER_FIXEDPOINT_GNU_PREFIX): New.
|
||||
|
@ -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*)
|
||||
;;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user