Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/97596/?format=api
{ "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": [] }