Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/107415/?format=api
{ "id": 107415, "url": "http://patchwork.ozlabs.org/api/patches/107415/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20110729164746.42dda9d9@rex.config/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20110729164746.42dda9d9@rex.config>", "list_archive_url": null, "date": "2011-07-29T15:47:46", "name": "ARM fixed-point support [6/6]: target-specific parts", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "3022113f991dcec60032b16e4190f67642eab5c4", "submitter": { "id": 4374, "url": "http://patchwork.ozlabs.org/api/people/4374/?format=api", "name": "Julian Brown", "email": "julian@codesourcery.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20110729164746.42dda9d9@rex.config/mbox/", "series": [], "comments": "http://patchwork.ozlabs.org/api/patches/107415/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/107415/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-return-298422-incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "mailing list gcc-patches@gcc.gnu.org" ], "Received": [ "from sourceware.org (server1.sourceware.org [209.132.180.131])\n\tby ozlabs.org (Postfix) with SMTP id C74B5B6F64\n\tfor <incoming@patchwork.ozlabs.org>;\n\tSat, 30 Jul 2011 01:48:22 +1000 (EST)", "(qmail 27609 invoked by alias); 29 Jul 2011 15:48:20 -0000", "(qmail 27593 invoked by uid 22791); 29 Jul 2011 15:48:15 -0000", "from mail.codesourcery.com (HELO mail.codesourcery.com)\n\t(38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with\n\tESMTP; Fri, 29 Jul 2011 15:47:55 +0000", "(qmail 20184 invoked from network); 29 Jul 2011 15:47:53 -0000", "from unknown (HELO rex.config) (julian@127.0.0.2) by\n\tmail.codesourcery.com with ESMTPA; 29 Jul 2011 15:47:53 -0000" ], "X-SWARE-Spam-Status": "No, hits=-0.9 required=5.0\ttests=AWL, BAYES_50,\n\tRP_MATCHES_RCVD", "X-Spam-Check-By": "sourceware.org", "Date": "Fri, 29 Jul 2011 16:47:46 +0100", "From": "Julian Brown <julian@codesourcery.com>", "To": "Richard Earnshaw <rearnsha@arm.com>", "Cc": "gcc-patches@gcc.gnu.org, \"Joseph S. Myers\" <joseph@codesourcery.com>,\n\tpaul@codesourcery.com, rearnsha@codesourcery.com,\n\tRamana Radhakrishnan <ramana.radhakrishnan@linaro.org>", "Subject": "Re: [PATCH] ARM fixed-point support [6/6]: target-specific parts", "Message-ID": "<20110729164746.42dda9d9@rex.config>", "In-Reply-To": "<4E0C7D5E.2000901@arm.com>", "References": "<20110513145818.69689c09@rex.config>\t<Pine.LNX.4.64.1105131449520.4437@digraph.polyomino.org.uk>\t<20110513173118.39cbeac7@rex.config>\t<20110526174558.5253ffca@rex.config>\t<4E0C7D5E.2000901@arm.com>", "Mime-Version": "1.0", "Content-Type": "multipart/mixed; boundary=\"MP_/d.m_s_T.U.KfV.oT_BC4RC3\"", "X-IsSubscribed": "yes", "Mailing-List": "contact gcc-patches-help@gcc.gnu.org; run by ezmlm", "Precedence": "bulk", "List-Id": "<gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<mailto:gcc-patches-unsubscribe-incoming=patchwork.ozlabs.org@gcc.gnu.org>", "List-Archive": "<http://gcc.gnu.org/ml/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-help@gcc.gnu.org>", "Sender": "gcc-patches-owner@gcc.gnu.org" }, "content": "On Thu, 30 Jun 2011 14:42:54 +0100\nRichard Earnshaw <rearnsha@arm.com> wrote:\n\n> > OK to apply? Tested alongside the rest of the patch series, in both\n> > big & little-endian mode.\n> > [snip]\n> \n> Please put the iterator definitions in iterators.md\n\nI've done this, and made a few other changes as required by the new\nversion of [4/6] in this series:\n\nhttp://gcc.gnu.org/ml/gcc-patches/2011-07/msg02680.html\n\nOK to apply? (I'll assume so if the previous patch gets approved, and\ntests look OK).\n\nJulian\n\nChangeLog\n\n gcc/\n * configure.ac (fixed-point): Add ARM support.\n * configure: Regenerate.\n * config/arm/arm.c (arm_fixed_mode_set): New struct.\n (arm_set_fixed_optab_libfunc): New.\n (arm_set_fixed_conv_libfunc): New.\n (arm_init_libfuncs): Initialise fixed-point helper libfuncs with\n ARM-specific names.\n (aapcs_libcall_value): Return sub-word-size fixed-point libcall\n return values in SImode.\n (arm_return_in_msb): Return fixed-point types in the msb.\n (arm_pad_reg_upwards, arm_pad_arg_upwards): Pad fixed-point types\n upwards.\n (arm_scalar_mode_supported_p): Support fixed-point modes.\n (arm_vector_mode_supported_p): Support vector fixed-point modes.\n * config/arm/arm.h (SHORT_FRACT_TYPE_SIZE, FRACT_TYPE_SIZE)\n (LONG_FRACT_TYPE_SIZE, LONG_LONG_FRACT_TYPE_SIZE)\n (SHORT_ACCUM_TYPE_SIZE, ACCUM_TYPE_SIZE, LONG_ACCUM_TYPE_SIZE)\n (LONG_LONG_ACCUM_TYPE_SIZE, MAX_FIXED_MODE_SIZE): Define.\n * config/arm/iterators.md (FIXED, ADDSUB, UQADDSUB, QADDSUB, QMUL):\n New mode iterators.\n (qaddsub_suf): New mode attribute.\n * config/arm/arm-modes.def (FRACT, UFRACT, ACCUM, UACCUM): Declare\n vector modes.\n * config/arm/predicates.md (sat_shift_operator): New predicate.\n * config/arm/arm-fixed.md: New.\n * config/arm/arm.md: Include arm-fixed.md.\n * config/arm/t-arm (MD_INCLUDES): Add arm-fixed.md.\n \n libgcc/\n * config.host (arm*-*-linux*, arm*-*-uclinux*, arm*-*-eabi*)\n (arm*-*-symbianelf*): Add t-fixedpoint-gnu-prefix makefile fragment.\n * config/arm/bpabi-lib.h (LIBGCC2_GNU_PREFIX): Define, if\n BUILDING_FIXED_BIT is set.\n\n gcc/testsuite/\n * gcc.target/arm/fixed-point-exec.c: New test.", "diff": "commit 51a5cdba96c5e583456b24bfb71aaad75c86ec8b\nAuthor: Julian Brown <julian@henry8.codesourcery.com>\nDate: Thu May 26 09:12:05 2011 -0700\n\n Fixed-point extension support for ARM.\n\ndiff --git a/gcc/config/arm/arm-fixed.md b/gcc/config/arm/arm-fixed.md\nnew file mode 100644\nindex 0000000..bd33ce2\n--- /dev/null\n+++ b/gcc/config/arm/arm-fixed.md\n@@ -0,0 +1,384 @@\n+;; Copyright 2011 Free Software Foundation, Inc.\n+;;\n+;; This file is part of GCC.\n+;;\n+;; GCC is free software; you can redistribute it and/or modify it\n+;; under the terms of the GNU General Public License as published\n+;; by the Free Software Foundation; either version 3, or (at your\n+;; option) any later version.\n+;;\n+;; GCC is distributed in the hope that it will be useful, but WITHOUT\n+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\n+;; License for more details.\n+;;\n+;; You should have received a copy of the GNU General Public License\n+;; along with GCC; see the file COPYING3. If not see\n+;; <http://www.gnu.org/licenses/>.\n+;;\n+;; This file contains ARM instructions that support fixed-point operations.\n+\n+(define_insn \"add<mode>3\"\n+ [(set (match_operand:FIXED 0 \"s_register_operand\" \"=r\")\n+\t(plus:FIXED (match_operand:FIXED 1 \"s_register_operand\" \"r\")\n+\t\t (match_operand:FIXED 2 \"s_register_operand\" \"r\")))]\n+ \"TARGET_32BIT\"\n+ \"add%?\\\\t%0, %1, %2\"\n+ [(set_attr \"predicable\" \"yes\")])\n+\n+(define_insn \"add<mode>3\"\n+ [(set (match_operand:ADDSUB 0 \"s_register_operand\" \"=r\")\n+\t(plus:ADDSUB (match_operand:ADDSUB 1 \"s_register_operand\" \"r\")\n+\t\t (match_operand:ADDSUB 2 \"s_register_operand\" \"r\")))]\n+ \"TARGET_INT_SIMD\"\n+ \"sadd<qaddsub_suf>%?\\\\t%0, %1, %2\"\n+ [(set_attr \"predicable\" \"yes\")])\n+\n+(define_insn \"usadd<mode>3\"\n+ [(set (match_operand:UQADDSUB 0 \"s_register_operand\" \"=r\")\n+\t(us_plus:UQADDSUB (match_operand:UQADDSUB 1 \"s_register_operand\" \"r\")\n+\t\t\t (match_operand:UQADDSUB 2 \"s_register_operand\" \"r\")))]\n+ \"TARGET_INT_SIMD\"\n+ \"uqadd<qaddsub_suf>%?\\\\t%0, %1, %2\"\n+ [(set_attr \"predicable\" \"yes\")])\n+\n+(define_insn \"ssadd<mode>3\"\n+ [(set (match_operand:QADDSUB 0 \"s_register_operand\" \"=r\")\n+\t(ss_plus:QADDSUB (match_operand:QADDSUB 1 \"s_register_operand\" \"r\")\n+\t\t\t (match_operand:QADDSUB 2 \"s_register_operand\" \"r\")))]\n+ \"TARGET_INT_SIMD\"\n+ \"qadd<qaddsub_suf>%?\\\\t%0, %1, %2\"\n+ [(set_attr \"predicable\" \"yes\")])\n+\n+(define_insn \"sub<mode>3\"\n+ [(set (match_operand:FIXED 0 \"s_register_operand\" \"=r\")\n+\t(minus:FIXED (match_operand:FIXED 1 \"s_register_operand\" \"r\")\n+\t\t (match_operand:FIXED 2 \"s_register_operand\" \"r\")))]\n+ \"TARGET_32BIT\"\n+ \"sub%?\\\\t%0, %1, %2\"\n+ [(set_attr \"predicable\" \"yes\")])\n+\n+(define_insn \"sub<mode>3\"\n+ [(set (match_operand:ADDSUB 0 \"s_register_operand\" \"=r\")\n+\t(minus:ADDSUB (match_operand:ADDSUB 1 \"s_register_operand\" \"r\")\n+\t\t (match_operand:ADDSUB 2 \"s_register_operand\" \"r\")))]\n+ \"TARGET_INT_SIMD\"\n+ \"ssub<qaddsub_suf>%?\\\\t%0, %1, %2\"\n+ [(set_attr \"predicable\" \"yes\")])\n+\n+(define_insn \"ussub<mode>3\"\n+ [(set (match_operand:UQADDSUB 0 \"s_register_operand\" \"=r\")\n+\t(us_minus:UQADDSUB\n+\t (match_operand:UQADDSUB 1 \"s_register_operand\" \"r\")\n+\t (match_operand:UQADDSUB 2 \"s_register_operand\" \"r\")))]\n+ \"TARGET_INT_SIMD\"\n+ \"uqsub<qaddsub_suf>%?\\\\t%0, %1, %2\"\n+ [(set_attr \"predicable\" \"yes\")])\n+\n+(define_insn \"sssub<mode>3\"\n+ [(set (match_operand:QADDSUB 0 \"s_register_operand\" \"=r\")\n+\t(ss_minus:QADDSUB (match_operand:QADDSUB 1 \"s_register_operand\" \"r\")\n+\t\t\t (match_operand:QADDSUB 2 \"s_register_operand\" \"r\")))]\n+ \"TARGET_INT_SIMD\"\n+ \"qsub<qaddsub_suf>%?\\\\t%0, %1, %2\"\n+ [(set_attr \"predicable\" \"yes\")])\n+\n+;; Fractional multiplies.\n+\n+; Note: none of these do any rounding.\n+\n+(define_expand \"mulqq3\"\n+ [(set (match_operand:QQ 0 \"s_register_operand\" \"\")\n+\t(mult:QQ (match_operand:QQ 1 \"s_register_operand\" \"\")\n+\t\t (match_operand:QQ 2 \"s_register_operand\" \"\")))]\n+ \"TARGET_DSP_MULTIPLY && arm_arch_thumb2\"\n+{\n+ rtx tmp1 = gen_reg_rtx (HImode);\n+ rtx tmp2 = gen_reg_rtx (HImode);\n+ rtx tmp3 = gen_reg_rtx (SImode);\n+ \n+ emit_insn (gen_extendqihi2 (tmp1, gen_lowpart (QImode, operands[1])));\n+ emit_insn (gen_extendqihi2 (tmp2, gen_lowpart (QImode, operands[2])));\n+ emit_insn (gen_mulhisi3 (tmp3, tmp1, tmp2));\n+ emit_insn (gen_extv (gen_lowpart (SImode, operands[0]), tmp3, GEN_INT (8),\n+\t\t GEN_INT (7)));\n+ DONE;\n+})\n+\n+(define_expand \"mulhq3\"\n+ [(set (match_operand:HQ 0 \"s_register_operand\" \"\")\n+\t(mult:HQ (match_operand:HQ 1 \"s_register_operand\" \"\")\n+\t\t (match_operand:HQ 2 \"s_register_operand\" \"\")))]\n+ \"TARGET_DSP_MULTIPLY && arm_arch_thumb2\"\n+{\n+ rtx tmp = gen_reg_rtx (SImode);\n+\n+ emit_insn (gen_mulhisi3 (tmp, gen_lowpart (HImode, operands[1]),\n+\t\t\t gen_lowpart (HImode, operands[2])));\n+ /* We're doing a s.15 * s.15 multiplication, getting an s.30 result. Extract\n+ an s.15 value from that. This won't overflow/saturate for _Fract\n+ values. */\n+ emit_insn (gen_extv (gen_lowpart (SImode, operands[0]), tmp,\n+\t\t GEN_INT (16), GEN_INT (15)));\n+ DONE;\n+})\n+\n+(define_expand \"mulsq3\"\n+ [(set (match_operand:SQ 0 \"s_register_operand\" \"\")\n+\t(mult:SQ (match_operand:SQ 1 \"s_register_operand\" \"\")\n+\t\t (match_operand:SQ 2 \"s_register_operand\" \"\")))]\n+ \"TARGET_32BIT && arm_arch3m\"\n+{\n+ rtx tmp1 = gen_reg_rtx (DImode);\n+ rtx tmp2 = gen_reg_rtx (SImode);\n+ rtx tmp3 = gen_reg_rtx (SImode);\n+ \n+ /* s.31 * s.31 -> s.62 multiplication. */\n+ emit_insn (gen_mulsidi3 (tmp1, gen_lowpart (SImode, operands[1]),\n+\t\t\t gen_lowpart (SImode, operands[2])));\n+ emit_insn (gen_lshrsi3 (tmp2, gen_lowpart (SImode, tmp1), GEN_INT (31)));\n+ emit_insn (gen_ashlsi3 (tmp3, gen_highpart (SImode, tmp1), GEN_INT (1)));\n+ emit_insn (gen_iorsi3 (gen_lowpart (SImode, operands[0]), tmp2, tmp3));\n+\n+ DONE;\n+})\n+\n+;; Accumulator multiplies.\n+\n+(define_expand \"mulsa3\"\n+ [(set (match_operand:SA 0 \"s_register_operand\" \"\")\n+\t(mult:SA (match_operand:SA 1 \"s_register_operand\" \"\")\n+\t\t (match_operand:SA 2 \"s_register_operand\" \"\")))]\n+ \"TARGET_32BIT && arm_arch3m\"\n+{\n+ rtx tmp1 = gen_reg_rtx (DImode);\n+ rtx tmp2 = gen_reg_rtx (SImode);\n+ rtx tmp3 = gen_reg_rtx (SImode);\n+ \n+ emit_insn (gen_mulsidi3 (tmp1, gen_lowpart (SImode, operands[1]),\n+\t\t\t gen_lowpart (SImode, operands[2])));\n+ emit_insn (gen_lshrsi3 (tmp2, gen_lowpart (SImode, tmp1), GEN_INT (15)));\n+ emit_insn (gen_ashlsi3 (tmp3, gen_highpart (SImode, tmp1), GEN_INT (17)));\n+ emit_insn (gen_iorsi3 (gen_lowpart (SImode, operands[0]), tmp2, tmp3));\n+\n+ DONE;\n+})\n+\n+(define_expand \"mulusa3\"\n+ [(set (match_operand:USA 0 \"s_register_operand\" \"\")\n+\t(mult:USA (match_operand:USA 1 \"s_register_operand\" \"\")\n+\t\t (match_operand:USA 2 \"s_register_operand\" \"\")))]\n+ \"TARGET_32BIT && arm_arch3m\"\n+{\n+ rtx tmp1 = gen_reg_rtx (DImode);\n+ rtx tmp2 = gen_reg_rtx (SImode);\n+ rtx tmp3 = gen_reg_rtx (SImode);\n+ \n+ emit_insn (gen_umulsidi3 (tmp1, gen_lowpart (SImode, operands[1]),\n+\t\t\t gen_lowpart (SImode, operands[2])));\n+ emit_insn (gen_lshrsi3 (tmp2, gen_lowpart (SImode, tmp1), GEN_INT (16)));\n+ emit_insn (gen_ashlsi3 (tmp3, gen_highpart (SImode, tmp1), GEN_INT (16)));\n+ emit_insn (gen_iorsi3 (gen_lowpart (SImode, operands[0]), tmp2, tmp3));\n+ \n+ DONE;\n+})\n+\n+;; The code sequence emitted by this insn pattern uses the Q flag, which GCC\n+;; doesn't generally know about, so we don't bother expanding to individual\n+;; instructions. It may be better to just use an out-of-line asm libcall for\n+;; this.\n+\n+(define_insn \"ssmulsa3\"\n+ [(set (match_operand:SA 0 \"s_register_operand\" \"=r\")\n+\t(ss_mult:SA (match_operand:SA 1 \"s_register_operand\" \"r\")\n+\t\t (match_operand:SA 2 \"s_register_operand\" \"r\")))\n+ (clobber (match_scratch:DI 3 \"=r\"))\n+ (clobber (match_scratch:SI 4 \"=r\"))\n+ (clobber (reg:CC CC_REGNUM))]\n+ \"TARGET_32BIT && arm_arch6\"\n+{\n+ /* s16.15 * s16.15 -> s32.30. */\n+ output_asm_insn (\"smull\\\\t%Q3, %R3, %1, %2\", operands);\n+\n+ if (TARGET_ARM)\n+ output_asm_insn (\"msr\\\\tAPSR_nzcvq, #0\", operands);\n+ else\n+ {\n+ output_asm_insn (\"mov\\\\t%4, #0\", operands);\n+ output_asm_insn (\"msr\\\\tAPSR_nzcvq, %4\", operands);\n+ }\n+\n+ /* We have:\n+ 31 high word 0 31 low word 0 \n+\n+ [ S i i .... i i i ] [ i f f f ... f f ]\n+ |\n+\t\t\tv\n+\t [ S i ... i f ... f f ]\n+\n+ Need 16 integral bits, so saturate at 15th bit of high word. */\n+\n+ output_asm_insn (\"ssat\\\\t%R3, #15, %R3\", operands);\n+ output_asm_insn (\"mrs\\\\t%4, APSR\", operands);\n+ output_asm_insn (\"tst\\\\t%4, #1<<27\", operands);\n+ if (TARGET_THUMB2)\n+ output_asm_insn (\"it\\\\tne\", operands);\n+ output_asm_insn (\"mvnne\\\\t%Q3, %R3, asr #32\", operands);\n+ output_asm_insn (\"mov\\\\t%0, %Q3, lsr #15\", operands);\n+ output_asm_insn (\"orr\\\\t%0, %0, %R3, asl #17\", operands);\n+ return \"\";\n+}\n+ [(set_attr \"conds\" \"clob\")\n+ (set (attr \"length\")\n+\t(if_then_else (eq_attr \"is_thumb\" \"yes\")\n+\t\t (const_int 38)\n+\t\t (const_int 32)))])\n+\n+;; Same goes for this.\n+\n+(define_insn \"usmulusa3\"\n+ [(set (match_operand:USA 0 \"s_register_operand\" \"=r\")\n+\t(us_mult:USA (match_operand:USA 1 \"s_register_operand\" \"r\")\n+\t\t (match_operand:USA 2 \"s_register_operand\" \"r\")))\n+ (clobber (match_scratch:DI 3 \"=r\"))\n+ (clobber (match_scratch:SI 4 \"=r\"))\n+ (clobber (reg:CC CC_REGNUM))]\n+ \"TARGET_32BIT && arm_arch6\"\n+{\n+ /* 16.16 * 16.16 -> 32.32. */\n+ output_asm_insn (\"umull\\\\t%Q3, %R3, %1, %2\", operands);\n+\n+ if (TARGET_ARM)\n+ output_asm_insn (\"msr\\\\tAPSR_nzcvq, #0\", operands);\n+ else\n+ {\n+ output_asm_insn (\"mov\\\\t%4, #0\", operands);\n+ output_asm_insn (\"msr\\\\tAPSR_nzcvq, %4\", operands);\n+ }\n+\n+ /* We have:\n+ 31 high word 0 31 low word 0 \n+\n+ [ i i i .... i i i ] [ f f f f ... f f ]\n+ |\n+\t\t\tv\n+\t [ i i ... i f ... f f ]\n+\n+ Need 16 integral bits, so saturate at 16th bit of high word. */\n+\n+ output_asm_insn (\"usat\\\\t%R3, #16, %R3\", operands);\n+ output_asm_insn (\"mrs\\\\t%4, APSR\", operands);\n+ output_asm_insn (\"tst\\\\t%4, #1<<27\", operands);\n+ if (TARGET_THUMB2)\n+ output_asm_insn (\"it\\\\tne\", operands);\n+ output_asm_insn (\"sbfxne\\\\t%Q3, %R3, #15, #1\", operands);\n+ output_asm_insn (\"lsr\\\\t%0, %Q3, #16\", operands);\n+ output_asm_insn (\"orr\\\\t%0, %0, %R3, asl #16\", operands);\n+ return \"\";\n+}\n+ [(set_attr \"conds\" \"clob\")\n+ (set (attr \"length\")\n+\t(if_then_else (eq_attr \"is_thumb\" \"yes\")\n+\t\t (const_int 38)\n+\t\t (const_int 32)))])\n+\n+(define_expand \"mulha3\"\n+ [(set (match_operand:HA 0 \"s_register_operand\" \"\")\n+\t(mult:HA (match_operand:HA 1 \"s_register_operand\" \"\")\n+\t\t (match_operand:HA 2 \"s_register_operand\" \"\")))]\n+ \"TARGET_DSP_MULTIPLY && arm_arch_thumb2\"\n+{\n+ rtx tmp = gen_reg_rtx (SImode);\n+ \n+ emit_insn (gen_mulhisi3 (tmp, gen_lowpart (HImode, operands[1]),\n+\t\t\t gen_lowpart (HImode, operands[2])));\n+ emit_insn (gen_extv (gen_lowpart (SImode, operands[0]), tmp, GEN_INT (16),\n+\t\t GEN_INT (7)));\n+\n+ DONE;\n+})\n+\n+(define_expand \"muluha3\"\n+ [(set (match_operand:UHA 0 \"s_register_operand\" \"\")\n+\t(mult:UHA (match_operand:UHA 1 \"s_register_operand\" \"\")\n+\t\t (match_operand:UHA 2 \"s_register_operand\" \"\")))]\n+ \"TARGET_DSP_MULTIPLY\"\n+{\n+ rtx tmp1 = gen_reg_rtx (SImode);\n+ rtx tmp2 = gen_reg_rtx (SImode);\n+ rtx tmp3 = gen_reg_rtx (SImode);\n+ \n+ /* 8.8 * 8.8 -> 16.16 multiply. */\n+ emit_insn (gen_zero_extendhisi2 (tmp1, gen_lowpart (HImode, operands[1])));\n+ emit_insn (gen_zero_extendhisi2 (tmp2, gen_lowpart (HImode, operands[2])));\n+ emit_insn (gen_mulsi3 (tmp3, tmp1, tmp2));\n+ emit_insn (gen_extzv (gen_lowpart (SImode, operands[0]), tmp3,\n+\t\t\tGEN_INT (16), GEN_INT (8)));\n+\n+ DONE;\n+})\n+\n+(define_expand \"ssmulha3\"\n+ [(set (match_operand:HA 0 \"s_register_operand\" \"\")\n+\t(ss_mult:HA (match_operand:HA 1 \"s_register_operand\" \"\")\n+\t\t (match_operand:HA 2 \"s_register_operand\" \"\")))]\n+ \"TARGET_32BIT && TARGET_DSP_MULTIPLY && arm_arch6\"\n+{\n+ rtx tmp = gen_reg_rtx (SImode);\n+ rtx rshift;\n+ \n+ emit_insn (gen_mulhisi3 (tmp, gen_lowpart (HImode, operands[1]),\n+\t\t\t gen_lowpart (HImode, operands[2])));\n+\n+ rshift = gen_rtx_ASHIFTRT (SImode, tmp, GEN_INT (7));\n+\n+ emit_insn (gen_rtx_SET (VOIDmode, gen_lowpart (HImode, operands[0]),\n+\t\t\t gen_rtx_SS_TRUNCATE (HImode, rshift)));\n+\n+ DONE;\n+})\n+\n+(define_expand \"usmuluha3\"\n+ [(set (match_operand:UHA 0 \"s_register_operand\" \"\")\n+\t(us_mult:UHA (match_operand:UHA 1 \"s_register_operand\" \"\")\n+\t\t (match_operand:UHA 2 \"s_register_operand\" \"\")))]\n+ \"TARGET_INT_SIMD\"\n+{\n+ rtx tmp1 = gen_reg_rtx (SImode);\n+ rtx tmp2 = gen_reg_rtx (SImode);\n+ rtx tmp3 = gen_reg_rtx (SImode);\n+ rtx rshift_tmp = gen_reg_rtx (SImode);\n+ \n+ /* Note: there's no smul[bt][bt] equivalent for unsigned multiplies. Use a\n+ normal 32x32->32-bit multiply instead. */\n+ emit_insn (gen_zero_extendhisi2 (tmp1, gen_lowpart (HImode, operands[1])));\n+ emit_insn (gen_zero_extendhisi2 (tmp2, gen_lowpart (HImode, operands[2])));\n+ \n+ emit_insn (gen_mulsi3 (tmp3, tmp1, tmp2));\n+\n+ /* The operand to \"usat\" is signed, so we cannot use the \"..., asr #8\"\n+ form of that instruction since the multiplication result TMP3 may have the\n+ top bit set, thus be negative and saturate to zero. Use a separate\n+ logical right-shift instead. */\n+ emit_insn (gen_lshrsi3 (rshift_tmp, tmp3, GEN_INT (8)));\n+ emit_insn (gen_arm_usatsihi (gen_lowpart (HImode, operands[0]), rshift_tmp));\n+\n+ DONE;\n+})\n+\n+(define_insn \"arm_ssatsihi_shift\"\n+ [(set (match_operand:HI 0 \"s_register_operand\" \"=r\")\n+\t(ss_truncate:HI (match_operator:SI 1 \"sat_shift_operator\"\n+\t\t\t [(match_operand:SI 2 \"s_register_operand\" \"r\")\n+\t\t\t (match_operand:SI 3 \"immediate_operand\" \"I\")])))]\n+ \"TARGET_32BIT && arm_arch6\"\n+ \"ssat%?\\\\t%0, #16, %2%S1\"\n+ [(set_attr \"predicable\" \"yes\")\n+ (set_attr \"type\" \"alu_shift\")])\n+\n+(define_insn \"arm_usatsihi\"\n+ [(set (match_operand:HI 0 \"s_register_operand\" \"=r\")\n+\t(us_truncate:HI (match_operand:SI 1 \"s_register_operand\")))]\n+ \"TARGET_INT_SIMD\"\n+ \"usat%?\\\\t%0, #16, %1\"\n+ [(set_attr \"predicable\" \"yes\")])\ndiff --git a/gcc/config/arm/arm-modes.def b/gcc/config/arm/arm-modes.def\nindex 24e3d90..7f19ebe 100644\n--- a/gcc/config/arm/arm-modes.def\n+++ b/gcc/config/arm/arm-modes.def\n@@ -70,6 +70,12 @@ VECTOR_MODES (INT, 16); /* V16QI V8HI V4SI V2DI */\n VECTOR_MODES (FLOAT, 8); /* V4HF V2SF */\n VECTOR_MODES (FLOAT, 16); /* V8HF V4SF V2DF */\n \n+/* Fraction and accumulator vector modes. */\n+VECTOR_MODES (FRACT, 4); /* V4QQ V2HQ */\n+VECTOR_MODES (UFRACT, 4); /* V4UQQ V2UHQ */\n+VECTOR_MODES (ACCUM, 4); /* V2HA */\n+VECTOR_MODES (UACCUM, 4); /* V2UHA */\n+\n /* Opaque integer modes for 3, 4, 6 or 8 Neon double registers (2 is\n TImode). */\n INT_MODE (EI, 24);\ndiff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c\nindex e0b8c3d..28b34c2 100644\n--- a/gcc/config/arm/arm.c\n+++ b/gcc/config/arm/arm.c\n@@ -1038,6 +1038,49 @@ bit_count (unsigned long value)\n return count;\n }\n \n+typedef struct\n+{\n+ enum machine_mode mode;\n+ const char *name;\n+} arm_fixed_mode_set;\n+\n+/* A small helper for setting fixed-point library libfuncs. */\n+\n+static void\n+arm_set_fixed_optab_libfunc (optab optable, enum machine_mode mode,\n+\t\t\t const char *funcname, const char *modename,\n+\t\t\t int num_suffix)\n+{\n+ char buffer[50];\n+ \n+ if (num_suffix == 0)\n+ sprintf (buffer, \"__gnu_%s%s\", funcname, modename);\n+ else\n+ sprintf (buffer, \"__gnu_%s%s%d\", funcname, modename, num_suffix);\n+ \n+ set_optab_libfunc (optable, mode, buffer);\n+}\n+\n+static void\n+arm_set_fixed_conv_libfunc (convert_optab optable, enum machine_mode to,\n+\t\t\t enum machine_mode from, const char *funcname,\n+\t\t\t const char *toname, const char *fromname)\n+{\n+ char buffer[50];\n+ char *maybe_suffix_2 = \"\";\n+ \n+ /* Follow the logic for selecting a \"2\" suffix in fixed-bit.h. */\n+ if (ALL_FIXED_POINT_MODE_P (from) && ALL_FIXED_POINT_MODE_P (to)\n+ && UNSIGNED_FIXED_POINT_MODE_P (from) == UNSIGNED_FIXED_POINT_MODE_P (to)\n+ && ALL_FRACT_MODE_P (from) == ALL_FRACT_MODE_P (to))\n+ maybe_suffix_2 = \"2\";\n+ \n+ sprintf (buffer, \"__gnu_%s%s%s%s\", funcname, fromname, toname,\n+\t maybe_suffix_2);\n+\n+ set_conv_libfunc (optable, to, from, buffer);\n+}\n+\n /* Set up library functions unique to ARM. */\n \n static void\n@@ -1183,6 +1226,137 @@ arm_init_libfuncs (void)\n break;\n }\n \n+ /* Use names prefixed with __gnu_ for fixed-point helper functions. */\n+ {\n+ const arm_fixed_mode_set fixed_arith_modes[] =\n+ {\n+\t{ QQmode, \"qq\" },\n+\t{ UQQmode, \"uqq\" },\n+\t{ HQmode, \"hq\" },\n+\t{ UHQmode, \"uhq\" },\n+\t{ SQmode, \"sq\" },\n+\t{ USQmode, \"usq\" },\n+\t{ DQmode, \"dq\" },\n+\t{ UDQmode, \"udq\" },\n+\t{ TQmode, \"tq\" },\n+\t{ UTQmode, \"utq\" },\n+\t{ HAmode, \"ha\" },\n+\t{ UHAmode, \"uha\" },\n+\t{ SAmode, \"sa\" },\n+\t{ USAmode, \"usa\" },\n+\t{ DAmode, \"da\" },\n+\t{ UDAmode, \"uda\" },\n+\t{ TAmode, \"ta\" },\n+\t{ UTAmode, \"uta\" }\n+ };\n+ const arm_fixed_mode_set fixed_conv_modes[] =\n+ {\n+\t{ QQmode, \"qq\" },\n+\t{ UQQmode, \"uqq\" },\n+\t{ HQmode, \"hq\" },\n+\t{ UHQmode, \"uhq\" },\n+\t{ SQmode, \"sq\" },\n+\t{ USQmode, \"usq\" },\n+\t{ DQmode, \"dq\" },\n+\t{ UDQmode, \"udq\" },\n+\t{ TQmode, \"tq\" },\n+\t{ UTQmode, \"utq\" },\n+\t{ HAmode, \"ha\" },\n+\t{ UHAmode, \"uha\" },\n+\t{ SAmode, \"sa\" },\n+\t{ USAmode, \"usa\" },\n+\t{ DAmode, \"da\" },\n+\t{ UDAmode, \"uda\" },\n+\t{ TAmode, \"ta\" },\n+\t{ UTAmode, \"uta\" },\n+\t{ QImode, \"qi\" },\n+\t{ HImode, \"hi\" },\n+\t{ SImode, \"si\" },\n+\t{ DImode, \"di\" },\n+\t{ TImode, \"ti\" },\n+\t{ SFmode, \"sf\" },\n+\t{ DFmode, \"df\" }\n+ };\n+ unsigned int i, j;\n+\n+ for (i = 0; i < ARRAY_SIZE (fixed_arith_modes); i++)\n+ {\n+\tarm_set_fixed_optab_libfunc (add_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"add\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (ssadd_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"ssadd\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (usadd_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"usadd\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (sub_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"sub\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (sssub_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"sssub\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (ussub_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"ussub\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (smul_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"mul\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (ssmul_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"ssmul\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (usmul_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"usmul\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (sdiv_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"div\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (udiv_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"udiv\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (ssdiv_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"ssdiv\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (usdiv_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"usdiv\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (neg_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"neg\", fixed_arith_modes[i].name, 2);\n+\tarm_set_fixed_optab_libfunc (ssneg_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"ssneg\", fixed_arith_modes[i].name, 2);\n+\tarm_set_fixed_optab_libfunc (usneg_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"usneg\", fixed_arith_modes[i].name, 2);\n+\tarm_set_fixed_optab_libfunc (ashl_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"ashl\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (ashr_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"ashr\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (lshr_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"lshr\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (ssashl_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"ssashl\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (usashl_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"usashl\", fixed_arith_modes[i].name, 3);\n+\tarm_set_fixed_optab_libfunc (cmp_optab, fixed_arith_modes[i].mode,\n+\t\t\t\t \"cmp\", fixed_arith_modes[i].name, 2);\n+ }\n+\n+ for (i = 0; i < ARRAY_SIZE (fixed_conv_modes); i++)\n+ for (j = 0; j < ARRAY_SIZE (fixed_conv_modes); j++)\n+\t{\n+\t if (i == j\n+\t || (!ALL_FIXED_POINT_MODE_P (fixed_conv_modes[i].mode)\n+\t\t && !ALL_FIXED_POINT_MODE_P (fixed_conv_modes[j].mode)))\n+\t continue;\n+\n+\t arm_set_fixed_conv_libfunc (fract_optab, fixed_conv_modes[i].mode,\n+\t\t\t\t fixed_conv_modes[j].mode, \"fract\",\n+\t\t\t\t fixed_conv_modes[i].name,\n+\t\t\t\t fixed_conv_modes[j].name);\n+\t arm_set_fixed_conv_libfunc (satfract_optab,\n+\t\t\t\t fixed_conv_modes[i].mode,\n+\t\t\t\t fixed_conv_modes[j].mode, \"satfract\",\n+\t\t\t\t fixed_conv_modes[i].name,\n+\t\t\t\t fixed_conv_modes[j].name);\n+\t arm_set_fixed_conv_libfunc (fractuns_optab,\n+\t\t\t\t fixed_conv_modes[i].mode,\n+\t\t\t\t fixed_conv_modes[j].mode, \"fractuns\",\n+\t\t\t\t fixed_conv_modes[i].name,\n+\t\t\t\t fixed_conv_modes[j].name);\n+\t arm_set_fixed_conv_libfunc (satfractuns_optab,\n+\t\t\t\t fixed_conv_modes[i].mode,\n+\t\t\t\t fixed_conv_modes[j].mode, \"satfractuns\",\n+\t\t\t\t fixed_conv_modes[i].name,\n+\t\t\t\t fixed_conv_modes[j].name);\n+\t}\n+ }\n+\n if (TARGET_AAPCS_BASED)\n synchronize_libfunc = init_one_libfunc (\"__sync_synchronize\");\n }\n@@ -4203,6 +4377,10 @@ aapcs_allocate_return_reg (enum machine_mode mode, const_tree type,\n rtx\n aapcs_libcall_value (enum machine_mode mode)\n {\n+ if (BYTES_BIG_ENDIAN && ALL_FIXED_POINT_MODE_P (mode)\n+ && GET_MODE_SIZE (mode) <= 4)\n+ mode = SImode;\n+\n return aapcs_allocate_return_reg (mode, NULL_TREE, NULL_TREE);\n }\n \n@@ -9252,8 +9430,9 @@ arm_return_in_msb (const_tree valtype)\n {\n return (TARGET_AAPCS_BASED\n && BYTES_BIG_ENDIAN\n- && (AGGREGATE_TYPE_P (valtype)\n- || TREE_CODE (valtype) == COMPLEX_TYPE));\n+\t && (AGGREGATE_TYPE_P (valtype)\n+\t || TREE_CODE (valtype) == COMPLEX_TYPE\n+\t || FIXED_POINT_TYPE_P (valtype)));\n }\n \n /* Returns TRUE if INSN is an \"LDR REG, ADDR\" instruction.\n@@ -11287,7 +11466,8 @@ arm_pad_reg_upward (enum machine_mode mode ATTRIBUTE_UNUSED,\n {\n if (TARGET_AAPCS_BASED\n && BYTES_BIG_ENDIAN\n- && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)\n+ && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE\n+\t || FIXED_POINT_TYPE_P (type))\n && int_size_in_bytes (type) <= 4)\n return true;\n \n@@ -19433,6 +19613,8 @@ arm_scalar_mode_supported_p (enum machine_mode mode)\n {\n if (mode == HFmode)\n return (arm_fp16_format != ARM_FP16_FORMAT_NONE);\n+ else if (ALL_FIXED_POINT_MODE_P (mode))\n+ return true;\n else\n return default_scalar_mode_supported_p (mode);\n }\n@@ -22552,6 +22734,11 @@ arm_vector_mode_supported_p (enum machine_mode mode)\n \t || (mode == V8QImode)))\n return true;\n \n+ if (TARGET_INT_SIMD && (mode == V4UQQmode || mode == V4QQmode\n+ || mode == V2UHQmode || mode == V2HQmode || mode == V2UHAmode\n+ || mode == V2HAmode))\n+ return true;\n+\n return false;\n }\n \ndiff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h\nindex 3810f9e..869b9a9 100644\n--- a/gcc/config/arm/arm.h\n+++ b/gcc/config/arm/arm.h\n@@ -607,6 +607,20 @@ extern int arm_arch_thumb_hwdiv;\n #define WCHAR_TYPE_SIZE BITS_PER_WORD\n #endif\n \n+/* Sized for fixed-point types. */\n+\n+#define SHORT_FRACT_TYPE_SIZE 8\n+#define FRACT_TYPE_SIZE 16\n+#define LONG_FRACT_TYPE_SIZE 32\n+#define LONG_LONG_FRACT_TYPE_SIZE 64\n+\n+#define SHORT_ACCUM_TYPE_SIZE 16\n+#define ACCUM_TYPE_SIZE 32\n+#define LONG_ACCUM_TYPE_SIZE 64\n+#define LONG_LONG_ACCUM_TYPE_SIZE 64\n+\n+#define MAX_FIXED_MODE_SIZE 64\n+\n #ifndef SIZE_TYPE\n #define SIZE_TYPE (TARGET_AAPCS_BASED ? \"unsigned int\" : \"long unsigned int\")\n #endif\ndiff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md\nindex 03ae72d..3d4dcfa 100644\n--- a/gcc/config/arm/arm.md\n+++ b/gcc/config/arm/arm.md\n@@ -10889,3 +10889,5 @@\n (include \"neon.md\")\n ;; Synchronization Primitives\n (include \"sync.md\")\n+;; Fixed-point patterns\n+(include \"arm-fixed.md\")\ndiff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md\nindex b11b112..219918c 100644\n--- a/gcc/config/arm/iterators.md\n+++ b/gcc/config/arm/iterators.md\n@@ -140,7 +140,18 @@\n \n ;; Modes with 8-bit, 16-bit and 32-bit elements.\n (define_mode_iterator VU [V16QI V8HI V4SI])\n- \n+\n+;; Iterators used for fixed-point support.\n+(define_mode_iterator FIXED [QQ HQ SQ UQQ UHQ USQ HA SA UHA USA])\n+\n+(define_mode_iterator ADDSUB [V4QQ V2HQ V2HA])\n+\n+(define_mode_iterator UQADDSUB [V4UQQ V2UHQ UQQ UHQ V2UHA UHA])\n+\n+(define_mode_iterator QADDSUB [V4QQ V2HQ QQ HQ V2HA HA SQ SA])\n+\n+(define_mode_iterator QMUL [HQ HA])\n+\n ;;----------------------------------------------------------------------------\n ;; Code iterators\n ;;----------------------------------------------------------------------------\n@@ -384,6 +395,12 @@\n \t\t\t\t (QI \"nonimmediate_operand\")])\n (define_mode_attr qhs_extenddi_cstr [(SI \"r\") (HI \"rm\") (QI \"rm\")])\n \n+;; Mode attributes used for fixed-point support.\n+(define_mode_attr qaddsub_suf [(V4UQQ \"8\") (V2UHQ \"16\") (UQQ \"8\") (UHQ \"16\")\n+\t\t\t (V2UHA \"16\") (UHA \"16\")\n+\t\t\t (V4QQ \"8\") (V2HQ \"16\") (QQ \"8\") (HQ \"16\")\n+\t\t\t (V2HA \"16\") (HA \"16\") (SQ \"\") (SA \"\")])\n+\n ;;----------------------------------------------------------------------------\n ;; Code attributes\n ;;----------------------------------------------------------------------------\ndiff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md\nindex 678a31c..cfe8d33 100644\n--- a/gcc/config/arm/predicates.md\n+++ b/gcc/config/arm/predicates.md\n@@ -227,6 +227,13 @@\n \t (match_code \"ashift,ashiftrt,lshiftrt,rotatert\"))\n (match_test \"mode == GET_MODE (op)\")))\n \n+;; True for shift operators which can be used with saturation instructions.\n+(define_special_predicate \"sat_shift_operator\"\n+ (and (match_code \"ashift,ashiftrt\")\n+ (match_test \"GET_CODE (XEXP (op, 1)) == CONST_INT\n+\t\t && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op, 1)) <= 32)\")\n+ (match_test \"mode == GET_MODE (op)\")))\n+\n ;; True for MULT, to identify which variant of shift_operator is in use.\n (define_special_predicate \"mult_operator\"\n (match_code \"mult\"))\ndiff --git a/gcc/config/arm/t-arm b/gcc/config/arm/t-arm\nindex 826ec0a..b970ec2 100644\n--- a/gcc/config/arm/t-arm\n+++ b/gcc/config/arm/t-arm\n@@ -37,7 +37,8 @@ MD_INCLUDES= \t$(srcdir)/config/arm/arm-tune.md \\\n \t\t$(srcdir)/config/arm/iwmmxt.md \\\n \t\t$(srcdir)/config/arm/vfp.md \\\n \t\t$(srcdir)/config/arm/neon.md \\\n-\t\t$(srcdir)/config/arm/thumb2.md\n+\t\t$(srcdir)/config/arm/thumb2.md \\\n+\t\t$(srcdir)/config/arm/arm-fixed.md\n \n LIB1ASMSRC = arm/lib1funcs.asm\n LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \\\ndiff --git a/gcc/configure b/gcc/configure\nindex 1a4c1b7..63e44c5 100755\n--- a/gcc/configure\n+++ b/gcc/configure\n@@ -6965,6 +6965,10 @@ if test \"${enable_fixed_point+set}\" = set; then :\n else\n \n case $target in\n+ arm*)\n+ enable_fixed_point=yes\n+ ;;\n+\n mips*-*-*)\n case $host in\n \tmips*-sgi-irix*)\n@@ -17801,7 +17805,7 @@ else\n lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2\n lt_status=$lt_dlunknown\n cat > conftest.$ac_ext <<_LT_EOF\n-#line 17804 \"configure\"\n+#line 17808 \"configure\"\n #include \"confdefs.h\"\n \n #if HAVE_DLFCN_H\n@@ -17907,7 +17911,7 @@ else\n lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2\n lt_status=$lt_dlunknown\n cat > conftest.$ac_ext <<_LT_EOF\n-#line 17910 \"configure\"\n+#line 17914 \"configure\"\n #include \"confdefs.h\"\n \n #if HAVE_DLFCN_H\ndiff --git a/gcc/configure.ac b/gcc/configure.ac\nindex 9d7bb66..c71281c 100644\n--- a/gcc/configure.ac\n+++ b/gcc/configure.ac\n@@ -638,6 +638,10 @@ AC_ARG_ENABLE(fixed-point,\n [],\n [\n case $target in\n+ arm*)\n+ enable_fixed_point=yes\n+ ;;\n+\n mips*-*-*)\n case $host in\n \tmips*-sgi-irix*)\ndiff --git a/gcc/testsuite/gcc.target/arm/fixed-point-exec.c b/gcc/testsuite/gcc.target/arm/fixed-point-exec.c\nnew file mode 100644\nindex 0000000..6bc3b07\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/arm/fixed-point-exec.c\n@@ -0,0 +1,301 @@\n+/* { dg-do run { target { fixed_point } } } */\n+/* { dg-options \"-std=gnu99\" } */\n+\n+/* Check basic arithmetic ops for ARM fixed-point/saturating operation support.\n+ Not target-independent since we make various assumptions about precision and\n+ magnitudes of various types. */\n+\n+#include <stdlib.h>\n+#include <stdio.h>\n+#include <math.h>\n+#include <stdfix.h>\n+\n+#define TEST(TYPE, OP, NAME, SUFFIX)\t\t\t\t\\\n+ TYPE NAME##SUFFIX (TYPE A, TYPE B)\t\t\t\t\\\n+ {\t\t\t\t\t\t\t\t\\\n+ return A OP B;\t\t\t\t\t\t\\\n+ }\n+\n+#define VARIANTS(TYPE, OP, NAME)\t\t\t\t\\\n+ TEST (short TYPE, OP, NAME, _short);\t\t\t\t\\\n+ TEST (TYPE, OP, NAME, _regular);\t\t\t\t\\\n+ TEST (long TYPE, OP, NAME, _long);\t\t\t\t\\\n+ TEST (_Sat short TYPE, OP, NAME, _sat_short);\t\t\t\\\n+ TEST (_Sat TYPE, OP, NAME, _sat_regular);\t\t\t\\\n+ TEST (_Sat long TYPE, OP, NAME, _sat_long);\t\t\t\\\n+ TEST (unsigned short TYPE, OP, NAME, _uns_short);\t\t\\\n+ TEST (unsigned TYPE, OP, NAME, _uns_regular);\t\t\t\\\n+ TEST (unsigned long TYPE, OP, NAME, _uns_long);\t\t\\\n+ TEST (unsigned _Sat short TYPE, OP, NAME, _uns_sat_short);\t\\\n+ TEST (unsigned _Sat TYPE, OP, NAME, _uns_sat_regular);\t\\\n+ TEST (unsigned _Sat long TYPE, OP, NAME, _uns_sat_long)\n+\n+VARIANTS (_Fract, +, plus_fract);\n+VARIANTS (_Accum, +, plus_accum);\n+VARIANTS (_Fract, -, minus_fract);\n+VARIANTS (_Accum, -, minus_accum);\n+VARIANTS (_Fract, *, mult_fract);\n+VARIANTS (_Accum, *, mult_accum);\n+VARIANTS (_Accum, /, div_accum);\n+\n+/* Inputs for signed add, multiply fractional tests. */\n+short _Fract sf_a = 0.9hr;\n+short _Fract sf_b = -0.8hr;\n+_Fract f_a = 0.9r;\n+_Fract f_b = -0.8r;\n+long _Fract lf_a = 0.9lr;\n+long _Fract lf_b = -0.8lr;\n+\n+/* Inputs for signed subtract fractional tests. */\n+short _Fract sf_c = 0.7hr;\n+short _Fract sf_d = 0.9hr;\n+_Fract f_c = 0.7r;\n+_Fract f_d = 0.9r;\n+long _Fract lf_c = 0.7lr;\n+long _Fract lf_d = 0.9lr;\n+\n+/* Inputs for unsigned add, subtract, multiply fractional tests. */\n+unsigned short _Fract usf_a = 0.4uhr;\n+unsigned short _Fract usf_b = 0.3uhr;\n+unsigned _Fract uf_a = 0.4ur;\n+unsigned _Fract uf_b = 0.3ur;\n+unsigned long _Fract ulf_a = 0.4ulr;\n+unsigned long _Fract ulf_b = 0.3ulr;\n+\n+/* Inputs for saturating signed add tests. */\n+short _Sat _Fract sf_e = 0.8hr;\n+short _Sat _Fract sf_f = 0.8hr;\n+_Sat _Fract f_e = 0.8r;\n+_Sat _Fract f_f = 0.8r;\n+long _Sat _Fract lf_e = 0.8r;\n+long _Sat _Fract lf_f = 0.8r;\n+\n+short _Sat _Fract sf_g = -0.8hr;\n+short _Sat _Fract sf_h = -0.8hr;\n+_Sat _Fract f_g = -0.8r;\n+_Sat _Fract f_h = -0.8r;\n+long _Sat _Fract lf_g = -0.8r;\n+long _Sat _Fract lf_h = -0.8r;\n+\n+/* Inputs for saturating unsigned subtract tests. */\n+unsigned short _Sat _Fract usf_c = 0.3uhr;\n+unsigned short _Sat _Fract usf_d = 0.4uhr;\n+unsigned _Sat _Fract uf_c = 0.3ur;\n+unsigned _Sat _Fract uf_d = 0.4ur;\n+unsigned long _Sat _Fract ulf_c = 0.3ulr;\n+unsigned long _Sat _Fract ulf_d = 0.4ulr;\n+\n+/* Inputs for signed accumulator tests. */\n+\n+short _Accum sa_a = 1.25hk;\n+short _Accum sa_b = -1.5hk;\n+_Accum a_a = 100.25k;\n+_Accum a_b = -100.5k;\n+long _Accum la_a = 1000.25lk;\n+long _Accum la_b = -1000.5lk;\n+\n+/* Inputs for unsigned accumulator tests. */\n+\n+unsigned short _Accum usa_a = 2.5uhk;\n+unsigned short _Accum usa_b = 1.75uhk;\n+unsigned _Accum ua_a = 255.5uk;\n+unsigned _Accum ua_b = 170.25uk;\n+unsigned long _Accum ula_a = 1550.5ulk;\n+unsigned long _Accum ula_b = 999.5ulk;\n+\n+/* Inputs for signed saturating accumulator tests. */\n+\n+short _Sat _Accum sa_c = 240.0hk;\n+short _Sat _Accum sa_d = 250.0hk;\n+short _Sat _Accum sa_e = -240.0hk;\n+short _Sat _Accum sa_f = -250.0hk;\n+short _Sat _Accum sa_g = 0.5hk;\n+\n+_Sat _Accum a_c = 65000.0k;\n+_Sat _Accum a_d = 20000.0k;\n+_Sat _Accum a_e = -65000.0k;\n+_Sat _Accum a_f = -20000.0k;\n+_Sat _Accum a_g = 0.5k;\n+\n+long _Sat _Accum la_c = 3472883712.0lk;\n+long _Sat _Accum la_d = 3456106496.0lk;\n+long _Sat _Accum la_e = -3472883712.0lk;\n+long _Sat _Accum la_f = -3456106496.0lk;\n+long _Sat _Accum la_g = 0.5lk;\n+\n+/* Inputs for unsigned saturating accumulator tests. */\n+\n+unsigned short _Sat _Accum usa_c = 250.0uhk;\n+unsigned short _Sat _Accum usa_d = 240.0uhk;\n+unsigned short _Sat _Accum usa_e = 0.5uhk;\n+\n+unsigned _Sat _Accum ua_c = 65000.0uk;\n+unsigned _Sat _Accum ua_d = 20000.0uk;\n+unsigned _Sat _Accum ua_e = 0.5uk;\n+\n+unsigned long _Sat _Accum ula_c = 3472883712.0ulk;\n+unsigned long _Sat _Accum ula_d = 3456106496.0ulk;\n+unsigned long _Sat _Accum ula_e = 0.5ulk;\n+\n+#define CHECK(FN, EXP) do {\t\t\t\t\t\t \\\n+ if (fabs ((float) (FN) - (EXP)) > 0.05)\t\t\t\t \\\n+ {\t\t\t\t\t\t\t\t\t \\\n+ fprintf (stderr, \"result for \" #FN \" (as float): %f\\n\", (double) (FN));\\\n+ abort ();\t\t\t\t\t\t\t\t \\\n+ }\t\t\t\t\t\t\t\t\t \\\n+ } while (0)\n+\n+#define CHECK_EXACT(FN, EXP) do {\t\t\t\t\t \\\n+ if ((FN) != (EXP))\t\t\t\t\t\t\t \\\n+ {\t\t\t\t\t\t\t\t\t \\\n+ fprintf (stderr, \"result for \" #FN \" (as float): %f, should be %f\\n\", \\\n+\t (double) (FN), (double) (EXP));\t\t\t\t \\\n+ abort ();\t\t\t\t\t\t\t\t \\\n+ }\t\t\t\t\t\t\t\t\t \\\n+ } while (0)\n+\n+int\n+main (int argc, char *argv[])\n+{\n+ /* Fract/fract operations, non-saturating. */\n+\n+ CHECK (plus_fract_short (sf_a, sf_b), 0.1);\n+ CHECK (plus_fract_regular (f_a, f_b), 0.1);\n+ CHECK (plus_fract_long (lf_a, lf_b), 0.1);\n+\n+ CHECK (plus_fract_uns_short (usf_a, usf_b), 0.7);\n+ CHECK (plus_fract_uns_regular (uf_a, uf_b), 0.7);\n+ CHECK (plus_fract_uns_long (ulf_a, ulf_b), 0.7);\n+\n+ CHECK (minus_fract_short (sf_c, sf_d), -0.2);\n+ CHECK (minus_fract_regular (f_c, f_d), -0.2);\n+ CHECK (minus_fract_long (lf_c, lf_d), -0.2);\n+\n+ CHECK (minus_fract_uns_short (usf_a, usf_b), 0.1);\n+ CHECK (minus_fract_uns_regular (uf_a, uf_b), 0.1);\n+ CHECK (minus_fract_uns_long (ulf_a, ulf_b), 0.1);\n+\n+ CHECK (mult_fract_short (sf_a, sf_b), -0.72);\n+ CHECK (mult_fract_regular (f_a, f_b), -0.72);\n+ CHECK (mult_fract_long (lf_a, lf_b), -0.72);\n+\n+ CHECK (mult_fract_uns_short (usf_a, usf_b), 0.12);\n+ CHECK (mult_fract_uns_regular (uf_a, uf_b), 0.12);\n+ CHECK (mult_fract_uns_long (ulf_a, ulf_b), 0.12);\n+\n+ /* Fract/fract operations, saturating. */\n+\n+ CHECK (plus_fract_sat_short (sf_e, sf_f), 1.0);\n+ CHECK (plus_fract_sat_regular (f_e, f_f), 1.0);\n+ CHECK (plus_fract_sat_long (lf_e, lf_f), 1.0);\n+\n+ CHECK (plus_fract_sat_short (sf_g, sf_h), -1.0);\n+ CHECK (plus_fract_sat_regular (f_g, f_h), -1.0);\n+ CHECK (plus_fract_sat_long (lf_g, lf_h), -1.0);\n+ \n+ CHECK (plus_fract_uns_sat_short (sf_e, sf_f), 1.0);\n+ CHECK (plus_fract_uns_sat_regular (f_e, f_f), 1.0);\n+ CHECK (plus_fract_uns_sat_long (lf_e, lf_f), 1.0);\n+\n+ CHECK (plus_fract_sat_short (sf_a, sf_b), 0.1);\n+ CHECK (plus_fract_sat_regular (f_a, f_b), 0.1);\n+ CHECK (plus_fract_sat_long (lf_a, lf_b), 0.1);\n+ \n+ CHECK (plus_fract_uns_sat_short (usf_a, usf_b), 0.7);\n+ CHECK (plus_fract_uns_sat_regular (uf_a, uf_b), 0.7);\n+ CHECK (plus_fract_uns_sat_long (ulf_a, ulf_b), 0.7);\n+\n+ CHECK (minus_fract_uns_sat_short (usf_c, usf_d), 0.0);\n+ CHECK (minus_fract_uns_sat_regular (uf_c, uf_d), 0.0);\n+ CHECK (minus_fract_uns_sat_short (ulf_c, ulf_d), 0.0);\n+ \n+ CHECK (minus_fract_sat_short (sf_c, sf_d), -0.2);\n+ CHECK (minus_fract_sat_regular (f_c, f_d), -0.2);\n+ CHECK (minus_fract_sat_long (lf_c, lf_d), -0.2);\n+\n+ /* Accum/accum operations, non-saturating. */\n+\n+ CHECK (plus_accum_short (sa_a, sa_b), -0.25);\n+ CHECK (plus_accum_regular (a_a, a_b), -0.25);\n+ CHECK (plus_accum_long (la_a, la_b), -0.25);\n+\n+ CHECK (minus_accum_short (sa_a, sa_b), 2.75);\n+ CHECK (minus_accum_regular (a_a, a_b), 200.75);\n+ CHECK (minus_accum_long (la_a, la_b), 2000.75);\n+ \n+ CHECK (mult_accum_short (sa_a, sa_b), -1.875);\n+ CHECK (mult_accum_regular (a_a, a_b), -10075.125);\n+ CHECK (mult_accum_long (la_a, la_b), -1000750.125);\n+\n+ CHECK (div_accum_short (sa_a, sa_b), -1.25/1.5);\n+ CHECK (div_accum_regular (a_a, a_b), -100.25/100.5);\n+ CHECK (div_accum_long (la_a, la_b), -1000.25/1000.5);\n+\n+ /* Unsigned accum/accum operations, non-saturating. */\n+ \n+ CHECK (plus_accum_uns_short (usa_a, usa_b), 4.25);\n+ CHECK (plus_accum_uns_regular (ua_a, ua_b), 425.75);\n+ CHECK (plus_accum_uns_long (ula_a, ula_b), 2550.0);\n+\n+ CHECK (minus_accum_uns_short (usa_a, usa_b), 0.75);\n+ CHECK (minus_accum_uns_regular (ua_a, ua_b), 85.25);\n+ CHECK (minus_accum_uns_long (ula_a, ula_b), 551.0);\n+ \n+ CHECK (mult_accum_uns_short (usa_a, usa_b), 4.375);\n+ CHECK (mult_accum_uns_regular (ua_a, ua_b), 43498.875);\n+ CHECK (mult_accum_uns_long (ula_a, ula_b), 1549724.75);\n+\n+ CHECK (div_accum_uns_short (usa_a, usa_b), 2.5/1.75);\n+ CHECK (div_accum_uns_regular (ua_a, ua_b), 255.5/170.25);\n+ CHECK (div_accum_uns_long (ula_a, ula_b), 1550.5/999.5);\n+\n+ /* Signed accum/accum operations, saturating. */\n+ \n+ CHECK_EXACT (plus_accum_sat_short (sa_c, sa_d), SACCUM_MAX);\n+ CHECK_EXACT (plus_accum_sat_short (sa_e, sa_f), SACCUM_MIN);\n+ CHECK_EXACT (plus_accum_sat_regular (a_c, a_d), ACCUM_MAX);\n+ CHECK_EXACT (plus_accum_sat_regular (a_e, a_f), ACCUM_MIN);\n+ CHECK_EXACT (plus_accum_sat_long (la_c, la_d), LACCUM_MAX);\n+ CHECK_EXACT (plus_accum_sat_long (la_e, la_f), LACCUM_MIN);\n+\n+ CHECK_EXACT (minus_accum_sat_short (sa_e, sa_d), SACCUM_MIN);\n+ CHECK_EXACT (minus_accum_sat_short (sa_c, sa_f), SACCUM_MAX);\n+ CHECK_EXACT (minus_accum_sat_regular (a_e, a_d), ACCUM_MIN);\n+ CHECK_EXACT (minus_accum_sat_regular (a_c, a_f), ACCUM_MAX);\n+ CHECK_EXACT (minus_accum_sat_long (la_e, la_d), LACCUM_MIN);\n+ CHECK_EXACT (minus_accum_sat_long (la_c, la_f), LACCUM_MAX);\n+\n+ CHECK_EXACT (mult_accum_sat_short (sa_c, sa_d), SACCUM_MAX);\n+ CHECK_EXACT (mult_accum_sat_short (sa_c, sa_e), SACCUM_MIN);\n+ CHECK_EXACT (mult_accum_sat_regular (a_c, a_d), ACCUM_MAX);\n+ CHECK_EXACT (mult_accum_sat_regular (a_c, a_e), ACCUM_MIN);\n+ CHECK_EXACT (mult_accum_sat_long (la_c, la_d), LACCUM_MAX);\n+ CHECK_EXACT (mult_accum_sat_long (la_c, la_e), LACCUM_MIN);\n+ \n+ CHECK_EXACT (div_accum_sat_short (sa_d, sa_g), SACCUM_MAX);\n+ CHECK_EXACT (div_accum_sat_short (sa_e, sa_g), SACCUM_MIN);\n+ CHECK_EXACT (div_accum_sat_regular (a_c, a_g), ACCUM_MAX);\n+ CHECK_EXACT (div_accum_sat_regular (a_e, a_g), ACCUM_MIN);\n+ CHECK_EXACT (div_accum_sat_long (la_d, la_g), LACCUM_MAX);\n+ CHECK_EXACT (div_accum_sat_long (la_e, la_g), LACCUM_MIN);\n+\n+ /* Unsigned accum/accum operations, saturating. */\n+\n+ CHECK_EXACT (plus_accum_uns_sat_short (usa_c, usa_d), USACCUM_MAX);\n+ CHECK_EXACT (plus_accum_uns_sat_regular (ua_c, ua_d), UACCUM_MAX);\n+ CHECK_EXACT (plus_accum_uns_sat_long (ula_c, ula_d), ULACCUM_MAX);\n+ \n+ CHECK_EXACT (minus_accum_uns_sat_short (usa_d, usa_c), 0uhk);\n+ CHECK_EXACT (minus_accum_uns_sat_regular (ua_d, ua_c), 0uk);\n+ CHECK_EXACT (minus_accum_uns_sat_long (ula_d, ula_c), 0ulk);\n+\n+ CHECK_EXACT (mult_accum_uns_sat_short (usa_c, usa_d), USACCUM_MAX);\n+ CHECK_EXACT (mult_accum_uns_sat_regular (ua_c, ua_d), UACCUM_MAX);\n+ CHECK_EXACT (mult_accum_uns_sat_long (ula_c, ula_d), ULACCUM_MAX);\n+\n+ CHECK_EXACT (div_accum_uns_sat_short (usa_c, usa_e), USACCUM_MAX);\n+ CHECK_EXACT (div_accum_uns_sat_regular (ua_c, ua_e), UACCUM_MAX);\n+ CHECK_EXACT (div_accum_uns_sat_long (ula_c, ula_e), ULACCUM_MAX);\n+\n+ return 0;\n+}\ndiff --git a/libgcc/config.host b/libgcc/config.host\nindex 11760d0..f7c1b3b 100644\n--- a/libgcc/config.host\n+++ b/libgcc/config.host\n@@ -264,12 +264,15 @@ arm*-*-freebsd*)\n arm*-*-netbsdelf*)\n \t;;\n arm*-*-linux*)\t\t\t# ARM GNU/Linux with ELF\n+\ttmake_file=\"${tmake_file} t-fixedpoint-gnu-prefix\"\n \t;;\n arm*-*-uclinux*)\t\t# ARM ucLinux\n+\ttmake_file=\"${tmake_file} t-fixedpoint-gnu-prefix\"\n \t;;\n arm*-*-ecos-elf)\n \t;;\n arm*-*-eabi* | arm*-*-symbianelf* )\n+\ttmake_file=\"${tmake_file} t-fixedpoint-gnu-prefix\"\n \t;;\n arm*-*-rtems*)\n \t;;\ndiff --git a/libgcc/config/arm/bpabi-lib.h b/libgcc/config/arm/bpabi-lib.h\nindex 49a28c3..3a6cb91 100644\n--- a/libgcc/config/arm/bpabi-lib.h\n+++ b/libgcc/config/arm/bpabi-lib.h\n@@ -78,3 +78,10 @@\n #ifdef L_floatundisf\n #define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatundisf, ul2f)\n #endif\n+\n+/* For ARM bpabi, we only want to use a \"__gnu_\" prefix for the fixed-point\n+ helper functions - not everything in libgcc - in the interests of\n+ maintaining backward compatibility. */\n+#ifdef BUILDING_FIXED_BIT\n+#define LIBGCC2_GNU_PREFIX\n+#endif\n", "prefixes": [] }