get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/97596/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 97596,
    "url": "http://patchwork.ozlabs.org/api/patches/97596/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20110526174558.5253ffca@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": "<20110526174558.5253ffca@rex.config>",
    "list_archive_url": null,
    "date": "2011-05-26T16:45:58",
    "name": "ARM fixed-point support [6/6]: target-specific parts",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "f4e90e73407c74fac7dcc53270ea549488414398",
    "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/20110526174558.5253ffca@rex.config/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/97596/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/97596/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<gcc-patches-return-292899-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 29677B6F89\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 27 May 2011 02:46:35 +1000 (EST)",
            "(qmail 28022 invoked by alias); 26 May 2011 16:46:33 -0000",
            "(qmail 28012 invoked by uid 22791); 26 May 2011 16:46:29 -0000",
            "from mail.codesourcery.com (HELO mail.codesourcery.com)\n\t(38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with\n\tESMTP; Thu, 26 May 2011 16:46:07 +0000",
            "(qmail 31784 invoked from network); 26 May 2011 16:46:05 -0000",
            "from unknown (HELO rex.config) (julian@127.0.0.2) by\n\tmail.codesourcery.com with ESMTPA; 26 May 2011 16:46:05 -0000"
        ],
        "X-SWARE-Spam-Status": "No, hits=-0.3 required=5.0\ttests=AWL, BAYES_50,\n\tT_RP_MATCHES_RCVD",
        "X-Spam-Check-By": "sourceware.org",
        "Date": "Thu, 26 May 2011 17:45:58 +0100",
        "From": "Julian Brown <julian@codesourcery.com>",
        "To": "gcc-patches@gcc.gnu.org",
        "Cc": "\"Joseph S. Myers\" <joseph@codesourcery.com>, paul@codesourcery.com,\n\trearnsha@codesourcery.com,\n\tRamana Radhakrishnan <ramana.radhakrishnan@linaro.org>",
        "Subject": "Re: [PATCH] ARM fixed-point support [6/6]: target-specific parts",
        "Message-ID": "<20110526174558.5253ffca@rex.config>",
        "In-Reply-To": "<20110513173118.39cbeac7@rex.config>",
        "References": "<20110513145818.69689c09@rex.config>\t<Pine.LNX.4.64.1105131449520.4437@digraph.polyomino.org.uk>\t<20110513173118.39cbeac7@rex.config>",
        "Mime-Version": "1.0",
        "Content-Type": "multipart/mixed; boundary=\"MP_/U1wVm9kOkM/W0nI393RqjDd\"",
        "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 Fri, 13 May 2011 17:31:18 +0100\nJulian Brown <julian@codesourcery.com> wrote:\n\n> On Fri, 13 May 2011 14:54:47 +0000 (UTC)\n> \"Joseph S. Myers\" <joseph@codesourcery.com> wrote:\n> \n> > On Fri, 13 May 2011, Julian Brown wrote:\n> > \n> > > although Joseph's comments have (hopefully) all been addressed.\n> > > One must now configure with \"--enable-fixed-point\" to enable the\n> > > fixed-point support.\n> > \n> > No, that's not how this configure logic works; it enables fixed\n> > point by default for the given targets.  The bit that enables it by\n> > default for MIPS (and that you're changing to cover ARM as well) is\n> > the code that is called if the user *doesn't* pass\n> > --enable-fixed-point or --disable-fixed-point.\n> \n> Yes, you're quite right: I had forgotten to run autoconf after\n> changing configure.ac whilst testing. Sorry for the misinformation!\n\nThis is a new version of the patch, which fixes a couple of issues\ndiscovered on our internal branch since the last version was posted.\nThis version handles \"long long\" fixed point types in the same way as\n32-bit MIPS: basically the sizes of those types are clamped to 64 bits.\n\nThis means the testsuite changes in:\n\nhttp://gcc.gnu.org/ml/gcc-patches/2011-05/msg00969.html\n\nare no longer required.\n\nAnother couple of problems have also been fixed, relating to big-endian\nmode. One was the use of simplify_gen_subreg with a hard-wired offset in\na several of the insn expanders, where I should have just used\ngen_highpart -- which works in either endianness, and makes the intent\nclearer anyway.\n\nThe other issue is ABI-related. My previous assertion that fixed-point\ntypes (smaller than word size) should be passed to and returned from\nfunctions \"like integers\" doesn't really work out very well after all\nin big-endian mode, so needs re-thinking. The problem is basically that\nsuch fixed-point types are incorrectly padded in big-endian mode, so\nthe data ends up in a different part of the passed word than expected.\n\nThe way chars and shorts is handled is as follows: when those types are\npassed to a function, they are promoted to word-size ints, which is a\nnop-op: the values can simply be reinterpreted as ints, and that works\nfine in either endianness. We might hope to be able to do the same thing\nfor smaller-than-word-size fixed-point types, but unfortunately we\ncan't: e.g. a \"short fract\" or \"fract\" can't just be reinterpreted as a\n\"long fract\" (the 32-bit fractional type), because the fixed-point is\nin a different place for the wider type (and performing conversions\nwould itself require libcalls at present). It also doesn't work to\npromote small fixed-point types to SImode: as well as being\nconceptually messy, we hit ICEs very quickly attempting that.\n\nSo instead, I think that small fixed-point types should be handled the\nsame way as small aggregates or small complex-valued types. This means\neffectively no change in little-endian mode, but in big-endian mode:\n\n* for register arguments, fixed-point types are passed in the\n  most-significant end of the register.\n\n* for stack arguments, fixed-point types are passed in lower memory\n  addresses.\n\n* for return values, fixed-point types are again in the\n  most-significant end of the return register (r0).\n\nThis is quite easy to set up in the backend code, but unfortunately I\nhit a snag in libcall expansion in calls.c: padding of arguments and\nreturn values is not properly supported, as it is for regular function\ncalls. I've implemented that, and will post it as a separate patch.\n\nOK to apply? Tested alongside the rest of the patch series, in both big\n& little-endian mode.\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/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    * config/arm/fixed-bit-machine.h: New.\n \n    libgcc/\n    * config.host (arm*-*-linux*, arm*-*-uclinux*, arm*-*-eabi*)\n    (arm*-*-symbianelf*): Add arm/t-fixed-point makefile fragment.\n    target-specific or generic fixed_bit_machine_header to decorate the\n    names of fixed-point helper functions.\n    * config/arm/t-fixed-point: New.\n\n    gcc/testsuite/\n    * gcc.target/arm/fixed-point-exec.c: New test.",
    "diff": "commit b4ddde3e7fbc6a2961dd24695df53623f4970f1d\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..df1c9ef\n--- /dev/null\n+++ b/gcc/config/arm/arm-fixed.md\n@@ -0,0 +1,399 @@\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_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+(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+(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 cd32fe3..5a62802 100644\n--- a/gcc/config/arm/arm.c\n+++ b/gcc/config/arm/arm.c\n@@ -986,6 +986,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@@ -1131,6 +1174,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@@ -4137,6 +4311,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@@ -9037,8 +9215,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@@ -11401,7 +11580,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@@ -19539,6 +19719,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@@ -22664,6 +22846,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 86d842d..7a5dd01 100644\n--- a/gcc/config/arm/arm.h\n+++ b/gcc/config/arm/arm.h\n@@ -592,6 +592,20 @@ extern int arm_arch_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 12fd7ca..72f862e 100644\n--- a/gcc/config/arm/arm.md\n+++ b/gcc/config/arm/arm.md\n@@ -10935,3 +10935,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/fixed-bit-machine.h b/gcc/config/arm/fixed-bit-machine.h\nnew file mode 100644\nindex 0000000..9f3bf5b\n--- /dev/null\n+++ b/gcc/config/arm/fixed-bit-machine.h\n@@ -0,0 +1,30 @@\n+/* Machine-specific override for fixed-point support routine names.\n+   Copyright (C) 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+   Under Section 7 of GPL version 3, you are granted additional\n+   permissions described in the GCC Runtime Library Exception, version\n+   3.1, as published by the Free Software Foundation.\n+\n+   You should have received a copy of the GNU General Public License and\n+   a copy of the GCC Runtime Library Exception along with this program;\n+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see\n+   <http://www.gnu.org/licenses/>.  */\n+\n+/* To be EABI-compliant (until the EABI supports fixed-point functionality),\n+   use the __gnu_ namespace for fixed-point helper functions.  */\n+\n+#ifdef __ARM_EABI__\n+#define DECORATE_FIXED_NAME(X) __gnu_ ## X\n+#endif\ndiff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md\nindex 891a974..f1800dc 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 274af3e..aba11bf 100755\ndiff --git a/gcc/configure.ac b/gcc/configure.ac\nindex 9ace66d..db783ea 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 e3c48bb..5f24004 100644\n--- a/libgcc/config.host\n+++ b/libgcc/config.host\n@@ -207,12 +207,15 @@ arm*-*-freebsd*)\n arm*-*-netbsdelf*)\n \t;;\n arm*-*-linux*)\t\t\t# ARM GNU/Linux with ELF\n+\ttmake_file=\"${tmake_file} arm/t-fixed-point\"\n \t;;\n arm*-*-uclinux*)\t\t# ARM ucLinux\n+\ttmake_file=\"${tmake_file} arm/t-fixed-point\"\n \t;;\n arm*-*-ecos-elf)\n \t;;\n arm*-*-eabi* | arm*-*-symbianelf* )\n+\ttmake_file=\"${tmake_file} arm/t-fixed-point\"\n \t;;\n arm*-*-rtems*)\n \t;;\ndiff --git a/libgcc/config/arm/t-fixed-point b/libgcc/config/arm/t-fixed-point\nnew file mode 100644\nindex 0000000..66346dd\n--- /dev/null\n+++ b/libgcc/config/arm/t-fixed-point\n@@ -0,0 +1 @@\n+fixed_bit_machine_header := arm/fixed-bit-machine.h\n",
    "prefixes": []
}