From: R. Steve McKown Date: Wed, 9 Dec 2009 20:10:56 +0000 (-0700) Subject: Import debianized version from old svn repository. X-Git-Tag: debian/4.4.3-1tmi~7 X-Git-Url: https://oss.titaniummirror.com/gitweb?p=msp430-gcc.git;a=commitdiff_plain;h=e6ddaf27a8264cdde896aa4f78fcf67cce78e07a Import debianized version from old svn repository. Note that we did not import the svn-commit.tmp file, which shouldn't have been in the svn repository anyway. --- diff --git a/debian/README.Debian b/debian/README.Debian new file mode 100644 index 00000000..cbbc401c --- /dev/null +++ b/debian/README.Debian @@ -0,0 +1,2 @@ +This package is derived from the standard gcc package in Ubuntu, the patches +from mspgcc.sf.net, the mspgcc build script and the tinyos msp430 build script. diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 00000000..fb51f0ad --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +msp430-gcc (3.2.3-0tinyos1) hardy; urgency=low + + * Initial release, combining knowledge from mspgcc and tinyos build scripts. + + -- R. Steve McKown Fri, 22 Aug 2008 09:45:16 -0600 diff --git a/debian/control b/debian/control new file mode 100644 index 00000000..2f60d9cf --- /dev/null +++ b/debian/control @@ -0,0 +1,16 @@ +Source: msp430-gcc +Section: devel +Priority: optional +Maintainer: R. Steve McKown +Standards-Version: 3.7.2.0 +Build-Depends: dpkg-dev (>= 1.13.9), autoconf (>= 2.13), bison, flex, gettext, texinfo, binutils (>= 2.9.5.0.12), gcc (>= 4:4.2.2), dejagnu (>= 1.4.2-1.1), dpatch, file, bzip2, lsb-release, msp430-binutils (>= 2.18) + +Package: msp430-gcc +Architecture: any +Depends: msp430-binutils (>= 2.18), ${shlibs:Depends} +Suggests: +Priority: extra +Description: The GNU C/C++ compiler for msp430 target + This package provides the GNU C and C++ cross compilers for the msp430 target. + You don't need this package unless you plan to cross-compile programs for the + msp430. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 00000000..9735a7f7 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,535 @@ +This is the Debian GNU/Linux version of the GNU compiler for the msp430 target. + +This package was put together by me, R. Steve McKown , +from sources and other information obtained from the following locations: + + ftp://ftp.gnu.org/pub/gnu/gcc/ + cvs://:pserver:anonymous@mspgcc.cvs.sourceforge.net:/cvsroot/mspgcc + http://hinrg.cs.jhu.edu/git/tinyos-toolchain-packages.git + +Standard copyright information follows. + +--- + +This is the Debian GNU/Linux prepackaged version of the GCC compiler +collection, containing C, C++, Objective-C, Fortran-77, Java, Chill +and Pascal compilers, and the libstdc++ support library. + +The compilers are split into several binary packages: gcc (which has +support for C, g++ (which supports C++), gobjc (which supports +Objective C), g77 (supports Fortran77), gij, gcj (supports Java), chill +(supports Chill) and gpc (supports Pascal). A version of libstdc++-v3 +is also provided. + +Documentation is provided in the packages cpp-3.3-doc, gcc-3.3-doc, +gcj-3.3-doc, g77-3.3-doc and gpc-2.1-3.3-doc. + +This package was put together by the Debian GCC maintainers +, with sources obtained from: + + [NOTE: the current prereleases obtained from the CVS archive] + ftp://gcc.gnu.org/pub/gcc/releases/gcc-3.3.tar.bz2 + + http://gnu-pascal.de/alpha/ + +Changes: See changelog.Debian.gz + +GCC is Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, +1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +On Debian GNU/Linux systems, the complete text of the GNU General +Public License can be found in `/usr/share/common-licenses/GPL'. + +The libstdc++-v3 library is licensed under the terms of the GNU General +Public License, with this special exception: + + As a special exception, you may use this file as part of a free software + library without restriction. Specifically, if other files instantiate + templates or use macros or inline functions from this file, or you compile + this file and link it with other files to produce an executable, this + file does not by itself cause the resulting executable to be covered by + the GNU General Public License. This exception does not however + invalidate any other reasons why the executable file might be covered by + the GNU General Public License. + +gpc is copyright Free Software Foundation, and is licensed under the +GNU General Public License which on Debian GNU/Linux systems can be +found as `/usr/share/common-licenses/GPL'. + +The libgcj library is licensed under the terms of the GNU General +Public License, with this special exception: + + As a special exception, if you link this library with other files + to produce an executable, this library does not by itself cause + the resulting executable to be covered by the GNU General Public + License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU + General Public License. + +gcc/libgcc2.c (source for libgcc) has the following addition: + + In addition to the permissions in the GNU General Public License, + the Free Software Foundation gives you unlimited permission to + link the compiled version of this file into combinations with + other programs, and to distribute those combinations without any + restriction coming from the use of this file. (The General Public + License restrictions do apply in other respects; for example, they + cover modification of the file, and distribution when not linked + into a combine executable.) + +gcc/unwind-libunwind.c (source for libgcc) has the following addition: + + As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable to + be covered by the GNU General Public License. This exception does + not however invalidate any other reasons why the executable file + might be covered by the GNU General Public License. + + +The documentation is licensed under the GNU Free Documentation License +(v1.2), appended at the end of this file. + + +GNU Free Documentation License +****************************** + + Version 1.2, November 2002 + Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 0. PREAMBLE + + The purpose of this License is to make a manual, textbook, or other + functional and useful document "free" in the sense of freedom: to + assure everyone the effective freedom to copy and redistribute it, + with or without modifying it, either commercially or + noncommercially. Secondarily, this License preserves for the + author and publisher a way to get credit for their work, while not + being considered responsible for modifications made by others. + + This License is a kind of "copyleft", which means that derivative + works of the document must themselves be free in the same sense. + It complements the GNU General Public License, which is a copyleft + license designed for free software. + + We have designed this License in order to use it for manuals for + free software, because free software needs free documentation: a + free program should come with manuals providing the same freedoms + that the software does. But this License is not limited to + software manuals; it can be used for any textual work, regardless + of subject matter or whether it is published as a printed book. + We recommend this License principally for works whose purpose is + instruction or reference. + + 1. APPLICABILITY AND DEFINITIONS + + This License applies to any manual or other work, in any medium, + that contains a notice placed by the copyright holder saying it + can be distributed under the terms of this License. Such a notice + grants a world-wide, royalty-free license, unlimited in duration, + to use that work under the conditions stated herein. The + "Document", below, refers to any such manual or work. Any member + of the public is a licensee, and is addressed as "you". You + accept the license if you copy, modify or distribute the work in a + way requiring permission under copyright law. + + A "Modified Version" of the Document means any work containing the + Document or a portion of it, either copied verbatim, or with + modifications and/or translated into another language. + + A "Secondary Section" is a named appendix or a front-matter section + of the Document that deals exclusively with the relationship of the + publishers or authors of the Document to the Document's overall + subject (or to related matters) and contains nothing that could + fall directly within that overall subject. (Thus, if the Document + is in part a textbook of mathematics, a Secondary Section may not + explain any mathematics.) The relationship could be a matter of + historical connection with the subject or with related matters, or + of legal, commercial, philosophical, ethical or political position + regarding them. + + The "Invariant Sections" are certain Secondary Sections whose + titles are designated, as being those of Invariant Sections, in + the notice that says that the Document is released under this + License. If a section does not fit the above definition of + Secondary then it is not allowed to be designated as Invariant. + The Document may contain zero Invariant Sections. If the Document + does not identify any Invariant Sections then there are none. + + The "Cover Texts" are certain short passages of text that are + listed, as Front-Cover Texts or Back-Cover Texts, in the notice + that says that the Document is released under this License. A + Front-Cover Text may be at most 5 words, and a Back-Cover Text may + be at most 25 words. + + A "Transparent" copy of the Document means a machine-readable copy, + represented in a format whose specification is available to the + general public, that is suitable for revising the document + straightforwardly with generic text editors or (for images + composed of pixels) generic paint programs or (for drawings) some + widely available drawing editor, and that is suitable for input to + text formatters or for automatic translation to a variety of + formats suitable for input to text formatters. A copy made in an + otherwise Transparent file format whose markup, or absence of + markup, has been arranged to thwart or discourage subsequent + modification by readers is not Transparent. An image format is + not Transparent if used for any substantial amount of text. A + copy that is not "Transparent" is called "Opaque". + + Examples of suitable formats for Transparent copies include plain + ASCII without markup, Texinfo input format, LaTeX input format, + SGML or XML using a publicly available DTD, and + standard-conforming simple HTML, PostScript or PDF designed for + human modification. Examples of transparent image formats include + PNG, XCF and JPG. Opaque formats include proprietary formats that + can be read and edited only by proprietary word processors, SGML or + XML for which the DTD and/or processing tools are not generally + available, and the machine-generated HTML, PostScript or PDF + produced by some word processors for output purposes only. + + The "Title Page" means, for a printed book, the title page itself, + plus such following pages as are needed to hold, legibly, the + material this License requires to appear in the title page. For + works in formats which do not have any title page as such, "Title + Page" means the text near the most prominent appearance of the + work's title, preceding the beginning of the body of the text. + + A section "Entitled XYZ" means a named subunit of the Document + whose title either is precisely XYZ or contains XYZ in parentheses + following text that translates XYZ in another language. (Here XYZ + stands for a specific section name mentioned below, such as + "Acknowledgements", "Dedications", "Endorsements", or "History".) + To "Preserve the Title" of such a section when you modify the + Document means that it remains a section "Entitled XYZ" according + to this definition. + + The Document may include Warranty Disclaimers next to the notice + which states that this License applies to the Document. These + Warranty Disclaimers are considered to be included by reference in + this License, but only as regards disclaiming warranties: any other + implication that these Warranty Disclaimers may have is void and + has no effect on the meaning of this License. + + 2. VERBATIM COPYING + + You may copy and distribute the Document in any medium, either + commercially or noncommercially, provided that this License, the + copyright notices, and the license notice saying this License + applies to the Document are reproduced in all copies, and that you + add no other conditions whatsoever to those of this License. You + may not use technical measures to obstruct or control the reading + or further copying of the copies you make or distribute. However, + you may accept compensation in exchange for copies. If you + distribute a large enough number of copies you must also follow + the conditions in section 3. + + You may also lend copies, under the same conditions stated above, + and you may publicly display copies. + + 3. COPYING IN QUANTITY + + If you publish printed copies (or copies in media that commonly + have printed covers) of the Document, numbering more than 100, and + the Document's license notice requires Cover Texts, you must + enclose the copies in covers that carry, clearly and legibly, all + these Cover Texts: Front-Cover Texts on the front cover, and + Back-Cover Texts on the back cover. Both covers must also clearly + and legibly identify you as the publisher of these copies. The + front cover must present the full title with all words of the + title equally prominent and visible. You may add other material + on the covers in addition. Copying with changes limited to the + covers, as long as they preserve the title of the Document and + satisfy these conditions, can be treated as verbatim copying in + other respects. + + If the required texts for either cover are too voluminous to fit + legibly, you should put the first ones listed (as many as fit + reasonably) on the actual cover, and continue the rest onto + adjacent pages. + + If you publish or distribute Opaque copies of the Document + numbering more than 100, you must either include a + machine-readable Transparent copy along with each Opaque copy, or + state in or with each Opaque copy a computer-network location from + which the general network-using public has access to download + using public-standard network protocols a complete Transparent + copy of the Document, free of added material. If you use the + latter option, you must take reasonably prudent steps, when you + begin distribution of Opaque copies in quantity, to ensure that + this Transparent copy will remain thus accessible at the stated + location until at least one year after the last time you + distribute an Opaque copy (directly or through your agents or + retailers) of that edition to the public. + + It is requested, but not required, that you contact the authors of + the Document well before redistributing any large number of + copies, to give them a chance to provide you with an updated + version of the Document. + + 4. MODIFICATIONS + + You may copy and distribute a Modified Version of the Document + under the conditions of sections 2 and 3 above, provided that you + release the Modified Version under precisely this License, with + the Modified Version filling the role of the Document, thus + licensing distribution and modification of the Modified Version to + whoever possesses a copy of it. In addition, you must do these + things in the Modified Version: + + A. Use in the Title Page (and on the covers, if any) a title + distinct from that of the Document, and from those of + previous versions (which should, if there were any, be listed + in the History section of the Document). You may use the + same title as a previous version if the original publisher of + that version gives permission. + + B. List on the Title Page, as authors, one or more persons or + entities responsible for authorship of the modifications in + the Modified Version, together with at least five of the + principal authors of the Document (all of its principal + authors, if it has fewer than five), unless they release you + from this requirement. + + C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. + + D. Preserve all the copyright notices of the Document. + + E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. + + F. Include, immediately after the copyright notices, a license + notice giving the public permission to use the Modified + Version under the terms of this License, in the form shown in + the Addendum below. + + G. Preserve in that license notice the full lists of Invariant + Sections and required Cover Texts given in the Document's + license notice. + + H. Include an unaltered copy of this License. + + I. Preserve the section Entitled "History", Preserve its Title, + and add to it an item stating at least the title, year, new + authors, and publisher of the Modified Version as given on + the Title Page. If there is no section Entitled "History" in + the Document, create one stating the title, year, authors, + and publisher of the Document as given on its Title Page, + then add an item describing the Modified Version as stated in + the previous sentence. + + J. Preserve the network location, if any, given in the Document + for public access to a Transparent copy of the Document, and + likewise the network locations given in the Document for + previous versions it was based on. These may be placed in + the "History" section. You may omit a network location for a + work that was published at least four years before the + Document itself, or if the original publisher of the version + it refers to gives permission. + + K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the + section all the substance and tone of each of the contributor + acknowledgements and/or dedications given therein. + + L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section + titles. + + M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. + + N. Do not retitle any existing section to be Entitled + "Endorsements" or to conflict in title with any Invariant + Section. + + O. Preserve any Warranty Disclaimers. + + If the Modified Version includes new front-matter sections or + appendices that qualify as Secondary Sections and contain no + material copied from the Document, you may at your option + designate some or all of these sections as invariant. To do this, + add their titles to the list of Invariant Sections in the Modified + Version's license notice. These titles must be distinct from any + other section titles. + + You may add a section Entitled "Endorsements", provided it contains + nothing but endorsements of your Modified Version by various + parties--for example, statements of peer review or that the text + has been approved by an organization as the authoritative + definition of a standard. + + You may add a passage of up to five words as a Front-Cover Text, + and a passage of up to 25 words as a Back-Cover Text, to the end + of the list of Cover Texts in the Modified Version. Only one + passage of Front-Cover Text and one of Back-Cover Text may be + added by (or through arrangements made by) any one entity. If the + Document already includes a cover text for the same cover, + previously added by you or by arrangement made by the same entity + you are acting on behalf of, you may not add another; but you may + replace the old one, on explicit permission from the previous + publisher that added the old one. + + The author(s) and publisher(s) of the Document do not by this + License give permission to use their names for publicity for or to + assert or imply endorsement of any Modified Version. + + 5. COMBINING DOCUMENTS + + You may combine the Document with other documents released under + this License, under the terms defined in section 4 above for + modified versions, provided that you include in the combination + all of the Invariant Sections of all of the original documents, + unmodified, and list them all as Invariant Sections of your + combined work in its license notice, and that you preserve all + their Warranty Disclaimers. + + The combined work need only contain one copy of this License, and + multiple identical Invariant Sections may be replaced with a single + copy. If there are multiple Invariant Sections with the same name + but different contents, make the title of each such section unique + by adding at the end of it, in parentheses, the name of the + original author or publisher of that section if known, or else a + unique number. Make the same adjustment to the section titles in + the list of Invariant Sections in the license notice of the + combined work. + + In the combination, you must combine any sections Entitled + "History" in the various original documents, forming one section + Entitled "History"; likewise combine any sections Entitled + "Acknowledgements", and any sections Entitled "Dedications". You + must delete all sections Entitled "Endorsements." + + 6. COLLECTIONS OF DOCUMENTS + + You may make a collection consisting of the Document and other + documents released under this License, and replace the individual + copies of this License in the various documents with a single copy + that is included in the collection, provided that you follow the + rules of this License for verbatim copying of each of the + documents in all other respects. + + You may extract a single document from such a collection, and + distribute it individually under this License, provided you insert + a copy of this License into the extracted document, and follow + this License in all other respects regarding verbatim copying of + that document. + + 7. AGGREGATION WITH INDEPENDENT WORKS + + A compilation of the Document or its derivatives with other + separate and independent documents or works, in or on a volume of + a storage or distribution medium, is called an "aggregate" if the + copyright resulting from the compilation is not used to limit the + legal rights of the compilation's users beyond what the individual + works permit. When the Document is included an aggregate, this + License does not apply to the other works in the aggregate which + are not themselves derivative works of the Document. + + If the Cover Text requirement of section 3 is applicable to these + copies of the Document, then if the Document is less than one half + of the entire aggregate, the Document's Cover Texts may be placed + on covers that bracket the Document within the aggregate, or the + electronic equivalent of covers if the Document is in electronic + form. Otherwise they must appear on printed covers that bracket + the whole aggregate. + + 8. TRANSLATION + + Translation is considered a kind of modification, so you may + distribute translations of the Document under the terms of section + 4. Replacing Invariant Sections with translations requires special + permission from their copyright holders, but you may include + translations of some or all Invariant Sections in addition to the + original versions of these Invariant Sections. You may include a + translation of this License, and all the license notices in the + Document, and any Warrany Disclaimers, provided that you also + include the original English version of this License and the + original versions of those notices and disclaimers. In case of a + disagreement between the translation and the original version of + this License or a notice or disclaimer, the original version will + prevail. + + If a section in the Document is Entitled "Acknowledgements", + "Dedications", or "History", the requirement (section 4) to + Preserve its Title (section 1) will typically require changing the + actual title. + + 9. TERMINATION + + You may not copy, modify, sublicense, or distribute the Document + except as expressly provided for under this License. Any other + attempt to copy, modify, sublicense or distribute the Document is + void, and will automatically terminate your rights under this + License. However, parties who have received copies, or rights, + from you under this License will not have their licenses + terminated so long as such parties remain in full compliance. + + 10. FUTURE REVISIONS OF THIS LICENSE + + The Free Software Foundation may publish new, revised versions of + the GNU Free Documentation License from time to time. Such new + versions will be similar in spirit to the present version, but may + differ in detail to address new problems or concerns. See + `http://www.gnu.org/copyleft/'. + + Each version of the License is given a distinguishing version + number. If the Document specifies that a particular numbered + version of this License "or any later version" applies to it, you + have the option of following the terms and conditions either of + that specified version or of any later version that has been + published (not as a draft) by the Free Software Foundation. If + the Document does not specify a version number of this License, + you may choose any version ever published (not as a draft) by the + Free Software Foundation. + +ADDENDUM: How to use this License for your documents +==================================================== + + To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and license +notices just after the title page: + + Copyright (C) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled ``GNU + Free Documentation License''. + + If you have Invariant Sections, Front-Cover Texts and Back-Cover +Texts, replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with + the Front-Cover Texts being LIST, and with the Back-Cover Texts + being LIST. + + If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + + If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, to +permit their use in free software. diff --git a/debian/gcc.postinst b/debian/gcc.postinst new file mode 100644 index 00000000..9977c686 --- /dev/null +++ b/debian/gcc.postinst @@ -0,0 +1,7 @@ +#! /bin/sh + +set -e + +if [ "$1" = "configure" ]; then + ldconfig +fi diff --git a/debian/gcc.postrm b/debian/gcc.postrm new file mode 100644 index 00000000..33a236e9 --- /dev/null +++ b/debian/gcc.postrm @@ -0,0 +1,7 @@ +#! /bin/sh + +set -e + +if [ "$1" = "remove" ]; then + ldconfig +fi diff --git a/debian/gcc.shlibs b/debian/gcc.shlibs new file mode 100644 index 00000000..e69de29b diff --git a/debian/patches/002-mspgcc-3.2.3-20080819.dpatch b/debian/patches/002-mspgcc-3.2.3-20080819.dpatch new file mode 100755 index 00000000..5e93a73c --- /dev/null +++ b/debian/patches/002-mspgcc-3.2.3-20080819.dpatch @@ -0,0 +1,19291 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 001-mspgcc-3.2.3-20080819.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Patch derived from mspgcc project gcc/3.3 directory, CVS 20080819 + +@DPATCH@ + +diff -urN -x CVS gcc-3.2.3.orig/configure.in gcc-3.2.3/configure.in +--- gcc-3.2.3.orig/configure.in 2002-07-08 04:00:57.000000000 -0600 ++++ gcc-3.2.3/configure.in 2008-08-22 09:17:00.000000000 -0600 +@@ -907,6 +907,9 @@ + target_configdirs="${target_configdirs} target-bsp target-libstub target-cygmon" + fi + ;; ++ msp430-*-*) ++ noconfigdirs="$noconfigdirs target-libiberty ${libstdcxx_version} ${libgcj}" ++ ;; + powerpc-*-aix*) + # copied from rs6000-*-* entry + # The configure and build of ld are currently disabled because +diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/libgcc.c gcc-3.2.3/gcc/config/msp430/libgcc.c +--- gcc-3.2.3.orig/gcc/config/msp430/libgcc.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-3.2.3/gcc/config/msp430/libgcc.c 2008-08-22 09:17:00.000000000 -0600 +@@ -0,0 +1,74 @@ ++ ++/* ++ Stages of division: ++ 0. Clear carry flag, et all. ++ 1. Shift divident into divider. ++ Shift carry bit into divident. ++ 2. Check if the remainder >= divider ++ 3. if yes, remainder -= divider ++ this MUST set carry flag ++ 4. if not, clear carry flag ++ ++ repeat from 1 sizeof(type) times ++ */ ++ ++ ++typedef unsigned long __XX; ++ ++__XX ++__udivmodXI3 ( __XX a, __XX b) ++{ ++ __XX al = a; // quotant ++ __XX ah = 0; // reminder ++ __XX tmpf; ++ int i; ++ ++ for (i = sizeof(__XX)*8; i > 0; i--) ++ { ++ ah = (ah << 1) | (al >> (sizeof(__XX)*8-1) ); ++ tmpf = (ah >= b) ? 1 : 0; ++ ah -= ((tmpf) ? b : 0); ++ al = (al << 1) | tmpf; ++ } ++ ++ return al; // for __udivXi3 ++ return ah; // for __umodXi3 ++} ++ ++/* Signed: */ ++ ++__XX ++__divmodXI3 ( __XX a, __XX b) ++{ ++ unsigned at = abs(a); ++ unsigned bt = abs(b); ++ unsigned al, ah; ++ ++ __udivmodXI3 (at, bt); ++ ++ // now we get al, ah ++ ++ if (a < 0) ++ ah = -ah, al = -al; ++ ++ if (b < 0) ++ al = -al; ++ ++ return al; ++ return ah; ++} ++ ++#if 1 ++int main() ++{ ++ __XX a,b, r; ++ ++ a = 100; ++ b = 0; ++ r = __udivmodXI3(a,b); ++ printf("R=%d\n",r); ++ ++} ++#endif ++ ++ +diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/libgcc.S gcc-3.2.3/gcc/config/msp430/libgcc.S +--- gcc-3.2.3.orig/gcc/config/msp430/libgcc.S 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-3.2.3/gcc/config/msp430/libgcc.S 2008-08-22 09:17:00.000000000 -0600 +@@ -0,0 +1,1326 @@ ++/* -*- Mode: Asm -*- */ ++ ++ ++ .section .text.libgcc, "ax", @progbits ++ ++#if defined (L_cmpdi2) ++ ++ .global __cmpdi2 ++ .func __cmpdi2 ++__cmpdi2: ++ sub 2(r1), r12 ; a = a-b; ++ subc 4(r1), r13 ++ subc 6(r1), r14 ++ subc 8(r1), r15 ++ ++ tst r15 ; c<0 ? return -1; ++ jge .L2 ++ ++ mov #-1, r15 ; yes, return -1 ++ ret ++.L2: ++ bis r12, r14 ; check if zero ++ bis r13, r15 ++ bis r14, r15 ++ tst r15 ++ jeq .L4 ; test result or or'ing all nibbles ++ ++ mov #1, r15 ; no, positive, return 1 ++ ret ++.L4: ++ mov #0, r15 ; return 0 ++ ret ++.endfunc ++#endif ++ ++#if defined (L_cmpsf2) ++ .global __cmpsf2 ++ .func __cmpsf2 ++__cmpsf2: ++/* prologue: frame size = 0; addenum 0; alloca:0, varargs:0 , fpr:0*/ ++.L__FrameSize___cmpsf2=0x0 ++.L__FrameOffset___cmpsf2=0x4 ++/* prologue end (size=2) */ ++ cmp r12, r14 ; 11 cmpsi [length = 3] ++ jne .L2 ++ cmp r13, r15 ++ jne .L2 ; 12 bne [length = 1] ++ mov #llo(0), r15 ; 15 *movhi3/7 [length = 1] ++ ret ++.L2: ++ tst r15 ; 20 tstsi [length = 1] ++ jge .L3 ; 21 bge [length = 1] ++ tst r13 ; 22 tstsi [length = 1] ++ jge .L3 ; 23 bge [length = 1] ++ xor #lhi(-2147483648), r15 ; 27 *xorsi3_3 [length = 2] ++ xor #lhi(-2147483648), r13 ; 29 *xorsi3_3 [length = 2] ++.L3: ++ sub r14, r12 ; 64 *subsi3_3 [length = 2] ++ subc r15, r13 ++ jge .L4 ; 33 bge [length = 1] ++ mov #llo(1), r15 ; 36 *movhi3/7 [length = 1] ++ ret ++.L4: ++ mov #llo(-1), r15 ; 43 *movhi3/7 [length = 1] ++.L1: ++/* epilogue: frame size=0 */ ++ ret ++/* epilogue end (size=3) */ ++/* function __cmpsf2 size 25 (20) */ ++ ++.endfunc ++ ++#endif ++ ++ ++ ++/******************************************************* ++ Multiplication 8 x 8 ++*******************************************************/ ++#if defined (L_mulqi3) ++/* ++ a = reg:qi 10 clobber ++ b = reg:qi 12 clobber ++ res = reg:qi 14 ++*/ ++ ++ .global __mulqi3 ++ .func __mulqi3 ++__mulqi3: ++ clr r14 ++.L__mulqiloop: ++ tst.b r10 ++ jz .L__mulqiexit ++ clrc ++ rrc.b r12 ++ jnc +2 ++ add.b r10, r14 ++ rla.b r10 ++ tst.b r12 ++ jne .L__mulqiloop ++.L__mulqiexit: ++ ret ++ .endfunc ++#endif /* defined (L_mulqi3) */ ++ ++ ++#if defined (L_mulqihi3) ++ .global __mulqihi3 ++ .func __mulqihi3 ++__mulqihi3: ++ sxt r10 ++ sxt r12 ++ br #__mulhi3 ++.endfunc ++#endif /* defined (L_mulqihi3) */ ++ ++#if defined (L_umulqihi3) ++ .global __umulqihi3 ++ .func __umulqihi3 ++__umulqihi3: ++ and.b #-1, r10 ++ and.b #-1, r12 ++ br #__mulhi3 ++ .endfunc ++#endif /* defined (L_umulqihi3) */ ++ ++/******************************************************* ++ Multiplication 16 x 16 ++*******************************************************/ ++#if defined (L_mulhi3) ++/* ++ a = reg:hi 10 clobber ++ b = reg:hi 12 clobber ++ res = reg:hi 14 ++*/ ++ ++ .global __mulhi3 ++ .func __mulhi3 ++__mulhi3: ++ clr r14 ++.L__mulhiloop: ++ tst r10 ++ jz .L__mulhiexit ++ clrc ++ rrc r12 ++ jnc +2 ++ add r10, r14 ++ rla r10 ++ tst r12 ++ jne .L__mulhiloop ++.L__mulhiexit: ++ ret ++ .endfunc ++#endif /* defined (L_mulhi3) */ ++ ++#if defined (L_mulhisi3) ++/* clobber r11, r13 */ ++ .global __mulhisi3 ++ .func __mulhisi3 ++__mulhisi3: ++ br #__mulsi3 ++ .endfunc ++#endif /* defined (L_mulhisi3) */ ++ ++#if defined (L_umulhisi3) ++ .global __umulhisi3 ++ .func __umulhisi3 ++__umulhisi3: ++ br #__mulsi3 ++ .endfunc ++#endif /* defined (L_umulhisi3) */ ++ ++#if defined (L_mulsi3) ++/******************************************************* ++ Multiplication 32 x 32 ++*******************************************************/ ++/* ++res = a*b ++ a - reg:SI 10 clobber ++ b - reg:SI 12 clobber ++ res - reg: SI 14 ++*/ ++ .global __mulsi3 ++ .func __mulsi3 ++ ++__mulsi3: ++ clr r14 ++ clr r15 ++ jmp .L__mulsi3st ++.L__mulsi3loop: ++ clrc ++ rrc r13 ; b >>= 1 ++ rrc r12 ++ jnc +4 ; ++ add r10, r14 ; res = res + a ++ addc r11, r15 ++ rla r10 ++ rlc r11 ; a <<= 1 ++.L__mulsi3st: ++ tst r12 ; if b ne 0 goto L__mulsi3loop ++ jne .L__mulsi3loop ++ tst r13 ++ jne .L__mulsi3loop ++ ret ++ .endfunc ++ ++#endif ++ ++#if defined (L_mulsi3hw) ++ ++__MPY=0x130 ++__MPYS=0x132 ++__MAC=0x134 ++__MACS=0x136 ++__OP2=0x138 ++__RESLO=0x13a ++__RESHI=0x13c ++__SUMEXT=0x13e ++ ++ .global __umulsi3hw ++ .func __umulsi3hw ++__umulsi3hw: ++ mov r12, &__MPY ++ mov r10, &__OP2 ++ mov r12, &__MAC ++ mov &__RESLO, r14 ++ mov &__RESHI, &__RESLO ++ mov r11, &__OP2 ++ mov r13, &__MAC ++ mov r10, &__OP2 ++ mov &__RESLO, r15 ++ ret ++.endfunc ++ ++#endif ++ ++ ++/******************************************************* ++ Division 8 / 8 => (result + remainder) ++*******************************************************/ ++ ++#define r_rem r14 /* remainder */ ++#define r_arg1 r12 /* dividend, quotient */ ++#define r_arg2 r10 /* divisor */ ++#define r_cnt r11 /* loop count */ ++#define r_tmp r13 /* save carry flag */ ++ ++ ++#if defined (L_udivmodqi4) ++ .global __udivmodqi4 ++ .func __udivmodqi4 ++__udivmodqi4: ++ xor.b r_rem, r_rem ; clear reminder and carry ++ mov.b #9, r_cnt ++ jmp .L__udivmodqi4_ep ++.L__udivmodqi4_loop: ++ rrc r_tmp ; restore carry bit ++ rlc.b r_rem ++ cmp.b r_arg2, r_rem ++ jlo .L__udivmodqi4_ep ++ sub.b r_arg2, r_rem ; FIXME: will this clobber carry ? ++.L__udivmodqi4_ep: ++ rlc.b r_arg1 ; shift divident ++ rlc r_tmp ; save carry bit ++ dec.b r_cnt ; this clobbers C bit. ++ jnz .L__udivmodqi4_loop ++ ret ++ .endfunc ++#endif /* defined (L_udivmodqi4) */ ++ ++ ++#if defined (L_divmodqi4) ++ .global __divmodqi4 ++ .func __divmodqi4 ++__divmodqi4: ++ clr r_tmp ++ bit #0x80, r_arg1 ; save divident sign ++ jnc .L__divmodqi4arg1pos ++ inv.b r_arg1 ; negate ++ inc.b r_arg1 ++ bis #4, r_tmp ++ ++.L__divmodqi4arg1pos: ++ bit #0x80, r_arg2 ; check divisor sign ++ jnc .L__divmodqi4arg2pos ++ inv.b r_arg2 ; negate ++ inc.b r_arg2 ++ bis #8, r_tmp ++ ++.L__divmodqi4arg2pos: ++ ++ call #__udivmodqi4 ; do unsigned division ++ rrc r_tmp ; restore carry and sign bits ++ ++ bit #4, r_tmp ; is divident < 0 ? ++ jnc .L__divmodqi4rem ; no. skip ++ inv.b r_rem ; negate remainder ++ inc.b r_rem ++ ++;; bit #8, r_tmp ++;; jc .L__divmodqi4end ++ inv.b r_arg1 ; negate quotient ++ inc.b r_arg1 ++ ++.L__divmodqi4rem: ++ bit #8, r_tmp ++ jnc .L__divmodqi4end ++ inv.b r_arg1 ++ inc.b r_arg1 ++ ++.L__divmodqi4end: ++ ret ++ ++ .endfunc ++#endif /* defined (L_divmodqi4) */ ++ ++#undef r_rem ++#undef r_arg1 ++#undef r_arg2 ++#undef r_cnt ++#undef r_tmp ++ ++ ++/******************************************************* ++ Division 16 / 16 => (result + remainder) ++*******************************************************/ ++ ++#define r_rem r14 /* remainder */ ++#define r_arg1 r12 /* dividend, quotient */ ++#define r_arg2 r10 /* divisor */ ++#define r_cnt r11 /* loop count */ ++#define r_tmp r13 ++ ++ ++#if defined (L_udivmodhi4) ++ .global __udivmodhi4 ++ .func __udivmodhi4 ++__udivmodhi4: ++ xor r_rem, r_rem ; clear reminder and carry ++ mov #17, r_cnt ++ jmp .L__udivmodhi4_ep ++.L__udivmodhi4_loop: ++ rrc r_tmp ; restore carry bit ++ rlc r_rem ++ cmp r_arg2, r_rem ++ jlo .L__udivmodhi4_ep ++ sub r_arg2, r_rem ++.L__udivmodhi4_ep: ++ rlc r_arg1 ++ rlc r_tmp ; save carry bit ++ dec r_cnt ; this clobbers C bit. ++ jnz .L__udivmodhi4_loop ++ ret ++ .endfunc ++#endif /* defined (L_udivmodhi4) */ ++ ++ ++#if defined (L_divmodhi4) ++#define r_rem r14 /* remainder */ ++#define r_arg1 r12 /* dividend, quotient */ ++#define r_arg2 r10 /* divisor */ ++#define r_cnt r11 /* loop count */ ++#define r_tmp r13 ++ ++ ++ .global __divmodhi4 ++ .func __divmodhi4 ++__divmodhi4: ++ clr r_tmp ; clear reg is cheaper than clr 2 bits. ++ bit #0x8000, r_arg1 ; save divident sign ++ jnc .L__divmodhi4arg1pos ++ inv r_arg1 ; negate ++ inc r_arg1 ++ bis #4, r_tmp ++ ++.L__divmodhi4arg1pos: ++ bit #0x8000, r_arg2 ; check divisor sign ++ jnc .L__divmodhi4arg2pos ++ inv r_arg2 ; negate ++ inc r_arg2 ++ bis #8, r_tmp ++ ++.L__divmodhi4arg2pos: ++ call #__udivmodhi4 ; do unsigned division ++ rrc r_tmp ; restore carry and sign bits ++ ++ bit #4, r_tmp ; is divident < 0 ? ++ jnc .L__divmodhi4rem ; no. skip ++ inv r_rem ; negate remainder ++ inc r_rem ++ ++;; bit #8, r_tmp ++;; jc .L__divmodhi4end ++ inv r_arg1 ; negate quotient ++ inc r_arg1 ++ ++.L__divmodhi4rem: ++ bit #8, r_tmp ++ jnc .L__divmodhi4end ++ inv r_arg1 ++ inc r_arg1 ++ ++.L__divmodhi4end: ++ ret ++ .endfunc ++#endif /* defined (L_divmodhi4) */ ++ ++#undef r_rem ++#undef r_arg1 ++#undef r_arg2 ++#undef r_cnt ++#undef r_tmp ++ ++/******************************************************* ++ Division 32 / 32 => (result + remainder) ++*******************************************************/ ++ ++#if defined (L_udivmodsi4) ++ ++#define r_remh r15 ++#define r_reml r14 /* remainder */ ++#define r_arg1h r13 ++#define r_arg1l r12 /* dividend, quotient */ ++#define r_arg2h r11 ++#define r_arg2l r10 /* divisor */ ++#define r_cnt r9 /* loop count */ ++#define r_tmp r8 ++ ++ .global __udivmodsi4 ++ .func __udivmodsi4 ++__udivmodsi4: ++ xor r_remh, r_remh ; clear reminder and carry ++ xor r_reml, r_reml ++ mov #33, r_cnt ++ jmp .L__udivmodsi4_ep ++.L__udivmodsi4_loop: ++ rrc r_tmp ; restore carry bit ++ rlc r_reml ++ rlc r_remh ++ ++ cmp r_arg2h, r_remh ; is reminder < divisor ? ++ jlo .L__udivmodsi4_ep ; yes, skip correction ++ jne +4 ++ ; they equal. check LSBytes ++ cmp r_arg2l, r_reml ++ jlo .L__udivmodsi4_ep ; is reminder still < divisor ? ++ ++ sub r_arg2l, r_reml ; adjust reminder ++ subc r_arg2h, r_remh ++ ++.L__udivmodsi4_ep: ++ rlc r_arg1l ++ rlc r_arg1h ++ rlc r_tmp ++ dec r_cnt ; this clobbers C bit. ++ jnz .L__udivmodsi4_loop ++ ret ++ .endfunc ++ ++#undef r_remh ++#undef r_reml ++#undef r_arg1h ++#undef r_arg1l ++#undef r_arg2h ++#undef r_arg2l ++ ++#undef r_cnt ++#undef r_tmp ++ ++#endif /* defined (L_udivmodsi4) */ ++ ++ ++#if defined (L_divmodsi4) ++#define r_remh r15 ++#define r_reml r14 /* remainder */ ++#define r_arg1h r13 ++#define r_arg1l r12 /* dividend, quotient */ ++#define r_arg2h r11 ++#define r_arg2l r10 /* divisor */ ++#define r_cnt r9 /* loop count */ ++#define r_tmp r8 ++ ++ .global __divmodsi4 ++ .func __divmodsi4 ++__divmodsi4: ++ clr r_tmp ; clear reg is cheaper than clr 2 bits. ++ bit #0x8000, r_arg1h ; save divident sign ++ jz .L__divmodsi4arg1pos ++ inv r_arg1h ; negate ++ inv r_arg1l ++ inc r_arg1l ++ adc r_arg1h ++ bis #4, r_tmp ++ ++.L__divmodsi4arg1pos: ++ bit #0x8000, r_arg2h ; check divisor sign ++ jz .L__divmodsi4arg2pos ++ inv r_arg2h ; negate ++ inv r_arg2l ++ inc r_arg2l ++ adc r_arg2h ++ bis #8, r_tmp ; save divisor sign ++ ++.L__divmodsi4arg2pos: ++ ++ call #__udivmodsi4 ; do unsigned division ++ rrc r_tmp ; restore carry and sign bits ++ ++ bit #4, r_tmp ; is divident < 0 ? ++ jz .L__divmodsi4rem ; no. skip ++ inv r_reml ; negate remainder ++ inv r_remh ++ inc r_reml ++ adc r_remh ++ ++;; bit #8, r_tmp ++;; jc .L__divmodsi4end ++ inv r_arg1l ; negate quotient ++ inv r_arg1h ++ inc r_arg1l ++ adc r_arg1h ++ ++.L__divmodsi4rem: ++ bit #8, r_tmp ++ jz .L__divmodsi4end ++ inv r_arg1l ++ inv r_arg1h ++ inc r_arg1l ++ adc r_arg1h ++ ++.L__divmodsi4end: ++ ret ++ .endfunc ++ ++#undef r_remh ++#undef r_reml ++#undef r_arg1h ++#undef r_arg1l ++#undef r_arg2h ++#undef r_arg2l ++ ++#undef r_cnt ++#undef r_tmp ++ ++#endif /* defined (L_divmodsi4) */ ++ ++ ++/******* CRT support functions *********/ ++ ++#if defined(L_reset_vector__) ++/***************************************************************** ++ * Program starts here. ++ * overwriting this label in the user program ++ * causes removing all strtup code except __do_global_ctors ++ *****************************************************************/ ++ .section .init0, "ax", @progbits ++ ++ .global _reset_vector__ ++ .weak _reset_vector__ ++ ++ .func _reset_vector__ ++ ++_reset_vector__: ++ ++ /* link following functions if library _reset_vector__ used */ ++ ++; actualy stack initialized in main() prologue, so don't link __init_stack ++; .global __init_stack ++ ++ .global __low_level_init ++ .global __do_copy_data ++ .global __do_clear_bss ++ .global __jump_to_main ++ ++ .endfunc ++#endif /* defined(L_reset_vector__) */ ++ ++#if defined(L__init_stack) ++/***************************************************************** ++ * Set stack pointer ++ * can be overwriten ++ *****************************************************************/ ++ .section .init2, "ax", @progbits ++ ++ .global __init_stack ++ .weak __init_stack ++ ++ .func __init_stack ++ ++set_stack_pointer: ++ mov #__stack, r1 ++ ++ .endfunc ++#endif ++ ++#if defined(L__low_level_init) ++/***************************************************************** ++ * Initialize peripherial, particularly disable watchdog ++ * can be overwriten ++ *****************************************************************/ ++ .section .init3, "ax", @progbits ++ ++ .global __low_level_init ++ .weak __low_level_init ++ ++ .func __low_level_init ++ ++__low_level_init: ++ mov #0x5a80, &0x120 ++ ++ .endfunc ++#endif ++ ++#if defined(L_copy_data) ++/***************************************************************** ++ * Initialize data: copy data ++ * from __data_load_start ( = _etext) to __data_start ++ * can be overwriten ++ *****************************************************************/ ++ .section .init4, "ax", @progbits ++ ++ .global __do_copy_data ++ .weak __do_copy_data ++ ++ .func __do_copy_data ++ ++__do_copy_data: ++ mov #__data_size, r15 ++ tst r15 ++ jz .L__copy_data_end ++.L__copy_data_loop: ++ decd r15 ++ mov.w __data_load_start(r15), __data_start(r15) ; data section is word-aligned, so word transfer is acceptable ++ jne .L__copy_data_loop ++.L__copy_data_end: ++ ++ .endfunc ++#endif /* defined(L_copy_data) */ ++ ++#if defined(L_clear_bss) ++/***************************************************************** ++ * Initialize data: clear .bss ++ * can be overwriten ++ *****************************************************************/ ++ .section .init4, "ax", @progbits ++ ++ .global __do_clear_bss ++ .weak __do_clear_bss ++ ++ .func __do_clear_bss ++ ++__do_clear_bss: ++ mov #__bss_size, r15 ++ tst r15 ++ jz .L__clear_bss_end ++.L__clear_bss_loop: ++ dec r15 ++ clr.b __bss_start(r15) ++ jne .L__clear_bss_loop ++.L__clear_bss_end: ++ ++ .endfunc ++#endif /* defined(L_clear_bss) */ ++ ++#if defined(L_ctors) ++/***************************************************************** ++ * Call C++ global and static objects constructors ++ * can be overwriten ++ *****************************************************************/ ++ .section .init6, "ax", @progbits ++ .global __do_global_ctors ++ .weak __do_global_ctors ++ ++ .func __do_global_ctors ++ .global __init_stack ; stack has to be set before constructors calling ++ ++ ++__do_global_ctors: ++ mov #__ctors_start, r11 ++ mov #__ctors_end, r10 ++.L__ctors_loop: ++ call @r11+ ; call constructor ++ cmp r10, r11 ++ jne .L__ctors_loop ++ ++ .endfunc ++#endif ++ ++#if defined(L__jump_to_main) ++/***************************************************************** ++ * jump to main. ++ * can be overwriten ++ *****************************************************************/ ++ .section .init9, "ax", @progbits ++ ++ .global __jump_to_main ++ .weak __jump_to_main ++ ++ .func __jump_to_main ++ ++__jump_to_main: ++ br #main ++ .endfunc ++#endif ++ ++#if defined(L__stop_progExec__) ++/***************************************************************** ++ * return from main. ++ * can be overwriten ++ *****************************************************************/ ++ .section .fini9, "ax", @progbits ++ .global __stop_progExec__ ++ .weak __stop_progExec__ ++ ++ .func __stop_progExec__ ++ ++__stop_progExec__: ++ ++ .endfunc ++#endif ++ ++#if defined(L_dtors) ++/***************************************************************** ++ * Call C++ global and static objects destructors ++ * can be overwriten ++ *****************************************************************/ ++ .section .fini6,"ax",@progbits ++ .global __do_global_dtors ++ .weak __do_global_dtors ++ ++ .func _dtors ++ ++__do_global_dtors: ++ mov #__dtors_start, r11 ++ mov #__dtors_end, r10 ++.L__dtors_loop: ++ call @r11+ ++ cmp r10, r11 ++ jne .L__dtors_loop ++ ++ .endfunc ++#endif ++ ++#if defined(L__stop_progExec__) ++/***************************************************************** ++ * endless loop ++ * can be overwriten ++ *****************************************************************/ ++ .section .fini0, "ax", @progbits ++ ++ .func _endless_loop__ ++1: ++ jmp 1b ++ ++ .endfunc ++#endif ++ ++/********* PROLOGE / EPILOGUE aux routines ******************/ ++#if defined (L__prologue_saver) ++ .global __prologue_saver ++ .func __prologue_saver ++__prologue_saver: ++ mov r4, 0(r1) ++ mov r5, 2(r1) ++ mov r6, 4(r1) ++ mov r7, 6(r1) ++ mov r8, 8(r1) ++ mov r9, 10(r1) ++ mov r10, 12(r1) ++ mov r11, 14(r1) ++ br r12 ; now jump to the function body ++.endfunc ++ ++#endif ++ ++ ++#if defined (L__epilogue_restorer) ++ .global __epilogue_restorer ++ .func __epilogue_restorer ++__epilogue_restorer: ++ pop r4 ++ pop r5 ++ pop r6 ++ pop r7 ++ pop r8 ++ pop r9 ++ pop r10 ++ pop r11 ++ ret ++.endfunc ++ ++#endif ++ ++ ++#if defined (L__epilogue_restorer_intr) ++ .global __epilogue_restorer_intr ++ .func __epilogue_restorer_intr ++__epilogue_restorer_intr: ++ pop r4 ++ pop r5 ++ pop r6 ++ pop r7 ++ pop r8 ++ pop r9 ++ pop r10 ++ pop r11 ++ pop r12 ++ pop r13 ++ pop r14 ++ pop r15 ++ reti ++.endfunc ++ ++#endif ++ ++/****************************************** ++ * quot/rem = 64/64 ++ ******************************************/ ++ ++#if defined (L_udivmoddi3_parts) || defined (L_udivdi3) || defined (L_umoddi3) || defined (L_divdi3) || defined (L_moddi3) ++ ++#define r_remhh r11 /* remainder */ ++#define r_remhl r10 ++#define r_remlh r9 ++#define r_remll r8 ++ ++#define r_arg1hh r15 /* dividend, quotient */ ++#define r_arg1hl r14 ++#define r_arg1lh r13 ++#define r_arg1ll r12 ++ ++#define r_arg2hh r7 /* divisor */ ++#define r_arg2hl r6 ++#define r_arg2lh r5 ++#define r_arg2ll r4 ++ ++#define r_cnt 2(r1) /* loop count */ ++#define r_tmp 0(r1) /* we'll save carry and signs here */ ++ ++#endif ++ ++ ++#if defined (L_udivmoddi3_parts) ++ ++ .global __udivmoddi3_parts ++ .func __udivmoddi3_parts ++__udivmoddi3_parts: ++ xor r_remhh, r_remhh ; clear reminder and carry ++ xor r_remhl, r_remhl ++ xor r_remlh, r_remlh ++ xor r_remll, r_remll ++ ++ mov #65, 2+r_cnt ++ jmp .L__udivmoddi3_ep ++ ++.L__udivmoddi3_loop: ++ rrc 2+r_tmp ; restore carry bit ++ ++ rlc r_remll ; shift carry in. ++ rlc r_remlh ++ rlc r_remhl ++ rlc r_remhh ++ ++ cmp r_arg2hh, r_remhh ; is reminder < divisor ? ++ jlo .L__udivmoddi3_ep ; yes, skip correction ++ jne .L_udmdcrt ++ ; they equal. check LSBytes ++ cmp r_arg2hl, r_remhl ++ jlo .L__udivmoddi3_ep ; is reminder still < divisor ? ++ jne .L_udmdcrt ++ ++ cmp r_arg2lh, r_remlh ++ jlo .L__udivmoddi3_ep ++ jne .L_udmdcrt ++ ++ cmp r_arg2ll, r_remll ++ jlo .L__udivmoddi3_ep ++ jne .L_udmdcrt ++ ++.L_udmdcrt: ++ sub r_arg2ll, r_remll ; adjust reminder ++ subc r_arg2lh, r_remlh ++ subc r_arg2hl, r_remhl ++ subc r_arg2hh, r_remhh ++ ++.L__udivmoddi3_ep: ++ rlc r_arg1ll ; shift carry into arg1 ++ rlc r_arg1lh ++ rlc r_arg1hl ++ rlc r_arg1hh ++ ++ rlc 2+r_tmp ; save carry ++ dec 2+r_cnt ; this clobbers C bit. ++ jnz .L__udivmoddi3_loop ++ ++ ret ++ .endfunc ++ ++#endif /* defined (L_udivmoddi3_parts) */ ++ ++ ++#if defined (L_udivdi3) ++ ++;; First arg will be in r15:r12 ++;; next on stack ++;; return in r15:r12 ++;; rearrange them as: ++;; r15:r12 -> r_arg1hh:r_arg1ll ++;; stack+8:stack+2 -> r_arg2hh:r_arg2ll ++ ++ .global __udivdi3 ++ .func __udivdi3 ++__udivdi3: ++ push r4 ++ push r5 ++ push r6 ++ push r7 ++ push r8 ++ push r9 ++ push r10 ++ push r11 ++ ++ mov 18+0(r1), r_arg2ll ; 18 is a stack offset ++ mov 18+2(r1), r_arg2lh ; so move arg 2 in. ++ mov 18+4(r1), r_arg2hl ++ mov 18+6(r1), r_arg2hh ++ ++ sub #4, r1 ++ call #__udivmoddi3_parts ++ add #4, r1 ++ ++ pop r11 ++ pop r10 ++ pop r9 ++ pop r8 ++ pop r7 ++ pop r6 ++ pop r5 ++ pop r4 ++ ret ++ .endfunc ++#endif ++ ++ ++#if defined (L_umoddi3) ++ .global __umoddi3 ++ .func __umoddi3 ++__umoddi3: ++ push r4 ++ push r5 ++ push r6 ++ push r7 ++ push r8 ++ push r9 ++ push r10 ++ push r11 ++ ++ mov 18+0(r1), r_arg2ll ++ mov 18+2(r1), r_arg2lh ++ mov 18+4(r1), r_arg2hl ++ mov 18+6(r1), r_arg2hh ++ ++ sub #4, r1 ++ call #__udivmoddi3_parts ++ add #4, r1 ++ ++ mov r_remhh, r15 ; move reminder to (reg:DI 12) ++ mov r_remhl, r14 ++ mov r_remlh, r13 ++ mov r_remll, r12 ++ ++ pop r11 ++ pop r10 ++ pop r9 ++ pop r8 ++ pop r7 ++ pop r6 ++ pop r5 ++ pop r4 ++ ret ++ .endfunc ++#endif ++ ++ ++#if defined (L_divdi3) ++ .global __divdi3 ++ .func __divdi3 ++__divdi3: ++ push r4 ++ push r5 ++ push r6 ++ push r7 ++ push r8 ++ push r9 ++ push r10 ++ push r11 ++ ++ mov 18+0(r1), r_arg2ll ++ mov 18+2(r1), r_arg2lh ++ mov 18+4(r1), r_arg2hl ++ mov 18+6(r1), r_arg2hh ++ ++ sub #4, r1 ++ ++ clr r_tmp ++ bit #0x8000, r_arg1hh ++ jnc .L__divdi3rempos ++ inv r_arg1hh ++ inv r_arg1hl ++ inv r_arg1lh ++ inv r_arg1ll ++ inc r_arg1ll ++ adc r_arg1lh ++ adc r_arg1hl ++ adc r_arg1hh ++ bis #4, r_tmp ++ ++.L__divdi3rempos: ++ bit #0x8000, r_arg2hh ++ jnc .L__divdi3arg2pos ++ inv r_arg2hh ++ inv r_arg2hl ++ inv r_arg2lh ++ inv r_arg2ll ++ inc r_arg2ll ++ adc r_arg2lh ++ adc r_arg2hl ++ adc r_arg2hh ++ xor #4, r_tmp ; this is a trick - invert bit 4 => ++ ; do not perform double negation. ++.L__divdi3arg2pos: ++ call #__udivmoddi3_parts ++ ++ rrc r_tmp ; restore sign bits ++ ++ bit #4, r_tmp ++ jz .L__divdi3end ++ inv r_arg1hh ++ inv r_arg1hl ++ inv r_arg1lh ++ inv r_arg1ll ++ inc r_arg1ll ++ adc r_arg1lh ++ adc r_arg1hl ++ adc r_arg1hh ++ ++.L__divdi3end: ++ add #4, r1 ++ pop r11 ++ pop r10 ++ pop r9 ++ pop r8 ++ pop r7 ++ pop r6 ++ pop r5 ++ pop r4 ++ ret ++ .endfunc ++#endif ++ ++ ++#if defined (L_moddi3) ++ .global __moddi3 ++ .func __moddi3 ++__moddi3: ++ push r4 ++ push r5 ++ push r6 ++ push r7 ++ push r8 ++ push r9 ++ push r10 ++ push r11 ++ ++ mov 18+0(r1), r_arg2ll ++ mov 18+2(r1), r_arg2lh ++ mov 18+4(r1), r_arg2hl ++ mov 18+6(r1), r_arg2hh ++ ++ sub #4, r1 ++ ++ clr r_tmp ++ bit #0x8000, r_arg1hh ++ jnc .L__moddi3rempos ++ inv r_arg1hh ++ inv r_arg1hl ++ inv r_arg1lh ++ inv r_arg1ll ++ inc r_arg1ll ++ adc r_arg1lh ++ adc r_arg1hl ++ adc r_arg1hh ++ bis #4, r_tmp ++ ++.L__moddi3rempos: ++ bit #0x8000, r_arg2hh ++ jnc .L__moddi3arg2pos ++ inv r_arg2hh ++ inv r_arg2hl ++ inv r_arg2lh ++ inv r_arg2ll ++ inc r_arg2ll ++ adc r_arg2lh ++ adc r_arg2hl ++ adc r_arg2hh ++ ++.L__moddi3arg2pos: ++ call #__udivmoddi3_parts ++ ++ rrc r_tmp ++ ++ bit #4, r_tmp ++ jz .L__moddi3rem ++ ++ inv r_remhh ++ inv r_remhl ++ inv r_remlh ++ inv r_remll ++ inc r_remll ++ adc r_remlh ++ adc r_remhl ++ adc r_remhh ++ ++.L__moddi3rem: ++ mov r_remhh, r15 ++ mov r_remhl, r14 ++ mov r_remlh, r13 ++ mov r_remll, r12 ++ ++ add #4, r1 ++ pop r11 ++ pop r10 ++ pop r9 ++ pop r8 ++ pop r7 ++ pop r6 ++ pop r5 ++ pop r4 ++ ret ++ .endfunc ++#endif ++ ++ ++/************************************************************** ++ * Multiplication 64 = 64 x 64 ++ **************************************************************/ ++#if defined(L_muldi3) && !defined(MSP430_HAS_HWMUL) ++ ++#define r_reshh r11 /* res = arg1 * arg2 */ ++#define r_reshl r10 ++#define r_reslh r9 ++#define r_resll r8 ++ ++#define r_arg1hh r15 /* arg1 */ ++#define r_arg1hl r14 ++#define r_arg1lh r13 ++#define r_arg1ll r12 ++ ++#define r_arg2hh r7 /* arg2 */ ++#define r_arg2hl r6 ++#define r_arg2lh r5 ++#define r_arg2ll r4 ++ ++ .global __muldi3 ++ .func __muldi3 ++__muldi3: ++ push r4 ++ push r5 ++ push r6 ++ push r7 ++ push r8 ++ push r9 ++ push r10 ++ push r11 ++ ++ mov 18+0(r1), r_arg2ll ; 18 is a stack offset ++ mov 18+2(r1), r_arg2lh ; so move arg 2 in. ++ mov 18+4(r1), r_arg2hl ++ mov 18+6(r1), r_arg2hh ++ ++ clr r_reshh ++ clr r_reshl ++ clr r_reslh ++ clr r_resll ++ ++.L_muldi3_loop: ++ clrc ++ rrc r_arg2hh ; arg2 >>= 1 (shift LSB into carry) ++ rrc r_arg2hl ++ rrc r_arg2lh ++ rrc r_arg2ll ++ ++ jnc +8 ; check if bit is set ++ ; yes, it is. ++ add r_arg1ll, r_resll ; res += arg1 ++ addc r_arg1lh, r_reslh ++ addc r_arg1hl, r_reshl ++ addc r_arg1hh, r_reshh ++ ++ rla r_arg1ll ; arg1 <<= 1 ++ rlc r_arg1lh ++ rlc r_arg1hl ++ rlc r_arg1hh ++ ++ tst r_arg2ll ; arg2 !=0 ? loop again , exit otherwise. ++ jne .L_muldi3_loop ++ tst r_arg2lh ++ jne .L_muldi3_loop ++ tst r_arg2hl ++ jne .L_muldi3_loop ++ tst r_arg2hh ++ jne .L_muldi3_loop ++ ++ ; move result to proper location ++ mov r_resll, r12 ++ mov r_reslh, r13 ++ mov r_reshl, r14 ++ mov r_reshh, r15 ++ ++ pop r11 ++ pop r10 ++ pop r9 ++ pop r8 ++ pop r7 ++ pop r6 ++ pop r5 ++ pop r4 ++ ret ++ .endfunc ++#endif ++ ++#if defined(L_muldi3) && defined(MSP430_HAS_HWMUL) ++ ++__MPY=0x130 ++__MPYS=0x132 ++__MAC=0x134 ++__MACS=0x136 ++__OP2=0x138 ++__RESLO=0x13a ++__RESHI=0x13c ++__SUMEXT=0x13e ++ ++#define r_reshh r11 /* res = arg1 * arg2 */ ++#define r_reshl r10 ++#define r_reslh r9 ++#define r_resll r8 ++ ++#define r_arg1hh r15 /* arg1 */ ++#define r_arg1hl r14 ++#define r_arg1lh r13 ++#define r_arg1ll r12 ++ ++#define r_arg2hh r7 /* arg2 */ ++#define r_arg2hl r6 ++#define r_arg2lh r5 ++#define r_arg2ll r4 ++ ++ .global __muldi3 ++ .func __muldi3 ++__muldi3: ++ ++ push r4 ++ push r5 ++ push r6 ++ push r7 ++ push r8 ++ push r9 ++ push r10 ++ push r11 ++ ++ mov 18+0(r1), r_arg2ll ; 18 is a stack offset ++ mov 18+2(r1), r_arg2lh ; so move arg 2 in. ++ mov 18+4(r1), r_arg2hl ++ mov 18+6(r1), r_arg2hh ++ ++;; r15:r14:r13:r12 * r7:r6:r5:r4 -> r11:r10:r9:r8 ++;; actual code follows.... ++ ++ mov r_arg1ll,&__MPY ++ mov r_arg2ll,&__OP2 ;; LL1xLL2 ++ mov &__RESLO,r_resll ++ mov &__RESHI,&__RESLO ++ mov &__SUMEXT,&__RESHI ++ ++ mov r_arg1ll,&__MAC ++ mov r_arg2lh,&__OP2 ;; LL1xLH2 ++ mov r_arg1lh,&__MAC ++ mov r_arg2ll,&__OP2 ;; LH1xLL2 ++ mov &__RESLO,r_reslh ++ mov &__RESHI,&__RESLO ++ mov &__SUMEXT,&__RESHI ++ ++ mov r_arg2lh,&__OP2 ;; LH1xLH2 ++ mov r_arg1ll,&__MAC ++ mov r_arg2hl,&__OP2 ;; LL1xHL2 ++ mov r_arg1hl,&__MAC ++ mov r_arg2ll,&__OP2 ;; HL1xLL2 ++ mov &__RESLO,r_reshl ++ mov &__RESHI,&__RESLO ++ ++ mov r_arg2lh,&__OP2 ;; HL1xLH2 ++ mov r_arg1ll,&__MAC ++ mov r_arg2hh,&__OP2 ;; LL1xHH2 ++ mov r_arg1lh,&__MAC ++ mov r_arg2hl,&__OP2 ;; LH1xHL2 ++ mov r_arg1hh,&__MAC ++ mov r_arg2ll,&__OP2 ;; HH1xLL2 ++ mov &__RESLO,r_reshh ++ ++;; reload result ++ mov r_resll, r12 ++ mov r_reslh, r13 ++ mov r_reshl, r14 ++ mov r_reshh, r15 ++ ++ pop r11 ++ pop r10 ++ pop r9 ++ pop r8 ++ pop r7 ++ pop r6 ++ pop r5 ++ pop r4 ++ ret ++.endfunc ++#endif +diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/msp430.c gcc-3.2.3/gcc/config/msp430/msp430.c +--- gcc-3.2.3.orig/gcc/config/msp430/msp430.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-3.2.3/gcc/config/msp430/msp430.c 2008-08-22 09:17:00.000000000 -0600 +@@ -0,0 +1,9851 @@ ++/* Subroutines for insn-output.c for Texas Instruments MSP430 MCU ++ Copyright (C) 2001, 2002 Free Software Foundation, Inc. ++ Contributed by Dmitry Diky ++ ++ This file is part of GNU CC. ++ GNU CC is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, or (at your option) ++ any later version. ++ ++ GNU CC is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with GNU CC; see the file COPYING. If not, write to ++ the Free Software Foundation, 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. */ ++ ++#include "config.h" ++#include "system.h" ++#include "rtl.h" ++#include "regs.h" ++#include "hard-reg-set.h" ++#include "real.h" ++#include "insn-config.h" ++#include "conditions.h" ++#include "output.h" ++#include "insn-attr.h" ++#include "flags.h" ++#include "reload.h" ++#include "tree.h" ++#include "expr.h" ++#include "toplev.h" ++#include "obstack.h" ++#include "function.h" ++#include "recog.h" ++#include "tm_p.h" ++#include "target.h" ++#include "target-def.h" ++ ++ ++/* This holds the last insn address. */ ++static int last_insn_address = 0; ++ ++/* Commands count in the compiled file */ ++static int commands_in_file; ++ ++/* Commands in the functions prologues in the compiled file */ ++static int commands_in_prologues; ++ ++/* Commands in the functions epilogues in the compiled file */ ++static int commands_in_epilogues; ++ ++/* Prologue/Epilogue size in words */ ++static int prologue_size; ++static int epilogue_size; ++ ++/* Size of all jump tables in the current function, in words. */ ++static int jump_tables_size; ++ ++/* the size of the stack space freed during mdr pass */ ++ ++/* actual frame offset */ ++static int msp430_current_frame_offset = 0; ++ ++/* ret/reti issue indicator for _current_ function */ ++static int return_issued = 0; ++ ++/* registers used for incoming funct arguments */ ++static char arg_register_used[16]; ++ ++/* push helper */ ++int self_push PARAMS ((rtx)); ++ ++ ++/* aux functions */ ++static int msp430_cc_source PARAMS ((rtx, enum rtx_code, rtx, rtx)); ++static int msp430_func_num_saved_regs PARAMS ((void)); ++static int noint_hwmul_function_p PARAMS ((tree func)); ++static int interrupt_function_p PARAMS ((tree func)); ++static int msp430_naked_function_p PARAMS ((tree func)); ++static int msp430_task_function_p PARAMS ((tree func)); ++static int signal_function_p PARAMS ((tree func)); ++static int wakeup_function_p PARAMS ((tree func)); ++static int msp430_num_arg_regs PARAMS ((enum machine_mode mode, tree type)); ++static int msp430_critical_function_p PARAMS ((tree func)); ++static int msp430_reentrant_function_p PARAMS ((tree func)); ++static int msp430_save_prologue_function_p PARAMS ((tree func)); ++ ++const char * msp430_emit_bltnoovfl PARAMS ((rtx *, int)); ++ ++ ++ ++const char *msp430_init_stack = "__stack"; ++const char *msp430_endup = "__stop_progExec__"; ++ ++int msp430_case_values_threshold = 30000; ++int msp430_has_hwmul = 0; ++ ++struct rtx_def *msp430_compare_op0; ++struct rtx_def *msp430_compare_op1; ++ ++ ++const char *msp430_mcu_name = "msp430x110"; ++ ++enum msp430_arch ++{ ++ MSP430_ISA_1 = 1, ++ MSP430_ISA_2 = 2, ++ MSP430_ISA_110 = 110, ++ MSP430_ISA_11 = 11, ++ MSP430_ISA_12 = 12, ++ MSP430_ISA_13 = 13, ++ MSP430_ISA_14 = 14, ++ MSP430_ISA_15 = 15, ++ MSP430_ISA_16 = 16, ++ MSP430_ISA_20 = 20, ++ MSP430_ISA_21 = 21, ++ MSP430_ISA_22 = 22, ++ MSP430_ISA_23 = 23, ++ MSP430_ISA_24 = 24, ++ MSP430_ISA_241 = 241, ++ MSP430_ISA_26 = 26, ++ MSP430_ISA_31 = 31, ++ MSP430_ISA_32 = 32, ++ MSP430_ISA_33 = 33, ++ MSP430_ISA_41 = 41, ++ MSP430_ISA_42 = 42, ++ MSP430_ISA_43 = 43, ++ MSP430_ISA_44 = 44, ++ MSP430_ISA_46 = 46 ++}; ++ ++struct mcu_type_s ++{ ++ const char *name; ++ enum msp430_arch arch; ++ int has_hwmul; ++}; ++ ++static struct mcu_type_s msp430_mcu_types[] = { ++ /* generic types */ ++ {"msp1", MSP430_ISA_1, 0}, ++ {"msp2", MSP430_ISA_2, 1}, ++ ++ /* F1xx family */ ++ {"msp430x110", MSP430_ISA_11, 0}, ++ {"msp430x112", MSP430_ISA_11, 0}, ++ ++ {"msp430x1101", MSP430_ISA_110, 0}, ++ {"msp430x1111", MSP430_ISA_110, 0}, ++ {"msp430x1121", MSP430_ISA_110, 0}, ++ {"msp430x1122", MSP430_ISA_110, 0}, ++ {"msp430x1132", MSP430_ISA_110, 0}, ++ ++ {"msp430x122", MSP430_ISA_12, 0}, ++ {"msp430x123", MSP430_ISA_12, 0}, ++ {"msp430x1222", MSP430_ISA_12, 0}, ++ {"msp430x1232", MSP430_ISA_12, 0}, ++ ++ {"msp430x133", MSP430_ISA_13, 0}, ++ {"msp430x135", MSP430_ISA_13, 0}, ++ {"msp430x1331", MSP430_ISA_13, 0}, ++ {"msp430x1351", MSP430_ISA_13, 0}, ++ ++ {"msp430x147", MSP430_ISA_14, 1}, ++ {"msp430x148", MSP430_ISA_14, 1}, ++ {"msp430x149", MSP430_ISA_14, 1}, ++ {"msp430x1471", MSP430_ISA_14, 1}, ++ {"msp430x1481", MSP430_ISA_14, 1}, ++ {"msp430x1491", MSP430_ISA_14, 1}, ++ ++ {"msp430x155", MSP430_ISA_15, 0}, ++ {"msp430x156", MSP430_ISA_15, 0}, ++ {"msp430x157", MSP430_ISA_15, 0}, ++ ++ {"msp430x167", MSP430_ISA_16, 1}, ++ {"msp430x168", MSP430_ISA_16, 1}, ++ {"msp430x169", MSP430_ISA_16, 1}, ++ {"msp430x1610", MSP430_ISA_16, 1}, ++ {"msp430x1611", MSP430_ISA_16, 1}, ++ {"msp430x1612", MSP430_ISA_16, 1}, ++ ++ /* F2xx family */ ++ {"msp430x2001", MSP430_ISA_20, 0}, ++ {"msp430x2011", MSP430_ISA_20, 0}, ++ ++ {"msp430x2002", MSP430_ISA_20, 0}, ++ {"msp430x2012", MSP430_ISA_20, 0}, ++ ++ {"msp430x2003", MSP430_ISA_20, 0}, ++ {"msp430x2013", MSP430_ISA_20, 0}, ++ ++ {"msp430x2101", MSP430_ISA_21, 0}, ++ {"msp430x2111", MSP430_ISA_21, 0}, ++ {"msp430x2121", MSP430_ISA_21, 0}, ++ {"msp430x2131", MSP430_ISA_21, 0}, ++ ++ {"msp430x2112", MSP430_ISA_22, 0}, ++ {"msp430x2122", MSP430_ISA_22, 0}, ++ {"msp430x2132", MSP430_ISA_22, 0}, ++ ++ {"msp430x2232", MSP430_ISA_22, 0}, ++ {"msp430x2252", MSP430_ISA_22, 0}, ++ {"msp430x2272", MSP430_ISA_22, 0}, ++ ++ {"msp430x2234", MSP430_ISA_22, 0}, ++ {"msp430x2254", MSP430_ISA_22, 0}, ++ {"msp430x2274", MSP430_ISA_22, 0}, ++ ++ {"msp430x233", MSP430_ISA_23, 1}, ++ {"msp430x235", MSP430_ISA_23, 1}, ++ ++ {"msp430x2330", MSP430_ISA_23, 1}, ++ {"msp430x2350", MSP430_ISA_23, 1}, ++ {"msp430x2370", MSP430_ISA_23, 1}, ++ ++ {"msp430x247", MSP430_ISA_24, 1}, ++ {"msp430x248", MSP430_ISA_24, 1}, ++ {"msp430x249", MSP430_ISA_24, 1}, ++ {"msp430x2410", MSP430_ISA_24, 1}, ++ {"msp430x2471", MSP430_ISA_24, 1}, ++ {"msp430x2481", MSP430_ISA_24, 1}, ++ {"msp430x2491", MSP430_ISA_24, 1}, ++ ++ {"msp430x2416", MSP430_ISA_241, 1}, ++ {"msp430x2417", MSP430_ISA_241, 1}, ++ {"msp430x2418", MSP430_ISA_241, 1}, ++ {"msp430x2419", MSP430_ISA_241, 1}, ++ ++ {"msp430x2616", MSP430_ISA_26, 1}, ++ {"msp430x2617", MSP430_ISA_26, 1}, ++ {"msp430x2618", MSP430_ISA_26, 1}, ++ {"msp430x2619", MSP430_ISA_26, 1}, ++ ++ /* 3xx family (ROM) */ ++ {"msp430x311", MSP430_ISA_31, 0}, ++ {"msp430x312", MSP430_ISA_31, 0}, ++ {"msp430x313", MSP430_ISA_31, 0}, ++ {"msp430x314", MSP430_ISA_31, 0}, ++ {"msp430x315", MSP430_ISA_31, 0}, ++ ++ {"msp430x323", MSP430_ISA_32, 0}, ++ {"msp430x325", MSP430_ISA_32, 0}, ++ ++ {"msp430x336", MSP430_ISA_33, 1}, ++ {"msp430x337", MSP430_ISA_33, 1}, ++ ++ /* F4xx family */ ++ {"msp430x412", MSP430_ISA_41, 0}, ++ {"msp430x413", MSP430_ISA_41, 0}, ++ {"msp430x415", MSP430_ISA_41, 0}, ++ {"msp430x417", MSP430_ISA_41, 0}, ++ ++ {"msp430x423", MSP430_ISA_42, 1}, ++ {"msp430x425", MSP430_ISA_42, 1}, ++ {"msp430x427", MSP430_ISA_42, 1}, ++ ++ {"msp430x4250", MSP430_ISA_42, 0}, ++ {"msp430x4260", MSP430_ISA_42, 0}, ++ {"msp430x4270", MSP430_ISA_42, 0}, ++ ++ {"msp430xE423", MSP430_ISA_42, 1}, ++ {"msp430xE425", MSP430_ISA_42, 1}, ++ {"msp430xE427", MSP430_ISA_42, 1}, ++ ++ {"msp430xW423", MSP430_ISA_42, 0}, ++ {"msp430xW425", MSP430_ISA_42, 0}, ++ {"msp430xW427", MSP430_ISA_42, 0}, ++ ++ {"msp430xG437", MSP430_ISA_43, 0}, ++ {"msp430xG438", MSP430_ISA_43, 0}, ++ {"msp430xG439", MSP430_ISA_43, 0}, ++ ++ {"msp430x435", MSP430_ISA_43, 0}, ++ {"msp430x436", MSP430_ISA_43, 0}, ++ {"msp430x437", MSP430_ISA_43, 0}, ++ ++ {"msp430x447", MSP430_ISA_44, 1}, ++ {"msp430x448", MSP430_ISA_44, 1}, ++ {"msp430x449", MSP430_ISA_44, 1}, ++ ++ {"msp430xG4616", MSP430_ISA_46, 1}, ++ {"msp430xG4617", MSP430_ISA_46, 1}, ++ {"msp430xG4618", MSP430_ISA_46, 1}, ++ {"msp430xG4619", MSP430_ISA_46, 1}, ++ ++ {NULL, 0, 0} ++}; ++ ++ ++ ++const struct attribute_spec msp430_attribute_table[]; ++static tree msp430_handle_fndecl_attribute ++PARAMS ((tree *, tree, tree, int, bool *)); ++ ++#undef TARGET_ASM_FUNCTION_PROLOGUE ++#define TARGET_ASM_FUNCTION_PROLOGUE function_prologue ++#undef TARGET_ASM_FUNCTION_EPILOGUE ++#define TARGET_ASM_FUNCTION_EPILOGUE function_epilogue ++#undef TARGET_ATTRIBUTE_TABLE ++#define TARGET_ATTRIBUTE_TABLE msp430_attribute_table ++#undef TARGET_SECTION_TYPE_FLAGS ++#define TARGET_SECTION_TYPE_FLAGS msp430_section_type_flags ++ ++ ++ ++struct gcc_target targetm = TARGET_INITIALIZER; ++ ++/****** ATTRIBUTES TO FUNCTION *************************************/ ++const struct attribute_spec msp430_attribute_table[] = { ++ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ ++ {"reserve", 1, 1, false, false, false, msp430_handle_fndecl_attribute}, ++ {"signal", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, ++ {"interrupt", 1, 1, true, false, false, msp430_handle_fndecl_attribute}, ++ {"naked", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, ++ {"task", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, ++ {"wakeup", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, ++ {"critical", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, ++ {"reentrant", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, ++ {"saveprologue", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, ++ {"noint_hwmul", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, ++ {NULL, 0, 0, false, false, false, NULL} ++}; ++ ++unsigned int ++msp430_section_type_flags (decl, name, reloc) ++ tree decl; ++ const char *name; ++ int reloc; ++{ ++ unsigned int flags = 0; ++ ++ if (!strcmp (name, ".infomemnobits") || !strcmp (name, ".noinit")) ++ flags = SECTION_BSS; ++ ++ flags |= default_section_type_flags (decl, name, reloc); ++ return flags; ++} ++ ++/* Handle an attribute requiring a FUNCTION_DECL; arguments as in ++ struct attribute_spec.handler. */ ++static tree ++msp430_handle_fndecl_attribute (node, name, args, flags, no_add_attrs) ++ tree *node; ++ tree name; ++ tree args ATTRIBUTE_UNUSED; ++ int flags ATTRIBUTE_UNUSED; ++ bool *no_add_attrs; ++{ ++ if (TREE_CODE (*node) != FUNCTION_DECL) ++ { ++ warning ("%s' attribute only applies to functions.", ++ IDENTIFIER_POINTER (name)); ++ *no_add_attrs = true; ++ } ++ return NULL_TREE; ++} ++ ++ ++static int ++msp430_naked_function_p (func) ++ tree func; ++{ ++ tree a; ++ if (TREE_CODE (func) != FUNCTION_DECL) ++ abort (); ++ a = lookup_attribute ("naked", DECL_ATTRIBUTES (func)); ++ return a != NULL_TREE; ++} ++ ++static int ++msp430_task_function_p (func) ++ tree func; ++{ ++ tree a; ++ if (TREE_CODE (func) != FUNCTION_DECL) ++ abort (); ++ a = lookup_attribute ("task", DECL_ATTRIBUTES (func)); ++ return a != NULL_TREE; ++} ++static int ++msp430_save_prologue_function_p (func) ++ tree func; ++{ ++ tree a; ++ if (TREE_CODE (func) != FUNCTION_DECL) ++ abort (); ++ a = lookup_attribute ("saveprologue", DECL_ATTRIBUTES (func)); ++ return a != NULL_TREE; ++} ++ ++static int ++interrupt_function_p (func) ++ tree func; ++{ ++ tree a; ++ if (TREE_CODE (func) != FUNCTION_DECL) ++ abort (); ++ a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func)); ++ return a != NULL_TREE; ++} ++ ++static int ++msp430_critical_function_p (func) ++ tree func; ++{ ++ tree a; ++ if (TREE_CODE (func) != FUNCTION_DECL) ++ abort (); ++ a = lookup_attribute ("critical", DECL_ATTRIBUTES (func)); ++ return a != NULL_TREE; ++ ++} ++ ++static int ++msp430_reentrant_function_p (func) ++ tree func; ++{ ++ tree a; ++ if (TREE_CODE (func) != FUNCTION_DECL) ++ abort (); ++ a = lookup_attribute ("reentrant", DECL_ATTRIBUTES (func)); ++ return a != NULL_TREE; ++ ++} ++ ++static int ++noint_hwmul_function_p (func) ++ tree func; ++{ ++ tree a; ++ if (TREE_CODE (func) != FUNCTION_DECL) ++ abort (); ++ a = lookup_attribute ("noint_hwmul", DECL_ATTRIBUTES (func)); ++ return a != NULL_TREE; ++} ++ ++int ++msp430_current_function_noint_hwmul_function_p (void) ++{ ++ int rval; ++ if (!current_function_decl) ++ return (TARGET_NOINT_HWMUL); ++ rval = noint_hwmul_function_p (current_function_decl); ++ ++ return (TARGET_NOINT_HWMUL || rval); ++} ++ ++static int ++signal_function_p (func) ++ tree func; ++{ ++ tree a; ++ if (TREE_CODE (func) != FUNCTION_DECL) ++ abort (); ++ a = lookup_attribute ("signal", DECL_ATTRIBUTES (func)); ++ return a != NULL_TREE; ++} ++ ++ ++static int ++wakeup_function_p (func) ++ tree func; ++{ ++ tree a; ++ if (TREE_CODE (func) != FUNCTION_DECL) ++ abort (); ++ a = lookup_attribute ("wakeup", DECL_ATTRIBUTES (func)); ++ return a != NULL_TREE; ++} ++ ++enum msp430_arch ++msp430_get_arch () ++{ ++ const struct mcu_type_s *t; ++ ++ for (t = msp430_mcu_types; t->name; t++) ++ { ++ if (strcmp (t->name, msp430_mcu_name) == 0) ++ break; ++ } ++ ++ if (!t->name) ++ { ++ error ("MCU %s not supported", msp430_mcu_name); ++ fprintf (stderr, "Known MCU names:\n"); ++ for (t = msp430_mcu_types; t->name; t++) ++ fprintf (stderr, " %s\n", t->name); ++ abort (); ++ return -1; ++ } ++ return t->arch; ++} ++ ++int ++msp430_is_xarch () ++{ ++ switch (msp430_get_arch()) ++ { ++ case MSP430_ISA_241: ++ case MSP430_ISA_26: ++ case MSP430_ISA_46: ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++void ++msp430_override_options () ++{ ++ const struct mcu_type_s *t; ++ ++ for (t = msp430_mcu_types; t->name; t++) ++ { ++ if (strcmp (t->name, msp430_mcu_name) == 0) ++ break; ++ } ++ ++ if (!t->name) ++ { ++ error ("MCU %s not supported", msp430_mcu_name); ++ fprintf (stderr, "Known MCU names:\n"); ++ for (t = msp430_mcu_types; t->name; t++) ++ fprintf (stderr, " %s\n", t->name); ++ abort (); ++ return; ++ } ++ ++ msp430_has_hwmul = t->has_hwmul || TARGET_HWMUL; ++ ++ if (TARGET_NO_HWMUL) ++ msp430_has_hwmul = 0; ++ ++ msp430_case_values_threshold = 8; /* ? or there is a better value ? */ ++} ++ ++rtx mpy_rtx, mpys_rtx, mac_rtx, macs_rtx, op2_rtx, reslo_rtx, reshi_rtx, ++ sumext_rtx, ressi_rtx; ++ ++ ++static char __dummy[1024]; ++ ++rtx ++sym_ref(mode, arg) ++enum machine_mode mode; ++const char *arg; ++{ ++ rtx rt; ++ static int i = 0; ++ rt = (rtx) &__dummy[i]; ++ i += sizeof(*rt); ++ memset(rt,0,4); ++ PUT_CODE(rt,SYMBOL_REF); ++ PUT_MODE(rt,mode); ++ XSTR(rt,0) = arg; ++ ++ return rt; ++} ++ ++ ++void ++msp430_init_once () ++{ ++/****************************** ++ ++ __MPY=0x130 ++ __MPYS=0x132 ++ __MAC=0x134 ++ __MACS=0x136 ++ __OP2=0x138 ++ __RESLO=0x13a ++ __RESHI=0x13c ++ __SUMEXT=0x13e ++ __RESSI <- not natural ++ *****************************/ ++ ++ mpy_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__MPY")); ++ mpys_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__MPYS")); ++ mac_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__MAC")); ++ macs_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__MACS")); ++ op2_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__OP2")); ++ reslo_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__RESLO")); ++ reshi_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__RESHI")); ++ sumext_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__SUMEXT")); ++ ressi_rtx = gen_rtx_MEM (SImode, sym_ref (SImode, "__RESLO")); ++ return; ++} ++ ++static int reg_class_tab[16] = { ++ PC_REG, STACK_REGS, CG_REGS, CG_REGS, ++ GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, ++ GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, ++ GENERAL_REGS, GENERAL_REGS /* r0 - r15 */ ++}; ++ ++ ++int ++msp430_regno_ok_for_base_p (r) ++ int r; ++{ ++ ++ if (r == 2) ++ return 0; ++ if (r == 3) ++ return 0; ++ if (r < FIRST_PSEUDO_REGISTER && r > 0) ++ return 1; ++ if (reg_renumber ++ && reg_renumber[r] < FIRST_PSEUDO_REGISTER ++ && reg_renumber[r] > 0 && reg_renumber[r] != 2 && reg_renumber[r] != 3) ++ return 1; ++ ++ return 0; ++ ++} ++ ++enum reg_class ++msp430_regno_reg_class (r) ++ int r; ++{ ++ if (r < FIRST_PSEUDO_REGISTER) ++ return reg_class_tab[r]; ++ ++ return NO_REGS; ++} ++ ++ ++enum reg_class ++msp430_reg_class_from_letter (c) ++ int c; ++{ ++ switch (c) ++ { ++ case 'd': ++ return SP_REG; ++ default: ++ break; ++ } ++ ++ return NO_REGS; ++} ++ ++ ++ ++#define NOVECTOR 0xff ++ ++void ++asm_declare_function_name (file, name, decl) ++ FILE *file; ++ char *name; ++ tree decl ATTRIBUTE_UNUSED; ++{ ++ int interrupt_func_p; ++ tree ss = 0; ++ int vector = -1; ++ int vectors_start; ++ int cfp = msp430_critical_function_p (current_function_decl); ++ int ree = msp430_reentrant_function_p (current_function_decl); ++ ++ interrupt_func_p = interrupt_function_p (current_function_decl); ++ ++ if (interrupt_func_p) ++ { ++ /* ++ * .global This_func1 ++ * .set vector11, This_func1 ++ * .type This_func1,@function ++ * ++ */ ++ if (msp430_is_xarch()) ++ { ++ vectors_start = 0xffc0; ++ } ++ else ++ { ++ vectors_start = 0xffe0; ++ } ++ ++ ss = lookup_attribute ("interrupt", ++ DECL_ATTRIBUTES (current_function_decl)); ++ ss = TREE_VALUE (ss); ++ if (ss) ++ { ++ ss = TREE_VALUE (ss); ++ if (ss) ++ vector = TREE_INT_CST_LOW (ss); ++ ++ if (vector != NOVECTOR) ++ vector += vectors_start; ++ } ++ ++ if (vector == -1) ++ { ++ warning ("No valid interrupt vector assigned to ISR `%s'.", name); ++ } ++ ++ if ((vector < vectors_start || vector > 0xfffe || (vector & 1)) ++ && (vector != NOVECTOR && vector != -1)) ++ { ++ warning ++ ("Interrupt vector 0x%x assigned to ISR `%s' is invalid.", ++ vector, name); ++ } ++ ++ if (vector != NOVECTOR) ++ { ++ fprintf (file, ".global vector_%04x\n", vector); ++ } ++ fprintf (file, "%s", TYPE_ASM_OP); ++ assemble_name (file, name); ++ putc (',', file); ++ fprintf (file, TYPE_OPERAND_FMT, "function"); ++ putc ('\n', file); ++ fprintf (file, "/***********************\n"); ++ fprintf (file, " * Interrupt %sRoutine `", ++ (vector != NOVECTOR) ? "Service " : "Sub-"); ++ assemble_name (file, name); ++ fprintf (file, "' at 0x%04x\n", vector); ++ fprintf (file, " ***********************/\n"); ++ ++ if (vector != NOVECTOR) ++ { ++ fprintf (file, "vector_%04x:\n", vector); ++ } ++ ++ ASM_OUTPUT_LABEL (file, name); ++ } ++ else ++ { ++ fprintf (file, "%s", TYPE_ASM_OP); ++ assemble_name (file, name); ++ putc (',', file); ++ fprintf (file, TYPE_OPERAND_FMT, "function"); ++ putc ('\n', file); ++ fprintf (file, "/***********************\n"); ++ fprintf (file, " * Function `"); ++ assemble_name (file, name); ++ fprintf (file, "' %s\n ***********************/\n", ++ cfp ? "(OS critical)" : ree ? "(reentrant)" : ""); ++ ASM_OUTPUT_LABEL (file, name); ++ } ++} ++ ++ ++static int ++msp430_saved_regs_frame (void) ++{ ++ int interrupt_func_p = interrupt_function_p (current_function_decl); ++ int cfp = msp430_critical_function_p (current_function_decl); ++ int leaf_func_p = leaf_function_p (); ++ int offset = interrupt_func_p ? 0 : (cfp ? 2 : 0); ++ int reg; ++ ++ for (reg = 4; reg < 16; ++reg) ++ { ++ if ((!leaf_func_p && call_used_regs[reg] && (interrupt_func_p)) ++ || (regs_ever_live[reg] ++ && (!call_used_regs[reg] || interrupt_func_p))) ++ { ++ offset += 2; ++ } ++ } ++ ++ return offset; ++} ++ ++int ++msp430_empty_epilogue () ++{ ++ int cfp = msp430_critical_function_p (current_function_decl); ++ int ree = msp430_reentrant_function_p (current_function_decl); ++ int nfp = msp430_naked_function_p (current_function_decl); ++ int ifp = interrupt_function_p (current_function_decl); ++ int wup = wakeup_function_p (current_function_decl); ++ int size = msp430_saved_regs_frame (); ++ int fs = get_frame_size (); ++ ++ if (cfp && ree) ++ ree = 0; ++ ++ /* the following combination of attributes forces to issue ++ some commands in function epilogue */ ++ if (ree ++ || nfp || fs || wup || MAIN_NAME_P (DECL_NAME (current_function_decl))) ++ return 0; ++ ++ size += fs; ++ ++ /* <= 2 necessary for first call */ ++ if (size <= 2 && cfp) ++ return 2; ++ if (size == 0 && !cfp && !ifp) ++ return 1; ++ if (size == 0 && ifp) ++ return 2; ++ ++ return 0; ++} ++ ++/* Returns a number of pushed registers */ ++static int ++msp430_func_num_saved_regs () ++{ ++ int i; ++ int saves = 0; ++ int interrupt_func_p = interrupt_function_p (current_function_decl); ++ int leaf_func_p = leaf_function_p (); ++ ++ for (i = 4; i < 16; i++) ++ { ++ if ((regs_ever_live[i] ++ && (!call_used_regs[i] ++ || interrupt_func_p)) ++ || (!leaf_func_p && (call_used_regs[i] && interrupt_func_p))) ++ { ++ saves += 1; ++ } ++ } ++ ++ return saves; ++} ++ ++ ++/* Output function prologue */ ++void ++function_prologue (file, size) ++ FILE *file; ++ int size; ++{ ++ int i; ++ int interrupt_func_p = interrupt_function_p (current_function_decl); ++ int signal_func_p = signal_function_p (current_function_decl); ++ int leaf_func_p = leaf_function_p (); ++ int main_p = MAIN_NAME_P (DECL_NAME (current_function_decl)); ++ int stack_reserve = 0; ++ tree ss = 0; ++ rtx x = DECL_RTL (current_function_decl); ++ const char *fnname = XSTR (XEXP (x, 0), 0); ++ int offset; ++ int cfp = msp430_critical_function_p (current_function_decl); ++ int tfp = msp430_task_function_p (current_function_decl); ++ int ree = msp430_reentrant_function_p (current_function_decl); ++ int save_prologue_p = ++ msp430_save_prologue_function_p (current_function_decl); ++ int num_saved_regs; ++ ++ return_issued = 0; ++ last_insn_address = 0; ++ jump_tables_size = 0; ++ prologue_size = 0; ++ ++ /* check attributes compatibility */ ++ ++ if ((cfp && ree) || (ree && interrupt_func_p)) ++ { ++ warning ("attribute 'reentrant' ignored"); ++ ree = 0; ++ } ++ ++ if (cfp && interrupt_func_p) ++ { ++ warning ("attribute 'critical' ignored"); ++ cfp = 0; ++ } ++ ++ if (signal_func_p && !interrupt_func_p) ++ { ++ warning ("attribute 'signal' does not make sense."); ++ signal_func_p = 0; ++ } ++ ++ /* naked function discards everything */ ++ if (msp430_naked_function_p (current_function_decl)) ++ { ++ fprintf (file, "\t/* prologue: naked */\n"); ++ fprintf (file, ".L__FrameSize_%s=0x%x\n", fnname, size); ++ return; ++ } ++ ss = lookup_attribute ("reserve", DECL_ATTRIBUTES (current_function_decl)); ++ if (ss) ++ { ++ ss = TREE_VALUE (ss); ++ if (ss) ++ { ++ ss = TREE_VALUE (ss); ++ if (ss) ++ stack_reserve = TREE_INT_CST_LOW (ss); ++ stack_reserve++; ++ stack_reserve &= ~1; ++ } ++ } ++ ++ fprintf (file, "\t/* prologue: frame size = %d */\n", size); ++ fprintf (file, ".L__FrameSize_%s=0x%x\n", fnname, size); ++ ++ ++ offset = initial_elimination_offset (0, 0) - 2; ++ ++ msp430_current_frame_offset = offset; ++ ++ fprintf (file, ".L__FrameOffset_%s=0x%x\n", fnname, offset); ++ ++ if (signal_func_p && interrupt_func_p) ++ { ++ prologue_size += 1; ++ fprintf (file, "\teint\t; enable nested interrupt\n"); ++ } ++ ++ if (main_p) ++ { ++ if (TARGET_NSI) ++ { ++ if (size || stack_reserve) ++ fprintf (file, "\tsub\t#%d, r1\t", size + stack_reserve); ++ if (frame_pointer_needed) ++ { ++ fprintf (file, "\tmov\tr1,r%d\n", FRAME_POINTER_REGNUM); ++ prologue_size += 1; ++ } ++ ++ if (size) ++ prologue_size += 2; ++ if (size == 1 || size == 2 || size == 4 || size == 8) ++ prologue_size--; ++ } ++ else ++ { ++ fprintf (file, "\tmov\t#(%s-%d), r1\n", msp430_init_stack, ++ size + stack_reserve); ++ ++ if (frame_pointer_needed) ++ { ++ fprintf (file, "\tmov\tr1,r%d\n", FRAME_POINTER_REGNUM); ++ prologue_size += 1; ++ } ++ prologue_size += 2; ++ } ++ } ++ else ++ { ++ /* Here, we've got a chance to jump to prologue saver */ ++ num_saved_regs = msp430_func_num_saved_regs (); ++ ++ if ((TARGET_SAVE_PROLOGUE || save_prologue_p) ++ && !interrupt_func_p && !arg_register_used[12] && num_saved_regs > 4) ++ { ++ fprintf (file, "\tsub\t#16, r1\n"); ++ fprintf (file, "\tmov\tr0, r12\n"); ++ fprintf (file, "\tadd\t#8, r12\n"); ++ fprintf (file, "\tbr\t#__prologue_saver+%d\n", ++ (8 - num_saved_regs) * 4); ++ ++ if (cfp && 8 - num_saved_regs) ++ { ++ int n = 16 - num_saved_regs * 2; ++ fprintf (file, "\tadd\t#%d, r1\n", n); ++ if (n != 0 && n != 1 && n != 2 && n != 4 && n != 8) ++ prologue_size += 1; ++ } ++ else ++ size -= 16 - num_saved_regs * 2; ++ ++ prologue_size += 7; ++ } ++ else if(!tfp) ++ { ++ for (i = 15; i >= 4; i--) ++ { ++ if ((regs_ever_live[i] ++ && (!call_used_regs[i] ++ || interrupt_func_p)) ++ || (!leaf_func_p && (call_used_regs[i] ++ && (interrupt_func_p)))) ++ { ++ fprintf (file, "\tpush\tr%d\n", i); ++ prologue_size += 1; ++ } ++ } ++ } ++ ++ if (!interrupt_func_p && cfp) ++ { ++ prologue_size += 3; ++ fprintf (file, "\tpush\tr2\n"); ++ fprintf (file, "\tdint\n"); ++ if (!size) ++ fprintf (file, "\tnop\n"); ++ } ++ ++ if (size) ++ { ++ /* The next is a hack... I do not undestand why, but if there ++ ARG_POINTER_REGNUM and FRAME/STACK are different, ++ the compiler fails to compute corresponding ++ displacement */ ++ if (!optimize && !optimize_size ++ && regs_ever_live[ARG_POINTER_REGNUM]) ++ { ++ int o = initial_elimination_offset (0, 0) - size; ++ fprintf (file, "\tmov\tr1, r%d\n", ARG_POINTER_REGNUM); ++ fprintf (file, "\tadd\t#%d, r%d\n", o, ARG_POINTER_REGNUM); ++ prologue_size += 2; ++ if (o != 0 && o != 1 && o != 2 && o != 4 && o != 8) ++ prologue_size += 1; ++ } ++ ++ /* adjust frame ptr... */ ++ if (size > 0) ++ fprintf (file, "\tsub\t#%d, r1\t; %d, fpn %d\n", (size + 1) & ~1, ++ size, frame_pointer_needed); ++ else ++ { ++ size = -size; ++ fprintf (file, "\tadd\t#%d, r1\t; %d, fpn %d\n", ++ (size + 1) & ~1, size, frame_pointer_needed); ++ } ++ ++ if (frame_pointer_needed) ++ { ++ fprintf (file, "\tmov\tr1,r%d\n", FRAME_POINTER_REGNUM); ++ prologue_size += 1; ++ } ++ ++ if (size == 1 || size == 2 || size == 4 || size == 8) ++ prologue_size += 1; ++ else ++ prologue_size += 2; ++ } ++ ++ /* disable interrupt for reentrant function */ ++ if (!interrupt_func_p && ree) ++ { ++ prologue_size += 1; ++ fprintf (file, "\tdint\n"); ++ } ++ } ++ ++ fprintf (file, "\t/* prologue end (size=%d) */\n\n", prologue_size); ++} ++ ++ ++/* Output function epilogue */ ++ ++void ++function_epilogue (file, size) ++ FILE *file; ++ int size; ++{ ++ int i; ++ int interrupt_func_p = interrupt_function_p (current_function_decl); ++ int leaf_func_p = leaf_function_p (); ++ int main_p = MAIN_NAME_P (DECL_NAME (current_function_decl)); ++ int wakeup_func_p = wakeup_function_p (current_function_decl); ++ int cfp = msp430_critical_function_p (current_function_decl); ++ int ree = msp430_reentrant_function_p (current_function_decl); ++ int save_prologue_p = ++ msp430_save_prologue_function_p (current_function_decl); ++ int still_return = 1; ++ int function_size; ++ ++ ++ last_insn_address = 0; ++ jump_tables_size = 0; ++ epilogue_size = 0; ++ function_size = (INSN_ADDRESSES (INSN_UID (get_last_insn ())) ++ - INSN_ADDRESSES (INSN_UID (get_insns ()))); ++ ++ if (msp430_task_function_p (current_function_decl)) ++ { ++ fprintf (file, "\n\t/* epilogue: empty, task functions never return */\n"); ++ return; ++ } ++ ++ if (msp430_naked_function_p (current_function_decl)) ++ { ++ fprintf (file, "\n\t/* epilogue: naked */\n"); ++ return; ++ } ++ ++ if (msp430_empty_epilogue ()) ++ { ++ if (!return_issued) ++ { ++ fprintf (file, "\t%s\n", msp430_emit_return (NULL, NULL, NULL)); ++ epilogue_size++; ++ } ++ fprintf (file, "\n\t/* epilogue: not required */\n"); ++ goto done_epilogue; ++ } ++ ++ if ((cfp || interrupt_func_p) && ree) ++ ree = 0; ++ if (cfp && interrupt_func_p) ++ cfp = 0; ++ ++ fprintf (file, "\n\t/* epilogue: frame size=%d */\n", size); ++ ++ if (main_p) ++ { ++ if (size) ++ fprintf (file, "\tadd\t#%d, r1\n", (size + 1) & ~1); ++ fprintf (file, "\tbr\t#%s\n", msp430_endup); ++ epilogue_size += 4; ++ if (size == 1 || size == 2 || size == 4 || size == 8) ++ epilogue_size--; ++ } ++ else ++ { ++ if (ree) ++ { ++ fprintf (file, "\teint\n"); ++ epilogue_size += 1; ++ } ++ ++ if (size) ++ { ++ fprintf (file, "\tadd\t#%d, r1\n", (size + 1) & ~1); ++ if (size == 1 || size == 2 || size == 4 || size == 8) ++ epilogue_size += 1; ++ else ++ epilogue_size += 2; ++ } ++ ++ if (!interrupt_func_p && cfp) ++ { ++ epilogue_size += 1; ++ if (msp430_saved_regs_frame () == 2) ++ { ++ fprintf (file, "\treti\n"); ++ still_return = 0; ++ } ++ else ++ fprintf (file, "\tpop\tr2\n"); ++ } ++ ++ if ((TARGET_SAVE_PROLOGUE || save_prologue_p) ++ && !interrupt_func_p && msp430_func_num_saved_regs () > 2) ++ { ++ fprintf (file, "\tbr\t#__epilogue_restorer+%d\n", ++ (8 - msp430_func_num_saved_regs ()) * 2); ++ epilogue_size += 2; ++ } ++ else if ((TARGET_SAVE_PROLOGUE || save_prologue_p) && interrupt_func_p) ++ { ++ fprintf (file, "\tbr\t#__epilogue_restorer_intr+%d\n", ++ (12 - msp430_func_num_saved_regs ()) * 2); ++ } ++ else ++ { ++ for (i = 4; i < 16; i++) ++ { ++ if ((regs_ever_live[i] ++ && (!call_used_regs[i] ++ || interrupt_func_p)) ++ || (!leaf_func_p && (call_used_regs[i] && interrupt_func_p))) ++ { ++ fprintf (file, "\tpop\tr%d\n", i); ++ epilogue_size += 1; ++ } ++ } ++ ++ if (interrupt_func_p) ++ { ++ if (wakeup_func_p) ++ { ++ fprintf (file, "\tbic\t#0xf0,0(r1)\n"); ++ epilogue_size += 3; ++ } ++ ++ fprintf (file, "\treti\n"); ++ epilogue_size += 1; ++ } ++ else ++ { ++ if (still_return) ++ fprintf (file, "\tret\n"); ++ epilogue_size += 1; ++ } ++ } ++ } ++ ++ fprintf (file, "\t/* epilogue end (size=%d) */\n", epilogue_size); ++done_epilogue: ++ fprintf (file, "\t/* function %s size %d (%d) */\n", current_function_name, ++ prologue_size + function_size + epilogue_size, function_size); ++ ++ commands_in_file += prologue_size + function_size + epilogue_size; ++ commands_in_prologues += prologue_size; ++ commands_in_epilogues += epilogue_size; ++} ++ ++ ++/* Attempts to replace X with a valid ++ memory address for an operand of mode MODE */ ++/* FIXME: broken call */ ++rtx ++legitimize_address (x, oldx, mode) ++ rtx x; ++ rtx oldx ATTRIBUTE_UNUSED; ++ enum machine_mode mode ATTRIBUTE_UNUSED; ++{ ++ /* if (GET_CODE (oldx) == MEM ++ && GET_CODE (XEXP(oldx,0)) == PLUS ++ && GET_CODE (XEXP(XEXP(oldx,0),0)) == MEM) ++ { ++ x = force_operand (oldx,0); ++ return x; ++ } ++ ++ return oldx; ++ */ ++ return x; ++} ++ ++int ++legitimate_address_p (mode, operand, strict) ++ enum machine_mode mode ATTRIBUTE_UNUSED; ++ rtx operand; ++ int strict; ++{ ++ rtx xfoob, x = operand; ++ ++ xfoob = XEXP (operand, 0); ++ ++ /* accept @Rn (Rn points to operand address ) */ ++ if (GET_CODE (operand) == REG ++ && (strict ? REG_OK_FOR_BASE_STRICT_P (x) ++ : REG_OK_FOR_BASE_NOSTRICT_P (x))) ++ goto granted; ++ ++ /* accept address */ ++ if (CONSTANT_P (operand)) ++ goto granted; ++ ++ /* accept X(Rn) Rn + X points to operand address */ ++ if (GET_CODE (operand) == PLUS ++ && GET_CODE (XEXP (operand, 0)) == REG ++ && CONSTANT_P (XEXP (operand, 1)) ++ && (strict ? (REG_OK_FOR_BASE_STRICT_P (xfoob)) ++ : (REG_OK_FOR_BASE_NOSTRICT_P (xfoob)))) ++ goto granted; ++ ++ if (TARGET_ALL_DEBUG) ++ fprintf (stderr, "Address Failed\n"); ++ return 0; ++ ++granted: ++ if (TARGET_ALL_DEBUG) ++ fprintf (stderr, "Address granted\n"); ++ return 1; ++} ++ ++ ++void ++print_operand_address (file, addr) ++ FILE *file; ++ rtx addr; ++{ ++ /* hopefully will be never entered. */ ++ switch (GET_CODE (addr)) ++ { ++ case REG: ++ fprintf (file, "r%d", REGNO (addr)); ++ return; ++ case POST_INC: ++ fprintf (file, "@r%d+", REGNO (XEXP(addr,0))); ++ return; ++ case SYMBOL_REF: ++ case LABEL_REF: ++ case CONST: ++ fprintf (file, "#"); ++ break; ++ case CODE_LABEL: ++ break; ++ default: ++ abort (); ++ fprintf (file, "&"); ++ } ++ output_addr_const (file, addr); ++} ++ ++void print_sub_operand PARAMS ((FILE *, rtx, int)); ++ ++const char *trim_array[] = { "llo", "lhi", "hlo", "hhi" }; ++ ++ ++ ++void ++print_sub_operand (file, x, code) ++ FILE *file; ++ rtx x; ++ int code; ++{ ++ ++ if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) ++ { ++ output_addr_const (file, x); ++ return; ++ } ++ else if (GET_CODE (x) == CONST) ++ { ++ print_sub_operand (file, XEXP (x, 0), code); ++ return; ++ } ++ else if (GET_CODE (x) == PLUS) ++ { ++ print_sub_operand (file, XEXP (x, 0), code); ++ fprintf (file, "+"); ++ print_sub_operand (file, XEXP (x, 1), code); ++ return; ++ } ++ else if (GET_CODE (x) == CONST_INT) ++ { ++ fprintf (file, "%d", INTVAL (x)); ++ return; ++ } ++ else ++ abort (); ++} ++ ++void ++print_operand (file, x, code) ++ FILE *file; ++ rtx x; ++ int code; ++{ ++ int shift = 0; ++ int ml = GET_MODE_SIZE (x->mode); ++ int source_reg = 0; ++ ++ ++ if (ml > 1) ++ ml = 2; ++ ++ if (code >= 'A' && code <= 'D') ++ shift = code - 'A'; ++ ++ if (code >= 'E' && code <= 'H') ++ { ++ shift = code - 'E'; ++ source_reg = 1; ++ } ++ ++ if (code >= 'I' && code <= 'L') ++ { ++ ml = 1; ++ shift = code - 'I'; ++ } ++ ++ if (GET_CODE (x) == PLUS) ++ { ++ fprintf (file, "add%s", shift ? "c" : ""); ++ } ++ else if (GET_CODE (x) == MINUS) ++ { ++ fprintf (file, "sub%s", shift ? "c" : ""); ++ } ++ else if (GET_CODE (x) == AND) ++ { ++ fprintf (file, "and"); ++ } ++ else if (GET_CODE (x) == IOR) ++ { ++ fprintf (file, "bis"); ++ } ++ else if (GET_CODE (x) == XOR) ++ { ++ fprintf (file, "xor"); ++ } ++ else if (REG_P (x)) ++ { ++ fprintf (file, reg_names[true_regnum (x) + shift]); ++ } ++ else if (GET_CODE (x) == CONST_INT) ++ { ++ if (code != 'F') ++ fprintf (file, "#%s(%d)", trim_array[shift], INTVAL (x)); ++ else ++ fprintf (file, "%d", INTVAL (x)); ++ } ++ else if (GET_CODE (x) == MEM) ++ { ++ rtx addr = XEXP (x, 0); ++ ++ if (GET_CODE (addr) == POST_INC) ++ { ++ fprintf (file, "@r%d+", REGNO (XEXP(addr,0))); ++ } ++ else if (GET_CODE (addr) == REG) ++ { /* for X(Rn) */ ++ if (shift || !source_reg) ++ { ++ if (shift) ++ fprintf (file, "%d(r%d)", shift * ml, REGNO (addr)); ++ else ++ fprintf (file, "@r%d", REGNO (addr)); ++ } ++ else if (source_reg) ++ { ++ fprintf (file, "r%d", REGNO (addr) + shift); ++ } ++ else ++ { ++ fprintf (file, "@r%d", REGNO (addr)); ++ } ++ } ++ else if (GET_CODE (addr) == SYMBOL_REF) ++ { ++ fprintf (file, "&"); ++ output_addr_const (file, addr); ++ if (shift) ++ fprintf (file, "+%d", shift * ml); ++ } ++ else if (GET_CODE (addr) == CONST || GET_CODE (addr) == CONST_INT) ++ { ++ fputc ('&', file); ++ output_addr_const (file, addr); ++ if (shift) ++ fprintf (file, "+%d", shift * ml); ++ } ++ else if (GET_CODE (addr) == PLUS) ++ { ++ ++ print_sub_operand (file, XEXP (addr, 1), code); ++ ++ /* shift if the indirect pointer register is the stack pointer */ ++ if ((code >= 'M' && code <= 'N') && (REGNO (XEXP (addr, 0)) == 1)) ++ shift = code - 'M'; ++ ++ if (shift) ++ fprintf (file, "+%d", shift * ml); ++ ++ if (REG_P (XEXP (addr, 0))) ++ fprintf (file, "(r%d)", REGNO (XEXP (addr, 0))); ++ else ++ abort (); ++ } ++ else if (GET_CODE (addr) == MEM) ++ { ++ fprintf (file, "@(Invalid addressing mode)"); ++ print_operand (file, addr, code); ++ } ++ else ++ { ++ fprintf (file, "Unknown operand. Please check."); ++ } ++ } ++ else if (GET_CODE (x) == SYMBOL_REF) ++ { ++ fprintf (file, "#"); ++ output_addr_const (file, x); ++ if (shift) ++ fprintf (file, "+%d", shift * ml); ++ } ++ else if (GET_CODE (x) == CONST_DOUBLE) ++ { ++ if (GET_MODE (x) == VOIDmode) /* FIXME: may be long long?? */ ++ { ++ if (shift < 2) ++ fprintf (file, "#%s(%d)", trim_array[shift], CONST_DOUBLE_LOW (x)); ++ else ++ fprintf (file, "#%s(%d)", trim_array[shift - 2], ++ CONST_DOUBLE_HIGH (x)); ++ } ++ else if (GET_MODE (x) == SFmode || GET_MODE (x) == SImode) ++ { ++ long val; ++ REAL_VALUE_TYPE rv; ++ REAL_VALUE_FROM_CONST_DOUBLE (rv, x); ++ REAL_VALUE_TO_TARGET_SINGLE (rv, val); ++ asm_fprintf (file, "#%s(0x%lx)", trim_array[shift], val); ++ } ++ else ++ { ++ fatal_insn ("Internal compiler bug. Unknown mode:", x); ++ } ++ } ++ else ++ print_operand_address (file, x); ++} ++ ++/* mode for branch instruction */ ++int ++msp430_jump_dist (x, insn) ++ rtx x; ++ rtx insn; ++{ ++ int dest_addr = INSN_ADDRESSES (INSN_UID (GET_CODE (x) == LABEL_REF ++ ? XEXP (x, 0) : x)); ++ int cur_addr = INSN_ADDRESSES (INSN_UID (insn)); ++ int jump_distance = dest_addr - cur_addr; ++ ++ return jump_distance; ++} ++ ++ ++ ++#define FIRST_CUM_REG 16 ++static CUMULATIVE_ARGS *cum_incoming = 0; ++ ++/* Initializing the variable cum for the state at the beginning ++ of the argument list. */ ++void ++init_cumulative_args (cum, fntype, libname, indirect) ++ CUMULATIVE_ARGS *cum; ++ tree fntype; ++ rtx libname; ++ int indirect ATTRIBUTE_UNUSED; ++{ ++ cum->nregs = 4; ++ cum->regno = FIRST_CUM_REG; ++ if (!libname) ++ { ++ int stdarg = (TYPE_ARG_TYPES (fntype) != 0 ++ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) ++ != void_type_node)); ++ if (stdarg) ++ cum->nregs = 0; ++ } ++} ++ ++/* the same in scope of the cum.args., buf usefull for a ++ function call */ ++void ++init_cumulative_incoming_args (cum, fntype, libname) ++ CUMULATIVE_ARGS *cum; ++ tree fntype; ++ rtx libname; ++{ ++ int i; ++ cum->nregs = 4; ++ cum->regno = FIRST_CUM_REG; ++ if (!libname) ++ { ++ int stdarg = (TYPE_ARG_TYPES (fntype) != 0 ++ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) ++ != void_type_node)); ++ if (stdarg) ++ cum->nregs = 0; ++ } ++ ++ for (i = 0; i < 16; i++) ++ arg_register_used[i] = 0; ++ ++ cum_incoming = cum; ++} ++ ++rtx ++msp430_libcall_value (mode) ++ enum machine_mode mode; ++{ ++ int offs = GET_MODE_SIZE (mode); ++ offs >>= 1; ++ if (offs < 1) ++ offs = 1; ++ return gen_rtx (REG, mode, (RET_REGISTER + 1 - offs)); ++} ++ ++rtx ++msp430_function_value (type, func) ++ tree type; ++ tree func ATTRIBUTE_UNUSED; ++{ ++ int offs; ++ if (TYPE_MODE (type) != BLKmode) ++ return msp430_libcall_value (TYPE_MODE (type)); ++ ++ offs = int_size_in_bytes (type); ++ offs >>= 1; ++ if (offs < 1) ++ offs = 1; ++ if (offs > 1 && offs < (GET_MODE_SIZE (SImode) >> 1)) ++ offs = GET_MODE_SIZE (SImode) >> 1; ++ else if (offs > (GET_MODE_SIZE (SImode) >> 1) ++ && offs < (GET_MODE_SIZE (DImode) >> 1)) ++ offs = GET_MODE_SIZE (DImode) >> 1; ++ ++ return gen_rtx (REG, BLKmode, (RET_REGISTER + 1 - offs)); ++} ++ ++/* Returns the number of registers to allocate for a function argument. */ ++static int ++msp430_num_arg_regs (mode, type) ++ enum machine_mode mode; ++ tree type; ++{ ++ int size; ++ ++ if (mode == BLKmode) ++ size = int_size_in_bytes (type); ++ else ++ size = GET_MODE_SIZE (mode); ++ ++ if (size < 2) ++ size = 2; ++ ++ /* we do not care if argument is passed in odd register ++ so, do not align the size ... ++ BUT!!! even char argument passed in 16 bit register ++ so, align the size */ ++ return ((size + 1) & ~1) >> 1; ++} ++ ++/* Controls whether a function argument is passed ++ in a register, and which register. */ ++rtx ++function_arg (cum, mode, type, named) ++ CUMULATIVE_ARGS *cum; ++ enum machine_mode mode; ++ tree type; ++ int named ATTRIBUTE_UNUSED; ++{ ++ int regs = msp430_num_arg_regs (mode, type); ++ ++ if (cum->nregs && regs <= cum->nregs) ++ { ++ int regnum = cum->regno - regs; ++ ++ if (cum == cum_incoming) ++ { ++ arg_register_used[regnum] = 1; ++ if (regs >= 2) ++ arg_register_used[regnum + 1] = 1; ++ if (regs >= 3) ++ arg_register_used[regnum + 2] = 1; ++ if (regs >= 4) ++ arg_register_used[regnum + 3] = 1; ++ } ++ ++ return gen_rtx (REG, mode, regnum); ++ } ++ return NULL_RTX; ++} ++ ++ ++/* Update the summarizer variable CUM to advance past an argument ++ in the argument list. */ ++void ++function_arg_advance (cum, mode, type, named) ++ CUMULATIVE_ARGS *cum; ++ enum machine_mode mode; ++ tree type; ++ int named ATTRIBUTE_UNUSED; ++{ ++ int regs = msp430_num_arg_regs (mode, type); ++ ++ cum->nregs -= regs; ++ cum->regno -= regs; ++ ++ if (cum->nregs <= 0) ++ { ++ cum->nregs = 0; ++ cum->regno = FIRST_CUM_REG; ++ } ++} ++ ++/* Workaround for volatile variables */ ++int ++nonimmediate_operand_msp430 (op, mode) ++ rtx op; ++ enum machine_mode mode; ++{ ++ int save_volatile_ok = volatile_ok; ++ int niop = 0; ++ ++ if (!TARGET_NVWA) ++ volatile_ok = 1; ++ niop = nonimmediate_operand (op, mode); ++ volatile_ok = save_volatile_ok; ++ ++ return niop; ++} ++ ++int ++memory_operand_msp430 (op, mode) ++ rtx op; ++ enum machine_mode mode; ++{ ++ int save_volatile_ok = volatile_ok; ++ int mop = 0; ++ ++ if (!TARGET_NVWA) ++ volatile_ok = 1; ++ mop = memory_operand (op, mode); ++ volatile_ok = save_volatile_ok; ++ return mop; ++} ++ ++int ++general_operand_msp430 (op, mode) ++ rtx op; ++ enum machine_mode mode; ++{ ++ int save_volatile_ok = volatile_ok; ++ int gop = 0; ++ ++ if (!TARGET_NVWA) ++ volatile_ok = 1; ++ gop = general_operand (op, mode); ++ volatile_ok = save_volatile_ok; ++ return gop; ++} ++ ++ ++int ++halfnibble_integer (op, mode) ++ rtx op; ++ enum machine_mode mode; ++{ ++ int hi, lo; ++ int val; ++ ++ if (!const_int_operand (op, mode)) ++ return 0; ++ ++ /* this integer is the one of form: ++ 0xXXXX0000 or 0x0000XXXX, ++ where XXXX not one of -1,1,2,4,8 ++ */ ++ val = INTVAL (op); ++ hi = ((val & 0xffff0000ul) >> 16) & 0xffff; ++ lo = (val & 0xffff); ++ ++ if (hi && lo) ++ return 0; ++ ++ if (hi && hi != 0xffff && hi != 1 && hi != 2 && hi != 4 && hi != 8) ++ return 1; ++ if (lo && lo != 0xffff && lo != 1 && lo != 2 && lo != 4 && lo != 8) ++ return 1; ++ ++ return 0; ++} ++ ++ ++int ++halfnibble_constant (op, mode) ++ rtx op; ++ enum machine_mode mode; ++{ ++ int hi, lo; ++ int val; ++ ++ if (!const_int_operand (op, mode)) ++ return 0; ++ ++ /* this integer is the one of form: ++ 0xXXXX0000 or 0x0000XXXX, ++ where XXXX one of -1,1,2,4,8 ++ */ ++ val = INTVAL (op); ++ hi = ((val & 0xffff0000ul) >> 16) & 0x0000ffff; ++ lo = (val & 0x0000ffff); ++ ++ if ((hi && lo) || (!hi && !lo)) ++ return 0; ++ ++ if (hi == 0xffff || hi == 1 || hi == 2 || hi == 4 || hi == 8) ++ return 1; ++ if (lo == 0xffff || lo == 1 || lo == 2 || lo == 4 || lo == 8) ++ return 1; ++ ++ if (!(hi && lo)) ++ return 1; ++ ++ return 0; ++} ++ ++ ++int ++halfnibble_integer_shift (op, mode) ++ rtx op; ++ enum machine_mode mode; ++{ ++ int hi, lo; ++ int val; ++ ++ if (!immediate_operand (op, mode)) ++ return 0; ++ ++ /* this integer is the one of form: ++ 0xXXXX0000 or 0x0000XXXX, ++ where XXXX not one of -1,1,2,4,8 ++ */ ++ val = 1 << INTVAL (op); ++ hi = ((val & 0xffff0000ul) >> 16) & 0x0000ffff; ++ lo = (val & 0x0000ffff); ++ ++ if (hi && lo) ++ return 0; ++ ++ if (hi && hi != 0xffff && hi != 1 && hi != 2 && hi != 4 && hi != 8) ++ return 1; ++ if (lo && lo != 0xffff && lo != 1 && lo != 2 && lo != 4 && lo != 8) ++ return 1; ++ ++ return 0; ++} ++ ++ ++int ++halfnibble_constant_shift (op, mode) ++ rtx op; ++ enum machine_mode mode; ++{ ++ int hi, lo; ++ int val; ++ ++ if (!immediate_operand (op, mode)) ++ return 0; ++ ++ /* this integer is the one of form: ++ 0xXXXX0000 or 0x0000XXXX, ++ where XXXX one of -1,1,2,4,8 ++ */ ++ val = 1 << INTVAL (op); ++ hi = ((val & 0xffff0000ul) >> 16) & 0x0000ffff; ++ lo = (val & 0x0000ffff); ++ ++ if (hi && lo) ++ return 0; ++ ++ if (hi && hi == 0xffff && hi == 1 && hi == 2 && hi == 4 && hi == 8) ++ return 1; ++ if (lo && lo == 0xffff && lo == 1 && lo == 2 && lo == 4 && lo == 8) ++ return 1; ++ ++ return 0; ++} ++ ++ ++int ++which_nibble (val) ++ int val; ++{ ++ if (val & 0xffff0000ul) ++ return 1; ++ return 0; ++} ++ ++ ++int ++which_nibble_shift (val) ++ int val; ++{ ++ if (val & 0xffff0000ul) ++ return 1; ++ return 0; ++} ++ ++ ++int ++extra_constraint (x, c) ++ rtx x; ++ int c; ++{ ++ ++ if (c == 'R') ++ { ++ if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == REG) ++ { ++ rtx xx = XEXP (x, 0); ++ int regno = REGNO (xx); ++ if (regno >= 4 || regno == 1) ++ return 1; ++ } ++ } ++ else if (c == 'Q') ++ { ++ if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == REG) ++ { ++ rtx xx = XEXP (x, 0); ++ int regno = REGNO (xx); ++ if (regno >= 4 || regno == 1) ++ return 1; ++ } ++ ++ if (GET_CODE (x) == MEM ++ && GET_CODE (XEXP (x, 0)) == PLUS ++ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) ++ { ++ rtx xx = XEXP (XEXP (x, 0), 0); ++ int regno = REGNO (xx); ++ if (regno >= 4 || regno == 1) ++ return 1; ++ } ++ ++ if (GET_CODE (x) == MEM ++ && GET_CODE (XEXP (x, 0)) == PLUS && REG_P (XEXP (XEXP (x, 0), 0))) ++ { ++ return 1; ++ } ++ ++ } ++ else if (c == 'S') ++ { ++ if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == SYMBOL_REF) ++ { ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++int ++indexed_location (x) ++ rtx x; ++{ ++ int r = 0; ++ ++ if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == REG) ++ { ++ r = 1; ++ } ++ ++ if (TARGET_ALL_DEBUG) ++ { ++ fprintf (stderr, "indexed_location %s: %s \n", ++ r ? "granted" : "failed", ++ reload_completed ? "reload completed" : "reload in progress"); ++ debug_rtx (x); ++ } ++ ++ return r; ++} ++ ++ ++int ++zero_shifted (x) ++ rtx x; ++{ ++ int r = 0; ++ ++ if (GET_CODE (x) == MEM && ++ GET_CODE (XEXP (x, 0)) == REG ++ && REGNO (XEXP (x, 0)) != STACK_POINTER_REGNUM ++ && REGNO (XEXP (x, 0)) != FRAME_POINTER_REGNUM ++ /* the following is Ok, cause we do not corrupt r4 within ISR */ ++ /*&& REGNO(XEXP (x,0)) != ARG_POINTER_REGNUM */ ) ++ { ++ r = 1; ++ } ++ return r; ++} ++ ++ ++int ++default_rtx_costs (X, code, outer_code) ++ rtx X ATTRIBUTE_UNUSED; ++ enum rtx_code code; ++ enum rtx_code outer_code ATTRIBUTE_UNUSED; ++{ ++ int cost = 0; ++ ++ switch (code) ++ { ++ case SYMBOL_REF: ++ cost = 1; ++ break; ++ case LABEL_REF: ++ cost = 1; ++ break; ++ case MEM: ++ cost += 1; ++ break; ++ case CONST_INT: ++ cost = 1; ++ break; ++ case SIGN_EXTEND: ++ case ZERO_EXTEND: ++ cost += 2; ++ break; ++ default: ++ break; ++ } ++ return cost; ++} ++ ++ ++void ++order_regs_for_local_alloc () ++{ ++ unsigned int i; ++ ++ if (TARGET_REORDER) ++ { ++ reg_alloc_order[0] = 12; ++ reg_alloc_order[1] = 13; ++ reg_alloc_order[2] = 14; ++ reg_alloc_order[3] = 15; ++ for (i = 4; i < 16; i++) ++ reg_alloc_order[i] = 15 - i; ++ } ++ else ++ { ++ for (i = 0; i < 16; i++) ++ reg_alloc_order[i] = 15 - i; ++ } ++ ++ return; ++} ++ ++/* Output rtx VALUE as .byte to file FILE */ ++void ++asm_output_char (file, value) ++ FILE *file; ++ rtx value; ++{ ++ fprintf (file, "\t.byte\t"); ++ output_addr_const (file, value); ++ fprintf (file, "\n"); ++} ++ ++/* Output VALUE as .byte to file FILE */ ++void ++asm_output_byte (file, value) ++ FILE *file; ++ int value; ++{ ++ fprintf (file, "\t.byte 0x%x\n", value & 0xff); ++} ++ ++/* Output rtx VALUE as .word to file FILE */ ++void ++asm_output_short (file, value) ++ FILE *file; ++ rtx value; ++{ ++ fprintf (file, "\t.word "); ++ output_addr_const (file, (value)); ++ fprintf (file, "\n"); ++} ++ ++/* Output real N to file FILE */ ++void ++asm_output_float (file, n) ++ FILE *file; ++ REAL_VALUE_TYPE n; ++{ ++ long val; ++ char dstr[100]; ++ ++ REAL_VALUE_TO_TARGET_SINGLE (n, val); ++ REAL_VALUE_TO_DECIMAL (n, "%g", dstr); ++ fprintf (file, "\t.long 0x%08lx\t/* %s */\n", val, dstr); ++} ++ ++/* Sets section name for declaration DECL */ ++void ++unique_section (decl, reloc) ++ tree decl; ++ int reloc ATTRIBUTE_UNUSED; ++{ ++ int len; ++ const char *name, *prefix; ++ char *string; ++ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); ++ STRIP_NAME_ENCODING (name, name); ++ ++ if ((TREE_CODE (decl) == FUNCTION_DECL) || DECL_READONLY_SECTION (decl, 0)) ++ prefix = ".text."; ++ else if ((DECL_INITIAL (decl) == 0) || (DECL_INITIAL (decl) == error_mark_node)) ++ prefix = ".bss."; ++ else ++ prefix = ".data."; ++ ++ len = strlen (name) + strlen (prefix); ++ string = alloca (len + 1); ++ sprintf (string, "%s%s", prefix, name); ++ DECL_SECTION_NAME (decl) = build_string (len, string); ++} ++ ++ ++/* Output section name to file FILE ++ We make the section read-only and executable for a function decl, ++ read-only for a const data decl, and writable for a non-const data decl. */ ++ ++void ++asm_output_section_name (file, decl, name, reloc) ++ FILE *file; ++ tree decl; ++ const char *name; ++ int reloc ATTRIBUTE_UNUSED; ++{ ++ fprintf (file, ".section %s, \"%s\", @progbits\n", name, ++ decl && TREE_CODE (decl) == FUNCTION_DECL ? "ax" : ++ decl && TREE_READONLY (decl) ? "a" : "aw"); ++} ++ ++ ++/* The routine used to output NUL terminated strings. We use a special ++ version of this for most svr4 targets because doing so makes the ++ generated assembly code more compact (and thus faster to assemble) ++ as well as more readable, especially for targets like the i386 ++ (where the only alternative is to output character sequences as ++ comma separated lists of numbers). */ ++ ++void ++gas_output_limited_string (file, str) ++ FILE *file; ++ const char *str; ++{ ++ const unsigned char *_limited_str = (unsigned char *) str; ++ unsigned ch; ++ fprintf (file, "%s\"", STRING_ASM_OP); ++ for (; (ch = *_limited_str); _limited_str++) ++ { ++ int escape; ++ switch (escape = ESCAPES[ch]) ++ { ++ case 0: ++ putc (ch, file); ++ break; ++ case 1: ++ fprintf (file, "\\%03o", ch); ++ break; ++ default: ++ putc ('\\', file); ++ putc (escape, file); ++ break; ++ } ++ } ++ fprintf (file, "\"\n"); ++} ++ ++/* The routine used to output sequences of byte values. We use a special ++ version of this for most svr4 targets because doing so makes the ++ generated assembly code more compact (and thus faster to assemble) ++ as well as more readable. Note that if we find subparts of the ++ character sequence which end with NUL (and which are shorter than ++ STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING. */ ++ ++void ++gas_output_ascii (file, str, length) ++ FILE *file; ++ const char *str; ++ size_t length; ++{ ++ const unsigned char *_ascii_bytes = (const unsigned char *) str; ++ const unsigned char *limit = _ascii_bytes + length; ++ unsigned bytes_in_chunk = 0; ++ for (; _ascii_bytes < limit; _ascii_bytes++) ++ { ++ const unsigned char *p; ++ if (bytes_in_chunk >= 60) ++ { ++ fprintf (file, "\"\n"); ++ bytes_in_chunk = 0; ++ } ++ for (p = _ascii_bytes; p < limit && *p != '\0'; p++) ++ continue; ++ if (p < limit && (p - _ascii_bytes) <= (signed) STRING_LIMIT) ++ { ++ if (bytes_in_chunk > 0) ++ { ++ fprintf (file, "\"\n"); ++ bytes_in_chunk = 0; ++ } ++ gas_output_limited_string (file, (char *) _ascii_bytes); ++ _ascii_bytes = p; ++ } ++ else ++ { ++ int escape; ++ unsigned ch; ++ if (bytes_in_chunk == 0) ++ fprintf (file, "\t.ascii\t\""); ++ switch (escape = ESCAPES[ch = *_ascii_bytes]) ++ { ++ case 0: ++ putc (ch, file); ++ bytes_in_chunk++; ++ break; ++ case 1: ++ fprintf (file, "\\%03o", ch); ++ bytes_in_chunk += 4; ++ break; ++ default: ++ putc ('\\', file); ++ putc (escape, file); ++ bytes_in_chunk += 2; ++ break; ++ } ++ } ++ } ++ if (bytes_in_chunk > 0) ++ fprintf (file, "\"\n"); ++} ++ ++ ++ ++/* Outputs to the stdio stream FILE some ++ appropriate text to go at the start of an assembler file. */ ++ ++void ++asm_file_start (file) ++ FILE *file; ++{ ++ output_file_directive (file, main_input_filename); ++ fprintf (file, "\t.arch %s\n\n", msp430_mcu_name); ++ ++ if (msp430_has_hwmul) ++ { ++ fprintf (file, "/* Hardware multiplier registers: */\n" ++ "__MPY=0x130\n" ++ "__MPYS=0x132\n" ++ "__MAC=0x134\n" ++ "__MACS=0x136\n" ++ "__OP2=0x138\n" ++ "__RESLO=0x13a\n" "__RESHI=0x13c\n" "__SUMEXT=0x13e\n" "\n"); ++ ++ } ++ ++ commands_in_file = 0; ++ commands_in_prologues = 0; ++ commands_in_epilogues = 0; ++} ++ ++/* Outputs to the stdio stream FILE some ++ appropriate text to go at the end of an assembler file. */ ++ ++void ++asm_file_end (file) ++ FILE *file; ++{ ++ fprintf (file, ++ "\n" ++ "/*********************************************************************\n" ++ " * File %s: code size: %d words (0x%x)\n * incl. words in prologues: %d, epilogues: %d\n" ++ " *********************************************************************/\n", ++ main_input_filename, ++ commands_in_file, ++ commands_in_file, commands_in_prologues, commands_in_epilogues); ++} ++ ++int ++msp430_hard_regno_mode_ok (regno, mode) ++ int regno ATTRIBUTE_UNUSED; ++ enum machine_mode mode ATTRIBUTE_UNUSED; ++{ ++ return 1; ++} ++ ++int ++frame_pointer_required_p () ++{ ++ return (current_function_calls_alloca ++ /* || current_function_args_info.nregs == 0 */ ++ || current_function_varargs); ++ ++ /* || get_frame_size () > 0); */ ++} ++ ++enum reg_class ++preferred_reload_class (x, class) ++ rtx x ATTRIBUTE_UNUSED; ++ enum reg_class class; ++{ ++ return class; ++} ++ ++/* cfp minds the fact that the function may save r2 */ ++int ++initial_elimination_offset (from, to) ++ int from; ++ int to; ++{ ++ int reg; ++ if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) ++ return 0; ++ else ++ { ++ int interrupt_func_p = interrupt_function_p (current_function_decl); ++ int cfp = msp430_critical_function_p (current_function_decl); ++ int leaf_func_p = leaf_function_p (); ++ int offset = interrupt_func_p ? 0 : (cfp ? 2 : 0); ++ ++ for (reg = 4; reg < 16; ++reg) ++ { ++ if ((!leaf_func_p && call_used_regs[reg] && (interrupt_func_p)) ++ || (regs_ever_live[reg] ++ && (!call_used_regs[reg] || interrupt_func_p))) ++ { ++ offset += 2; ++ } ++ } ++ return get_frame_size () + offset + 2; ++ } ++ return 0; ++} ++ ++int ++adjust_insn_length (insn, len) ++ rtx insn; ++ int len; ++{ ++ ++ rtx patt = PATTERN (insn); ++ rtx set; ++ ++ set = single_set (insn); ++ ++ if (GET_CODE (patt) == SET) ++ { ++ rtx op[10]; ++ op[1] = SET_SRC (patt); ++ op[0] = SET_DEST (patt); ++ ++ if (general_operand (op[1], VOIDmode) ++ && general_operand (op[0], VOIDmode)) ++ { ++ op[2] = SET_SRC (patt); ++ switch (GET_MODE (op[0])) ++ { ++ case QImode: ++ case HImode: ++ if (indexed_location (op[1])) ++ len--; ++ break; ++ ++ case SImode: ++ case SFmode: ++ /* get length first */ ++ msp430_movesi_code (insn, op, &len); ++ ++ if (zero_shifted (op[1]) && regsi_ok_safe (op)) ++ { ++ rtx reg = XEXP (op[1], 0); ++ if (dead_or_set_p (insn, reg)) ++ len -= 1; ++ } ++ else if (!zero_shifted (op[1]) && indexed_location (op[1])) ++ { ++ len -= 1; ++ } ++ break; ++ case DImode: ++ msp430_movedi_code (insn, op, &len); ++ if (zero_shifted (op[1]) && regdi_ok_safe (op)) ++ { ++ rtx reg = XEXP (op[1], 0); ++ if (dead_or_set_p (insn, reg)) ++ len -= 1; ++ } ++ else if (!zero_shifted (op[1]) && indexed_location (op[1])) ++ { ++ len -= 1; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (GET_CODE (op[2]) == CONST_INT) ++ { ++ if (GET_MODE (op[0]) == DImode) ++ { ++ int x = INTVAL (op[2]); ++ int y = (x & 0xffff0000ul) >> 16; ++ x = x & 0xffff; ++ ++ len -= 2; ++ ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 ++ || x == 0xffff) ++ len--; ++ if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 ++ || y == 0xffff) ++ len--; ++ } ++ else if (GET_MODE (op[0]) == SImode) ++ { ++ int x = INTVAL (op[2]); ++ int y = (x & 0xffff0000ul) >> 16; ++ x = x & 0xffff; ++ ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 ++ || x == 0xffff) ++ len--; ++ if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 ++ || y == 0xffff) ++ len--; ++ } ++ else ++ { ++ /* mighr be hi or qi modes */ ++ int x = INTVAL (op[2]); ++ x = x & 0xffff; ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 ++ || x == 0xffff) ++ len--; ++ } ++ } ++ ++ if (GET_CODE (op[2]) == CONST_DOUBLE) ++ { ++ if (GET_MODE (op[0]) == SFmode) ++ { ++ long val; ++ int y, x; ++ REAL_VALUE_TYPE rv; ++ REAL_VALUE_FROM_CONST_DOUBLE (rv, op[2]); ++ REAL_VALUE_TO_TARGET_SINGLE (rv, val); ++ ++ y = (val & 0xffff0000ul) >> 16; ++ x = val & 0xffff; ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 ++ || x == 0xffff) ++ len--; ++ if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 ++ || y == 0xffff) ++ len--; ++ } ++ else ++ { ++ int hi = CONST_DOUBLE_HIGH (op[2]); ++ int lo = CONST_DOUBLE_LOW (op[2]); ++ int x, y, z; ++ ++ x = (hi & 0xffff0000ul) >> 16; ++ y = hi & 0xffff; ++ z = (lo & 0xffff0000ul) >> 16; ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 ++ || x == 0xffff) ++ len--; ++ if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 ++ || y == 0xffff) ++ len--; ++ if (z == 0 || z == 1 || z == 2 || z == 4 || z == 8 ++ || z == 0xffff) ++ len--; ++ z = lo & 0xffff; ++ if (z == 0 || z == 1 || z == 2 || z == 4 || z == 8 ++ || z == 0xffff) ++ len--; ++ } ++ } ++ ++ return len; ++ } ++ else if (GET_CODE (op[1]) == MULT) ++ { ++ rtx ops[10]; ++ ops[0] = op[0]; ++ ops[1] = XEXP (op[1], 0); ++ ops[2] = XEXP (op[1], 1); ++ ++ if (GET_MODE (ops[0]) != SImode ++ && GET_MODE (ops[0]) != SFmode && GET_MODE (ops[0]) != DImode) ++ { ++ if (indexed_location (ops[1])) ++ len--; ++ if (indexed_location (ops[2])) ++ len--; ++ } ++ } ++ else if (GET_CODE (op[1]) == ASHIFT ++ || GET_CODE (op[1]) == ASHIFTRT || GET_CODE (op[1]) == LSHIFTRT) ++ { ++ rtx ops[10]; ++ ops[0] = op[0]; ++ ops[1] = XEXP (op[1], 0); ++ ops[2] = XEXP (op[1], 1); ++ ++ switch (GET_CODE (op[1])) ++ { ++ case ASHIFT: ++ switch (GET_MODE (op[0])) ++ { ++ case QImode: ++ msp430_emit_ashlqi3 (insn, ops, &len); ++ break; ++ case HImode: ++ msp430_emit_ashlhi3 (insn, ops, &len); ++ break; ++ case SImode: ++ msp430_emit_ashlsi3 (insn, ops, &len); ++ break; ++ case DImode: ++ msp430_emit_ashldi3 (insn, ops, &len); ++ break; ++ default: ++ break; ++ } ++ break; ++ ++ case ASHIFTRT: ++ switch (GET_MODE (op[0])) ++ { ++ case QImode: ++ msp430_emit_ashrqi3 (insn, ops, &len); ++ break; ++ case HImode: ++ msp430_emit_ashrhi3 (insn, ops, &len); ++ break; ++ case SImode: ++ msp430_emit_ashrsi3 (insn, ops, &len); ++ break; ++ case DImode: ++ msp430_emit_ashrdi3 (insn, ops, &len); ++ break; ++ default: ++ break; ++ } ++ break; ++ ++ case LSHIFTRT: ++ switch (GET_MODE (op[0])) ++ { ++ case QImode: ++ msp430_emit_lshrqi3 (insn, ops, &len); ++ break; ++ case HImode: ++ msp430_emit_lshrhi3 (insn, ops, &len); ++ break; ++ case SImode: ++ msp430_emit_lshrsi3 (insn, ops, &len); ++ break; ++ case DImode: ++ msp430_emit_lshrdi3 (insn, ops, &len); ++ break; ++ default: ++ break; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ else if (GET_CODE (op[1]) == PLUS ++ || GET_CODE (op[1]) == MINUS ++ || GET_CODE (op[1]) == AND ++ || GET_CODE (op[1]) == IOR || GET_CODE (op[1]) == XOR) ++ { ++ rtx ops[10]; ++ ops[0] = op[0]; ++ ops[1] = XEXP (op[1], 0); ++ ops[2] = XEXP (op[1], 1); ++ ++ if (GET_CODE (op[1]) == AND && !general_operand (ops[1], VOIDmode)) ++ return len; ++ ++ switch (GET_MODE (ops[0])) ++ { ++ case QImode: ++ case HImode: ++ if (indexed_location (ops[2])) ++ len--; ++ break; ++ case SImode: ++ case SFmode: ++ ++ if (GET_CODE (op[1]) == PLUS) ++ msp430_addsi_code (insn, ops, &len); ++ if (GET_CODE (op[1]) == MINUS) ++ msp430_subsi_code (insn, ops, &len); ++ if (GET_CODE (op[1]) == AND) ++ msp430_andsi_code (insn, ops, &len); ++ if (GET_CODE (op[1]) == IOR) ++ msp430_iorsi_code (insn, ops, &len); ++ if (GET_CODE (op[1]) == XOR) ++ msp430_xorsi_code (insn, ops, &len); ++ ++ if (zero_shifted (ops[2]) && regsi_ok_safe (ops)) ++ { ++ rtx reg = XEXP (ops[2], 0); ++ if (dead_or_set_p (insn, reg)) ++ len -= 1; ++ } ++ else if (!zero_shifted (ops[2]) && indexed_location (ops[2])) ++ { ++ len -= 1; ++ } ++ break; ++ case DImode: ++ ++ if (GET_CODE (op[1]) == PLUS) ++ msp430_adddi_code (insn, ops, &len); ++ if (GET_CODE (op[1]) == MINUS) ++ msp430_subdi_code (insn, ops, &len); ++ if (GET_CODE (op[1]) == AND) ++ msp430_anddi_code (insn, ops, &len); ++ if (GET_CODE (op[1]) == IOR) ++ msp430_iordi_code (insn, ops, &len); ++ if (GET_CODE (op[1]) == XOR) ++ msp430_xordi_code (insn, ops, &len); ++ ++ if (zero_shifted (ops[2]) && regdi_ok_safe (ops)) ++ { ++ rtx reg = XEXP (ops[2], 0); ++ if (dead_or_set_p (insn, reg)) ++ len -= 1; ++ } ++ else if (!zero_shifted (ops[2]) && indexed_location (ops[2])) ++ { ++ len -= 1; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (GET_MODE (ops[0]) == SImode) ++ { ++ if (GET_CODE (ops[2]) == CONST_INT) ++ { ++ if (GET_CODE (op[1]) == AND) ++ { ++ msp430_emit_immediate_and2 (insn, ops, &len); ++ } ++ else if (GET_CODE (op[1]) == IOR) ++ { ++ msp430_emit_immediate_ior2 (insn, ops, &len); ++ } ++ else ++ { ++ if (GET_MODE (ops[0]) == SImode) ++ { ++ int x = INTVAL (ops[2]); ++ int y = (x & 0xffff0000ul) >> 16; ++ x = x & 0xffff; ++ ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 ++ || x == 0xffff) ++ len--; ++ if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 ++ || y == 0xffff) ++ len--; ++ } ++ } ++ } ++ } ++ ++ if (GET_MODE (ops[0]) == SFmode || GET_MODE (ops[0]) == DImode) ++ { ++ if (GET_CODE (ops[2]) == CONST_DOUBLE) ++ { ++ ++ if (GET_CODE (op[1]) == AND) ++ { ++ msp430_emit_immediate_and4 (insn, ops, &len); ++ } ++ else if (GET_CODE (op[1]) == IOR) ++ { ++ msp430_emit_immediate_ior4 (insn, ops, &len); ++ } ++ else if (GET_MODE (ops[0]) == SFmode) ++ { ++ long val; ++ int y, x; ++ REAL_VALUE_TYPE rv; ++ REAL_VALUE_FROM_CONST_DOUBLE (rv, ops[2]); ++ REAL_VALUE_TO_TARGET_SINGLE (rv, val); ++ ++ y = (val & 0xffff0000ul) >> 16; ++ x = val & 0xffff; ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 ++ || x == 0xffff) ++ len--; ++ if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 ++ || y == 0xffff) ++ len--; ++ } ++ else ++ { ++ int hi = CONST_DOUBLE_HIGH (ops[2]); ++ int lo = CONST_DOUBLE_LOW (ops[2]); ++ int x, y, z; ++ ++ x = (hi & 0xffff0000ul) >> 16; ++ y = hi & 0xffff; ++ z = (lo & 0xffff0000ul) >> 16; ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 ++ || x == 0xffff) ++ len--; ++ if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 ++ || y == 0xffff) ++ len--; ++ if (z == 0 || z == 1 || z == 2 || z == 4 || z == 8 ++ || z == 0xffff) ++ len--; ++ } ++ } ++ } ++ ++ return len; ++ } ++ else if (GET_CODE (op[1]) == NOT ++ || GET_CODE (op[1]) == ABS || GET_CODE (op[1]) == NEG) ++ { ++ if (GET_MODE (op[0]) == HImode || GET_MODE (op[0]) == QImode) ++ if (indexed_location (XEXP (op[1], 0))) ++ len--; ++ /* consts handled by cpp */ ++ /* nothing... */ ++ } ++ else if (GET_CODE (op[1]) == ZERO_EXTEND) ++ { ++ rtx ops[10]; ++ ops[0] = op[0]; ++ ops[1] = XEXP (op[1], 0); ++ ++ if (GET_MODE (ops[1]) == QImode) ++ { ++ if (GET_MODE (ops[0]) == HImode) ++ zeroextendqihi (insn, ops, &len); ++ else if (GET_MODE (ops[0]) == SImode) ++ zeroextendqisi (insn, ops, &len); ++ else if (GET_MODE (ops[0]) == DImode) ++ zeroextendqidi (insn, ops, &len); ++ } ++ else if (GET_MODE (ops[1]) == HImode) ++ { ++ if (GET_MODE (ops[0]) == SImode) ++ zeroextendhisi (insn, ops, &len); ++ else if (GET_MODE (ops[0]) == DImode) ++ zeroextendhidi (insn, ops, &len); ++ } ++ else if (GET_MODE (ops[1]) == SImode) ++ { ++ if (GET_MODE (ops[1]) == DImode) ++ zeroextendsidi (insn, ops, &len); ++ } ++ } ++ else if (GET_CODE (op[1]) == SIGN_EXTEND) ++ { ++ rtx ops[10]; ++ ops[0] = op[0]; /* dest */ ++ ops[1] = XEXP (op[1], 0); /* src */ ++ ++ if (GET_MODE (ops[1]) == QImode) ++ { ++ if (GET_MODE (ops[0]) == HImode) ++ signextendqihi (insn, ops, &len); ++ else if (GET_MODE (ops[0]) == SImode) ++ signextendqisi (insn, ops, &len); ++ else if (GET_MODE (ops[0]) == DImode) ++ signextendqidi (insn, ops, &len); ++ } ++ else if (GET_MODE (ops[1]) == HImode) ++ { ++ if (GET_MODE (ops[0]) == SImode) ++ signextendhisi (insn, ops, &len); ++ else if (GET_MODE (ops[0]) == DImode) ++ signextendhidi (insn, ops, &len); ++ } ++ else if (GET_MODE (ops[1]) == SImode) ++ { ++ if (GET_MODE (ops[0]) == DImode) ++ signextendsidi (insn, ops, &len); ++ } ++ } ++ else if (GET_CODE (op[1]) == IF_THEN_ELSE) ++ { ++ if (GET_CODE (op[0]) == PC) ++ { ++ rtx ops[5]; ++ ops[0] = XEXP (op[1], 1); ++ ops[1] = XEXP (op[1], 0); ++ ops[2] = XEXP (ops[1], 0); ++ ops[3] = XEXP (ops[1], 1); ++ msp430_cbranch (insn, ops, &len); ++ } ++ } ++ else if (GET_CODE (op[0]) == MEM ++ && GET_CODE (XEXP (op[0], 0)) == POST_DEC) ++ { ++ rtx ops[4]; ++ ops[0] = op[1]; ++ if (GET_MODE (op[0]) == QImode) ++ msp430_pushqi (insn, ops, &len); ++ if (GET_MODE (op[0]) == HImode) ++ msp430_pushhi (insn, ops, &len); ++ if (GET_MODE (op[0]) == SImode) ++ msp430_pushsisf (insn, ops, &len); ++ if (GET_MODE (op[0]) == DImode) ++ msp430_pushdi (insn, ops, &len); ++ } ++ } ++ ++ if (set) ++ { ++ rtx op[10]; ++ op[1] = SET_SRC (set); ++ op[0] = SET_DEST (set); ++ ++ if (GET_CODE (patt) == PARALLEL) ++ { ++ if (GET_CODE (op[0]) == PC && GET_CODE (op[1]) == IF_THEN_ELSE) ++ { ++ rtx ops[5]; ++ ops[0] = XEXP (op[1], 1); ++ ops[1] = XEXP (op[1], 0); ++ ops[2] = XEXP (ops[1], 0); ++ ops[3] = XEXP (ops[1], 1); ++ msp430_cbranch (insn, ops, &len); ++ } ++ ++ if (GET_CODE (op[1]) == ASHIFT ++ || GET_CODE (op[1]) == ASHIFTRT || GET_CODE (op[1]) == LSHIFTRT) ++ { ++ rtx ops[10]; ++ ops[0] = op[0]; ++ ops[1] = XEXP (op[1], 0); ++ ops[2] = XEXP (op[1], 1); ++ ++ switch (GET_CODE (op[1])) ++ { ++ case ASHIFT: ++ switch (GET_MODE (op[0])) ++ { ++ case QImode: ++ msp430_emit_ashlqi3 (insn, ops, &len); ++ break; ++ case HImode: ++ msp430_emit_ashlhi3 (insn, ops, &len); ++ break; ++ case SImode: ++ msp430_emit_ashlsi3 (insn, ops, &len); ++ break; ++ case DImode: ++ msp430_emit_ashldi3 (insn, ops, &len); ++ break; ++ default: ++ break; ++ } ++ break; ++ ++ case ASHIFTRT: ++ switch (GET_MODE (op[0])) ++ { ++ case QImode: ++ msp430_emit_ashrqi3 (insn, ops, &len); ++ break; ++ case HImode: ++ msp430_emit_ashrhi3 (insn, ops, &len); ++ break; ++ case SImode: ++ msp430_emit_ashrsi3 (insn, ops, &len); ++ break; ++ case DImode: ++ msp430_emit_ashrdi3 (insn, ops, &len); ++ break; ++ default: ++ break; ++ } ++ break; ++ ++ case LSHIFTRT: ++ switch (GET_MODE (op[0])) ++ { ++ case QImode: ++ msp430_emit_lshrqi3 (insn, ops, &len); ++ break; ++ case HImode: ++ msp430_emit_lshrhi3 (insn, ops, &len); ++ break; ++ case SImode: ++ msp430_emit_lshrsi3 (insn, ops, &len); ++ break; ++ case DImode: ++ msp430_emit_lshrdi3 (insn, ops, &len); ++ break; ++ default: ++ break; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ } ++ } ++ ++ return len; ++} ++ ++ ++/* Output all insn addresses and their sizes into the assembly language ++ output file. This is helpful for debugging whether the length attributes ++ in the md file are correct. ++ Output insn cost for next insn. */ ++ ++void ++final_prescan_insn (insn, operand, num_operands) ++ rtx insn, *operand ATTRIBUTE_UNUSED; ++ int num_operands ATTRIBUTE_UNUSED; ++{ ++ int uid = INSN_UID (insn); ++ ++ if (TARGET_ALL_DEBUG) ++ { ++ fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n", ++ INSN_ADDRESSES (uid), ++ INSN_ADDRESSES (uid) - last_insn_address, ++ rtx_cost (PATTERN (insn), INSN)); ++ } ++ last_insn_address = INSN_ADDRESSES (uid); ++} ++ ++void ++msp430_output_addr_vec_elt (stream, value) ++ FILE *stream; ++ int value; ++{ ++ fprintf (stream, "\t.word .L%d\n", value); ++ jump_tables_size++; ++} ++ ++ ++void ++machine_dependent_reorg (first_insn) ++ rtx first_insn ATTRIBUTE_UNUSED; ++{ ++ /* nothing to be done here this time */ ++ return; ++} ++ ++ ++int ++test_hard_reg_class (class, x) ++ enum reg_class class; ++ rtx x; ++{ ++ int regno = true_regnum (x); ++ if (regno < 0) ++ return 0; ++ return TEST_HARD_REG_CLASS (class, regno); ++} ++ ++ ++/* Returns 1 if SCRATCH are safe to be allocated as a scratch ++ registers (for a define_peephole2) in the current function. */ ++/* UNUSED ... yet... */ ++int ++msp430_peep2_scratch_safe (scratch) ++ rtx scratch; ++{ ++ if ((interrupt_function_p (current_function_decl) ++ || signal_function_p (current_function_decl)) && leaf_function_p ()) ++ { ++ int first_reg = true_regnum (scratch); ++ int last_reg; ++ int size = GET_MODE_SIZE (GET_MODE (scratch)); ++ int reg; ++ ++ size >>= 1; ++ if (!size) ++ size = 1; ++ ++ last_reg = first_reg + size - 1; ++ ++ for (reg = first_reg; reg <= last_reg; reg++) ++ { ++ if (!regs_ever_live[reg]) ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++/* Update the condition code in the INSN. ++ now mostly unused */ ++ ++void ++notice_update_cc (body, insn) ++ rtx body ATTRIBUTE_UNUSED; ++ rtx insn ATTRIBUTE_UNUSED; ++{ ++ CC_STATUS_INIT; ++} ++ ++ ++ ++/*********************************************************************/ ++ ++/* ++ Next two return non zero for rtx as ++ (set (reg:xx) ++ (mem:xx (reg:xx)) ++ ++*/ ++ ++int ++regsi_ok_safe (operands) ++ rtx operands[]; ++{ ++ rtx dest = operands[0]; ++ rtx areg; ++ int src_reg; ++ int dst_reg; ++ ++ if (operands[2]) ++ areg = XEXP (operands[2], 0); ++ else ++ areg = XEXP (operands[1], 0); ++ ++ if (GET_CODE (dest) == MEM) ++ { ++ dest = XEXP (operands[0], 0); ++ if (GET_CODE (dest) == PLUS && GET_CODE (XEXP (dest, 0)) == REG) ++ { ++ dest = XEXP (dest, 0); ++ } ++ else if (GET_CODE (dest) == REG) ++ { ++ ; /* register */ ++ } ++ else ++ return 1; ++ } ++ ++ if (REGNO (dest) >= FIRST_PSEUDO_REGISTER ++ || REGNO (areg) >= FIRST_PSEUDO_REGISTER) ++ return 1; ++ ++ dst_reg = true_regnum (dest); ++ src_reg = true_regnum (areg); ++ if (dst_reg > src_reg || dst_reg + 1 < src_reg) ++ { ++ return 1; ++ } ++ return 0; ++} ++ ++int ++regsi_ok_clobber (operands) ++ rtx operands[]; ++{ ++ rtx dest = operands[0]; ++ rtx areg = XEXP (operands[2], 0); ++ int src_reg; ++ int dst_reg; ++ int regno = REGNO (dest); ++ ++ ++ if (GET_CODE (dest) == MEM) ++ { ++ dest = XEXP (operands[0], 0); ++ if (GET_CODE (dest) == PLUS && GET_CODE (XEXP (dest, 0)) == REG) ++ { ++ dest = XEXP (dest, 0); ++ } ++ else if (GET_CODE (dest) == REG) ++ { ++ ; /* register */ ++ } ++ else ++ return 1; ++ } ++ ++ if (regno >= FIRST_PSEUDO_REGISTER || REGNO (areg) >= FIRST_PSEUDO_REGISTER) ++ return 1; ++ ++ dst_reg = true_regnum (dest); ++ src_reg = true_regnum (areg); ++ if (dst_reg + 1 == src_reg) ++ return 1; ++ return 0; ++} ++ ++int ++regdi_ok_safe (operands) ++ rtx operands[]; ++{ ++ rtx dest = operands[0]; ++ rtx areg = XEXP (operands[2], 0); ++ int src_reg; ++ int dst_reg; ++ ++ ++ if (GET_CODE (dest) == MEM) ++ { ++ dest = XEXP (operands[0], 0); ++ if (GET_CODE (dest) == PLUS && GET_CODE (XEXP (dest, 0)) == REG) ++ { ++ dest = XEXP (dest, 0); ++ } ++ else if (GET_CODE (dest) == REG) ++ { ++ ; /* register */ ++ } ++ else ++ return 1; ++ } ++ ++ if (REGNO (dest) >= FIRST_PSEUDO_REGISTER ++ || REGNO (areg) >= FIRST_PSEUDO_REGISTER) ++ return 1; ++ ++ dst_reg = true_regnum (dest); ++ src_reg = true_regnum (areg); ++ if (dst_reg > src_reg || dst_reg + 3 < src_reg) ++ { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++int ++regdi_ok_clobber (operands) ++ rtx operands[]; ++{ ++ rtx dest = operands[0]; ++ rtx areg = XEXP (operands[2], 0); ++ int src_reg; ++ int dst_reg; ++ int regno = REGNO (dest); ++ ++ if (GET_CODE (dest) == MEM) ++ { ++ dest = XEXP (operands[0], 0); ++ if (GET_CODE (dest) == PLUS && GET_CODE (XEXP (dest, 0)) == REG) ++ { ++ dest = XEXP (dest, 0); ++ } ++ else if (GET_CODE (dest) == REG) ++ { ++ ; /* register */ ++ } ++ else ++ return 1; ++ } ++ ++ if (regno >= FIRST_PSEUDO_REGISTER || REGNO (areg) >= FIRST_PSEUDO_REGISTER) ++ return 1; ++ ++ dst_reg = true_regnum (dest); ++ src_reg = true_regnum (areg); ++ if (dst_reg + 3 == src_reg) ++ return 1; ++ return 0; ++} ++ ++ ++/***************** ARITHMETIC *******************/ ++ ++int ++emit_indexed_arith (insn, operands, m, cmd, iscarry) ++ rtx insn; ++ rtx operands[]; ++ int m; ++ const char *cmd; ++ int iscarry; ++{ ++ char template[256]; ++ register int i = 0; ++ char *p; ++ rtx reg = NULL; ++ int len = m * 2; ++ rtx x = operands[0]; ++ int havestop = 0; ++ rtx pattern; ++ rtx next = next_real_insn (insn); ++ ++ ++ pattern = PATTERN (next); ++ ++ if (pattern && GET_CODE (pattern) == PARALLEL) ++ { ++ pattern = XVECEXP (pattern, 0, 0); ++ } ++ ++ if (followed_compare_condition (insn) != UNKNOWN ++ || GET_CODE(insn) == JUMP_INSN ++ || (pattern ++ && GET_CODE (pattern) == SET ++ && SET_DEST (pattern) == cc0_rtx) ++ || (pattern && GET_CODE (pattern) == SET ++ && SET_DEST (pattern) == pc_rtx)) ++ { ++ /* very exotic case */ ++ ++ snprintf (template, 255, "%s\t" "%%A%d, %%A0", cmd, operands[2] ? 2 : 1); ++ output_asm_insn (template, operands); ++ snprintf (template, 255, "%s%s\t" "%%B%d, %%B0", cmd, iscarry ? "c" : "", ++ operands[2] ? 2 : 1); ++ output_asm_insn (template, operands); ++ ++ if (m == 2) ++ return len; ++ ++ snprintf (template, 255, "%s%s\t" "%%C%d, %%C0", cmd, iscarry ? "c" : "", ++ operands[2] ? 2 : 1); ++ output_asm_insn (template, operands); ++ snprintf (template, 255, "%s%s\t" "%%D%d, %%D0", cmd, iscarry ? "c" : "", ++ operands[2] ? 2 : 1); ++ output_asm_insn (template, operands); ++ ++ return len; ++ } ++ ++ if (operands[2]) ++ reg = XEXP (operands[2], 0); ++ else ++ reg = XEXP (operands[1], 0); ++ ++ if (GET_CODE (x) == REG) ++ { ++ int src; ++ int dst = REGNO (x); ++ ++ if (!reg) ++ { ++ reg = XEXP (operands[1], 0); ++ } ++ ++ src = REGNO (reg); ++ ++ /* check if registers overlap */ ++ if (dst > src || (dst + m - 1) < src) ++ { ++ ; /* fine ! */ ++ } ++ else if ((dst + m - 1) == src) ++ { ++ havestop = 1; /* worse */ ++ } ++ else ++ { ++ /* cannot do reverse assigment */ ++ while (i < m) ++ { ++ p = (char *) (template + strlen (cmd)); ++ p += (i && iscarry) ? 3 : 2; ++ strcpy (template, cmd); ++ strcat (template, (i && iscarry) ? "c\t%" : "\t%"); ++ *p = 'A' + i; ++ p++; ++ *p = 0; ++ strcat (template, "0, %"); ++ p += 2; ++ *p = 'A' + i; ++ p++; ++ *p = 0; ++ strcat (template, operands[2] ? "2" : "1"); ++ output_asm_insn (template, operands); ++ i++; ++ } ++ return m * 3; ++ } ++ } ++ ++ while (i < (m - havestop)) ++ { ++ p = template + strlen (cmd); ++ ++ strcpy (template, cmd); ++ ++ if (i && iscarry) ++ { ++ strcat (template, "c\t"); ++ p += 2; ++ } ++ else ++ { ++ strcat (template, "\t"); ++ p += 1; ++ } ++ strcat (template, operands[2] ? "@%E2+, %" : "@%E1+, %"); ++ p += 8; ++ *p = 'A' + i; ++ p++; ++ *p = 0; ++ strcat (template, "0"); ++ p++; ++ output_asm_insn (template, operands); ++ i++; ++ } ++ ++ if (havestop) ++ { ++ len++; ++ p = template + strlen (cmd); ++ strcpy (template, cmd); ++ if (i && iscarry) ++ { ++ strcat (template, "c\t"); ++ p += 2; ++ } ++ else ++ { ++ strcat (template, "\t"); ++ p += 1; ++ } ++ strcat (template, operands[2] ? "@%E2, %" : "@%E1, %"); ++ p += 8; ++ *p = 'A' + i; ++ p++; ++ *p = 0; ++ strcat (template, "0 ; register won't die"); ++ p += 1; ++ output_asm_insn (template, operands); ++ } ++ ++ if (!dead_or_set_p (insn, reg) && !havestop) ++ { ++ len++; ++ p = template + 3; ++ strcpy (template, "sub"); ++ strcat (template, "\t#"); ++ p += 2; ++ *p = '0' + m * 2; ++ p++; ++ *p = 0; ++ ++ if (operands[2]) ++ strcat (template, ", %E2 ; restore %E2"); ++ else ++ strcat (template, ", %E1 ; restore %E1"); ++ output_asm_insn (template, operands); ++ } ++ ++ return len; ++} ++ ++static int sameoperand_p PARAMS ((rtx, rtx)); ++ ++int ++sameoperand (operands, i) ++ rtx operands[]; ++ int i; ++{ ++ rtx dst = operands[0]; ++ rtx src = operands[i]; ++ ++ return sameoperand_p (src, dst); ++} ++ ++static int ++sameoperand_p (src, dst) ++ rtx src; ++ rtx dst; ++{ ++ enum rtx_code scode = GET_CODE (src); ++ enum rtx_code dcode = GET_CODE (dst); ++ /* cannot use standard functions here ++ cause operands have different modes: ++ */ ++ ++ if (scode != dcode) ++ return 0; ++ ++ switch (scode) ++ { ++ case REG: ++ return REGNO (src) == REGNO (dst); ++ break; ++ case MEM: ++ return sameoperand_p (XEXP (src, 0), XEXP (dst, 0)); ++ break; ++ case PLUS: ++ return sameoperand_p (XEXP (src, 0), XEXP (dst, 0)) ++ && sameoperand_p (XEXP (src, 1), XEXP (dst, 1)); ++ break; ++ case CONST_INT: ++ return INTVAL (src) == INTVAL (dst); ++ break; ++ case SYMBOL_REF: ++ return XSTR (src, 0) == XSTR (dst, 0); ++ break; ++ default: ++ break; ++ } ++ return 0; ++ ++} ++ ++#define OUT_INSN(x,p,o) \ ++do { \ ++if(!x) output_asm_insn (p,o); \ ++} while(0) ++ ++ ++ ++/************** MOV CODE *********************************/ ++ ++const char * ++movstrsi_insn (insn, operands, l) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ ++ /* operands 0 and 1 are registers !!! */ ++ /* operand 2 is a cnt and not zero */ ++ output_asm_insn ("\n.Lmsn%=:", operands); ++ output_asm_insn ("mov.b\t@%1+,0(%0)", operands); ++ output_asm_insn ("inc\t%0", operands); ++ output_asm_insn ("dec\t%2", operands); ++ output_asm_insn ("jnz\t.Lmsn%=", operands); ++ ++ return ""; ++} ++ ++ ++const char * ++clrstrsi_insn (insn, operands, l) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ ++ /* operand 0 is a register !!! */ ++ /* operand 1 is a cnt and not zero */ ++ output_asm_insn ("\n.Lcsn%=:", operands); ++ output_asm_insn ("clr.b\t0(%0) ; clr does not support @rn+", ++ operands); ++ output_asm_insn ("inc\t%0", operands); ++ output_asm_insn ("dec\t%1", operands); ++ output_asm_insn ("jnz\t.Lcsn%=", operands); ++ return ""; ++} ++ ++const char * ++movstrhi_insn (insn, operands, l) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ ++ /* operands 0 and 1 are registers !!! */ ++ /* operand 2 is a cnt and not zero */ ++ output_asm_insn ("\n.Lmsn%=:", operands); ++ output_asm_insn ("mov.b\t@%1+,0(%0)", operands); ++ output_asm_insn ("inc\t%0", operands); ++ output_asm_insn ("dec\t%2", operands); ++ output_asm_insn ("jnz\t.Lmsn%=", operands); ++ return ""; ++} ++ ++const char * ++clrstrhi_insn (insn, operands, l) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ ++ /* operand 0 is a register !!! */ ++ /* operand 1 is a cnt and not zero */ ++ output_asm_insn ("\n.Lcsn%=:", operands); ++ output_asm_insn ("clr.b\t0(%0)", operands); ++ output_asm_insn ("inc\t%0", operands); ++ output_asm_insn ("dec\t%1", operands); ++ output_asm_insn ("jnz\t.Lcsn%=", operands); ++ return ""; ++} ++ ++int ++msp430_emit_indexed_mov (insn, operands, m, cmd) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int m; ++ const char *cmd; ++{ ++ char template[256]; ++ register int i = 0; ++ char *p; ++ rtx reg = XEXP (operands[1], 0); ++ int len = m * 2; ++ rtx dst = 0; ++ int sreg,dreg = 0; ++ ++ if(memory_operand(operands[0], VOIDmode)) ++ { ++ if( REG_P(XEXP(operands[0],0))) ++ dreg = REGNO(XEXP(operands[0],0)); ++ else if(GET_CODE(XEXP(operands[0],0)) == PLUS ++ && REG_P(XEXP(XEXP(operands[0],0),0)) ) ++ dreg = REGNO(XEXP(XEXP(operands[0],0),0)); ++ } ++ ++ ++ sreg = REGNO(XEXP(operands[1],0)); ++ ++ while (i < m) ++ { ++ p = template + strlen (cmd); ++ ++ strcpy (template, cmd); ++ strcat (template, "\t"); ++ p += 1; ++ strcat (template, "@%E1+, "); ++ p += 7; ++ ++ if(dreg==sreg) ++ { ++ *p = '-'; p++; ++ *p = '2'; p++; ++ *p = '+'; p++; ++ } ++ ++ *p = '%'; p++; ++ *p = 'A' + ((dreg==sreg)?0:i); ++ ++ p++; ++ *p = 0; ++ strcat (template, "0"); ++ p += 1; ++ output_asm_insn (template, operands); ++ i++; ++ } ++ ++ if (!dead_or_set_p (insn, reg)) ++ { ++ len++; ++ p = template + 3; ++ strcpy (template, "sub"); ++ strcat (template, "\t#"); ++ p += 2; ++ *p = '0' + m * 2; ++ p++; ++ *p = 0; ++ strcat (template, ", %E1 ; restore %E1"); ++ output_asm_insn (template, operands); ++ } ++ ++ return len; ++} ++ ++const char * ++msp430_emit_indexed_mov2 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ msp430_emit_indexed_mov (insn, operands, 2, "mov"); ++ return ""; ++} ++ ++const char * ++msp430_emit_indexed_mov4 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ msp430_emit_indexed_mov (insn, operands, 4, "mov"); ++ return ""; ++} ++ ++const char * ++movsisf_regmode (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ rtx dest = operands[0]; ++ rtx src = operands[1]; ++ rtx areg = XEXP (src, 0); ++ int src_reg = true_regnum (areg); ++ int dst_reg = true_regnum (dest); ++ ++ ++ if (dst_reg > src_reg || dst_reg + 1 < src_reg) ++ { ++ output_asm_insn ("mov\t@%E1+, %A0", operands); ++ output_asm_insn ("mov\t@%E1+, %B0", operands); ++ if (!dead_or_set_p (insn, areg)) ++ { ++ output_asm_insn ("sub\t#4, %E1\t;\trestore %E1", operands); ++ } ++ return ""; ++ } ++ else if (dst_reg + 1 == src_reg) ++ { ++ output_asm_insn ("mov\t@%E1+, %A0", operands); ++ output_asm_insn ("mov\t@%E1, %B0", operands); ++ return ""; ++ } ++ else ++ { ++ /* destination overlaps with source. ++ so, update destination in reverse way */ ++ output_asm_insn ("mov\t%B1, %B0", operands); ++ output_asm_insn ("mov\t@%E1, %A0", operands); ++ } ++ ++ return ""; /* make compiler happy */ ++} ++ ++ ++/* From Max Behensky ++ This function tells you what the index register in an operand is. It ++ returns the register number, or -1 if it is not an indexed operand */ ++static int get_indexed_reg PARAMS ((rtx)); ++static int ++get_indexed_reg (x) ++ rtx x; ++{ ++ int code; ++ ++ code = GET_CODE (x); ++ ++ if (code != MEM) ++ return (-1); ++ ++ x = XEXP (x, 0); ++ code = GET_CODE (x); ++ if (code == REG) ++ return (REGNO (x)); ++ ++ if (code != PLUS) ++ return (-1); ++ ++ x = XEXP (x, 0); ++ code = GET_CODE (x); ++ if (code != REG) ++ return (-1); ++ ++ return (REGNO (x)); ++} ++ ++ ++const char * ++msp430_movesi_code (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx op0 = operands[0]; ++ rtx op1 = operands[1]; ++ ++ ++ if (memory_operand (op0, VOIDmode) ++ && memory_operand (op1, VOIDmode) && zero_shifted (op1)) ++ { ++ if (!len) ++ msp430_emit_indexed_mov2 (insn, operands, NULL); ++ else ++ *len = 5; ++ return ""; ++ } ++ else if (register_operand (op0, VOIDmode) ++ && memory_operand (op1, VOIDmode) && zero_shifted (op1)) ++ { ++ if (!len) ++ movsisf_regmode (insn, operands, NULL); ++ else ++ *len = 3; ++ return ""; ++ } ++ ++ if (!len) ++ { ++ if ((register_operand (op0, VOIDmode) ++ && register_operand (op1, VOIDmode) ++ && REGNO (op1) + 1 == REGNO (op0)) ++ || (register_operand (op0, VOIDmode) ++ && memory_operand (op1, VOIDmode) ++ && get_indexed_reg (op1) == true_regnum (op0))) ++ { ++ output_asm_insn ("mov\t%B1, %B0", operands); ++ output_asm_insn ("mov\t%A1, %A0", operands); ++ } ++ else ++ { ++ output_asm_insn ("mov\t%A1, %A0", operands); ++ output_asm_insn ("mov\t%B1, %B0", operands); ++ } ++ } ++ else ++ { ++ *len = 2; /* base length */ ++ ++ if (register_operand (op0, VOIDmode)) ++ *len += 0; ++ else if (memory_operand (op0, VOIDmode)) ++ *len += 2; ++ ++ if (register_operand (op1, VOIDmode)) ++ *len += 0; ++ else if (memory_operand (op1, VOIDmode)) ++ *len += 2; ++ else if (immediate_operand (op1, VOIDmode)) ++ *len += 2; ++ } ++ ++ return ""; ++} ++ ++const char * ++movdidf_regmode (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ rtx dest = operands[0]; ++ rtx src = operands[1]; ++ rtx areg = XEXP (src, 0); ++ ++ int src_reg = true_regnum (areg); ++ int dst_reg = true_regnum (dest); ++ ++ ++ if (dst_reg > src_reg || dst_reg + 3 < src_reg) ++ { ++ output_asm_insn ("mov\t@%E1+, %A0", operands); ++ output_asm_insn ("mov\t@%E1+, %B0", operands); ++ output_asm_insn ("mov\t@%E1+, %C0", operands); ++ output_asm_insn ("mov\t@%E1+, %D0", operands); ++ if (!dead_or_set_p (insn, areg)) ++ { ++ output_asm_insn ("sub\t#8, %E1\t;\trestore %E1", operands); ++ } ++ } ++ else if (dst_reg + 3 == src_reg) ++ { ++ output_asm_insn ("mov\t@%E1+, %A0", operands); ++ output_asm_insn ("mov\t@%E1+, %B0", operands); ++ output_asm_insn ("mov\t@%E1+, %C0", operands); ++ output_asm_insn ("mov\t@%E1, %D0 ; %E1 == %D0", operands); ++ } ++ else ++ { ++ /* destination overlaps source. ++ so, update destination in reverse way */ ++ output_asm_insn ("mov\t%D1, %D0 ; %E1 overlaps wit one of %A0 - %D0", ++ operands); ++ output_asm_insn ("mov\t%C1, %C0", operands); ++ output_asm_insn ("mov\t%B1, %B0", operands); ++ output_asm_insn ("mov\t@%E1, %A0", operands); ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_movedi_code (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx op0 = operands[0]; ++ rtx op1 = operands[1]; ++ ++ if (memory_operand (op0, DImode) ++ && memory_operand (op1, DImode) && zero_shifted (op1)) ++ { ++ if (!len) ++ msp430_emit_indexed_mov4 (insn, operands, NULL); ++ else ++ *len = 9; ++ return ""; ++ } ++ else if (register_operand (op0, DImode) ++ && memory_operand (op1, DImode) && zero_shifted (op1)) ++ { ++ if (!len) ++ movdidf_regmode (insn, operands, NULL); ++ else ++ *len = 5; ++ return ""; ++ } ++ ++ if (!len) ++ { ++ if (register_operand (op0, SImode) ++ && register_operand (op1, SImode) && REGNO (op1) + 3 == REGNO (op0)) ++ { ++ output_asm_insn ("mov\t%D1, %D0", operands); ++ output_asm_insn ("mov\t%C1, %C0", operands); ++ output_asm_insn ("mov\t%B1, %B0", operands); ++ output_asm_insn ("mov\t%A1, %A0", operands); ++ } ++ else ++ { ++ output_asm_insn ("mov\t%A1, %A0", operands); ++ output_asm_insn ("mov\t%B1, %B0", operands); ++ output_asm_insn ("mov\t%C1, %C0", operands); ++ output_asm_insn ("mov\t%D1, %D0", operands); ++ } ++ } ++ else ++ { ++ *len = 4; /* base length */ ++ ++ if (register_operand (op0, DImode)) ++ *len += 0; ++ else if (memory_operand (op0, DImode)) ++ *len += 4; ++ ++ if (register_operand (op1, DImode)) ++ *len += 0; ++ else if (memory_operand (op1, DImode)) ++ *len += 4; ++ else if (immediate_operand (op1, DImode)) ++ *len += 4; ++ } ++ ++ return ""; ++} ++ ++ ++ ++ ++/************** ADD CODE *********************************/ ++ ++ ++const char * ++msp430_emit_indexed_add2 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ emit_indexed_arith (insn, operands, 2, "add", 1); ++ return ""; ++} ++ ++const char * ++msp430_emit_indexed_add4 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ emit_indexed_arith (insn, operands, 4, "add", 1); ++ return ""; ++} ++ ++const char * ++msp430_addsi_code (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx op0 = operands[0]; ++ rtx op2 = operands[2]; ++ rtx ops[4]; ++ ++ if (memory_operand (op2, SImode) ++ && zero_shifted (operands[2]) && regsi_ok_safe (operands)) ++ { ++ if (!len) ++ msp430_emit_indexed_add2 (insn, operands, NULL); ++ else ++ { ++ if (memory_operand (op0, SImode)) ++ *len = 5; ++ else if (register_operand (op0, SImode)) ++ *len = 3; ++ } ++ return ""; ++ } ++ else if (memory_operand (op2, SImode) ++ && zero_shifted (operands[2]) && regsi_ok_clobber (operands)) ++ { ++ if (!len) ++ { ++ output_asm_insn ("add\t@%E2+, %A0", operands); ++ output_asm_insn ("addc\t@%E2+, %B0", operands); ++ } ++ else ++ { ++ if (register_operand (op0, SImode)) ++ *len = 2; ++ else if (memory_operand (op0, SImode)) ++ *len = 4; ++ else ++ abort (); ++ } ++ return ""; ++ } ++ ++ ops[0] = operands[0]; ++ ops[2] = operands[2]; ++ ++ if (!len) ++ { ++ output_asm_insn ("add\t%A2, %A0", ops); ++ output_asm_insn ("addc\t%B2, %B0", ops); ++ } ++ ++ if (len) ++ { ++ *len = 2; /* base length */ ++ ++ if (register_operand (ops[0], SImode)) ++ *len += 0; ++ else if (memory_operand (ops[0], SImode)) ++ *len += 2; ++ ++ if (register_operand (ops[2], SImode)) ++ *len += 0; ++ else if (memory_operand (ops[2], SImode)) ++ *len += 2; ++ else if (immediate_operand (ops[2], SImode)) ++ { ++ int x = INTVAL (ops[2]); ++ if (x == -2 || x == -4 || x == -8) ++ { ++ *len += 1; ++ } ++ else ++ *len += 2; ++ } ++ } ++ return ""; ++} ++ ++const char * ++msp430_adddi_code (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx op0 = operands[0]; ++ rtx op2 = operands[2]; ++ ++ if (memory_operand (op2, DImode) ++ && zero_shifted (operands[2]) && regdi_ok_safe (operands)) ++ { ++ if (!len) ++ msp430_emit_indexed_add4 (insn, operands, NULL); ++ else ++ { ++ if (memory_operand (op0, DImode)) ++ *len = 9; ++ else if (register_operand (op0, DImode)) ++ *len = 5; ++ } ++ ++ return ""; ++ } ++ else if (memory_operand (op2, DImode) ++ && zero_shifted (operands[2]) && regdi_ok_clobber (operands)) ++ { ++ if (!len) ++ { ++ output_asm_insn ("add\t@%E2+, %A0", operands); ++ output_asm_insn ("addc\t@%E2+, %B0", operands); ++ output_asm_insn ("addc\t@%E2+, %C0", operands); ++ output_asm_insn ("addc\t@%E2+, %D0", operands); ++ } ++ else ++ { ++ if (register_operand (op0, DImode)) ++ *len = 4; ++ else if (memory_operand (op0, DImode)) ++ *len = 8; ++ else ++ abort (); ++ } ++ return ""; ++ } ++ ++ if (!len) ++ { ++ output_asm_insn ("add\t%A2, %A0", operands); ++ output_asm_insn ("addc\t%B2, %B0", operands); ++ output_asm_insn ("addc\t%C2, %C0", operands); ++ output_asm_insn ("addc\t%D2, %D0", operands); ++ } ++ else ++ { ++ *len = 4; /* base length */ ++ ++ if (register_operand (op0, DImode)) ++ *len += 0; ++ else if (memory_operand (op0, DImode)) ++ *len += 4; ++ ++ if (register_operand (op2, DImode)) ++ *len += 0; ++ else if (memory_operand (op2, DImode)) ++ *len += 4; ++ else if (immediate_operand (op2, DImode)) ++ { ++ int x = INTVAL (op2); ++ ++ if (x == -2 || x == -4 || x == -8) ++ *len += 0; ++ else ++ *len += 4; ++ } ++ else ++ abort (); ++ } ++ ++ return ""; ++} ++ ++ ++/************** SUB CODE *********************************/ ++ ++const char * ++msp430_emit_indexed_sub2 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ emit_indexed_arith (insn, operands, 2, "sub", 1); ++ return ""; ++} ++ ++const char * ++msp430_emit_indexed_sub4 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ emit_indexed_arith (insn, operands, 4, "sub", 1); ++ return ""; ++} ++ ++const char * ++msp430_subsi_code (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx op0 = operands[0]; ++ rtx op2 = operands[2]; ++ ++ if (memory_operand (op2, SImode) ++ && zero_shifted (operands[2]) && regsi_ok_safe (operands)) ++ { ++ if (!len) ++ msp430_emit_indexed_sub2 (insn, operands, NULL); ++ else ++ { ++ if (memory_operand (op0, SImode)) ++ *len = 5; ++ else if (register_operand (op0, SImode)) ++ *len = 3; ++ } ++ ++ return ""; ++ } ++ else if (memory_operand (op2, SImode) ++ && zero_shifted (operands[2]) && regsi_ok_clobber (operands)) ++ { ++ if (!len) ++ { ++ output_asm_insn ("sub\t@%E2+, %A0", operands); ++ output_asm_insn ("subc\t@%E2+, %B0", operands); ++ } ++ else ++ { ++ if (register_operand (op0, SImode)) ++ *len = 2; ++ else if (memory_operand (op0, SImode)) ++ *len = 4; ++ else ++ abort (); ++ } ++ return ""; ++ } ++ ++ if (!len) ++ { ++ output_asm_insn ("sub\t%A2, %A0", operands); ++ output_asm_insn ("subc\t%B2, %B0", operands); ++ } ++ else ++ { ++ *len = 2; /* base length */ ++ ++ if (register_operand (op0, SImode)) ++ *len += 0; ++ else if (memory_operand (op0, SImode)) ++ *len += 2; ++ ++ if (register_operand (op2, SImode)) ++ *len += 0; ++ else if (memory_operand (op2, SImode)) ++ *len += 2; ++ else if (immediate_operand (op2, SImode)) ++ *len += 2; ++ } ++ ++ return ""; ++} ++ ++ ++const char * ++msp430_subdi_code (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx op0 = operands[0]; ++ rtx op2 = operands[2]; ++ ++ if (memory_operand (op2, DImode) ++ && zero_shifted (operands[2]) && regdi_ok_safe (operands)) ++ { ++ if (!len) ++ msp430_emit_indexed_sub4 (insn, operands, NULL); ++ else ++ { ++ if (memory_operand (op0, DImode)) ++ *len = 9; ++ else if (register_operand (op0, DImode)) ++ *len = 5; ++ } ++ ++ return ""; ++ } ++ else if (memory_operand (op2, DImode) ++ && zero_shifted (operands[2]) && regdi_ok_clobber (operands)) ++ { ++ if (!len) ++ { ++ output_asm_insn ("sub\t@%E2+, %A0", operands); ++ output_asm_insn ("subc\t@%E2+, %B0", operands); ++ output_asm_insn ("subc\t@%E2+, %C0", operands); ++ output_asm_insn ("subc\t@%E2+, %D0", operands); ++ } ++ else ++ { ++ if (register_operand (op0, DImode)) ++ *len = 4; ++ else if (memory_operand (op0, DImode)) ++ *len = 8; ++ else ++ abort (); ++ } ++ return ""; ++ } ++ ++ if (!len) ++ { ++ output_asm_insn ("sub\t%A2, %A0", operands); ++ output_asm_insn ("subc\t%B2, %B0", operands); ++ output_asm_insn ("subc\t%C2, %C0", operands); ++ output_asm_insn ("subc\t%D2, %D0", operands); ++ } ++ else ++ { ++ *len = 4; /* base length */ ++ ++ if (register_operand (op0, DImode)) ++ *len += 0; ++ else if (memory_operand (op0, DImode)) ++ *len += 4; ++ ++ if (register_operand (op2, DImode)) ++ *len += 0; ++ else if (memory_operand (op2, DImode)) ++ *len += 4; ++ else if (immediate_operand (op2, DImode)) ++ *len += 4; ++ else ++ abort (); ++ } ++ ++ return ""; ++} ++ ++ ++/************** AND CODE *********************************/ ++ ++const char * ++msp430_emit_indexed_and2 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ emit_indexed_arith (insn, operands, 2, "and", 0); ++ return ""; ++} ++ ++const char * ++msp430_emit_indexed_and4 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ emit_indexed_arith (insn, operands, 4, "and", 0); ++ return ""; ++} ++ ++const char * ++msp430_emit_immediate_and2 (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int v; ++ int l = INTVAL (operands[2]); ++ int r = REG_P (operands[0]); ++ int list1 = ((~1) & 0xffff); ++ int list2 = ((~2) & 0xffff); ++ int list4 = ((~4) & 0xffff); ++ int list8 = ((~8) & 0xffff); ++ ++ rtx op[4]; ++ ++ op[0] = operands[0]; ++ op[1] = operands[1]; ++ op[2] = operands[2]; ++ ++ /* check nibbles */ ++ ++ v = (l) & 0xffff; ++ if (v != 0xffff) ++ { ++ if (v == list1 || v == list2 || v == list4 || v == list8) ++ { ++ op[2] = gen_rtx_CONST_INT (SImode, ~v); ++ OUT_INSN (len, "bic\t%A2, %A0", op); ++ dummy++; ++ if (!r) ++ dummy++; ++ } ++ else ++ { ++ op[2] = gen_rtx_CONST_INT (SImode, v); ++ OUT_INSN (len, "and\t%A2, %A0", op); ++ dummy++; ++ dummy++; ++ if (!r) ++ dummy++; ++ if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8) ++ dummy--; ++ } ++ } ++ ++ v = (l >> 16) & 0xffff; ++ if (v != 0xffff) ++ { ++ if (v == list1 || v == list2 || v == list4 || v == list8) ++ { ++ op[2] = gen_rtx_CONST_INT (SImode, ~v); ++ OUT_INSN (len, "bic\t%A2, %B0", op); ++ dummy++; ++ if (!r) ++ dummy++; ++ } ++ else ++ { ++ op[2] = gen_rtx_CONST_INT (SImode, v); ++ OUT_INSN (len, "and\t%A2, %B0", op); ++ dummy++; ++ dummy++; ++ if (!r) ++ dummy++; ++ if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8) ++ dummy--; ++ } ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++} ++ ++const char * ++msp430_emit_immediate_and4 (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int v; ++ int l = CONST_DOUBLE_LOW (operands[2]); ++ int h = CONST_DOUBLE_HIGH (operands[2]); ++ int r = REG_P (operands[0]); ++ int list1 = ((~1) & 0xffff); ++ int list2 = ((~2) & 0xffff); ++ int list4 = ((~4) & 0xffff); ++ int list8 = ((~8) & 0xffff); ++ rtx op[4]; ++ ++ op[0] = operands[0]; ++ op[1] = operands[1]; ++ op[2] = operands[2]; ++ ++ /* check if operand 2 is really const_double */ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ l = INTVAL (operands[2]); ++ h = 0; ++ } ++ ++ /* check nibbles */ ++ v = (l) & 0xffff; ++ if (v != 0xffff) ++ { ++ if (v == list1 || v == list2 || v == list4 || v == list8) ++ { ++ op[2] = gen_rtx_CONST_INT (SImode, ~v); ++ OUT_INSN (len, "bic\t%A2, %A0", op); ++ dummy++; ++ if (!r) ++ dummy++; ++ } ++ else ++ { ++ op[2] = gen_rtx_CONST_INT (SImode, v); ++ OUT_INSN (len, "and\t%A2, %A0", op); ++ dummy++; ++ dummy++; ++ if (!r) ++ dummy++; ++ if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8) ++ dummy--; ++ } ++ } ++ ++ v = (l >> 16) & 0xffff; ++ if (v != 0xffff) ++ { ++ if (v == list1 || v == list2 || v == list4 || v == list8) ++ { ++ op[2] = gen_rtx_CONST_INT (SImode, ~v); ++ OUT_INSN (len, "bic\t%A2, %B0", op); ++ dummy++; ++ if (!r) ++ dummy++; ++ } ++ else ++ { ++ op[2] = gen_rtx_CONST_INT (SImode, v); ++ OUT_INSN (len, "and\t%A2, %B0", op); ++ dummy++; ++ dummy++; ++ if (!r) ++ dummy++; ++ if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8) ++ dummy--; ++ } ++ } ++ ++ v = (h) & 0xffff; ++ if (v != 0xffff) ++ { ++ if (v == list1 || v == list2 || v == list4 || v == list8) ++ { ++ op[2] = gen_rtx_CONST_INT (SImode, ~v); ++ OUT_INSN (len, "bic\t%A2, %C0", op); ++ dummy++; ++ if (!r) ++ dummy++; ++ } ++ else ++ { ++ op[2] = gen_rtx_CONST_INT (SImode, v); ++ OUT_INSN (len, "and\t%A2, %C0", op); ++ dummy++; ++ dummy++; ++ if (!r) ++ dummy++; ++ if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8) ++ dummy--; ++ } ++ } ++ ++ v = (h >> 16) & 0xffff; ++ if (v != 0xffff) ++ { ++ if (v == list1 || v == list2 || v == list4 || v == list8) ++ { ++ op[2] = gen_rtx_CONST_INT (SImode, ~v); ++ OUT_INSN (len, "bic\t%A2, %D0", op); ++ dummy++; ++ if (!r) ++ dummy++; ++ } ++ else ++ { ++ op[2] = gen_rtx_CONST_INT (SImode, v); ++ OUT_INSN (len, "and\t%A2, %D0", op); ++ dummy++; ++ dummy++; ++ if (!r) ++ dummy++; ++ if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8) ++ dummy--; ++ } ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++} ++ ++const char * ++msp430_andsi_code (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx op0 = operands[0]; ++ rtx op2 = operands[2]; ++ ++ if (nonimmediate_operand (op0, SImode) && immediate_operand (op2, SImode)) ++ { ++ if (!len) ++ msp430_emit_immediate_and2 (insn, operands, NULL); ++ return ""; ++ } ++ ++ if (memory_operand (op2, SImode) ++ && zero_shifted (operands[2]) && regsi_ok_safe (operands)) ++ { ++ if (!len) ++ msp430_emit_indexed_and2 (insn, operands, NULL); ++ else ++ { ++ if (memory_operand (op0, SImode)) ++ *len = 5; ++ else if (register_operand (op0, SImode)) ++ *len = 3; ++ } ++ ++ return ""; ++ } ++ else if (memory_operand (op2, SImode) ++ && zero_shifted (operands[2]) && regsi_ok_clobber (operands)) ++ { ++ if (!len) ++ { ++ output_asm_insn ("and\t@%E2+, %A0", operands); ++ output_asm_insn ("and\t@%E2+, %B0", operands); ++ } ++ else ++ { ++ if (register_operand (op0, SImode)) ++ *len = 2; ++ else if (memory_operand (op0, SImode)) ++ *len = 4; ++ else ++ abort (); ++ } ++ return ""; ++ } ++ ++ if (!len) ++ { ++ output_asm_insn ("and\t%A2, %A0", operands); ++ output_asm_insn ("and\t%B2, %B0", operands); ++ } ++ else ++ { ++ *len = 2; /* base length */ ++ ++ if (register_operand (op0, SImode)) ++ *len += 0; ++ else if (memory_operand (op0, SImode)) ++ *len += 2; ++ ++ if (register_operand (op2, SImode)) ++ *len += 0; ++ else if (memory_operand (op2, SImode)) ++ *len += 2; ++ else if (immediate_operand (op2, SImode)) ++ *len += 2; ++ } ++ ++ return ""; ++} ++ ++ ++const char * ++msp430_anddi_code (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx op0 = operands[0]; ++ rtx op2 = operands[2]; ++ ++ if (nonimmediate_operand (op0, DImode) && immediate_operand (op2, DImode)) ++ { ++ if (!len) ++ msp430_emit_immediate_and4 (insn, operands, NULL); ++ return ""; ++ } ++ ++ if (memory_operand (op2, DImode) ++ && zero_shifted (operands[2]) && regdi_ok_safe (operands)) ++ { ++ if (!len) ++ msp430_emit_indexed_and4 (insn, operands, NULL); ++ else ++ { ++ if (memory_operand (op0, DImode)) ++ *len = 9; ++ else if (register_operand (op0, DImode)) ++ *len = 5; ++ } ++ ++ return ""; ++ } ++ else if (memory_operand (op2, DImode) ++ && zero_shifted (operands[2]) && regdi_ok_clobber (operands)) ++ { ++ if (!len) ++ { ++ output_asm_insn ("and\t@%E2+, %A0", operands); ++ output_asm_insn ("and\t@%E2+, %B0", operands); ++ output_asm_insn ("and\t@%E2+, %C0", operands); ++ output_asm_insn ("and\t@%E2+, %D0", operands); ++ } ++ else ++ { ++ if (register_operand (op0, DImode)) ++ *len = 4; ++ else if (memory_operand (op0, DImode)) ++ *len = 8; ++ else ++ abort (); ++ } ++ return ""; ++ } ++ ++ if (!len) ++ { ++ output_asm_insn ("and\t%A2, %A0", operands); ++ output_asm_insn ("and\t%B2, %B0", operands); ++ output_asm_insn ("and\t%C2, %C0", operands); ++ output_asm_insn ("and\t%D2, %D0", operands); ++ } ++ else ++ { ++ *len = 4; /* base length */ ++ ++ if (register_operand (op0, DImode)) ++ *len += 0; ++ else if (memory_operand (op0, DImode)) ++ *len += 4; ++ ++ if (register_operand (op2, DImode)) ++ *len += 0; ++ else if (memory_operand (op2, DImode)) ++ *len += 4; ++ else if (immediate_operand (op2, DImode)) ++ *len += 4; ++ else ++ abort (); ++ } ++ ++ return ""; ++} ++ ++/************** IOR CODE *********************************/ ++ ++const char * ++msp430_emit_indexed_ior2 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ emit_indexed_arith (insn, operands, 2, "bis", 0); ++ return ""; ++} ++ ++const char * ++msp430_emit_indexed_ior4 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ emit_indexed_arith (insn, operands, 4, "bis", 0); ++ return ""; ++} ++ ++const char * ++msp430_emit_immediate_ior2 (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int l = INTVAL (operands[2]); ++ int r = REG_P (operands[0]); ++ int v; ++ ++ ++ v = l & 0xffff; ++ ++ if (v) ++ { ++ OUT_INSN (len, "bis\t%A2,%A0", operands); ++ dummy++; ++ dummy++; ++ if (v == 0xffff || v == 1 || v == 2 || v == 4 || v == 8) ++ dummy--; ++ if (!r) ++ dummy++; ++ } ++ ++ v = (l >> 16) & 0xffff; ++ ++ if (v) ++ { ++ OUT_INSN (len, "bis\t%B2,%B0", operands); ++ dummy++; ++ dummy++; ++ if (v == 0xffff || v == 1 || v == 2 || v == 4 || v == 8) ++ dummy--; ++ if (!r) ++ dummy++; ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++} ++ ++const char * ++msp430_emit_immediate_ior4 (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int l = CONST_DOUBLE_LOW (operands[2]); ++ int h = CONST_DOUBLE_HIGH (operands[2]); ++ int r = REG_P (operands[0]); ++ int v; ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ l = INTVAL (operands[2]); ++ h = 0; ++ } ++ ++ v = l & 0xffff; ++ ++ if (v) ++ { ++ OUT_INSN (len, "bis\t%A2,%A0", operands); ++ dummy++; ++ dummy++; ++ if (v == 0xffff || v == 1 || v == 2 || v == 4 || v == 8) ++ dummy--; ++ if (!r) ++ dummy++; ++ } ++ ++ v = (l >> 16) & 0xffff; ++ ++ if (v) ++ { ++ OUT_INSN (len, "bis\t%B2,%B0", operands); ++ dummy++; ++ dummy++; ++ if (v == 0xffff || v == 1 || v == 2 || v == 4 || v == 8) ++ dummy--; ++ if (!r) ++ dummy++; ++ } ++ ++ l = h; ++ v = l & 0xffff; ++ ++ if (v) ++ { ++ OUT_INSN (len, "bis\t%C2,%C0", operands); ++ dummy++; ++ dummy++; ++ if (v == 0xffff || v == 1 || v == 2 || v == 4 || v == 8) ++ dummy--; ++ if (!r) ++ dummy++; ++ } ++ ++ v = (l >> 16) & 0xffff; ++ ++ if (v) ++ { ++ OUT_INSN (len, "bis\t%D2,%D0", operands); ++ dummy++; ++ dummy++; ++ if (v == 0xffff || v == 1 || v == 2 || v == 4 || v == 8) ++ dummy--; ++ if (!r) ++ dummy++; ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++} ++ ++const char * ++msp430_iorsi_code (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx op0 = operands[0]; ++ rtx op2 = operands[2]; ++ ++ if (nonimmediate_operand (op0, SImode) && immediate_operand (op2, SImode)) ++ { ++ if (!len) ++ msp430_emit_immediate_ior2 (insn, operands, NULL); ++ return ""; ++ } ++ ++ if (memory_operand (op2, SImode) ++ && zero_shifted (operands[2]) && regsi_ok_safe (operands)) ++ { ++ if (!len) ++ msp430_emit_indexed_ior2 (insn, operands, NULL); ++ else ++ { ++ if (memory_operand (op0, SImode)) ++ *len = 5; ++ else if (register_operand (op0, SImode)) ++ *len = 3; ++ } ++ ++ return ""; ++ } ++ else if (memory_operand (op2, SImode) ++ && zero_shifted (operands[2]) && regsi_ok_clobber (operands)) ++ { ++ if (!len) ++ { ++ output_asm_insn ("bis\t@%E2+, %A0", operands); ++ output_asm_insn ("bis\t@%E2+, %B0", operands); ++ } ++ else ++ { ++ if (register_operand (op0, SImode)) ++ *len = 2; ++ else if (memory_operand (op0, SImode)) ++ *len = 4; ++ else ++ abort (); ++ } ++ return ""; ++ } ++ ++ if (!len) ++ { ++ output_asm_insn ("bis\t%A2, %A0", operands); ++ output_asm_insn ("bis\t%B2, %B0", operands); ++ } ++ else ++ { ++ *len = 2; /* base length */ ++ ++ if (register_operand (op0, SImode)) ++ *len += 0; ++ else if (memory_operand (op0, SImode)) ++ *len += 2; ++ ++ if (register_operand (op2, SImode)) ++ *len += 0; ++ else if (memory_operand (op2, SImode)) ++ *len += 2; ++ else if (immediate_operand (op2, SImode)) ++ *len += 2; ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_iordi_code (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx op0 = operands[0]; ++ rtx op2 = operands[2]; ++ ++ if (nonimmediate_operand (op0, DImode) && immediate_operand (op2, DImode)) ++ { ++ if (!len) ++ msp430_emit_immediate_ior4 (insn, operands, NULL); ++ return ""; ++ } ++ ++ if (memory_operand (op2, DImode) ++ && zero_shifted (operands[2]) && regdi_ok_safe (operands)) ++ { ++ if (!len) ++ msp430_emit_indexed_ior4 (insn, operands, NULL); ++ else ++ { ++ if (memory_operand (op0, DImode)) ++ *len = 9; ++ else if (register_operand (op0, DImode)) ++ *len = 5; ++ } ++ ++ return ""; ++ } ++ else if (memory_operand (op2, DImode) ++ && zero_shifted (operands[2]) && regdi_ok_clobber (operands)) ++ { ++ if (!len) ++ { ++ output_asm_insn ("bis\t@%E2+, %A0", operands); ++ output_asm_insn ("bis\t@%E2+, %B0", operands); ++ output_asm_insn ("bis\t@%E2+, %C0", operands); ++ output_asm_insn ("bis\t@%E2+, %D0", operands); ++ } ++ else ++ { ++ if (register_operand (op0, DImode)) ++ *len = 4; ++ else if (memory_operand (op0, DImode)) ++ *len = 8; ++ else ++ abort (); ++ } ++ return ""; ++ } ++ ++ if (!len) ++ { ++ output_asm_insn ("bis\t%A2, %A0", operands); ++ output_asm_insn ("bis\t%B2, %B0", operands); ++ output_asm_insn ("bis\t%C2, %C0", operands); ++ output_asm_insn ("bis\t%D2, %D0", operands); ++ } ++ else ++ { ++ *len = 4; /* base length */ ++ ++ if (register_operand (op0, DImode)) ++ *len += 0; ++ else if (memory_operand (op0, DImode)) ++ *len += 4; ++ ++ if (register_operand (op2, DImode)) ++ *len += 0; ++ else if (memory_operand (op2, DImode)) ++ *len += 4; ++ else if (immediate_operand (op2, DImode)) ++ *len += 4; ++ else ++ abort (); ++ } ++ ++ return ""; ++} ++ ++ ++/************************* XOR CODE *****************/ ++ ++const char * ++msp430_emit_indexed_xor2 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l; ++{ ++ int dummy = emit_indexed_arith (insn, operands, 2, "xor", 0); ++ if (!l) ++ l = &dummy; ++ *l = dummy; ++ return ""; ++} ++ ++const char * ++msp430_emit_indexed_xor4 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l; ++{ ++ int dummy = emit_indexed_arith (insn, operands, 4, "xor", 0); ++ if (!l) ++ l = &dummy; ++ *l = dummy; ++ return ""; ++} ++ ++ ++const char * ++msp430_emit_indexed_xor2_3 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l; ++{ ++ int dummy; ++ rtx x = operands[2]; ++ if (zero_shifted (x)) ++ { ++ dummy = emit_indexed_arith (insn, operands, 2, "xor", 0); ++ } ++ else ++ { ++ dummy = 6; ++ output_asm_insn ("xor\t%A2, %A0", operands); ++ output_asm_insn ("xor\t%B2, %B0", operands); ++ } ++ ++ if (!l) ++ l = &dummy; ++ *l = dummy; ++ return ""; ++} ++ ++const char * ++msp430_emit_indexed_xor4_3 (insn, operands, l) ++ rtx insn; ++ rtx operands[]; ++ int *l; ++{ ++ ++ int dummy; ++ rtx x = operands[2]; ++ if (zero_shifted (x)) ++ { ++ dummy = emit_indexed_arith (insn, operands, 4, "xor", 0); ++ } ++ else ++ { ++ dummy = 8; ++ output_asm_insn ("xor\t%A2, %A0", operands); ++ output_asm_insn ("xor\t%B2, %B0", operands); ++ output_asm_insn ("xor\t%C2, %C0", operands); ++ output_asm_insn ("xor\t%D2, %D0", operands); ++ } ++ ++ if (!l) ++ l = &dummy; ++ *l = dummy; ++ return ""; ++} ++ ++const char * ++msp430_xorsi_code (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx op0 = operands[0]; ++ rtx op2 = operands[2]; ++ ++ if (memory_operand (op2, SImode) ++ && zero_shifted (operands[2]) && regsi_ok_safe (operands)) ++ { ++ if (!len) ++ msp430_emit_indexed_xor2 (insn, operands, NULL); ++ else ++ { ++ if (memory_operand (op0, SImode)) ++ *len = 5; ++ else if (register_operand (op0, SImode)) ++ *len = 3; ++ } ++ ++ return ""; ++ } ++ else if (memory_operand (op2, SImode) ++ && zero_shifted (operands[2]) && regsi_ok_clobber (operands)) ++ { ++ if (!len) ++ { ++ output_asm_insn ("xor\t@%E2+, %A0", operands); ++ output_asm_insn ("xor\t@%E2+, %B0", operands); ++ } ++ else ++ { ++ if (register_operand (op0, SImode)) ++ *len = 2; ++ else if (memory_operand (op0, SImode)) ++ *len = 4; ++ else ++ abort (); ++ } ++ return ""; ++ } ++ ++ if (!len) ++ { ++ ++ if (immediate_operand (op2, SImode)) ++ { ++ if (INTVAL (op2) & 0xfffful) ++ output_asm_insn ("xor\t%A2, %A0", operands); ++ ++ if (INTVAL (op2) & 0xffff0000ul) ++ output_asm_insn ("xor\t%B2, %B0", operands); ++ } ++ else ++ { ++ output_asm_insn ("xor\t%A2, %A0", operands); ++ output_asm_insn ("xor\t%B2, %B0", operands); ++ } ++ ++ } ++ else ++ { ++ *len = 2; /* base length */ ++ ++ if (register_operand (op0, SImode)) ++ *len += 0; ++ else if (memory_operand (op0, SImode)) ++ *len += 2; ++ ++ if (register_operand (op2, SImode)) ++ *len += 0; ++ else if (memory_operand (op2, SImode)) ++ *len += 2; ++ else if (immediate_operand (op2, SImode)) ++ { ++ if (INTVAL (op2) & 0xfffful) ++ *len += 1; ++ if (INTVAL (op2) & 0xffff0000ul) ++ *len += 1; ++ } ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_xordi_code (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx op0 = operands[0]; ++ rtx op2 = operands[2]; ++ ++ if (memory_operand (op2, DImode) ++ && zero_shifted (operands[2]) && regdi_ok_safe (operands)) ++ { ++ if (!len) ++ msp430_emit_indexed_xor4 (insn, operands, NULL); ++ else ++ { ++ if (memory_operand (op0, DImode)) ++ *len = 9; ++ else if (register_operand (op0, DImode)) ++ *len = 5; ++ } ++ ++ return ""; ++ } ++ else if (memory_operand (op2, DImode) ++ && zero_shifted (operands[2]) && regdi_ok_clobber (operands)) ++ { ++ if (!len) ++ { ++ output_asm_insn ("xor\t@%E2+, %A0", operands); ++ output_asm_insn ("xor\t@%E2+, %B0", operands); ++ output_asm_insn ("xor\t@%E2+, %C0", operands); ++ output_asm_insn ("xor\t@%E2+, %D0", operands); ++ } ++ else ++ { ++ if (register_operand (op0, DImode)) ++ *len = 4; ++ else if (memory_operand (op0, DImode)) ++ *len = 8; ++ else ++ abort (); ++ } ++ return ""; ++ } ++ ++ if (!len) ++ { ++ output_asm_insn ("xor\t%A2, %A0", operands); ++ output_asm_insn ("xor\t%B2, %B0", operands); ++ output_asm_insn ("xor\t%C2, %C0", operands); ++ output_asm_insn ("xor\t%D2, %D0", operands); ++ } ++ else ++ { ++ *len = 4; /* base length */ ++ ++ if (register_operand (op0, DImode)) ++ *len += 0; ++ else if (memory_operand (op0, DImode)) ++ *len += 4; ++ ++ if (register_operand (op2, DImode)) ++ *len += 0; ++ else if (memory_operand (op2, DImode)) ++ *len += 4; ++ else if (immediate_operand (op2, DImode)) ++ *len += 4; ++ else ++ abort (); ++ } ++ ++ return ""; ++} ++ ++ ++/********* ABS CODE ***************************************/ ++const char * ++msp430_emit_abssi (insn, operands, l) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ output_asm_insn ("tst\t%B0", operands); ++ output_asm_insn ("jge\t.Lae%=", operands); ++ output_asm_insn ("inv\t%A0", operands); ++ output_asm_insn ("inv\t%B0", operands); ++ output_asm_insn ("inc\t%A0", operands); ++ output_asm_insn ("adc\t%B0", operands); ++ output_asm_insn (".Lae%=:", operands); ++ return ""; ++} ++ ++const char * ++msp430_emit_absdi (insn, operands, l) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *l ATTRIBUTE_UNUSED; ++{ ++ output_asm_insn ("tst\t%D0", operands); ++ output_asm_insn ("jge\t.Lae%=", operands); ++ output_asm_insn ("inv\t%A0", operands); ++ output_asm_insn ("inv\t%B0", operands); ++ output_asm_insn ("inv\t%C0", operands); ++ output_asm_insn ("inv\t%D0", operands); ++ output_asm_insn ("inc\t%A0", operands); ++ output_asm_insn ("adc\t%B0", operands); ++ output_asm_insn ("adc\t%C0", operands); ++ output_asm_insn ("adc\t%D0", operands); ++ output_asm_insn (".Lae%=:", operands); ++ return ""; ++} ++ ++ ++/***** SIGN EXTEND *********/ ++const char * ++signextendqihi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ ++ if (!sameoperand (operands, 1)) ++ { ++ OUT_INSN (len, "mov.b\t%A1, %A0", operands); ++ dummy = 3; ++ if (indexed_location (operands[1])) ++ dummy = 2; ++ if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ if (GET_CODE (operands[1]) == REG) ++ dummy--; ++ } ++ ++ OUT_INSN (len, "sxt\t%A0", operands); ++ dummy += 2; ++ ++ if (zs || GET_CODE (operands[0]) == REG) ++ dummy -= 1; ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++const char * ++signextendqisi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ ++ if (!sameoperand (operands, 1)) ++ { ++ OUT_INSN (len, "mov.b\t%A1, %A0", operands); ++ dummy = 3; ++ if (indexed_location (operands[1])) ++ dummy = 2; ++ if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ if (GET_CODE (operands[1]) == REG) ++ dummy--; ++ } ++ ++ OUT_INSN (len, "sxt\t%A0", operands); ++ OUT_INSN (len, "mov\t%A0, %B0", operands); ++ OUT_INSN (len, "rla\t%B0", operands); ++ OUT_INSN (len, "subc\t%B0, %B0", operands); ++ OUT_INSN (len, "inv\t%B0", operands); ++ ++ if (GET_CODE (operands[0]) == REG) ++ dummy += 5; ++ else if (zs) ++ dummy += 10; ++ else ++ dummy += 12; ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++const char * ++signextendqidi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ ++ if (!sameoperand (operands, 1)) ++ { ++ OUT_INSN (len, "mov.b\t%A1, %A0", operands); ++ dummy = 3; ++ if (indexed_location (operands[1])) ++ dummy = 2; ++ if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ if (GET_CODE (operands[1]) == REG) ++ dummy--; ++ } ++ ++ OUT_INSN (len, "sxt\t%A0", operands); ++ OUT_INSN (len, "mov\t%A0, %B0", operands); ++ OUT_INSN (len, "rla\t%B0", operands); ++ OUT_INSN (len, "subc\t%B0, %B0", operands); ++ OUT_INSN (len, "inv\t%B0", operands); ++ OUT_INSN (len, "mov\t%B0, %C0", operands); ++ OUT_INSN (len, "mov\t%C0, %D0", operands); ++ ++ ++ if (GET_CODE (operands[0]) == REG) ++ dummy += 7; ++ else if (zs) ++ dummy += 16; ++ else ++ dummy += 18; ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++const char * ++signextendhisi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ ++ if (!sameoperand (operands, 1)) ++ { ++ OUT_INSN (len, "mov\t%A1, %A0", operands); ++ dummy = 3; ++ if (indexed_location (operands[1])) ++ dummy = 2; ++ if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ if (GET_CODE (operands[1]) == REG) ++ dummy--; ++ } ++ ++ OUT_INSN (len, "mov\t%A0, %B0", operands); ++ OUT_INSN (len, "rla\t%B0", operands); ++ OUT_INSN (len, "subc\t%B0, %B0", operands); ++ OUT_INSN (len, "inv\t%B0", operands); ++ ++ if (GET_CODE (operands[0]) == REG) ++ dummy += 4; ++ else if (zs) ++ dummy += 9; ++ else ++ dummy += 11; ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++const char * ++signextendhidi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ ++ if (!sameoperand (operands, 1)) ++ { ++ OUT_INSN (len, "mov\t%A1, %A0", operands); ++ dummy = 3; ++ if (indexed_location (operands[1])) ++ dummy = 2; ++ if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ if (GET_CODE (operands[1]) == REG) ++ dummy--; ++ } ++ ++ OUT_INSN (len, "mov\t%A0, %B0", operands); ++ OUT_INSN (len, "rla\t%B0", operands); ++ OUT_INSN (len, "subc\t%B0, %B0", operands); ++ OUT_INSN (len, "inv\t%B0", operands); ++ OUT_INSN (len, "mov\t%B0, %C0", operands); ++ OUT_INSN (len, "mov\t%C0, %D0", operands); ++ ++ if (GET_CODE (operands[0]) == REG) ++ dummy += 6; ++ else if (zs) ++ dummy += 13; ++ else ++ dummy += 14; ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++const char * ++signextendsidi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ ++ if (!sameoperand (operands, 1)) ++ { ++ OUT_INSN (len, "mov\t%A1, %A0", operands); ++ OUT_INSN (len, "mov\t%B1, %B0", operands); ++ dummy = 6; ++ if (indexed_location (operands[1])) ++ dummy = 4; ++ if (GET_CODE (operands[0]) == REG) ++ dummy -= 2; ++ if (GET_CODE (operands[1]) == REG) ++ dummy -= 2; ++ } ++ ++ OUT_INSN (len, "mov\t%B0, %C0", operands); ++ OUT_INSN (len, "rla\t%C0", operands); ++ OUT_INSN (len, "subc\t%C0, %C0", operands); ++ OUT_INSN (len, "inv\t%C0", operands); ++ OUT_INSN (len, "mov\t%C0, %D0", operands); ++ ++ if (GET_CODE (operands[0]) == REG) ++ dummy += 5; ++ else ++ dummy += 13; ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++ ++/**** ZERO EXTEND *****/ ++ ++const char * ++zeroextendqihi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[1]) || indexed_location (operands[1]); ++ ++ if(operands[0] == op2_rtx) ++ { ++ OUT_INSN (len, "and #0xff00, %0",operands); ++ dummy = 3; ++ return ""; ++ } ++ if (!sameoperand (operands, 1)) ++ { ++ OUT_INSN (len, "mov.b\t%A1, %A0", operands); ++ dummy = 3; ++ if (zs) ++ dummy = 2; ++ if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ if (GET_CODE (operands[1]) == REG) ++ dummy--; ++ } ++ ++ if (!REG_P (operands[0])) ++ { ++ OUT_INSN (len, "clr.b\t%J0", operands); ++ dummy += 2; ++ } ++ else if (sameoperand (operands, 1)) ++ { ++ OUT_INSN (len, "and.b\t#-1,%0", operands); ++ dummy++; ++ } ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++const char * ++zeroextendqisi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[1]) || indexed_location (operands[1]); ++ ++ if (!sameoperand (operands, 1) || REG_P (operands[0])) ++ { ++ OUT_INSN (len, "mov.b\t%A1, %A0", operands); ++ dummy = 3; ++ if (zs) ++ dummy = 2; ++ if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ if (GET_CODE (operands[1]) == REG) ++ dummy--; ++ } ++ ++ ++ if (!REG_P (operands[0])) ++ { ++ OUT_INSN (len, "clr.b\t%J0", operands); ++ } ++ else if (sameoperand (operands, 1)) ++ { ++ OUT_INSN (len, "and.b\t#-1,%0", operands); ++ dummy++; ++ } ++ OUT_INSN (len, "clr\t%B0", operands); ++ dummy += 2; ++ if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++ ++const char * ++zeroextendqidi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[1]) || indexed_location (operands[1]); ++ ++ if (!sameoperand (operands, 1) || REG_P (operands[0])) ++ { ++ OUT_INSN (len, "mov.b\t%A1, %A0", operands); ++ dummy = 3; ++ if (zs) ++ dummy = 2; ++ if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ if (GET_CODE (operands[1]) == REG) ++ dummy--; ++ } ++ ++ if (!REG_P (operands[0])) ++ { ++ OUT_INSN (len, "clr.b\t%J0", operands); ++ dummy += 2; ++ } ++ else if (sameoperand (operands, 1)) ++ { ++ OUT_INSN (len, "and.b\t#-1,%0", operands); ++ dummy++; ++ } ++ dummy += 6; ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%C0", operands); ++ OUT_INSN (len, "clr\t%D0", operands); ++ ++ if (GET_CODE (operands[0]) == REG && len) ++ *len -= 3; ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++const char * ++zeroextendhisi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[1]) || indexed_location (operands[1]); ++ ++ if (!sameoperand (operands, 1)) ++ { ++ OUT_INSN (len, "mov\t%A1, %A0", operands); ++ dummy = 3; ++ if (zs) ++ dummy = 2; ++ if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ if (GET_CODE (operands[1]) == REG) ++ dummy--; ++ } ++ ++ OUT_INSN (len, "clr\t%B0", operands); ++ dummy += 2; ++ if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++ ++} ++ ++const char * ++zeroextendhidi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[1]) || indexed_location (operands[1]); ++ ++ if (!sameoperand (operands, 1)) ++ { ++ OUT_INSN (len, "mov\t%A1, %A0", operands); ++ dummy = 3; ++ if (zs) ++ dummy = 2; ++ if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ if (GET_CODE (operands[1]) == REG) ++ dummy--; ++ } ++ ++ dummy += 6; ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%C0", operands); ++ OUT_INSN (len, "clr\t%D0", operands); ++ ++ if (GET_CODE (operands[0]) == REG) ++ dummy -= 3; ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++const char * ++zeroextendsidi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ ++ if (!sameoperand (operands, 1)) ++ { ++ if (zero_shifted (operands[1])) ++ { ++ rtx reg = XEXP (operands[1], 0); ++ ++ OUT_INSN (len, "mov\t@%E1+, %A0", operands); ++ OUT_INSN (len, "mov\t@%E1+, %B0", operands); ++ dummy = 4; ++ if (GET_CODE (operands[0]) == REG) ++ dummy -= 2; ++ ++ if (!dead_or_set_p (insn, reg)) ++ { ++ OUT_INSN (len, "sub\t#4, %E1", operands); ++ dummy += 1; ++ } ++ } ++ else ++ { ++ OUT_INSN (len, "mov\t%A1, %A0", operands); ++ OUT_INSN (len, "mov\t%B1, %B0", operands); ++ dummy = 6; ++ if (GET_CODE (operands[0]) == REG) ++ dummy -= 2; ++ if (GET_CODE (operands[1]) == REG) ++ dummy -= 2; ++ if (indexed_location (operands[1])) ++ dummy--; ++ } ++ } ++ ++ dummy += 4; ++ OUT_INSN (len, "clr\t%C0", operands); ++ OUT_INSN (len, "clr\t%D0", operands); ++ ++ if (GET_CODE (operands[0]) == REG) ++ dummy -= 2; ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++/******************* TESTS AND JUMPS *********************/ ++ ++RTX_CODE ++msp430_canonicalize_comparison (code, op0, op1) ++ RTX_CODE code; ++ rtx *op0; ++ rtx *op1; ++{ ++ RTX_CODE rc = code; ++ ++ if ( CONSTANT_P(*op1) ) ++ { ++ ; /* nothing to be done */ ++ } ++ else ++ { ++ switch (code) ++ { ++ case GT: ++ case LE: ++ case GTU: ++ case LEU: ++ { ++ rtx x; ++ rc = swap_condition (code); ++ x = *op0; ++ *op0 = *op1; ++ *op1 = x; ++ } ++ break; ++ default: ++ break; ++ } ++ } ++ return rc; ++} ++ ++ ++void ++msp430_emit_cbranch (code, loc) ++ enum rtx_code code; ++ rtx loc; ++{ ++ rtx op0 = msp430_compare_op0; ++ rtx op1 = msp430_compare_op1; ++ rtx condition_rtx, loc_ref, branch; ++ enum machine_mode mode; ++ int mem_volatil=0; ++ ++ if (!msp430_compare_op0 && !msp430_compare_op1) ++ { ++ /* this is a branch upon previous insn issued */ ++ loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc); ++ condition_rtx = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx); ++ ++ branch = gen_rtx_SET (VOIDmode, ++ pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ condition_rtx, ++ loc_ref, pc_rtx)); ++ emit_jump_insn (branch); ++ return; ++ } ++ ++ mode = GET_MODE (op0); ++ if (mode != SImode && mode != HImode && mode != QImode) ++ abort (); ++ ++ ++ /* now convert codes */ ++ code = msp430_canonicalize_comparison (code, &op0, &op1); ++ ++ /* for HI and QI modes everything is simple. ++ Also, if code is eq or ne in SI mode, no clobbers required. */ ++ ++ if (mode == SImode && !(code == EQ || code == NE)) ++ { ++ /* check if only high nibbles required */ ++ if (GET_CODE (op1) == CONST_INT ++ && INTVAL (op1) == 0 && (code == LT || code == GE)) ++ { ++ mem_volatil = MEM_VOLATILE_P(op0); ++ MEM_VOLATILE_P(op0) = 0; ++ op0 = gen_highpart (HImode, op0); ++ MEM_VOLATILE_P(op0) = mem_volatil; ++ mode = HImode; ++ PUT_MODE (op1, VOIDmode); /* paranoia ? */ ++ } ++ else if (GET_CODE (op1) == CONST_INT ++ && ((INTVAL (op1) + 1) & 0xffff) == 0 ++ && (code == GT || code == GTU || code == LE || code == LEU)) ++ { ++ /* check if this can be done simple. ++ we will not clobber const operand. */ ++ int x = INTVAL (op1); ++ x++; ++ x >>= 16; ++ MEM_VOLATILE_P(op0) = 0; ++ op0 = gen_highpart (HImode, op0); ++ MEM_VOLATILE_P(op0) = mem_volatil; ++ mode = HImode; ++ op1 = GEN_INT (trunc_int_for_mode (x, HImode)); ++ ++ if (code == GT) ++ code = GE; ++ else if (code == GTU) ++ code = GEU; ++ else if (code == LEU) ++ code = LTU; ++ else if (code == LE) ++ code = LT; ++ } ++ else ++ { ++ rtvec vec; ++ /* the redudant move will be deleted */ ++ op0 = copy_to_mode_reg (SImode, op0); ++ condition_rtx = gen_rtx (code, mode, op0, op1); ++ loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc); ++ branch = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, ++ loc_ref, pc_rtx)); ++ vec = gen_rtvec (2, branch, gen_rtx_CLOBBER (SImode, op0)); ++ emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec)); ++ msp430_compare_op0 = 0; ++ msp430_compare_op1 = 0; ++ return; ++ } ++ } ++ else if(mode == SImode && code == NE ++ && GET_CODE(op1)!= CONST_INT && op1 != const0_rtx) ++ { ++ rtx op0lo, op0hi, op1lo, op1hi; ++ ++ mem_volatil = MEM_VOLATILE_P(op0); ++ op0lo = gen_lowpart(HImode, op0); ++ op0hi = gen_highpart(HImode, op0); ++ MEM_VOLATILE_P(op0) = mem_volatil; ++ ++ mem_volatil = MEM_VOLATILE_P(op1); ++ op1lo = gen_lowpart(HImode, op1); ++ op1hi = gen_highpart(HImode, op1); ++ MEM_VOLATILE_P(op1) = mem_volatil; ++ ++ condition_rtx = gen_rtx (NE,HImode,op0lo,op1lo); ++ loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc); ++ branch = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, ++ loc_ref, pc_rtx)); ++ emit_jump_insn (branch); ++ condition_rtx = gen_rtx (NE,HImode,op0hi,op1hi); ++ branch = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, ++ loc_ref, pc_rtx)); ++ emit_jump_insn (branch); ++ msp430_compare_op0 = 0; ++ msp430_compare_op1 = 0; ++ return; ++ } ++ else if(mode == SImode && code == EQ && GET_CODE(op1)!= CONST_INT ) ++ { ++ rtx tlabel = gen_label_rtx(); ++ rtx tloc_ref; ++ rtx op0lo, op0hi, op1lo, op1hi; ++ ++ mem_volatil = MEM_VOLATILE_P(op0); ++ op0lo = gen_lowpart(HImode, op0); ++ op0hi = gen_highpart(HImode, op0); ++ MEM_VOLATILE_P(op0) = mem_volatil; ++ ++ mem_volatil = MEM_VOLATILE_P(op1); ++ op1lo = gen_lowpart(HImode, op1); ++ op1hi = gen_highpart(HImode, op1); ++ MEM_VOLATILE_P(op1) = mem_volatil; ++ ++ condition_rtx = gen_rtx (NE,HImode,op0lo,op1lo); ++ tloc_ref = gen_rtx_LABEL_REF (VOIDmode, tlabel); ++ branch = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, ++ tloc_ref, pc_rtx)); ++ emit_jump_insn (branch); ++ ++ condition_rtx = gen_rtx (EQ,HImode,op0hi,op1hi); ++ loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc); ++ branch = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, ++ loc_ref, pc_rtx)); ++ emit_jump_insn (branch); ++ emit_label(tlabel); ++ msp430_compare_op0 = 0; ++ msp430_compare_op1 = 0; ++ return ; ++ } ++ ++ condition_rtx = gen_rtx (code, mode, op0, op1); ++ loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc); ++ branch = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, ++ loc_ref, pc_rtx)); ++ ++ emit_jump_insn (branch); ++ ++ msp430_compare_op0 = 0; ++ msp430_compare_op1 = 0; ++ return; ++} ++ ++ ++/* x - dst ++ y - src */ ++static int ++msp430_cc_source (insn, code, x, y) ++ rtx insn; ++ enum rtx_code code ATTRIBUTE_UNUSED; ++ rtx x; ++ rtx y; ++{ ++ rtx prev = insn; ++ enum attr_cc cc; ++ rtx set; ++ rtx src, dst; ++ rtx x1 = 0; ++ ++ if(GET_CODE(x) == MEM) ++ { ++ x1 = XEXP(x,0); ++ if(GET_CODE(x1) == PLUS) ++ { ++ x1 = XEXP(x1,0); ++ } ++ ++ if(!REG_P(x1)) x1 = 0; ++ } ++ ++ while (0 != (prev = PREV_INSN (prev))) ++ { ++ if (GET_CODE (prev) == CODE_LABEL ++ || GET_CODE (prev) == BARRIER || GET_CODE (prev) == CALL_INSN) ++ return 0; ++ ++ if (GET_CODE (prev) == INSN) ++ { ++ set = single_set (prev); ++ ++ if(!set) ++ return 0; ++ ++ cc = get_attr_cc (prev); ++ ++ if (cc == CC_NONE) /* does not change CC */ ++ { ++ /*The one spot by Nick C. */ ++ dst = SET_DEST (set); ++ if((dst && rtx_equal_p (x, dst)) || ++ (x1 && dst && rtx_equal_p (x1, dst))) ++ return 0; ++ else ++ continue; ++ } ++ ++ if (cc == CC_CLOBBER) /* clobber */ ++ return 0; ++ ++ if (cc == CC_OPER) /* post-incremental stuff */ ++ { ++ src = SET_SRC (set); ++ if (GET_CODE (set) == IOR) /* does not change CC */ ++ { ++ dst = SET_DEST (set); ++ if(dst && rtx_equal_p (x, dst)) ++ return 0; ++ else ++ continue; ++ } ++ } ++ ++ /* all other attributes are bit messy. ++ So, we'll record destination and check if ++ this matches 'x' and compare is against zero */ ++ dst = SET_DEST (set); ++ if (rtx_equal_p (x, dst) && rtx_equal_p (y, const0_rtx)) ++ return 1; ++ else ++ return 0; ++ } ++ else if (GET_CODE (prev) == JUMP_INSN) ++ { ++ /* if 2 consequent jump insns were issued, this means ++ that operands (more likely src) are different. ++ however, some jumps optimization can equalize these operands ++ and everything will be bad. Therefore, assume that ++ any jump insn clobbers condition codes.*/ ++ return 0; ++ } ++ } ++ return 0; ++} ++ ++ ++ ++const char * ++msp430_cbranch (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ rtx ops[3]; ++ enum rtx_code code; ++ rtx locs[3]; ++ int dummy = 0; ++ enum machine_mode mode; ++ int quater = 0; ++ rtx loc = operands[0]; ++ int distance = msp430_jump_dist (loc, insn); ++ int predist = get_attr_length (insn); ++ int nooverflow = 0; ++ ++#define ECOND(f,x) do{if(!len)msp430_emit_b##f(locs,predist + x);dummy+=(predist + x);}while(0) ++ locs[0] = operands[0]; ++ ops[0] = operands[2]; ++ ops[1] = operands[3]; ++ ++ if (ops[1] && ops[0]) ++ { ++ mode = GET_MODE (operands[2]); ++ code = GET_CODE (operands[1]); ++ quater = (mode == QImode); ++ } ++ else ++ { ++ mode = HImode; ++ code = GET_CODE (operands[1]); ++ } ++ ++ /* here check wiered conditions */ ++ if (ops[1] && GET_CODE (ops[1]) == CONST_INT ++ && (code == GT || code == LE || code == GTU || code == LEU)) ++ { ++ int x = INTVAL (ops[1]); ++ switch (code) ++ { ++ case GT: ++ ops[1] = GEN_INT (x + 1); ++ code = GE; ++ break; ++ case LE: ++ ops[1] = GEN_INT (x + 1); ++ code = LT; ++ break; ++ case GTU: ++ ops[1] = GEN_INT (x + 1); ++ code = GEU; ++ break; ++ case LEU: ++ ops[1] = GEN_INT (x + 1); ++ code = LTU; ++ break; ++ default: ++ break; ++ } ++ } ++ else if (ops[1] && CONSTANT_P (ops[1]) && GET_MODE(ops[1]) == HImode ++ && (code == GT || code == LE || code == GTU || code == LEU)) ++ { ++ /* Handle pointers here */ ++ ops[1] = gen_rtx_CONST(HImode,gen_rtx_PLUS(HImode,ops[1],GEN_INT(1))); ++ ++ switch (code) ++ { ++ case GT: ++ code = GE; ++ break; ++ case LE: ++ code = LT; ++ break; ++ case GTU: ++ code = GEU; ++ break; ++ case LEU: ++ code = LTU; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ if (ops[0] != cc0_rtx && ops[1] && ops[0]) ++ { ++ if (code == NE || code == EQ) ++ { ++ /* check if op0 is zero shited - win 1 byte */ ++ if (indexed_location (ops[0]) && !CONSTANT_P (ops[1])) ++ { ++ rtx x = ops[0]; ++ ops[0] = ops[1]; ++ ops[1] = x; ++ } ++ } ++ ++ /* check if compares were not issued */ ++ if ((mode == QImode || mode == HImode) ++ && msp430_cc_source (insn, code, ops[0], ops[1])) ++ { ++ /* check if overflow can be usefull here. */ ++ if( ops[1] == const0_rtx ++ || (GET_CODE(ops[1]) == CONST_INT ++ && INTVAL(ops[1]) == 0 )) ++ { ++ if(code == LT || code == GE) ++ nooverflow = 1; ++ } ++ } ++ else if (mode == QImode || mode == HImode) ++ { ++ /* check if previous insns did not set CC correctly */ ++ if (quater) ++ OUT_INSN (len, "cmp.b\t%1, %0", ops); ++ else ++ OUT_INSN (len, "cmp\t%1, %0", ops); ++ dummy += 3; ++ if (REG_P (ops[0])) ++ dummy--; ++ if (REG_P (ops[1])) ++ dummy--; ++ if (indexed_location (ops[1])) ++ dummy--; ++ if (GET_CODE (ops[1]) == CONST_INT) ++ { ++ int x = INTVAL (ops[1]) & 0xffff; ++ if (x == 0 || x == -1 || x == 1 || x == 2 || x == 4 || x == 8) ++ dummy--; ++ } ++ } ++ ++ /* adjust distance */ ++ distance -= dummy; ++ ++ if (mode == SImode && (code == EQ || code == NE)) ++ { ++ /* compare against zero and can we clobber source register ? */ ++ if (((GET_CODE (ops[1]) == CONST_INT ++ && INTVAL (ops[1]) == 0) ++ || ops[1] == const0_rtx) ++ && REG_P (ops[0]) && dead_or_set_p (insn, ops[0])) ++ { ++ OUT_INSN (len, "bis\t%A0, %B0", ops); ++ OUT_INSN (len, "tst\t%B0", ops); ++ dummy += 2; ++ } ++ else ++ { ++ /* cannot clobber or something... */ ++ OUT_INSN (len, "cmp\t%A1, %A0", ops); ++ dummy += 3; ++ if (REG_P (ops[0])) ++ dummy--; ++ if (REG_P (ops[1])) ++ dummy--; ++ if (indexed_location (ops[1])) ++ dummy--; ++ if (GET_CODE (ops[1]) == CONST_INT) ++ { ++ int x = INTVAL (ops[1]) & 0xffff; ++ if (x == 0 || x == 1 || x == -1 || x == 2 || x == 4 ++ || x == 8) ++ dummy--; ++ } ++ distance -= dummy; ++ if (distance > 500 || distance < -500) ++ predist = 3; ++ else ++ predist = 1; ++ ++ if (code == EQ) ++ { ++ OUT_INSN (len, "jne\t.LcmpSIe%=", ops); ++ OUT_INSN (len, "cmp\t%B1, %B0", ops); ++ dummy++; ++ } ++ else ++ { ++ ECOND (ne, 0); ++ OUT_INSN (len, "cmp\t%B1, %B0", ops); ++ } ++ ++ dummy += 3; ++ if (REG_P (ops[0])) ++ dummy--; ++ if (REG_P (ops[1])) ++ dummy--; ++ if (GET_CODE (ops[1]) == CONST_INT) ++ { ++ int x = (INTVAL (ops[1]) >> 16) & 0xffff; ++ if (x == 0 || x == 0xffff || x == 1 || x == 2 || x == 4 ++ || x == 8) ++ dummy--; ++ } ++ } ++ } ++ else if (mode == SImode) ++ { ++ int dl = 0; ++ rtx oops[3]; ++ oops[0] = ops[0]; ++ oops[1] = ops[0]; ++ oops[2] = ops[1]; ++ ++ if (len) ++ msp430_subsi_code (insn, oops, &dl); ++ else ++ msp430_subsi_code (insn, oops, NULL); ++ ++ if (len) ++ { ++ /* not handeled by adjust_insn_len() */ ++ dummy += dl; ++ if (GET_CODE (ops[1]) == CONST_INT) ++ { ++ int x = (INTVAL (ops[1]) >> 16) & 0xffff; ++ if (x == 0 || x == 1 || x == -1 || x == 2 || x == 4 ++ || x == 8) ++ dummy--; ++ x = (INTVAL (ops[1]) >> 0) & 0xffff; ++ if (x == 0 || x == 1 || x == -1 || x == 2 || x == 4 ++ || x == 8) ++ dummy--; ++ } ++ } ++ } ++ } ++ ++ distance -= dummy; ++ ++ if (distance > 500 || distance < -500) ++ predist = 3; ++ else ++ predist = 1; ++ ++ /* out assembler commands if required */ ++ switch (code) ++ { ++ case EQ: ++ ECOND (eq, 0); ++ if (mode == SImode) ++ { ++ OUT_INSN (len, ".LcmpSIe%=:", operands); ++ } ++ break; ++ case NE: ++ ECOND (ne, 0); ++ break; ++ case LT: ++ if(nooverflow) ++ ECOND (ltnoovfl,0); ++ else ++ ECOND (lt, 0); ++ break; ++ case GE: ++ if(nooverflow) ++ { ++ if(len) *len += 2; ++ if(mode == QImode) ++ OUT_INSN (len, "bit.b\t#0x80, %0",ops); ++ else ++ OUT_INSN (len, "bit\t#0x8000, %0",ops); ++ } ++ ECOND (ge, 0); ++ break; ++ case LTU: ++ ECOND (ltu, 0); ++ break; ++ case GEU: ++ ECOND (geu, 0); ++ break; ++ /* hopfully the following will not occure */ ++ case LEU: ++ ECOND (leu, 1); ++ break; ++ case GT: ++ ECOND (gt, 1); ++ break; ++ case GTU: ++ ECOND (gtu, 1); ++ break; ++ case LE: ++ ECOND (le, 1); ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++} ++ ++/***************** AUXES FOR TESTS *********************/ ++ ++RTX_CODE ++followed_compare_condition (insn) ++ rtx insn; ++{ ++ rtx next = next_real_insn (insn); ++ RTX_CODE cond = UNKNOWN; ++ ++ if (next && GET_CODE (next) == JUMP_INSN) ++ { ++ rtx pat = PATTERN (next); ++ rtx src, t; ++ ++ if (GET_CODE (pat) == RETURN) ++ return UNKNOWN; ++ ++ src = SET_SRC (pat); ++ t = XEXP (src, 0); ++ cond = GET_CODE (t); ++ } ++ else if (next && GET_CODE (next) == INSN) ++ { ++ /* here, two possible : sgeu ans sltu */ ++ ++ rtx pat = PATTERN (next); ++ rtx src; ++ ++ if (!pat || GET_CODE (pat) != SET) ++ return UNKNOWN; ++ ++ src = SET_SRC (pat); ++ cond = GET_CODE (src); /* this must be IF_THEN_ELSE */ ++ if (cond != IF_THEN_ELSE) ++ return UNKNOWN; ++ } ++ return cond; ++} ++ ++/******** jumps ************/ ++ ++const char * ++msp430_emit_blt0si (operands, len) ++ rtx operands[]; ++ int len; ++{ ++ output_asm_insn ("tst\t%B2", operands); ++ switch (len) ++ { ++ case 2: ++ output_asm_insn ("jl\t%0", operands); ++ break; ++ case 4: ++ output_asm_insn ("jge\t+4", operands); ++ output_asm_insn ("br\t#%0", operands); ++ break; ++ default: ++ return "bug!!!"; ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_beq (operands, len) ++ rtx operands[]; ++ int len; ++{ ++ ++ switch (len) ++ { ++ case 1: ++ case 2: ++ output_asm_insn ("jeq\t%0", operands); ++ break; ++ case 3: ++ case 4: ++ output_asm_insn ("jne\t+4", operands); ++ output_asm_insn ("br\t#%0", operands); ++ break; ++ default: ++ return "bug!!!"; ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_bne (operands, len) ++ rtx operands[]; ++ int len; ++{ ++ ++ switch (len) ++ { ++ case 1: ++ case 2: ++ output_asm_insn ("jne\t%0", operands); ++ break; ++ case 3: ++ case 4: ++ output_asm_insn ("jeq\t+4", operands); ++ output_asm_insn ("br\t#%0", operands); ++ break; ++ default: ++ return "bug!!!"; ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_bgt (operands, len) ++ rtx operands[]; ++ int len; ++{ ++ switch (len) ++ { ++ case 2: ++ output_asm_insn ("jeq\t+2", operands); ++ output_asm_insn ("jge\t%0", operands); ++ ++ break; ++ case 4: ++ output_asm_insn ("jeq\t+6", operands); ++ output_asm_insn ("jl\t+4", operands); ++ output_asm_insn ("br\t#%0", operands); ++ break; ++ default: ++ return "bug!!!"; ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_bgtu (operands, len) ++ rtx operands[]; ++ int len; ++{ ++ switch (len) ++ { ++ case 2: ++ output_asm_insn ("jeq\t+2", operands); ++ output_asm_insn ("jhs\t%0", operands); ++ ++ break; ++ case 4: ++ output_asm_insn ("jeq\t+6", operands); ++ output_asm_insn ("jlo\t+4", operands); ++ output_asm_insn ("br\t#%0", operands); ++ break; ++ default: ++ return "bug!!!"; ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_blt (operands, len) ++ rtx operands[]; ++ int len; ++{ ++ switch (len) ++ { ++ case 1: ++ case 2: ++ output_asm_insn ("jl\t%0", operands); ++ break; ++ case 3: ++ case 4: ++ output_asm_insn ("jge\t+4", operands); ++ output_asm_insn ("br\t#%0", operands); ++ break; ++ default: ++ return "bug!!!"; ++ } ++ ++ return ""; ++} ++ ++ ++const char * ++msp430_emit_bltnoovfl (operands, len) ++ rtx operands[]; ++ int len; ++{ ++ switch (len) ++ { ++ case 1: ++ case 2: ++ output_asm_insn ("jn\t%0", operands); ++ break; ++ case 3: ++ case 4: ++ output_asm_insn ("jn\t+2",operands); ++ output_asm_insn ("jmp\t+4", operands); ++ output_asm_insn ("br\t#%0", operands); ++ break; ++ default: ++ return "bug!!!"; ++ } ++ ++ return ""; ++} ++ ++ ++ ++const char * ++msp430_emit_bltu (operands, len) ++ rtx operands[]; ++ int len; ++{ ++ switch (len) ++ { ++ case 1: ++ case 2: ++ output_asm_insn ("jlo\t%0", operands); ++ break; ++ case 3: ++ case 4: ++ output_asm_insn ("jhs\t+4", operands); ++ output_asm_insn ("br\t#%0", operands); ++ break; ++ default: ++ return "bug!!!"; ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_bge (operands, len) ++ rtx operands[]; ++ int len; ++{ ++ switch (len) ++ { ++ case 1: ++ case 2: ++ output_asm_insn ("jge\t%l0", operands); ++ break; ++ case 3: ++ case 4: ++ output_asm_insn ("jl\t+4", operands); ++ output_asm_insn ("br\t#%0", operands); ++ break; ++ default: ++ return "bug!!!"; ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_bgeu (operands, len) ++ rtx operands[]; ++ int len; ++{ ++ switch (len) ++ { ++ case 1: ++ case 2: ++ output_asm_insn ("jhs\t%l0", operands); ++ break; ++ case 3: ++ case 4: ++ output_asm_insn ("jlo\t+4", operands); ++ output_asm_insn ("br\t#%0", operands); ++ break; ++ default: ++ return "bug!!!"; ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_ble (operands, len) ++ rtx operands[]; ++ int len; ++{ ++ switch (len) ++ { ++ case 2: ++ output_asm_insn ("jeq\t%0", operands); ++ output_asm_insn ("jl\t%0", operands); ++ break; ++ case 4: ++ output_asm_insn ("jeq\t+2", operands); ++ output_asm_insn ("jge\t+4", operands); ++ output_asm_insn ("br\t#%0", operands); ++ break; ++ default: ++ return "bug!!!"; ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_bleu (operands, len) ++ rtx operands[]; ++ int len; ++{ ++ switch (len) ++ { ++ case 2: ++ output_asm_insn ("jeq\t%0", operands); ++ output_asm_insn ("jlo\t%0", operands); ++ break; ++ case 4: ++ output_asm_insn ("jeq\t+2", operands); ++ output_asm_insn ("jhs\t+4", operands); ++ output_asm_insn ("br\t#%0", operands); ++ break; ++ default: ++ return "bug!!!"; ++ } ++ ++ return ""; ++} ++ ++ ++/* SHIFT GUARDS */ ++int ++msp430_ashlhi3 (operands) ++ rtx operands[]; ++{ ++ int x; ++ rtx set, shift; ++ rtx dst; ++ ++ if (!const_int_operand (operands[2], VOIDmode)) ++ { ++ rtx op0, op1; ++ ++ op0 = force_reg (HImode, operands[0]); ++ op1 = force_reg (HImode, operands[1]); ++ operands[2] = copy_to_mode_reg (HImode, operands[2]); ++ emit_insn (gen_ashlhi3_cnt (op0, op1, operands[2])); ++ emit_move_insn (operands[0], op0); ++ return 1; ++ } ++ ++ x = INTVAL (operands[2]); ++ ++ if (x > 15 || x < 0) ++ { ++ emit_move_insn (operands[0], const0_rtx); ++ return 1; ++ } ++ ++ if (x == 0) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ return 1; ++ } ++ ++ if (x < 3) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ dst = operands[0]; ++ shift = gen_rtx_ASHIFT (HImode, dst, const1_rtx); ++ set = gen_rtx_SET (HImode, dst, shift); ++ while (x--) ++ emit_insn (set); ++ return 1; ++ } ++ ++ if (x == 15) ++ { ++ shift = gen_rtx_ASHIFT (HImode, operands[1], GEN_INT (15)); ++ set = gen_rtx_SET (HImode, operands[0], shift); ++ emit_insn (set); ++ return 1; ++ } ++ ++ if (operands[0] != operands[1]) ++ dst = copy_to_mode_reg (HImode, operands[1]); ++ else ++ dst = operands[1]; ++ if (x > 7) ++ { ++ emit_insn (gen_andhi3 (dst, dst, GEN_INT (0xff))); ++ emit_insn (gen_swpb (dst, dst)); ++ x -= 8; ++ } ++ ++ shift = gen_rtx_ASHIFT (HImode, dst, const1_rtx); ++ set = gen_rtx_SET (HImode, dst, shift); ++ ++ while (x--) ++ emit_insn (set); ++ if (dst != operands[0]) ++ emit_move_insn (operands[0], dst); ++ return 1; ++} ++ ++int ++msp430_ashlsi3 (operands) ++ rtx operands[]; ++{ ++ int x; ++ rtx shift, set, dst; ++ ++ if (!const_int_operand (operands[2], VOIDmode)) ++ { ++ rtx op0, op1; ++ ++ op0 = force_reg (SImode, operands[0]); ++ op1 = force_reg (SImode, operands[1]); ++ operands[2] = copy_to_mode_reg (HImode, operands[2]); ++ emit_insn (gen_ashlsi3_cnt (op0, op1, operands[2])); ++ emit_move_insn (operands[0], op0); ++ return 1; ++ } ++ ++ x = INTVAL (operands[2]); ++ ++ if (x >= 32 || x < 0) ++ { ++ emit_move_insn (operands[0], const0_rtx); ++ return 1; ++ } ++ ++ if (x == 0) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ return 1; ++ } ++ ++ if (x == 1) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ dst = operands[0]; ++ shift = gen_rtx_ASHIFT (SImode, dst, operands[2]); ++ set = gen_rtx_SET (SImode, dst, shift); ++ emit_insn (set); ++ return 1; ++ } ++ ++ if (operands[0] != operands[1]) ++ dst = copy_to_mode_reg (SImode, operands[1]); ++ else ++ dst = operands[1]; ++ ++ if (x == 31) ++ { ++ shift = gen_rtx_ASHIFT (SImode, operands[1], GEN_INT (31)); ++ set = gen_rtx_SET (SImode, operands[0], shift); ++ emit_insn (set); ++ return 1; ++ } ++ ++ if (x >= 16) ++ { ++ rtx dhi = gen_highpart (HImode, operands[0]); ++ rtx dlo = gen_lowpart (HImode, operands[0]); ++ rtx shi = gen_highpart (HImode, operands[1]); ++ rtx slo = gen_lowpart (HImode, operands[1]); ++ ++ emit_move_insn (dhi, slo); ++ emit_move_insn (dlo, const0_rtx); ++ x -= 16; ++ if (x) ++ { ++ rtx ops[3]; ++ ops[0] = dhi; ++ ops[1] = dhi; ++ ops[2] = GEN_INT (x); ++ msp430_ashlhi3 (ops); ++ } ++ return 1; ++ } ++ ++ if (x >= 8) ++ { ++ shift = gen_rtx_ASHIFT (SImode, dst, GEN_INT (8)); ++ set = gen_rtx_SET (SImode, dst, shift); ++ emit_insn (set); ++ x -= 8; ++ } ++ ++ shift = gen_rtx_ASHIFT (SImode, dst, GEN_INT (1)); ++ set = gen_rtx_SET (SImode, dst, shift); ++ ++ while (x--) ++ emit_insn (set); ++ if (dst != operands[0]) ++ emit_move_insn (operands[0], dst); ++ return 1; ++} ++ ++/* arithmetic right */ ++int ++msp430_ashrhi3 (operands) ++ rtx operands[]; ++{ ++ int x; ++ rtx shift, set, dst; ++ ++ if (!const_int_operand (operands[2], VOIDmode)) ++ { ++ rtx op0, op1; ++ ++ op0 = force_reg (HImode, operands[0]); ++ op1 = force_reg (HImode, operands[1]); ++ operands[2] = copy_to_mode_reg (HImode, operands[2]); ++ emit_insn (gen_ashrhi3_cnt (op0, op1, operands[2])); ++ emit_move_insn (operands[0], op0); ++ return 1; ++ } ++ ++ x = INTVAL (operands[2]); ++ if (x >= 15 || x < 0) ++ { ++ dst = gen_lowpart (QImode, operands[0]); ++ emit_move_insn (operands[0], operands[1]); ++ emit_insn (gen_swpb (operands[0], operands[0])); ++ emit_insn (gen_extendqihi2 (operands[0], dst)); ++ emit_insn (gen_swpb (operands[0], operands[0])); ++ emit_insn (gen_extendqihi2 (operands[0], dst)); ++ return 1; ++ } ++ ++ if (x == 0) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ return 1; ++ } ++ ++ if (x < 3) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ dst = operands[0]; ++ shift = gen_rtx_ASHIFTRT (HImode, dst, const1_rtx); ++ set = gen_rtx_SET (HImode, dst, shift); ++ ++ while (x--) ++ emit_insn (set); ++ return 1; ++ } ++ ++ if (operands[0] != operands[1]) ++ dst = copy_to_mode_reg (HImode, operands[1]); ++ else ++ dst = operands[1]; ++ ++ if (x >= 8) ++ { ++ rtx dlo = gen_lowpart (QImode, dst); ++ emit_insn (gen_swpb (dst, dst)); ++ emit_insn (gen_extendqihi2 (dst, dlo)); ++ x -= 8; ++ } ++ ++ shift = gen_rtx_ASHIFTRT (HImode, dst, const1_rtx); ++ set = gen_rtx_SET (HImode, dst, shift); ++ ++ while (x--) ++ emit_insn (set); ++ ++ if (dst != operands[0]) ++ emit_move_insn (operands[0], dst); ++ ++ return 1; ++} ++ ++int ++msp430_ashrsi3 (operands) ++ rtx operands[]; ++{ ++ int x; ++ rtx shift, set, dst; ++ ++ if (!const_int_operand (operands[2], VOIDmode)) ++ { ++ rtx op0, op1; ++ ++ op0 = force_reg (SImode, operands[0]); ++ op1 = force_reg (SImode, operands[1]); ++ operands[2] = copy_to_mode_reg (HImode, operands[2]); ++ emit_insn (gen_ashrsi3_cnt (op0, op1, operands[2])); ++ emit_move_insn (operands[0], op0); ++ return 1; ++ } ++ ++ x = INTVAL (operands[2]); ++ ++ if (x == 0) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ return 1; ++ } ++ ++ if (operands[0] != operands[1]) ++ dst = copy_to_mode_reg (SImode, operands[1]); ++ else ++ dst = operands[1]; ++ ++ if (x >= 31 || x < 0) ++ { ++ ++ shift = gen_rtx_ASHIFTRT (SImode, dst, GEN_INT (31)); ++ set = gen_rtx_SET (SImode, dst, shift); ++ emit_insn (set); ++ ++ if (dst != operands[0]) ++ emit_move_insn (operands[0], dst); ++ return 1; ++ } ++ ++ if (x == 1) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ dst = operands[0]; ++ shift = gen_rtx_ASHIFTRT (SImode, dst, operands[2]); ++ set = gen_rtx_SET (SImode, dst, shift); ++ emit_insn (set); ++ return 1; ++ } ++ ++ if (x >= 16) ++ { ++ rtx dlo = gen_lowpart (HImode, operands[0]); ++ rtx shi = gen_highpart (HImode, dst); ++ ++ emit_move_insn (gen_highpart (HImode, operands[0]), const0_rtx); ++ emit_insn (gen_extendhisi2 (operands[0], shi)); ++ x -= 16; ++ if (x) ++ { ++ rtx ops[3]; ++ ops[0] = dlo; ++ ops[1] = dlo; ++ ops[2] = GEN_INT (x); ++ msp430_ashrhi3 (ops); ++ } ++ return 1; ++ } ++ ++ if (x >= 8) ++ { ++ shift = gen_rtx_ASHIFTRT (SImode, dst, GEN_INT (8)); ++ set = gen_rtx_SET (SImode, dst, shift); ++ emit_insn (set); ++ x -= 8; ++ } ++ ++ shift = gen_rtx_ASHIFTRT (SImode, dst, GEN_INT (1)); ++ set = gen_rtx_SET (SImode, dst, shift); ++ ++ while (x--) ++ emit_insn (set); ++ if (dst != operands[0]) ++ emit_move_insn (operands[0], dst); ++ return 1; ++} ++ ++/* logical right */ ++int ++msp430_lshrhi3 (operands) ++ rtx operands[]; ++{ ++ int x; ++ rtx shift, set, dst; ++ ++ if (!const_int_operand (operands[2], VOIDmode)) ++ { ++ rtx op0, op1; ++ ++ op0 = force_reg (HImode, operands[0]); ++ op1 = force_reg (HImode, operands[1]); ++ operands[2] = copy_to_mode_reg (HImode, operands[2]); ++ emit_insn (gen_lshrhi3_cnt (op0, op1, operands[2])); ++ emit_move_insn (operands[0], op0); ++ return 1; ++ } ++ ++ x = INTVAL (operands[2]); ++ if (x > 15 || x < 0) ++ { ++ emit_move_insn (operands[0], const0_rtx); ++ return 1; ++ } ++ ++ if (x == 0) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ return 1; ++ } ++ ++ if (x < 3) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ dst = operands[0]; ++ shift = gen_rtx_LSHIFTRT (HImode, dst, const1_rtx); ++ set = gen_rtx_SET (HImode, dst, shift); ++ emit_insn (set); ++ x--; ++ ++ if (x) ++ { ++ shift = gen_rtx_ASHIFTRT (HImode, dst, const1_rtx); ++ set = gen_rtx_SET (HImode, dst, shift); ++ emit_insn (set); ++ } ++ return 1; ++ } ++ ++ if (x == 15) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ dst = operands[0]; ++ shift = gen_rtx_LSHIFTRT (HImode, dst, GEN_INT (15)); ++ set = gen_rtx_SET (HImode, dst, shift); ++ emit_insn (set); ++ return 1; ++ } ++ ++ if (operands[0] != operands[1]) ++ dst = copy_to_mode_reg (HImode, operands[1]); ++ else ++ dst = operands[1]; ++ ++ if (x >= 8) ++ { ++ rtx dlo = gen_lowpart (QImode, dst); ++ emit_insn (gen_swpb (dst, dst)); ++ emit_insn (gen_zero_extendqihi2 (dst, dlo)); ++ x -= 8; ++ } ++ ++ if (x) ++ { ++ shift = gen_rtx_LSHIFTRT (HImode, dst, const1_rtx); ++ set = gen_rtx_SET (HImode, dst, shift); ++ x--; ++ emit_insn (set); ++ } ++ shift = gen_rtx_ASHIFTRT (HImode, dst, const1_rtx); ++ set = gen_rtx_SET (HImode, dst, shift); ++ ++ while (x--) ++ emit_insn (set); ++ ++ if (dst != operands[0]) ++ emit_move_insn (operands[0], dst); ++ ++ return 1; ++} ++ ++int ++msp430_lshrsi3 (operands) ++ rtx operands[]; ++{ ++ int x; ++ rtx shift, set, dst; ++ ++ if (!const_int_operand (operands[2], VOIDmode)) ++ { ++ rtx op0, op1; ++ ++ op0 = force_reg (SImode, operands[0]); ++ op1 = force_reg (SImode, operands[1]); ++ operands[2] = copy_to_mode_reg (HImode, operands[2]); ++ emit_insn (gen_lshrsi3_cnt (op0, op1, operands[2])); ++ emit_move_insn (operands[0], op0); ++ return 1; ++ } ++ ++ x = INTVAL (operands[2]); ++ ++ if (x == 0) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ return 1; ++ } ++ ++ if (x == 1) ++ { ++ emit_move_insn (operands[0], operands[1]); ++ dst = operands[0]; ++ shift = gen_rtx_LSHIFTRT (SImode, dst, operands[2]); ++ set = gen_rtx_SET (SImode, dst, shift); ++ emit_insn (set); ++ return 1; ++ } ++ ++ if (x > 31 || x < 0) ++ { ++ emit_move_insn (operands[0], const0_rtx); ++ return 1; ++ } ++ ++ if (operands[0] != operands[1]) ++ dst = copy_to_mode_reg (SImode, operands[1]); ++ else ++ dst = operands[1]; ++ ++ if (x >= 16) ++ { ++ rtx dlo = gen_lowpart (HImode, operands[0]); ++ rtx shi = gen_highpart (HImode, dst); ++ ++ emit_move_insn (gen_highpart (HImode, operands[0]), const0_rtx); ++ emit_insn (gen_zero_extendhisi2 (operands[0], shi)); ++ x -= 16; ++ if (x) ++ { ++ rtx ops[3]; ++ ops[0] = dlo; ++ ops[1] = dlo; ++ ops[2] = GEN_INT (x); ++ msp430_lshrhi3 (ops); ++ } ++ return 1; ++ } ++ ++ if (x >= 8) ++ { ++ shift = gen_rtx_LSHIFTRT (SImode, dst, GEN_INT (8)); ++ set = gen_rtx_SET (SImode, dst, shift); ++ emit_insn (set); ++ x -= 8; ++ } ++ ++ if (x) ++ { ++ shift = gen_rtx_LSHIFTRT (SImode, dst, const1_rtx); ++ set = gen_rtx_SET (SImode, dst, shift); ++ emit_insn (set); ++ x--; ++ } ++ ++ shift = gen_rtx_ASHIFTRT (SImode, dst, GEN_INT (1)); ++ set = gen_rtx_SET (SImode, dst, shift); ++ ++ while (x--) ++ emit_insn (set); ++ if (dst != operands[0]) ++ emit_move_insn (operands[0], dst); ++ return 1; ++} ++ ++/******* COMMON SHIFT CODE ***************/ ++int ++is_shift_better_in_reg (operands) ++ rtx operands[]; ++{ ++ rtx x = operands[0]; ++ rtx cnt = operands[2]; ++ int size = GET_MODE_SIZE (x->mode); ++ int icnt = -1; ++ int r = 0; ++ ++ if (!optimize) ++ return 0; ++ ++ if (GET_CODE (cnt) == CONST_INT) ++ icnt = INTVAL (cnt); ++ else ++ return 1; ++ ++ switch (size) ++ { ++ case 1: ++ if (icnt != 1 && icnt != 2 && icnt != 7) ++ r = 1; ++ break; ++ case 2: ++ if (icnt != 1 && icnt != 2 && icnt != 8 && icnt != 15) ++ r = 2; ++ break; ++ case 4: ++ if (icnt != 1 ++ && icnt != 2 && icnt != 8 && icnt != 16 && icnt != 24 && icnt != 31) ++ r = 4; ++ break; ++ case 8: ++ if (icnt != 1 ++ && icnt != 2 && icnt != 16 && icnt != 32 && icnt != 48 && icnt != 63) ++ r = 8; ++ break; ++ } ++ ++ return r; ++} ++ ++ ++static int set_len PARAMS ((rtx, int, int)); ++/* for const operand2 and for SI, DI modes.*/ ++static int ++set_len (x, bl, sc) ++ rtx x; /* operand0 */ ++ int bl; /* base length in assumption of memory operand */ ++ int sc; /* shift count */ ++{ ++ int dummy; ++ int zs = zero_shifted (x); ++ int size = GET_MODE_SIZE (x->mode); ++ int sshi = 0; ++ ++ if (size == 4) ++ sshi = 1; ++ else if (size == 8) ++ sshi = 2; ++ ++ if (size == 1) ++ size++; ++ ++ if (GET_CODE (x) == REG) ++ dummy = (bl >> 1) - sshi; /* bl / 2 is not fully correct */ ++ else if (zs) ++ dummy = bl - (size >> 1) + 1; ++ else if (indexed_location (x)) ++ dummy = bl - 1; ++ else ++ dummy = bl; ++ ++ return dummy * sc; ++} ++ ++static int set_ren PARAMS ((rtx, int, int)); ++/* for const operand2 and for SI, DI modes.*/ ++static int ++set_ren (x, bl, sc) ++ rtx x; /* operand0 */ ++ int bl; /* base length in assumption of memory operand */ ++ int sc; /* shift count */ ++{ ++ int dummy; ++ ++ bl *= sc; ++ if (GET_CODE (x) == REG) ++ dummy = bl / 2; ++ else if (indexed_location (x)) ++ dummy = bl - sc; ++ else ++ dummy = bl; ++ return dummy; ++} ++ ++static int set_rel PARAMS ((rtx, int, int)); ++/* for const operand2 and for SI, DI modes.*/ ++static int ++set_rel (x, bl, sc) ++ rtx x; /* operand0 */ ++ int bl; /* base length in assumption of memory operand */ ++ int sc; /* shift count */ ++{ ++ int dummy; ++ ++ bl *= sc; ++ if (GET_CODE (x) == REG) ++ dummy = bl / 2; ++ else if (indexed_location (x)) ++ dummy = bl - sc; ++ else ++ dummy = bl; ++ dummy += sc; ++ return dummy; ++} ++ ++ ++ ++#define INST_THRESHOLD 16 ++ ++int ++msp430_emit_shift_cnt (set_len_fun, pattern, insn, operands, len, lsc) ++ int (*set_len_fun) (rtx, int, int); ++ const char *pattern; ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++ int lsc; ++{ ++ rtx op[10]; ++ int dummy = 0; ++ ++ op[0] = operands[0]; ++ op[1] = operands[1]; ++ op[2] = operands[2]; ++ op[3] = operands[3]; ++ ++ ++ OUT_INSN (len, "tst\t%2", op); ++ OUT_INSN (len, "jz\t.Lsend%=\n.Lsst%=:", op); ++ OUT_INSN (len, pattern, op); ++ OUT_INSN (len, "dec\t%2", op); ++ OUT_INSN (len, "jnz\t.Lsst%=\n.Lsend%=:", op); ++ dummy = (set_len_fun) (op[0], lsc, 1) + 4; ++ if (!REG_P (op[2]) && !indexed_location (op[2])) ++ dummy += 2; ++ ++ ++ if (len) ++ *len = dummy; ++ return 0; ++} ++ ++ ++/* <<<<<<<<<<<<< SHIFT LEFT CODE <<<<<<<<<<<<<<<<< */ ++ ++const char * ++msp430_emit_ashlqi3 (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ const char *pattern; ++ int shiftpos; ++ ++ if (zs) ++ pattern = "rla.b\t@%E0"; ++ else ++ pattern = "rla.b\t%A0"; ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ shiftpos = INTVAL (operands[2]); ++ ++ switch (shiftpos) ++ { ++ default: ++ if (zs) ++ OUT_INSN (len, "clr.b\t@%E0", operands); ++ else ++ OUT_INSN (len, "clr.b\t%A0", operands); ++ dummy = 2; ++ if (REG_P (operands[0])) ++ dummy >>= 1; ++ break; ++ ++ case 0: /* paranoia setting */ ++ dummy = 0; ++ break; ++ ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_len (operands[0], 3, 1); ++ } ++ break; ++ ++ case 7: ++ if (zs) ++ { ++ OUT_INSN (len, "rra.b\t%0", operands); ++ OUT_INSN (len, "clr.b\t%0", operands); ++ OUT_INSN (len, "rrc.b\t%0", operands); ++ dummy = 5; ++ } ++ else ++ { ++ OUT_INSN (len, "rra.b\t%0", operands); ++ OUT_INSN (len, "clr.b\t%0", operands); ++ OUT_INSN (len, "rrc.b\t%0", operands); ++ dummy = 6; ++ if (REG_P (operands[0])) ++ dummy = 3; ++ } ++ ++ break; ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ ++ } ++ else ++ { ++ msp430_emit_shift_cnt (set_len, pattern, insn, operands, len, 3); ++ } ++ ++ return ""; ++} ++ ++ ++const char * ++msp430_emit_ashlhi3 (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs; ++ const char *pattern; ++ int shiftpos; ++ ++ zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ ++ if (zs) ++ pattern = "rla\t@%E0"; ++ else ++ pattern = "rla\t%A0"; ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ shiftpos = INTVAL (operands[2]); ++ ++ switch (shiftpos) ++ { ++ case 0: /* paranoia setting */ ++ dummy = 0; ++ break; ++ ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_len (operands[0], 3, 1); ++ } ++ break; ++ ++ case 8: ++ case 9: ++ case 10: ++ case 11: ++ case 12: ++ case 13: ++ case 14: ++ if (zs) ++ { ++ dummy = 3; ++ OUT_INSN (len, "and.b\t#0xffff, %A0", operands); ++ OUT_INSN (len, "swpb\t@%E0", operands); ++ } ++ else ++ { ++ dummy = 4; ++ OUT_INSN (len, "and.b\t#0xffff, %A0", operands); ++ OUT_INSN (len, "swpb\t%A0", operands); ++ if (REG_P (operands[0])) ++ dummy = 2; ++ } ++ ++ ++ shiftpos -= 8; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_len (operands[0], 3, 1); ++ } ++ break; ++ ++ case 15: ++ if (zs) ++ { ++ OUT_INSN (len, "rra\t%0", operands); ++ OUT_INSN (len, "clr\t%0", operands); ++ OUT_INSN (len, "rrc\t%0", operands); ++ dummy = 5; ++ } ++ else ++ { ++ OUT_INSN (len, "rra\t%0", operands); ++ OUT_INSN (len, "clr\t%0", operands); ++ OUT_INSN (len, "rrc\t%0", operands); ++ dummy = 6; ++ if (REG_P (operands[0])) ++ dummy = 3; ++ } ++ ++ break; ++ ++ ++ default: ++ ++ OUT_INSN (len, "clr\t%A0", operands); ++ dummy = 2; ++ if (REG_P (operands[0])) ++ dummy = 1; ++ break; ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ } ++ else ++ { ++ msp430_emit_shift_cnt (set_len, pattern, insn, operands, len, 3); ++ } ++ ++ return ""; ++} ++ ++ ++const char * ++msp430_emit_ashlsi3 (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ ++ int dummy = 0; ++ int zs; ++ const char *pattern; ++ ++ zs = zero_shifted (operands[0]); ++ ++ if (zs) ++ pattern = "add\t@%E0+, -2(%E0)\n\taddc\t@%E0+, -2(%E0)\n\tsub\t#4, %E0"; ++ else ++ pattern = "rla\t%A0\n\trlc\t%B0"; ++ ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ int shiftpos = INTVAL (operands[2]); ++ ++ switch (shiftpos) ++ { ++ ++ case 0: ++ dummy = 0; ++ break; ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_len (operands[0], 6, 1); ++ } ++ break; ++ ++ case 8: ++ case 9: ++ case 10: ++ case 11: ++ case 12: ++ case 13: ++ case 14: ++ case 15: ++ ++ if (zs || indexed_location (operands[0])) ++ { ++ OUT_INSN (len, "xor.b\t@%E0, %B0", operands); ++ OUT_INSN (len, "xor\t@%E0, %B0", operands); ++ OUT_INSN (len, "swpb\t%B0", operands); ++ OUT_INSN (len, "and.b\t#-1, %A0", operands); ++ OUT_INSN (len, "swpb\t@%E0", operands); ++ dummy = 9; ++ } ++ else ++ { ++ OUT_INSN (len, "xor.b\t%A0, %B0", operands); ++ OUT_INSN (len, "xor\t%A0, %B0", operands); ++ OUT_INSN (len, "swpb\t%B0", operands); ++ OUT_INSN (len, "and.b\t#-1, %A0", operands); ++ OUT_INSN (len, "swpb\t%A0", operands); ++ dummy = 12; ++ if (REG_P (operands[0])) ++ dummy = 5; ++ } ++ ++ shiftpos -= 8; ++ ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_len (operands[0], 6, 1); ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ ++ break; ++ ++ case 16: ++ case 17: ++ case 18: ++ case 19: ++ case 20: ++ case 21: ++ case 22: ++ case 23: ++ ++ if (zs || indexed_location (operands[0])) ++ { ++ OUT_INSN (len, "mov\t@%E0, %B0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ dummy = 4; ++ } ++ else ++ { ++ OUT_INSN (len, "mov\t%A0, %B0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ dummy = 5; ++ if (REG_P (operands[0])) ++ dummy = 3; ++ } ++ ++ shiftpos -= 16; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_len (operands[0], 6, 1); ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ break; ++ ++ case 24: ++ case 25: ++ case 26: ++ case 27: ++ case 28: ++ case 29: ++ case 30: ++ if (zs || indexed_location (operands[0])) ++ { ++ OUT_INSN (len, "mov.b\t@%E0,%B0", operands); ++ OUT_INSN (len, "swpb\t%B0", operands); ++ OUT_INSN (len, "clr\t@%E0", operands); ++ dummy = 6; ++ } ++ else ++ { ++ OUT_INSN (len, "mov.b\t%A0,%B0", operands); ++ OUT_INSN (len, "swpb\t%B0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ dummy = 8; ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 3; ++ } ++ ++ shiftpos -= 24; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_len (operands[0], 6, 1); ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ ++ break; ++ ++ case 31: ++ if (zs || indexed_location (operands[0])) ++ { ++ OUT_INSN (len, "rra\t@%E0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "rrc\t%B0", operands); ++ dummy = 9; ++ ++ } ++ else ++ { ++ OUT_INSN (len, "rra\t%A0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "rrc\t%B0", operands); ++ dummy = 10; ++ if (REG_P (operands[0])) ++ dummy = 4; ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ break; ++ ++ default: ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ if (len) ++ *len = set_len (operands[0], 6, 1); ++ return ""; ++ break; ++ ++ } /* switch */ ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ } ++ else ++ msp430_emit_shift_cnt (set_len, pattern, insn, operands, len, 6); ++ ++ return ""; ++ ++} ++ ++const char * ++msp430_emit_ashldi3 (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ ++ int dummy = 0; ++ int zs; ++ const char *pattern; ++ ++ zs = zero_shifted (operands[0]); ++ ++ if (zs) ++ pattern = ++ "add\t@%E0+,-2(%E0)\n\taddc\t@%E0+,-2(%E0)\n\taddc\t@%E0+,-2(%E0)\n\taddc\t@%E0+,-2(%E0)\n\tsub\t#8,%E0"; ++ else ++ pattern = "rla\t%A0\n\trlc\t%B0\n\trlc\t%C0\n\trlc\t%D0"; ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ int shiftpos = INTVAL (operands[2]); ++ ++ switch (shiftpos) ++ { ++ case 0: ++ dummy = 0; ++ if (len) ++ *len = dummy; ++ break; ++ ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ case 8: ++ case 9: ++ case 10: ++ case 11: ++ case 12: ++ case 13: ++ case 14: ++ case 15: ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_len (operands[0], 12, 1); ++ } ++ if (len) ++ *len = dummy; ++ break; ++ ++ case 16: ++ case 17: ++ case 18: ++ case 19: ++ case 20: ++ case 21: ++ case 22: ++ case 23: ++ if (zs || indexed_location (operands[0])) ++ { ++ dummy = 10; ++ OUT_INSN (len, "mov\t%C0, %D0", operands); ++ OUT_INSN (len, "mov\t%B0, %C0", operands); ++ OUT_INSN (len, "mov\t@%E0, %B0", operands); ++ OUT_INSN (len, "clr\t@%E0", operands); ++ } ++ else ++ { ++ dummy = 11; ++ OUT_INSN (len, "mov\t%C0, %D0", operands); ++ OUT_INSN (len, "mov\t%B0, %C0", operands); ++ OUT_INSN (len, "mov\t%A0, %B0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ ++ } ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 4; ++ shiftpos -= 16; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_len (operands[0], 12, 1); ++ } ++ if (len) ++ *len = dummy; ++ break; ++ ++ case 24: ++ case 25: ++ case 26: ++ case 27: ++ case 28: ++ case 29: ++ case 30: ++ case 31: ++ if (zs) ++ { ++ dummy = 8; ++ OUT_INSN (len, "mov\t@%E0, %D0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%C0", operands); ++ ++ } ++ else ++ { ++ dummy = 9; ++ OUT_INSN (len, "mov\t%A0, %D0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%C0", operands); ++ } ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 4; ++ ++ shiftpos -= 16; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_len (operands[0], 12, 1); ++ } ++ ++ if (len) ++ *len = dummy; ++ break; ++ ++ case 32: ++ case 33: ++ case 34: ++ case 35: ++ case 36: ++ case 37: ++ case 38: ++ case 39: ++ case 40: ++ case 41: ++ case 42: ++ case 43: ++ case 44: ++ case 45: ++ case 46: ++ case 47: ++ ++ if (zs) ++ { ++ OUT_INSN (len, "mov\t@%E0+, %C0", operands); ++ OUT_INSN (len, "mov\t@%E0+, %D0", operands); ++ OUT_INSN (len, "sub\t#4, %E0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ dummy = 9; ++ } ++ else ++ { ++ dummy = 10; ++ OUT_INSN (len, "mov\t%A0, %C0", operands); ++ OUT_INSN (len, "mov\t%B0, %D0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ } ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 4; ++ ++ shiftpos -= 32; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_len (operands[0], 12, 1); ++ } ++ ++ if (len) ++ *len = dummy; ++ break; ++ ++ case 48: ++ case 49: ++ case 50: ++ case 51: ++ case 52: ++ case 53: ++ case 54: ++ case 55: ++ case 56: ++ case 57: ++ case 58: ++ case 59: ++ case 60: ++ case 61: ++ case 62: ++ if (zs) ++ { ++ dummy = 8; ++ OUT_INSN (len, "mov\t@%E0, %D0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%C0", operands); ++ } ++ else ++ { ++ dummy = 9; ++ OUT_INSN (len, "mov\t%A0, %D0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%C0", operands); ++ } ++ ++ shiftpos -= 48; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_len (operands[0], 12, 1); ++ } ++ ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 4; ++ if (len) ++ *len = dummy; ++ ++ break; ++ ++ case 63: ++ if (zs || indexed_location (operands[0])) ++ { ++ OUT_INSN (len, "rra\t@%E0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%C0", operands); ++ OUT_INSN (len, "clr\t%D0", operands); ++ OUT_INSN (len, "rrc\t%D0", operands); ++ dummy = 11; ++ } ++ else ++ { ++ OUT_INSN (len, "rra\t%A0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%C0", operands); ++ OUT_INSN (len, "clr\t%D0", operands); ++ OUT_INSN (len, "rrc\t%D0", operands); ++ dummy = 12; ++ if (REG_P (operands[0])) ++ dummy = 6; ++ } ++ ++ if (len) ++ *len = dummy; ++ ++ break; /* make compiler happy */ ++ ++ default: ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%C0", operands); ++ OUT_INSN (len, "clr\t%D0", operands); ++ dummy = 8; ++ if (zs) ++ dummy--; ++ if (REG_P (operands[0])) ++ dummy = 4; ++ ++ if (len) ++ *len = dummy; ++ ++ } /* switch */ ++ ++ return ""; ++ } ++ else ++ msp430_emit_shift_cnt (set_len, pattern, insn, operands, len, 12); ++ ++ return ""; /* make compiler happy */ ++} ++ ++/********* SHIFT RIGHT CODE ***************************************/ ++const char * ++msp430_emit_ashrqi3 (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ const char *pattern; ++ int shiftpos; ++ ++ if (zs) ++ pattern = "rra.b\t@%E0"; ++ else ++ pattern = "rra.b\t%A0"; ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ ++ shiftpos = INTVAL (operands[2]); ++ ++ switch (shiftpos) ++ { ++ case 0: /* paranoia setting */ ++ dummy = 0; ++ break; ++ ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += 2; ++ } ++ break; ++ ++ case 7: ++ if (zs) ++ { ++ OUT_INSN (len, "sxt\t@%E0", operands); ++ OUT_INSN (len, "swpb\t@%E0", operands); ++ OUT_INSN (len, "and.b\t#-1, %A0", operands); ++ dummy = 4; ++ } ++ else ++ { ++ OUT_INSN (len, "sxt\t%A0", operands); ++ OUT_INSN (len, "swpb\t%A0", operands); ++ OUT_INSN (len, "and.b\t#-1, %A0", operands); ++ dummy = 6; ++ } ++ if (REG_P (operands[0])) ++ dummy = 3; ++ if (len) ++ *len = dummy; ++ return ""; ++ ++ break; ++ ++ default: ++ OUT_INSN (len, "clr.b\t%A0", operands); ++ dummy = 2; ++ if (REG_P (operands[0])) ++ dummy = 1; ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ } ++ else ++ { ++ msp430_emit_shift_cnt (set_ren, pattern, insn, operands, len, 2); ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_ashrhi3 (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ const char *pattern; ++ int shiftpos; ++ ++ if (zs) ++ pattern = "rra\t@%E0"; ++ else ++ pattern = "rra\t%A0"; ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ shiftpos = INTVAL (operands[2]); ++ ++ switch (shiftpos) ++ { ++ case 0: /* paranoia setting */ ++ dummy = 0; ++ break; ++ ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += 2; ++ } ++ if (zs || REG_P (operands[0])) ++ dummy >>= 1; ++ break; ++ ++ case 8: ++ case 9: ++ case 10: ++ case 11: ++ case 12: ++ case 13: ++ case 14: ++ if (zs) ++ { ++ OUT_INSN (len, "swpb\t@%E0", operands); ++ OUT_INSN (len, "sxt\t@%E0", operands); ++ dummy = 2; ++ } ++ else ++ { ++ OUT_INSN (len, "swpb\t%A0", operands); ++ OUT_INSN (len, "sxt\t%A0", operands); ++ dummy = 4; ++ if (REG_P (operands[0])) ++ dummy = 2; ++ } ++ shiftpos -= 8; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += (zs || REG_P (operands[0])) ? 1 : 2; ++ } ++ break; ++ ++ case 15: ++ if (zs) ++ { ++ OUT_INSN (len, "swpb\t@%E0", operands); ++ OUT_INSN (len, "sxt\t@%E0", operands); ++ OUT_INSN (len, "swpb\t@%E0", operands); ++ OUT_INSN (len, "swpb\t@%E0", operands); ++ dummy = 4; ++ } ++ else ++ { ++ OUT_INSN (len, "swpb\t%A0", operands); ++ OUT_INSN (len, "sxt\t%A0", operands); ++ OUT_INSN (len, "swpb\t%A0", operands); ++ OUT_INSN (len, "sxt\t%A0", operands); ++ dummy = 8; ++ } ++ if (REG_P (operands[0])) ++ dummy = 4; ++ break; ++ ++ default: ++ OUT_INSN (len, "clr\t%A0", operands); ++ dummy = 2; ++ if (REG_P (operands[0])) ++ dummy = 1; ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ } ++ else ++ { ++ msp430_emit_shift_cnt (set_ren, pattern, insn, operands, len, 2); ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_ashrsi3 (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ ++ int dummy = 0; ++ const char *pattern; ++ int zs = zero_shifted (operands[0]); ++ ++ pattern = "rra\t%B0\n\trrc\t%A0"; ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ int shiftpos = INTVAL (operands[2]); ++ ++ switch (shiftpos) ++ { ++ case 0: ++ dummy = 0; ++ break; ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_ren (operands[0], 4, 1); ++ } ++ break; ++ ++ case 8: ++ case 9: ++ case 10: ++ case 11: ++ case 12: ++ case 13: ++ case 14: ++ case 15: ++ OUT_INSN (len, "swpb\t%A0", operands); ++ OUT_INSN (len, "swpb\t%B0", operands); ++ OUT_INSN (len, "xor.b\t%B0, %A0", operands); ++ OUT_INSN (len, "xor\t%B0, %A0", operands); ++ OUT_INSN (len, "sxt\t%B0", operands); ++ dummy = 12; ++ ++ if (REG_P (operands[0])) ++ dummy = 5; ++ shiftpos -= 8; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_ren (operands[0], 4, 1); ++ } ++ break; ++ ++ case 16: ++ case 17: ++ case 18: ++ case 19: ++ case 20: ++ case 21: ++ case 22: ++ case 23: ++ OUT_INSN (len, "mov\t%B0, %A0", operands); ++ OUT_INSN (len, "bit\t#0x8000, %B0", operands); ++ OUT_INSN (len, "jz\t.Lsrc%=", operands); ++ OUT_INSN (len, "bis\t#0xffff, %B0", operands); ++ OUT_INSN (len, "jmp\t.Lsre%=\n.Lsrc%=:", operands); ++ OUT_INSN (len, "clr\t%B0\n.Lsre%=:", operands); ++ dummy = 12; ++ ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 7; ++ ++ shiftpos -= 16; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, "rra\t%A0", operands); ++ dummy += 2; ++ if (GET_CODE (operands[0]) == REG || zs) ++ dummy--; ++ } ++ ++ break; ++ ++ case 24: ++ case 25: ++ case 26: ++ case 27: ++ case 28: ++ case 29: ++ case 30: ++ OUT_INSN (len, "swpb\t%B0", operands); ++ OUT_INSN (len, "sxt\t%B0", operands); ++ OUT_INSN (len, "mov\t%B0, %A0", operands); ++ OUT_INSN (len, "swpb\t%B0", operands); ++ OUT_INSN (len, "sxt\t%B0", operands); ++ dummy = 11; ++ ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 5; ++ ++ shiftpos -= 24; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, "rra\t%A0", operands); ++ dummy += 2; ++ if (GET_CODE (operands[0]) == REG || zs) ++ dummy--; ++ } ++ break; ++ ++ case 31: ++ OUT_INSN (len, "tst\t%B0", operands); ++ OUT_INSN (len, "mov\t#-1,%B0", operands); ++ OUT_INSN (len, "mov\t#-1,%A0", operands); ++ if (GET_CODE (operands[0]) == REG) ++ OUT_INSN (len, "jn\t+4", operands); ++ else ++ OUT_INSN (len, "jn\t+8", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ dummy = 11; ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 6; ++ break; ++ ++ default: ++ dummy = 0; /* leave it alone!!! */ ++ break; ++ ++ } /* switch */ ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ } ++ else ++ msp430_emit_shift_cnt (set_ren, pattern, insn, operands, len, 4); ++ ++ return ""; ++ ++} ++ ++const char * ++msp430_emit_ashrdi3 (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ ++ int dummy = 0; ++ const char *pattern; ++ ++ pattern = "rra\t%D0\n\trrc\t%C0\n\trrc\t%B0\n\trrc\t%A0"; ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ int shiftpos = INTVAL (operands[2]); ++ ++ switch (shiftpos) ++ { ++ case 0: ++ dummy = 0; ++ break; ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ case 8: ++ case 9: ++ case 10: ++ case 11: ++ case 12: ++ case 13: ++ case 14: ++ case 15: ++ while (shiftpos--) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_ren (operands[0], 8, 1); ++ } ++ break; ++ ++ case 16: ++ case 17: ++ case 18: ++ case 19: ++ case 20: ++ case 21: ++ case 22: ++ case 23: ++ case 24: ++ case 25: ++ case 26: ++ case 27: ++ case 28: ++ case 29: ++ case 30: ++ case 31: ++ ++ OUT_INSN (len, "mov\t%B0, %A0", operands); ++ OUT_INSN (len, "mov\t%C0, %B0", operands); ++ OUT_INSN (len, "mov\t%D0, %C0", operands); ++ OUT_INSN (len, "swpb\t%D0", operands); ++ OUT_INSN (len, "sxt\t%D0", operands); ++ OUT_INSN (len, "swpb\t%D0", operands); ++ OUT_INSN (len, "sxt\t%D0", operands); ++ ++ dummy = 17; ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 7; ++ shiftpos -= 16; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, "rra\t%C0\n\trrc\t%B0\n\trrc\t%A0", operands); ++ dummy += set_ren (operands[0], 6, 1); ++ } ++ ++ break; ++ ++ case 32: ++ case 33: ++ case 34: ++ case 35: ++ case 36: ++ case 37: ++ case 38: ++ case 39: ++ case 40: ++ case 41: ++ case 42: ++ case 43: ++ case 44: ++ case 45: ++ case 46: ++ case 47: ++ OUT_INSN (len, "mov\t%C0, %A0", operands); ++ OUT_INSN (len, "mov\t%D0, %B0", operands); ++ OUT_INSN (len, "swpb\t%D0", operands); ++ OUT_INSN (len, "sxt\t%D0", operands); ++ OUT_INSN (len, "swpb\t%D0", operands); ++ OUT_INSN (len, "sxt\t%D0", operands); ++ OUT_INSN (len, "mov\t%D0, %C0", operands); ++ dummy = 17; ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 8; ++ shiftpos -= 32; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, "rra\t%B0\n\trrc\t%A0", operands); ++ dummy += set_ren (operands[0], 4, 1); ++ } ++ break; ++ ++ case 48: ++ case 49: ++ case 50: ++ case 51: ++ case 52: ++ case 53: ++ case 54: ++ case 55: ++ case 56: ++ case 57: ++ case 58: ++ case 59: ++ case 60: ++ case 61: ++ case 62: ++ OUT_INSN (len, "mov\t%D0, %A0", operands); ++ OUT_INSN (len, "swpb\t%D0", operands); ++ OUT_INSN (len, "sxt\t%D0", operands); ++ OUT_INSN (len, "swpb\t%D0", operands); ++ OUT_INSN (len, "sxt\t%D0", operands); ++ OUT_INSN (len, "mov\t%D0, %C0", operands); ++ OUT_INSN (len, "mov\t%D0, %B0", operands); ++ dummy = 17; ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 7; ++ shiftpos -= 48; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, "rra\t%A0", operands); ++ dummy += set_ren (operands[0], 2, 1); ++ } ++ break; ++ ++ case 63: ++ OUT_INSN (len, "swpb\t%D0", operands); ++ OUT_INSN (len, "sxt\t%D0", operands); ++ OUT_INSN (len, "swpb\t%D0", operands); ++ OUT_INSN (len, "sxt\t%D0", operands); ++ OUT_INSN (len, "mov\t%D0, %C0", operands); ++ OUT_INSN (len, "mov\t%D0, %B0", operands); ++ OUT_INSN (len, "mov\t%D0, %A0", operands); ++ dummy = 17; ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 7; ++ break; ++ ++ default: ++ dummy = 0; ++ ++ } /* case */ ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ } ++ else ++ msp430_emit_shift_cnt (set_ren, pattern, insn, operands, len, 8); ++ return ""; ++} ++ ++/********* LOGICAL SHIFT RIGHT CODE ***************************************/ ++const char * ++msp430_emit_lshrqi3 (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ const char *pattern; ++ const char *second_pat; ++ int shiftpos; ++ ++ if (zs) ++ { ++ pattern = "clrc\n\trrc.b\t@%E0"; ++ second_pat = "rra.b\t@%E0"; ++ } ++ else ++ { ++ pattern = "clrc\n\trrc.b\t%A0"; ++ second_pat = "rra.b\t%A0"; ++ } ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ ++ shiftpos = INTVAL (operands[2]); ++ ++ if (shiftpos != 7 && shiftpos) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_rel (operands[0], 2, 1); ++ shiftpos--; ++ } ++ ++ switch (shiftpos) ++ { ++ case 0: ++ break; ++ ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ ++ while (shiftpos--) ++ { ++ OUT_INSN (len, second_pat, operands); ++ dummy += set_rel (operands[0], 2, 1) - 1; ++ } ++ ++ break; ++ ++ case 7: ++ if (zs) ++ { ++ OUT_INSN (len, "rla.b\t@%E0", operands); ++ OUT_INSN (len, "clr.b\t%A0", operands); ++ OUT_INSN (len, "rlc.b\t@%E0", operands); ++ dummy = 4; ++ } ++ else ++ { ++ OUT_INSN (len, "rla.b\t%A0", operands); ++ OUT_INSN (len, "clr.b\t%A0", operands); ++ OUT_INSN (len, "rlc.b\t%A0", operands); ++ dummy = 6; ++ } ++ if (REG_P (operands[0])) ++ dummy = 3; ++ break; ++ ++ default: ++ OUT_INSN (len, "clr.b\t%A0", operands); ++ dummy = 2; ++ if (REG_P (operands[0])) ++ dummy = 1; ++ break; ++ } ++ ++ if (len) ++ *len = dummy; ++ } ++ else ++ { ++ msp430_emit_shift_cnt (set_rel, pattern, insn, operands, len, 2); ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_lshrhi3 (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ const char *pattern; ++ const char *second_pat; ++ int shiftpos; ++ ++ if (zs) ++ { ++ pattern = "clrc\n\trrc\t@%E0"; ++ second_pat = "rra\t@%E0"; ++ } ++ else ++ { ++ pattern = "clrc\n\trrc\t%A0"; ++ second_pat = "rra\t%A0"; ++ } ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ shiftpos = INTVAL (operands[2]); ++ ++ if (shiftpos < 8 && shiftpos) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_rel (operands[0], 2, 1); ++ shiftpos--; ++ } ++ ++ switch (shiftpos) ++ { ++ case 0: ++ break; ++ ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ ++ while (shiftpos--) ++ { ++ OUT_INSN (len, second_pat, operands); ++ dummy += set_rel (operands[0], 2, 1) - 1; ++ } ++ ++ break; ++ ++ case 8: ++ case 9: ++ case 10: ++ case 11: ++ case 12: ++ case 13: ++ case 14: ++ ++ if (zs) ++ { ++ OUT_INSN (len, "swpb\t@%E0", operands); ++ OUT_INSN (len, "and.b\t#-1, %A0", operands); ++ dummy = 3; ++ } ++ else ++ { ++ OUT_INSN (len, "swpb\t%A0", operands); ++ OUT_INSN (len, "and.b\t#-1, %A0", operands); ++ dummy = 4; ++ } ++ if (REG_P (operands[0])) ++ dummy = 2; ++ shiftpos -= 8; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, second_pat, operands); ++ dummy += set_rel (operands[0], 2, 1) - 1; ++ } ++ break; ++ ++ case 15: ++ ++ if (zs) ++ { ++ OUT_INSN (len, "rla\t@%E0", operands); ++ OUT_INSN (len, "clr\t@%E0", operands); ++ OUT_INSN (len, "rlc\t@%E0", operands); ++ dummy = 3; ++ } ++ else ++ { ++ OUT_INSN (len, "rla\t%A0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "rlc\t%A0", operands); ++ dummy = 6; ++ } ++ if (REG_P (operands[0])) ++ dummy = 3; ++ break; ++ ++ default: ++ OUT_INSN (len, "clr\t%A0", operands); ++ dummy = 2; ++ if (REG_P (operands[0])) ++ dummy = 1; ++ break; ++ } ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ } ++ else ++ { ++ msp430_emit_shift_cnt (set_rel, pattern, insn, operands, len, 2); ++ } ++ ++ return ""; ++ ++} ++ ++const char * ++msp430_emit_lshrsi3 (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ const char *pattern; ++ int dummy = 0; ++ int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ const char *second_pat = "rra\t%B0\n\trrc\t%A0"; ++ ++ pattern = "clrc\n\trrc\t%B0\n\trrc\t%A0"; ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ int shiftpos = INTVAL (operands[2]); ++ ++ if (shiftpos < 8 && shiftpos) ++ { ++ OUT_INSN (len, pattern, operands); ++ /* This function was underestimating the length by 1 for shifts from ++ 1 to 7. I added one here - Max */ ++ dummy += set_rel (operands[0], 2, 1) + 1; ++ shiftpos--; ++ } ++ ++ switch (shiftpos) ++ { ++ case 0: ++ break; ++ ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ while (shiftpos--) ++ { ++ OUT_INSN (len, second_pat, operands); ++ dummy += set_rel (operands[0], 4, 1) - 1; ++ } ++ ++ break; ++ ++ case 8: ++ case 9: ++ case 10: ++ case 11: ++ case 12: ++ case 13: ++ case 14: ++ case 15: ++ OUT_INSN (len, "swpb\t%A0", operands); ++ OUT_INSN (len, "swpb\t%B0", operands); ++ OUT_INSN (len, "xor.b\t%B0, %A0", operands); ++ OUT_INSN (len, "xor\t%B0, %A0", operands); ++ OUT_INSN (len, "and.b\t#-1, %B0", operands); ++ dummy = 12; ++ ++ if (REG_P (operands[0])) ++ dummy = 5; ++ shiftpos -= 8; ++ while (shiftpos--) ++ { ++ OUT_INSN (len, second_pat, operands); ++ dummy += set_rel (operands[0], 4, 1) - 1; ++ } ++ break; ++ ++ case 16: ++ case 17: ++ case 18: ++ case 19: ++ case 20: ++ case 21: ++ case 22: ++ case 23: ++ OUT_INSN (len, "mov\t%B0, %A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ dummy = 5; ++ if (REG_P (operands[0])) ++ dummy = 2; ++ ++ shiftpos -= 16; ++ if (shiftpos) ++ { ++ OUT_INSN (len, "clrc\n\trrc\t%A0", operands); ++ dummy += 2; ++ if (!zs && !REG_P (operands[0])) ++ dummy++; ++ shiftpos--; ++ } ++ ++ while (shiftpos--) ++ { ++ OUT_INSN (len, "rra\t%A0", operands); ++ dummy += 1; ++ if (!zs && !REG_P (operands[0])) ++ dummy++; ++ } ++ break; ++ ++ case 24: ++ case 25: ++ case 26: ++ case 27: ++ case 28: ++ case 29: ++ case 30: ++ OUT_INSN (len, "mov\t%B0, %A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "swpb\t%A0", operands); ++ OUT_INSN (len, "and.b\t#-1, %A0", operands); ++ dummy = 9; ++ if (REG_P (operands[0])) ++ dummy = 4; ++ if (indexed_location (operands[0])) ++ dummy -= 1; ++ shiftpos -= 24; ++ ++ while (shiftpos--) ++ { ++ OUT_INSN (len, "rra\t%A0", operands); ++ dummy += 1; ++ if (!zs && !REG_P (operands[0])) ++ dummy++; ++ } ++ break; ++ ++ case 31: ++ OUT_INSN (len, "rla\r%B0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "rlc\t%A0", operands); ++ dummy = 8; ++ if (REG_P (operands[0])) ++ dummy = 4; ++ if (indexed_location (operands[0])) ++ dummy -= 1; ++ break; ++ ++ default: ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ dummy = 4; ++ if (REG_P (operands[0])) ++ dummy = 2; ++ break; ++ ++ } /* switch */ ++ ++ if (len) ++ *len = dummy; ++ return ""; ++ } ++ else ++ msp430_emit_shift_cnt (set_rel, pattern, insn, operands, len, 4); ++ ++ return ""; ++} ++ ++const char * ++msp430_emit_lshrdi3 (insn, operands, len) ++ rtx insn; ++ rtx operands[]; ++ int *len; ++{ ++ int dummy = 0; ++ const char *pattern; ++ int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); ++ const char *secondary_pat = "rra\t%D0\n\trrc\t%C0\n\trrc\t%B0\n\trrc\t%A0"; ++ ++ pattern = "clrc\n\trrc\t%D0\n\trrc\t%C0\n\trrc\t%B0\n\trrc\t%A0"; ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ int shiftpos = INTVAL (operands[2]); ++ ++ if (shiftpos < 16 && shiftpos) ++ { ++ OUT_INSN (len, pattern, operands); ++ dummy += set_rel (operands[0], 2, 1); ++ shiftpos--; ++ } ++ ++ switch (shiftpos) ++ { ++ case 0: ++ break; ++ ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ case 7: ++ case 8: ++ case 9: ++ case 10: ++ case 11: ++ case 12: ++ case 13: ++ case 14: ++ case 15: ++ while (shiftpos--) ++ { ++ OUT_INSN (len, secondary_pat, operands); ++ dummy += set_rel (operands[0], 8, 1) - 1; ++ } ++ ++ break; ++ ++ case 16: ++ case 17: ++ case 18: ++ case 19: ++ case 20: ++ case 21: ++ case 22: ++ case 23: ++ case 24: ++ case 25: ++ case 26: ++ case 27: ++ case 28: ++ case 29: ++ case 30: ++ case 31: ++ OUT_INSN (len, "mov\t%B0, %A0", operands); ++ OUT_INSN (len, "mov\t%C0, %B0", operands); ++ OUT_INSN (len, "mov\t%D0, %C0", operands); ++ OUT_INSN (len, "clr\t%D0", operands); ++ dummy = 11; ++ if (REG_P (operands[0])) ++ dummy = 4; ++ shiftpos -= 16; ++ ++ if (shiftpos) ++ { ++ OUT_INSN (len, secondary_pat, operands); ++ dummy += set_rel (operands[0], 8, 1) - 1; ++ shiftpos--; ++ } ++ ++ while (shiftpos--) ++ { ++ OUT_INSN (len, "rra\t%C0\n\trrc\t%B0\n\trrc\t%A0", operands); ++ if (REG_P (operands[0])) ++ dummy = 3; ++ else ++ dummy += 6; ++ if (zs) ++ dummy--; ++ } ++ ++ break; ++ ++ case 32: ++ case 33: ++ case 34: ++ case 35: ++ case 36: ++ case 37: ++ case 38: ++ case 39: ++ case 40: ++ case 41: ++ case 42: ++ case 43: ++ case 44: ++ case 45: ++ case 46: ++ case 47: ++ OUT_INSN (len, "mov\t%C0, %A0", operands); ++ OUT_INSN (len, "mov\t%D0, %B0", operands); ++ OUT_INSN (len, "clr\t%C0", operands); ++ OUT_INSN (len, "clr\t%D0", operands); ++ ++ dummy = 10; ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 4; ++ ++ shiftpos -= 32; ++ ++ if (shiftpos) ++ { ++ OUT_INSN (len, "clrc\n\trrc\t%B0,rrc\t%A0", operands); ++ if (REG_P (operands[0])) ++ dummy += 3; ++ else ++ dummy += 5; ++ if (zs) ++ dummy--; ++ shiftpos--; ++ } ++ ++ while (shiftpos--) ++ { ++ OUT_INSN (len, "rra\t%B0,rrc\t%A0", operands); ++ if (REG_P (operands[0])) ++ dummy += 2; ++ else ++ dummy += 4; ++ if (zs) ++ dummy--; ++ } ++ break; ++ ++ case 48: ++ case 49: ++ case 50: ++ case 51: ++ case 52: ++ case 53: ++ case 54: ++ case 55: ++ case 56: ++ case 57: ++ case 58: ++ case 59: ++ case 60: ++ case 61: ++ case 62: ++ OUT_INSN (len, "mov\t%D0, %A0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%C0", operands); ++ OUT_INSN (len, "clr\t%D0", operands); ++ dummy = 9; ++ if (GET_CODE (operands[0]) == REG) ++ dummy = 4; ++ shiftpos -= 48; ++ ++ if (shiftpos) ++ { ++ OUT_INSN (len, "clrc\n\trrc\t%A0", operands); ++ if (REG_P (operands[0]) || zs) ++ dummy += 2; ++ else ++ dummy += 3; ++ ++ shiftpos--; ++ } ++ ++ while (shiftpos--) ++ { ++ OUT_INSN (len, "rra\t%A0", operands); ++ if (REG_P (operands[0]) || zs) ++ dummy++; ++ else ++ dummy += 2; ++ } ++ break; ++ ++ case 63: ++ ++ OUT_INSN (len, "rla\t%D0", operands); ++ OUT_INSN (len, "clr\t%D0", operands); ++ OUT_INSN (len, "clr\t%C0", operands); ++ OUT_INSN (len, "clr\t%B0", operands); ++ OUT_INSN (len, "clr\t%A0", operands); ++ OUT_INSN (len, "rlc\t%A0", operands); ++ if (REG_P (operands[0])) ++ dummy += 6; ++ else ++ dummy += 13; ++ ++ if (zs) ++ dummy--; ++ break; ++ ++ default: ++ break; ++ } /* case */ ++ ++ if (len) ++ *len = dummy; ++ } ++ else ++ msp430_emit_shift_cnt (set_rel, pattern, insn, operands, len, 8); ++ ++ return ""; ++} ++ ++/* ++ * Multiplication helpers ++ * 1. As shifts, 2. the rest ++ */ ++ ++#define SOME_SHIFT_THRESHOLD_VAL 10 ++ ++int ++msp430_easy_mul (operands, sext) ++ rtx operands[]; ++ int sext; ++{ ++ enum machine_mode op0mode = GET_MODE (operands[0]); ++ enum machine_mode op1mode = GET_MODE (operands[1]); ++ rtx op0 = operands[0]; ++ rtx op1 = operands[1]; ++ rtx insn; ++ int m = INTVAL (operands[2]); ++ int sign = (m < 0); ++ int val = (m > 0 ? m : -m); ++ int shift1 = 0, shift0 = 0; ++ int add1 = 0, sub1 = 0; ++ int t0, t1; ++ int ops = 0; ++ ++ m = val; ++ /* ++ we can do: ++ const == single bit const +- N that (shift0 + add1/sub1 < 8 instructions) ++ */ ++ shift0 = 1; ++ shift1 = 0; ++ ++ for (t0 = 2; ++ t0 <= val * 2 && shift0 < GET_MODE_SIZE (op0mode) * BITS_PER_UNIT; ++ t0 <<= 1) ++ { ++ if (t0 == val) ++ goto done; ++ ++ for (t1 = 1; t1 < t0 && shift1 < GET_MODE_SIZE (op1mode) * BITS_PER_UNIT; ++ t1 <<= 1) ++ { ++ add1 = 0; ++ sub1 = 0; ++ if (t0 + t1 == m) ++ { ++ add1 = 1; ++ goto done; ++ } ++ if (t0 - t1 == m) ++ { ++ sub1 = 1; ++ goto done; ++ } ++ ++ if (t0 + t1 * 3 == m) ++ { ++ add1 = 3; ++ goto done; ++ } ++ ++ if (t0 - t1 * 3 == m) ++ { ++ sub1 = 3; ++ goto done; ++ } ++ ++ add1 = 0; ++ sub1 = 0; ++ shift1++; ++ ++ } ++ shift1 = 0; ++ shift0++; ++ } ++ ++ return 0; ++done: ++ ++ ops = shift0 * (op0mode == SImode ? 2 : 1); ++ ops += shift1 + add1 + sub1; ++ if (op0mode != op1mode) ++ { ++ ops += (op0mode == SImode ? 2 : 1) * ((add1 || sub1) ? 2 : 1); ++ } ++ ++ if (ops > SOME_SHIFT_THRESHOLD_VAL) ++ return 0; ++ ++ if (op0mode != op1mode) ++ { ++ rtx extend; ++ if (sext) ++ extend = gen_rtx_SIGN_EXTEND (op0mode, op1); ++ else ++ extend = gen_rtx_ZERO_EXTEND (op0mode, op1); ++ insn = gen_rtx_SET (VOIDmode, op0, extend); ++ emit_insn (insn); ++ } ++ else ++ { ++ emit_move_insn (op0, op1); ++ } ++ ++ /* shift0 */ ++ switch (op0mode) ++ { ++ case QImode: ++ emit_insn (gen_ashlqi3 (op0, op0, GEN_INT (shift0))); ++ break; ++ case HImode: ++ emit_insn (gen_ashlhi3 (op0, op0, GEN_INT (shift0))); ++ break; ++ case SImode: ++ emit_insn (gen_ashlsi3 (op0, op0, GEN_INT (shift0))); ++ break; ++ case DImode: ++ emit_insn (gen_ashldi3 (op0, op0, GEN_INT (shift0))); ++ break; ++ default: ++ abort (); ++ } ++ ++ if (op0mode != op1mode && (add1 || sub1 || shift1)) ++ { ++ /* equalize operands modes */ ++ rtx extend; ++ rtx treg = gen_reg_rtx (op0mode); ++ ++ if (sext) ++ extend = gen_rtx_SIGN_EXTEND (op0mode, op1); ++ else ++ extend = gen_rtx_ZERO_EXTEND (op0mode, op1); ++ insn = gen_rtx_SET (VOIDmode, treg, extend); ++ emit_insn (insn); ++ op1 = treg; ++ op1mode = GET_MODE (treg); ++ } ++ else if (add1 || sub1 || shift1) ++ { ++ rtx treg = gen_reg_rtx (op0mode); ++ emit_move_insn (treg, op1); ++ op1 = treg; ++ } ++ ++ if (shift1 && (add1 || sub1)) ++ { ++ switch (op1mode) ++ { ++ case QImode: ++ emit_insn (gen_ashlqi3 (op1, op1, GEN_INT (shift1))); ++ break; ++ case HImode: ++ emit_insn (gen_ashlhi3 (op1, op1, GEN_INT (shift1))); ++ break; ++ case SImode: ++ emit_insn (gen_ashlsi3 (op1, op1, GEN_INT (shift1))); ++ break; ++ case DImode: ++ emit_insn (gen_ashldi3 (op1, op1, GEN_INT (shift1))); ++ break; ++ default: ++ abort (); ++ } ++ } ++ else if (shift1) ++ abort (); /* paranoia */ ++ ++ while (add1--) ++ { ++ insn = ++ gen_rtx_SET (VOIDmode, op0, gen_rtx_PLUS (GET_MODE (op0), op0, op1)); ++ emit_insn (insn); ++ } ++ ++ while (sub1--) ++ { ++ insn = ++ gen_rtx_SET (VOIDmode, op0, ++ gen_rtx_MINUS (GET_MODE (op0), op0, op1)); ++ emit_insn (insn); ++ } ++ ++ if (sign) ++ { ++ switch (op0mode) ++ { ++ case QImode: ++ emit_insn (gen_negqi2 (op0, op0)); ++ break; ++ case HImode: ++ emit_insn (gen_neghi2 (op0, op0)); ++ break; ++ case SImode: ++ emit_insn (gen_negsi2 (op0, op0)); ++ break; ++ case DImode: ++ emit_insn (gen_negdi2 (op0, op0)); ++ break; ++ default: ++ abort (); ++ } ++ } ++ ++ return 1; ++} ++ ++/* multiplication guards */ ++#define LOAD_MPY(x) \ ++do{ \ ++ if(GET_MODE(x) == QImode) \ ++ emit_insn(gen_load_mpyq(x)); \ ++ else \ ++ emit_insn(gen_load_mpy(x)); \ ++}while(0) ++ ++#define LOAD_MPYS(x) \ ++do{ \ ++ if(GET_MODE(x) == QImode) \ ++ emit_insn(gen_load_mpysq(x)); \ ++ else \ ++ emit_insn(gen_load_mpys(x)); \ ++}while(0) ++ ++#define LOAD_OP2(x) \ ++do{ \ ++ if(GET_MODE(x) == QImode) \ ++ emit_insn(gen_load_op2q(x)); \ ++ else \ ++ emit_insn(gen_load_op2(x)); \ ++}while(0) ++ ++int ++msp430_mul3_guard (operands, sext) ++ rtx operands[]; ++ int sext; ++{ ++ rtx m_mpys = mpys_rtx; ++ rtx m_op2 = op2_rtx; ++ rtx m_reslo = reslo_rtx; ++ enum machine_mode op0mode = GET_MODE (operands[0]); ++ enum machine_mode op1mode = GET_MODE (operands[1]); ++ rtx r12 = gen_rtx_REG (op1mode, 12); ++ rtx r10 = gen_rtx_REG (op1mode, 10); ++ rtx r14 = gen_rtx_REG (op0mode, 14); ++ ++ if (const_int_operand (operands[2], VOIDmode) && ++ msp430_easy_mul (operands, sext)) ++ return 1; ++ ++ if (!msp430_has_hwmul) ++ { ++ rtx clob1 = gen_rtx_CLOBBER (VOIDmode, r10); ++ rtx clob2 = gen_rtx_CLOBBER (VOIDmode, r12); ++ rtx set; ++ rtx mult, op1, op2; ++ rtvec vec; ++ /* prepare 'call' pattern */ ++ if (sext==1) ++ { ++ op1 = gen_rtx_SIGN_EXTEND (op0mode, r10); ++ op2 = gen_rtx_SIGN_EXTEND (op0mode, r12); ++ } ++ else ++ { ++ op1 = r10; ++ op2 = r12; ++ } ++ mult = gen_rtx_MULT (op0mode, op1, op2); ++ set = gen_rtx_SET (op0mode, r14, mult); ++ vec = gen_rtvec (3, set, clob1, clob2); ++ ++ emit_move_insn (r10, operands[1]); ++ emit_move_insn (r12, operands[2]); ++ emit (gen_rtx_PARALLEL (VOIDmode, vec)); ++ emit_move_insn (operands[0], r14); ++ return 1; ++ } ++ if (op1mode == QImode) ++ { ++ m_mpys = gen_lowpart (QImode, mpys_rtx); ++ m_op2 = gen_lowpart (QImode, op2_rtx); ++ } ++ ++ if (op0mode == QImode) ++ m_reslo = gen_lowpart (QImode, reslo_rtx); ++ ++ if (!MSP430_NOINT_HWMUL) ++ emit_insn (gen_reent_in ()); ++ ++ LOAD_MPYS (operands[1]); ++ if (sext) ++ emit_insn (gen_extendqihi2 (mpys_rtx, m_mpys)); ++ LOAD_OP2 (operands[2]); ++ if (sext) ++ emit_insn (gen_extendqihi2 (op2_rtx, m_op2)); ++ ++ if (MSP430_NOINT_HWMUL) ++ { ++ if (op0mode == HImode) ++ emit_insn (gen_fetch_result_hi_nint (operands[0])); ++ else ++ emit_insn (gen_fetch_result_qi_nint (operands[0])); ++ } ++ else ++ { ++ if (op0mode == HImode) ++ emit_insn (gen_fetch_result_hi (operands[0])); ++ else ++ emit_insn (gen_fetch_result_qi (operands[0])); ++ } ++ ++ return 1; ++} ++ ++ ++int ++msp430_umul3_guard (operands, sext) ++ rtx operands[]; ++ int sext ATTRIBUTE_UNUSED; ++{ ++ rtx m_mpy = mpy_rtx; ++ rtx m_op2 = op2_rtx; ++ enum machine_mode op0mode = GET_MODE (operands[0]); ++ enum machine_mode op1mode = GET_MODE (operands[1]); ++ rtx r12 = gen_rtx_REG (op1mode, 12); ++ rtx r10 = gen_rtx_REG (op1mode, 10); ++ rtx r14 = gen_rtx_REG (op0mode, 14); ++ ++ if (const_int_operand (operands[2], VOIDmode) && ++ msp430_easy_mul (operands, 0)) ++ return 1; ++ ++ if (!msp430_has_hwmul) ++ { ++ rtx clob1 = gen_rtx_CLOBBER (VOIDmode, r10); ++ rtx clob2 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (op1mode, 12)); ++ rtx set; ++ rtx mult, op1, op2; ++ rtvec vec; ++ /* prepare 'call' pattern */ ++ op1 = gen_rtx_ZERO_EXTEND (op0mode, r10); ++ op2 = gen_rtx_ZERO_EXTEND (op0mode, r12); ++ ++ mult = gen_rtx_MULT (op0mode, op1, op2); ++ set = gen_rtx_SET (op0mode, r14, mult); ++ vec = gen_rtvec (3, set, clob1, clob2); ++ ++ emit_move_insn (r10, operands[1]); ++ emit_move_insn (r12, operands[2]); ++ emit (gen_rtx_PARALLEL (VOIDmode, vec)); ++ emit_move_insn (operands[0], r14); ++ return 1; ++ } ++ ++ m_mpy = gen_lowpart (QImode, mpy_rtx); ++ m_op2 = gen_lowpart (QImode, op2_rtx); ++ ++ if (!MSP430_NOINT_HWMUL) ++ emit_insn (gen_reent_in ()); ++ ++ LOAD_MPY (gen_lowpart (QImode,operands[1])); ++ //emit_insn (gen_zero_extendqihi2 (mpy_rtx, m_mpy)); ++ //LOAD_OP2 (gen_lowpart (QImode,operands[2])); ++ //emit_insn (gen_zero_extendqihi2 (op2_rtx, m_op2)); ++ emit_move_insn(m_op2, gen_lowpart (QImode,operands[2])); ++ ++ if (MSP430_NOINT_HWMUL) ++ emit_insn (gen_fetch_result_hi_nint (operands[0])); ++ else ++ emit_insn (gen_fetch_result_hi (operands[0])); ++ ++ return 1; ++} ++ ++ ++int ++msp430_mulhisi_guard (operands) ++ rtx operands[]; ++{ ++ enum machine_mode op0mode = GET_MODE (operands[0]); ++ enum machine_mode op1mode = GET_MODE (operands[1]); ++ rtx r12 = gen_rtx_REG (op1mode, 12); ++ rtx r10 = gen_rtx_REG (op1mode, 10); ++ rtx r14 = gen_rtx_REG (op0mode, 14); ++ rtx r11 = gen_rtx_REG (op1mode, 11); ++ rtx r13 = gen_rtx_REG (op1mode, 13); ++ ++ if (const_int_operand (operands[2], VOIDmode) && ++ msp430_easy_mul (operands, 1)) ++ return 1; ++ ++ if (!msp430_has_hwmul) ++ { ++ rtx clob1 = gen_rtx_CLOBBER (VOIDmode, r10); ++ rtx clob2 = gen_rtx_CLOBBER (VOIDmode, r11); ++ rtx clob3 = gen_rtx_CLOBBER (VOIDmode, r12); ++ rtx clob4 = gen_rtx_CLOBBER (VOIDmode, r13); ++ ++ rtx set; ++ rtx mult, op1, op2; ++ rtvec vec; ++ /* prepare 'call' pattern */ ++ op1 = gen_rtx_SIGN_EXTEND (op0mode, r10); ++ op2 = gen_rtx_SIGN_EXTEND (op0mode, r12); ++ ++ mult = gen_rtx_MULT (op0mode, op1, op2); ++ set = gen_rtx_SET (op0mode, r14, mult); ++ vec = gen_rtvec (5, set, clob1, clob2, clob3, clob4); ++ ++ emit_move_insn (r10, operands[1]); ++ emit_move_insn (r12, operands[2]); ++ emit (gen_rtx_PARALLEL (VOIDmode, vec)); ++ emit_move_insn (operands[0], r14); ++ return 1; ++ } ++ if (!MSP430_NOINT_HWMUL) ++ emit_insn (gen_reent_in ()); ++ ++ LOAD_MPYS (operands[1]); ++ LOAD_OP2 (operands[2]); ++ ++ if (MSP430_NOINT_HWMUL) ++ { ++ emit_insn (gen_fetch_result_si_nint (operands[0])); ++ } ++ else ++ emit_insn (gen_fetch_result_si (operands[0])); ++ ++ return 1; ++} ++ ++ ++int ++msp430_umulhisi_guard (operands) ++ rtx operands[]; ++{ ++ enum machine_mode op0mode = GET_MODE (operands[0]); ++ enum machine_mode op1mode = GET_MODE (operands[1]); ++ rtx r12 = gen_rtx_REG (op1mode, 12); ++ rtx r10 = gen_rtx_REG (op1mode, 10); ++ rtx r14 = gen_rtx_REG (op0mode, 14); ++ rtx r11 = gen_rtx_REG (op1mode, 11); ++ rtx r13 = gen_rtx_REG (op1mode, 13); ++ ++ if (const_int_operand (operands[2], VOIDmode) && ++ msp430_easy_mul (operands, 0)) ++ return 1; ++ ++ if (!msp430_has_hwmul) ++ { ++ rtx clob1 = gen_rtx_CLOBBER (VOIDmode, r10); ++ rtx clob2 = gen_rtx_CLOBBER (VOIDmode, r11); ++ rtx clob3 = gen_rtx_CLOBBER (VOIDmode, r12); ++ rtx clob4 = gen_rtx_CLOBBER (VOIDmode, r13); ++ ++ rtx set; ++ rtx mult, op1, op2; ++ rtvec vec; ++ /* prepare 'call' pattern */ ++ op1 = gen_rtx_ZERO_EXTEND (op0mode, r10); ++ op2 = gen_rtx_ZERO_EXTEND (op0mode, r12); ++ ++ mult = gen_rtx_MULT (op0mode, op1, op2); ++ set = gen_rtx_SET (op0mode, r14, mult); ++ vec = gen_rtvec (5, set, clob1, clob2, clob3, clob4); ++ ++ emit_move_insn (r10, operands[1]); ++ emit_move_insn (r12, operands[2]); ++ emit (gen_rtx_PARALLEL (VOIDmode, vec)); ++ emit_move_insn (operands[0], r14); ++ return 1; ++ } ++ ++ if (!MSP430_NOINT_HWMUL) ++ emit_insn (gen_reent_in ()); ++ ++ LOAD_MPY (operands[1]); ++ LOAD_OP2 (operands[2]); ++ ++ if (MSP430_NOINT_HWMUL) ++ { ++ emit_insn (gen_fetch_result_si_nint (operands[0])); ++ } ++ else ++ emit_insn (gen_fetch_result_si (operands[0])); ++ ++ return 1; ++} ++ ++ ++/* something like 'push x(r1)' or 'push @r1' */ ++int ++self_push (x) ++ rtx x; ++{ ++ rtx c; ++ rtx r; ++ ++ if (GET_CODE (x) != MEM) ++ return 0; ++ ++ c = XEXP (x, 0); ++ ++ if (REG_P (c) && REGNO (c) == 1) ++ return 1; ++ ++ if (GET_CODE (c) == PLUS) ++ { ++ r = XEXP (c, 0); ++ if (REG_P (r) && REGNO (r) == 1) ++ return 1; ++ } ++ return 0; ++} ++ ++/* difficult pushes. ++ if planets are not aligned, the combiner does not allocate ++ r4 as a frame pointer. Instead, it uses stack pointer for frame. ++ If there is a va_arg call and non-register local var has to be passed ++ as a function parameter, the push X(r1) in SI, SF and DI modes will ++ corrupt passed var. The following minds this fact */ ++ ++ ++const char * ++msp430_pushqi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int sp = self_push (operands[0]); ++ int dummy = 0; ++ ++ if (sp) ++ { ++ rtx c; ++ c = XEXP (operands[0], 0); ++ if (REG_P (c)) ++ OUT_INSN (len, "push.b\t2(%E0)", operands); ++ else ++ OUT_INSN (len, "push.b\t2+%A0", operands); ++ dummy = 2; ++ } ++ else ++ { ++ OUT_INSN (len, "push.b\t%A0", operands); ++ dummy = 2; ++ ++ if (GET_CODE (operands[0]) == CONST_INT) ++ { ++ int cval = INTVAL (operands[0]); ++ int x = (cval) & 0x0fffful; ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 || x == 0xffff) ++ dummy--; ++ ++ } ++ else if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ else if (GET_CODE (operands[0]) == MEM && REG_P (XEXP (operands[0], 0))) ++ dummy--; ++ } ++ ++ return ""; ++} ++ ++const char * ++msp430_pushhi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int sp = self_push (operands[0]); ++ int dummy = 0; ++ ++ if (sp) ++ { ++ rtx c; ++ c = XEXP (operands[0], 0); ++ if (REG_P (c)) ++ OUT_INSN (len, "push\t2(%E0)", operands); ++ else ++ OUT_INSN (len, "push\t2+%A0", operands); ++ dummy = 2; ++ } ++ else ++ { ++ OUT_INSN (len, "push\t%A0", operands); ++ dummy = 2; ++ ++ if (GET_CODE (operands[0]) == CONST_INT) ++ { ++ int cval = INTVAL (operands[0]); ++ int x = (cval) & 0x0fffful; ++ ++ if (cval == 99999999) ++ { ++ if (len) ++ *len = 3; ++ return ""; ++ } ++ ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 || x == 0xffff) ++ dummy--; ++ ++ } ++ else if (GET_CODE (operands[0]) == REG) ++ dummy--; ++ else if (GET_CODE (operands[0]) == MEM && REG_P (XEXP (operands[0], 0))) ++ dummy--; ++ } ++ if (len) ++ *len = dummy; ++ return ""; ++} ++ ++const char * ++msp430_pushsisf (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int sp = self_push (operands[0]); ++ int dummy = 0; ++ ++ if (!sp) ++ { ++ OUT_INSN (len, "push\t%B0", operands); ++ OUT_INSN (len, "push\t%A0", operands); ++ dummy = 4; ++ if (indexed_location (operands[0])) ++ dummy--; ++ if (REG_P (operands[0])) ++ dummy -= 2; ++ if (GET_CODE (operands[0]) == CONST_INT) ++ { ++ int cval = INTVAL (operands[0]); ++ int x = (cval) & 0x0fffful; ++ int y = (((unsigned long) (cval)) & 0xffff0000ul >> 16); ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 || x == 0xffff) ++ dummy--; ++ if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 || y == 0xffff) ++ dummy--; ++ } ++ else if (GET_CODE (operands[0]) == CONST_DOUBLE ++ && GET_MODE (operands[0]) == SFmode) ++ { ++ long val; ++ int y, x; ++ REAL_VALUE_TYPE rv; ++ REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[0]); ++ REAL_VALUE_TO_TARGET_SINGLE (rv, val); ++ ++ y = (val & 0xffff0000ul) >> 16; ++ x = val & 0xffff; ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 || x == 0xffff) ++ dummy--; ++ if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 || y == 0xffff) ++ dummy--; ++ } ++ } ++ else ++ { ++ OUT_INSN (len, "push\t2+%B0", operands); ++ OUT_INSN (len, "push\t2+%B0", operands); ++ dummy = 4; ++ } ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++ ++const char * ++msp430_pushdi (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[]; ++ int *len; ++{ ++ int sp = self_push (operands[0]); ++ int dummy = 0; ++ ++ if (!sp) ++ { ++ OUT_INSN (len, "push\t%D0", operands); ++ OUT_INSN (len, "push\t%C0", operands); ++ OUT_INSN (len, "push\t%B0", operands); ++ OUT_INSN (len, "push\t%A0", operands); ++ ++ dummy = 8; ++ if (indexed_location (operands[0])) ++ dummy--; ++ if (REG_P (operands[0])) ++ dummy -= 4; ++ if (GET_CODE (operands[0]) == CONST_DOUBLE) ++ { ++ int hi = CONST_DOUBLE_HIGH (operands[0]); ++ int lo = CONST_DOUBLE_LOW (operands[0]); ++ int x, y, z; ++ ++ x = (hi & 0xffff0000ul) >> 16; ++ y = hi & 0xffff; ++ z = (lo & 0xffff0000ul) >> 16; ++ if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 || x == 0xffff) ++ dummy--; ++ if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 || y == 0xffff) ++ dummy--; ++ if (z == 0 || z == 1 || z == 2 || z == 4 || z == 8 || z == 0xffff) ++ dummy--; ++ z = lo & 0xffff; ++ if (z == 0 || z == 1 || z == 2 || z == 4 || z == 8 || z == 0xffff) ++ dummy--; ++ } ++ } ++ else ++ { ++ OUT_INSN (len, "push\t2+%D0", operands); ++ OUT_INSN (len, "push\t2+%D0", operands); ++ OUT_INSN (len, "push\t2+%D0", operands); ++ OUT_INSN (len, "push\t2+%D0", operands); ++ dummy = 8; ++ } ++ ++ if (len) ++ *len = dummy; ++ ++ return ""; ++} ++ ++int ++dead_or_set_in_peep (which, insn, x) ++ int which; ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx x; ++{ ++ rtx r; ++ rtx next; ++ ++ next = peep2_next_insn (which); ++ if (!next) ++ return 0; ++ if (!REG_P (x)) ++ return 0; ++ r = find_regno_note (next, REG_DEAD, REGNO (x)); ++ ++ if (!r) ++ return 0; ++ ++ r = XEXP (r, 0); ++ return GET_MODE (r) == GET_MODE (x); ++} ++ ++void ++msp430_trampoline_template (FILE * fd) ++{ ++ fprintf (fd, "; TRAMPOLINE HERE\n" ++ "; move context (either r1 or r4) to r6\n" ++ "; call function (0xf0f0 will be changed)\n"); ++ fprintf (fd, "\tmov #0xf0f0, r6\n"); ++ fprintf (fd, "\tbr #0xf0f0\n"); ++ fprintf (fd, "; END OF TRAMPOLINE\n\n"); ++} ++ ++void ++msp430_initialize_trampoline (tramp, fn, ctx) ++ rtx tramp; ++ rtx fn; ++ rtx ctx; ++{ ++ emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), ctx); ++ emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 6)), fn); ++} ++ ++const char * ++msp430_emit_return (insn, operands, len) ++ rtx insn ATTRIBUTE_UNUSED; ++ rtx operands[] ATTRIBUTE_UNUSED; ++ int *len ATTRIBUTE_UNUSED; ++{ ++ return_issued = 1; ++ if (msp430_empty_epilogue () == 1) ++ return "ret"; ++ ++ return "reti"; ++} ++ ++int ++three_operands_msp430 (x, mode) ++ rtx x; ++ enum machine_mode mode; ++{ ++ enum rtx_code code = GET_CODE (x); ++ if (GET_MODE (x) != mode) ++ return 0; ++ ++ return (code == PLUS ++ || code == MINUS || code == AND || code == IOR || code == XOR); ++} ++ ++int ++equality_operator (op, mode) ++ register rtx op; ++ enum machine_mode mode; ++{ ++ return ((mode == VOIDmode || GET_MODE (op) == mode) ++ && (GET_CODE (op) == EQ || GET_CODE (op) == NE)); ++} ++ ++/* Return 1 if this is a comparison operator but not an EQ or NE operator. */ ++int ++inequality_operator (op, mode) ++ register rtx op; ++ enum machine_mode mode; ++{ ++ return comparison_operator (op, mode) && !equality_operator (op, mode); ++} +diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/msp430.h gcc-3.2.3/gcc/config/msp430/msp430.h +--- gcc-3.2.3.orig/gcc/config/msp430/msp430.h 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-3.2.3/gcc/config/msp430/msp430.h 2008-08-22 09:17:00.000000000 -0600 +@@ -0,0 +1,3378 @@ ++ ++/* Definitions of target machine for GNU compiler, ++ for Texas Instruments MSP430 microcontrollers. ++ Copyright (C) 2001 Free Software Foundation, Inc. ++ Contributed by Dmitry Diky ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++/* Names to predefine in the preprocessor for this target machine. */ ++ ++#define CPP_PREDEFINES "-DMSP430" ++/* Define this to be a string constant containing `-D' options to ++ define the predefined macros that identify this machine and system. ++ These macros will be predefined unless the `-ansi' option is ++ specified. ++ ++ In addition, a parallel set of macros are predefined, whose names ++ are made by appending `__' at the beginning and at the end. These ++ `__' macros are permitted by the ANSI standard, so they are ++ predefined regardless of whether `-ansi' is specified. ++ ++ For example, on the Sun, one can use the following value: ++ ++ "-Dmc68000 -Dsun -Dunix" ++ ++ The result is to define the macros `__mc68000__', `__sun__' and ++ `__unix__' unconditionally, and the macros `mc68000', `sun' and ++ `unix' provided `-ansi' is not specified. */ ++ ++ ++/* This declaration should be present. */ ++/* ++#include ++*/ ++ ++extern int target_flags; ++ ++#define MASK_PROF_STD 0x00000001 ++#define MASK_PROF_LIB 0x00000002 ++#define MASK_PROF_STACK 0x00000004 ++ ++#define MASK_RTL_DUMP 0x00000010 ++#define MASK_ALL_DEBUG 0x00000FE0 ++#define MASK_FORCE_HWMUL 0x00001000 ++#define MASK_STRICT_ALIGN 0x00002000 ++#define MASK_IAR 0x00004000 ++#define MASK_NO_STACK_INIT 0x00008000 ++#define MASK_NO_VOLAT_WRKAR 0x00010000 ++#define MASK_REORDER 0x00020000 ++#define MASK_INLINESIHWMUL 0x00040000 ++#define MASK_NO_HWMUL 0x00100000 ++#define MASK_NOINT_HWMUL 0x00200000 ++#define MASK_SAVE_PROLOGUE 0x00400000 ++ ++ ++ ++#define TARGET_PROF_STD (target_flags & MASK_PROF_STD) ++#define TARGET_PROF_LIB (target_flags & MASK_PROF_LIB) ++#define TARGET_PROF_STACK (target_flags & MASK_PROF_STACK) ++#define TARGET_NO_HWMUL (target_flags & MASK_NO_HWMUL) ++#define TARGET_HWMUL (target_flags & MASK_FORCE_HWMUL) ++#define TARGET_NOINT_HWMUL (target_flags & MASK_NOINT_HWMUL) ++#define TARGET_RTL_DUMP (target_flags & MASK_RTL_DUMP) ++#define TARGET_ALL_DEBUG (target_flags & MASK_ALL_DEBUG) ++#define TARGET_STRICT_ALIGN (target_flags & MASK_STRICT_ALIGN) ++#define TARGET_IAR (target_flags & MASK_IAR) ++#define TARGET_NSI (target_flags & MASK_NO_STACK_INIT) ++#define TARGET_NVWA (target_flags & MASK_NO_VOLAT_WRKAR) ++#define TARGET_REORDER (target_flags & MASK_REORDER) ++#define TARGET_INLINESIHWMUL (target_flags & MASK_INLINESIHWMUL) ++#define TARGET_SAVE_PROLOGUE (target_flags & MASK_SAVE_PROLOGUE) ++ ++ ++#define TARGET_SWITCHES { \ ++ { "pgs", MASK_PROF_STD, N_("Add ordinary profile information")}, \ ++ { "pgl", MASK_PROF_LIB, N_("Add library profile information")}, \ ++ { "pgr", MASK_PROF_STACK,N_("Add stack information to profiler") }, \ ++ { "rtl", MASK_RTL_DUMP, NULL }, \ ++ { "deb", MASK_ALL_DEBUG, NULL }, \ ++ { "strict-align", MASK_STRICT_ALIGN,N_("Strict alignment for all structures") }, \ ++ { "force-hwmul", MASK_FORCE_HWMUL,N_("Force hardware multiplier") },\ ++ { "disable-hwmul", MASK_NO_HWMUL, N_("Disable hardware multiplier") }, \ ++ { "inline-hwmul", MASK_INLINESIHWMUL, N_("Issue inline multiplication code for 32-bit integers") }, \ ++ { "noint-hwmul", MASK_NOINT_HWMUL, ("Assume interrupt routine does not do hardware multiply")}, \ ++ { "IAR",MASK_IAR,N_("Produce IAR assembler syntax") }, \ ++ { "no-stack-init",MASK_NO_STACK_INIT,N_("No stack init in main()") }, \ ++ { "no-volatile-workaround",MASK_NO_STACK_INIT,N_("Do not perform volatile workaround for bitwise operations") }, \ ++ { "save-prologue",MASK_SAVE_PROLOGUE, ("Use subroutine call for function prologue/epilogue when possible")}, \ ++ { "", 0, NULL } \ ++} ++ ++extern const char *msp430_endup; ++extern const char *msp430_init_stack; ++extern const char *msp430_mcu_name; ++extern int msp430_has_hwmul; ++ ++ ++#define MSP430_HAS_HWMUL_INTERNAL (msp430_has_hwmul) ++ ++int msp430_current_function_noint_hwmul_function_p(void); ++#define MSP430_NOINT_HWMUL (msp430_current_function_noint_hwmul_function_p()) ++ ++#define TARGET_OPTIONS { \ ++ { "init-stack=", &msp430_init_stack, N_("Specify the initial stack address") }, \ ++ { "mcu=", &msp430_mcu_name, N_("Specify the MCU name") }, \ ++ { "endup-at=",&msp430_endup,N_("Jump to specified routine at the end of main()")} \ ++} ++ ++ ++#define TARGET_VERSION fprintf (stderr, " (GNU assembler syntax)"); ++ ++#define OVERRIDE_OPTIONS msp430_override_options() ++ ++#define CAN_DEBUG_WITHOUT_FP ++/* Define this macro if debugging can be performed even without a ++ frame pointer. If this macro is defined, GNU CC will turn on the ++ `-fomit-frame-pointer' option whenever `-O' is specified. */ ++ ++#define BITS_BIG_ENDIAN 0 ++#define BYTES_BIG_ENDIAN 0 ++#define WORDS_BIG_ENDIAN 0 ++#define BITS_PER_UNIT 8 ++#define BITS_PER_WORD 16 ++ ++#ifdef IN_LIBGCC2 ++/* This is to get correct SI and DI modes in libgcc2.c (32 and 64 bits). */ ++#define UNITS_PER_WORD 4 ++#else ++/* Width of a word, in units (bytes). */ ++#define UNITS_PER_WORD 2 ++#endif ++ ++/* Width in bits of a pointer. ++ See also the macro `Pmode' defined below. */ ++#define POINTER_SIZE 16 ++ ++ ++/* Maximum sized of reasonable data type ++ DImode or Dfmode ... */ ++#define MAX_FIXED_MODE_SIZE 32 ++ ++/* Allocation boundary (in *bits*) for storing arguments in argument list. */ ++#define PARM_BOUNDARY 16 ++ ++/* Allocation boundary (in *bits*) for the code of a function. */ ++#define FUNCTION_BOUNDARY 16 ++ ++/* Alignment of field after `int : 0' in a structure. */ ++#define EMPTY_FIELD_BOUNDARY 16 ++ ++/* No data type wants to be aligned rounder than this. */ ++#define BIGGEST_ALIGNMENT 16 ++ ++/* Define this if move instructions will actually fail to work ++ when given unaligned data. */ ++#define STRICT_ALIGNMENT TARGET_STRICT_ALIGN ++ ++/* A C expression for the size in bits of the type `int' on the ++ target machine. If you don't define this, the default is one word. */ ++#define INT_TYPE_SIZE ( 16) ++ ++ ++/* A C expression for the size in bits of the type `short' on the ++ target machine. If you don't define this, the default is half a ++ word. (If this would be less than one storage unit, it is rounded ++ up to one unit.) */ ++#define SHORT_TYPE_SIZE (INT_TYPE_SIZE == 8 ? INT_TYPE_SIZE : 16) ++ ++/* A C expression for the size in bits of the type `long' on the ++ target machine. If you don't define this, the default is one word. */ ++#define LONG_TYPE_SIZE (INT_TYPE_SIZE == 8 ? 16 : 32) ++ ++#define MAX_LONG_TYPE_SIZE 32 ++/* Maximum number for the size in bits of the type `long' on the ++ target machine. If this is undefined, the default is ++ `LONG_TYPE_SIZE'. Otherwise, it is the constant value that is the ++ largest value that `LONG_TYPE_SIZE' can have at run-time. This is ++ used in `cpp'. */ ++ ++ ++#define LONG_LONG_TYPE_SIZE 64 ++/* A C expression for the size in bits of the type `long long' on the ++ target machine. If you don't define this, the default is two ++ words. If you want to support GNU Ada on your machine, the value ++ of macro must be at least 64. */ ++ ++ ++#define CHAR_TYPE_SIZE 8 ++/* A C expression for the size in bits of the type `char' on the ++ target machine. If you don't define this, the default is one ++ quarter of a word. (If this would be less than one storage unit, ++ it is rounded up to one unit.) */ ++ ++#define FLOAT_TYPE_SIZE 32 ++/* A C expression for the size in bits of the type `float' on the ++ target machine. If you don't define this, the default is one word. */ ++ ++#define DOUBLE_TYPE_SIZE 32 ++/* A C expression for the size in bits of the type `double' on the ++ target machine. If you don't define this, the default is two ++ words. */ ++ ++ ++#define LONG_DOUBLE_TYPE_SIZE 32 ++/* A C expression for the size in bits of the type `long double' on ++ the target machine. If you don't define this, the default is two ++ words. */ ++ ++#define DEFAULT_SIGNED_CHAR 1 ++/* An expression whose value is 1 or 0, according to whether the type ++ `char' should be signed or unsigned by default. The user can ++ always override this default with the options `-fsigned-char' and ++ `-funsigned-char'. */ ++ ++/* `DEFAULT_SHORT_ENUMS' ++ A C expression to determine whether to give an `enum' type only as ++ many bytes as it takes to represent the range of possible values ++ of that type. A nonzero value means to do that; a zero value ++ means all `enum' types should be allocated like `int'. ++ ++ If you don't define the macro, the default is 0. */ ++ ++#define SIZE_TYPE (INT_TYPE_SIZE == 8 ? "long unsigned int" : "unsigned int") ++/* A C expression for a string describing the name of the data type ++ to use for size values. The typedef name `size_t' is defined ++ using the contents of the string. ++ ++ The string can contain more than one keyword. If so, separate ++ them with spaces, and write first any length keyword, then ++ `unsigned' if appropriate, and finally `int'. The string must ++ exactly match one of the data type names defined in the function ++ `init_decl_processing' in the file `c-decl.c'. You may not omit ++ `int' or change the order--that would cause the compiler to crash ++ on startup. ++ ++ If you don't define this macro, the default is `"long unsigned ++ int"'. */ ++ ++#define PTRDIFF_TYPE (INT_TYPE_SIZE == 8 ? "long int" :"int") ++/* A C expression for a string describing the name of the data type ++ to use for the result of subtracting two pointers. The typedef ++ name `ptrdiff_t' is defined using the contents of the string. See ++ `SIZE_TYPE' above for more information. ++ ++ If you don't define this macro, the default is `"long int"'. */ ++ ++ ++#define WCHAR_TYPE_SIZE 16 ++/* A C expression for the size in bits of the data type for wide ++ characters. This is used in `cpp', which cannot make use of ++ `WCHAR_TYPE'. */ ++ ++#define FIRST_PSEUDO_REGISTER 16 ++/* Number of hardware registers known to the compiler. They receive ++ numbers 0 through `FIRST_PSEUDO_REGISTER-1'; thus, the first ++ pseudo register's number really is assigned the number ++ `FIRST_PSEUDO_REGISTER'. */ ++ ++#define FIXED_REGISTERS {\ ++ 1,1,/* r0 r1 == PC SP */\ ++ 1,1,/* r2 r3 == CG1(SR) CG2*/\ ++ 0,0,/* r4 r5 */\ ++ 0,0,/* r6 r7 */\ ++ 0,0,/* r8 r9 */\ ++ 0,0,/* r10 r11 */\ ++ 0,0,/* r12 r13 */\ ++ 0,0,/* r14 r15 */\ ++} ++/* An initializer that says which registers are used for fixed ++ purposes all throughout the compiled code and are therefore not ++ available for general allocation. These would include the stack ++ pointer, the frame pointer (except on machines where that can be ++ used as a general register when no frame pointer is needed), the ++ program counter on machines where that is considered one of the ++ addressable registers, and any other numbered register with a ++ standard use. ++ ++ This information is expressed as a sequence of numbers, separated ++ by commas and surrounded by braces. The Nth number is 1 if ++ register N is fixed, 0 otherwise. ++ ++ The table initialized from this macro, and the table initialized by ++ the following one, may be overridden at run time either ++ automatically, by the actions of the macro ++ `CONDITIONAL_REGISTER_USAGE', or by the user with the command ++ options `-ffixed-REG', `-fcall-used-REG' and `-fcall-saved-REG'. */ ++ ++#define CALL_USED_REGISTERS { \ ++ 1,1,/* r0 r1 */ \ ++ 1,1,/* r2 r3 */ \ ++ 0,0,/* r4 r5 */ \ ++ 0,0,/* r6 r7 */ \ ++ 0,0,/* r8 r9 */ \ ++ 0,0,/* r10 r11 */ \ ++ 1,1,/* r12 r13 */ \ ++ 1,1,/* r14 r15 */ \ ++} ++/* Like `FIXED_REGISTERS' but has 1 for each register that is ++ clobbered (in general) by function calls as well as for fixed ++ registers. This macro therefore identifies the registers that are ++ not available for general allocation of values that must live ++ across function calls. ++ ++ If a register has 0 in `CALL_USED_REGISTERS', the compiler ++ automatically saves it on function entry and restores it on ++ function exit, if the register is used within the function. */ ++ ++#define NON_SAVING_SETJMP 0 ++/* If this macro is defined and has a nonzero value, it means that ++ `setjmp' and related functions fail to save the registers, or that ++ `longjmp' fails to restore them. To compensate, the compiler ++ avoids putting variables in registers in functions that use ++ `setjmp'. */ ++ ++#define REG_ALLOC_ORDER { 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 } ++ ++/* If defined, an initializer for a vector of integers, containing the ++ numbers of hard registers in the order in which GNU CC should ++ prefer to use them (from most preferred to least). ++ ++ If this macro is not defined, registers are used lowest numbered ++ first (all else being equal). ++ ++ One use of this macro is on machines where the highest numbered ++ registers must always be saved and the save-multiple-registers ++ instruction supports only sequences of consetionve registers. On ++ such machines, define `REG_ALLOC_ORDER' to be an initializer that ++ lists the highest numbered allocatable register first. */ ++ ++#define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc () ++/* ORDER_REGS_FOR_LOCAL_ALLOC' ++ A C statement (sans semicolon) to choose the order in which to ++ allocate hard registers for pseudo-registers local to a basic ++ block. ++ ++ Store the desired register order in the array `reg_alloc_order'. ++ Element 0 should be the register to allocate first; element 1, the ++ next register; and so on. ++ ++ The macro body should not assume anything about the contents of ++ `reg_alloc_order' before execution of the macro. ++ ++ On most machines, it is not necessary to define this macro. */ ++ ++ ++#define HARD_REGNO_NREGS(REGNO, MODE) \ ++((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) ++ ++/* A C expression for the number of consecutive hard registers, ++ starting at register number REGNO, required to hold a value of mode ++ MODE. ++ ++ On a machine where all registers are exactly one word, a suitable ++ definition of this macro is ++ ++ #define HARD_REGNO_NREGS(REGNO, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD)) */ ++ ++#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 ++/* ++msp430_hard_regno_mode_ok(REGNO, MODE) ++*/ ++/* A C expression that is nonzero if it is permissible to store a ++ value of mode MODE in hard register number REGNO (or in several ++ registers starting with that one). For a machine where all ++ registers are equivalent, a suitable definition is ++ ++ #define HARD_REGNO_MODE_OK(REGNO, MODE) 1 ++ ++ It is not necessary for this macro to check for the numbers of ++ fixed registers, because the allocation mechanism considers them ++ to be always occupied. ++ ++ On some machines, double-precision values must be kept in even/odd ++ register pairs. The way to implement that is to define this macro ++ to reject odd register numbers for such modes. ++ ++ The minimum requirement for a mode to be OK in a register is that ++ the `movMODE' instruction pattern support moves between the ++ register and any other hard register for which the mode is OK; and ++ that moving a value into the register and back out not alter it. ++ ++ Since the same instruction used to move `SImode' will work for all ++ narrower integer modes, it is not necessary on any machine for ++ `HARD_REGNO_MODE_OK' to distinguish between these modes, provided ++ you define patterns `movhi', etc., to take advantage of this. This ++ is useful because of the interaction between `HARD_REGNO_MODE_OK' ++ and `MODES_TIEABLE_P'; it is very desirable for all integer modes ++ to be tieable. ++ ++ Many machines have special registers for floating point arithmetic. ++ Often people assume that floating point machine modes are allowed ++ only in floating point registers. This is not true. Any ++ registers that can hold integers can safely *hold* a floating ++ point machine mode, whether or not floating arithmetic can be done ++ on it in those registers. Integer move instructions can be used ++ to move the values. ++ ++ On some machines, though, the converse is true: fixed-point machine ++ modes may not go in floating registers. This is true if the ++ floating registers normalize any value stored in them, because ++ storing a non-floating value there would garble it. In this case, ++ `HARD_REGNO_MODE_OK' should reject fixed-point machine modes in ++ floating registers. But if the floating registers do not ++ automatically normalize, if you can store any bit pattern in one ++ and retrieve it unchanged without a trap, then any machine mode ++ may go in a floating register, so you can define this macro to say ++ so. ++ ++ The primary significance of special floating registers is rather ++ that they are the registers acceptable in floating point arithmetic ++ instructions. However, this is of no concern to ++ `HARD_REGNO_MODE_OK'. You handle it by writing the proper ++ constraints for those instructions. ++ ++ On some machines, the floating registers are especially slow to ++ access, so that it is better to store a value in a stack frame ++ than in such a register if floating point arithmetic is not being ++ done. As long as the floating registers are not in class ++ `GENERAL_REGS', they will not be used unless some pattern's ++ constraint asks for one. */ ++ ++#define MODES_TIEABLE_P(MODE1, MODE2) \ ++0 ++/* ++ ((MODE1) == (MODE2) \ ++ || ((MODE1) == QImode && (MODE2) == HImode) \ ++ || ((MODE1) == HImode && (MODE2) == QImode)) ++*/ ++/* A C expression that is nonzero if it is desirable to choose ++ register allocation so as to avoid move instructions between a ++ value of mode MODE1 and a value of mode MODE2. ++ ++ If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R, ++ MODE2)' are ever different for any R, then `MODES_TIEABLE_P (MODE1, ++ MODE2)' must be zero. */ ++ ++ ++ ++ ++enum reg_class { ++ NO_REGS, ++ PC_REG, /* r0 - PC */ ++ SP_REG, /* r1 - SP */ ++ STACK_REGS, /* r2 - SR */ ++ CG1_REG, /* r2 - CG1 */ ++ CG2_REG, /* r3 - CG2 */ ++ CG_REGS, /* r2, r3 */ ++ GENERAL_REGS, /* r4 - r15 */ ++ POINTER_REGS, ++ FFOUR_REG, ++ ALL_REGS, LIM_REG_CLASSES ++}; ++ ++/* An enumeral type that must be defined with all the register class ++ names as enumeral values. `NO_REGS' must be first. `ALL_REGS' ++ must be the last register class, followed by one more enumeral ++ value, `LIM_REG_CLASSES', which is not a register class but rather ++ tells how many classes there are. ++ ++ Each register class has a number, which is the value of casting ++ the class name to type `int'. The number serves as an index in ++ many of the tables described below. */ ++ ++ ++#define N_REG_CLASSES (int) LIM_REG_CLASSES ++/* The number of distinct register classes, defined as follows: ++ #define N_REG_CLASSES (int) LIM_REG_CLASSES */ ++ ++#define REG_CLASS_NAMES { \ ++ "NO_REGS", \ ++ "PC_REG", \ ++ "SP_REG", \ ++ "STACK_REGS", \ ++ "CG1_REG", \ ++ "CG2_REG", \ ++ "CG_REGS", \ ++ "GENERAL_REGS", \ ++ "POINTER_REGS", \ ++ "FFOUR_REG", \ ++ "ALL_REGS" \ ++} ++ ++/* An initializer containing the names of the register classes as C ++ string constants. These names are used in writing some of the ++ debugging dumps. */ ++ ++#define REG_CLASS_CONTENTS { \ ++ {0x00000000ul}, /* NO_REGS */ \ ++ {0x00000001ul}, /* PC_REG */ \ ++ {0x00000002ul}, /* SP_REG */ \ ++ {0x00000004ul}, /* r2 */ \ ++ {0x00000004ul}, /* r2 */ \ ++ {0x00000008ul}, /* r3 */ \ ++ {0x0000000cul}, /* r2,r3 */ \ ++ {0x0000fff2ul}, /* r4 - r15,r1 */ \ ++ {0x0000fff2ul}, /* r4 - r15,r1 */ \ ++ {0x0000fff0ul}, /* r4 - r15 */ \ ++ {0x0000fffful} /* ALL_REGS */ \ ++} ++/* An initializer containing the contents of the register classes, as ++ integers which are bit masks. The Nth integer specifies the ++ contents of class N. The way the integer MASK is interpreted is ++ that register R is in the class if `MASK & (1 << R)' is 1. ++ ++ When the machine has more than 32 registers, an integer does not ++ suffice. Then the integers are replaced by sub-initializers, ++ braced groupings containing several integers. Each ++ sub-initializer must be suitable as an initializer for the type ++ `HARD_REG_SET' which is defined in `hard-reg-set.h'. */ ++ ++ ++enum reg_class msp430_regno_reg_class PARAMS ((int)); ++#define REGNO_REG_CLASS(R) msp430_regno_reg_class(R) ++/* A C expression whose value is a register class containing hard ++ register REGNO. In general there is more than one such class; ++ choose a class which is "minimal", meaning that no smaller class ++ also contains the register. */ ++ ++#define BASE_REG_CLASS POINTER_REGS ++/* A macro whose definition is the name of the class to which a valid ++ base register must belong. A base register is one used in an ++ address which is the register value plus a displacement. */ ++ ++#define INDEX_REG_CLASS NO_REGS ++/* A macro whose definition is the name of the class to which a valid ++ index register must belong. An index register is one used in an ++ address where its value is either multiplied by a scale factor or ++ added to another register (as well as added to a displacement). */ ++ ++#define REG_CLASS_FROM_LETTER(C) msp430_reg_class_from_letter(C) ++/* A C expression which defines the machine-dependent operand ++ constraint letters for register classes. If CHAR is such a ++ letter, the value should be the register class corresponding to ++ it. Otherwise, the value should be `NO_REGS'. The register ++ letter `r', corresponding to class `GENERAL_REGS', will not be ++ passed to this macro; you do not need to handle it. */ ++ ++#define REGNO_OK_FOR_BASE_P(r) msp430_regno_ok_for_base_p(r) ++ ++/* A C expression which is nonzero if register number NUM is suitable ++ for use as a base register in operand addresses. It may be either ++ a suitable hard register or a pseudo register that has been ++ allocated such a hard register. */ ++ ++/* #define REGNO_MODE_OK_FOR_BASE_P(r, m) ++ A C expression that is just like `REGNO_OK_FOR_BASE_P', except that ++ that expression may examine the mode of the memory reference in ++ MODE. You should define this macro if the mode of the memory ++ reference affects whether a register may be used as a base ++ register. If you define this macro, the compiler will use it ++ instead of `REGNO_OK_FOR_BASE_P'. */ ++ ++#define REGNO_OK_FOR_INDEX_P(NUM) 0 ++/* A C expression which is nonzero if register number NUM is suitable ++ for use as an index register in operand addresses. It may be ++ either a suitable hard register or a pseudo register that has been ++ allocated such a hard register. ++ ++ The difference between an index register and a base register is ++ that the index register may be scaled. If an address involves the ++ sum of two registers, neither one of them scaled, then either one ++ may be labeled the "base" and the other the "index"; but whichever ++ labeling is used must fit the machine's constraints of which ++ registers may serve in each capacity. The compiler will try both ++ labelings, looking for one that is valid, and will reload one or ++ both registers only if neither labeling works. */ ++ ++#define PREFERRED_RELOAD_CLASS(X, CLASS) FFOUR_REG ++ ++/* ++referred_reload_class(X,CLASS) ++ A C expression that places additional restrictions on the register ++ class to use when it is necessary to copy value X into a register ++ in class CLASS. The value is a register class; perhaps CLASS, or ++ perhaps another, smaller class. On many machines, the following ++ definition is safe: ++ ++ #define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS ++ ++ Sometimes returning a more restrictive class makes better code. ++ For example, on the 68000, when X is an integer constant that is ++ in range for a `moveq' instruction, the value of this macro is ++ always `DATA_REGS' as long as CLASS includes the data registers. ++ Requiring a data register guarantees that a `moveq' will be used. ++ ++ If X is a `const_double', by returning `NO_REGS' you can force X ++ into a memory constant. This is useful on certain machines where ++ immediate floating values cannot be loaded into certain kinds of ++ registers. */ ++/* `PREFERRED_OUTPUT_RELOAD_CLASS (X, CLASS)' ++ Like `PREFERRED_RELOAD_CLASS', but for output reloads instead of ++ input reloads. If you don't define this macro, the default is to ++ use CLASS, unchanged. */ ++ ++/* `LIMIT_RELOAD_CLASS (MODE, CLASS)' ++ A C expression that places additional restrictions on the register ++ class to use when it is necessary to be able to hold a value of ++ mode MODE in a reload register for which class CLASS would ++ ordinarily be used. ++ ++ Unlike `PREFERRED_RELOAD_CLASS', this macro should be used when ++ there are certain modes that simply can't go in certain reload ++ classes. ++ ++ The value is a register class; perhaps CLASS, or perhaps another, ++ smaller class. ++ ++ Don't define this macro unless the target machine has limitations ++ which require the macro to do something nontrivial. */ ++ ++/* ++#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X) GENERAL_REGS ++ ++ ++#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X) GENERAL_REGS ++ ++ ++ `SECONDARY_RELOAD_CLASS (CLASS, MODE, X)' ++ `SECONDARY_OUTPUT_RELOAD_CLASS (CLASS, MODE, X)' ++ Many machines have some registers that cannot be copied directly ++ to or from memory or even from other types of registers. An ++ example is the `MQ' register, which on most machines, can only be ++ copied to or from general registers, but not memory. Some ++ machines allow copying all registers to and from memory, but ++ require a scratch register for stores to some memory locations ++ (e.g., those with symbolic address on the RT, and those with ++ certain symbolic address on the Sparc when compiling PIC). In ++ some cases, both an intermediate and a scratch register are ++ required. ++ ++ You should define these macros to indicate to the reload phase ++ that it may need to allocate at least one register for a reload in ++ addition to the register to contain the data. Specifically, if ++ copying X to a register CLASS in MODE requires an intermediate ++ register, you should define `SECONDARY_INPUT_RELOAD_CLASS' to ++ return the largest register class all of whose registers can be ++ used as intermediate registers or scratch registers. ++ ++ If copying a register CLASS in MODE to X requires an intermediate ++ or scratch register, `SECONDARY_OUTPUT_RELOAD_CLASS' should be ++ defined to return the largest register class required. If the ++ requirements for input and output reloads are the same, the macro ++ `SECONDARY_RELOAD_CLASS' should be used instead of defining both ++ macros identically. ++ ++ The values returned by these macros are often `GENERAL_REGS'. ++ Return `NO_REGS' if no spare register is needed; i.e., if X can be ++ directly copied to or from a register of CLASS in MODE without ++ requiring a scratch register. Do not define this macro if it ++ would always return `NO_REGS'. ++ ++ If a scratch register is required (either with or without an ++ intermediate register), you should define patterns for ++ `reload_inM' or `reload_outM', as required (*note Standard ++ Names::.. These patterns, which will normally be implemented with ++ a `define_expand', should be similar to the `movM' patterns, ++ except that operand 2 is the scratch register. ++ ++ Define constraints for the reload register and scratch register ++ that contain a single register class. If the original reload ++ register (whose class is CLASS) can meet the constraint given in ++ the pattern, the value returned by these macros is used for the ++ class of the scratch register. Otherwise, two additional reload ++ registers are required. Their classes are obtained from the ++ constraints in the insn pattern. ++ ++ X might be a pseudo-register or a `subreg' of a pseudo-register, ++ which could either be in a hard register or in memory. Use ++ `true_regnum' to find out; it will return -1 if the pseudo is in ++ memory and the hard register number if it is in a register. ++ ++ These macros should not be used in the case where a particular ++ class of registers can only be copied to memory and not to another ++ class of registers. In that case, secondary reload registers are ++ not needed and would not be helpful. Instead, a stack location ++ must be used to perform the copy and the `movM' pattern should use ++ memory as a intermediate storage. This case often occurs between ++ floating-point and general registers. */ ++ ++/* `SECONDARY_MEMORY_NEEDED (CLASS1, CLASS2, M)' ++ Certain machines have the property that some registers cannot be ++ copied to some other registers without using memory. Define this ++ macro on those machines to be a C expression that is non-zero if ++ objects of mode M in registers of CLASS1 can only be copied to ++ registers of class CLASS2 by storing a register of CLASS1 into ++ memory and loading that memory location into a register of CLASS2. ++ ++ Do not define this macro if its value would always be zero. ++ ++ `SECONDARY_MEMORY_NEEDED_RTX (MODE)' ++ Normally when `SECONDARY_MEMORY_NEEDED' is defined, the compiler ++ allocates a stack slot for a memory location needed for register ++ copies. If this macro is defined, the compiler instead uses the ++ memory location defined by this macro. ++ ++ Do not define this macro if you do not define ++ `SECONDARY_MEMORY_NEEDED'. */ ++ ++#define SMALL_REGISTER_CLASSES 1 ++/* Normally the compiler avoids choosing registers that have been ++ explicitly mentioned in the rtl as spill registers (these ++ registers are normally those used to pass parameters and return ++ values). However, some machines have so few registers of certain ++ classes that there would not be enough registers to use as spill ++ registers if this were done. ++ ++ Define `SMALL_REGISTER_CLASSES' to be an expression with a non-zero ++ value on these machines. When this macro has a non-zero value, the ++ compiler allows registers explicitly used in the rtl to be used as ++ spill registers but avoids extending the lifetime of these ++ registers. ++ ++ It is always safe to define this macro with a non-zero value, but ++ if you unnecessarily define it, you will reduce the amount of ++ optimizations that can be performed in some cases. If you do not ++ define this macro with a non-zero value when it is required, the ++ compiler will run out of spill registers and print a fatal error ++ message. For most machines, you should not define this macro at ++ all. */ ++ ++/* ++#define CLASS_LIKELY_SPILLED_P(CLASS) \ ++ ( (CLASS) != ALL_REGS && (CLASS) != GENERAL_REGS) ++ A C expression whose value is nonzero if pseudos that have been ++ assigned to registers of class CLASS would likely be spilled ++ because registers of CLASS are needed for spill registers. ++ ++ The default value of this macro returns 1 if CLASS has exactly one ++ register and zero otherwise. On most machines, this default ++ should be used. Only define this macro to some other expression ++ if pseudo allocated by `local-alloc.c' end up in memory because ++ their hard registers were needed for spill registers. If this ++ macro returns nonzero for those classes, those pseudos will only ++ be allocated by `global.c', which knows how to reallocate the ++ pseudo to another register. If there would not be another ++ register available for reallocation, you should not change the ++ definition of this macro since the only effect of such a ++ definition would be to slow down register allocation. */ ++ ++#define CLASS_MAX_NREGS(CLASS, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) ++/* A C expression for the maximum number of consecutive registers of ++ class CLASS needed to hold a value of mode MODE. ++ ++ This is closely related to the macro `HARD_REGNO_NREGS'. In fact, ++ the value of the macro `CLASS_MAX_NREGS (CLASS, MODE)' should be ++ the maximum value of `HARD_REGNO_NREGS (REGNO, MODE)' for all ++ REGNO values in the class CLASS. ++ ++ This macro helps control the handling of multiple-word values in ++ the reload pass. */ ++ ++#define CONST_OK_FOR_LETTER_P(VALUE, C) \ ++ ((C) == 'I' ? (VALUE) >= -32767 && (VALUE) <= 32767 : \ ++ (C) == 'J' ? (VALUE) <= 0 && (VALUE) >= -32767: \ ++ (C) == 'K' ? (VALUE) >= 0 && (VALUE) <= 32767 : \ ++ (C) == 'L' ? (VALUE) >= 0 && (VALUE) <= 0xff : \ ++ (C) == 'M' ? (VALUE) >= 0x10 && (VALUE) <= 0xff : \ ++ (C) == 'N' ? (VALUE) >= 0x100 && (VALUE) <= 0x1ff : \ ++ (C) == 'O' ? (VALUE)&1: \ ++ (C) == 'P' ? ((VALUE)==-1||(VALUE)==1||(VALUE)==2||(VALUE)==4||(VALUE)==8 ||(VALUE)==0) : 0) ++/* A C expression that defines the machine-dependent operand ++ constraint letters (`I', `J', `K', ... `P') that specify ++ particular ranges of integer values. If C is one of those ++ letters, the expression should check that VALUE, an integer, is in ++ the appropriate range and return 1 if so, 0 otherwise. If C is ++ not one of those letters, the value should be 0 regardless of ++ VALUE. */ ++ ++ ++#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ ++ ((C) == 'G' ? (VALUE) == CONST0_RTX (SFmode) \ ++ : 0) ++/* `CONST_DOUBLE_OK_FOR_LETTER_P (VALUE, C)' ++ A C expression that defines the machine-dependent operand ++ constraint letters that specify particular ranges of ++ `const_double' values (`G' or `H'). ++ ++ If C is one of those letters, the expression should check that ++ VALUE, an RTX of code `const_double', is in the appropriate range ++ and return 1 if so, 0 otherwise. If C is not one of those ++ letters, the value should be 0 regardless of VALUE. ++ ++ `const_double' is used for all floating-point constants and for ++ `DImode' fixed-point constants. A given letter can accept either ++ or both kinds of values. It can use `GET_MODE' to distinguish ++ between these kinds. */ ++ ++#define EXTRA_CONSTRAINT(x, c) extra_constraint(x, c) ++/* A C expression that defines the optional machine-dependent ++ constraint letters (``Q', `R', `S', `T', `U') that can' ++ be used to segregate specific types of operands, usually memory ++ references, for the target machine. Normally this macro will not ++ be defined. If it is required for a particular target machine, it ++ should return 1 if VALUE corresponds to the operand type ++ represented by the constraint letter C. If C is not defined as an ++ extra constraint, the value returned should be 0 regardless of ++ VALUE. ++ ++ For example, on the ROMP, load instructions cannot have their ++ output in r0 if the memory reference contains a symbolic address. ++ Constraint letter `Q' is defined as representing a memory address ++ that does *not* contain a symbolic address. An alternative is ++ specified with a `Q' constraint on the input and `r' on the ++ output. The next alternative specifies `m' on the input and a ++ register class that does not include r0 on the output. */ ++ ++/* This is an undocumented variable which describes ++ how GCC will push a data */ ++#define STACK_PUSH_CODE POST_DEC ++ ++#define STACK_GROWS_DOWNWARD ++/* Define this macro if pushing a word onto the stack moves the stack ++ pointer to a smaller address. ++ ++ When we say, "define this macro if ...," it means that the ++ compiler checks this macro only with `#ifdef' so the precise ++ definition used does not matter. */ ++ ++#define STARTING_FRAME_OFFSET 0 ++/* Offset from the frame pointer to the first local variable slot to ++ be allocated. ++ ++ If `FRAME_GROWS_DOWNWARD', find the next slot's offset by ++ subtracting the first slot's length from `STARTING_FRAME_OFFSET'. ++ Otherwise, it is found by adding the length of the first slot to ++ the value `STARTING_FRAME_OFFSET'. */ ++ ++#define STACK_POINTER_OFFSET 0 ++/* Offset from the stack pointer register to the first location at ++ which outgoing arguments are placed. If not specified, the ++ default value of zero is used. This is the proper value for most ++ machines. ++ ++ If `ARGS_GROW_DOWNWARD', this is the offset to the location above ++ the first location at which outgoing arguments are placed. */ ++ ++#define FIRST_PARM_OFFSET(FUNDECL) 0 ++/* Offset from the argument pointer register to the first argument's ++ address. On some machines it may depend on the data type of the ++ function. ++ ++ If `ARGS_GROW_DOWNWARD', this is the offset to the location above ++ the first argument's address. */ ++ ++/* `STACK_DYNAMIC_OFFSET (FUNDECL)' ++ Offset from the stack pointer register to an item dynamically ++ allocated on the stack, e.g., by `alloca'. ++ ++ The default value for this macro is `STACK_POINTER_OFFSET' plus the ++ length of the outgoing arguments. The default is correct for most ++ machines. See `function.c' for details. */ ++ ++#define STACK_BOUNDARY 16 ++/* Define this macro if there is a guaranteed alignment for the stack ++ pointer on this machine. The definition is a C expression for the ++ desired alignment (measured in bits). This value is used as a ++ default if PREFERRED_STACK_BOUNDARY is not defined. */ ++ ++#define STACK_POINTER_REGNUM 1 ++/* The register number of the stack pointer register, which must also ++ be a fixed register according to `FIXED_REGISTERS'. On most ++ machines, the hardware determines which register this is. */ ++ ++#define FRAME_POINTER_REGNUM 4 ++/* The register number of the frame pointer register, which is used to ++ access automatic variables in the stack frame. On some machines, ++ the hardware determines which register this is. On other ++ machines, you can choose any register you wish for this purpose. */ ++ ++#define ARG_POINTER_REGNUM 5 ++/* The register number of the arg pointer register, which is used to ++ access the function's argument list. On some machines, this is ++ the same as the frame pointer register. On some machines, the ++ hardware determines which register this is. On other machines, ++ you can choose any register you wish for this purpose. If this is ++ not the same register as the frame pointer register, then you must ++ mark it as a fixed register according to `FIXED_REGISTERS', or ++ arrange to be able to eliminate it (*note Elimination::.). */ ++ ++#define STATIC_CHAIN_REGNUM 6 ++/* Register numbers used for passing a function's static chain ++ pointer. If register windows are used, the register number as ++ seen by the called function is `STATIC_CHAIN_INCOMING_REGNUM', ++ while the register number as seen by the calling function is ++ `STATIC_CHAIN_REGNUM'. If these registers are the same, ++ `STATIC_CHAIN_INCOMING_REGNUM' need not be defined. ++ ++ The static chain register need not be a fixed register. ++ ++ If the static chain is passed in memory, these macros should not be ++ defined; instead, the next two macros should be defined. */ ++ ++#define FRAME_POINTER_REQUIRED frame_pointer_required_p() ++ ++/* ++ A C expression which is nonzero if a function must have and use a ++ frame pointer. This expression is evaluated in the reload pass. ++ If its value is nonzero the function will have a frame pointer. ++ ++ The expression can in principle examine the current function and ++ decide according to the facts, but on most machines the constant 0 ++ or the constant 1 suffices. Use 0 when the machine allows code to ++ be generated with no frame pointer, and doing so saves some time ++ or space. Use 1 when there is no possible advantage to avoiding a ++ frame pointer. ++ ++ In certain cases, the compiler does not know how to produce valid ++ code without a frame pointer. The compiler recognizes those cases ++ and automatically gives the function a frame pointer regardless of ++ what `FRAME_POINTER_REQUIRED' says. You don't need to worry about ++ them. ++ ++ In a function that does not require a frame pointer, the frame ++ pointer register can be allocated for ordinary usage, unless you ++ mark it as a fixed register. See `FIXED_REGISTERS' for more ++ information. */ ++ ++#define ELIMINABLE_REGS { \ ++ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ {ARG_POINTER_REGNUM, STACK_POINTER_REGNUM} \ ++} ++/* If defined, this macro specifies a table of register pairs used to ++ eliminate unneeded registers that point into the stack frame. If ++ it is not defined, the only elimination attempted by the compiler ++ is to replace references to the frame pointer with references to ++ the stack pointer. ++ ++ The definition of this macro is a list of structure ++ initializations, each of which specifies an original and ++ replacement register. ++ ++ On some machines, the position of the argument pointer is not ++ known until the compilation is completed. In such a case, a ++ separate hard register must be used for the argument pointer. ++ This register can be eliminated by replacing it with either the ++ frame pointer or the argument pointer, depending on whether or not ++ the frame pointer has been eliminated. ++ ++ In this case, you might specify: ++ #define ELIMINABLE_REGS \ ++ {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ ++ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} ++ ++ Note that the elimination of the argument pointer with the stack ++ pointer is specified first since that is the preferred elimination. */ ++ ++#define CAN_ELIMINATE(FROM, TO) 1 ++/* A C expression that returns non-zero if the compiler is allowed to ++ try to replace register number FROM-REG with register number ++ TO-REG. This macro need only be defined if `ELIMINABLE_REGS' is ++ defined, and will usually be the constant 1, since most of the ++ cases preventing register elimination are things that the compiler ++ already knows about. */ ++ ++#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ ++ OFFSET = initial_elimination_offset (FROM, TO) ++/* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'. It ++ specifies the initial difference between the specified pair of ++ registers. This macro must be defined if `ELIMINABLE_REGS' is ++ defined. */ ++/* ++#define RETURN_ADDR_RTX(count, x) \ ++ gen_rtx_MEM (Pmode, memory_address (Pmode, plus_constant (tem, 1))) ++*/ ++#define PUSH_ROUNDING(NPUSHED) ((NPUSHED+1) & ~1) ++/* A C expression that is the number of bytes actually pushed onto the ++ stack when an instruction attempts to push NPUSHED bytes. ++ ++ If the target machine does not have a push instruction, do not ++ define this macro. That directs GNU CC to use an alternate ++ strategy: to allocate the entire argument block and then store the ++ arguments into it. ++ ++ On some machines, the definition ++ ++ #define PUSH_ROUNDING(BYTES) (BYTES) ++ ++ will suffice. But on other machines, instructions that appear to ++ push one byte actually push two bytes in an attempt to maintain ++ alignment. Then the definition should be ++ ++ #define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1) */ ++ ++#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACK_SIZE) 0 ++/* A C expression that should indicate the number of bytes of its own ++ arguments that a function pops on returning, or 0 if the function ++ pops no arguments and the caller must therefore pop them all after ++ the function returns. ++ ++ FUNDECL is a C variable whose value is a tree node that describes ++ the function in question. Normally it is a node of type ++ `FUNCTION_DECL' that describes the declaration of the function. ++ From this you can obtain the DECL_MACHINE_ATTRIBUTES of the ++ function. ++ ++ FUNTYPE is a C variable whose value is a tree node that describes ++ the function in question. Normally it is a node of type ++ `FUNCTION_TYPE' that describes the data type of the function. ++ From this it is possible to obtain the data types of the value and ++ arguments (if known). ++ ++ When a call to a library function is being considered, FUNDECL ++ will contain an identifier node for the library function. Thus, if ++ you need to distinguish among various library functions, you can ++ do so by their names. Note that "library function" in this ++ context means a function used to perform arithmetic, whose name is ++ known specially in the compiler and was not mentioned in the C ++ code being compiled. ++ ++ STACK-SIZE is the number of bytes of arguments passed on the ++ stack. If a variable number of bytes is passed, it is zero, and ++ argument popping will always be the responsibility of the calling ++ function. ++ ++ On the Vax, all functions always pop their arguments, so the ++ definition of this macro is STACK-SIZE. On the 68000, using the ++ standard calling convention, no functions pop their arguments, so ++ the value of the macro is always 0 in this case. But an ++ alternative calling convention is available in which functions ++ that take a fixed number of arguments pop them but other functions ++ (such as `printf') pop nothing (the caller pops all). When this ++ convention is in use, FUNTYPE is examined to determine whether a ++ function takes a fixed number of arguments. */ ++ ++#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ ++(function_arg (&(CUM), MODE, TYPE, NAMED)) ++ ++/* ++#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \ ++(function_incoming_arg (&(CUM), MODE, TYPE, NAMED)) ++*/ ++/* A C expression that controls whether a function argument is passed ++ in a register, and which register. ++ ++ The arguments are CUM, which summarizes all the previous ++ arguments; MODE, the machine mode of the argument; TYPE, the data ++ type of the argument as a tree node or 0 if that is not known ++ (which happens for C support library functions); and NAMED, which ++ is 1 for an ordinary argument and 0 for nameless arguments that ++ correspond to `...' in the called function's prototype. ++ ++ The value of the expression is usually either a `reg' RTX for the ++ hard register in which to pass the argument, or zero to pass the ++ argument on the stack. ++ ++ For machines like the Vax and 68000, where normally all arguments ++ are pushed, zero suffices as a definition. ++ ++ The value of the expression can also be a `parallel' RTX. This is ++ used when an argument is passed in multiple locations. The mode ++ of the of the `parallel' should be the mode of the entire ++ argument. The `parallel' holds any number of `expr_list' pairs; ++ each one describes where part of the argument is passed. In each ++ `expr_list', the first operand can be either a `reg' RTX for the ++ hard register in which to pass this part of the argument, or zero ++ to pass the argument on the stack. If this operand is a `reg', ++ then the mode indicates how large this part of the argument is. ++ The second operand of the `expr_list' is a `const_int' which gives ++ the offset in bytes into the entire argument where this part ++ starts. ++ ++ The usual way to make the ANSI library `stdarg.h' work on a machine ++ where some arguments are usually passed in registers, is to cause ++ nameless arguments to be passed on the stack instead. This is done ++ by making `FUNCTION_ARG' return 0 whenever NAMED is 0. ++ ++ You may use the macro `MUST_PASS_IN_STACK (MODE, TYPE)' in the ++ definition of this macro to determine if this argument is of a ++ type that must be passed in the stack. If `REG_PARM_STACK_SPACE' ++ is not defined and `FUNCTION_ARG' returns non-zero for such an ++ argument, the compiler will abort. If `REG_PARM_STACK_SPACE' is ++ defined, the argument will be computed in the stack and then ++ loaded into a register. */ ++ ++typedef struct msp430_args { ++ int nregs; /* # registers available for passing */ ++ int regno; /* next available register number */ ++} CUMULATIVE_ARGS; ++/* A C type for declaring a variable that is used as the first ++ argument of `FUNCTION_ARG' and other related values. For some ++ target machines, the type `int' suffices and can hold the number ++ of bytes of argument so far. ++ ++ There is no need to record in `CUMULATIVE_ARGS' anything about the ++ arguments that have been passed on the stack. The compiler has ++ other variables to keep track of that. For target machines on ++ which all arguments are passed on the stack, there is no need to ++ store anything in `CUMULATIVE_ARGS'; however, the data structure ++ must exist and should not be empty, so use `int'. */ ++ ++#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ ++init_cumulative_args (&(CUM), FNTYPE, LIBNAME, INDIRECT) ++ ++#define INIT_CUMULATIVE_INCOMING_ARGS(CUM, FNTYPE, LIBNAME) \ ++init_cumulative_incoming_args(&(CUM), FNTYPE, LIBNAME) ++ ++/* A C statement (sans semicolon) for initializing the variable CUM ++ for the state at the beginning of the argument list. The variable ++ has type `CUMULATIVE_ARGS'. The value of FNTYPE is the tree node ++ for the data type of the function which will receive the args, or 0 ++ if the args are to a compiler support library function. The value ++ of INDIRECT is nonzero when processing an indirect call, for ++ example a call through a function pointer. The value of INDIRECT ++ is zero for a call to an explicitly named function, a library ++ function call, or when `INIT_CUMULATIVE_ARGS' is used to find ++ arguments for the function being compiled. ++ ++ When processing a call to a compiler support library function, ++ LIBNAME identifies which one. It is a `symbol_ref' rtx which ++ contains the name of the function, as a string. LIBNAME is 0 when ++ an ordinary C function call is being processed. Thus, each time ++ this macro is called, either LIBNAME or FNTYPE is nonzero, but ++ never both of them at once. */ ++ ++#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ ++ (function_arg_advance (&CUM, MODE, TYPE, NAMED)) ++ ++/* A C statement (sans semicolon) to update the summarizer variable ++ CUM to advance past an argument in the argument list. The values ++ MODE, TYPE and NAMED describe that argument. Once this is done, ++ the variable CUM is suitable for analyzing the *following* ++ argument with `FUNCTION_ARG', etc. ++ ++ This macro need not do anything if the argument in question was ++ passed on the stack. The compiler knows how to track the amount ++ of stack space used for arguments without any special help. */ ++ ++#define FUNCTION_ARG_REGNO_P(r) (r >= 12 && r <= 15) ++/* A C expression that is nonzero if REGNO is the number of a hard ++ register in which function arguments are sometimes passed. This ++ does *not* include implicit arguments such as the static chain and ++ the structure-value address. On many machines, no registers can be ++ used for this purpose since all function arguments are pushed on ++ the stack. */ ++ ++extern int msp430_reg_order[]; ++ ++#define RET_REGISTER 15 /* msp430_ret_register ()*/ ++ ++#define FUNCTION_VALUE(VALTYPE, FUNC) msp430_function_value (VALTYPE, FUNC) ++/* A C expression to create an RTX representing the place where a ++ function returns a value of data type VALTYPE. VALTYPE is a tree ++ node representing a data type. Write `TYPE_MODE (VALTYPE)' to get ++ the machine mode used to represent that type. On many machines, ++ only the mode is relevant. (Actually, on most machines, scalar ++ values are returned in the same place regardless of mode). ++ ++ The value of the expression is usually a `reg' RTX for the hard ++ register where the return value is stored. The value can also be a ++ `parallel' RTX, if the return value is in multiple places. See ++ `FUNCTION_ARG' for an explanation of the `parallel' form. ++ ++ If `PROMOTE_FUNCTION_RETURN' is defined, you must apply the same ++ promotion rules specified in `PROMOTE_MODE' if VALTYPE is a scalar ++ type. ++ ++ If the precise function being called is known, FUNC is a tree node ++ (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer. This ++ makes it possible to use a different value-returning convention ++ for specific functions when all their calls are known. ++ ++ `FUNCTION_VALUE' is not used for return vales with aggregate data ++ types, because these are returned in another way. See ++ `STRUCT_VALUE_REGNUM' and related macros, below. */ ++ ++#define LIBCALL_VALUE(MODE) msp430_libcall_value (MODE) ++/* A C expression to create an RTX representing the place where a ++ library function returns a value of mode MODE. If the precise ++ function being called is known, FUNC is a tree node ++ (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer. This ++ makes it possible to use a different value-returning convention ++ for specific functions when all their calls are known. ++ ++ Note that "library function" in this context means a compiler ++ support routine, used to perform arithmetic, whose name is known ++ specially by the compiler and was not mentioned in the C code being ++ compiled. ++ ++ The definition of `LIBRARY_VALUE' need not be concerned aggregate ++ data types, because none of the library functions returns such ++ types. */ ++ ++#define FUNCTION_VALUE_REGNO_P(N) ((N) == RET_REGISTER) ++/* A C expression that is nonzero if REGNO is the number of a hard ++ register in which the values of called function may come back. ++ ++ A register whose use for returning values is limited to serving as ++ the second of a pair (for a value of type `double', say) need not ++ be recognized by this macro. So for most machines, this definition ++ suffices: ++ ++ #define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) ++ ++ If the machine has register windows, so that the caller and the ++ called function use different registers for the return value, this ++ macro should recognize only the caller's register numbers. */ ++ ++#define RETURN_IN_MEMORY(TYPE) ((TYPE_MODE (TYPE) == BLKmode) \ ++ ? int_size_in_bytes (TYPE) > 8 \ ++ : 0) ++/* A C expression which can inhibit the returning of certain function ++ values in registers, based on the type of value. A nonzero value ++ says to return the function value in memory, just as large ++ structures are always returned. Here TYPE will be a C expression ++ of type `tree', representing the data type of the value. ++ ++ Note that values of mode `BLKmode' must be explicitly handled by ++ this macro. Also, the option `-fpcc-struct-return' takes effect ++ regardless of this macro. On most systems, it is possible to ++ leave the macro undefined; this causes a default definition to be ++ used, whose value is the constant 1 for `BLKmode' values, and 0 ++ otherwise. ++ ++ Do not use this macro to indicate that structures and unions ++ should always be returned in memory. You should instead use ++ `DEFAULT_PCC_STRUCT_RETURN' to indicate this. */ ++ ++#define DEFAULT_PCC_STRUCT_RETURN 0 ++/* Define this macro to be 1 if all structure and union return values ++ must be in memory. Since this results in slower code, this should ++ be defined only if needed for compatibility with other compilers ++ or with an ABI. If you define this macro to be 0, then the ++ conventions used for structure and union return values are decided ++ by the `RETURN_IN_MEMORY' macro. ++ ++ If not defined, this defaults to the value 1. */ ++ ++#define STRUCT_VALUE 0 ++/* If the structure value address is not passed in a register, define ++ `STRUCT_VALUE' as an expression returning an RTX for the place ++ where the address is passed. If it returns 0, the address is ++ passed as an "invisible" first argument. */ ++ ++#define STRUCT_VALUE_INCOMING 0 ++/* If the incoming location is not a register, then you should define ++ `STRUCT_VALUE_INCOMING' as an expression for an RTX for where the ++ called function should find the value. If it should find the ++ value on the stack, define this to create a `mem' which refers to ++ the frame pointer. A definition of 0 means that the address is ++ passed as an "invisible" first argument. */ ++ ++#define STRICT_ARGUMENT_NAMING 1 ++/* Define this macro if the location where a function argument is ++ passed depends on whether or not it is a named argument. ++ ++ This macro controls how the NAMED argument to `FUNCTION_ARG' is ++ set for varargs and stdarg functions. With this macro defined, ++ the NAMED argument is always true for named arguments, and false ++ for unnamed arguments. If this is not defined, but ++ `SETUP_INCOMING_VARARGS' is defined, then all arguments are ++ treated as named. Otherwise, all named arguments except the last ++ are treated as named. */ ++ ++ ++/* ++#define HAVE_PRE_INCREMENT 1 ++*/ ++ ++#define HAVE_POST_INCREMENT 1 ++ ++/* ++#define HAVE_PRE_DECREMENT 1 ++#define HAVE_PRE_INCREMENT 1 ++#define HAVE_POST_DECREMENT 1 ++*/ ++/* Similar for other kinds of addressing. */ ++ ++#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) ++ ++/* ++(GET_CODE (X) == LABEL_REF \ ++|| GET_CODE (X) == SYMBOL_REF \ ++|| GET_CODE (X) == CONST_INT \ ++|| GET_CODE (X) == CONST) ++*/ ++ ++/* ++#define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \ ++do{CODE = msp430_canonicalize_comparison(CODE, &OP0, &OP1); }while(0) ++*/ ++ ++/* A C expression that is 1 if the RTX X is a constant which is a ++ valid address. On most machines, this can be defined as ++ `CONSTANT_P (X)', but a few machines are more restrictive in which ++ constant addresses are supported. ++ ++ `CONSTANT_P' accepts integer-values expressions whose values are ++ not explicitly known, such as `symbol_ref', `label_ref', and ++ `high' expressions and `const' arithmetic expressions, in addition ++ to `const_int' and `const_double' expressions. */ ++ ++#define MAX_REGS_PER_ADDRESS 1 ++/* A number, the maximum number of registers that can appear in a ++ valid memory address. Note that it is up to you to specify a ++ value equal to the maximum number that `GO_IF_LEGITIMATE_ADDRESS' ++ would ever accept. */ ++ ++#ifdef REG_OK_STRICT ++# define GO_IF_LEGITIMATE_ADDRESS(mode, operand, ADDR) \ ++{ \ ++ if (legitimate_address_p (mode, operand, 1)) \ ++ goto ADDR; \ ++} ++# else ++# define GO_IF_LEGITIMATE_ADDRESS(mode, operand, ADDR) \ ++{ \ ++ if (legitimate_address_p (mode, operand, 0)) \ ++ goto ADDR; \ ++} ++#endif ++/* A C compound statement with a conditional `goto LABEL;' executed ++ if X (an RTX) is a legitimate memory address on the target machine ++ for a memory operand of mode MODE. ++ ++ It usually pays to define several simpler macros to serve as ++ subroutines for this one. Otherwise it may be too complicated to ++ understand. ++ ++ This macro must exist in two variants: a strict variant and a ++ non-strict one. The strict variant is used in the reload pass. It ++ must be defined so that any pseudo-register that has not been ++ allocated a hard register is considered a memory reference. In ++ contexts where some kind of register is required, a pseudo-register ++ with no hard register must be rejected. ++ ++ The non-strict variant is used in other passes. It must be ++ defined to accept all pseudo-registers in every context where some ++ kind of register is required. ++ ++ Compiler source files that want to use the strict variant of this ++ macro define the macro `REG_OK_STRICT'. You should use an `#ifdef ++ REG_OK_STRICT' conditional to define the strict variant in that ++ case and the non-strict variant otherwise. ++ ++ Subroutines to check for acceptable registers for various purposes ++ (one for base registers, one for index registers, and so on) are ++ typically among the subroutines used to define ++ `GO_IF_LEGITIMATE_ADDRESS'. Then only these subroutine macros ++ need have two variants; the higher levels of macros may be the ++ same whether strict or not. ++ ++ Normally, constant addresses which are the sum of a `symbol_ref' ++ and an integer are stored inside a `const' RTX to mark them as ++ constant. Therefore, there is no need to recognize such sums ++ specifically as legitimate addresses. Normally you would simply ++ recognize any `const' as legitimate. ++ ++ Usually `PRINT_OPERAND_ADDRESS' is not prepared to handle constant ++ sums that are not marked with `const'. It assumes that a naked ++ `plus' indicates indexing. If so, then you *must* reject such ++ naked constant sums as illegitimate addresses, so that none of ++ them will be given to `PRINT_OPERAND_ADDRESS'. ++ ++ On some machines, whether a symbolic address is legitimate depends ++ on the section that the address refers to. On these machines, ++ define the macro `ENCODE_SECTION_INFO' to store the information ++ into the `symbol_ref', and then check for it here. When you see a ++ `const', you will have to look inside it to find the `symbol_ref' ++ in order to determine the section. *Note Assembler Format::. ++ ++ The best way to modify the name string is by adding text to the ++ beginning, with suitable punctuation to prevent any ambiguity. ++ Allocate the new name in `saveable_obstack'. You will have to ++ modify `ASM_OUTPUT_LABELREF' to remove and decode the added text ++ and output the name accordingly, and define `STRIP_NAME_ENCODING' ++ to access the original name string. ++ ++ You can check the information stored here into the `symbol_ref' in ++ the definitions of the macros `GO_IF_LEGITIMATE_ADDRESS' and ++ `PRINT_OPERAND_ADDRESS'. */ ++ ++/* `REG_OK_FOR_BASE_P (X)' ++ A C expression that is nonzero if X (assumed to be a `reg' RTX) is ++ valid for use as a base register. For hard registers, it should ++ always accept those which the hardware permits and reject the ++ others. Whether the macro accepts or rejects pseudo registers ++ must be controlled by `REG_OK_STRICT' as described above. This ++ usually requires two variant definitions, of which `REG_OK_STRICT' ++ controls the one actually used. */ ++ ++#define REG_OK_FOR_BASE_NOSTRICT_P(X) \ ++ (REGNO (X) >= FIRST_PSEUDO_REGISTER || REG_OK_FOR_BASE_STRICT_P(X)) ++ ++#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) ++ ++#ifdef REG_OK_STRICT ++# define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P (X) ++#else ++# define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NOSTRICT_P (X) ++#endif ++ ++/* A C expression that is just like `REG_OK_FOR_BASE_P', except that ++ that expression may examine the mode of the memory reference in ++ MODE. You should define this macro if the mode of the memory ++ reference affects whether a register may be used as a base ++ register. If you define this macro, the compiler will use it ++ instead of `REG_OK_FOR_BASE_P'. */ ++ ++ ++#define REG_OK_FOR_INDEX_P(X) 0 /*( REGNO(X)!=3 && REGNO(X)!=2 &®NO(X)<=15) */ ++/* A C expression that is nonzero if X (assumed to be a `reg' RTX) is ++ valid for use as an index register. ++ ++ The difference between an index register and a base register is ++ that the index register may be scaled. If an address involves the ++ sum of two registers, neither one of them scaled, then either one ++ may be labeled the "base" and the other the "index"; but whichever ++ labeling is used must fit the machine's constraints of which ++ registers may serve in each capacity. The compiler will try both ++ labelings, looking for one that is valid, and will reload one or ++ both registers only if neither labeling works. */ ++ ++#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ ++GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN) ++ ++/*{ \ ++ \ ++ (X) = legitimize_address (X, OLDX, MODE); \ ++ if (memory_address_p (MODE, X)) \ ++ goto WIN; \ ++ \ ++} */ ++ ++/* A C compound statement that attempts to replace X with a valid ++ memory address for an operand of mode MODE. WIN will be a C ++ statement label elsewhere in the code; the macro definition may use ++ ++ GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); ++ ++ to avoid further processing if the address has become legitimate. ++ ++ X will always be the result of a call to `break_out_memory_refs', ++ and OLDX will be the operand that was given to that function to ++ produce X. ++ ++ The code generated by this macro should not alter the substructure ++ of X. If it transforms X into a more legitimate form, it should ++ assign X (which will always be a C variable) a new value. ++ ++ It is not necessary for this macro to come up with a legitimate ++ address. The compiler has standard ways of doing so in all cases. ++ In fact, it is safe for this macro to do nothing. But often a ++ machine-dependent strategy can generate better code. */ ++ ++/* A C compound statement that attempts to replace X, which is an ++ address that needs reloading, with a valid memory address for an ++ operand of mode MODE. WIN will be a C statement label elsewhere ++ in the code. It is not necessary to define this macro, but it ++ might be useful for performance reasons. ++ ++ For example, on the i386, it is sometimes possible to use a single ++ reload register instead of two by reloading a sum of two pseudo ++ registers into a register. On the other hand, for number of RISC ++ processors offsets are limited so that often an intermediate ++ address needs to be generated in order to address a stack slot. ++ By defining LEGITIMIZE_RELOAD_ADDRESS appropriately, the ++ intermediate addresses generated for adjacent some stack slots can ++ be made identical, and thus be shared. ++ ++ *Note*: This macro should be used with caution. It is necessary ++ to know something of how reload works in order to effectively use ++ this, and it is quite easy to produce macros that build in too ++ much knowledge of reload internals. ++ ++ *Note*: This macro must be able to reload an address created by a ++ previous invocation of this macro. If it fails to handle such ++ addresses then the compiler may generate incorrect code or abort. ++ ++ The macro definition should use `push_reload' to indicate parts ++ that need reloading; OPNUM, TYPE and IND_LEVELS are usually ++ suitable to be passed unaltered to `push_reload'. ++ ++ The code generated by this macro must not alter the substructure of ++ X. If it transforms X into a more legitimate form, it should ++ assign X (which will always be a C variable) a new value. This ++ also applies to parts that you change indirectly by calling ++ `push_reload'. ++ ++ The macro definition may use `strict_memory_address_p' to test if ++ the address has become legitimate. ++ ++ If you want to change only a part of X, one standard way of doing ++ this is to use `copy_rtx'. Note, however, that is unshares only a ++ single level of rtl. Thus, if the part to be changed is not at the ++ top level, you'll need to replace first the top leve It is not ++ necessary for this macro to come up with a legitimate address; ++ but often a machine-dependent strategy can generate better code. */ ++ ++#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ ++{} ++/* A C statement or compound statement with a conditional `goto ++ LABEL;' executed if memory address X (an RTX) can have different ++ meanings depending on the machine mode of the memory reference it ++ is used for or if the address is valid for some modes but not ++ others. ++ ++ Autoincrement and autodecrement addresses typically have ++ mode-dependent effects because the amount of the increment or ++ decrement is the size of the operand being addressed. Some ++ machines have other mode-dependent addresses. Many RISC machines ++ have no mode-dependent addresses. ++ ++ You may assume that ADDR is a valid address for the machine. */ ++ ++#define LEGITIMATE_CONSTANT_P(X) 1 ++/* A C expression that is nonzero if X is a legitimate constant for ++ an immediate operand on the target machine. You can assume that X ++ satisfies `CONSTANT_P', so you need not check this. In fact, `1' ++ is a suitable definition for this macro on machines where anything ++ `CONSTANT_P' is valid. */ ++ ++#define CONST_COSTS(x,CODE,OUTER_CODE) \ ++ case CONST_INT: \ ++ if (OUTER_CODE == PLUS \ ++ || OUTER_CODE == IOR \ ++ || OUTER_CODE == AND \ ++ || OUTER_CODE == MINUS \ ++ || OUTER_CODE == SET \ ++ || INTVAL (x) == 0 \ ++ || INTVAL (x) == 1 \ ++ || INTVAL (x) == 2 \ ++ || INTVAL (x) == 4 \ ++ || INTVAL (x) == 8 \ ++ || INTVAL (x) == -1) \ ++ return 0; \ ++ case CONST: \ ++ return 0; \ ++ case LABEL_REF: \ ++ return 1; \ ++ case SYMBOL_REF: \ ++ return 2; \ ++ case CONST_DOUBLE: \ ++ return 4; ++ ++/* A part of a C `switch' statement that describes the relative costs ++ of constant RTL expressions. It must contain `case' labels for ++ expression codes `const_int', `const', `symbol_ref', `label_ref' ++ and `const_double'. Each case must ultimately reach a `return' ++ statement to return the relative cost of the use of that kind of ++ constant value in an expression. The cost may depend on the ++ precise value of the constant, which is available for examination ++ in X, and the rtx code of the expression in which it is contained, ++ found in OUTER_CODE. ++ ++ CODE is the expression code--redundant, since it can be obtained ++ with `GET_CODE (X)'. */ ++ ++#define DEFAULT_RTX_COSTS(x, code, outer_code) \ ++{ \ ++ int cst = default_rtx_costs (x, code, outer_code); \ ++ if (cst>0) \ ++ return cst; \ ++ else if (cst<0) \ ++ total += -cst; \ ++ break; \ ++} ++ ++/* Like `CONST_COSTS' but applies to nonconstant RTL expressions. ++ This can be used, for example, to indicate how costly a multiply ++ instruction is. In writing this macro, you can use the construct ++ `COSTS_N_INSNS (N)' to specify a cost equal to N fast ++ instructions. OUTER_CODE is the code of the expression in which X ++ is contained. ++ ++ This macro is optional; do not define it if the default cost ++ assumptions are adequate for the target machine. */ ++ ++#define ADDRESS_COST(ADDRESS) 2 ++ ++/* An expression giving the cost of an addressing mode that contains ++ ADDRESS. If not defined, the cost is computed from the ADDRESS ++ expression and the `CONST_COSTS' values. ++ ++ For most CISC machines, the default cost is a good approximation ++ of the true cost of the addressing mode. However, on RISC ++ machines, all instructions normally have the same length and ++ execution time. Hence all addresses will have equal costs. ++ ++ In cases where more than one form of an address is known, the form ++ with the lowest cost will be used. If multiple forms have the ++ same, lowest, cost, the one that is the most complex will be used. ++ ++ For example, suppose an address that is equal to the sum of a ++ register and a constant is used twice in the same basic block. ++ When this macro is not defined, the address will be computed in a ++ register and memory references will be indirect through that ++ register. On machines where the cost of the addressing mode ++ containing the sum is no higher than that of a simple indirect ++ reference, this will produce an additional instruction and ++ possibly require an additional register. Proper specification of ++ this macro eliminates this overhead for such machines. ++ ++ Similar use of this macro is made in strength reduction of loops. ++ ++ ADDRESS need not be valid as an address. In such a case, the cost ++ is not relevant and can be any value; invalid addresses need not be ++ assigned a different cost. ++ ++ On machines where an address involving more than one register is as ++ cheap as an address computation involving only one register, ++ defining `ADDRESS_COST' to reflect this can cause two registers to ++ be live over a region of code where only one would have been if ++ `ADDRESS_COST' were not defined in that manner. This effect should ++ be considered in the definition of this macro. Equivalent costs ++ should probably only be given to addresses with different numbers ++ of registers on machines with lots of registers. ++ ++ This macro will normally either not be defined or be defined as a ++ constant. */ ++ ++#define REGISTER_MOVE_COST(MODE, FROM, TO) ((MODE)==QImode ? 1 : \ ++ (MODE)==HImode ? 1 : \ ++ (MODE)==SImode ? 2 : \ ++ (MODE)==SFmode ? 2 : 4) ++ ++/* A C expression for the cost of moving data from a register in class ++ FROM to one in class TO. The classes are expressed using the ++ enumeration values such as `GENERAL_REGS'. A value of 2 is the ++ default; other values are interpreted relative to that. ++ ++ It is not required that the cost always equal 2 when FROM is the ++ same as TO; on some machines it is expensive to move between ++ registers if they are not general registers. ++ ++ If reload sees an insn consisting of a single `set' between two ++ hard registers, and if `REGISTER_MOVE_COST' applied to their ++ classes returns a value of 2, reload does not check to ensure that ++ the constraints of the insn are met. Setting a cost of other than ++ 2 will allow reload to verify that the constraints are met. You ++ should do this if the `movM' pattern's constraints do not allow ++ such copying. */ ++ ++#define MEMORY_MOVE_COST(MODE,CLASS,IN) ((MODE)==QImode ? 2 : \ ++ (MODE)==HImode ? 2 : \ ++ (MODE)==SImode ? 4 : \ ++ (MODE)==SFmode ? 4 : 8) ++/* A C expression for the cost of moving data of mode M between a ++ register and memory. A value of 4 is the default; this cost is ++ relative to those in `REGISTER_MOVE_COST'. ++ ++ If moving between registers and memory is more expensive than ++ between two registers, you should define this macro to express the ++ relative cost. */ ++ ++#define BRANCH_COST 0 ++/* A C expression for the cost of a branch instruction. A value of 1 ++ is the default; other values are interpreted relative to that. ++ ++ Here are additional macros which do not specify precise relative ++ costs, but only that certain actions are more expensive than GCC would ++ ordinarily expect. */ ++ ++#define SLOW_BYTE_ACCESS 0 ++/* Define this macro as a C expression which is nonzero if accessing ++ less than a word of memory (i.e. a `char' or a `short') is no ++ faster than accessing a word of memory, i.e., if such access ++ require more than one instruction or if there is no difference in ++ cost between byte and (aligned) word loads. ++ ++ When this macro is not defined, the compiler will access a field by ++ finding the smallest containing object; when it is defined, a ++ fullword load will be used if alignment permits. Unless bytes ++ accesses are faster than word accesses, using word accesses is ++ preferable since it may eliminate subsequent memory access if ++ subsequent accesses occur to other fields in the same word of the ++ structure, but to different bytes. ++ ++ `SLOW_ZERO_EXTEND' ++ Define this macro if zero-extension (of a `char' or `short' to an ++ `int') can be done faster if the destination is a register that is ++ known to be zero. ++ ++ If you define this macro, you must have instruction patterns that ++ recognize RTL structures like this: ++ ++ (set (strict_low_part (subreg:QI (reg:SI ...) 0)) ...) ++ ++ and likewise for `HImode'. ++ ++ `SLOW_UNALIGNED_ACCESS' ++ Define this macro to be the value 1 if unaligned accesses have a ++ cost many times greater than aligned accesses, for example if they ++ are emulated in a trap handler. ++ ++ When this macro is non-zero, the compiler will act as if ++ `STRICT_ALIGNMENT' were non-zero when generating code for block ++ moves. This can cause significantly more instructions to be ++ produced. Therefore, do not set this macro non-zero if unaligned ++ accesses only add a cycle or two to the time for a memory access. ++ ++ If the value of this macro is always zero, it need not be defined. ++ ++ `DONT_REDUCE_ADDR' ++ Define this macro to inhibit strength reduction of memory ++ addresses. (On some machines, such strength reduction seems to do ++ harm rather than good.) ++ ++ `MOVE_RATIO' ++ The number of scalar move insns which should be generated instead ++ of a string move insn or a library call. Increasing the value ++ will always make code faster, but eventually incurs high cost in ++ increased code size. ++ ++ If you don't define this, a reasonable default is used. */ ++ ++#define NO_FUNCTION_CSE ++/* Define this macro if it is as good or better to call a constant ++ function address than to call an address kept in a register. */ ++ ++#define NO_RECURSIVE_FUNCTION_CSE ++/* Define this macro if it is as good or better for a function to call ++ itself with an explicit address than to call an address kept in a ++ register. ++ ++ `ADJUST_COST (INSN, LINK, DEP_INSN, COST)' ++ A C statement (sans semicolon) to update the integer variable COST ++ based on the relationship between INSN that is dependent on ++ DEP_INSN through the dependence LINK. The default is to make no ++ adjustment to COST. This can be used for example to specify to ++ the scheduler that an output- or anti-dependence does not incur ++ the same cost as a data-dependence. ++ ++ `ADJUST_PRIORITY (INSN)' ++ A C statement (sans semicolon) to update the integer scheduling ++ priority `INSN_PRIORITY(INSN)'. Reduce the priority to execute ++ the INSN earlier, increase the priority to execute INSN later. ++ Do not define this macro if you do not need to adjust the ++ scheduling priorities of insns. */ ++ ++ ++#define TEXT_SECTION_ASM_OP "\t.text" ++/* A C expression whose value is a string containing the assembler ++ operation that should precede instructions and read-only data. ++ Normally `"\t.text"' is right. */ ++ ++#define DATA_SECTION_ASM_OP "\t.data" ++/* A C expression whose value is a string containing the assembler ++ operation to identify the following data as writable initialized ++ data. Normally `"\t.data"' is right. */ ++ ++#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section ++ ++#define EXTRA_SECTIONS in_bootloader, in_infomem ++/* A list of names for sections other than the standard two, which are ++ `in_text' and `in_data'. You need not define this macro on a ++ system with no other sections (that GCC needs to use). */ ++ ++#define EXTRA_SECTION_FUNCTIONS \ ++ \ ++void \ ++bootloader_section (void) \ ++{ \ ++ if (in_section != in_bootloader) \ ++ { \ ++ fprintf (asm_out_file, \ ++ "\t.section .bootloader, \"ax\", @progbits\n"); \ ++ /* Should already be aligned, this is just to be safe if it isn't. */ \ ++ fprintf (asm_out_file, "\t.p2align 1\n"); \ ++ in_section = in_bootloader; \ ++ } \ ++} \ ++ \ ++void \ ++infomem_section (void) \ ++{ \ ++ if (in_section != in_infomem) \ ++ { \ ++ fprintf (asm_out_file, \ ++ "\t.section .infomem, \"a\", @progbits\n"); \ ++ /* Should already be aligned, this is just to be safe if it isn't. */ \ ++ fprintf (asm_out_file, "\t.p2align 1\n"); \ ++ in_section = in_infomem; \ ++ } \ ++} ++ ++ ++/* Define the pseudo-ops used to switch to the .ctors and .dtors sections. ++ There are no shared libraries on this target, and these sections are ++ placed in the read-only program memory, so they are not writable. */ ++ ++#undef CTORS_SECTION_ASM_OP ++#define CTORS_SECTION_ASM_OP "\t.global\t__do_global_ctors\n\t.section .ctors,\"a\",@progbits" ++ ++#undef DTORS_SECTION_ASM_OP ++#define DTORS_SECTION_ASM_OP "\t.global\t__do_global_dtors\n\t.section .dtors,\"a\",@progbits" ++ ++#define TARGET_ASM_CONSTRUCTOR default_ctor_section_asm_out_constructor ++ ++#define TARGET_ASM_DESTRUCTOR default_dtor_section_asm_out_destructor ++ ++/* `EXTRA_SECTION_FUNCTIONS' ++ One or more functions to be defined in `varasm.c'. These ++ functions should do jobs analogous to those of `text_section' and ++ `data_section', for your additional sections. Do not define this ++ macro if you do not define `EXTRA_SECTIONS'. */ ++ ++/* ++#define READONLY_DATA_SECTION data_section ++ On most machines, read-only variables, constants, and jump tables ++ are placed in the text section. If this is not the case on your ++ machine, this macro should be defined to be the name of a function ++ (either `data_section' or a function defined in `EXTRA_SECTIONS') ++ that switches to the section to be used for read-only items. ++ ++ If these items should be placed in the text section, this macro ++ should not be defined. */ ++ ++/* `SELECT_SECTION (EXP, RELOC)' ++ A C statement or statements to switch to the appropriate section ++ for output of EXP. You can assume that EXP is either a `VAR_DECL' ++ node or a constant of some sort. RELOC indicates whether the ++ initial value of EXP requires link-time relocations. Select the ++ section by calling `text_section' or one of the alternatives for ++ other sections. ++ ++ Do not define this macro if you put all read-only variables and ++ constants in the read-only data section (usually the text section). */ ++ ++/* `SELECT_RTX_SECTION (MODE, RTX)' ++ A C statement or statements to switch to the appropriate section ++ for output of RTX in mode MODE. You can assume that RTX is some ++ kind of constant in RTL. The argument MODE is redundant except in ++ the case of a `const_int' rtx. Select the section by calling ++ `text_section' or one of the alternatives for other sections. ++ ++ Do not define this macro if you put all constants in the read-only ++ data section. */ ++ ++#define JUMP_TABLES_IN_TEXT_SECTION 0 ++/* Define this macro if jump tables (for `tablejump' insns) should be ++ output in the text section, along with the assembler instructions. ++ Otherwise, the readonly data section is used. ++ ++ This macro is irrelevant if there is no separate readonly data ++ section. */ ++ ++/* ???? ++#define ENCODE_SECTION_INFO(DECL) encode_section_info(DECL) ++ Define this macro if references to a symbol must be treated ++ differently depending on something about the variable or function ++ named by the symbol (such as what section it is in). ++ ++ The macro definition, if any, is executed immediately after the ++ rtl for DECL has been created and stored in `DECL_RTL (DECL)'. ++ The value of the rtl will be a `mem' whose address is a ++ `symbol_ref'. ++ ++ The usual thing for this macro to do is to record a flag in the ++ `symbol_ref' (such as `SYMBOL_REF_FLAG') or to store a modified ++ name string in the `symbol_ref' (if one bit is not enough ++ information). */ ++ ++ ++#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \ ++ (VAR) = (SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*' || (SYMBOL_NAME)[0] == '@'); ++/* `STRIP_NAME_ENCODING (VAR, SYM_NAME)' ++ Decode SYM_NAME and store the real name part in VAR, sans the ++ characters that encode section info. Define this macro if ++ `ENCODE_SECTION_INFO' alters the symbol's name string. */ ++/* `UNIQUE_SECTION_P (DECL)' ++ A C expression which evaluates to true if DECL should be placed ++ into a unique section for some target-specific reason. If you do ++ not define this macro, the default is `0'. Note that the flag ++ `-ffunction-sections' will also cause functions to be placed into ++ unique sections. */ ++ ++#define UNIQUE_SECTION(DECL, RELOC) unique_section (DECL, RELOC) ++/* `UNIQUE_SECTION (DECL, RELOC)' ++ A C statement to build up a unique section name, expressed as a ++ STRING_CST node, and assign it to `DECL_SECTION_NAME (DECL)'. ++ RELOC indicates whether the initial value of EXP requires ++ link-time relocations. If you do not define this macro, GNU CC ++ will use the symbol name prefixed by `.' as the section name. */ ++ ++ ++#define ASM_FILE_START(STREAM) asm_file_start (STREAM) ++/* A C expression which outputs to the stdio stream STREAM some ++ appropriate text to go at the start of an assembler file. ++ ++ Normally this macro is defined to output a line containing ++ `#NO_APP', which is a comment that has no effect on most ++ assemblers but tells the GNU assembler that it can save time by not ++ checking for certain assembler constructs. ++ ++ On systems that use SDB, it is necessary to output certain ++ commands; see `attasm.h'. */ ++ ++#define ASM_FILE_END(STREAM) asm_file_end (STREAM) ++/* A C expression which outputs to the stdio stream STREAM some ++ appropriate text to go at the end of an assembler file. ++ ++ If this macro is not defined, the default is to output nothing ++ special at the end of the file. Most systems don't require any ++ definition. ++ ++ On systems that use SDB, it is necessary to output certain ++ commands; see `attasm.h'. */ ++ ++#define ASM_COMMENT_START " ; " ++/* A C string constant describing how to begin a comment in the target ++ assembler language. The compiler assumes that the comment will ++ end at the end of the line. */ ++ ++#define ASM_APP_ON "/* #APP */\n" ++/* A C string constant for text to be output before each `asm' ++ statement or group of consecutive ones. Normally this is ++ `"#APP"', which is a comment that has no effect on most assemblers ++ but tells the GNU assembler that it must check the lines that ++ follow for all valid assembler constructs. */ ++ ++#define ASM_APP_OFF "/* #NOAPP */\n" ++/* A C string constant for text to be output after each `asm' ++ statement or group of consecutive ones. Normally this is ++ `"#NO_APP"', which tells the GNU assembler to resume making the ++ time-saving assumptions that are valid for ordinary compiler ++ output. */ ++ ++#define ASM_OUTPUT_SOURCE_LINE(STREAM, LINE) fprintf (STREAM,"/* line: %d */\n",LINE) ++/* A C statement to output DBX or SDB debugging information before ++ code for line number LINE of the current source file to the stdio ++ stream STREAM. ++ ++ This macro need not be defined if the standard form of debugging ++ information for the debugger in use is appropriate. */ ++ ++#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \ ++ asm_output_section_name(FILE, DECL, NAME, RELOC) ++ ++/* `ASM_OUTPUT_SECTION_NAME (STREAM, DECL, NAME, RELOC)' ++ A C statement to output something to the assembler file to switch ++ to section NAME for object DECL which is either a `FUNCTION_DECL', ++ a `VAR_DECL' or `NULL_TREE'. RELOC indicates whether the initial ++ value of EXP requires link-time relocations. Some target formats ++ do not support arbitrary sections. Do not define this macro in ++ such cases. ++ ++ At present this macro is only used to support section attributes. ++ When this macro is undefined, section attributes are disabled. */ ++ ++#define OBJC_PROLOGUE {} ++/* A C statement to output any assembler statements which are ++ required to precede any Objective C object definitions or message ++ sending. The statement is executed only when compiling an ++ Objective C program. */ ++ ++ ++ ++#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) fprintf (STREAM, "no double float %.20e\n", VALUE) ++#define ASM_OUTPUT_FLOAT(STREAM, VALUE) asm_output_float (STREAM, VALUE) ++/* `ASM_OUTPUT_LONG_DOUBLE (STREAM, VALUE)' ++ `ASM_OUTPUT_THREE_QUARTER_FLOAT (STREAM, VALUE)' ++ `ASM_OUTPUT_SHORT_FLOAT (STREAM, VALUE)' ++ `ASM_OUTPUT_BYTE_FLOAT (STREAM, VALUE)' ++ A C statement to output to the stdio stream STREAM an assembler ++ instruction to assemble a floating-point constant of `TFmode', ++ `DFmode', `SFmode', `TQFmode', `HFmode', or `QFmode', ++ respectively, whose value is VALUE. VALUE will be a C expression ++ of type `REAL_VALUE_TYPE'. Macros such as ++ `REAL_VALUE_TO_TARGET_DOUBLE' are useful for writing these ++ definitions. */ ++ ++ ++#define ASM_OUTPUT_INT(FILE, VALUE) \ ++ ( fprintf (FILE, "\t.long "), \ ++ output_addr_const (FILE, (VALUE)), \ ++ fputs ("\n", FILE)) ++ ++ /* Likewise for `short' and `char' constants. */ ++ ++#define ASM_OUTPUT_SHORT(FILE,VALUE) asm_output_short(FILE,VALUE) ++#define ASM_OUTPUT_CHAR(FILE,VALUE) asm_output_char(FILE,VALUE) ++ ++/* `ASM_OUTPUT_QUADRUPLE_INT (STREAM, EXP)' ++ A C statement to output to the stdio stream STREAM an assembler ++ instruction to assemble an integer of 16, 8, 4, 2 or 1 bytes, ++ respectively, whose value is VALUE. The argument EXP will be an ++ RTL expression which represents a constant value. Use ++ `output_addr_const (STREAM, EXP)' to output this value as an ++ assembler expression. ++ ++ For sizes larger than `UNITS_PER_WORD', if the action of a macro ++ would be identical to repeatedly calling the macro corresponding to ++ a size of `UNITS_PER_WORD', once for each word, you need not define ++ the macro. */ ++ ++ ++#define ASM_OUTPUT_BYTE(FILE,VALUE) asm_output_byte (FILE,VALUE) ++/* A C statement to output to the stdio stream STREAM an assembler ++ instruction to assemble a single byte containing the number VALUE. */ ++ ++#define ASM_BYTE_OP "\t.byte " ++/* A C string constant giving the pseudo-op to use for a sequence of ++ single-byte constants. If this macro is not defined, the default ++ is `"\t.byte\t"'. */ ++ ++#define ASM_OUTPUT_ASCII(FILE, P, SIZE) gas_output_ascii (FILE,P,SIZE) ++/* `ASM_OUTPUT_ASCII (STREAM, PTR, LEN)' ++ output_ascii (FILE, P, SIZE) ++ A C statement to output to the stdio stream STREAM an assembler ++ instruction to assemble a string constant containing the LEN bytes ++ at PTR. PTR will be a C expression of type `char *' and LEN a C ++ expression of type `int'. ++ ++ If the assembler has a `.ascii' pseudo-op as found in the Berkeley ++ Unix assembler, do not define the macro `ASM_OUTPUT_ASCII'. */ ++ ++#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == '\n') ++/* Define this macro as a C expression which is nonzero if C is used ++ as a logical line separator by the assembler. ++ ++ If you do not define this macro, the default is that only the ++ character `;' is treated as a logical line separator. */ ++ ++/* ++#define ASM_OPEN_PAREN "(" ++#define ASM_CLOSE_PAREN ")" ++ These macros are defined as C string constant, describing the ++ syntax in the assembler for grouping arithmetic expressions. The ++ following definitions are correct for most assemblers: ++ ++ #define ASM_OPEN_PAREN "(" ++ #define ASM_CLOSE_PAREN ")" ++ ++ These macros are provided by `real.h' for writing the definitions of ++ `ASM_OUTPUT_DOUBLE' and the like: */ ++ ++/* Here we much catch r0 - r15 variable names */ ++ ++#define ASM_OUTPUT_LABELREF(FILE,NAME) \ ++do{ \ ++ char *p = NAME; \ ++ while(*p == '_') p++; \ ++ if(*p == 'r' || *p == 'R') \ ++ { \ ++ int val; \ ++ char *endptr; \ ++ p++; \ ++ val = strtol (p, &endptr, 10); \ ++ if(val >= 0 && val <= 15 && \ ++ *endptr == 0 ) \ ++ { \ ++ asm_fprintf ((FILE), "_%U%s", (NAME)); \ ++ } \ ++ else \ ++ asm_fprintf ((FILE), "%U%s", (NAME)); \ ++ } \ ++ else \ ++ asm_fprintf ((FILE), "%U%s", (NAME)); \ ++} while(0) ++ ++/* macros to output uninitialized variable definitions */ ++ ++/* Return a non-zero value if DECL has a section attribute. */ ++#define IN_NAMED_SECTION(DECL) \ ++ ((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \ ++ && DECL_SECTION_NAME (DECL) != NULL_TREE) ++ ++/* macro to output uninitialized varible in normal case where -fno-common is not specified */ ++ ++#undef ASM_OUTPUT_ALIGNED_DECL_COMMON ++#define ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN) \ ++ do \ ++ { \ ++ char *p = NAME; \ ++ if(*p == '*' || *p == '@' ) p++; \ ++ if(*p >= '0' && *p <= '9' ) break; \ ++ if (IN_NAMED_SECTION (DECL)) \ ++ { \ ++ /* case where -fdata-sections is specified */ \ ++ named_section (DECL, NULL, 0); \ ++ ASM_GLOBALIZE_LABEL (FILE, NAME); \ ++ ASM_OUTPUT_ALIGN (FILE, floor_log2 (ALIGN / BITS_PER_UNIT)); \ ++ last_assemble_variable_decl = DECL; \ ++ ASM_DECLARE_OBJECT_NAME (FILE, NAME, DECL); \ ++ ASM_OUTPUT_SKIP (FILE, SIZE ? SIZE : 1); \ ++ } \ ++ else \ ++ { \ ++ /* default case */ \ ++ fputs ("\t.comm ", (FILE)); \ ++ assemble_name ((FILE), (NAME)); \ ++ fprintf ((FILE), ",%d%s", (SIZE), (SIZE)>1?",2\n":"\n"); \ ++ } \ ++ } \ ++ while (0) ++ ++ ++/* macro to output uninitialized variable when -fno-common _is_ specified */ ++#undef ASM_OUTPUT_ALIGNED_BSS ++#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ ++ do \ ++ { \ ++ char *p = NAME; \ ++ if(*p == '*' || *p == '@' ) p++; \ ++ if(*p >= '0' && *p <= '9' ) break; \ ++ if (IN_NAMED_SECTION (DECL)) \ ++ named_section (DECL, NULL, 0); \ ++ else \ ++ bss_section (); \ ++ \ ++ ASM_OUTPUT_ALIGN (FILE, floor_log2 (ALIGN / BITS_PER_UNIT)); \ ++ \ ++ last_assemble_variable_decl = DECL; \ ++ ASM_DECLARE_OBJECT_NAME (FILE, NAME, DECL); \ ++ ASM_OUTPUT_SKIP (FILE, SIZE ? SIZE : 1); \ ++ } \ ++ while (0) ++ ++ ++#undef ASM_OUTPUT_ALIGNED_DECL_LOCAL ++#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN) \ ++ do \ ++ { \ ++ char *p = NAME; \ ++ if(*p == '*' || *p == '@' ) p++; \ ++ if(*p >= '0' && *p <= '9' ) break; \ ++ if ((DECL) != NULL && IN_NAMED_SECTION (DECL)) \ ++ named_section (DECL, NULL, 0); \ ++ else \ ++ bss_section (); \ ++ \ ++ ASM_OUTPUT_ALIGN (FILE, floor_log2 (ALIGN / BITS_PER_UNIT)); \ ++ ASM_OUTPUT_LABEL (FILE, NAME); \ ++ fprintf (FILE, "\t.space\t%d\n", SIZE); \ ++ } \ ++ while (0) ++ ++#define BSS_SECTION_ASM_OP "\t.section\t.bss" ++/* If defined, a C expression whose value is a string containing the ++ assembler operation to identify the following data as ++ uninitialized global data. If not defined, and neither ++ 'ASM_OUTPUT_BSS' nor 'ASM_OUTPUT_ALIGNED_BSS' are defined, ++ uninitialized global data will be output in the data section if ++ -fno-common' is passed, otherwise 'ASM_OUTPUT_COMMON' will be ++ used. ++*/ ++ ++ ++ ++#define ASM_OUTPUT_LABEL(STREAM, NAME) \ ++{ \ ++ assemble_name (STREAM, NAME); \ ++ fprintf (STREAM, ":\n"); \ ++} ++/* A C statement (sans semicolon) to output to the stdio stream ++ STREAM the assembler definition of a label named NAME. Use the ++ expression `assemble_name (STREAM, NAME)' to output the name ++ itself; before and after that, output the additional assembler ++ syntax for defining the name, and a newline. */ ++ ++#undef TYPE_ASM_OP ++#undef SIZE_ASM_OP ++#undef WEAK_ASM_OP ++#define TYPE_ASM_OP "\t.type\t" ++#define SIZE_ASM_OP "\t.size\t" ++#define WEAK_ASM_OP "\t.weak\t" ++/* Define the strings used for the special svr4 .type and .size directives. ++ These strings generally do not vary from one system running svr4 to ++ another, but if a given system (e.g. m88k running svr) needs to use ++ different pseudo-op names for these, they may be overridden in the ++ file which includes this one. */ ++ ++ ++#undef TYPE_OPERAND_FMT ++#define TYPE_OPERAND_FMT "@%s" ++/* The following macro defines the format used to output the second ++ operand of the .type assembler directive. Different svr4 assemblers ++ expect various different forms for this operand. The one given here ++ is just a default. You may need to override it in your machine- ++ specific tm.h file (depending upon the particulars of your assembler). */ ++ ++ ++#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ ++asm_declare_function_name (FILE, NAME, DECL) ++ ++ ++/* A C statement (sans semicolon) to output to the stdio stream ++ STREAM any text necessary for declaring the name NAME of a ++ function which is being defined. This macro is responsible for ++ outputting the label definition (perhaps using ++ `ASM_OUTPUT_LABEL'). The argument DECL is the `FUNCTION_DECL' ++ tree node representing the function. ++ ++ If this macro is not defined, then the function name is defined in ++ the usual manner as a label (by means of `ASM_OUTPUT_LABEL'). */ ++ ++#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ ++ do { \ ++ if (!flag_inhibit_size_directive) \ ++ { \ ++ char label[256]; \ ++ static int labelno; \ ++ labelno++; \ ++ ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ ++ ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \ ++ fprintf (FILE, "%s", SIZE_ASM_OP); \ ++ assemble_name (FILE, (FNAME)); \ ++ fprintf (FILE, ","); \ ++ assemble_name (FILE, label); \ ++ fprintf (FILE, "-"); \ ++ assemble_name (FILE, (FNAME)); \ ++ fprintf (FILE,"\n/********* End of function ******/\n\n"); \ ++ } \ ++ } while (0) ++/* A C statement (sans semicolon) to output to the stdio stream ++ STREAM any text necessary for declaring the size of a function ++ which is being defined. The argument NAME is the name of the ++ function. The argument DECL is the `FUNCTION_DECL' tree node ++ representing the function. ++ ++ If this macro is not defined, then the function size is not ++ defined. */ ++ ++#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ ++do { \ ++ fprintf (FILE, "%s", TYPE_ASM_OP); \ ++ assemble_name (FILE, NAME); \ ++ putc (',', FILE); \ ++ fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ ++ putc ('\n', FILE); \ ++ size_directive_output = 0; \ ++ if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ ++ { \ ++ size_directive_output = 1; \ ++ fprintf (FILE, "%s", SIZE_ASM_OP); \ ++ assemble_name (FILE, NAME); \ ++ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ ++ } \ ++ ASM_OUTPUT_LABEL(FILE, NAME); \ ++} while (0) ++/* A C statement (sans semicolon) to output to the stdio stream ++ STREAM any text necessary for declaring the name NAME of an ++ initialized variable which is being defined. This macro must ++ output the label definition (perhaps using `ASM_OUTPUT_LABEL'). ++ The argument DECL is the `VAR_DECL' tree node representing the ++ variable. ++ ++ If this macro is not defined, then the variable name is defined in ++ the usual manner as a label (by means of `ASM_OUTPUT_LABEL'). */ ++ ++#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ ++do { \ ++ const char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ ++ if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \ ++ && ! AT_END && TOP_LEVEL \ ++ && DECL_INITIAL (DECL) == error_mark_node \ ++ && !size_directive_output) \ ++ { \ ++ size_directive_output = 1; \ ++ fprintf (FILE, "%s", SIZE_ASM_OP); \ ++ assemble_name (FILE, name); \ ++ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ ++ } \ ++ } while (0) ++/* A C statement (sans semicolon) to finish up declaring a variable ++ name once the compiler has processed its initializer fully and ++ thus has had a chance to determine the size of an array when ++ controlled by an initializer. This is used on systems where it's ++ necessary to declare something about the size of the object. ++ ++ If you don't define this macro, that is equivalent to defining it ++ to do nothing. */ ++ ++ ++#define ESCAPES \ ++"\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ ++\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ ++\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0\ ++\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\ ++\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ ++\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ ++\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ ++\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1" ++/* A table of bytes codes used by the ASM_OUTPUT_ASCII and ++ ASM_OUTPUT_LIMITED_STRING macros. Each byte in the table ++ corresponds to a particular byte value [0..255]. For any ++ given byte value, if the value in the corresponding table ++ position is zero, the given character can be output directly. ++ If the table value is 1, the byte must be output as a \ooo ++ octal escape. If the tables value is anything else, then the ++ byte value should be output as a \ followed by the value ++ in the table. Note that we can use standard UN*X escape ++ sequences for many control characters, but we don't use ++ \a to represent BEL because some svr4 assemblers (e.g. on ++ the i386) don't know about that. Also, we don't use \v ++ since some versions of gas, such as 2.2 did not accept it. */ ++ ++#define STRING_LIMIT ((unsigned) 64) ++#define STRING_ASM_OP "\t.string\t" ++/* Some svr4 assemblers have a limit on the number of characters which ++ can appear in the operand of a .string directive. If your assembler ++ has such a limitation, you should define STRING_LIMIT to reflect that ++ limit. Note that at least some svr4 assemblers have a limit on the ++ actual number of bytes in the double-quoted string, and that they ++ count each character in an escape sequence as one byte. Thus, an ++ escape sequence like \377 would count as four bytes. ++ ++ If your target assembler doesn't support the .string directive, you ++ should define this to zero. */ ++ ++#define ASM_GLOBALIZE_LABEL(STREAM, NAME) \ ++do { \ ++ char *p = NAME; \ ++ if(*p == '*' || *p == '@' ) p++; \ ++ if(*p >= '0' && *p <= '9' ) break; \ ++ fprintf (STREAM, ".global\t"); \ ++ assemble_name (STREAM, NAME); \ ++ fprintf (STREAM, "\n"); \ ++} \ ++while (0) ++ ++/* A C statement (sans semicolon) to output to the stdio stream ++ STREAM some commands that will make the label NAME global; that ++ is, available for reference from other files. Use the expression ++ `assemble_name (STREAM, NAME)' to output the name itself; before ++ and after that, output the additional assembler syntax for making ++ that name global, and a newline. */ ++ ++#define ASM_WEAKEN_LABEL(FILE, NAME) \ ++ do \ ++ { \ ++ fputs ("\t.weak\t", (FILE)); \ ++ assemble_name ((FILE), (NAME)); \ ++ fputc ('\n', (FILE)); \ ++ } \ ++ while (0) ++ ++/* A C statement (sans semicolon) to output to the stdio stream ++ STREAM some commands that will make the label NAME weak; that is, ++ available for reference from other files but only used if no other ++ definition is available. Use the expression `assemble_name ++ (STREAM, NAME)' to output the name itself; before and after that, ++ output the additional assembler syntax for making that name weak, ++ and a newline. ++ ++ If you don't define this macro, GNU CC will not support weak ++ symbols and you should not define the `SUPPORTS_WEAK' macro. ++*/ ++ ++#define SUPPORTS_WEAK 1 ++/* A C expression which evaluates to true if the target supports weak ++ symbols. ++ ++ If you don't define this macro, `defaults.h' provides a default ++ definition. If `ASM_WEAKEN_LABEL' is defined, the default ++ definition is `1'; otherwise, it is `0'. Define this macro if you ++ want to control weak symbol support with a compiler flag such as ++ `-melf'. ++ ++ `MAKE_DECL_ONE_ONLY' ++ A C statement (sans semicolon) to mark DECL to be emitted as a ++ public symbol such that extra copies in multiple translation units ++ will be discarded by the linker. Define this macro if your object ++ file format provides support for this concept, such as the `COMDAT' ++ section flags in the Microsoft Windows PE/COFF format, and this ++ support requires changes to DECL, such as putting it in a separate ++ section. ++ ++ `SUPPORTS_WEAK' ++ A C expression which evaluates to true if the target supports ++ one-only semantics. ++ ++ If you don't define this macro, `varasm.c' provides a default ++ definition. If `MAKE_DECL_ONE_ONLY' is defined, the default ++ definition is `1'; otherwise, it is `0'. Define this macro if you ++ want to control weak symbol support with a compiler flag, or if ++ setting the `DECL_ONE_ONLY' flag is enough to mark a declaration to ++ be emitted as one-only. */ ++ ++#define ASM_OUTPUT_INTERNAL_LABEL(STREAM, PREFIX, NUM) \ ++fprintf(STREAM, ".%s%d:\n", PREFIX, NUM) ++/* A C statement to output to the stdio stream STREAM a label whose ++ name is made from the string PREFIX and the number NUM. ++ ++ It is absolutely essential that these labels be distinct from the ++ labels used for user-level functions and variables. Otherwise, ++ certain programs will have name conflicts with internal labels. ++ ++ It is desirable to exclude internal labels from the symbol table ++ of the object file. Most assemblers have a naming convention for ++ labels that should be excluded; on many systems, the letter `L' at ++ the beginning of a label has this effect. You should find out what ++ convention your system uses, and follow it. ++ ++ The usual definition of this macro is as follows: ++ ++ fprintf (STREAM, "L%s%d:\n", PREFIX, NUM) */ ++ ++#define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM) \ ++sprintf (STRING, "*.%s%d", PREFIX, NUM) ++/* A C statement to store into the string STRING a label whose name ++ is made from the string PREFIX and the number NUM. ++ ++ This string, when output subsequently by `assemble_name', should ++ produce the output that `ASM_OUTPUT_INTERNAL_LABEL' would produce ++ with the same PREFIX and NUM. ++ ++ If the string begins with `*', then `assemble_name' will output ++ the rest of the string unchanged. It is often convenient for ++ `ASM_GENERATE_INTERNAL_LABEL' to use `*' in this way. If the ++ string doesn't start with `*', then `ASM_OUTPUT_LABELREF' gets to ++ output the string, and may change it. (Of course, ++ `ASM_OUTPUT_LABELREF' is also part of your machine description, so ++ you should know what it does on your machine.) */ ++ ++#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ ++( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ ++ sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) ++ ++/* A C expression to assign to OUTVAR (which is a variable of type ++ `char *') a newly allocated string made from the string NAME and ++ the number NUMBER, with some suitable punctuation added. Use ++ `alloca' to get space for the string. ++ ++ The string will be used as an argument to `ASM_OUTPUT_LABELREF' to ++ produce an assembler label for an internal static variable whose ++ name is NAME. Therefore, the string must be such as to result in ++ valid assembler code. The argument NUMBER is different each time ++ this macro is executed; it prevents conflicts between ++ similarly-named internal static variables in different scopes. ++ ++ Ideally this string should not be a valid C identifier, to prevent ++ any conflict with the user's own symbols. Most assemblers allow ++ periods or percent signs in assembler symbols; putting at least ++ one of these between the name and the number will suffice. */ ++ ++/* `ASM_OUTPUT_WEAK_ALIAS (STREAM, NAME, VALUE)' ++ A C statement to output to the stdio stream STREAM assembler code ++ which defines (equates) the weak symbol NAME to have the value ++ VALUE. ++ ++ Define this macro if the target only supports weak aliases; define ++ ASM_OUTPUT_DEF instead if possible. */ ++ ++#define HAS_INIT_SECTION 1 ++/* If defined, `main' will not call `__main' as described above. ++ This macro should be defined for systems that control the contents ++ of the init section on a symbol-by-symbol basis, such as OSF/1, ++ and should not be defined explicitly for systems that support ++ `INIT_SECTION_ASM_OP'. */ ++ ++#define REGISTER_NAMES { \ ++ "r0","r1","r2","r3","r4","r5","r6","r7", \ ++ "r8","r9","r10","r11","r12","r13","r14","r15" \ ++} ++/* A C initializer containing the assembler's names for the machine ++ registers, each one as a C string constant. This is what ++ translates register numbers in the compiler into assembler ++ language. */ ++ ++#define FINAL_PRESCAN_INSN(insn, operand, nop) final_prescan_insn (insn, operand,nop) ++/* If defined, a C statement to be executed just prior to the output ++ of assembler code for INSN, to modify the extracted operands so ++ they will be output differently. ++ ++ Here the argument OPVEC is the vector containing the operands ++ extracted from INSN, and NOPERANDS is the number of elements of ++ the vector which contain meaningful data for this insn. The ++ contents of this vector are what will be used to convert the insn ++ template into assembler code, so you can change the assembler ++ output by changing the contents of the vector. ++ ++ This macro is useful when various assembler syntaxes share a single ++ file of instruction patterns; by defining this macro differently, ++ you can cause a large class of instructions to be output ++ differently (such as with rearranged operands). Naturally, ++ variations in assembler syntax affecting individual insn patterns ++ ought to be handled by writing conditional output routines in ++ those patterns. ++ ++ If this macro is not defined, it is equivalent to a null statement. */ ++ ++#define PRINT_OPERAND(STREAM, X, CODE) print_operand (STREAM, X, CODE) ++/* A C compound statement to output to stdio stream STREAM the ++ assembler syntax for an instruction operand X. X is an RTL ++ expression. ++ ++ CODE is a value that can be used to specify one of several ways of ++ printing the operand. It is used when identical operands must be ++ printed differently depending on the context. CODE comes from the ++ `%' specification that was used to request printing of the ++ operand. If the specification was just `%DIGIT' then CODE is 0; ++ if the specification was `%LTR DIGIT' then CODE is the ASCII code ++ for LTR. ++ ++ If X is a register, this macro should print the register's name. ++ The names can be found in an array `reg_names' whose type is `char ++ *[]'. `reg_names' is initialized from `REGISTER_NAMES'. ++ ++ When the machine description has a specification `%PUNCT' (a `%' ++ followed by a punctuation character), this macro is called with a ++ null pointer for X and the punctuation character for CODE. */ ++ ++#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '~') ++/* A C expression which evaluates to true if CODE is a valid ++ punctuation character for use in the `PRINT_OPERAND' macro. If ++ `PRINT_OPERAND_PUNCT_VALID_P' is not defined, it means that no ++ punctuation characters (except for the standard one, `%') are used ++ in this way. */ ++ ++#define PRINT_OPERAND_ADDRESS(STREAM, X) print_operand_address(STREAM, X) ++/* A C compound statement to output to stdio stream STREAM the ++ assembler syntax for an instruction operand that is a memory ++ reference whose address is X. X is an RTL expression. ++ ++ On some machines, the syntax for a symbolic address depends on the ++ section that the address refers to. On these machines, define the ++ macro `ENCODE_SECTION_INFO' to store the information into the ++ `symbol_ref', and then check for it here. *Note Assembler ++ Format::. */ ++ ++#define USER_LABEL_PREFIX "" ++/* `LOCAL_LABEL_PREFIX' ++ `REGISTER_PREFIX' ++ `IMMEDIATE_PREFIX' ++ If defined, C string expressions to be used for the `%R', `%L', ++ `%U', and `%I' options of `asm_fprintf' (see `final.c'). These ++ are useful when a single `md' file must support multiple assembler ++ formats. In that case, the various `tm.h' files can define these ++ macros differently. */ ++ ++#define ASSEMBLER_DIALECT MSP430_HAS_HWMUL_INTERNAL ++/* If your target supports multiple dialects of assembler language ++ (such as different opcodes), define this macro as a C expression ++ that gives the numeric index of the assembler language dialect to ++ use, with zero as the first variant. ++ ++ If this macro is defined, you may use constructs of the form ++ `{option0|option1|option2...}' in the output templates of patterns ++ (*note Output Template::.) or in the first argument of ++ `asm_fprintf'. This construct outputs `option0', `option1' or ++ `option2', etc., if the value of `ASSEMBLER_DIALECT' is zero, one ++ or two, etc. Any special characters within these strings retain ++ their usual meaning. ++ ++ If you do not define this macro, the characters `{', `|' and `}' ++ do not have any special meaning when used in templates or operands ++ to `asm_fprintf'. ++ ++ Define the macros `REGISTER_PREFIX', `LOCAL_LABEL_PREFIX', ++ `USER_LABEL_PREFIX' and `IMMEDIATE_PREFIX' if you can express the ++ variations in assembler language syntax with that mechanism. ++ Define `ASSEMBLER_DIALECT' and use the `{option0|option1}' syntax ++ if the syntax variant are larger and involve such things as ++ different opcodes or operand order. */ ++ ++#define ASM_OUTPUT_REG_PUSH(STREAM, REGNO) \ ++{ \ ++ if (REGNO > 15) \ ++ abort (); \ ++ fprintf (STREAM, "\tpush\tr%d", REGNO); \ ++} ++/* A C expression to output to STREAM some assembler code which will ++ push hard register number REGNO onto the stack. The code need not ++ be optimal, since this macro is used only when profiling. */ ++ ++#define ASM_OUTPUT_REG_POP(STREAM, REGNO) \ ++{ \ ++ if (REGNO > 15) \ ++ abort (); \ ++ fprintf (STREAM, "\tpop\tr%d", REGNO); \ ++} ++/* A C expression to output to STREAM some assembler code which will ++ pop hard register number REGNO off of the stack. The code need ++ not be optimal, since this macro is used only when profiling. */ ++ ++#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \ ++ msp430_output_addr_vec_elt(STREAM, VALUE) ++/* This macro should be provided on machines where the addresses in a ++ dispatch table are absolute. ++ ++ The definition should be a C statement to output to the stdio ++ stream STREAM an assembler pseudo-instruction to generate a ++ reference to a label. VALUE is the number of an internal label ++ whose definition is output using `ASM_OUTPUT_INTERNAL_LABEL'. For ++ example, ++ ++ fprintf (STREAM, "\t.word L%d\n", VALUE) */ ++ ++/* ++#define ASM_OUTPUT_CASE_LABEL(STREAM, PREFIX, NUM, TABLE) \ ++ progmem_section (), ASM_OUTPUT_INTERNAL_LABEL (STREAM, PREFIX, NUM) ++ ++ `ASM_OUTPUT_CASE_LABEL (STREAM, PREFIX, NUM, TABLE)' ++ Define this if the label before a jump-table needs to be output ++ specially. The first three arguments are the same as for ++ `ASM_OUTPUT_INTERNAL_LABEL'; the fourth argument is the jump-table ++ which follows (a `jump_insn' containing an `addr_vec' or ++ `addr_diff_vec'). ++ ++ This feature is used on system V to output a `swbeg' statement for ++ the table. ++ ++ If this macro is not defined, these labels are output with ++ `ASM_OUTPUT_INTERNAL_LABEL'. */ ++ ++/* `ASM_OUTPUT_CASE_END (STREAM, NUM, TABLE)' ++ Define this if something special must be output at the end of a ++ jump-table. The definition should be a C statement to be executed ++ after the assembler code for the table is written. It should write ++ the appropriate code to stdio stream STREAM. The argument TABLE ++ is the jump-table insn, and NUM is the label-number of the ++ preceding label. ++ ++ If this macro is not defined, nothing special is output at the end ++ of the jump-table. */ ++ ++#ifndef SET_ASM_OP ++#define SET_ASM_OP "\t.set\t" ++#endif ++ ++#define ASM_OUTPUT_SKIP(STREAM, N) \ ++fprintf (STREAM, "\t.skip %d,0\n", N) ++/* A C statement to output to the stdio stream STREAM an assembler ++ instruction to advance the location counter by NBYTES bytes. ++ Those bytes should be zero when loaded. NBYTES will be a C ++ expression of type `int'. */ ++ ++#define ASM_OUTPUT_ALIGN(STREAM, POWER) \ ++fprintf (STREAM, "\t.p2align %d,0\n", POWER) ++/* A C statement to output to the stdio stream STREAM an assembler ++ command to advance the location counter to a multiple of 2 to the ++ POWER bytes. POWER will be a C expression of type `int'. */ ++ ++#define CASE_VECTOR_MODE HImode ++/* An alias for a machine mode name. This is the machine mode that ++ elements of a jump-table should have. */ ++ ++ ++#define PREDICATE_CODES \ ++{"memory_operand_msp430", {SUBREG, MEM}}, \ ++{"nonimmediate_operand_msp430", {SUBREG, REG, MEM}},\ ++{"general_operand_msp430", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, LABEL_REF, SUBREG, REG, MEM}},\ ++{"three_operands_msp430", {PLUS, MINUS, AND, IOR, XOR}}, \ ++{"equality_operator", {EQ, NE }}, \ ++{"inequality_operator", {GE, GT, LE, LT, GEU, GTU, LEU, LTU }}, ++ ++ ++ ++ ++extern struct rtx_def *msp430_compare_op0, *msp430_compare_op1; ++ ++ ++extern int msp430_case_values_threshold; ++ ++#define CASE_VALUES_THRESHOLD msp430_case_values_threshold ++/* `CASE_VALUES_THRESHOLD' ++ Define this to be the smallest number of different values for ++ which it is best to use a jump-table instead of a tree of ++ conditional branches. The default is four for machines with a ++ `casesi' instruction and five otherwise. This is best for most ++ machines. */ ++ ++#undef WORD_REGISTER_OPERATIONS ++/* Define this macro if operations between registers with integral ++ mode smaller than a word are always performed on the entire ++ register. Most RISC machines have this property and most CISC ++ machines do not. */ ++ ++/* ++#define EASY_DIV_EXPR TRUNC_DIV_EXPR ++ An alias for a tree code that is the easiest kind of division to ++ compile code for in the general case. It may be `TRUNC_DIV_EXPR', ++ `FLOOR_DIV_EXPR', `CEIL_DIV_EXPR' or `ROUND_DIV_EXPR'. These four ++ division operators differ in how they round the result to an ++ integer. `EASY_DIV_EXPR' is used when it is permissible to use ++ any of those kinds of division and the choice should be made on ++ the basis of efficiency. */ ++ ++#define MOVE_MAX 2 ++/* The maximum number of bytes that a single instruction can move ++ quickly between memory and registers or between two memory ++ locations. */ ++ ++#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 ++/* A C expression which is nonzero if on this machine it is safe to ++ "convert" an integer of INPREC bits to one of OUTPREC bits (where ++ OUTPREC is smaller than INPREC) by merely operating on it as if it ++ had only OUTPREC bits. ++ ++ On many machines, this expression can be 1. ++ ++ When `TRULY_NOOP_TRUNCATION' returns 1 for a pair of sizes for ++ modes for which `MODES_TIEABLE_P' is 0, suboptimal code can result. ++ If this is the case, making `TRULY_NOOP_TRUNCATION' return 0 in ++ such cases may improve things. */ ++ ++#define Pmode HImode ++/* An alias for the machine mode for pointers. On most machines, ++ define this to be the integer mode corresponding to the width of a ++ hardware pointer; `SImode' on 32-bit machine or `DImode' on 64-bit ++ machines. On some machines you must define this to be one of the ++ partial integer modes, such as `PSImode'. ++ ++ The width of `Pmode' must be at least as large as the value of ++ `POINTER_SIZE'. If it is not equal, you must define the macro ++ `POINTERS_EXTEND_UNSIGNED' to specify how pointers are extended to ++ `Pmode'. */ ++ ++#define FUNCTION_MODE HImode ++/* An alias for the machine mode used for memory references to ++ functions being called, in `call' RTL expressions. On most ++ machines this should be `QImode'. */ ++ /* 1 3 */ ++#define INTEGRATE_THRESHOLD(DECL) (1 + (3 * list_length (DECL_ARGUMENTS (DECL)) / 2)) ++ ++/* A C expression for the maximum number of instructions above which ++ the function DECL should not be inlined. DECL is a ++ `FUNCTION_DECL' node. ++ ++ The default definition of this macro is 64 plus 8 times the number ++ of arguments that the function accepts. Some people think a larger ++ threshold should be used on RISC machines. */ ++ ++/* ++#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ ++valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) ++ `VALID_MACHINE_DECL_ATTRIBUTE (DECL, ATTRIBUTES, IDENTIFIER, ARGS)' ++ If defined, a C expression whose value is nonzero if IDENTIFIER ++ with arguments ARGS is a valid machine specific attribute for DECL. ++ The attributes in ATTRIBUTES have previously been assigned to DECL. */ ++ ++/* ++#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, IDENTIFIER, ARGS) \ ++ valid_machine_type_attribute(TYPE, ATTRIBUTES, IDENTIFIER, ARGS) ++ `VALID_MACHINE_TYPE_ATTRIBUTE (TYPE, ATTRIBUTES, IDENTIFIER, ARGS)' ++ If defined, a C expression whose value is nonzero if IDENTIFIER ++ with arguments ARGS is a valid machine specific attribute for TYPE. ++ The attributes in ATTRIBUTES have previously been assigned to TYPE. */ ++ ++#define DOLLARS_IN_IDENTIFIERS 0 ++/* Define this macro to control use of the character `$' in identifier ++ names. 0 means `$' is not allowed by default; 1 means it is ++ allowed. 1 is the default; there is no need to define this macro ++ in that case. This macro controls the compiler proper; it does ++ not affect the preprocessor. */ ++ ++#define NO_DOLLAR_IN_LABEL 1 ++/* Define this macro if the assembler does not accept the character ++ `$' in label names. By default constructors and destructors in ++ G++ have `$' in the identifiers. If this macro is defined, `.' is ++ used instead. */ ++ ++#define MACHINE_DEPENDENT_REORG(INSN) machine_dependent_reorg (INSN) ++/* In rare cases, correct code generation requires extra machine ++ dependent processing between the second jump optimization pass and ++ delayed branch scheduling. On those machines, define this macro ++ as a C statement to act on the code starting at INSN. */ ++ ++#define GIV_SORT_CRITERION(X, Y) \ ++ if (GET_CODE ((X)->add_val) == CONST_INT \ ++ && GET_CODE ((Y)->add_val) == CONST_INT) \ ++ return INTVAL ((X)->add_val) - INTVAL ((Y)->add_val); ++ ++/* `GIV_SORT_CRITERION(GIV1, GIV2)' ++ In some cases, the strength reduction optimization pass can ++ produce better code if this is defined. This macro controls the ++ order that induction variables are combined. This macro is ++ particularly useful if the target has limited addressing modes. ++ For instance, the SH target has only positive offsets in ++ addresses. Thus sorting to put the smallest address first allows ++ the most combinations to be found. */ ++ ++/* Define results of standard character escape sequences. */ ++#define TARGET_BELL 007 ++#define TARGET_BS 010 ++#define TARGET_TAB 011 ++#define TARGET_NEWLINE 012 ++#define TARGET_VT 013 ++#define TARGET_FF 014 ++#define TARGET_CR 015 ++#define TARGET_ESC 033 ++ ++#define TRAMPOLINE_TEMPLATE(FILE) msp430_trampoline_template((FILE)) ++ ++#define TRAMPOLINE_SIZE 8 ++#define TRAMPOLINE_ALIGNMENT 16 ++ ++ ++#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ ++ msp430_initialize_trampoline (TRAMP, FNADDR, CXT) ++ ++ ++/* Store in cc_status the expressions ++ that the condition codes will describe ++ after execution of an instruction whose pattern is EXP. ++ Do not alter them if the instruction would not alter the cc's. */ ++ ++#define NOTICE_UPDATE_CC(EXP, INSN) notice_update_cc(EXP, INSN) ++ ++/* The add insns don't set overflow in a usable way. */ ++#define CC_OVERFLOW_UNUSABLE 01000 ++/* The mov,and,or,xor insns don't set carry. That's ok though as the ++ Z bit is all we need when doing unsigned comparisons on the result of ++ these insns (since they're always with 0). However, conditions.h has ++ CC_NO_OVERFLOW defined for this purpose. Rename it to something more ++ understandable. */ ++#define CC_NO_CARRY CC_NO_OVERFLOW ++ ++ ++/* Output assembler code to FILE to increment profiler label # LABELNO ++ for profiling a function entry. */ ++ ++#define FUNCTION_PROFILER(FILE, LABELNO) \ ++ fprintf (FILE, "/* profiler %d */", (LABELNO)) ++ ++/* `FIRST_INSN_ADDRESS' ++ When the `length' insn attribute is used, this macro specifies the ++ value to be assigned to the address of the first insn in a ++ function. If not specified, 0 is used. */ ++ ++#define ADJUST_INSN_LENGTH(INSN, LENGTH) (LENGTH =\ ++ adjust_insn_length (INSN, LENGTH)) ++/* If defined, modifies the length assigned to instruction INSN as a ++ function of the context in which it is used. LENGTH is an lvalue ++ that contains the initially computed length of the insn and should ++ be updated with the correct length of the insn. If updating is ++ required, INSN must not be a varying-length insn. ++ ++ This macro will normally not be required. A case in which it is ++ required is the ROMP. On this machine, the size of an `addr_vec' ++ insn must be increased by two to compensate for the fact that ++ alignment may be required. */ ++ ++#define TARGET_MEM_FUNCTIONS ++/* Define this macro if GNU CC should generate calls to the System V ++ (and ANSI C) library functions `memcpy' and `memset' rather than ++ the BSD functions `bcopy' and `bzero'. */ ++ ++#define CPP_SPEC "\ ++%{!mmcu*|mmcu=msp1:%(cpp_msp1)} \ ++%{mmcu=msp2:%(cpp_msp2) -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x110:%(cpp_msp1) -D__MSP430_110__} \ ++%{mmcu=msp430x112:%(cpp_msp1) -D__MSP430_112__} \ ++%{mmcu=msp430x1101:%(cpp_msp1) -D__MSP430_1101__} \ ++%{mmcu=msp430x1111:%(cpp_msp1) -D__MSP430_1111__} \ ++%{mmcu=msp430x1121:%(cpp_msp1) -D__MSP430_1121__} \ ++%{mmcu=msp430x1122:%(cpp_msp1) -D__MSP430_1122__} \ ++%{mmcu=msp430x1132:%(cpp_msp1) -D__MSP430_1132__} \ ++%{mmcu=msp430x122:%(cpp_msp1) -D__MSP430_122__} \ ++%{mmcu=msp430x123:%(cpp_msp1) -D__MSP430_123__} \ ++%{mmcu=msp430x1222:%(cpp_msp1) -D__MSP430_1222__} \ ++%{mmcu=msp430x1232:%(cpp_msp1) -D__MSP430_1232__} \ ++%{mmcu=msp430x133:%(cpp_msp1) -D__MSP430_133__} \ ++%{mmcu=msp430x135:%(cpp_msp1) -D__MSP430_135__} \ ++%{mmcu=msp430x1331:%(cpp_msp1) -D__MSP430_1331__} \ ++%{mmcu=msp430x1351:%(cpp_msp1) -D__MSP430_1351__} \ ++%{mmcu=msp430x147:%(cpp_msp2) -D__MSP430_147__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x148:%(cpp_msp2) -D__MSP430_148__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x149:%(cpp_msp2) -D__MSP430_149__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x1471:%(cpp_msp2) -D__MSP430_1471__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x1481:%(cpp_msp2) -D__MSP430_1481__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x1491:%(cpp_msp2) -D__MSP430_1491__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x155:%(cpp_msp1) -D__MSP430_155__} \ ++%{mmcu=msp430x156:%(cpp_msp1) -D__MSP430_156__} \ ++%{mmcu=msp430x157:%(cpp_msp1) -D__MSP430_157__} \ ++%{mmcu=msp430x167:%(cpp_msp2) -D__MSP430_167__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x168:%(cpp_msp2) -D__MSP430_168__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x169:%(cpp_msp2) -D__MSP430_169__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x1610:%(cpp_msp2) -D__MSP430_1610__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x1611:%(cpp_msp2) -D__MSP430_1611__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x1612:%(cpp_msp2) -D__MSP430_1612__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2001:%(cpp_msp1) -D__MSP430_2001__} \ ++%{mmcu=msp430x2011:%(cpp_msp1) -D__MSP430_2011__} \ ++%{mmcu=msp430x2002:%(cpp_msp1) -D__MSP430_2002__} \ ++%{mmcu=msp430x2012:%(cpp_msp1) -D__MSP430_2012__} \ ++%{mmcu=msp430x2003:%(cpp_msp1) -D__MSP430_2003__} \ ++%{mmcu=msp430x2013:%(cpp_msp1) -D__MSP430_2013__} \ ++%{mmcu=msp430x2101:%(cpp_msp1) -D__MSP430_2101__} \ ++%{mmcu=msp430x2111:%(cpp_msp1) -D__MSP430_2111__} \ ++%{mmcu=msp430x2121:%(cpp_msp1) -D__MSP430_2121__} \ ++%{mmcu=msp430x2131:%(cpp_msp1) -D__MSP430_2131__} \ ++%{mmcu=msp430x2232:%(cpp_msp1) -D__MSP430_2232__} \ ++%{mmcu=msp430x2252:%(cpp_msp1) -D__MSP430_2252__} \ ++%{mmcu=msp430x2272:%(cpp_msp1) -D__MSP430_2272__} \ ++%{mmcu=msp430x2234:%(cpp_msp1) -D__MSP430_2234__} \ ++%{mmcu=msp430x2254:%(cpp_msp1) -D__MSP430_2254__} \ ++%{mmcu=msp430x2274:%(cpp_msp1) -D__MSP430_2274__} \ ++%{mmcu=msp430x233:%(cpp_msp2) -D__MSP430_233__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x235:%(cpp_msp2) -D__MSP430_235__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2330:%(cpp_msp2) -D__MSP430_2330__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2350:%(cpp_msp2) -D__MSP430_2350__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2370:%(cpp_msp2) -D__MSP430_2370__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x247:%(cpp_msp2) -D__MSP430_247__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x248:%(cpp_msp2) -D__MSP430_248__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x249:%(cpp_msp2) -D__MSP430_249__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2410:%(cpp_msp2) -D__MSP430_2410__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2471:%(cpp_msp2) -D__MSP430_2471__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2481:%(cpp_msp2) -D__MSP430_2481__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2491:%(cpp_msp2) -D__MSP430_2491__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2416:%(cpp_msp2) -D__MSP430_2416__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2417:%(cpp_msp2) -D__MSP430_2417__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2418:%(cpp_msp2) -D__MSP430_2418__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2419:%(cpp_msp2) -D__MSP430_2419__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2616:%(cpp_msp2) -D__MSP430_2616__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2617:%(cpp_msp2) -D__MSP430_2617__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2618:%(cpp_msp2) -D__MSP430_2618__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x2619:%(cpp_msp2) -D__MSP430_2619__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x311:%(cpp_msp1) -D__MSP430_311__} \ ++%{mmcu=msp430x312:%(cpp_msp1) -D__MSP430_312__} \ ++%{mmcu=msp430x313:%(cpp_msp1) -D__MSP430_313__} \ ++%{mmcu=msp430x314:%(cpp_msp1) -D__MSP430_314__} \ ++%{mmcu=msp430x315:%(cpp_msp1) -D__MSP430_315__} \ ++%{mmcu=msp430x323:%(cpp_msp1) -D__MSP430_323__} \ ++%{mmcu=msp430x325:%(cpp_msp1) -D__MSP430_325__} \ ++%{mmcu=msp430x336:%(cpp_msp2) -D__MSP430_336__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x337:%(cpp_msp2) -D__MSP430_337__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x412:%(cpp_msp1) -D__MSP430_412__} \ ++%{mmcu=msp430x413:%(cpp_msp1) -D__MSP430_413__} \ ++%{mmcu=msp430x415:%(cpp_msp1) -D__MSP430_415__} \ ++%{mmcu=msp430x417:%(cpp_msp1) -D__MSP430_417__} \ ++%{mmcu=msp430x423:%(cpp_msp2) -D__MSP430_423__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x425:%(cpp_msp2) -D__MSP430_425__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x427:%(cpp_msp2) -D__MSP430_427__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x4250:%(cpp_msp1) -D__MSP430_4250__} \ ++%{mmcu=msp430x4260:%(cpp_msp1) -D__MSP430_4260__} \ ++%{mmcu=msp430x4270:%(cpp_msp1) -D__MSP430_4270__} \ ++%{mmcu=msp430xE423:%(cpp_msp2) -D__MSP430_E423__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430xE425:%(cpp_msp2) -D__MSP430_E425__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430xE427:%(cpp_msp2) -D__MSP430_E427__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430xW423:%(cpp_msp1) -D__MSP430_W423__} \ ++%{mmcu=msp430xW425:%(cpp_msp1) -D__MSP430_W425__} \ ++%{mmcu=msp430xW427:%(cpp_msp1) -D__MSP430_W427__} \ ++%{mmcu=msp430xG437:%(cpp_msp1) -D__MSP430_G437__} \ ++%{mmcu=msp430xG438:%(cpp_msp1) -D__MSP430_G438__} \ ++%{mmcu=msp430xG439:%(cpp_msp1) -D__MSP430_G439__} \ ++%{mmcu=msp430x435:%(cpp_msp1) -D__MSP430_435__} \ ++%{mmcu=msp430x436:%(cpp_msp1) -D__MSP430_436__} \ ++%{mmcu=msp430x437:%(cpp_msp1) -D__MSP430_437__} \ ++%{mmcu=msp430x447:%(cpp_msp2) -D__MSP430_447__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x448:%(cpp_msp2) -D__MSP430_448__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430x449:%(cpp_msp2) -D__MSP430_449__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430xG4616:%(cpp_msp2) -D__MSP430_G4616__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430xG4617:%(cpp_msp2) -D__MSP430_G4617__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430xG4618:%(cpp_msp2) -D__MSP430_G4618__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ ++%{mmcu=msp430xG4619:%(cpp_msp2) -D__MSP430_G4619__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ ++%{mint8:-D__SIZE_TYPE__=long\\ unsigned\\ int -D__PTRDIFF_TYPE__=long -D__INT_MAX__=127} \ ++%{!mint*:-D__SIZE_TYPE__=unsigned\\ int -D__PTRDIFF_TYPE__=int -D__INT_MAX__=32767} \ ++%{posix:-D_POSIX_SOURCE} %{mIAR:-D_IAR_ASSEMBLER_}" ++ ++/* A C string constant that tells the GNU CC driver program options to ++ pass to CPP. It can also specify how to translate options you ++ give to GNU CC into options for GNU CC to pass to the CPP. ++ ++ Do not define this macro if it does not need to do anything. */ ++ ++#define NO_BUILTIN_SIZE_TYPE ++/* If this macro is defined, the preprocessor will not define the ++ builtin macro `__SIZE_TYPE__'. The macro `__SIZE_TYPE__' must ++ then be defined by `CPP_SPEC' instead. ++ ++ This should be defined if `SIZE_TYPE' depends on target dependent ++ flags which are not accessible to the preprocessor. Otherwise, it ++ should not be defined. */ ++ ++#define NO_BUILTIN_PTRDIFF_TYPE ++/* If this macro is defined, the preprocessor will not define the ++ builtin macro `__PTRDIFF_TYPE__'. The macro `__PTRDIFF_TYPE__' ++ must then be defined by `CPP_SPEC' instead. ++ ++ This should be defined if `PTRDIFF_TYPE' depends on target ++ dependent flags which are not accessible to the preprocessor. ++ Otherwise, it should not be defined. ++ ++ `SIGNED_CHAR_SPEC' ++ A C string constant that tells the GNU CC driver program options to ++ pass to CPP. By default, this macro is defined to pass the option ++ `-D__CHAR_UNSIGNED__' to CPP if `char' will be treated as ++ `unsigned char' by `cc1'. ++ ++ Do not define this macro unless you need to override the default ++ definition. */ ++ ++#define CC1_SPEC "%{profile:-p}" ++/* A C string constant that tells the GNU CC driver program options to ++ pass to `cc1'. It can also specify how to translate options you ++ give to GNU CC into options for GNU CC to pass to the `cc1'. ++ ++ Do not define this macro if it does not need to do anything. */ ++ ++#define ASM_SPEC "" ++/* A C string constant that tells the GNU CC driver program options to ++ pass to the assembler. It can also specify how to translate ++ options you give to GNU CC into options for GNU CC to pass to the ++ assembler. See the file `sun3.h' for an example of this. ++ ++ Do not define this macro if it does not need to do anything. */ ++ ++#define ASM_FINAL_SPEC "" ++/* A C string constant that tells the GNU CC driver program how to ++ run any programs which cleanup after the normal assembler. ++ Normally, this is not needed. See the file `mips.h' for an ++ example of this. ++ ++ Do not define this macro if it does not need to do anything. */ ++ ++#define LINK_SPEC "\ ++%{!mmcu*:-m msp430x110} \ ++%{mmcu=msp1:-m msp430x110} \ ++%{mmcu=msp2:-m msp430x336} \ ++%{mmcu=msp430x110:-m msp430x110 } \ ++%{mmcu=msp430x112:-m msp430x112 } \ ++%{mmcu=msp430x1101:-m msp430x1101 } \ ++%{mmcu=msp430x1111:-m msp430x1111 } \ ++%{mmcu=msp430x1121:-m msp430x1121 } \ ++%{mmcu=msp430x1122:-m msp430x1122 } \ ++%{mmcu=msp430x1132:-m msp430x1132 } \ ++%{mmcu=msp430x122:-m msp430x122 } \ ++%{mmcu=msp430x123:-m msp430x123 } \ ++%{mmcu=msp430x1222:-m msp430x1222 } \ ++%{mmcu=msp430x1232:-m msp430x1232 } \ ++%{mmcu=msp430x133:-m msp430x133 } \ ++%{mmcu=msp430x135:-m msp430x135 } \ ++%{mmcu=msp430x1331:-m msp430x1331 } \ ++%{mmcu=msp430x1351:-m msp430x1351 } \ ++%{mmcu=msp430x147:-m msp430x147 } \ ++%{mmcu=msp430x148:-m msp430x148 } \ ++%{mmcu=msp430x149:-m msp430x149 } \ ++%{mmcu=msp430x1471:-m msp430x1471 } \ ++%{mmcu=msp430x1481:-m msp430x1481 } \ ++%{mmcu=msp430x1491:-m msp430x1491 } \ ++%{mmcu=msp430x155:-m msp430x155 } \ ++%{mmcu=msp430x156:-m msp430x156 } \ ++%{mmcu=msp430x157:-m msp430x157 } \ ++%{mmcu=msp430x167:-m msp430x167 } \ ++%{mmcu=msp430x168:-m msp430x168 } \ ++%{mmcu=msp430x169:-m msp430x169 } \ ++%{mmcu=msp430x1610:-m msp430x1610 } \ ++%{mmcu=msp430x1611:-m msp430x1611 } \ ++%{mmcu=msp430x1612:-m msp430x1612 } \ ++%{mmcu=msp430x2001:-m msp430x2001 } \ ++%{mmcu=msp430x2011:-m msp430x2011 } \ ++%{mmcu=msp430x2002:-m msp430x2002 } \ ++%{mmcu=msp430x2012:-m msp430x2012 } \ ++%{mmcu=msp430x2003:-m msp430x2003 } \ ++%{mmcu=msp430x2013:-m msp430x2013 } \ ++%{mmcu=msp430x2101:-m msp430x2101 } \ ++%{mmcu=msp430x2111:-m msp430x2111 } \ ++%{mmcu=msp430x2121:-m msp430x2121 } \ ++%{mmcu=msp430x2131:-m msp430x2131 } \ ++%{mmcu=msp430x2232:-m msp430x2232 } \ ++%{mmcu=msp430x2252:-m msp430x2252 } \ ++%{mmcu=msp430x2272:-m msp430x2272 } \ ++%{mmcu=msp430x2234:-m msp430x2234 } \ ++%{mmcu=msp430x2254:-m msp430x2254 } \ ++%{mmcu=msp430x2274:-m msp430x2274 } \ ++%{mmcu=msp430x233:-m msp430x233 } \ ++%{mmcu=msp430x235:-m msp430x235 } \ ++%{mmcu=msp430x2330:-m msp430x2330 } \ ++%{mmcu=msp430x2350:-m msp430x2350 } \ ++%{mmcu=msp430x2370:-m msp430x2370 } \ ++%{mmcu=msp430x247:-m msp430x247 } \ ++%{mmcu=msp430x248:-m msp430x248 } \ ++%{mmcu=msp430x249:-m msp430x249 } \ ++%{mmcu=msp430x2410:-m msp430x2410 } \ ++%{mmcu=msp430x2471:-m msp430x2471 } \ ++%{mmcu=msp430x2481:-m msp430x2481 } \ ++%{mmcu=msp430x2491:-m msp430x2491 } \ ++%{mmcu=msp430x2416:-m msp430x2416 } \ ++%{mmcu=msp430x2417:-m msp430x2417 } \ ++%{mmcu=msp430x2418:-m msp430x2418 } \ ++%{mmcu=msp430x2419:-m msp430x2419 } \ ++%{mmcu=msp430x2616:-m msp430x2616 } \ ++%{mmcu=msp430x2617:-m msp430x2617 } \ ++%{mmcu=msp430x2618:-m msp430x2618 } \ ++%{mmcu=msp430x2619:-m msp430x2619 } \ ++%{mmcu=msp430x311:-m msp430x311 } \ ++%{mmcu=msp430x312:-m msp430x312 } \ ++%{mmcu=msp430x313:-m msp430x313 } \ ++%{mmcu=msp430x314:-m msp430x314 } \ ++%{mmcu=msp430x315:-m msp430x315 } \ ++%{mmcu=msp430x323:-m msp430x323 } \ ++%{mmcu=msp430x325:-m msp430x325 } \ ++%{mmcu=msp430x336:-m msp430x336 } \ ++%{mmcu=msp430x337:-m msp430x337 } \ ++%{mmcu=msp430x412:-m msp430x412 } \ ++%{mmcu=msp430x413:-m msp430x413 } \ ++%{mmcu=msp430x415:-m msp430x415 } \ ++%{mmcu=msp430x417:-m msp430x417 } \ ++%{mmcu=msp430x423:-m msp430x423 } \ ++%{mmcu=msp430x425:-m msp430x425 } \ ++%{mmcu=msp430x427:-m msp430x427 } \ ++%{mmcu=msp430x4250:-m msp430x4250 } \ ++%{mmcu=msp430x4260:-m msp430x4260 } \ ++%{mmcu=msp430x4270:-m msp430x4270 } \ ++%{mmcu=msp430xE423:-m msp430xE423 } \ ++%{mmcu=msp430xE425:-m msp430xE425 } \ ++%{mmcu=msp430xE427:-m msp430xE427 } \ ++%{mmcu=msp430xW423:-m msp430xW423 } \ ++%{mmcu=msp430xW425:-m msp430xW425 } \ ++%{mmcu=msp430xW427:-m msp430xW427 } \ ++%{mmcu=msp430xG437:-m msp430xG437 } \ ++%{mmcu=msp430xG438:-m msp430xG438 } \ ++%{mmcu=msp430xG439:-m msp430xG439 } \ ++%{mmcu=msp430x435:-m msp430x435 } \ ++%{mmcu=msp430x436:-m msp430x436 } \ ++%{mmcu=msp430x437:-m msp430x437 } \ ++%{mmcu=msp430x447:-m msp430x447 } \ ++%{mmcu=msp430x448:-m msp430x448 } \ ++%{mmcu=msp430x449:-m msp430x449 } \ ++%{mmcu=msp430xG4616:-m msp430xG4616 } \ ++%{mmcu=msp430xG4617:-m msp430xG4617 } \ ++%{mmcu=msp430xG4618:-m msp430xG4618 } \ ++%{mmcu=msp430xG4619:-m msp430xG4619 }" ++ ++/* A C string constant that tells the GNU CC driver program options to ++ pass to the linker. It can also specify how to translate options ++ you give to GNU CC into options for GNU CC to pass to the linker. ++ ++ Do not define this macro if it does not need to do anything. */ ++ ++#define LIB_SPEC \ ++ "%{*:-lc }" ++/* Another C string constant used much like `LINK_SPEC'. The ++ difference between the two is that `LIB_SPEC' is used at the end ++ of the command given to the linker. ++ ++ If this macro is not defined, a default is provided that loads the ++ standard C library from the usual place. See `gcc.c'. */ ++ ++#define LIBGCC_SPEC \ ++ "%{*: -lgcc }" ++/* Another C string constant that tells the GNU CC driver program how ++ and when to place a reference to `libgcc.a' into the linker ++ command line. This constant is placed both before and after the ++ value of `LIB_SPEC'. ++ ++ If this macro is not defined, the GNU CC driver provides a default ++ that passes the string `-lgcc' to the linker unless the `-shared' ++ option is specified. */ ++ ++#define STARTFILE_SPEC "%(crt_binutils)" ++/* Another C string constant used much like `LINK_SPEC'. The ++ difference between the two is that `STARTFILE_SPEC' is used at the ++ very beginning of the command given to the linker. ++ ++ If this macro is not defined, a default is provided that loads the ++ standard C startup file from the usual place. See `gcc.c'. */ ++ ++#define ENDFILE_SPEC "" ++/* Another C string constant used much like `LINK_SPEC'. The ++ difference between the two is that `ENDFILE_SPEC' is used at the ++ very end of the command given to the linker. ++ ++ Do not define this macro if it does not need to do anything. */ ++ ++/* recently added: ++1222 1232 */ ++ ++#define CRT_BINUTILS_SPECS "\ ++%{!mmcu=*|mmcu=msp430x110|mmcu=msp1:crt430x110.o%s} \ ++%{mmcu=msp430x112:crt430x112.o%s} \ ++%{mmcu=msp430x1101:crt430x1101.o%s} \ ++%{mmcu=msp430x1111:crt430x1111.o%s} \ ++%{mmcu=msp430x1121:crt430x1121.o%s} \ ++%{mmcu=msp430x1122:crt430x1122.o%s} \ ++%{mmcu=msp430x1132:crt430x1132.o%s} \ ++%{mmcu=msp430x122:crt430x122.o%s} \ ++%{mmcu=msp430x123:crt430x123.o%s} \ ++%{mmcu=msp430x1222:crt430x1222.o%s} \ ++%{mmcu=msp430x1232:crt430x1232.o%s} \ ++%{mmcu=msp430x133:crt430x133.o%s} \ ++%{mmcu=msp430x135:crt430x135.o%s} \ ++%{mmcu=msp430x1331:crt430x1331.o%s} \ ++%{mmcu=msp430x1351:crt430x1351.o%s} \ ++%{mmcu=msp430x147:crt430x147.o%s} \ ++%{mmcu=msp430x148:crt430x148.o%s} \ ++%{mmcu=msp430x149:crt430x149.o%s} \ ++%{mmcu=msp430x1471:crt430x1471.o%s} \ ++%{mmcu=msp430x1481:crt430x1481.o%s} \ ++%{mmcu=msp430x1491:crt430x1491.o%s} \ ++%{mmcu=msp430x155:crt430x155.o%s} \ ++%{mmcu=msp430x156:crt430x156.o%s} \ ++%{mmcu=msp430x157:crt430x157.o%s} \ ++%{mmcu=msp430x167:crt430x167.o%s} \ ++%{mmcu=msp430x168:crt430x168.o%s} \ ++%{mmcu=msp430x169:crt430x169.o%s} \ ++%{mmcu=msp430x1610:crt430x1610.o%s} \ ++%{mmcu=msp430x1611:crt430x1611.o%s} \ ++%{mmcu=msp430x1612:crt430x1612.o%s} \ ++%{mmcu=msp430x2001:crt430x2001.o%s} \ ++%{mmcu=msp430x2011:crt430x2011.o%s} \ ++%{mmcu=msp430x2002:crt430x2002.o%s} \ ++%{mmcu=msp430x2012:crt430x2012.o%s} \ ++%{mmcu=msp430x2003:crt430x2003.o%s} \ ++%{mmcu=msp430x2013:crt430x2013.o%s} \ ++%{mmcu=msp430x2101:crt430x2101.o%s} \ ++%{mmcu=msp430x2111:crt430x2111.o%s} \ ++%{mmcu=msp430x2121:crt430x2121.o%s} \ ++%{mmcu=msp430x2131:crt430x2131.o%s} \ ++%{mmcu=msp430x2232:crt430x2232.o%s} \ ++%{mmcu=msp430x2252:crt430x2252.o%s} \ ++%{mmcu=msp430x2272:crt430x2272.o%s} \ ++%{mmcu=msp430x2234:crt430x2234.o%s} \ ++%{mmcu=msp430x2254:crt430x2254.o%s} \ ++%{mmcu=msp430x2274:crt430x2274.o%s} \ ++%{mmcu=msp430x247:crt430x247.o%s} \ ++%{mmcu=msp430x248:crt430x248.o%s} \ ++%{mmcu=msp430x249:crt430x249.o%s} \ ++%{mmcu=msp430x2410:crt430x2410.o%s} \ ++%{mmcu=msp430x2471:crt430x2471.o%s} \ ++%{mmcu=msp430x2481:crt430x2481.o%s} \ ++%{mmcu=msp430x2491:crt430x2491.o%s} \ ++%{mmcu=msp430x2416:crt430x2416.o%s} \ ++%{mmcu=msp430x2417:crt430x2417.o%s} \ ++%{mmcu=msp430x2418:crt430x2418.o%s} \ ++%{mmcu=msp430x2419:crt430x2419.o%s} \ ++%{mmcu=msp430x2616:crt430x2616.o%s} \ ++%{mmcu=msp430x2617:crt430x2617.o%s} \ ++%{mmcu=msp430x2618:crt430x2618.o%s} \ ++%{mmcu=msp430x2619:crt430x2619.o%s} \ ++%{mmcu=msp430x311:crt430x311.o%s} \ ++%{mmcu=msp430x312:crt430x312.o%s} \ ++%{mmcu=msp430x313:crt430x313.o%s} \ ++%{mmcu=msp430x314:crt430x314.o%s} \ ++%{mmcu=msp430x315:crt430x315.o%s} \ ++%{mmcu=msp430x323:crt430x323.o%s} \ ++%{mmcu=msp430x325:crt430x325.o%s} \ ++%{mmcu=msp430x336|mmcu=msp2:crt430x336.o%s} \ ++%{mmcu=msp430x337:crt430x337.o%s} \ ++%{mmcu=msp430x412:crt430x412.o%s} \ ++%{mmcu=msp430x413:crt430x413.o%s} \ ++%{mmcu=msp430x415:crt430x415.o%s} \ ++%{mmcu=msp430x417:crt430x417.o%s} \ ++%{mmcu=msp430x423:crt430x423.o%s} \ ++%{mmcu=msp430x425:crt430x425.o%s} \ ++%{mmcu=msp430x427:crt430x427.o%s} \ ++%{mmcu=msp430x4250:crt430x4250.o%s} \ ++%{mmcu=msp430x4260:crt430x4260.o%s} \ ++%{mmcu=msp430x4270:crt430x4270.o%s} \ ++%{mmcu=msp430xE423:crt430xE423.o%s} \ ++%{mmcu=msp430xE425:crt430xE425.o%s} \ ++%{mmcu=msp430xE427:crt430xE427.o%s} \ ++%{mmcu=msp430xW423:crt430xW423.o%s} \ ++%{mmcu=msp430xW425:crt430xW425.o%s} \ ++%{mmcu=msp430xW427:crt430xW427.o%s} \ ++%{mmcu=msp430xG437:crt430xG437.o%s} \ ++%{mmcu=msp430xG438:crt430xG438.o%s} \ ++%{mmcu=msp430xG439:crt430xG439.o%s} \ ++%{mmcu=msp430x435:crt430x435.o%s} \ ++%{mmcu=msp430x436:crt430x436.o%s} \ ++%{mmcu=msp430x437:crt430x437.o%s} \ ++%{mmcu=msp430x447:crt430x447.o%s} \ ++%{mmcu=msp430x448:crt430x448.o%s} \ ++%{mmcu=msp430x449:crt430x449.o%s} \ ++%{mmcu=msp430xG4616:crt430xG4616.o%s} \ ++%{mmcu=msp430xG4617:crt430xG4617.o%s} \ ++%{mmcu=msp430xG4618:crt430xG4618.o%s} \ ++%{mmcu=msp430xG4619:crt430xG4619.o%s}" ++ ++ ++ ++#define CPP_MSP1_SPEC " -DMSP430_NO_HW_MUL " ++#define CPP_MSP2_SPEC " -DMSP430_HAS_HW_MUL " ++ ++#define EXTRA_SPECS \ ++{"cpp_msp1",CPP_MSP1_SPEC}, \ ++{"cpp_msp2",CPP_MSP2_SPEC}, \ ++{"crt_binutils", CRT_BINUTILS_SPECS}, ++ ++/* Define this macro to provide additional specifications to put in ++ the `specs' file that can be used in various specifications like ++ `CC1_SPEC'. ++ ++ The definition should be an initializer for an array of structures, ++ containing a string constant, that defines the specification name, ++ and a string constant that provides the specification. ++ ++ Do not define this macro if it does not need to do anything. ++ ++ `EXTRA_SPECS' is useful when an architecture contains several ++ related targets, which have various `..._SPECS' which are similar ++ to each other, and the maintainer would like one central place to ++ keep these definitions. ++ ++ For example, the PowerPC System V.4 targets use `EXTRA_SPECS' to ++ define either `_CALL_SYSV' when the System V calling sequence is ++ used or `_CALL_AIX' when the older AIX-based calling sequence is ++ used. ++ ++ The `config/rs6000/rs6000.h' target file defines: ++ ++ #define EXTRA_SPECS \ ++ { "cpp_sysv_default", CPP_SYSV_DEFAULT }, ++ ++ #define CPP_SYS_DEFAULT "" ++ ++ The `config/rs6000/sysv.h' target file defines: ++ #undef CPP_SPEC ++ #define CPP_SPEC \ ++ "%{posix: -D_POSIX_SOURCE } \ ++ %{mcall-sysv: -D_CALL_SYSV } %{mcall-aix: -D_CALL_AIX } \ ++ %{!mcall-sysv: %{!mcall-aix: %(cpp_sysv_default) }} \ ++ %{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT}" ++ ++ #undef CPP_SYSV_DEFAULT ++ #define CPP_SYSV_DEFAULT "-D_CALL_SYSV" ++ ++ while the `config/rs6000/eabiaix.h' target file defines ++ `CPP_SYSV_DEFAULT' as: ++ ++ #undef CPP_SYSV_DEFAULT ++ #define CPP_SYSV_DEFAULT "-D_CALL_AIX" */ ++ ++ ++#define MULTILIB_DEFAULTS { "mmcu=msp430x110" } ++ ++/* This is undefined macro for collect2 disabling */ ++#define LINKER_NAME "msp430-ld" ++ ++#define TEST_HARD_REG_CLASS(CLASS, REGNO) \ ++ TEST_HARD_REG_BIT (reg_class_contents[ (int) (CLASS)], REGNO) ++ ++/* Note that the other files fail to use these ++ in some of the places where they should. */ ++ ++#if defined(__STDC__) || defined(ALMOST_STDC) ++#define AS2(a,b,c) #a " " #b "," #c ++#define AS2C(b,c) " " #b "," #c ++#define AS3(a,b,c,d) #a " " #b "," #c "," #d ++#define AS1(a,b) #a " " #b ++#else ++#define AS1(a,b) "a b" ++#define AS2(a,b,c) "a b,c" ++#define AS2C(b,c) " b,c" ++#define AS3(a,b,c,d) "a b,c,d" ++#endif ++#define OUT_AS1(a,b) output_asm_insn (AS1(a,b), operands) ++#define OUT_AS2(a,b,c) output_asm_insn (AS2(a,b,c), operands) ++#define CR_TAB "\n\t" ++ ++/* Define this macro as a C statement that declares additional library ++ routines renames existing ones. `init_optabs' calls this macro ++ after initializing all the normal library routines. */ ++ ++#define INIT_TARGET_OPTABS \ ++{ \ ++ msp430_init_once (); \ ++} ++ ++#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT ++ ++/* Define to use software floating point emulator for REAL_ARITHMETIC and ++ decimal <-> binary conversion. */ ++ ++#ifndef REAL_ARITHMETIC ++#define REAL_ARITHMETIC ++#endif ++ ++#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG ++#define DWARF2_DEBUGGING_INFO 1 ++#define OBJECT_FORMAT_ELF ++ ++#define DBX_REGISTER_NUMBER(r) (r) ++ ++/* Get the standard ELF stabs definitions. */ ++#include "dbxelf.h" ++ ++ +diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/msp430.md gcc-3.2.3/gcc/config/msp430/msp430.md +--- gcc-3.2.3.orig/gcc/config/msp430/msp430.md 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-3.2.3/gcc/config/msp430/msp430.md 2008-08-22 09:17:00.000000000 -0600 +@@ -0,0 +1,4079 @@ ++;; -*- Mode: Scheme -*- ++;; Machine description for GNU compiler, ++;; for Texas Instruments msp430 MCUs ++;; Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. ++;; Contributed by Dmitry Diky ++ ++;; This file is part of GCC. ++ ++;; GCC is free software; you can redistribute it and/or modify ++;; it under the terms of the GNU General Public License as published by ++;; the Free Software Foundation; either version 2, or (at your option) ++;; any later version. ++ ++;; GCC is distributed in the hope that it will be useful, ++;; but WITHOUT ANY WARRANTY; without even the implied warranty of ++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++;; GNU General Public License for more details. ++ ++;; You should have received a copy of the GNU General Public License ++;; along with GCC; see the file COPYING. If not, write to ++;; the Free Software Foundation, 59 Temple Place - Suite 330, ++;; Boston, MA 02111-1307, USA. ++ ++;; Special characters after '%': ++;; A No effect (add 0). ++;; B Add 1 to REG number, 2 to MEM address or CONST_INT. ++;; C 2 4 ++;; D 3 6 ++;; E adds nothing to reg but used only with (mem:hi (reg:hi)) ++;; F no trim array ++;; M Add 0 to address if using stack pointer ++;; N Add 2 to address if using stack pointer ++;; Extra constarains: ++;; P hardware constants: -1,0,+1,+2,+4,+8 ++;; Q Indexed destination register as X(Rn) ++;; R Indexed source register as @Rn+ ++;; S Symbol reference for 'C' like: a = *b; ++;; ++ ++;; Unspec usage: ++;; 3 - strlen ++;; 0 - addc_reg ++;; 5 - addc_any ++;; 1 - bittest_lo ++;; 2 - bittest_hi ++;; 6 - bittest ++;; 4 - swpb ++;; 7 - bittest_b ++;; 8 - move SF to SI with no conversion ++ ++ ++;; Condition code settings. ++ ++ ++(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber,further,oper,cbranch" ++ (const_string "none")) ++ ++(define_attr "type" "branch,branch1,arith" ++ (const_string "arith")) ++ ++(define_attr "msp430_has_hwmul" "yes,no" ++ (const (if_then_else (symbol_ref "MSP430_HAS_HWMUL_INTERNAL") ++ (const_string "yes") ++ (const_string "no")))) ++ ++(define_attr "msp430_noint_hwmul" "" (symbol_ref "MSP430_NOINT_HWMUL")) ++ ++;; The size of instructions in bytes. ++;; XXX may depend from "cc" ++ ++;; for confitional branches ++(define_attr "length" "" ++ (cond [(eq_attr "type" "branch") ++ (if_then_else (and (ge (minus (pc) (match_dup 0)) ++ (const_int -508)) ++ (le (minus (pc) (match_dup 0)) ++ (const_int 508))) ++ (const_int 1) ++ (const_int 2))] ++ (const_int 2) ++)) ++ ++ ++;;======================================================================== ++;; PUSH/POP helper functions ++;; ++ ++ ++(define_insn "*pushqi_pre_mod" ++[(set (mem:QI (pre_modify:HI (reg:HI 1) ++ (plus:HI (reg:HI 1) (const_int -2)))) ++ (match_operand:QI 0 "general_operand" "rim"))] ++"" ++"* return msp430_pushqi(insn, operands, NULL);" ++[(set_attr "length" "2")]) ++ ++(define_insn "*pushqi" ++ [(set (mem:QI (post_dec (reg:HI 1))) ++ (match_operand:QI 0 "general_operand" "rim"))] ++ "" ++ "* return msp430_pushqi(insn, operands, NULL);" ++ [(set_attr "length" "2")]) ++ ++(define_insn "*pushhi" ++ [(set (mem:HI (post_dec (reg:HI 1))) ++ (match_operand:HI 0 "general_operand" "rim"))] ++ "" ++ "* return msp430_pushhi(insn, operands, NULL);" ++ [(set_attr "length" "2")]) ++ ++(define_insn "*pushsi" ++ [(set (mem:SI (post_dec (reg:HI 1))) ++ (match_operand:SI 0 "general_operand" "rmi"))] ++ "" ++ "* return msp430_pushsisf(insn, operands, NULL);" ++ [(set_attr "length" "4")]) ++ ++ ++(define_insn "*pushdi" ++ [(set (mem:DI (post_dec (reg:HI 1))) ++ (match_operand:DI 0 "general_operand" "rmi"))] ++ "" ++ "* return msp430_pushdi(insn, operands, NULL);" ++ [(set_attr "length" "8")]) ++ ++ ++(define_insn "*pushsf" ++ [(set (mem:SF (post_dec (reg:HI 1))) ++ (match_operand:SF 0 "general_operand" "rmi"))] ++ "" ++ "* return msp430_pushsisf(insn, operands, NULL);" ++ [(set_attr "length" "4")]) ++ ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "general_operand" "")) ++ (set (mem:HI (post_dec (reg:HI 1))) ++ (match_dup 0))] ++"dead_or_set_in_peep(1, insn, operands[0])" ++ [(set (mem:HI (post_dec (reg:HI 1))) ++ (match_dup 1))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "general_operand" "")) ++ (set (mem:SI (post_dec (reg:HI 1))) ++ (match_dup 0))] ++"dead_or_set_in_peep(1, insn, operands[0])" ++ [(set (mem:SI (post_dec (reg:HI 1))) ++ (match_dup 1))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SF 0 "register_operand" "") ++ (match_operand:SF 1 "general_operand" "")) ++ (set (mem:SF (post_dec (reg:HI 1))) ++ (match_dup 0))] ++"dead_or_set_in_peep(1, insn, operands[0])" ++ [(set (mem:SF (post_dec (reg:HI 1))) ++ (match_dup 1))] ++"") ++ ++ ++;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++;; This instructin sets Z flag ++ ++(define_insn "sez" ++ [(set (cc0) (const_int 0))] ++"" ++"setz" ++ [(set_attr "length" "1") ++ (set_attr "cc" "compare")]) ++ ++ ++ ++;;======================================================================== ++;; compare ++ ++(define_expand "cmpqi" ++ [(set (cc0) ++ (compare:QI (match_operand:QI 0 "nonimmediate_operand_msp430" "rm") ++ (match_operand:QI 1 "general_operand_msp430" "rmi")))] ++ "" ++" ++ msp430_compare_op0 = operands[0]; ++ msp430_compare_op1 = operands[1]; ++ DONE; ++") ++ ++ ++(define_expand "cmphi" ++ [(set (cc0) ++ (compare:HI (match_operand:HI 0 "nonimmediate_operand_msp430" "rm") ++ (match_operand:HI 1 "general_operand_msp430" "rmi")))] ++ "" ++" ++ msp430_compare_op0 = operands[0]; ++ msp430_compare_op1 = operands[1]; ++ DONE; ++") ++ ++ ++(define_expand "cmpsi" ++ [(set (cc0) ++ (compare:SI (match_operand:SI 0 "nonimmediate_operand" "rm") ++ (match_operand:SI 1 "general_operand" "rmi")))] ++ "" ++" ++ msp430_compare_op0 = operands[0]; ++ msp430_compare_op1 = operands[1]; ++ DONE; ++") ++ ++ ++(define_expand "beq" ++ [(use (match_operand 0 "" ""))] ++"" ++"{ msp430_emit_cbranch (EQ, operands[0]); DONE; }") ++ ++(define_expand "bne" ++ [(use (match_operand 0 "" ""))] ++"" ++"{ msp430_emit_cbranch (NE, operands[0]); DONE; }") ++ ++(define_expand "bge" ++ [(use (match_operand 0 "" ""))] ++"" ++"{ msp430_emit_cbranch (GE, operands[0]); DONE; }") ++ ++(define_expand "bgt" ++ [(use (match_operand 0 "" ""))] ++"" ++"{ msp430_emit_cbranch (GT, operands[0]); DONE; }") ++ ++(define_expand "ble" ++ [(use (match_operand 0 "" ""))] ++"" ++"{ msp430_emit_cbranch (LE, operands[0]); DONE; }") ++ ++(define_expand "blt" ++ [(use (match_operand 0 "" ""))] ++"" ++"{ msp430_emit_cbranch (LT, operands[0]); DONE; }") ++ ++(define_expand "bgeu" ++ [(use (match_operand 0 "" ""))] ++"" ++"{ msp430_emit_cbranch (GEU, operands[0]); DONE; }") ++ ++(define_expand "bgtu" ++ [(use (match_operand 0 "" ""))] ++"" ++"{ msp430_emit_cbranch (GTU, operands[0]); DONE; }") ++ ++(define_expand "bleu" ++ [(use (match_operand 0 "" ""))] ++"" ++"{ msp430_emit_cbranch (LEU, operands[0]); DONE; }") ++ ++(define_expand "bltu" ++ [(use (match_operand 0 "" ""))] ++"" ++"{ msp430_emit_cbranch (LTU, operands[0]); DONE; }") ++ ++ ++(define_insn "*cbranchqi" ++ [(set (pc) ++ (if_then_else (match_operator:QI 1 "comparison_operator" ++ [(match_operand:QI 2 "nonimmediate_operand_msp430" "rm") ++ (match_operand:QI 3 "general_operand" "rmi")]) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++"" ++"* return msp430_cbranch(insn, operands, NULL);" ++ [(set_attr "length" "9") ++ (set_attr "cc" "cbranch")]) ++ ++ ++ ++(define_insn "*cbranchhi" ++ [(set (pc) ++ (if_then_else (match_operator:HI 1 "comparison_operator" ++ [(match_operand:HI 2 "nonimmediate_operand_msp430" "rm") ++ (match_operand:HI 3 "general_operand" "rmi")]) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++"" ++"* return msp430_cbranch(insn, operands, NULL);" ++ [(set_attr "length" "9") ++ (set_attr "cc" "cbranch")]) ++ ++ ++(define_insn "*cbranchsi_eqne" ++ [(set (pc) ++ (if_then_else (match_operator:SI 1 "equality_operator" ++ [(match_operand:SI 2 "nonimmediate_operand" "rm") ++ (match_operand:SI 3 "general_operand" "rmi")]) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++"" ++"* return msp430_cbranch(insn, operands, NULL);" ++[(set_attr "length" "9") ++ (set_attr "cc" "cbranch")]) ++ ++ ++(define_insn "*cbranchsi_others" ++ [(parallel [(set (pc) ++ (if_then_else (match_operator:SI 1 "inequality_operator" ++ [(match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "general_operand" "rmi")]) ++ (label_ref (match_operand 0 "" "")) ++ (pc))) ++ (clobber (match_dup 2))])] ++"" ++"* return msp430_cbranch(insn, operands, NULL);" ++[(set_attr "length" "9") ++ (set_attr "cc" "cbranch")]) ++ ++ ++(define_insn "*cbranch_uncoded" ++ [(set (pc) ++ (if_then_else (match_operator 1 "comparison_operator" ++ [(cc0) ++ (const_int 0)]) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++"" ++"* return msp430_cbranch(insn, operands, NULL);" ++[(set_attr "length" "9") ++(set_attr "cc" "cbranch")]) ++ ++ ++;;======================================================================== ++;; noop ++(define_insn "nop" ++ [(const_int 0)] ++ "" ++ "nop" ++ [(set_attr "cc" "none") ++ (set_attr "length" "1")]) ++ ++ ++;;============================================================================ ++;; call ++;; ++ ++(define_expand "call" ++ [(call (match_operand:HI 0 "general_operand" "") ++ (match_operand:HI 1 "general_operand" ""))] ++ "" ++ "") ++ ++(define_insn "*call_insn" ++ [(call (mem:HI (match_operand:HI 0 "general_operand" "r,P,mi")) ++ (match_operand:HI 1 "general_operand" "X,X,X"))] ++"" ++"call\\t%0" ++[ (set_attr "length" "1,1,2") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_expand "call_value" ++ [(set (match_operand 0 "register_operand" "") ++ (call (match_operand:HI 1 "general_operand" "") ++ (match_operand:HI 2 "general_operand" "")))] ++ "" ++ "") ++ ++(define_insn "*call_value_insn" ++ [( set (match_operand 0 "register_operand" "=r,r,r") ++ (call (mem:HI (match_operand:HI 1 "general_operand" "r,P,mi")) ++ (match_operand:HI 2 "general_operand" "X,X,X")))] ++"" ++ "call\\t%N1" ++[ (set_attr "length" "1,1,2") ++ (set_attr "cc" "clobber")]) ++ ++ ++ ++ ++ ++;;======================================================================== ++;;======================================================================== ++;; mult helpers ++ ++(define_insn "reent_in" ++ [(set (mem:HI (post_dec (reg:HI 1))) ++ (unspec_volatile:HI [(const_int 99999999)] 10))] ++ "" ++ "push\\tr2 ++\\tdint ++\\tnop" ++ [(set_attr "length" "4") ++ (set_attr "cc" "clobber")]) ++ ++;; ++;; Next three help to make sure, that ++;; all instructions are 'in order' ++ ++(define_insn "fetch_result_qi" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") ++ (unspec_volatile:QI [(const_int 0)] 12)) ++ (set (mem:HI (post_inc (reg:HI 1))) ++ (unspec_volatile:HI [(const_int 99999999)] 11))] ++ "" ++ "mov.b\\t&__RESLO, %0 ++\\tpop\\tr2" ++ [(set_attr "length" "3,4") ++ (set_attr "cc" "none")]) ++ ++(define_insn "fetch_result_hi" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") ++ (unspec_volatile:HI [(const_int 0)] 13)) ++ (set (mem:HI (post_inc (reg:HI 1))) ++ (unspec_volatile:HI [(const_int 99999999)] 11))] ++ "" ++ "mov\\t&__RESLO, %0 ++\\tpop\\tr2" ++ [(set_attr "length" "3,4") ++ (set_attr "cc" "none")]) ++ ++(define_insn "fetch_result_si" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,m") ++ (unspec_volatile:SI [(const_int 0)] 14)) ++ (set (mem:HI (post_inc (reg:HI 1))) ++ (unspec_volatile:HI [(const_int 99999999)] 11))] ++ "" ++ "mov\\t&__RESLO, %A0 ++\\tmov\\t&__RESHI, %B0 ++\\tpop\\tr2" ++ [(set_attr "length" "5,7") ++ (set_attr "cc" "none")]) ++ ++;; ===the same with no int ++ ++(define_insn "fetch_result_qi_nint" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") ++ (unspec_volatile:QI [(const_int 0)] 121))] ++ "" ++ "mov.b\\t&__RESLO, %0" ++ [(set_attr "length" "2,3") ++ (set_attr "cc" "none")]) ++ ++(define_insn "fetch_result_hi_nint" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") ++ (unspec_volatile:HI [(const_int 0)] 131))] ++ "" ++ "mov\\t&__RESLO, %0" ++ [(set_attr "length" "2,3") ++ (set_attr "cc" "none")]) ++ ++(define_insn "fetch_result_si_nint" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,m") ++ (unspec_volatile:SI [(const_int 0)] 141))] ++ "" ++ "mov\\t&__RESLO, %A0 ++\\tmov\\t&__RESHI, %B0" ++ [(set_attr "length" "4,6") ++ (set_attr "cc" "none")]) ++ ++(define_insn "addc_zero" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") ++ (unspec_volatile:HI [(const_int 0 )] 15))] ++ "" ++ "addc\\t#0, %0" ++[(set_attr "length" "1,2") ++ (set_attr "cc" "none")]) ++ ++(define_insn "subc_zero" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") ++ (unspec:HI [(const_int 0 )] 16))] ++ "" ++ "subc\\t#0, %0" ++[(set_attr "length" "1,2") ++ (set_attr "cc" "none")]) ++ ++(define_insn "load_mpy" ++ [(unspec_volatile:HI [(const_int 0)] 17) ++ (use (match_operand:HI 0 "general_operand_msp430" "rRP,mi"))] ++"" ++"mov\\t%0, &__MPY" ++[(set_attr "length" "2,3") ++ (set_attr "cc" "none")]) ++ ++ ++(define_insn "load_mpys" ++ [(unspec_volatile:HI [(const_int 0)] 18) ++ (use (match_operand:HI 0 "general_operand_msp430" "rRP,mi"))] ++"" ++"mov\\t%0, &__MPYS" ++[(set_attr "length" "2,3") ++ (set_attr "cc" "none")]) ++ ++ ++(define_insn "load_op2" ++ [(unspec_volatile:HI [(const_int 0)] 19) ++ (use (match_operand:HI 0 "general_operand_msp430" "rRP,mi"))] ++"" ++"mov\\t%0, &__OP2" ++[(set_attr "length" "2,3") ++ (set_attr "cc" "none")]) ++ ++ ++(define_insn "load_mpyq" ++ [(unspec_volatile:QI [(const_int 0 )] 20) ++ (use (match_operand:QI 0 "general_operand_msp430" "rRP,mi"))] ++"" ++"mov.b\\t%0, &__MPY" ++[(set_attr "length" "2,3") ++ (set_attr "cc" "none")]) ++ ++ ++(define_insn "load_mpysq" ++ [(unspec_volatile:QI [(const_int 0 )] 21) ++ (use (match_operand:QI 0 "general_operand_msp430" "rRP,mi"))] ++"" ++"mov.b\\t%0, &__MPYS" ++[(set_attr "length" "2,3") ++ (set_attr "cc" "none")]) ++ ++(define_insn "load_op2q" ++ [(unspec_volatile:QI [(const_int 0 )] 22) ++ (use (match_operand:QI 0 "general_operand_msp430" "rRP,mi"))] ++"" ++"mov.b\\t%0, &__OP2" ++[(set_attr "length" "2,3") ++ (set_attr "cc" "none")]) ++ ++ ++ ++ ++ ++ ++;;======================================================================== ++;;======================================================================== ++;;======================================================================== ++;; ++;; Multiplication ++ ++;;======================================================================== ++;; 8 = 8x8 and 16 = 8x8 ++ ++(define_expand "mulqi3" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") ++ (mult:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") ++ (match_operand:QI 2 "general_operand_msp430" "")))] ++ "" ++"{ msp430_mul3_guard(operands,0); DONE; }") ++ ++(define_insn "*mulqi3_call" ++ [(set (reg:QI 14) (mult:QI (reg:QI 10) (reg:QI 12))) ++ (clobber (reg:QI 10)) ++ (clobber (reg:QI 12))] ++ "!MSP430_HAS_HWMUL_INTERNAL" ++ "call #__mulqi3" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++;; ============= qi -> hi ======================================================= ++(define_expand "mulqihi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") ++ (mult:HI (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand_msp430" "")) ++ (sign_extend:HI (match_operand:QI 2 "general_operand_msp430" ""))))] ++"" ++"{ msp430_mul3_guard(operands,1); DONE; }") ++ ++(define_insn "*mulqihi3_call" ++ [(set (reg:HI 14) (mult:HI (sign_extend:HI (reg:QI 10)) ++ (sign_extend:HI (reg:QI 12)))) ++ (clobber (reg:QI 10)) ++ (clobber (reg:QI 12))] ++ "!MSP430_HAS_HWMUL_INTERNAL" ++ "call #__mulqihi3" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++;; ============ unsigned ones =================================================== ++(define_expand "umulqihi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") ++ (mult:HI (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand_msp430" "")) ++ (zero_extend:HI (match_operand:QI 2 "general_operand_msp430" ""))))] ++ "" ++ "{ msp430_umul3_guard(operands,0); DONE; }") ++ ++(define_insn "*umulqihi3_call" ++ [(set (reg:HI 14) (mult:HI (zero_extend:HI (reg:QI 10)) ++ (zero_extend:HI (reg:QI 12)))) ++ (clobber (reg:QI 10)) ++ (clobber (reg:QI 12))] ++ "!MSP430_HAS_HWMUL_INTERNAL" ++ "call #__umulqihi3" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++;;======================================================================== ++;; 16 = 16x16 and 32 = 16x16 ++ ++(define_expand "mulhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") ++ (mult:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "") ++ (match_operand:HI 2 "general_operand_msp430" "")))] ++ "" ++"{msp430_mul3_guard(operands,0); DONE; } ") ++ ++(define_insn "*mulhi3_call" ++ [(set (reg:HI 14) (mult:HI (reg:HI 10) (reg:HI 12))) ++ (clobber (reg:HI 10)) ++ (clobber (reg:HI 12))] ++ "!MSP430_HAS_HWMUL_INTERNAL" ++ "call #__mulhi3" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++;; ========================== hi -> si ============================= ++(define_expand "mulhisi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "") ++ (mult:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand_msp430" "")) ++ (sign_extend:SI (match_operand:HI 2 "general_operand_msp430" ""))))] ++"" ++ "{msp430_mulhisi_guard(operands); DONE;}" ++) ++ ++(define_insn "*mulhisi3_call" ++ [(set (reg:SI 14) (mult:SI (sign_extend:SI (reg:HI 10)) ++ (sign_extend:SI (reg:HI 12)))) ++ (clobber (reg:HI 10)) ++ (clobber (reg:HI 11)) ++ (clobber (reg:HI 12)) ++ (clobber (reg:HI 13))] ++ "!MSP430_HAS_HWMUL_INTERNAL" ++ "mov #0, r11 ++ tst r10 ++ jge +2 ++ mov #-1, r11 ++ mov #0, r13 ++ tst r12 ++ jge +2 ++ mov #-1, r13 ++ call #__mulhisi3" ++ [(set_attr "length" "10") ++ (set_attr "cc" "clobber")]) ++ ++;; ================== unsigned hi -> si ============================= ++(define_expand "umulhisi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "") ++ (mult:SI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand_msp430" "")) ++ (zero_extend:SI (match_operand:HI 2 "general_operand_msp430" ""))))] ++ "" ++ "{msp430_umulhisi_guard(operands); DONE;}") ++ ++(define_insn "*umulhisi3_call" ++ [(set (reg:SI 14) (mult:SI (zero_extend:SI (reg:HI 10)) ++ (zero_extend:SI (reg:HI 12)))) ++ (clobber (reg:HI 10)) ++ (clobber (reg:HI 11)) ++ (clobber (reg:HI 12)) ++ (clobber (reg:HI 13))] ++ "!MSP430_HAS_HWMUL_INTERNAL" ++ "clr r11 ++ clr r13 ++ call #__umulhisi3" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++ ++;;======================================================================== ++;; 32 = 32x32. 64 = 32x32 <- via library calls only ++ ++(define_expand "mulsi3" ++ [(set (reg:SI 10) (match_operand:SI 1 "nonimmediate_operand_msp430" "")) ++ (set (reg:SI 12) (match_operand:SI 2 "general_operand_msp430" "")) ++ (set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12))) ++ (set (match_operand:SI 0 "nonimmediate_operand_msp430" "") (reg:SI 14))] ++"" ++"{ ++ if (!MSP430_HAS_HWMUL_INTERNAL) ++ { ++ emit_insn (gen_mulsi3_call (operands[0], operands[1], operands[2])); ++ DONE; ++ } ++}") ++ ++(define_insn "*mulsi3hw_call_ni" ++ [(set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12)))] ++ "(!TARGET_INLINESIHWMUL) && MSP430_NOINT_HWMUL" ++ "call #__umulsi3hw" ++[(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*mulsi3hw_call_ie" ++ [(set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12)))] ++ "(!TARGET_INLINESIHWMUL) && !MSP430_NOINT_HWMUL" ++ "push r2 ++ dint ++ call #__umulsi3hw ++ pop r2" ++[(set_attr "length" "5") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*mulsi3hw_inline_ni" ++ [(set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12)))] ++ "TARGET_INLINESIHWMUL && MSP430_HAS_HWMUL_INTERNAL && MSP430_NOINT_HWMUL" ++ "mov r12, &__MPY ++ mov r10, &__OP2 ++ mov r12, &__MAC ++ mov &__RESLO, r14 ++ mov &__RESHI, &__RESLO ++ mov r11, &__OP2 ++ mov r13, &__MAC ++ mov r10, &__OP2 ++ mov &__RESLO, r15" ++[(set_attr "length" "19") ++ (set_attr "cc" "none")]) ++ ++(define_insn "*mulsi3hw_inline_ie" ++ [(set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12)))] ++ "TARGET_INLINESIHWMUL && MSP430_HAS_HWMUL_INTERNAL && !MSP430_NOINT_HWMUL" ++ "push r2 ++ dint ++ nop ++ mov r12, &__MPY ++ mov r10, &__OP2 ++ mov r12, &__MAC ++ mov &__RESLO, r14 ++ mov &__RESHI, &__RESLO ++ mov r11, &__OP2 ++ mov r13, &__MAC ++ mov r10, &__OP2 ++ mov &__RESLO, r15 ++ pop r2" ++[(set_attr "length" "23") ++ (set_attr "cc" "none")]) ++ ++(define_expand "mulsi3_call" ++ [(set (reg:SI 10) (match_operand:SI 1 "register_operand" "")) ++ (set (reg:SI 12) (match_operand:SI 2 "register_operand" "")) ++ (parallel [(set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12))) ++ (clobber (reg:SI 10)) ++ (clobber (reg:SI 12))]) ++ (set (match_operand:SI 0 "register_operand" "") (reg:SI 14))] ++"!MSP430_HAS_HWMUL_INTERNAL" ++"") ++ ++(define_insn "*mulsi3_call" ++ [(set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12))) ++ (clobber (reg:SI 10)) ++ (clobber (reg:SI 12))] ++ "!MSP430_HAS_HWMUL_INTERNAL" ++ "call #__mulsi3" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++ ++;; / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / ++;; / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / ++;; / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / ++;; / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / ++ ++(define_expand "divmodqi4" ++ [(set (reg:QI 12) (match_operand:QI 1 "register_operand" "")) ++ (set (reg:QI 10) (match_operand:QI 2 "register_operand" "")) ++ (parallel [(set (reg:QI 12) (div:QI (reg:QI 12) (reg:QI 10))) ++ (set (reg:QI 14) (mod:QI (reg:QI 12) (reg:QI 10))) ++ (clobber (reg:QI 10)) ++ (clobber (reg:QI 11)) ++ (clobber (reg:QI 13))]) ++ (set (match_operand:QI 0 "register_operand" "") (reg:QI 12)) ++ (set (match_operand:QI 3 "register_operand" "") (reg:QI 14))] ++ "" ++ "") ++ ++(define_insn "*divmodqi4_call" ++ [(set (reg:QI 12) (div:QI (reg:QI 12) (reg:QI 10))) ++ (set (reg:QI 14) (mod:QI (reg:QI 12) (reg:QI 10))) ++ (clobber (reg:QI 10)) ++ (clobber (reg:QI 11)) ++ (clobber (reg:QI 13))] ++ "" ++ "call #__divmodqi4" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++(define_expand "udivmodqi4" ++ [(set (reg:QI 12) (match_operand:QI 1 "register_operand" "")) ++ (set (reg:QI 10) (match_operand:QI 2 "register_operand" "")) ++ (parallel [(set (reg:QI 12) (udiv:QI (reg:QI 12) (reg:QI 10))) ++ (set (reg:QI 14) (umod:QI (reg:QI 12) (reg:QI 10))) ++ (clobber (reg:QI 10)) ++ (clobber (reg:QI 11)) ++ (clobber (reg:QI 13))]) ++ (set (match_operand:QI 0 "register_operand" "") (reg:QI 12)) ++ (set (match_operand:QI 3 "register_operand" "") (reg:QI 14))] ++ "" ++ "") ++ ++(define_insn "*udivmodqi4_call" ++ [(set (reg:QI 12) (udiv:QI (reg:QI 12) (reg:QI 10))) ++ (set (reg:QI 14) (umod:QI (reg:QI 12) (reg:QI 10))) ++ (clobber (reg:QI 10)) ++ (clobber (reg:QI 11)) ++ (clobber (reg:QI 13))] ++ "" ++ "call #__udivmodqi4" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_expand "divmodhi4" ++ [(set (reg:HI 12) (match_operand:HI 1 "register_operand" "")) ++ (set (reg:HI 10) (match_operand:HI 2 "register_operand" "")) ++ (parallel [(set (reg:HI 12) (div:HI (reg:HI 12) (reg:HI 10))) ++ (set (reg:HI 14) (mod:HI (reg:HI 12) (reg:HI 10))) ++ (clobber (reg:HI 10)) ++ (clobber (reg:HI 11)) ++ (clobber (reg:HI 13))]) ++ (set (match_operand:HI 0 "register_operand" "") (reg:HI 12)) ++ (set (match_operand:HI 3 "register_operand" "") (reg:HI 14))] ++ "" ++ "") ++ ++(define_insn "*divmodhi4_call" ++ [(set (reg:HI 12) (div:HI (reg:HI 12) (reg:HI 10))) ++ (set (reg:HI 14) (mod:HI (reg:HI 12) (reg:HI 10))) ++ (clobber (reg:HI 10)) ++ (clobber (reg:HI 11)) ++ (clobber (reg:HI 13))] ++ "" ++ "call #__divmodhi4" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++(define_expand "udivmodhi4" ++ [(set (reg:HI 12) (match_operand:HI 1 "register_operand" "")) ++ (set (reg:HI 10) (match_operand:HI 2 "register_operand" "")) ++ (parallel [(set (reg:HI 12) (udiv:HI (reg:HI 12) (reg:HI 10))) ++ (set (reg:HI 14) (umod:HI (reg:HI 12) (reg:HI 10))) ++ (clobber (reg:HI 10)) ++ (clobber (reg:HI 11)) ++ (clobber (reg:HI 13))]) ++ (set (match_operand:HI 0 "register_operand" "") (reg:HI 12)) ++ (set (match_operand:HI 3 "register_operand" "") (reg:HI 14))] ++ "" ++ "") ++ ++(define_insn "*udivmodhi4_call" ++ [(set (reg:HI 12) (udiv:HI (reg:HI 12) (reg:HI 10))) ++ (set (reg:HI 14) (umod:HI (reg:HI 12) (reg:HI 10))) ++ (clobber (reg:HI 10)) ++ (clobber (reg:HI 11)) ++ (clobber (reg:HI 13))] ++ "" ++ "call #__udivmodhi4" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++ ++;; ///////////////// SINGLE INTEGER %%%%%%%%%%%%%%%%% ++ ++(define_expand "divmodsi4" ++ [(set (reg:SI 12) (match_operand:SI 1 "register_operand" "")) ++ (set (reg:SI 10) (match_operand:SI 2 "register_operand" "")) ++ (parallel [(set (reg:SI 12) (div:SI (reg:SI 12) (reg:SI 10))) ++ (set (reg:SI 14) (mod:SI (reg:SI 12) (reg:SI 10))) ++ (clobber (reg:SI 10)) ++ (clobber (reg:HI 9)) ++ (clobber (reg:HI 8))]) ++ (set (match_operand:SI 0 "register_operand" "") (reg:SI 12)) ++ (set (match_operand:SI 3 "register_operand" "") (reg:SI 14))] ++ "" ++ "") ++ ++(define_insn "*divmodsi4_call" ++ [(set (reg:SI 12) (div:SI (reg:SI 12) (reg:SI 10))) ++ (set (reg:SI 14) (mod:SI (reg:SI 12) (reg:SI 10))) ++ (clobber (reg:SI 10)) ++ (clobber (reg:HI 9)) ++ (clobber (reg:HI 8))] ++ "" ++ "call #__divmodsi4" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++(define_expand "udivmodsi4" ++ [(set (reg:SI 12) (match_operand:SI 1 "register_operand" "")) ++ (set (reg:SI 10) (match_operand:SI 2 "register_operand" "")) ++ (parallel [(set (reg:SI 12) (udiv:SI (reg:SI 12) (reg:SI 10))) ++ (set (reg:SI 14) (umod:SI (reg:SI 12) (reg:SI 10))) ++ (clobber (reg:SI 10)) ++ (clobber (reg:HI 9)) ++ (clobber (reg:HI 8))]) ++ (set (match_operand:SI 0 "register_operand" "") (reg:SI 12)) ++ (set (match_operand:SI 3 "register_operand" "") (reg:SI 14))] ++ "" ++ "") ++ ++(define_insn "*udivmodsi4_call" ++ [(set (reg:SI 12) (udiv:SI (reg:SI 12) (reg:SI 10))) ++ (set (reg:SI 14) (umod:SI (reg:SI 12) (reg:SI 10))) ++ (clobber (reg:SI 10)) ++ (clobber (reg:HI 9)) ++ (clobber (reg:HI 8))] ++ "" ++ "call #__udivmodsi4" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++ ++ ++ ++;;======================================================================== ++;; MOV STRING ++;; structures and stuff are word aligned. ++;; so, QI mode only defined (as HI actually) ++;; ++ ++(define_expand "movstrhi" ++ [(parallel [(set (match_operand:BLK 0 "memory_operand" "") ++ (match_operand:BLK 1 "memory_operand" "")) ++ (use (match_operand 2 "const_int_operand" "")) ++ (use (match_operand 3 "const_int_operand" "")) ++ (clobber (match_dup 4)) ++ (clobber (match_dup 5)) ++ (clobber (match_dup 6))])] ++ "" ++ " ++{ ++ rtx addr0, addr1; ++ rtx a0, a1; ++ ++ if (GET_CODE (operands[2]) != CONST_INT) FAIL; ++ ++ addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); ++ addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); ++ ++ a0 = operands[0]; ++ a1 = operands[1]; ++ ++ operands[5] = addr0; ++ operands[6] = addr1; ++ ++ operands[0] = gen_rtx (MEM, BLKmode, addr0); ++ operands[1] = gen_rtx (MEM, BLKmode, addr1); ++ ++ if(INTVAL (operands[2]) <= 10 && !(INTVAL(operands[3])&1)) ++ { ++ int x = INTVAL (operands[2]); ++ int y = (x&~1) >> 1; ++ int i = 0; ++ ++ while(y--) ++ { ++ rtx dest = gen_rtx (MEM, HImode, gen_rtx_PLUS(HImode, addr0,GEN_INT(i))); ++ emit_insn(gen_movstrhi5(dest,addr1)); ++ i+= 2; ++ } ++ ++ if(x & 1) ++ { ++ rtx real_dst = gen_rtx (MEM, HImode, gen_rtx_PLUS(HImode, addr0,GEN_INT(x-1))); ++ emit_insn(gen_movstrqi5(real_dst,addr1)); ++ } ++ DONE; ++ } ++ else if(INTVAL (operands[2]) <= 6 && (INTVAL(operands[3])&1)) ++ { ++ int x = INTVAL (operands[2]); ++ int i = 0; ++ ++ while(x--) ++ { ++ rtx dst = gen_rtx (MEM, HImode, gen_rtx_PLUS(HImode, addr0,GEN_INT(i))); ++ emit_insn(gen_movstrqi5(dst,addr1)); ++ i++; ++ } ++ DONE; ++ } ++ else ++ { ++ operands[2] = copy_to_mode_reg (HImode, operands[2]); ++ operands[4] = operands[2]; ++ } ++} ++") ++ ++(define_insn "movstrqi5" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m") ++ (mem:HI (match_operand:HI 1 "register_operand" "+r"))) ++ (set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))] ++ "" ++ "mov.b @%1+, %0" ++[(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "movstrhi5" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m") ++ (mem:HI (match_operand:HI 1 "register_operand" "+r"))) ++ (set (match_dup 1) (plus:HI (match_dup 1) (const_int 2)))] ++ "" ++ "mov @%1+, %0" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*movstrhi_insn" ++ [(set (mem:BLK (match_operand:HI 0 "register_operand" "r")) ++ (mem:BLK (match_operand:HI 1 "register_operand" "r"))) ++ (use (match_operand:HI 2 "register_operand" "r")) ++ (use (match_operand 3 "const_int_operand" "i")) ++ (clobber (match_dup 2)) ++ (clobber (match_dup 0)) ++ (clobber (match_dup 1))] ++ "" ++ "* return movstrhi_insn(insn, operands, NULL);" ++ [(set_attr "length" "6") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_insn "*movstrqi_insn" ++ [(set (mem:BLK (match_operand:HI 0 "register_operand" "r")) ++ (mem:BLK (match_operand:HI 1 "register_operand" "r"))) ++ (use (match_operand:QI 2 "register_operand" "r")) ++ (use (match_operand 3 "const_int_operand" "i")) ++ (clobber (match_dup 2)) ++ (clobber (match_dup 0)) ++ (clobber (match_dup 1))] ++ "" ++ "* return movstrhi_insn(insn, operands, NULL);" ++ [(set_attr "length" "6") ++ (set_attr "cc" "clobber")]) ++ ++ ++ ++;;======================================================================== ++;; CLEAR STRING ++ ++(define_expand "clrstrhi" ++ [(parallel [(set (match_operand:BLK 0 "memory_operand" "") ++ (const_int 0)) ++ (use (match_operand 1 "const_int_operand" "")) ++ (use (match_operand 2 "const_int_operand" "i")) ++ (clobber (match_dup 3)) ++ (clobber (match_dup 4))])] ++ "" ++ " ++{ ++ rtx addr0; ++ ++ if (GET_CODE (operands[1]) != CONST_INT) FAIL; ++ operands[1] = copy_to_mode_reg (HImode, operands[1]); ++ operands[3] = operands[1]; ++ addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); ++ operands[4] = addr0; ++ operands[0] = gen_rtx (MEM, BLKmode, addr0); ++}") ++ ++ ++(define_insn "*clrstrhi_insn" ++ [(set (mem:BLK (match_operand:HI 0 "register_operand" "r")) ++ (const_int 0)) ++ (use (match_operand:HI 1 "register_operand" "r")) ++ (use (match_operand 2 "const_int_operand" "i")) ++ (clobber (match_dup 1)) ++ (clobber (match_dup 0))] ++ "" ++ "* return clrstrhi_insn(insn, operands, NULL);" ++[(set_attr "length" "6") ++ (set_attr "cc" "clobber")]) ++ ++ ++;;======================================================================== ++;; %0 = strchr(%1,%2) - %1 ++ ++(define_expand "strlenhi" ++ [(set (match_dup 4) ++ (unspec:HI [(match_operand:BLK 1 "memory_operand" "") ++ (match_operand 2 "const_int_operand" "") ++ (match_operand:HI 3 "immediate_operand" "")] 3)) ++ (set (match_operand:HI 0 "register_operand" "") ++ (minus:HI (match_dup 4) ++ (match_dup 5)))] ++ ++ "" ++ " ++{ ++ rtx addr; ++ ++ if (! (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0)) ++ FAIL; ++ addr = copy_to_mode_reg (Pmode, XEXP (operands[1],0)); ++ operands[1] = gen_rtx (MEM, BLKmode, addr); ++ operands[5] = addr; ++ operands[4] = gen_reg_rtx (HImode); ++ ++}") ++ ++ ++(define_insn "*strlenhi" ++ [(set (match_operand:HI 0 "register_operand" "=r") ++ (unspec:HI [(mem:BLK (match_operand:HI 1 "register_operand" "0")) ++ (const_int 0) ++ (match_operand:HI 2 "immediate_operand" "i") ] 3))] ++ "" ++"dec %0 ++.L__strlenhi__%=: ++ inc %0 ++ tst.b 0(%0) ++ jne .L__strlenhi__%=" ++[(set_attr "length" "5") ++ (set_attr "cc" "clobber")]) ++ ++ ++;;======================================================================== ++;; MOV code ++;; ++;; ++ ++ ++;;======================================================================== ++;; move byte ++;; nothing much special ++;; all addressing modes allowed ++;; fits perfectly into a single instruction ++ ++(define_expand "movqi" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") ++ (match_operand:QI 1 "general_operand" ""))] ++ "" ++ "") ++ ++(define_insn "*movqi3" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=m,m,m,m,r,r,r,r") ++ (match_operand:QI 1 "general_operand_msp430" " m,r,P,i,m,r,P,i"))] ++ "" ++ "mov.b\\t%1, %0" ++ [(set_attr "length" "3,2,3,3,2,1,2,2") ++ (set_attr "cc" "none,none,none,none,none,none,none,none")]) ++ ++ ++(define_insn "movqipi" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") ++ (mem:QI (post_inc:QI (match_operand:HI 1 "register_operand" "r,r"))))] ++ "" ++ "mov.b @%1+, %0" ++[(set_attr "length" "1,2") ++ (set_attr "cc" "none,none")]) ++ ++ ++ ++;;============================================================================ ++;; move word (16 bit) ++;; the same as above ++ ++(define_expand "movhi" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") ++ (match_operand:HI 1 "general_operand_msp430" ""))] ++ "" ++ "") ++ ++(define_insn "*movhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m,m,m,m,r,r,r,r") ++ (match_operand:HI 1 "general_operand_msp430" " r,m,P,i,r,m,P,i"))] ++ "" ++ "mov\\t%1, %0 " ++ [(set_attr "length" "2,3,3,3,1,2,2,2") ++ (set_attr "cc" "none")]) ++ ++(define_insn "movhipi" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") ++ (mem:HI (post_inc:HI (match_operand:HI 1 "register_operand" "r,r"))))] ++ "" ++ "mov @%1+, %0" ++[(set_attr "length" "1,2") ++ (set_attr "cc" "none,none")]) ++ ++;;============================================================================ ++;; move long (32 bit) ++;; the same as above ++ ++(define_expand "movsi" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (match_operand:SI 1 "general_operand" ""))] ++ "" ++ "") ++ ++(define_insn "*movsi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") ++ (match_operand:SI 1 "general_operand" " rmi"))] ++"" ++"* return msp430_movesi_code(insn,operands,NULL);" ++ [(set_attr "length" "6") ++ (set_attr "cc" "none")]) ++ ++(define_insn "movsipi" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,m") ++ (mem:SI (post_inc (match_operand:HI 1 "register_operand" "r,r"))))] ++ "" ++ "mov @%1+, %A0 ++ mov @%1+, %B0" ++[(set_attr "length" "2,4") ++ (set_attr "cc" "none,none")]) ++ ++ ++ ++;;============================================================================ ++;; floats are the SI ++ ++(define_expand "movsf" ++ [(set (match_operand:SF 0 "nonimmediate_operand" "") ++ (match_operand:SF 1 "general_operand" ""))] ++ "" ++ "") ++ ++(define_insn "*movsf3" ++ [(set (match_operand:SF 0 "nonimmediate_operand" "=rm") ++ (match_operand:SF 1 "general_operand" "rmi"))] ++"" ++"* return msp430_movesi_code(insn,operands,NULL);" ++ [(set_attr "length" "6") ++ (set_attr "cc" "none")]) ++ ++ ++(define_insn "movsfpi" ++ [(set (match_operand:SF 0 "nonimmediate_operand_msp430" "=r,m") ++ (mem:SF (post_inc (match_operand:HI 1 "register_operand" "r,r"))))] ++ "" ++ "mov @%1+, %A0 ++ mov @%1+, %B0" ++[(set_attr "length" "2,4") ++ (set_attr "cc" "none,none")]) ++ ++;;============================================================================ ++;; move long long (64 bit) ++;; the same as above ++(define_expand "movdi" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "") ++ (match_operand:DI 1 "general_operand" ""))] ++ "" ++ "") ++ ++(define_insn "*movdi3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") ++ (match_operand:DI 1 "general_operand" "rmi"))] ++"" ++"* return msp430_movedi_code(insn,operands,NULL);" ++ [(set_attr "length" "12") ++ (set_attr "cc" "none")]) ++ ++ ++(define_insn "movdipi" ++ [(set (match_operand:DI 0 "nonimmediate_operand_msp430" "=r,m") ++ (mem:DI (post_inc (match_operand:HI 1 "register_operand" "r,r"))))] ++ "" ++ "mov @%1+, %A0 ++ mov @%1+, %B0 ++ mov @%1+, %C0 ++ mov @%1+, %D0" ++[(set_attr "length" "4,8") ++ (set_attr "cc" "none,none")]) ++ ++ ++;;============================================================================ ++;; ARITHMETIC CODE ++;; ++ ++ ++;; random operations: ++ ++(define_insn "*opqi3_pi" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") ++ (match_operator:QI 3 "three_operands_msp430" ++ [(match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0") ++ (mem:QI (post_inc (match_operand:HI 2 "register_operand" "r,r")))]))] ++"" ++"%3.b @%2+, %0" ++ [(set_attr "length" "1,2") ++ (set_attr "cc" "oper,oper")]) ++ ++(define_insn "*ophi3_pi" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") ++ (match_operator:HI 3 "three_operands_msp430" ++ [(match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0") ++ (mem:HI (post_inc (match_operand:HI 2 "register_operand" "r,r")))]))] ++"" ++"%3 @%2+, %0" ++ [(set_attr "length" "1,2") ++ (set_attr "cc" "oper,oper")]) ++ ++(define_insn "*opsi3_pi" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,m") ++ (match_operator:SI 3 "three_operands_msp430" ++ [(match_operand:SI 1 "nonimmediate_operand_msp430" "%0,0") ++ (mem:SI (post_inc (match_operand:HI 2 "register_operand" "r,r")))]))] ++"" ++"%A3\\t@%2+, %A0 ++\\t%B3\\t@%2+, %B0" ++ [(set_attr "length" "1,2") ++ (set_attr "cc" "oper,oper")]) ++ ++(define_insn "*opdi3_pi" ++ [(set (match_operand:DI 0 "nonimmediate_operand_msp430" "=r,m") ++ (match_operator:DI 3 "three_operands_msp430" ++ [(match_operand:DI 1 "nonimmediate_operand_msp430" "%0,0") ++ (mem:DI (post_inc (match_operand:HI 2 "register_operand" "r,r")))]))] ++"" ++"%A3\\t@%2+, %A0 ++\\t%B3\\t@%2+, %B0 ++\\t%C3\\t@%2+, %C0 ++\\t%D3\\t@%2+, %D0" ++ [(set_attr "length" "1,2") ++ (set_attr "cc" "oper,oper")]) ++ ++ ++ ++ ++;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++;; add 1 byte ++ ++ ++(define_expand "addqi3" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") ++ (plus:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") ++ (match_operand:QI 2 "general_operand_msp430" "")))] ++ "" ++ "") ++ ++(define_insn "*addqi3_cg" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=m,r") ++ (plus:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0") ++ (match_operand 2 "const_int_operand" "i,i")))] ++"(INTVAL(operands[2]) == -2 ++ || INTVAL(operands[2]) == -4 ++ || INTVAL(operands[2]) == -8 )" ++"* { ++ operands[2] = gen_rtx_CONST_INT(QImode, -INTVAL(operands[2])); ++ return \"sub.b\\t%2, %0\"; ++}" ++[(set_attr "length" "2,1") ++ (set_attr "cc" "set_czn,set_czn")]) ++ ++ ++(define_insn "*addqi3_3" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=m,m,m,m,r,r,r,r") ++ (plus:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") ++ (match_operand:QI 2 "general_operand_msp430" " m,r,P,i,m,r,P,i")))] ++"" ++ "add.b %2, %0" ++ [(set_attr "length" "3,2,2,3,2,1,1,2") ++ (set_attr "cc" "set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) ++ ++ ++;;============================================================================ ++;; add 1 word (16 bits) ++;; same as above ++ ++ ++(define_expand "addhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") ++ (plus:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "") ++ (match_operand:HI 2 "general_operand_msp430" "")))] ++ "" ++ "") ++ ++(define_insn "*addhi3_cg" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m,r") ++ (plus:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0") ++ (match_operand 2 "const_int_operand" "i,i")))] ++"(INTVAL(operands[2]) == -2 ++ || INTVAL(operands[2]) == -4 ++ || INTVAL(operands[2]) == -8 )" ++"* { ++ operands[2] = gen_rtx_CONST_INT(HImode, -INTVAL(operands[2])); ++ return \"sub\\t%2, %0\" ; ++}" ++[(set_attr "length" "2,1") ++ (set_attr "cc" "set_czn,set_czn")]) ++ ++(define_insn "*addhi3_3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m,m,m,m,r,r,r,r") ++ (plus:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") ++ (match_operand:HI 2 "general_operand_msp430" " m,r,P,i,m,r,P,i")))] ++"" ++ "add %2, %0" ++ [(set_attr "length" "3,2,2,3,2,1,1,2") ++ (set_attr "cc" ++"set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) ++ ++ ++;;============================================================================ ++;; add 2 words (32 bits) ++;; same as above ++ ++(define_expand "addsi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "") ++ (plus:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "") ++ (match_operand:SI 2 "general_operand_msp430" "")))] ++ "" ++ "") ++ ++(define_insn "*addsi3_cg" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=m,r") ++ (plus:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "%0,0") ++ (match_operand 2 "const_int_operand" "i,i")))] ++"(INTVAL(operands[2]) == -2 ++ || INTVAL(operands[2]) == -4 ++ || INTVAL(operands[2]) == -8 )" ++"* { ++ operands[2] = gen_rtx_CONST_INT(SImode, -INTVAL(operands[2])); ++ return \"sub\\t%A2, %A0\\n\\tsubc\\t%B2, %B0\" ; ++}" ++[(set_attr "length" "4,2") ++ (set_attr "cc" "further,further")]) ++ ++ ++(define_insn "*addsi3_3" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=rm") ++ (plus:SI (match_operand:SI 1 "general_operand_msp430" "%0") ++ (match_operand:SI 2 "general_operand_msp430" " rmi")))] ++"" ++"* return msp430_addsi_code(insn, operands, NULL);" ++ [(set_attr "length" "6") ++ (set_attr "cc" "further")]) ++ ++ ++;;============================================================================ ++;; add 4 words (64 bits) ++;; same as above ++ ++(define_expand "adddi3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "") ++ (plus:DI (match_operand:DI 1 "nonimmediate_operand" "") ++ (match_operand:DI 2 "general_operand" "")))] ++ "" ++ "") ++ ++(define_insn "*adddi3_cg" ++ [(set (match_operand:DI 0 "nonimmediate_operand_msp430" "=m,r") ++ (plus:DI (match_operand:DI 1 "nonimmediate_operand_msp430" "%0,0") ++ (match_operand:DI 2 "const_int_operand" "i,i")))] ++"(INTVAL(operands[2]) == -2 ++ || INTVAL(operands[2]) == -4 ++ || INTVAL(operands[2]) == -8 )" ++"* { ++ operands[2] = gen_rtx_CONST_INT(DImode, -INTVAL(operands[2])); ++ return \"sub\\t%A2, %A0\\n\\tsubc\\t%B2, %B0\\n\\tsubc\\t%C2, %C0\\n\\tsubc\\t%D2, %D0\"; ++}" ++[(set_attr "length" "4,2") ++(set_attr "cc" "further,further")]) ++ ++(define_insn "*adddi3_3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") ++ (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0") ++ (match_operand:DI 2 "general_operand" " rmi")))] ++"" ++"* return msp430_adddi_code(insn, operands, NULL);" ++ [(set_attr "length" "12") ++ (set_attr "cc" "further")]) ++ ++ ++;;----------------------------------------------------------------------- ++;;----------------------------------------------------------------------- ++;;----------------------------------------------------------------------- ++;;----------------------------------------------------------------------- ++;;----------------------------------------------------------------------- ++;; sub 1 byte ++ ++ ++(define_expand "subqi3" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") ++ (minus:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") ++ (match_operand:QI 2 "general_operand_msp430" "")))] ++ "" ++ "") ++ ++(define_insn "*subqi3_3" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=m,m,m,m,r,r,r,r") ++ (minus:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "0,0,0,0,0,0,0,0") ++ (match_operand:QI 2 "general_operand_msp430" " m,r,P,i,m,r,P,i")))] ++"" ++ "sub.b %2, %0" ++ [(set_attr "length" "3,2,2,3,2,1,1,2") ++ (set_attr "cc" "set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) ++ ++ ++;;============================================================================ ++;; sub 1 word (16 bits) ++;; same as above ++ ++ ++(define_expand "subhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") ++ (minus:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "") ++ (match_operand:HI 2 "general_operand_msp430" "")))] ++ "" ++ "") ++ ++(define_insn "*subhi3_3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m,m,m,m,r,r,r,r") ++ (minus:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0,0,0,0,0,0,0") ++ (match_operand:HI 2 "general_operand_msp430" "m,r,P,i,m,r,P,i")))] ++"" ++ "sub %2, %0" ++ [(set_attr "length" "3,2,2,3,2,1,1,2") ++ (set_attr "cc" ++"set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) ++ ++ ++;;============================================================================ ++;; sub 2 words (32 bits) ++;; same as above ++ ++(define_expand "subsi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (minus:SI (match_operand:SI 1 "nonimmediate_operand" "") ++ (match_operand:SI 2 "general_operand" "")))] ++ "" ++ "") ++ ++ ++(define_insn "*subsi3_3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") ++ (minus:SI (match_operand:SI 1 "general_operand" "0") ++ (match_operand:SI 2 "general_operand" " rmi")))] ++"" ++"* return msp430_subsi_code(insn, operands, NULL);" ++ [(set_attr "length" "6") ++ (set_attr "cc" "further")]) ++ ++ ++;;============================================================================ ++;; sub 4 words (64 bits) ++;; same as above ++ ++(define_expand "subdi3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "") ++ (minus:DI (match_operand:DI 1 "nonimmediate_operand" "") ++ (match_operand:DI 2 "general_operand" "")))] ++ "" ++ "") ++ ++(define_insn "*subdi3_3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") ++ (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0") ++ (match_operand:DI 2 "general_operand" " rmi")))] ++"" ++"* return msp430_subdi_code(insn, operands,NULL);" ++ [(set_attr "length" "12") ++ (set_attr "cc" "set_n")]) ++ ++ ++ ++ ++ ++;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ++;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ++;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ++;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ++;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ++;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ++;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ++;; and 1 byte ++ ++ ++(define_expand "andqi3" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") ++ (and:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") ++ (match_operand:QI 2 "general_operand_msp430" "")))] ++ "" ++ "") ++ ++ ++(define_insn "*andqi3_inv" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") ++ (and:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0") ++ (match_operand:QI 2 "immediate_operand" " i,i")))] ++"(INTVAL(operands[2])==~1 ++ || INTVAL(operands[2])==~2 ++ || INTVAL(operands[2])==~4 ++ || INTVAL(operands[2])==~8)" ++"* { ++ operands[2] = gen_rtx_CONST_INT(QImode, ~(INTVAL(operands[2]))); ++ return \"bic.b %2,%0\"; ++}" ++ [(set_attr "length" "1,2") ++ (set_attr "cc" "none,none")]) ++ ++ ++(define_insn "*andqi3_3" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m,r,m,r,m,m,r") ++ (and:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") ++ (match_operand:QI 2 "general_operand_msp430" " r,m,P,P,m,r,i,i")))] ++"" ++"and.b %2, %0" ++ [(set_attr "length" "1,3,1,2,2,2,3,2") ++ (set_attr "cc" "set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) ++ ++ ++ ++ ++;;============================================================================ ++;; and 1 word (16 bits) ++;; same as above ++ ++(define_expand "andhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") ++ (and:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0") ++ (match_operand:HI 2 "general_operand_msp430" "")))] ++ "" ++ "") ++ ++ ++(define_insn "*andhi3_inv" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") ++ (and:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0") ++ (match_operand:HI 2 "immediate_operand" " i,i")))] ++"(INTVAL(operands[2])==~1 ++ || INTVAL(operands[2])==~2 ++ || INTVAL(operands[2])==~4 ++ || INTVAL(operands[2])==~8)" ++"* { ++ operands[2] = gen_rtx_CONST_INT(HImode, ~(INTVAL(operands[2]))); ++ return \"bic %2,%0\"; ++}" ++ [(set_attr "length" "1,2") ++ (set_attr "cc" "none,none")]) ++ ++(define_insn "*andhi3_clrup" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") ++ (and:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0") ++ (match_operand:HI 2 "immediate_operand" " i,i")))] ++"INTVAL(operands[2])==255" ++"* { ++ if(which_alternative == 0) ++ { ++ return \"and.b #-1, %0\"; ++ } ++ else if(which_alternative == 1) ++ { ++ return \"clr.b %J0\"; ++ } ++ ++ return \"bug\"; ++}" ++ [(set_attr "length" "1,2") ++ (set_attr "cc" "clobber,clobber")]) ++ ++(define_insn "*andhi3_clrlw" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m,r") ++ (and:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0") ++ (match_operand:HI 2 "immediate_operand" " i,i")))] ++"((0xffff&INTVAL(operands[2]))==0xff00)" ++"@ ++clr.b %I0 ++and\\t#0xff00, %0" ++ [(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_insn "*andhi3_3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m,r,m,r,m,m,r") ++ (and:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") ++ (match_operand:HI 2 "general_operand_msp430" " r,m,P,P,m,r,i,i")))] ++"" ++"and %2, %0" ++ [(set_attr "length" "1,3,1,2,2,2,3,2") ++ (set_attr "cc" "set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) ++ ++ ++ ++ ++ ++;;============================================================================ ++;; and 2 words (32 bits) ++;; same as above ++ ++(define_expand "andsi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (and:SI (match_operand:SI 1 "nonimmediate_operand" "") ++ (match_operand:SI 2 "general_operand" "")))] ++ "" ++ "") ++ ++(define_insn "*andsi3_3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") ++ (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0") ++ (match_operand:SI 2 "general_operand" " rmi")))] ++"" ++"* return msp430_andsi_code(insn, operands, NULL);" ++ [(set_attr "length" "6") ++ (set_attr "cc" "set_n")]) ++ ++ ++;;============================================================================ ++;; and 4 words (64 bits) ++;; same as above ++ ++(define_expand "anddi3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "") ++ (and:DI (match_operand:DI 1 "nonimmediate_operand" "") ++ (match_operand:DI 2 "general_operand" "")))] ++ "" ++ "") ++ ++(define_insn "*anddi3_3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") ++ (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0") ++ (match_operand:DI 2 "general_operand" " rmi")))] ++"" ++"* return msp430_anddi_code(insn, operands, NULL);" ++ [(set_attr "length" "14") ++ (set_attr "cc" "clobber")]) ++ ++ ++ ++;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ++;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ++;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ++;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ++;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ++;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ++;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ++;; ior 1 byte ++;; looks like a 'mov' insn ++ ++(define_expand "iorqi3" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") ++ (ior:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") ++ (match_operand:QI 2 "general_operand_msp430" "")))] ++ "" ++ "") ++ ++(define_insn "*iorqi3_3" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m,r,m,r,m,m,r") ++ (ior:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") ++ (match_operand:QI 2 "general_operand_msp430" " r,m,P,P,m,r,i,i")))] ++"" ++ "bis.b %2, %0" ++ [(set_attr "length" "1,3,1,2,2,2,3,2") ++ (set_attr "cc" "none,none,none,none,none,none,none,none")]) ++ ++ ++ ++;;============================================================================ ++;; ior 1 word (16 bits) ++;; same as above ++ ++(define_expand "iorhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") ++ (ior:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "") ++ (match_operand:HI 2 "general_operand_msp430" "")))] ++ "" ++ " ++ if(const_int_operand(operands[2], VOIDmode)) ++ { ++ int x = INTVAL(operands[2]) & 0xffff; ++ if(!x) DONE; ++ } ++ ") ++ ++(define_insn "*iorhi3_3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m,r,m,r,m,m,r") ++ (ior:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") ++ (match_operand:HI 2 "general_operand_msp430" " r,m,P,P,m,r,i,i")))] ++"" ++ "bis %2, %0" ++ [(set_attr "length" "1,3,1,2,2,2,3,2") ++ (set_attr "cc" "none,none,none,none,none,none,none,none")]) ++ ++ ++ ++;;============================================================================ ++;; ior 2 words (32 bits) ++;; same as above ++ ++ ++(define_expand "iorsi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (ior:SI (match_operand:SI 1 "nonimmediate_operand" "") ++ (match_operand:SI 2 "general_operand" "")))] ++ "" ++ "") ++ ++(define_insn "*iorsi3_3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") ++ (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") ++ (match_operand:SI 2 "general_operand" " rmi")))] ++"" ++"* return msp430_iorsi_code(insn, operands, NULL);" ++ [(set_attr "length" "6") ++ (set_attr "cc" "none")]) ++ ++(define_split ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (ior:SI (match_operand:SI 1 "nonimmediate_operand" "") ++ (match_operand:SI 2 "const_int_operand" "")))] ++ "reload_completed ++ && (halfnibble_integer(operands[2], VOIDmode) ++ || halfnibble_constant(operands[2], VOIDmode))" ++ [(set (match_dup 3) (ior:HI (match_dup 4) (match_dup 5)))] ++ "{ ++ int lo = trunc_int_for_mode(INTVAL(operands[2]),HImode); ++ int hi = trunc_int_for_mode(INTVAL(operands[2])>>16,HImode); ++ ++ if(lo == -1) ++ { ++ rtx op = gen_lowpart(HImode, operands[0]); ++ emit_insn(gen_rtx_SET(HImode, op, GEN_INT(-1))); ++ DONE; ++ } ++ ++ if(hi == -1) ++ { ++ rtx op = gen_highpart(HImode, operands[0]); ++ emit_insn(gen_rtx_SET(HImode, op, GEN_INT(-1))); ++ DONE; ++ } ++ ++ if(lo) ++ { ++ operands[3] = gen_lowpart(HImode, operands[0]); ++ operands[4] = gen_lowpart(HImode, operands[1]); ++ operands[5] = GEN_INT(lo); ++ } ++ else if(hi) ++ { ++ operands[3] = gen_highpart(HImode, operands[0]); ++ operands[4] = gen_highpart(HImode, operands[1]); ++ operands[5] = GEN_INT(hi); ++ } ++ }") ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") ++ (const_int 0)) ++ (set (match_dup 0) (ior:HI (match_dup 0) ++ (match_operand:HI 1 "const_int_operand" "")))] ++ "" ++ [(set (match_dup 0) (match_dup 1))] ++ "") ++ ++ ++;;============================================================================ ++;; ior 4 words (64 bits) ++;; same as above ++ ++(define_expand "iordi3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "") ++ (ior:DI (match_operand:DI 1 "nonimmediate_operand" "") ++ (match_operand:DI 2 "general_operand" "")))] ++ "" ++ "") ++ ++(define_insn "*iordi3_3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") ++ (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0") ++ (match_operand:DI 2 "general_operand" " rmi")))] ++"" ++"* return msp430_iordi_code(insn, operands, NULL);" ++ [(set_attr "length" "12") ++ (set_attr "cc" "none")]) ++ ++ ++ ++;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++;; xor 1 byte ++;; looks like a 'mov' insn ++ ++(define_expand "xorqi3" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") ++ (xor:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") ++ (match_operand:QI 2 "general_operand_msp430" "")))] ++ "" ++ "") ++ ++(define_insn "*xorqi3_3" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m,r,m,r,m,m,r") ++ (xor:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") ++ (match_operand:QI 2 "general_operand_msp430" " r,m,P,P,m,r,i,i")))] ++"" ++ "xor.b %2, %0" ++ [(set_attr "length" "1,3,1,2,2,2,3,2") ++ (set_attr "cc" "set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) ++ ++ ++ ++;;============================================================================ ++;; xor 1 word (16 bits) ++;; same as above ++ ++(define_expand "xorhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") ++ (xor:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "") ++ (match_operand:HI 2 "general_operand_msp430" "")))] ++ "" ++ "") ++ ++(define_insn "*xorhi3_3" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m,r,m,r,m,m,r") ++ (xor:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") ++ (match_operand:HI 2 "general_operand_msp430" " r,m,P,P,m,r,i,i")))] ++"" ++ "xor %2, %0" ++ [(set_attr "length" "1,3,1,2,2,2,3,2") ++ (set_attr "cc" "set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) ++ ++ ++ ++;;============================================================================ ++;; xor 2 words (32 bits) ++;; same as above ++ ++(define_expand "xorsi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (xor:SI (match_operand:SI 1 "nonimmediate_operand" "") ++ (match_operand:SI 2 "general_operand" "")))] ++ "" ++ "") ++ ++ ++(define_insn "*xorsi3_3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") ++ (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") ++ (match_operand:SI 2 "general_operand" " rmi")))] ++"" ++"* return msp430_xorsi_code(insn, operands, NULL);" ++ [(set_attr "length" "6") ++ (set_attr "cc" "set_n")]) ++ ++ ++(define_split ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (xor:SI (match_operand:SI 1 "nonimmediate_operand" "") ++ (match_operand:SI 2 "const_int_operand" "")))] ++ "reload_completed ++ && (halfnibble_integer(operands[2], VOIDmode) ++ || halfnibble_constant(operands[2], VOIDmode)) ++ && INTVAL(operands[2])" ++ [(set (match_dup 3) (xor:HI (match_dup 4) (match_dup 5)))] ++ "{ ++ int lo = trunc_int_for_mode(INTVAL(operands[2]),HImode); ++ int hi = trunc_int_for_mode(INTVAL(operands[2])>>16,HImode); ++ ++ if(lo) ++ { ++ operands[3] = gen_lowpart(HImode, operands[0]); ++ operands[4] = gen_lowpart(HImode, operands[1]); ++ operands[5] = GEN_INT(lo); ++ } ++ else if(hi) ++ { ++ operands[3] = gen_highpart(HImode, operands[0]); ++ operands[4] = gen_highpart(HImode, operands[1]); ++ operands[5] = GEN_INT(hi); ++ } ++ }") ++ ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") ++ (const_int 0)) ++ (set (match_dup 0) (xor:HI (match_dup 0) ++ (const_int -1)))] ++ "" ++ [(set (match_dup 0) (const_int -1))] ++ "") ++ ++ ++;;============================================================================ ++;; xor 4 words (64 bits) ++;; same as above ++ ++(define_expand "xordi3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "") ++ (xor:DI (match_operand:DI 1 "nonimmediate_operand" "") ++ (match_operand:DI 2 "general_operand" "")))] ++ "" ++ "") ++ ++(define_insn "*xordi3_3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") ++ (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0") ++ (match_operand:DI 2 "general_operand" " rmi")))] ++"" ++"* return msp430_xordi_code(insn, operands, NULL);" ++ [(set_attr "length" "4") ++ (set_attr "cc" "set_n")]) ++ ++ ++ ++ ++ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;; neg ++;; same as above ++ ++(define_expand "negqi2" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (neg:QI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++ "{ emit_insn(gen_one_cmplqi2(operands[0],operands[1])); ++ emit_insn(gen_addqi3(operands[0],operands[0],const1_rtx)); ++ DONE; }") ++ ++(define_expand "neghi2" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (neg:HI (match_operand:HI 1 "nonimmediate_operand" "")))] ++ "" ++ "{ emit_insn(gen_one_cmplhi2(operands[0],operands[1])); ++ emit_insn(gen_addhi3(operands[0],operands[0],const1_rtx)); ++ DONE; }") ++ ++(define_expand "negsi2" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (neg:SI (match_operand:SI 1 "nonimmediate_operand" "")))] ++ "" ++ ++ "{ emit_insn(gen_one_cmplsi2(operands[0],operands[1])); ++ emit_insn(gen_addsi3(operands[0],operands[0],const1_rtx)); ++ DONE; }") ++ ++(define_expand "negdi2" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "") ++ (neg:DI (match_operand:DI 1 "nonimmediate_operand" "")))] ++ "" ++ ++ "{ emit_insn(gen_one_cmpldi2(operands[0],operands[1])); ++ emit_insn(gen_adddi3(operands[0],operands[0],const1_rtx)); ++ DONE; }") ++ ++(define_insn "negsf2" ++ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,m") ++ (neg:SF (match_operand:SF 1 "nonimmediate_operand" "0,0")))] ++ "" ++ "xor #0x8000, %B0" ++ [(set_attr "length" "2,3") ++ (set_attr "cc" "clobber,clobber")]) ++ ++;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ++;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ++;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ++;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ++;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ++;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ++;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ++;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ++;; not x = !x ++;; ones component ++ ++(define_expand "one_cmplqi2" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") ++ (not:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "")))] ++ "" ++ "") ++ ++(define_insn "*one_cmplqi2_2" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") ++ (not:QI (match_operand:QI 1 "nonimmediate_operand_msp430" " 0, 0")))] ++ "" ++ "inv.b %0" ++ [(set_attr "length" "1,2") ++ (set_attr "cc" "set_czn,set_czn")]) ++ ++ ++;;============================================================================ ++;; not HI x = !x ++;; - ones component ++ ++(define_expand "one_cmplhi2" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") ++ (not:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0")))] ++ "" ++ "") ++ ++(define_insn "*one_cmplhi2_2" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r, m") ++ (not:HI (match_operand:HI 1 "nonimmediate_operand_msp430" " 0, 0")))] ++ "" ++ "inv %0" ++ [(set_attr "length" "1,2") ++ (set_attr "cc" "set_czn,set_czn")]) ++ ++ ++ ++;;============================================================================ ++;; not SI x = !x ++;; - ones component ++ ++(define_expand "one_cmplsi2" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))] ++ "" ++ "") ++ ++(define_insn "*one_cmplsi2_2" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=r, m") ++ (not:SI (match_operand:SI 1 "nonimmediate_operand" " 0, 0")))] ++"" ++ "inv %A0 ++ inv %B0" ++ [(set_attr "length" "2,4") ++ (set_attr "cc" "set_n,set_n")]) ++ ++ ++;;============================================================================ ++;; not DI x = !x ++;; - ones component ++ ++(define_expand "one_cmpldi2" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "") ++ (not:DI (match_operand:DI 1 "nonimmediate_operand" "0")))] ++ "" ++ "") ++ ++(define_insn "*one_cmpldi2_2" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=r, m") ++ (not:DI (match_operand:DI 1 "nonimmediate_operand" " 0, 0")))] ++ "" ++ "inv %A0 ++ inv %B0 ++ inv %C0 ++ inv %D0" ++ [(set_attr "length" "4,8") ++ (set_attr "cc" "set_n,set_n")]) ++ ++ ++ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;;============================================================================ ++;; abs ++;; x = |x| ++ ++(define_expand "absqi2" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (abs:QI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++ "") ++ ++(define_insn "*absqi2_2" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,m") ++ (abs:QI (match_operand:QI 1 "nonimmediate_operand" " 0, 0")))] ++ "" ++ "tst.b %0 ++ jge .Leaq%= ++ inv.b %0 ++ inc.b %0 ++.Leaq%=:" ++ [(set_attr "length" "4,7") ++ (set_attr "cc" "set_czn,set_czn")]) ++ ++ ++;;============================================================================ ++;; abs HI x = |x| ++;; ++ ++(define_expand "abshi2" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (abs:HI (match_operand:HI 1 "nonimmediate_operand" "0")))] ++ "" ++ "") ++ ++ ++(define_insn "*abshi2_2" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=r, m") ++ (abs:HI (match_operand:HI 1 "nonimmediate_operand" " 0, 0")))] ++ "" ++ "tst %0 ++ jge .Lae%= ++ inv %0 ++ inc %0 ++.Lae%=:" ++ [(set_attr "length" "4,7") ++ (set_attr "cc" "set_czn,set_czn")]) ++ ++ ++;;============================================================================ ++;; abs SI x = |x| ++ ++(define_expand "abssi2" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (abs:SI (match_operand:SI 1 "nonimmediate_operand" "0")))] ++ "" ++ "") ++ ++(define_insn "*abssi2_2" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=r, m") ++ (abs:SI (match_operand:SI 1 "nonimmediate_operand" " 0, 0")))] ++ "" ++ "* return msp430_emit_abssi(insn, operands,NULL);" ++ [(set_attr "length" "7,13") ++ (set_attr "cc" "clobber,clobber")]) ++ ++ ++;;============================================================================ ++;; abs DI x = |x| ++ ++(define_expand "absdi2" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "") ++ (abs:DI (match_operand:DI 1 "nonimmediate_operand" "0")))] ++ "" ++ "") ++ ++(define_insn "*absdi2_2" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=r, m") ++ (abs:DI (match_operand:DI 1 "nonimmediate_operand" " 0, 0")))] ++ "" ++ "* return msp430_emit_absdi(insn, operands,NULL);" ++ [(set_attr "length" "11,23") ++ (set_attr "cc" "clobber,clobber")]) ++ ++;;============================================================================ ++;; abs SF ++ ++(define_insn "abssf2" ++ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,m") ++ (abs:SF (match_operand:SF 1 "nonimmediate_operand" "0,0")))] ++"" ++"and #0x7fff, %B0" ++ [(set_attr "length" "2,3") ++ (set_attr "cc" "clobber,clobber")]) ++ ++ ++;; ========================================================================== ++;; there are shift helpers ++ ++(define_insn "trunchiqi" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") ++ (truncate:QI (match_operand:HI 1 "register_operand" "r,r")))] ++"" ++"mov.b %1, %0" ++ [(set_attr "length" "1,2") ++ (set_attr "cc" "none,none")]) ++ ++(define_insn "truncsihi" ++ [(set (match_operand:HI 0 "register_operand" "=r") ++ (truncate:HI (match_operand:SI 1 "register_operand" "r")))] ++"" ++"mov %1, %0" ++ [(set_attr "length" "1") ++ (set_attr "cc" "none")]) ++ ++ ++(define_insn "truncsiqi" ++ [(set (match_operand:QI 0 "register_operand" "=r") ++ (truncate:QI (match_operand:SI 1 "register_operand" "r")))] ++"" ++"mov.b %1, %0" ++ [(set_attr "length" "1") ++ (set_attr "cc" "none")]) ++ ++ ++(define_insn "truncdiqi" ++ [(set (match_operand:QI 0 "register_operand" "=r") ++ (truncate:QI (match_operand:DI 1 "register_operand" "r")))] ++"" ++"mov.b %1, %0" ++ [(set_attr "length" "1") ++ (set_attr "cc" "none")]) ++ ++(define_insn "truncdisi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI (match_operand:DI 1 "register_operand" "r")))] ++"" ++"mov %A1,%A0 ++ mov %B1,%B0" ++ [(set_attr "length" "2") ++ (set_attr "cc" "none")]) ++ ++ ++(define_expand "rotlhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "") ++ (match_operand:HI 2 "const_int_operand" "")))] ++"" ++" ++ if(INTVAL(operands[2])!=8) FAIL; ++") ++ ++(define_insn "*rotlhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,m") ++ (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") ++ (const_int 8)))] ++"" ++"swpb\\t%0" ++ [(set_attr "length" "1,2") ++ (set_attr "cc" "none")]) ++ ++ ++;;<< << << << << << << << << << << << << << << << << << << << << << << << << ++;; << << << << << << << << << << << << << << << << << << << << << << << << ++;;<< << << << << << << << << << << << << << << << << << << << << << << << << ++;; << << << << << << << << << << << << << << << << << << << << << << << << ++;;<< << << << << << << << << << << << << << << << << << << << << << << << << ++;; arithmetic shift left ++ ++(define_expand "ashlqi3" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "") ++ (match_operand:QI 2 "general_operand" "")))] ++"" ++"{ ++ if(!const_int_operand(operands[2],VOIDmode)) ++ { ++ rtx op0,op1; ++ ++ op0 = force_reg(QImode,operands[0]); ++ op1 = force_reg(QImode,operands[1]); ++ operands[2] = copy_to_mode_reg(QImode,operands[2]); ++ emit_insn(gen_ashlqi3_cnt (op0, op1, operands[2])); ++ emit_move_insn(operands[0],op0); ++ /*emit_move_insn(operands[1],op1);*/ ++ DONE; ++ } ++ else if(!register_operand(operands[1], QImode) ++ && is_shift_better_in_reg(operands)) ++ { ++ operands[1] = copy_to_mode_reg(QImode,operands[1]); ++ emit_insn (gen_ashlqi3fnl(operands[0], operands[1], operands[2])); ++ DONE; ++ } ++}") ++ ++(define_insn "ashlqi3_cnt" ++ [(parallel [(set (match_operand:QI 0 "register_operand" "=r") ++ (ashift:QI (match_operand:QI 1 "register_operand" "0") ++ (match_operand:QI 2 "register_operand" ""))) ++ (clobber (match_dup 2))])] ++"" ++"* return msp430_emit_ashlqi3(insn, operands,NULL);" ++ [(set_attr "length" "8") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "ashlqi3fnl" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=rm") ++ (ashift:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "0") ++ (match_operand 2 "const_int_operand" "i")))] ++ "" ++ "* return msp430_emit_ashlqi3(insn, operands,NULL);" ++ [(set_attr "length" "1") ++ (set_attr "cc" "clobber")]) ++ ++;; HImode ====================================== ++(define_expand "ashlhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "") ++ (match_operand 2 "general_operand" "")))] ++"" ++"{ msp430_ashlhi3(operands); DONE; }") ++ ++(define_insn "ashlhi3_cnt" ++ [(parallel [(set (match_operand:HI 0 "register_operand" "=r") ++ (ashift:HI (match_operand:HI 1 "register_operand" "0") ++ (match_operand:HI 2 "register_operand" "r"))) ++ (clobber (match_dup 2))])] ++ "" ++ "* return msp430_emit_ashlhi3(insn, operands,NULL);" ++ [(set_attr "length" "5") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*ashlhi3_1" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,R,m") ++ (ashift:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0,0") ++ (const_int 1)))] ++ "" ++ "rla\\t%0" ++ [(set_attr "length" "1,2,3") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*ashlhi3_15" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,R,m") ++ (ashift:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0,0") ++ (const_int 15)))] ++ "" ++ "rra\\t%0 ++\\tclr\\t%0 ++\\trrc\\t%0" ++ [(set_attr "length" "3,5,7") ++ (set_attr "cc" "clobber")]) ++ ++ ++;; SImode ====================================== ++ ++(define_expand "ashlsi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "") ++ (match_operand:HI 2 "general_operand" "")))] ++"" ++"{ msp430_ashlsi3(operands); DONE; }") ++ ++(define_insn "ashlsi3_cnt" ++ [(parallel [(set (match_operand:SI 0 "register_operand" "=r") ++ (ashift:SI (match_operand:SI 1 "register_operand" "0") ++ (match_operand:HI 2 "register_operand" ""))) ++ (clobber (match_dup 2))])] ++"" ++"* return msp430_emit_ashlsi3(insn, operands,NULL);" ++ [(set_attr "length" "8") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*ashlsi3_31" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") ++ (ashift:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") ++ (const_int 31)))] ++ "" ++"rra\\t%A0 ++\\tclr\\t%A0 ++\\tclr\\t%B0 ++\\trrc\\t%B0" ++[(set_attr "length" "4,7,8") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_insn "*ashlsi3_8" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") ++ (ashift:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") ++ (const_int 8)))] ++ "" ++"*{ ++ if(which_alternative==0) ++ { ++ return \"xor.b\\t%A0, %B0\\n\\txor\\t%A0, %B0\\n\\tswpb\\t%B0\\n\\tand.b\\t#-1, %A0\\n\\tswpb\\t%A0 \"; ++ } ++ else ++ { ++ return \"xor.b\\t%A0, %B0\\n\\tclr.b\\t%L0\\n\\txor\\t%A0, %B0\\n\\tswpb\\t%B0\\n\\tclr.b\\t%J0\\n\\tswpb\\t%A0\"; ++ } ++}" ++ [(set_attr "length" "5,11,12") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*ashlsi3_16" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,m,r,m") ++ (ashift:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "rR,rR,m,m") ++ (const_int 16)))] ++"" ++"mov %A1, %B0 ++\tmov #0, %A0" ++[(set_attr "length" "1,2,2,3") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*ashlsi3_1" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=m,R,r") ++ (ashift:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") ++ (const_int 1)))] ++ "" ++"rla\\t%A0 ++\\trlc\\t%B0" ++[(set_attr "length" "6,5,2") ++ (set_attr "cc" "clobber")]) ++ ++;; DImode ====================================== ++ ++(define_expand "ashldi3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "") ++ (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "") ++ (match_operand:HI 2 "general_operand" "")))] ++"" ++"{ ++ if( !const_int_operand(operands[2],VOIDmode) || ++ INTVAL(operands[2]) > 1) ++ { ++ rtx op0,op1; ++ ++ op0 = force_reg(DImode,operands[0]); ++ op1 = force_reg(DImode,operands[1]); ++ operands[2] = copy_to_mode_reg(HImode,operands[2]); ++ emit_insn(gen_ashldi3_cnt (op0, op1, operands[2])); ++ emit_move_insn(operands[0],op0); ++ /*emit_move_insn(operands[1],op1);*/ ++ DONE; ++ } ++ else if(!register_operand(operands[1], DImode) ++ && is_shift_better_in_reg(operands)) ++ { ++ operands[1] = copy_to_mode_reg(DImode,operands[1]); ++ emit_insn (gen_ashldi3fnl(operands[0], operands[1], operands[2])); ++ DONE; ++ } ++}") ++ ++(define_insn "ashldi3_cnt" ++ [(parallel [(set (match_operand:DI 0 "register_operand" "=r") ++ (ashift:DI (match_operand:DI 1 "register_operand" "0") ++ (match_operand:HI 2 "register_operand" ""))) ++ (clobber (match_dup 2))])] ++ "" ++ "* return msp430_emit_ashldi3(insn, operands,NULL);" ++ [(set_attr "length" "8") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_insn "ashldi3fnl" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") ++ (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "0") ++ (match_operand 2 "const_int_operand" "i")))] ++ "" ++ "* return msp430_emit_ashldi3(insn, operands,NULL);" ++ [(set_attr "length" "1") ++ (set_attr "cc" "clobber")]) ++ ++;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ++;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ++;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ++;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ++;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ++;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ++;; arithmetic shift right ++ ++(define_expand "ashrqi3" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "") ++ (match_operand:QI 2 "general_operand" "")))] ++"" ++"{ ++ if(!const_int_operand(operands[2],VOIDmode)) ++ { ++ rtx op0,op1; ++ ++ op0 = force_reg(QImode,operands[0]); ++ op1 = force_reg(QImode,operands[1]); ++ operands[2] = copy_to_mode_reg(QImode,operands[2]); ++ emit_insn(gen_ashrqi3_cnt (op0, op1, operands[2])); ++ emit_move_insn(operands[0],op0); ++ /*emit_move_insn(operands[1],op1);*/ ++ DONE; ++ } ++ else if(!register_operand(operands[1], QImode) ++ && INTVAL(operands[2])>2 ++ && INTVAL(operands[2])!=7) ++ { ++ operands[1] = copy_to_mode_reg(QImode,operands[1]); ++ emit_insn (gen_ashrqi3fnl(operands[0], operands[1], operands[2])); ++ DONE; ++ } ++ else if(INTVAL(operands[2]) == 7) ++ { ++ /* to do it simple we need a register */ ++ rtx r1 = gen_reg_rtx(HImode); ++ emit_insn(gen_extendqihi2(r1,operands[1])); ++ emit_insn(gen_swpb(r1,r1)); ++ emit_insn(gen_trunchiqi(operands[0],r1)); ++ DONE; ++ } ++}") ++ ++(define_insn "ashrqi3_cnt" ++ [(parallel [(set (match_operand:QI 0 "register_operand" "=r") ++ (ashiftrt:QI (match_operand:QI 1 "register_operand" "0") ++ (match_operand:QI 2 "register_operand" ""))) ++ (clobber (match_dup 2))])] ++"" ++"* return msp430_emit_ashrqi3(insn, operands,NULL);" ++ [(set_attr "length" "8") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "ashrqi3fnl" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=rm") ++ (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "0") ++ (match_operand 2 "const_int_operand" "i")))] ++ "" ++ "* return msp430_emit_ashrqi3(insn, operands,NULL);" ++ [(set_attr "length" "1") ++ (set_attr "cc" "clobber")]) ++ ++;; HImode ====================================== ++(define_expand "ashrhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "") ++ (match_operand 2 "general_operand" "")))] ++"" ++"{msp430_ashrhi3(operands); DONE; }") ++ ++(define_insn "ashrhi3_cnt" ++ [(parallel [(set (match_operand:HI 0 "register_operand" "=r") ++ (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") ++ (match_operand:HI 2 "register_operand" ""))) ++ (clobber (match_dup 2))])] ++"" ++"* return msp430_emit_ashrhi3(insn, operands,NULL);" ++ [(set_attr "length" "5") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_insn "*ashrhi3_1" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=rR,m") ++ (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0") ++ (const_int 1)))] ++ "" ++ "rra\\t%0" ++ [(set_attr "length" "1,2") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_insn "*ashrhi3_15" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=rR,m") ++ (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0") ++ (const_int 15)))] ++ "" ++ "swpb\\t%0 ++\\tsxt\\t%0 ++\\tswpb\\t%0 ++\\tsxt\\t%0" ++ [(set_attr "length" "4,8") ++ (set_attr "cc" "clobber")]) ++ ++ ++ ++;; SImode ====================================== ++ ++(define_expand "ashrsi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "") ++ (match_operand:HI 2 "general_operand" "")))] ++"" ++"{msp430_ashrsi3(operands);DONE; }") ++ ++(define_insn "ashrsi3_cnt" ++ [(parallel [(set (match_operand:SI 0 "register_operand" "=r") ++ (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") ++ (match_operand:HI 2 "register_operand" ""))) ++ (clobber (match_dup 2))])] ++"" ++"* return msp430_emit_ashrsi3(insn, operands,NULL);" ++ [(set_attr "length" "8") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*ashrsi3_1" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=rR,m") ++ (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0") ++ (const_int 1)))] ++ "" ++ "rra\\t%B0 ++\\trrc\\t%A0" ++ [(set_attr "length" "2,4") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*ashrsi3_31" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") ++ (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") ++ (const_int 31)))] ++ "" ++"swpb %B0 ++\\tsxt %B0 ++\\tswpb %B0 ++\\tsxt %B0 ++\\tmov %B0, %A0" ++ [(set_attr "length" "5,10,10") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*ashrsi3_8" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") ++ (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") ++ (const_int 8)))] ++ "" ++"*{ ++ if(which_alternative==0) ++ { ++ return \" swpb\\t%A0\\n\\tswpb\\t%B0\\n\\txor.b\\t%B0, %A0\\n\\txor\\t%B0, %A0\\n\\tsxt\\t%B0\"; ++ } ++ else ++ { ++ return \" swpb\\t%A0\\n\\tswpb\\t%B0\\n\\txor.b\\t%B0, %A0\\n\\tclr.b\\t%J0\\n\\txor\\t%B0, %A0\\n\\tsxt\\t%B0\"; ++ } ++}" ++ [(set_attr "length" "5,11,12") ++ (set_attr "cc" "clobber")]) ++ ++;; DImode ====================================== ++ ++(define_expand "ashrdi3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "") ++ (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "") ++ (match_operand:HI 2 "general_operand" "")))] ++"" ++"{ ++ if( !const_int_operand(operands[2],VOIDmode)) ++ { ++ rtx op0,op1; ++ ++ op0 = force_reg(DImode,operands[0]); ++ op1 = force_reg(DImode,operands[1]); ++ operands[2] = copy_to_mode_reg(HImode,operands[2]); ++ emit_insn(gen_ashrdi3_cnt (op0, op1, operands[2])); ++ emit_move_insn(operands[0],op0); ++ /*emit_move_insn(operands[1],op1);*/ ++ DONE; ++ } ++ else if(!register_operand(operands[1], DImode) ++ && is_shift_better_in_reg(operands)) ++ { ++ operands[1] = copy_to_mode_reg(DImode,operands[1]); ++ emit_insn (gen_ashrdi3fnl(operands[0], operands[1], operands[2])); ++ DONE; ++ } ++}") ++ ++(define_insn "ashrdi3_cnt" ++ [(parallel [(set (match_operand:DI 0 "register_operand" "=r") ++ (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") ++ (match_operand:HI 2 "register_operand" ""))) ++ (clobber (match_dup 2))])] ++ "" ++ "* return msp430_emit_ashrdi3(insn, operands,NULL);" ++ [(set_attr "length" "8") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_insn "ashrdi3fnl" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") ++ (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") ++ (match_operand 2 "const_int_operand" "i")))] ++ "" ++ "* return msp430_emit_ashrdi3(insn, operands,NULL);" ++ [(set_attr "length" "1") ++ (set_attr "cc" "clobber")]) ++ ++ ++ ++ ++ ++;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ++;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ++;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ++;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ++;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ++;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> ++;; logical shift right ++ ++(define_expand "lshrqi3" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "") ++ (match_operand:QI 2 "general_operand" "")))] ++"" ++"{ ++ if(!const_int_operand(operands[2],VOIDmode)) ++ { ++ rtx op0,op1; ++ ++ op0 = force_reg(QImode,operands[0]); ++ op1 = force_reg(QImode,operands[1]); ++ operands[2] = copy_to_mode_reg(QImode,operands[2]); ++ emit_insn(gen_lshrqi3_cnt (op0, op1, operands[2])); ++ emit_move_insn(operands[0],op0); ++ /*emit_move_insn(operands[1],op1);*/ ++ DONE; ++ } ++ else if(!register_operand(operands[1], QImode) ++ && is_shift_better_in_reg(operands)) ++ { ++ operands[1] = copy_to_mode_reg(QImode,operands[1]); ++ emit_insn (gen_lshrqi3fnl(operands[0], operands[1], operands[2])); ++ DONE; ++ } ++}") ++ ++(define_expand "lshrqi3_cnt" ++ [(parallel [(set (match_operand:QI 0 "register_operand" "=r") ++ (lshiftrt:QI (match_operand:QI 1 "register_operand" "0") ++ (match_operand:QI 2 "register_operand" ""))) ++ (clobber (match_dup 2))])] ++"" ++"") ++ ++(define_insn "*lshrqi3_cnt" ++ [(parallel [(set (match_operand:QI 0 "register_operand" "=r") ++ (lshiftrt:QI (match_operand:QI 1 "register_operand" "0") ++ (match_operand:QI 2 "register_operand" ""))) ++ (clobber (match_dup 2))])] ++"" ++"* return msp430_emit_lshrqi3(insn, operands,NULL);" ++ [(set_attr "length" "8") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "lshrqi3fnl" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=rm") ++ (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "0") ++ (match_operand 2 "const_int_operand" "i")))] ++ "" ++ "* return msp430_emit_lshrqi3(insn, operands,NULL);" ++ [(set_attr "length" "1") ++ (set_attr "cc" "clobber")]) ++ ++;; HImode ====================================== ++ ++(define_insn "clrc" ++ [(unspec:HI [(const_int 123454321)] 30)] ++"" ++ "clrc" ++[(set_attr "length" "1") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_expand "lshrhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "") ++ (match_operand 2 "general_operand" "")))] ++"" ++"{msp430_lshrhi3(operands); DONE; }") ++ ++(define_insn "lshrhi3_cnt" ++ [(parallel [(set (match_operand:HI 0 "register_operand" "=r") ++ (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") ++ (match_operand:HI 2 "register_operand" ""))) ++ (clobber (match_dup 2))])] ++"" ++"* return msp430_emit_lshrhi3(insn, operands,NULL);" ++ [(set_attr "length" "5") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*lshrhi3_15" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,R,m") ++ (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0,0") ++ (const_int 15)))] ++ "" ++ "rla\\t%0 ++\\tclr\\t%0 ++\\trlc\\t%0" ++ [(set_attr "length" "3,6,8") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_insn "*lshrhi3_1" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=rR,m") ++ (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0") ++ (const_int 1)))] ++ "" ++"clrc ++\\trrc\\t%0" ++ [(set_attr "length" "2,3") ++ (set_attr "cc" "clobber")]) ++ ++;; SImode ====================================== ++ ++(define_expand "lshrsi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "") ++ (match_operand:HI 2 "general_operand" "")))] ++"" ++"{ msp430_lshrsi3(operands); DONE; }") ++ ++(define_insn "lshrsi3_cnt" ++ [(parallel [(set (match_operand:SI 0 "register_operand" "=r") ++ (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") ++ (match_operand:HI 2 "register_operand" ""))) ++ (clobber (match_dup 2))])] ++"" ++"* return msp430_emit_lshrsi3(insn, operands,NULL);" ++ [(set_attr "length" "8") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_insn "*lshrsi3_31" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") ++ (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") ++ (const_int 31)))] ++ "" ++"rla %B0 ++\\tclr %B0 ++\\tclr %A0 ++\\trlc %A0" ++ [(set_attr "length" "4,9,10") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_insn "*lshrsi3_8" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") ++ (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") ++ (const_int 8)))] ++ "" ++"*{ ++ if(which_alternative==0) ++ { ++ return \"swpb\\t%A0\\n\\tswpb\\t%B0\\n\\txor.b\\t%B0, %A0\\n\\txor\\t%B0, %A0\\n\\tand.b\\t#-1, %B0\"; ++ } ++ else ++ { ++ return \"swpb\\t%A0\\n\\tswpb\\t%B0\\n\\txor.b\\t%B0, %A0\\n\\tclr.b\\t%J0\\n\\txor\\t%B0, %A0\\n\\tclr.b\\t%L0\"; ++ } ++}" ++ [(set_attr "length" "5,11,12") ++ (set_attr "cc" "clobber")]) ++ ++(define_insn "*lshrsi3_1" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") ++ (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") ++ (const_int 1)))] ++ "" ++"clrc ++\\trrc\\t%B0 ++\\trrc\\t%A0" ++ [(set_attr "length" "3,4,5") ++ (set_attr "cc" "clobber")]) ++ ++;; DImode ====================================== ++ ++(define_expand "lshrdi3" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "") ++ (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "") ++ (match_operand:HI 2 "general_operand" "")))] ++"" ++"{ ++ if( !const_int_operand(operands[2],VOIDmode)) ++ { ++ rtx op0,op1; ++ ++ op0 = force_reg(DImode,operands[0]); ++ op1 = force_reg(DImode,operands[1]); ++ operands[2] = copy_to_mode_reg(HImode,operands[2]); ++ emit_insn(gen_lshrdi3_cnt (op0, op1, operands[2])); ++ emit_move_insn(operands[0],op0); ++ /*emit_move_insn(operands[1],op1);*/ ++ DONE; ++ } ++ else if(!register_operand(operands[1], DImode) ++ && is_shift_better_in_reg(operands)) ++ { ++ operands[1] = copy_to_mode_reg(DImode,operands[1]); ++ emit_insn (gen_lshrdi3fnl(operands[0], operands[1], operands[2])); ++ DONE; ++ } ++}") ++ ++(define_insn "lshrdi3_cnt" ++ [(parallel [(set (match_operand:DI 0 "register_operand" "=r") ++ (lshiftrt:DI (match_operand:DI 1 "register_operand" "0") ++ (match_operand:HI 2 "register_operand" ""))) ++ (clobber (match_dup 2))])] ++ "" ++ "* return msp430_emit_lshrdi3(insn, operands,NULL);" ++ [(set_attr "length" "8") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_insn "lshrdi3fnl" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") ++ (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") ++ (match_operand 2 "const_int_operand" "i")))] ++ "" ++ "* return msp430_emit_lshrdi3(insn, operands,NULL);" ++ [(set_attr "length" "1") ++ (set_attr "cc" "clobber")]) ++ ++ ++ ++ ++ ++ ++;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x ++;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x ++;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x ++;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x ++;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x ++;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x ++;; sign extend ++ ++(define_insn "extendqihi2" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") ++ (sign_extend:HI (match_operand:QI 1 "general_operand" "0,*rmi")))] ++ "" ++ "* return signextendqihi(insn, operands,NULL);" ++ [(set_attr "length" "2,2") ++ (set_attr "cc" "set_n,set_n")]) ++ ++(define_insn "extendqisi2" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") ++ (sign_extend:SI (match_operand:QI 1 "general_operand" "0,*rmi")))] ++ "" ++ "* return signextendqisi(insn, operands,NULL);" ++ [(set_attr "length" "6,6") ++ (set_attr "cc" "set_n,set_n")]) ++ ++(define_insn "extendqidi2" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") ++ (sign_extend:DI (match_operand:QI 1 "general_operand" "0,*rmi")))] ++ "" ++ "* return signextendqidi(insn, operands,NULL);" ++ [(set_attr "length" "6,6") ++ (set_attr "cc" "set_n,set_n")]) ++ ++(define_insn "extendhisi2" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") ++ (sign_extend:SI (match_operand:HI 1 "general_operand" "0,*rmi")))] ++ "" ++ "* return signextendhisi(insn, operands,NULL);" ++ [(set_attr "length" "6,6") ++ (set_attr "cc" "set_n,set_n")]) ++ ++(define_insn "extendhidi2" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") ++ (sign_extend:DI (match_operand:HI 1 "general_operand" "0,*rmi")))] ++ "" ++ "* return signextendhidi(insn, operands,NULL);" ++ [(set_attr "length" "6,6") ++ (set_attr "cc" "set_n,set_n")]) ++ ++(define_insn "extendsidi2" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") ++ (sign_extend:DI (match_operand:SI 1 "general_operand" "0,*rmi")))] ++ "" ++ "* return signextendsidi(insn, operands,NULL);" ++ [(set_attr "length" "6,6") ++ (set_attr "cc" "set_n,set_n")]) ++ ++;; xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 ++;; xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 ++;; xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 ++;; xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 ++;; xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 ++;; xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 ++;; zero extend ++ ++(define_insn "zero_extendqihi2" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") ++ (zero_extend:HI (match_operand:QI 1 "general_operand" "0,*rmi")))] ++ "" ++ "* return zeroextendqihi(insn, operands,NULL);" ++ [(set_attr "length" "2,2") ++ (set_attr "cc" "clobber,clobber")]) ++ ++(define_insn "zero_extendqisi2" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") ++ (zero_extend:SI (match_operand:QI 1 "general_operand" "0,*rmi")))] ++ "" ++ "* return zeroextendqisi(insn, operands,NULL);" ++ [(set_attr "length" "6,6") ++ (set_attr "cc" "clobber,clobber")]) ++ ++(define_insn "zero_extendqidi2" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") ++ (zero_extend:DI (match_operand:QI 1 "general_operand" "0,*rmi")))] ++ "" ++ "* return zeroextendqidi(insn, operands,NULL);" ++ [(set_attr "length" "6,6") ++ (set_attr "cc" "clobber,clobber")]) ++ ++ ++(define_insn "zero_extendhisi2" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") ++ (zero_extend:SI (match_operand:HI 1 "general_operand" "0,*rmi")))] ++ "" ++ "* return zeroextendhisi(insn, operands,NULL);" ++ [(set_attr "length" "6,6") ++ (set_attr "cc" "clobber,clobber")]) ++ ++(define_insn "zero_extendhidi2" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") ++ (zero_extend:DI (match_operand:HI 1 "general_operand" "0,*rmi")))] ++ "" ++ "* return zeroextendhidi(insn, operands,NULL);" ++ [(set_attr "length" "6,6") ++ (set_attr "cc" "clobber,clobber")]) ++ ++(define_insn "zero_extendsidi2" ++ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") ++ (zero_extend:DI (match_operand:SI 1 "general_operand" "0,*rmi")))] ++ "" ++ "* return zeroextendsidi(insn, operands,NULL);" ++ [(set_attr "length" "6,6") ++ (set_attr "cc" "clobber,clobber")]) ++ ++;; ===================================================================== ++;; single bit extract ++;; as soon as all operatoins performed on io registers ++;; let use only QImode. ++ ++(define_expand "extv" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") ++ (sign_extract:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") ++ (match_operand 2 "const_int_operand" "") ++ (match_operand 3 "const_int_operand" "")))] ++"" ++"{ ++ if(INTVAL(operands[2]) != 1 || INTVAL(operands[3]) <= 0) ++ FAIL; ++}") ++ ++(define_insn "*extv" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,r,r,r,m,m,m,m") ++ (sign_extract:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "r,m,r,m,r,m,r,m") ++ (const_int 1) ++ (match_operand 2 "const_int_operand" "P,P,i,i,P,P,i,i")))] ++ "" ++"* { ++ operands[2] = GEN_INT(1<-500) ++ return \"jmp %0\"; ++ return \"br #%0\"; ++}" ++ [(set_attr "length" "2") ++ (set_attr "cc" "none")]) ++ ++ ++; indirect jump ++(define_expand "indirect_jump" ++ [(set (pc) (match_operand:HI 0 "nonimmediate_operand" ""))] ++ "" ++ "") ++ ++(define_insn "*indirect_jump_idx" ++ [(set (pc) (match_operand:HI 0 "memory_operand" "m"))] ++ "indexed_location(operands[0])" ++ "br @%E0" ++ [(set_attr "length" "1") ++ (set_attr "cc" "none")]) ++ ++(define_insn "*indirect_jump_mem" ++ [(set (pc) (match_operand:HI 0 "memory_operand" "m"))] ++ "!indexed_location(operands[0])" ++ "br %0" ++ [(set_attr "length" "2") ++ (set_attr "cc" "none")]) ++ ++ ++(define_insn "*indirect_jump_reg" ++ [(set (pc) (match_operand:HI 0 "register_operand" "r"))] ++ "" ++ "br %0" ++ [(set_attr "length" "1") ++ (set_attr "cc" "none")]) ++ ++ ++;;======================================================================= ++;;======================================================================= ++;;======================================================================= ++;;======================================================================= ++ ++ ++;;======================================================================= ++;; ++;; CASE ++;; ++ ++/* ++(define_expand "casesi" ++ [(set (match_dup 6) ++ (minus:HI (subreg:HI (match_operand:SI 0 "register_operand" "") 0) ++ (match_operand:HI 1 "register_operand" ""))) ++ (parallel [(set (cc0) ++ (compare (match_dup 6) ++ (match_operand:HI 2 "register_operand" "")))]) ++ (set (pc) ++ (if_then_else (gtu (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 4 "" "")) ++ (pc))) ++ (set (match_dup 6) ++ (plus:HI (match_dup 6) (label_ref (match_operand:HI 3 "" "")))) ++ ++ (parallel [(set (pc) (unspec:HI [(match_dup 6)] 1)) ++ (use (label_ref (match_dup 3))) ++ (clobber (match_dup 6))])] ++ "" ++ " ++{ ++ operands[6] = gen_reg_rtx (HImode); ++}") ++ ++*/ ++ ++;; Table helper ++(define_insn "tablejump" ++ [(set (pc) (match_operand:HI 0 "general_operand" "rRP,i,m")) ++ (use (label_ref (match_operand 1 "" "")))] ++ "" ++ "br %0 ; %1" ++ [(set_attr "length" "1,2,2") ++ (set_attr "cc" "clobber")]) ++ ++ ++;; ============================================================= ++;; match De Morgan's law ++(define_insn "nandqi" ++ [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m,m,r") ++ (and:QI (not:QI (match_operand:QI 1 "general_operand_msp430" "rRP,mi,rRP,mi")) ++ (match_operand:QI 2 "nonimmediate_operand_msp430" "0,0,0,0")))] ++"" ++"bic.b %1, %0" ++[(set_attr "length" "1,3,2,2") ++ (set_attr "cc" "none")]) ++ ++(define_insn "nandhi" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m,m,r") ++ (and:HI (not:HI (match_operand:HI 1 "general_operand_msp430" "rRP,mi,rRP,mi")) ++ (match_operand:HI 2 "nonimmediate_operand_msp430" "0,0,0,0")))] ++"" ++"bic %1, %0" ++[(set_attr "length" "1,3,2,2") ++ (set_attr "cc" "none")]) ++ ++(define_insn "nandsi" ++ [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,m,m,r,r,m") ++ (and:SI (not:SI (match_operand:SI 1 "general_operand_msp430" "rP,mi,rP,mi,R,R")) ++ (match_operand:SI 2 "nonimmediate_operand_msp430" "0,0,0,0,0,0")))] ++"" ++"bic %A1, %A0 ++\\tbic %B1, %B0" ++[(set_attr "length" "2,6,4,4,3,5") ++ (set_attr "cc" "none")]) ++ ++ ++ ++;; ============================================================= ++;; PEEPHOLES ++ ++;; a &= ~b; ++ ++(define_insn "*bit_clear" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m,m,r") ++ (unspec_volatile:HI [(match_operand:HI 1 "general_operand_msp430" "rRP,mi,rRP,mi")] 40))] ++"" ++"bic %1, %0" ++ [(set_attr "length" "1,3,2,2") ++ (set_attr "cc" "none")]) ++ ++ ++;; these two for: ++;; (ulong) x = (ulong) func() << 16; ++;; x |= func(); ++;; func() is uint ++;; ++ ++;; do not check for zeros here, cause this insn already issued. ++(define_peephole2 ++ [(set (match_operand:SI 1 "register_operand" "") ++ (sign_extend:SI (match_operand:HI 0 "register_operand" ""))) ++ (set (match_dup 1) (ashift:SI (match_dup 1) (const_int 16)))] ++"" ++ [(set (subreg:HI (match_dup 1) 2) (match_dup 0))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SI 1 "register_operand" "") ++ (zero_extend:SI (match_operand:HI 0 "register_operand" ""))) ++ (set (match_dup 1) (ashift:SI (match_dup 1) (const_int 16)))] ++"" ++ [(set (subreg:HI (match_dup 1) 2) (match_dup 0))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (zero_extend:SI (match_operand:HI 1 "register_operand" ""))) ++ (set (match_operand:SI 2 "register_operand" "") ++ (ior:SI (match_dup 2) (match_dup 0)))] ++"dead_or_set_in_peep(1,insn, operands[0])" ++ [(set (subreg:HI (match_dup 2) 0) ++ (ior:HI (subreg:HI (match_dup 2) 0) (match_dup 1)))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "general_operand_msp430" "")) ++ (set (match_operand:SI 2 "register_operand" "") ++ (zero_extend:SI (match_dup 0))) ++ (set (match_operand:SI 3 "register_operand" "") ++ (ior:SI (match_dup 3) (match_dup 2)))] ++"dead_or_set_in_peep(2,insn, operands[0])" ++ [(set (subreg:HI (match_dup 3) 0) ++ (ior:HI (subreg:HI (match_dup 3) 0) (match_dup 1)))] ++"") ++ ++ ++;; (ulong) x = (ulong) f >> 16; ++;; ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "register_operand" "")) ++ (set (match_dup 0) ++ (lshiftrt:SI (match_dup 0) ++ (const_int 16)))] ++"" ++[(set (subreg:HI (match_dup 0) 0) (subreg:HI (match_dup 1) 2)) ++ (set (subreg:HI (match_dup 0) 2) (const_int 0))] ++"") ++ ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "register_operand" "")) ++ (set (match_operand:SI 2 "register_operand" "") ++ (ior:SI (match_dup 2) (match_dup 0)))] ++"dead_or_set_in_peep(1,insn, operands[0])" ++ [(set (match_dup 2) (ior:SI (match_dup 2) ++ (match_dup 1)))] ++"") ++ ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (zero_extend:SI (match_operand:HI 1 "general_operand" ""))) ++ (set (match_dup 0) ++ (ashift:SI (match_dup 0) (const_int 16)))] ++"" ++ [(set (subreg:HI (match_dup 0) 2) (match_dup 1))] ++"") ++ ++ ++;; shift right & set ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "register_operand" "")) ++ (set (match_operand:HI 2 "register_operand" "") ++ (match_dup 0)) ++ (set (match_dup 2) ++ (and:HI (match_dup 2) ++ (match_operand 3 "const_int_operand" ""))) ++ (set (match_dup 2) ++ (lshiftrt:HI (match_dup 2) ++ (match_operand 4 "const_int_operand" ""))) ++ (set (match_dup 1) (match_dup 2))] ++"dead_or_set_in_peep(4,insn, operands[2])" ++ [(set (match_dup 0) (match_dup 1)) ++ (set (match_dup 1) ++ (and:HI (match_dup 1) ++ (match_dup 3))) ++ (set (match_dup 1) ++ (lshiftrt:HI (match_dup 1) ++ (match_dup 4)))] ++"") ++ ++;; shift left and set ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "register_operand" "")) ++ (set (match_operand:HI 2 "register_operand" "") ++ (match_dup 0)) ++ (set (match_dup 2) ++ (and:HI (match_dup 2) ++ (match_operand 3 "const_int_operand" ""))) ++ (set (match_dup 2) ++ (ashift:HI (match_dup 2) ++ (match_operand 4 "const_int_operand" ""))) ++ (set (match_dup 1) (match_dup 2))] ++"dead_or_set_in_peep(4,insn, operands[2])" ++ [(set (match_dup 0) (match_dup 1)) ++ (set (match_dup 1) ++ (and:HI (match_dup 1) ++ (match_dup 3))) ++ (set (match_dup 1) ++ (ashift:HI (match_dup 1) ++ (match_dup 4)))] ++"") ++ ++ ++;; ++;; these for some shifts and stuff. ++;; every peephole saves up to 4 bytes. ++;; ++ ++(define_insn "*addc_reg" ++ [(set (match_operand:HI 0 "register_operand" "=r,r") ++ (unspec:HI [(match_operand:HI 1 "register_operand" "%0,0") ++ (match_operand:HI 2 "general_operand_msp430" "rP,mi")] 0))] ++"" ++"addc %2, %0" ++[(set_attr "length" "1,2") ++ (set_attr "cc" "clobber,clobber")]) ++ ++ ++(define_insn "*addc_any" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m,m") ++ (unspec:HI [(match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0") ++ (match_operand:HI 2 "general_operand_msp430" "rP,mi")] 5))] ++"" ++"addc %2, %0" ++[(set_attr "length" "2,3") ++ (set_attr "cc" "clobber,clobber")]) ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "general_operand_msp430" "")) ++ (set (match_operand:SI 2 "register_operand" "") ++ (zero_extend:SI (match_dup 0))) ++ (set (match_operand:SI 3 "register_operand" "") ++ (plus:SI (match_dup 3) (match_dup 2)))] ++"dead_or_set_in_peep(2,insn, operands[2])" ++ [(set (subreg:HI (match_dup 3) 0) ++ (plus:HI (subreg:HI (match_dup 3) 0) ++ (match_dup 1))) ++ (set (subreg:HI (match_dup 3) 2) ++ (unspec:HI [(subreg:HI (match_dup 3) 2) (const_int 0)] 0))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "general_operand_msp430" "")) ++ (set (match_operand:SI 2 "register_operand" "") ++ (zero_extend:SI (match_dup 0))) ++ (set (match_operand:SI 3 "nonimmediate_operand_msp430" "") ++ (plus:SI (match_dup 3) (match_dup 2)))] ++"dead_or_set_in_peep(2,insn, operands[2])" ++ [(set (subreg:HI (match_dup 3) 0) ++ (plus:HI (subreg:HI (match_dup 3) 0) ++ (match_dup 1))) ++ (set (subreg:HI (match_dup 3) 2) ++ (unspec:HI [(subreg:HI (match_dup 3) 2) (const_int 0)] 5))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "general_operand_msp430" "")) ++ (set (match_operand:SI 2 "nonimmediate_operand_msp430" "") ++ (zero_extend:SI (match_dup 0)))] ++"dead_or_set_in_peep(1,insn, operands[0])" ++ [(set (subreg:HI (match_dup 2) 0) (match_dup 1)) ++ (set (subreg:HI (match_dup 2) 2) (const_int 0))] ++"") ++ ++;; ++;; these are for redudant moves. ++;; ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "nonimmediate_operand_msp430" "")) ++ (set (match_operand:SI 2 "register_operand" "") ++ (ior:SI (match_dup 2) (match_dup 0))) ++ (set (match_dup 1) (match_dup 2))] ++"dead_or_set_in_peep(1,insn, operands[0])" ++ [(set (match_dup 1) (ior:SI (match_dup 1) (match_dup 2)))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (ior:SI (match_dup 0) ++ (match_operand:SI 1 "register_operand" ""))) ++ (set (match_dup 1) (match_dup 0))] ++"dead_or_set_in_peep(1,insn, operands[0])" ++ [(set (match_dup 1) (ior:SI (match_dup 1) (match_dup 0)))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "register_operand" "")) ++ (set (match_dup 0) ++ (not:HI (match_dup 0))) ++ (set (match_operand:HI 2 "register_operand" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0]) && dead_or_set_in_peep(0,insn, operands[1])" ++ [(set (match_dup 1) (not:HI (match_dup 1))) ++ (set (match_dup 2) (match_dup 1))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "register_operand" "")) ++ (set (match_dup 0) ++ (not:SI (match_dup 0))) ++ (set (match_operand:SI 2 "register_operand" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0]) && dead_or_set_in_peep(0,insn, operands[1])" ++ [(set (match_dup 1) (not:SI (match_dup 1))) ++ (set (match_dup 2) (match_dup 1))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SF 0 "register_operand" "") ++ (match_operand:SF 1 "general_operand_msp430" "")) ++ (set (match_operand:SF 2 "nonimmediate_operand_msp430" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(1,insn, operands[0])" ++ [(set (match_dup 2) (match_dup 1))] ++"") ++ ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "general_operand_msp430" "")) ++ (set (match_operand:SI 2 "nonimmediate_operand_msp430" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(1,insn, operands[0])" ++ [(set (match_dup 2) (match_dup 1))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "general_operand_msp430" "")) ++ (set (match_operand:HI 2 "nonimmediate_operand_msp430" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(1,insn, operands[0])" ++ [(set (match_dup 2) (match_dup 1))] ++"") ++ ++ ++ ++;; ========================================================================= ++;; This one for bit tests like: ++;; volatile long a; ++;; while(a&CONST_HALFNIBBLE) ; ++ ++(define_insn "*bittest_lo" ++ [(set (cc0) ++ (unspec:SI [(match_operand:SI 0 "nonimmediate_operand_msp430" "r,r,m,m") ++ (match_operand:SI 1 "general_operand_msp430" "rPR,mi,rPR,mi")] 1))] ++"" ++"bit %A1,%A0" ++[(set_attr "length" "1,2,2,3") ++ (set_attr "cc" "compare,compare,compare,compare")]) ++ ++(define_insn "*bittest_hi" ++ [(set (cc0) ++ (unspec:SI [(match_operand:SI 0 "nonimmediate_operand_msp430" "r,r,m,m") ++ (match_operand:SI 1 "general_operand_msp430" "rPR,mi,rPR,mi")] 2))] ++"" ++"bit %B1,%B0" ++[(set_attr "length" "1,2,2,3") ++ (set_attr "cc" "compare,compare,compare,compare")]) ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "nonimmediate_operand_msp430" "")) ++ (set (match_dup 0) (and:SI (match_dup 0) ++ (match_operand 2 "const_int_operand" ""))) ++ (set (pc) ++ (if_then_else (match_operator:SI 3 "equality_operator" ++ [(match_dup 0) (const_int 0)]) ++ (label_ref (match_operand 4 "" "")) ++ (pc)))] ++"(halfnibble_integer(operands[2], VOIDmode) ++ || halfnibble_constant(operands[2], VOIDmode)) ++ && dead_or_set_in_peep(2,insn, operands[0]) ++ && which_nibble(INTVAL(operands[2])) == 0" ++ [(set (cc0) ++ (unspec:SI [(match_dup 1) (match_dup 2)] 1)) ++ (set (pc) (if_then_else (match_op_dup 3 ++ [(cc0) (const_int 0)]) ++ (label_ref (match_dup 4)) ++ (pc)))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "nonimmediate_operand_msp430" "")) ++ (set (match_dup 0) (and:SI (match_dup 0) ++ (match_operand 2 "const_int_operand" ""))) ++ (set (pc) (if_then_else (match_operator:SI 3 "equality_operator" ++ [(match_dup 0) (const_int 0)]) ++ (label_ref (match_operand 4 "" "")) ++ (pc)))] ++"(halfnibble_integer(operands[2], VOIDmode) ++ || halfnibble_constant(operands[2], VOIDmode)) ++ && dead_or_set_in_peep(2,insn, operands[0]) ++ && which_nibble(INTVAL(operands[2])) == 1" ++ [(set (cc0) ++ (unspec:SI [(match_dup 1) (match_dup 2)] 2)) ++ (set (pc) (if_then_else (match_op_dup 3 ++ [(cc0) (const_int 0)]) ++ (label_ref (match_dup 4)) ++ (pc)))] ++"") ++ ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "nonimmediate_operand_msp430" "")) ++ (set (match_dup 0) (and:SI (match_dup 0) ++ (match_operand 2 "const_int_operand" ""))) ++ (set (pc) ++ (if_then_else (match_operator:HI 3 "equality_operator" ++ [(match_operand:HI 4 "register_operand" "") (const_int 0)]) ++ (label_ref (match_operand 5 "" "")) ++ (pc)))] ++"(halfnibble_integer(operands[2], VOIDmode) ++ || halfnibble_constant(operands[2], VOIDmode)) ++ && dead_or_set_in_peep(2,insn, operands[0]) ++ && which_nibble(INTVAL(operands[2])) == 1 ++ && REGNO(operands[4]) == REGNO(operands[0])+1" ++ [(set (cc0) ++ (unspec:SI [(match_dup 1) (match_dup 2)] 1)) ++ (set (pc) (if_then_else (match_op_dup 3 ++ [(cc0) (const_int 0)]) ++ (label_ref (match_dup 5)) ++ (pc)))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "nonimmediate_operand_msp430" "")) ++ (set (match_dup 0) (and:SI (match_dup 0) ++ (match_operand 2 "const_int_operand" ""))) ++ (set (pc) ++ (if_then_else (match_operator:HI 3 "equality_operator" ++ [(match_operand:HI 4 "register_operand" "") (const_int 0)]) ++ (label_ref (match_operand 5 "" "")) ++ (pc)))] ++"(halfnibble_integer(operands[2], VOIDmode) ++ || halfnibble_constant(operands[2], VOIDmode)) ++ && dead_or_set_in_peep(2,insn, operands[0]) ++ && which_nibble(INTVAL(operands[2])) == 0 ++ && REGNO(operands[4]) == REGNO(operands[0])" ++ [(set (cc0) ++ (unspec:SI [(match_dup 1) (match_dup 2)] 1)) ++ (set (pc) (if_then_else (match_op_dup 3 ++ [(cc0) (const_int 0)]) ++ (label_ref (match_dup 5)) ++ (pc)))] ++"") ++ ++;; ++;; The same for HI mode: while(smts&0xXXXX) ; ++;; ++(define_insn "*bittest" ++ [(set (cc0) ++ (unspec:HI [(match_operand:HI 0 "general_operand_msp430" "r,r,m,m") ++ (match_operand:HI 1 "general_operand_msp430" "rPR,mi,rPR,mi")] 6))] ++"" ++"bit %1,%0" ++[(set_attr "length" "1,2,2,3") ++ (set_attr "cc" "compare,compare,compare,compare")]) ++ ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "nonimmediate_operand_msp430" "")) ++ (set (match_dup 0) (and:HI (match_dup 0) ++ (match_operand 2 "const_int_operand" ""))) ++ (set (pc) (if_then_else (match_operator:HI 3 "equality_operator" ++ [(match_dup 0) (const_int 0)]) ++ (label_ref (match_operand 4 "" "")) ++ (pc)))] ++"dead_or_set_in_peep(2,insn, operands[0]) " ++ [(set (cc0) ++ (unspec:HI [(match_dup 1) (match_dup 2)] 6)) ++ (set (pc) (if_then_else (match_op_dup 3 ++ [(cc0) (const_int 0)]) ++ (label_ref (match_dup 4)) ++ (pc)))] ++"") ++ ++ ++;; The same for QI mode ++ ++(define_insn "*bittest_b" ++ [(set (cc0) ++ (unspec:QI [(match_operand:QI 0 "general_operand_msp430" "r,r,m,m") ++ (match_operand:QI 1 "general_operand_msp430" "rPR,mi,rPR,mi")] 7))] ++"" ++"bit.b %1,%0" ++[(set_attr "length" "1,2,2,3") ++ (set_attr "cc" "compare,compare,compare,compare")]) ++ ++ ++(define_peephole2 ++ [(set (match_operand:QI 0 "register_operand" "") ++ (match_operand:QI 1 "nonimmediate_operand_msp430" "")) ++ (set (match_dup 0) (and:QI (match_dup 0) ++ (match_operand 2 "const_int_operand" ""))) ++ (set (pc) (if_then_else (match_operator:QI 3 "equality_operator" ++ [(match_dup 0) (const_int 0)]) ++ (label_ref (match_operand 4 "" "")) ++ (pc)))] ++"dead_or_set_in_peep(2,insn, operands[0]) " ++ [(set (cc0) ++ (unspec:QI [(match_dup 1) (match_dup 2)] 7)) ++ (set (pc) (if_then_else (match_op_dup 3 ++ [(cc0) (const_int 0)]) ++ (label_ref (match_dup 4)) ++ (pc)))] ++"") ++ ++ ++ ++;;=========================================================================== ++ ++(define_peephole2 ++ [(set (match_operand:QI 0 "register_operand" "") ++ (match_operand:QI 1 "general_operand_msp430" "")) ++ (set (match_dup 0) ++ (minus:QI (match_dup 0) ++ (match_operand:QI 2 "general_operand_msp430" ""))) ++ (set (match_operand:QI 3 "register_operand" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0]) && 0" ++ [(set (match_dup 3) (match_dup 1)) ++ (set (match_dup 3) (minus:QI (match_dup 3) (match_dup 2)))] ++"") ++ ++ ++(define_peephole2 ++ [(set (match_operand:QI 0 "register_operand" "") ++ (match_operand:QI 1 "general_operand_msp430" "")) ++ (set (match_dup 0) ++ (plus:QI (match_dup 0) ++ (match_operand:QI 2 "general_operand_msp430" ""))) ++ (set (match_operand:QI 3 "register_operand" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0]) && 0" ++ [(set (match_dup 3) (match_dup 1)) ++ (set (match_dup 3) (plus:QI (match_dup 3) (match_dup 2)))] ++"") ++ ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "general_operand_msp430" "")) ++ (set (match_dup 0) ++ (minus:HI (match_dup 0) ++ (match_operand:HI 2 "general_operand_msp430" ""))) ++ (set (match_operand:HI 3 "register_operand" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0]) && 0" ++ [(set (match_dup 3) (match_dup 1)) ++ (set (match_dup 3) (minus:HI (match_dup 3) (match_dup 2)))] ++"") ++ ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "general_operand_msp430" "")) ++ (set (match_dup 0) ++ (plus:HI (match_dup 0) ++ (match_operand:HI 2 "general_operand_msp430" ""))) ++ (set (match_operand:HI 3 "register_operand" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0]) && 0" ++ [(set (match_dup 3) (match_dup 1)) ++ (set (match_dup 3) (plus:HI (match_dup 3) (match_dup 2)))] ++"") ++ ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "general_operand_msp430" "")) ++ (set (match_dup 0) ++ (minus:SI (match_dup 0) ++ (match_operand:SI 2 "general_operand_msp430" ""))) ++ (set (match_operand:SI 3 "register_operand" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0]) && 0" ++ [(set (match_dup 3) (match_dup 1)) ++ (set (match_dup 3) (minus:SI (match_dup 3) (match_dup 2)))] ++"") ++ ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "general_operand_msp430" "")) ++ (set (match_dup 0) ++ (plus:SI (match_dup 0) ++ (match_operand:SI 2 "general_operand_msp430" ""))) ++ (set (match_operand:SI 3 "register_operand" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0]) && 0" ++ [(set (match_dup 3) (match_dup 1)) ++ (set (match_dup 3) (plus:SI (match_dup 3) (match_dup 2)))] ++"") ++ ++ ++;; ============================================================= ++;; ++;; adjust frame pointer index ++;; ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (sign_extend:HI (match_operand:QI 1 "general_operand_msp430" ""))) ++ (set (match_dup 0) ++ (plus:HI (match_dup 0) (match_operand:HI 2 "general_operand_msp430" ""))) ++ (set (match_operand:HI 3 "register_operand" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0])" ++ [(set (match_dup 3) (sign_extend:HI (match_dup 1))) ++ (set (match_dup 3) (plus:HI (match_dup 3) (match_dup 2)))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:HI 1 "general_operand_msp430" ""))) ++ (set (match_dup 0) ++ (plus:SI (match_dup 0) (match_operand:SI 2 "general_operand_msp430" ""))) ++ (set (match_operand:SI 3 "register_operand" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0])" ++ [(set (match_dup 3) (sign_extend:SI (match_dup 1))) ++ (set (match_dup 3) (plus:SI (match_dup 3) (match_dup 2)))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (sign_extend:HI (match_operand:QI 1 "general_operand_msp430" ""))) ++ (set (match_dup 0) ++ (minus:HI (match_dup 0) (match_operand:HI 2 "general_operand_msp430" ""))) ++ (set (match_operand:HI 3 "register_operand" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0])" ++ [(set (match_dup 3) (sign_extend:HI (match_dup 1))) ++ (set (match_dup 3) (minus:HI (match_dup 3) (match_dup 2)))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:HI 1 "general_operand_msp430" ""))) ++ (set (match_dup 0) ++ (minus:SI (match_dup 0) (match_operand:SI 2 "general_operand_msp430" ""))) ++ (set (match_operand:SI 3 "register_operand" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0])" ++ [(set (match_dup 3) (sign_extend:SI (match_dup 1))) ++ (set (match_dup 3) (minus:SI (match_dup 3) (match_dup 2)))] ++"") ++ ++;; ============================================================= ++;; mov & 'and' ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operand:HI 1 "nonimmediate_operand_msp430" "")) ++ (set (match_dup 0) ++ (and:HI (match_dup 0) ++ (match_operand:HI 2 "general_operand_msp430" ""))) ++ (set (match_dup 1) (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0])" ++ [(set (match_dup 1) ++ (and:HI (match_dup 1) (match_dup 2)))] ++"") ++ ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "nonimmediate_operand_msp430" "")) ++ (set (match_dup 0) ++ (and:SI (match_dup 0) ++ (match_operand:SI 2 "general_operand_msp430" ""))) ++ (set (match_dup 1) (match_dup 0))] ++"dead_or_set_in_peep(2,insn, operands[0])" ++ [(set (match_dup 1) ++ (and:SI (match_dup 1) (match_dup 2)))] ++"") ++ ++ ++ ++;; ============================================================= ++;; SWAP BYTES (should be a pattern for: ++;; r = (a<<8)|(a>>8); ++ ++(define_insn "swpb" ++ [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=rR,m") ++ (unspec:HI [(match_operand:HI 1 "nonimmediate_operand_msp430" "0,0")] 4))] ++"" ++"swpb %0" ++[(set_attr "length" "1,2") ++ (set_attr "cc" "clobber,clobber")]) ++ ++;; ++;; after mult and stuff ++;; ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (reg:SI 14)) ++ (set (match_operand:SI 1 "nonimmediate_operand_msp430" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(1,insn,operands[0])" ++ [(set (match_dup 1) (reg:SI 14))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (reg:HI 14)) ++ (set (match_operand:HI 1 "nonimmediate_operand_msp430" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(1,insn,operands[0])" ++ [(set (match_dup 1) (reg:HI 14))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (reg:SI 12)) ++ (set (match_operand:SI 1 "nonimmediate_operand_msp430" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(1,insn,operands[0])" ++ [(set (match_dup 1) (reg:SI 12))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (reg:HI 12)) ++ (set (match_operand:HI 1 "nonimmediate_operand_msp430" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(1,insn,operands[0])" ++ [(set (match_dup 1) (reg:HI 12))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:QI 1 "general_operand_msp430" ""))) ++ (set (match_operand:SI 2 "nonimmediate_operand_msp430" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(1,insn,operands[0])" ++ [(set (match_dup 2) (sign_extend:SI (match_dup 1)))] ++"") ++ ++(define_peephole2 ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:HI 1 "general_operand_msp430" ""))) ++ (set (match_operand:SI 2 "nonimmediate_operand_msp430" "") ++ (match_dup 0))] ++"dead_or_set_in_peep(1,insn,operands[0])" ++ [(set (match_dup 2) (sign_extend:SI (match_dup 1)))] ++"") ++ ++ ++;; ============================================================= ++ ++(define_peephole ++ [(set (match_operand:HI 0 "register_operand" "") ++ (sign_extend:HI (match_operand:QI 1 "register_operand" ""))) ++ (set (match_operand:HI 2 "register_operand" "") ++ (plus:HI (match_dup 2) (match_dup 0)))] ++"dead_or_set_in_peep(1,insn,operands[0])" ++"sxt %1 ++ add %1, %2" ++[(set_attr "length" "3") ++ (set_attr "cc" "clobber")]) ++ ++ ++(define_peephole ++ [(set (match_operand:HI 0 "register_operand" "") ++ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand_msp430" ""))) ++ (set (match_operand:HI 2 "register_operand" "") (match_dup 0))] ++"dead_or_set_in_peep(1,insn,operands[0])" ++"mov.b %1, %2 ++ sxt %2" ++[(set_attr "length" "2") ++ (set_attr "cc" "clobber")]) ++ ++;; ============================================================= ++;; a = (uint16_t)( (uint8_t)SFR ) << 8; ++;; (inderect_jump + 50) ++(define_peephole ++ [(set (match_operand:QI 0 "register_operand" "") ++ (match_operand:QI 1 "memory_operand_msp430" "m")) ++ (set (match_operand:HI 2 "register_operand" "") ++ (ashift:HI (match_dup 2) (const_int 8)))] ++ "REGNO(operands[0]) == REGNO(operands[2])" ++"mov.b %1, %0 ++ swpb %2" ++[(set_attr "length" "3") ++ (set_attr "cc" "clobber")]) ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") ++ (ior:HI (match_dup 0) ++ (match_operand:HI 1 "register_operand" ""))) ++ (set (match_operand:SI 2 "register_operand" "") ++ (match_operand:SI 3 "register_operand" ""))] ++"(REGNO(operands[0]) == REGNO(operands[2]) ++ && REGNO(operands[3])+1 == REGNO(operands[0]))" ++ [(set (match_dup 1) ++ (ior:HI (match_dup 1) ++ (match_dup 0))) ++ (set (subreg:HI (match_dup 2) 0) ++ (subreg:HI (match_dup 3) 0))] ++"") ++ ++ ++ ++;; ============================================================= ++;; combine ior and mov. ++;; ++(define_peephole2 ++[(set (match_operand:QI 0 "register_operand" "") ++ (ior:QI (match_dup 0) ++ (match_operand:QI 1 "nonimmediate_operand_msp430" ""))) ++ (set (match_dup 1) (match_dup 0))] ++"dead_or_set_in_peep(1,insn,operands[0])" ++[(set (match_dup 1) (ior:QI (match_dup 1) (match_dup 0)))] ++"") ++ ++(define_peephole2 ++[(set (match_operand:HI 0 "register_operand" "") ++ (ior:HI (match_dup 0) ++ (match_operand:HI 1 "nonimmediate_operand_msp430" ""))) ++ (set (match_dup 1) (match_dup 0))] ++"dead_or_set_in_peep(1,insn,operands[0])" ++[(set (match_dup 1) (ior:HI (match_dup 1) (match_dup 0)))] ++"") ++ ++(define_peephole2 ++[(set (match_operand:SI 0 "register_operand" "") ++ (ior:SI (match_dup 0) ++ (match_operand:SI 1 "nonimmediate_operand_msp430" ""))) ++ (set (match_dup 1) (match_dup 0))] ++"dead_or_set_in_peep(1,insn,operands[0])" ++[(set (match_dup 1) (ior:SI (match_dup 1) (match_dup 0)))] ++"") ++ ++(define_peephole2 ++[(set (match_operand:DI 0 "register_operand" "") ++ (ior:DI (match_dup 0) ++ (match_operand:DI 1 "nonimmediate_operand_msp430" ""))) ++ (set (match_dup 1) (match_dup 0))] ++"dead_or_set_in_peep(1,insn,operands[0])" ++[(set (match_dup 1) (ior:DI (match_dup 1) (match_dup 0)))] ++"") ++ ++ ++ +diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/msp430-protos.h gcc-3.2.3/gcc/config/msp430/msp430-protos.h +--- gcc-3.2.3.orig/gcc/config/msp430/msp430-protos.h 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-3.2.3/gcc/config/msp430/msp430-protos.h 2008-08-22 09:17:00.000000000 -0600 +@@ -0,0 +1,301 @@ ++/* Prototypes for exported functions defined in msp430.c ++ ++ Copyright (C) 2000, 2001 Free Software Foundation, Inc. ++ Contributed by Dmitry Diky ++ ++ This file is part of GNU CC. ++ ++ GNU CC is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, or (at your option) ++ any later version. ++ ++ GNU CC is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with GNU CC; see the file COPYING. If not, write to ++ the Free Software Foundation, 59 Temple Place - Suite 330, ++ Boston, MA 02111-1307, USA. */ ++ ++ ++extern void bootloader_section PARAMS ((void)); ++extern void infomem_section PARAMS ((void)); ++ ++extern void asm_file_start PARAMS ((FILE *file)); ++extern void asm_file_end PARAMS ((FILE *file)); ++extern void msp430_init_once PARAMS ((void)); ++extern void msp430_override_options PARAMS ((void)); ++extern void function_prologue PARAMS ((FILE *file, int size)); ++extern void function_epilogue PARAMS ((FILE *file, int size)); ++extern void gas_output_limited_string PARAMS ((FILE *file, const char *str)); ++extern void gas_output_ascii PARAMS ((FILE *file, const char *str, ++ size_t length)); ++extern void order_regs_for_local_alloc PARAMS ((void)); ++extern void msp430_trampoline_template PARAMS ((FILE *fd)); ++ ++ ++extern int frame_pointer_required_p PARAMS ((void)); ++extern int msp430_empty_epilogue PARAMS ((void)); ++ ++int msp430_regno_ok_for_base_p PARAMS ((int)); ++ ++ ++#ifdef HAVE_MACHINE_MODES ++extern int msp430_hard_regno_mode_ok PARAMS ((int regno, ++ enum machine_mode mode)); ++#endif ++ ++extern int initial_elimination_offset PARAMS ((int, int)); ++ ++ ++ ++#ifdef TREE_CODE ++extern void asm_output_external PARAMS ((FILE *file, tree decl, ++ char *name)); ++extern void unique_section PARAMS ((tree decl, int reloc)); ++extern void encode_section_info PARAMS ((tree decl)); ++extern void asm_output_section_name PARAMS ((FILE *file, tree decl, ++ const char *name, ++ int reloc)); ++extern int valid_machine_type_attribute PARAMS ((tree type, tree attributes, ++ tree identifier, ++ tree args)); ++extern int valid_machine_decl_attribute PARAMS ((tree decl, tree attributes, ++ tree attr, tree args)); ++extern void asm_declare_function_name PARAMS ((FILE *, char *, tree)); ++unsigned int msp430_section_type_flags PARAMS (( tree DECL, const char *NAME, int RELOC)); ++ ++ ++#ifdef RTX_CODE /* inside TREE_CODE */ ++extern rtx msp430_function_value PARAMS ((tree type, tree func)); ++extern void init_cumulative_args PARAMS ((CUMULATIVE_ARGS *cum, ++ tree fntype, rtx libname, ++ int indirect)); ++extern rtx function_arg PARAMS ((CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, ++ tree type, int named)); ++extern void init_cumulative_incoming_args PARAMS ((CUMULATIVE_ARGS *cum, ++ tree fntype, rtx libname)); ++extern rtx function_incoming_arg PARAMS ((CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, ++ tree type, int named)); ++ ++ ++ ++#endif /* RTX_CODE inside TREE_CODE */ ++ ++#ifdef HAVE_MACHINE_MODES /* inside TREE_CODE */ ++extern void function_arg_advance PARAMS ((CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ int named)); ++#endif /* HAVE_MACHINE_MODES inside TREE_CODE*/ ++#endif /* TREE_CODE */ ++ ++#ifdef RTX_CODE ++ ++ ++extern enum rtx_code msp430_canonicalize_comparison PARAMS ((enum rtx_code,rtx *,rtx *)); ++ ++ ++extern void msp430_emit_cbranch PARAMS ((enum rtx_code, rtx)); ++extern void msp430_emit_cset PARAMS ((enum rtx_code, rtx)); ++ ++extern int dead_or_set_in_peep PARAMS ((int, rtx, rtx)); ++extern void msp430_initialize_trampoline PARAMS ((rtx,rtx,rtx)); ++ ++ ++extern enum reg_class msp430_reg_class_from_letter PARAMS ((int)); ++extern enum reg_class preferred_reload_class PARAMS ((rtx,enum reg_class)); ++enum reg_class msp430_regno_reg_class PARAMS ((int)); ++ ++extern RTX_CODE followed_compare_condition PARAMS ((rtx)); ++ ++extern const char * msp430_movesi_code PARAMS ((rtx insn, rtx operands[], int *l)); ++extern const char * msp430_movedi_code PARAMS ((rtx insn, rtx operands[], int *l)); ++extern const char * msp430_addsi_code PARAMS ((rtx insn, rtx operands[], int *l)); ++extern const char * msp430_subsi_code PARAMS ((rtx insn, rtx operands[], int *l)); ++extern const char * msp430_andsi_code PARAMS ((rtx insn, rtx operands[], int *l)); ++extern const char * msp430_iorsi_code PARAMS ((rtx insn, rtx operands[], int *l)); ++extern const char * msp430_xorsi_code PARAMS ((rtx insn, rtx operands[], int *l)); ++extern const char * msp430_adddi_code PARAMS ((rtx insn, rtx operands[], int *l)); ++extern const char * msp430_subdi_code PARAMS ((rtx insn, rtx operands[], int *l)); ++extern const char * msp430_anddi_code PARAMS ((rtx insn, rtx operands[], int *l)); ++extern const char * msp430_iordi_code PARAMS ((rtx insn, rtx operands[], int *l)); ++extern const char * msp430_xordi_code PARAMS ((rtx insn, rtx operands[], int *l)); ++ ++ ++extern int zero_shifted PARAMS ((rtx )); ++extern int indexed_location PARAMS ((rtx )); ++ ++ ++extern int regsi_ok_safe PARAMS ((rtx operands[])); ++extern int regsi_ok_clobber PARAMS ((rtx operands[])); ++extern int regdi_ok_safe PARAMS ((rtx operands[])); ++extern int regdi_ok_clobber PARAMS ((rtx operands[])); ++extern int sameoperand PARAMS ((rtx operands[], int)); ++ ++extern int general_operand_msp430 PARAMS ((rtx, enum machine_mode )); ++extern int nonimmediate_operand_msp430 PARAMS ((rtx, enum machine_mode )); ++extern int memory_operand_msp430 PARAMS ((rtx, enum machine_mode )); ++extern int halfnibble_constant PARAMS ((rtx, enum machine_mode )); ++extern int halfnibble_integer PARAMS ((rtx, enum machine_mode )); ++extern int halfnibble_constant_shift PARAMS ((rtx, enum machine_mode )); ++extern int halfnibble_integer_shift PARAMS ((rtx, enum machine_mode )); ++extern int which_nibble PARAMS ((int)); ++extern int which_nibble_shift PARAMS ((int)); ++ ++ ++extern void asm_output_external_libcall PARAMS ((FILE *file, rtx symref)); ++extern int legitimate_address_p PARAMS ((enum machine_mode mode, rtx x, ++ int strict)); ++extern int compare_diff_p PARAMS ((rtx insn)); ++ ++extern int emit_indexed_arith PARAMS ((rtx insn, rtx operands[], int, const char *, int)); ++ ++extern const char * msp430_emit_abssi PARAMS ((rtx insn, rtx operands[], int *l)); ++extern const char * msp430_emit_absdi PARAMS ((rtx insn, rtx operands[], int *l)); ++ ++extern const char * msp430_emit_indexed_add2 PARAMS ((rtx insn, rtx op[], int *l)); ++extern const char * msp430_emit_indexed_add4 PARAMS ((rtx insn, rtx op[], int *l)); ++ ++extern const char * msp430_emit_indexed_sub2 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_indexed_sub4 PARAMS ((rtx insn, rtx operands[], int *len)); ++ ++extern const char * msp430_emit_indexed_and2 PARAMS ((rtx insn, rtx op[], int *l)); ++extern const char * msp430_emit_indexed_and4 PARAMS ((rtx insn, rtx op[], int *l)); ++extern const char * msp430_emit_immediate_and2 PARAMS ((rtx insn, rtx op[], int *l)); ++extern const char * msp430_emit_immediate_and4 PARAMS ((rtx insn, rtx op[], int *l)); ++ ++extern const char * msp430_emit_indexed_ior2 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_indexed_ior4 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_immediate_ior2 PARAMS ((rtx insn, rtx op[], int *l)); ++extern const char * msp430_emit_immediate_ior4 PARAMS ((rtx insn, rtx op[], int *l)); ++ ++ ++extern int msp430_emit_indexed_mov PARAMS ((rtx insn, rtx operands[], int len, const char *)); ++extern const char * movstrsi_insn PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * clrstrsi_insn PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * movstrhi_insn PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * clrstrhi_insn PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_indexed_mov2 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_indexed_mov4 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * movsisf_regmode PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * movdidf_regmode PARAMS ((rtx insn, rtx operands[], int *len)); ++ ++ ++extern int is_shift_better_in_reg PARAMS ((rtx operands[])); ++extern int msp430_emit_shift_cnt PARAMS ((int (*funct)(rtx, int, int), const char *, rtx insn, rtx operands[], int *len, int)); ++extern const char * msp430_emit_ashlqi3 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_ashlhi3 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_ashlsi3 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_ashldi3 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_ashrqi3 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_ashrhi3 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_ashrsi3 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_ashrdi3 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_lshrqi3 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_lshrhi3 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_lshrsi3 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_lshrdi3 PARAMS ((rtx insn, rtx operands[], int *len)); ++ ++extern const char * signextendqihi PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * signextendqisi PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * signextendqidi PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * signextendhisi PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * signextendhidi PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * signextendsidi PARAMS ((rtx insn, rtx operands[], int *len)); ++ ++extern const char * msp430_emit_indexed_sub2 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_indexed_sub4 PARAMS ((rtx insn, rtx operands[], int *len)); ++ ++extern const char * msp430_emit_indexed_xor2 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_indexed_xor4 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_indexed_xor2_3 PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_emit_indexed_xor4_3 PARAMS ((rtx insn, rtx operands[], int *len)); ++ ++extern const char * zeroextendqihi PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * zeroextendqisi PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * zeroextendqidi PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * zeroextendhisi PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * zeroextendhidi PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * zeroextendsidi PARAMS ((rtx insn, rtx operands[], int *len)); ++ ++extern const char * msp430_emit_blt0si PARAMS ((rtx operands[], int len)); ++extern const char * msp430_emit_beq PARAMS ((rtx operands[], int len)); ++extern const char * msp430_emit_bne PARAMS ((rtx operands[], int len)); ++extern const char * msp430_emit_bgt PARAMS ((rtx operands[], int len)); ++extern const char * msp430_emit_bgtu PARAMS ((rtx operands[], int len)); ++extern const char * msp430_emit_blt PARAMS ((rtx operands[], int len)); ++extern const char * msp430_emit_bltu PARAMS ((rtx operands[], int len)); ++extern const char * msp430_emit_bge PARAMS ((rtx operands[], int len)); ++extern const char * msp430_emit_bgeu PARAMS ((rtx operands[], int len)); ++extern const char * msp430_emit_ble PARAMS ((rtx operands[], int len)); ++extern const char * msp430_emit_bleu PARAMS ((rtx operands[], int len)); ++ ++extern const char * msp430_pushsisf PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_pushdi PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_pushhi PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char * msp430_pushqi PARAMS ((rtx insn, rtx operands[], int *len)); ++ ++extern const char * msp430_emit_return PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char *msp430_cbranch PARAMS ((rtx insn, rtx operands[], int *len)); ++extern const char *msp430_cset PARAMS ((rtx insn, rtx operands[], int *len)); ++ ++extern void notice_update_cc PARAMS ((rtx body, rtx insn)); ++extern int msp430_peep2_scratch_safe PARAMS ((rtx reg_rtx)); ++extern int test_hard_reg_class PARAMS ((enum reg_class class, rtx x)); ++extern void machine_dependent_reorg PARAMS ((rtx first_insn)); ++extern void msp430_output_addr_vec_elt PARAMS ((FILE *stream, int value)); ++extern void final_prescan_insn PARAMS ((rtx insn, rtx *operand, ++ int num_operands)); ++extern int adjust_insn_length PARAMS ((rtx insn, int len)); ++ ++ ++extern int msp430_address_cost PARAMS ((rtx x)); ++extern int extra_constraint PARAMS ((rtx x, int c)); ++extern rtx legitimize_address PARAMS ((rtx x, rtx oldx, ++ enum machine_mode mode)); ++extern rtx msp430_libcall_value PARAMS ((enum machine_mode mode)); ++extern int default_rtx_costs PARAMS ((rtx X, RTX_CODE code, ++ RTX_CODE outer_code)); ++extern void asm_output_char PARAMS ((FILE *file, rtx value)); ++extern void asm_output_short PARAMS ((FILE *file, rtx value)); ++extern void asm_output_byte PARAMS ((FILE *file, int value)); ++ ++extern void print_operand PARAMS ((FILE *file, rtx x, int code)); ++extern void print_operand_address PARAMS ((FILE *file, rtx addr)); ++extern int reg_unused_after PARAMS ((rtx insn, rtx reg)); ++extern int msp430_jump_dist PARAMS ((rtx x, rtx insn)); ++extern int call_insn_operand PARAMS ((rtx op, enum machine_mode mode)); ++extern int msp430_branch_mode PARAMS ((rtx x, rtx insn)); ++ ++extern int msp430_easy_mul PARAMS ((rtx [],int)); ++extern int msp430_mul3_guard PARAMS ((rtx [], int )); ++extern int msp430_umul3_guard PARAMS ((rtx [], int )); ++extern int msp430_mulhisi_guard PARAMS ((rtx [] )); ++extern int msp430_umulhisi_guard PARAMS ((rtx [] )); ++extern int msp430_ashlhi3 PARAMS ((rtx [] )); ++extern int msp430_ashlsi3 PARAMS ((rtx [] )); ++extern int msp430_ashrhi3 PARAMS ((rtx [] )); ++extern int msp430_ashrsi3 PARAMS ((rtx [] )); ++extern int msp430_lshrhi3 PARAMS ((rtx [] )); ++extern int msp430_lshrsi3 PARAMS ((rtx [] )); ++ ++ ++#endif /* RTX_CODE */ ++ ++#ifdef HAVE_MACHINE_MODES ++extern int class_max_nregs PARAMS ((enum reg_class class, ++ enum machine_mode mode)); ++#endif /* HAVE_MACHINE_MODES */ ++ ++#ifdef REAL_VALUE_TYPE ++ ++extern void asm_output_float PARAMS ((FILE *file, REAL_VALUE_TYPE n)); ++ ++#endif ++ ++ +diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/t-msp430 gcc-3.2.3/gcc/config/msp430/t-msp430 +--- gcc-3.2.3.orig/gcc/config/msp430/t-msp430 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-3.2.3/gcc/config/msp430/t-msp430 2008-08-22 09:17:00.000000000 -0600 +@@ -0,0 +1,116 @@ ++# Specific names for MSP430 tools ++AR_FOR_TARGET = msp430-ar ++RANLIB_FOR_TARGET = msp430-ranlib ++NM_FOR_TARGET = msp430-nm ++ ++CROSS_LIBGCC1 = libgcc1-asm.a ++LIB1ASMSRC = msp430/libgcc.S ++LIB1ASMFUNCS = _cmpdi2 \ ++ _cmpsf2 \ ++ __stop_progExec__ \ ++ _mulqi3 \ ++ _mulhi3 \ ++ _mulsi3 \ ++ _mulsi3hw \ ++ _umulqihi3 \ ++ _umulhisi3 \ ++ _mulqihi3 \ ++ _mulhisi3 \ ++ _udivmodqi4 \ ++ _divmodqi4 \ ++ _udivmodhi4 \ ++ _divmodhi4 \ ++ _udivmodsi4 \ ++ _divmodsi4 \ ++ _reset_vector__ \ ++ __prologue_saver \ ++ __epilogue_restorer \ ++ __epilogue_restorer_intr \ ++ _udivmoddi3_parts \ ++ _udivdi3 \ ++ _umoddi3 \ ++ _divdi3 \ ++ _moddi3 \ ++ _muldi3 \ ++ __low_level_init \ ++ __init_stack \ ++ _copy_data \ ++ _clear_bss \ ++ _ctors \ ++ __jump_to_main \ ++ _dtors ++ ++ ++ ++# libgcc... ++LIBGCC1_TEST = ++ ++# We do not have the DF type. ++# Most of the C functions in libgcc2 use almost all registers, ++TARGET_LIBGCC2_CFLAGS = -DDF=SF -Dinhibit_libc -g ++ ++fp-bit.c: $(srcdir)/config/fp-bit.c $(srcdir)/config/msp430/t-msp430 ++ echo '#define FLOAT' > fp-bit.c ++ echo '#define FLOAT_ONLY' >> fp-bit.c ++ echo '#define CMPtype HItype' >> fp-bit.c ++ echo '#define DF SF' >> fp-bit.c ++ echo '#define DI SI' >> fp-bit.c ++ echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c ++ echo '#define SMALL_MACHINE' >> fp-bit.c ++ cat $(srcdir)/config/fp-bit.c >> fp-bit.c ++ ++FPBIT = fp-bit.c ++ ++MULTILIB_OPTIONS = mmcu=msp1/mmcu=msp2 ++MULTILIB_DIRNAMES = msp1 msp2 ++ ++ ++MULTILIB_MATCHES = \ ++ mmcu?msp1=mmcu?msp430x110 mmcu?msp1=mmcu?msp430x112 \ ++ mmcu?msp1=mmcu?msp430x1101 mmcu?msp1=mmcu?msp430x1111 mmcu?msp1=mmcu?msp430x1121 \ ++ mmcu?msp1=mmcu?msp430x1122 mmcu?msp1=mmcu?msp430x1132 \ ++ mmcu?msp1=mmcu?msp430x122 mmcu?msp1=mmcu?msp430x123 \ ++ mmcu?msp1=mmcu?msp430x1222 mmcu?msp1=mmcu?msp430x1232 \ ++ mmcu?msp1=mmcu?msp430x133 mmcu?msp1=mmcu?msp430x135 \ ++ mmcu?msp1=mmcu?msp430x1331 mmcu?msp1=mmcu?msp430x1351 \ ++ mmcu?msp2=mmcu?msp430x147 mmcu?msp2=mmcu?msp430x148 mmcu?msp2=mmcu?msp430x149 \ ++ mmcu?msp2=mmcu?msp430x1471 mmcu?msp2=mmcu?msp430x1481 mmcu?msp2=mmcu?msp430x1491 \ ++ mmcu?msp1=mmcu?msp430x155 mmcu?msp1=mmcu?msp430x156 mmcu?msp1=mmcu?msp430x157 \ ++ mmcu?msp2=mmcu?msp430x167 mmcu?msp2=mmcu?msp430x168 mmcu?msp2=mmcu?msp430x169 \ ++ mmcu?msp2=mmcu?msp430x1610 mmcu?msp2=mmcu?msp430x1611 mmcu?msp2=mmcu?msp430x1612 \ ++ mmcu?msp1=mmcu?msp430x2001 mmcu?msp1=mmcu?msp430x2011 \ ++ mmcu?msp1=mmcu?msp430x2002 mmcu?msp1=mmcu?msp430x2012 \ ++ mmcu?msp1=mmcu?msp430x2003 mmcu?msp1=mmcu?msp430x2013 \ ++ mmcu?msp1=mmcu?msp430x2101 mmcu?msp1=mmcu?msp430x2111 mmcu?msp1=mmcu?msp430x2121 \ ++ mmcu?msp1=mmcu?msp430x2131 \ ++ mmcu?msp1=mmcu?msp430x2232 mmcu?msp1=mmcu?msp430x2252 mmcu?msp1=mmcu?msp430x2272 \ ++ mmcu?msp1=mmcu?msp430x2234 mmcu?msp1=mmcu?msp430x2254 mmcu?msp1=mmcu?msp430x2274 \ ++ mmcu?msp2=mmcu?msp430x247 mmcu?msp2=mmcu?msp430x248 mmcu?msp2=mmcu?msp430x249 \ ++ mmcu?msp2=mmcu?msp430x2410 \ ++ mmcu?msp2=mmcu?msp430x2471 mmcu?msp2=mmcu?msp430x2481 mmcu?msp2=mmcu?msp430x2491 \ ++ mmcu?msp2=mmcu?msp430x2416 mmcu?msp2=mmcu?msp430x2417 mmcu?msp2=mmcu?msp430x2418 \ ++ mmcu?msp2=mmcu?msp430x2419 \ ++ mmcu?msp2=mmcu?msp430x2616 mmcu?msp2=mmcu?msp430x2617 mmcu?msp2=mmcu?msp430x2618 \ ++ mmcu?msp2=mmcu?msp430x2619 \ ++ mmcu?msp1=mmcu?msp430x311 mmcu?msp1=mmcu?msp430x312 mmcu?msp1=mmcu?msp430x313 \ ++ mmcu?msp1=mmcu?msp430x314 mmcu?msp1=mmcu?msp430x315 \ ++ mmcu?msp1=mmcu?msp430x323 mmcu?msp1=mmcu?msp430x325 \ ++ mmcu?msp2=mmcu?msp430x336 mmcu?msp2=mmcu?msp430x337 \ ++ mmcu?msp1=mmcu?msp430x412 mmcu?msp1=mmcu?msp430x413 \ ++ mmcu?msp1=mmcu?msp430x415 mmcu?msp1=mmcu?msp430x417 \ ++ mmcu?msp2=mmcu?msp430x423 mmcu?msp2=mmcu?msp430x425 mmcu?msp2=mmcu?msp430x427 \ ++ mmcu?msp1=mmcu?msp430x4250 mmcu?msp1=mmcu?msp430x4260 mmcu?msp1=mmcu?msp430x4270 \ ++ mmcu?msp2=mmcu?msp430xE423 mmcu?msp2=mmcu?msp430xE425 mmcu?msp2=mmcu?msp430xE427 \ ++ mmcu?msp1=mmcu?msp430xW423 mmcu?msp1=mmcu?msp430xW425 mmcu?msp1=mmcu?msp430xW427 \ ++ mmcu?msp1=mmcu?msp430xG437 mmcu?msp1=mmcu?msp430xG438 mmcu?msp1=mmcu?msp430xG439 \ ++ mmcu?msp1=mmcu?msp430x435 mmcu?msp1=mmcu?msp430x436 mmcu?msp1=mmcu?msp430x437 \ ++ mmcu?msp2=mmcu?msp430x447 mmcu?msp2=mmcu?msp430x448 mmcu?msp2=mmcu?msp430x449 \ ++ mmcu?msp2=mmcu?msp430xG4616 mmcu?msp2=mmcu?msp430xG4617 mmcu?msp2=mmcu?msp430xG4618 \ ++ mmcu?msp2=mmcu?msp430xG4619 ++ ++MULTILIB_EXCEPTIONS = ++ ++LIBGCC = stmp-multilib ++INSTALL_LIBGCC = install-multilib ++ ++##STMP_FIXINC = +diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/xm-msp430.h gcc-3.2.3/gcc/config/msp430/xm-msp430.h +--- gcc-3.2.3.orig/gcc/config/msp430/xm-msp430.h 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-3.2.3/gcc/config/msp430/xm-msp430.h 2008-08-22 09:17:00.000000000 -0600 +@@ -0,0 +1 @@ ++#include "tm.h" +diff -urN -x CVS gcc-3.2.3.orig/gcc/config.gcc gcc-3.2.3/gcc/config.gcc +--- gcc-3.2.3.orig/gcc/config.gcc 2003-02-28 11:38:19.000000000 -0700 ++++ gcc-3.2.3/gcc/config.gcc 2008-08-22 09:17:00.000000000 -0600 +@@ -2667,6 +2667,8 @@ + ;; + mmix-knuth-mmixware) + ;; ++msp430-*-*) ++ ;; + mn10200-*-*) + float_format=i32 + tm_file="dbxelf.h elfos.h svr4.h ${tm_file}" +diff -urN -x CVS gcc-3.2.3.orig/gcc/cp/decl.c gcc-3.2.3/gcc/cp/decl.c +--- gcc-3.2.3.orig/gcc/cp/decl.c 2003-03-17 16:16:55.000000000 -0700 ++++ gcc-3.2.3/gcc/cp/decl.c 2008-08-22 09:17:00.000000000 -0600 +@@ -454,9 +454,9 @@ + /* The binding level currently in effect. */ + + #define current_binding_level \ +- (cfun && cp_function_chain->bindings \ +- ? cp_function_chain->bindings \ +- : scope_chain->bindings) ++ (*(cfun && cp_function_chain->bindings \ ++ ? &cp_function_chain->bindings \ ++ : &scope_chain->bindings)) + + /* The binding level of the current class, if any. */ + +diff -urN -x CVS gcc-3.2.3.orig/gcc-3.2.3-cygwin.patch gcc-3.2.3/gcc-3.2.3-cygwin.patch +--- gcc-3.2.3.orig/gcc-3.2.3-cygwin.patch 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-3.2.3/gcc-3.2.3-cygwin.patch 2008-08-22 09:17:00.000000000 -0600 +@@ -0,0 +1,57 @@ ++--- gcc-3.2.3.orig/ggc/gcc-page.c 2003-05-06 15:37:04 +0800 +++++ gcc-3.2.3/gcc/ggc-page.c 2003-05-06 15:37:54 +0800 ++@@ -495,28 +495,35 @@ ++ } ++ printf ("NULL\n"); ++ fflush (stdout); ++ } ++ +++static char *last_allocated_page = NULL; +++ ++ #ifdef USING_MMAP ++ /* Allocate SIZE bytes of anonymous memory, preferably near PREF, ++ (if non-null). The ifdef structure here is intended to cause a ++ compile error unless exactly one of the HAVE_* is defined. */ ++ ++ static inline char * ++ alloc_anon (pref, size) ++ char *pref ATTRIBUTE_UNUSED; ++ size_t size; ++ { +++ char *page; +++ +++ do { ++ #ifdef HAVE_MMAP_ANON ++- char *page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE, ++- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +++ page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE, +++ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ++ #endif ++ #ifdef HAVE_MMAP_DEV_ZERO ++- char *page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE, ++- MAP_PRIVATE, G.dev_zero_fd, 0); +++ page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE, +++ MAP_PRIVATE, G.dev_zero_fd, 0); ++ #endif +++ } while (page == last_allocated_page); +++ last_allocated_page = page; ++ ++ if (page == (char *) MAP_FAILED) ++ { ++ perror ("virtual memory exhausted"); ++ exit (FATAL_EXIT_CODE); ++--- gcc-3.2.3.orig/gcc/fixinc/gnu-regex.c 2003-05-06 15:37:04 +0800 +++++ gcc-3.2.3/gcc/fixinc/gnu-regex.c 2003-05-06 15:37:42 +0800 ++@@ -5718,11 +5718,11 @@ ++ if (errbuf_size != 0) ++ { ++ if (msg_size > errbuf_size) ++ { ++ #if defined HAVE_MEMPCPY || defined _LIBC ++- *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0'; +++ *((char *) mempcpy (errbuf, msg, errbuf_size - 1)) = '\0'; ++ #else ++ memcpy (errbuf, msg, errbuf_size - 1); ++ errbuf[errbuf_size - 1] = 0; ++ #endif ++ } +diff -urN -x CVS gcc-3.2.3.orig/include/obstack.h gcc-3.2.3/include/obstack.h +--- gcc-3.2.3.orig/include/obstack.h 2001-03-14 12:44:38.000000000 -0700 ++++ gcc-3.2.3/include/obstack.h 2008-08-22 09:17:00.000000000 -0600 +@@ -423,7 +423,8 @@ + ({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + sizeof (void *) > __o->chunk_limit) \ + _obstack_newchunk (__o, sizeof (void *)); \ +- *((void **)__o->next_free)++ = ((void *)datum); \ ++ *((void **)__o->next_free) = ((void *)datum); \ ++ __o->next_free += sizeof (void *); \ + (void) 0; }) + + # define obstack_int_grow(OBSTACK,datum) \ +diff -urN -x CVS gcc-3.2.3.orig/THIS_ACTUALLY_WORKS_WITH_VERSION_3_2_AND_BELOW_2002_09_02 gcc-3.2.3/THIS_ACTUALLY_WORKS_WITH_VERSION_3_2_AND_BELOW_2002_09_02 +--- gcc-3.2.3.orig/THIS_ACTUALLY_WORKS_WITH_VERSION_3_2_AND_BELOW_2002_09_02 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-3.2.3/THIS_ACTUALLY_WORKS_WITH_VERSION_3_2_AND_BELOW_2002_09_02 2008-08-22 09:17:00.000000000 -0600 +@@ -0,0 +1,6 @@ ++------------------------------------------------------------------- ++this directory works with gcc-3.2.x (tested with 3.2.3) ++ ++The mismatch between the numbering of gcc and this directory is an ++historical accident. ++------------------------------------------------------------------- diff --git a/debian/patches/003-mspgcc-3.2.3-20080819-FUNCTION.dpatch b/debian/patches/003-mspgcc-3.2.3-20080819-FUNCTION.dpatch new file mode 100755 index 00000000..1600143e --- /dev/null +++ b/debian/patches/003-mspgcc-3.2.3-20080819-FUNCTION.dpatch @@ -0,0 +1,31 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 002-mspgcc-3.2.3-20080819-FUNCTION.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: __FUNCTION__ patch from mspgcc 3.2.3 CVS 20080819 + +@DPATCH@ + +--- gcc-3.2.3.orig/gcc/c-common.c 2002-12-01 12:19:08.000000000 -0600 ++++ gcc-3.2.3/gcc/c-common.c 2006-03-18 22:08:27.000000000 -0600 +@@ -581,18 +581,20 @@ + if (TREE_TYPE (t) == wchar_array_type_node) + { + wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes); + wide_flag = 1; + } + else + { + length += (TREE_STRING_LENGTH (t) - 1); ++#if 0 + if (C_ARTIFICIAL_STRING_P (t) && !in_system_header) + warning ("concatenation of string literals with __FUNCTION__ is deprecated"); ++#endif + } + } + + /* If anything is wide, the non-wides will be converted, + which makes them take more space. */ + if (wide_flag) + length = length * wchar_bytes + wide_length; + diff --git a/debian/patches/00list b/debian/patches/00list new file mode 100644 index 00000000..bc2568ba --- /dev/null +++ b/debian/patches/00list @@ -0,0 +1,2 @@ +002-mspgcc-3.2.3-20080819.dpatch +003-mspgcc-3.2.3-20080819-FUNCTION.dpatch diff --git a/debian/rules b/debian/rules new file mode 100755 index 00000000..daed7ea6 --- /dev/null +++ b/debian/rules @@ -0,0 +1,169 @@ +#!/usr/bin/make -f +# debian/rules file - for gcc 3.2.3 with mspgcc patches +# Based on sample debian/rules file - for GNU Hello (1.3). +# Copyright 1994,1995 by Ian Jackson. +# Copyright 1998-2007 James Troup +# I hereby give you perpetual unlimited permission to copy, +# modify and relicense this file, provided that you do not remove +# my name from the file itself. (I assert my moral right of +# paternity under the Copyright, Designs and Patents Act 1988.) +# This file may have to be extensively modified + +include /usr/share/dpatch/dpatch.make + +TARGET = msp430 +package = $(TARGET)-gcc + +CC = gcc +CFLAGS = -g -O2 +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS = -g -O0 +endif +STRIP = strip --strip-unneeded --remove-section=.comment --remove-section=.note + +install_dir = install -d -m 755 +install_file = install -m 644 +install_script = install -m 755 +install_binary = install -m 755 -s + +DISTRIBUTION := $(shell lsb_release -is) +NJOBS = +# Support parallel= in DEB_BUILD_OPTIONS (see #209008) +ifneq (,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) + COMMA = , + NJOBS := -j $(subst parallel=,,$(filter parallel=%,$(subst $(COMMA), ,$(DEB_BUILD_OPTIONS)))) +endif + + +configure-stamp: patch-stamp + $(checkdir) +ifeq ($(with_check),yes) + @if echo "spawn true" | /usr/bin/expect -f - >/dev/null; then \ + : ; \ + else \ + echo "expect is failing on your system with the above error, which means the"; \ + echo "testsuite will fail. Please resolve the above issues and retry the build."; \ + echo "-----------------------------------------------------------------------------"; \ + exit 1; \ + fi +endif + rm -rf configure-stamp builddir + mkdir builddir + cd builddir \ + && env CC="$(CC)" ../configure --host=$(DEB_HOST_GNU_TYPE) \ + --build=$(DEB_BUILD_GNU_TYPE) --target=$(TARGET) --prefix=/usr \ + --disable-libc --disable-libssp \ + --disable-intl --disable-libiberty --with-gcc --with-gnu-ld \ + --with-gnu-as --with-stabs --disable-shared --disable-threads \ + --disable-win32-registry --disable-nls --enable-languages=c,c++ +# --disable-multilib --disable-libc --disable-libssp \ +# --with-pkgversion="GNU C/C++ for $(TARGET) on $(DISTRIBUTION)" + touch $@ + + +build: build-stamp +build-stamp: configure-stamp + $(checkdir) + $(MAKE) -C builddir $(NJOBS) CFLAGS="$(CFLAGS)" +ifeq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE)) +ifeq ($(with_check),yes) + -$(MAKE) -C builddir -k \ + CFLAGS="$(CFLAGS)" check + find buildir -name "*.sum" -exec cat "{}" ";" >> $$(pwd)/test-summary + @-[ -x /usr/bin/python ] \ + && echo "Test results, compared with installed gcc:" \ + && zcat /usr/share/doc/gcc-4.2/test-summary.gz > test-summary-installed \ + && python debian/test-suite-compare.py test-summary-installed test-summary +endif +endif + touch $@ + + +install: install-stamp +install-stamp: checkroot build-stamp + $(checkdir) + rm -rf debian/tmp + $(install_dir) debian/tmp + $(MAKE) -C builddir prefix=$$(pwd)/debian/tmp/usr \ + mandir=$$(pwd)/debian/tmp/usr/share/man install +ifeq ($(with_strip),yes) + find debian/tmp -type f | xargs file | grep "ELF.*executable" | \ + cut -f 1 -d : | xargs $(STRIP) +endif + touch $@ + + +binary-indep: checkroot build install + : # Nothing to do + + +binary-arch: checkroot build install + $(checkdir) + : # install maintainer scripts + $(install_dir) debian/tmp/DEBIAN + $(install_script) debian/gcc.postinst debian/tmp/DEBIAN/postinst + $(install_script) debian/gcc.postrm debian/tmp/DEBIAN/postrm + : # $(install_file) debian/gcc.shlibs debian/tmp/DEBIAN/shlibs + : # install docs + $(install_dir) debian/tmp/usr/share/doc/$(package)/ + $(install_file) debian/changelog \ + debian/tmp/usr/share/doc/$(package)/changelog.Debian + $(install_file) debian/copyright debian/tmp/usr/share/doc/$(package)/ +ifeq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE)) +ifeq ($(with_check),yes) + $(install_file) $$(pwd)/test-summary \ + debian/tmp/usr/share/doc/$(package)/ +endif +endif + $(install_file) BUGS COPYING COPYING.LIB FAQ MAINTAINERS README \ + debian/README.Debian debian/tmp/usr/share/doc/$(package)/ + $(install_file) ChangeLog debian/tmp/usr/share/doc/$(package)/changelog + : # Remove unnecessary files installed + rm -rf debian/tmp/usr/info debian/tmp/usr/lib/libiberty.a \ + debian/tmp/usr/share/man/man1/cpp* \ + debian/tmp/usr/share/man/man1/gcov* \ + debian/tmp/usr/share/man/man7 + : # Create links from usr/bin/msp430- to usr/msp430/bin/ + $(install_dir) debian/tmp/usr/$(TARGET)/bin/ + (cd debian/tmp/usr/bin && ls $(TARGET)-*) | \ + sed -e 's?\([^-]*\)-\(.*\)$$?\1-\2 \2?' | \ + while read line; do \ + set $$line; \ + ln -sf ../../bin/$$1 debian/tmp/usr/$(TARGET)/bin/$$2; \ + done + : # Compress stuff that needs it + gzip -9 debian/tmp/usr/share/man/man1/* + find debian/tmp/usr/share/doc/$(package)/ -type f ! -name copyright | \ + xargs gzip -9 + : # Finish it all up + find debian/tmp -type f | xargs file | grep ELF | cut -d: -f 1 | \ + xargs dpkg-shlibdeps + dpkg-gencontrol -isp $(CONFLICTS) + chown -R root:root debian/tmp + chmod -R go=rX debian/tmp + dpkg --build debian/tmp .. + + +binary: binary-indep binary-arch + + +clean: unpatch + $(checkdir) + -rm -rf debian/tmp builddir + -find . -name \*.gmo -o -name \*~ -o -name \*.info | xargs rm -f + -rm -f $$(pwd)/test-summary* + -rm -fr debian/patched debian/files* debian/substvars + -rm -f *-stamp + + +define checkdir + test -f gcc/config.gcc -a -f debian/rules +endef + + +checkroot: + $(checkdir) + test root = "`whoami`" + + +.PHONY: binary clean checkroot