get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 95482,
    "url": "http://patchwork.ozlabs.org/api/patches/95482/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20110513145818.69689c09@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": "<20110513145818.69689c09@rex.config>",
    "list_archive_url": null,
    "date": "2011-05-13T13:58:18",
    "name": "ARM fixed-point support [6/6]: target-specific parts",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "b2e359003ae373b7711d2616670e7c1a205b9318",
    "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/20110513145818.69689c09@rex.config/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/95482/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/95482/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<gcc-patches-return-291807-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 4EBE0B6EF1\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 13 May 2011 23:59:12 +1000 (EST)",
            "(qmail 5440 invoked by alias); 13 May 2011 13:59:08 -0000",
            "(qmail 5345 invoked by uid 22791); 13 May 2011 13:58:54 -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, 13 May 2011 13:58:24 +0000",
            "(qmail 17506 invoked from network); 13 May 2011 13:58:22 -0000",
            "from unknown (HELO rex.config) (julian@127.0.0.2) by\n\tmail.codesourcery.com with ESMTPA; 13 May 2011 13:58:22 -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": "Fri, 13 May 2011 14:58:18 +0100",
        "From": "Julian Brown <julian@codesourcery.com>",
        "To": "gcc-patches@gcc.gnu.org",
        "Subject": "[PATCH] ARM fixed-point support [6/6]: target-specific parts",
        "Message-ID": "<20110513145818.69689c09@rex.config>",
        "Mime-Version": "1.0",
        "Content-Type": "multipart/mixed; boundary=\"MP_/FcylFa5_mZkAF0_yLLNLgC1\"",
        "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": "This is the last patch to add fixed-point support to the ARM backend,\nthe actual ARM-specific backend parts. It's functionally unchanged from\nthe earlier patch:\n\nhttp://gcc.gnu.org/ml/gcc-patches/2011-05/msg00837.html\n\nalthough Joseph's comments have (hopefully) all been addressed. One\nmust now configure with \"--enable-fixed-point\" to enable the\nfixed-point support.\n\nTested alongside other patches in the series. OK to apply?\n\nJulian\n\nChangeLog\n\n    gcc/\n    * configure.ac (fixed-point): Add ARM support.\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    (arm_scalar_mode_supported_p): Support fixed-point modes.\n    (arm_vector_mode_supported_p): Support vector fixed-point modes.\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 a93c41f6d4a4d4f434be897e5a3e8a16a4d4e9ad\nAuthor: Julian Brown <julian@henry8.codesourcery.com>\nDate:   Wed May 11 04:42:46 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..b19745e\n--- /dev/null\n+++ b/gcc/config/arm/arm-fixed.md\n@@ -0,0 +1,402 @@\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, simplify_gen_subreg (SImode, tmp1, DImode, 4),\n+\t\t\t  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, simplify_gen_subreg (SImode, tmp1, DImode, 4),\n+\t\t\t  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, simplify_gen_subreg (SImode, tmp1, DImode, 4),\n+\t\t\t  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 && 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_32BIT && arm_arch6\"\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 4f9c2aa..6d22ee9 100644\n--- a/gcc/config/arm/arm.c\n+++ b/gcc/config/arm/arm.c\n@@ -1068,6 +1068,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@@ -1213,6 +1256,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@@ -19333,6 +19507,12 @@ 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 (mode == QQmode || mode == HQmode || mode == SQmode\n+\t   || mode == UQQmode || mode == UHQmode || mode == USQmode\n+\t   || mode == HAmode || mode == SAmode || mode == UHAmode\n+\t   || mode == USAmode || mode == DQmode || mode == UDQmode\n+\t   || mode == DAmode || mode == UDAmode)\n+    return true;\n   else\n     return default_scalar_mode_supported_p (mode);\n }\n@@ -22454,6 +22634,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.md b/gcc/config/arm/arm.md\nindex 40ebf35..8a1dd76 100644\n--- a/gcc/config/arm/arm.md\n+++ b/gcc/config/arm/arm.md\n@@ -10751,3 +10751,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 18a548a..24e2631 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.ac b/gcc/configure.ac\nindex 5fa5d07..0cf46bb 100644\n--- a/gcc/configure.ac\n+++ b/gcc/configure.ac\n@@ -633,6 +633,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": []
}