From patchwork Tue Jul 23 22:08:26 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 261227 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id C529B2C00B8 for ; Wed, 24 Jul 2013 08:09:01 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :message-id:from:to:cc:in-reply-to:subject:references; q=dns; s= default; b=VTRMF8b93JiClRYw+ZnaJXq9X0zmIXCT+bNeK1uwCdv2lyxRaey3X Freepzu51x0wzYpEsuFsJUgLJXXtj3b+NY6gwoemWcYGamsYMYuFUnpeDaTuWiMZ 0xwW+nX432YuVju6ScrDOd2BuPhzoMr91nnfHuFUXcG/QDnpP7zwWY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :message-id:from:to:cc:in-reply-to:subject:references; s= default; bh=+YgfnPmjcWCOY2IJ2geRdYkwNvQ=; b=qKUOrVOH7JviEBDOkf7D IXCXfCsEgJqXraxUpcC13LtvqL2f+PK7pwTxdzp25//Gz3/SfAKmv4PDYEiGJWR2 Xym9ueteoIFQuPnw3GTvnR/EXO/qIjUrGKzFxJX9PE08Vvz/JI8i0JuPzOzgpcdC mgdpUQQldOTmxAAsvCeO5o0= Received: (qmail 12349 invoked by alias); 23 Jul 2013 22:08:47 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 12320 invoked by uid 89); 23 Jul 2013 22:08:46 -0000 X-Spam-SWARE-Status: No, score=-3.4 required=5.0 tests=AWL, BAYES_99, KHOP_THREADED, RCVD_IN_HOSTKARMA_W, RCVD_IN_HOSTKARMA_WL, RDNS_NONE, SPF_HELO_PASS, SPF_PASS, TW_CL, TW_DP, TW_FN, TW_GC, TW_GD, TW_LG, TW_MF, TW_QE, TW_SR, TW_UC autolearn=no version=3.3.1 Received: from Unknown (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Tue, 23 Jul 2013 22:08:38 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r6NM8UNn021353 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 23 Jul 2013 18:08:30 -0400 Received: from greed.delorie.com (ovpn-113-149.phx2.redhat.com [10.3.113.149]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r6NM8ROA022866 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 23 Jul 2013 18:08:27 -0400 Received: from greed.delorie.com (greed.delorie.com [127.0.0.1]) by greed.delorie.com (8.14.4/8.14.4) with ESMTP id r6NM8QEY018304; Tue, 23 Jul 2013 18:08:26 -0400 Received: (from dj@localhost) by greed.delorie.com (8.14.4/8.14.4/Submit) id r6NM8QpY018297; Tue, 23 Jul 2013 18:08:26 -0400 Date: Tue, 23 Jul 2013 18:08:26 -0400 Message-Id: <201307232208.r6NM8QpY018297@greed.delorie.com> From: DJ Delorie To: Jeff Law CC: gcc-patches@gcc.gnu.org In-reply-to: <51E700D1.702@redhat.com> (message from Jeff Law on Wed, 17 Jul 2013 14:38:41 -0600) Subject: Re: msp430 port References: <51E700D1.702@redhat.com> Ok, I think I covered everything... [gcc] Index: contrib/config-list.mk =================================================================== --- contrib/config-list.mk (revision 201184) +++ contrib/config-list.mk (working copy) @@ -41,12 +41,13 @@ LIST = aarch64-elf aarch64-linux-gnu \ mips64el-st-linux-gnu mips64octeon-linux mipsisa64r2-linux \ mipsisa32r2-linux-gnu mipsisa64r2-sde-elf mipsisa32-elfoabi \ mipsisa64-elfoabi mipsisa64r2el-elf mipsisa64sr71k-elf mipsisa64sb1-elf \ mipsel-elf mips64-elf mips64vr-elf mips64orion-elf mips-rtems \ mips-wrs-vxworks mipstx39-elf mmix-knuth-mmixware mn10300-elf moxie-elf \ moxie-uclinux moxie-rtems pdp11-aout picochip-elfOPT-enable-obsolete \ + msp430-elf \ powerpc-darwin8 \ powerpc-darwin7 powerpc64-darwin powerpc-freebsd6 powerpc-netbsd \ powerpc-eabispe powerpc-eabisimaltivec powerpc-eabisim ppc-elf \ powerpc-eabialtivec powerpc-xilinx-eabi powerpc-eabi \ powerpc-rtems4.11OPT-enable-threads=yes powerpc-linux_spe \ powerpc-linux_paired powerpc64-linux_altivec \ Index: MAINTAINERS =================================================================== --- MAINTAINERS (revision 201184) +++ MAINTAINERS (working copy) @@ -84,12 +84,14 @@ microblaze Michael Eager eager@eagerco mips port Eric Christopher echristo@gmail.com mips port Richard Sandiford rdsandiford@googlemail.com mmix port Hans-Peter Nilsson hp@bitrange.com mn10300 port Jeff Law law@redhat.com mn10300 port Alexandre Oliva aoliva@redhat.com moxie port Anthony Green green@moxielogic.com +msp430 port DJ Delorie dj@redhat.com +msp430 port Nick Clifton nickc@redhat.com nds32 port Chung-Ju Wu jasonwucj@gmail.com nds32 port Shiva Chen shiva0217@gmail.com pdp11 port Paul Koning ni1d@arrl.net picochip port Daniel Towner dant@picochip.com rl78 port DJ Delorie dj@redhat.com rs6000/powerpc port David Edelsohn dje.gcc@gmail.com Index: libgcc/config.host =================================================================== --- libgcc/config.host (revision 201184) +++ libgcc/config.host (working copy) @@ -829,12 +829,15 @@ moxie-*-elf | moxie-*-uclinux*) ;; moxie-*-rtems*) tmake_file="$tmake_file moxie/t-moxie t-softfp-sfdf t-softfp-excl t-softfp" # Don't use default. extra_parts= ;; +msp430*-*-elf) + tmake_file="$tm_file t-crtstuff t-fdpbit msp430/t-msp430" + ;; pdp11-*-*) tmake_file="pdp11/t-pdp11 t-fdpbit" ;; picochip-*-*) tmake_file="picochip/t-picochip t-fpbit" ;; Index: libgcc/config/msp430/floathidf.c =================================================================== --- libgcc/config/msp430/floathidf.c (revision 0) +++ libgcc/config/msp430/floathidf.c (revision 0) @@ -0,0 +1,33 @@ +/* libgcc routines for MSP430 + Copyright (C) 2013 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +extern double __floatsidf (long); + +double +__floathidf (int u) +{ + return __floatsidf ((long)u); +} Index: libgcc/config/msp430/floatunhidf.c =================================================================== --- libgcc/config/msp430/floatunhidf.c (revision 0) +++ libgcc/config/msp430/floatunhidf.c (revision 0) @@ -0,0 +1,37 @@ +/* libgcc routines for MSP430 + Copyright (C) 2013 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +typedef int HItype __attribute__ ((mode (HI))); +typedef unsigned int UHItype __attribute__ ((mode (HI))); +typedef float DFtype __attribute__ ((mode (DF))); + +extern DFtype __floatunsidf (unsigned long); + +DFtype +__floatunhidf (UHItype u) +{ + return __floatunsidf ((unsigned long)u); +} Index: libgcc/config/msp430/mpy.c =================================================================== Index: libgcc/config/msp430/t-msp430 =================================================================== --- libgcc/config/msp430/t-msp430 (revision 0) +++ libgcc/config/msp430/t-msp430 (revision 0) @@ -0,0 +1,47 @@ +# Makefile fragment for building LIBGCC for the TI MSP430 processor. +# Copyright (C) 2011 Free Software Foundation, Inc. +# Contributed by Red Hat. +# +# 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 3, 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 COPYING3. If not see +# . + +# Note - we have separate versions of the lib2div files +# as the functions are quite large and we do not want to pull +# in unneeded division routines. + +LIB2ADD = \ + $(srcdir)/config/msp430/lib2divQI.c \ + $(srcdir)/config/msp430/lib2divHI.c \ + $(srcdir)/config/msp430/lib2divSI.c \ + $(srcdir)/config/msp430/lib2bitcountHI.c \ + $(srcdir)/config/msp430/lib2mul.c \ + $(srcdir)/config/msp430/lib2shift.c \ + $(srcdir)/config/msp430/epilogue.S \ + $(srcdir)/config/msp430/slli.S \ + $(srcdir)/config/msp430/srai.S \ + $(srcdir)/config/msp430/srli.S \ + $(srcdir)/config/msp430/cmpsi2.S \ + $(srcdir)/config/msp430/floatunhisf.c \ + $(srcdir)/config/msp430/floatunhidf.c \ + $(srcdir)/config/msp430/floathidf.c \ + $(srcdir)/config/msp430/floathisf.c \ + $(srcdir)/config/msp430/cmpd.c + +HOST_LIBGCC2_CFLAGS += -Os -ffunction-sections -fdata-sections + +# Local Variables: +# mode: Makefile +# End: Index: libgcc/config/msp430/lib2mul.c =================================================================== --- libgcc/config/msp430/lib2mul.c (revision 0) +++ libgcc/config/msp430/lib2mul.c (revision 0) @@ -0,0 +1,59 @@ +/* libgcc routines for MSP430 + Copyright (C) 2005, 2009, 2011 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +typedef unsigned int uint32_type __attribute__ ((mode (SI))); +typedef unsigned int uint16_type __attribute__ ((mode (HI))); +typedef unsigned int uint08_type __attribute__ ((mode (QI))); + +#define C3B(a,b,c) a##b##c +#define C3(a,b,c) C3B(a,b,c) + + +#define UINT_TYPE uint16_type +#define BITS_MINUS_1 15 +#define NAME_MODE hi + +#include "msp430-mul.h" + +#undef UINT_TYPE +#undef BITS_MINUS_1 +#undef NAME_MODE + +#define UINT_TYPE uint08_type +#define BITS_MINUS_1 7 +#define NAME_MODE qi + +#include "msp430-mul.h" + +#undef UINT_TYPE +#undef BITS_MINUS_1 +#undef NAME_MODE + +#define UINT_TYPE uint32_type +#define BITS_MINUS_1 31 +#define NAME_MODE si + +#include "msp430-mul.h" Index: libgcc/config/msp430/msp430-divmod.h =================================================================== --- libgcc/config/msp430/msp430-divmod.h (revision 0) +++ libgcc/config/msp430/msp430-divmod.h (revision 0) @@ -0,0 +1,118 @@ +/* libgcc routines for MSP430 + Copyright (C) 2005, 2009, 2011 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +UINT_TYPE C3(udivmod,NAME_MODE,4) (UINT_TYPE, UINT_TYPE, word_type); +SINT_TYPE C3(__div,NAME_MODE,3) (SINT_TYPE, SINT_TYPE); +SINT_TYPE C3(__mod,NAME_MODE,3) (SINT_TYPE, SINT_TYPE); +UINT_TYPE C3(__udiv,NAME_MODE,3) (UINT_TYPE, UINT_TYPE); +UINT_TYPE C3(__umod,NAME_MODE,3) (UINT_TYPE, UINT_TYPE); + +UINT_TYPE +C3(udivmod,NAME_MODE,4) (UINT_TYPE num, UINT_TYPE den, word_type modwanted) +{ + UINT_TYPE bit = 1; + UINT_TYPE res = 0; + + while (den < num && bit && !(den & (1L << BITS_MINUS_1))) + { + den <<= 1; + bit <<= 1; + } + while (bit) + { + if (num >= den) + { + num -= den; + res |= bit; + } + bit >>= 1; + den >>= 1; + } + if (modwanted) + return num; + return res; +} + +SINT_TYPE +C3(__div,NAME_MODE,3) (SINT_TYPE a, SINT_TYPE b) +{ + word_type neg = 0; + SINT_TYPE res; + + if (a < 0) + { + a = -a; + neg = !neg; + } + + if (b < 0) + { + b = -b; + neg = !neg; + } + + res = C3(udivmod,NAME_MODE,4) (a, b, 0); + + if (neg) + res = -res; + + return res; +} + +SINT_TYPE +C3(__mod,NAME_MODE,3) (SINT_TYPE a, SINT_TYPE b) +{ + word_type neg = 0; + SINT_TYPE res; + + if (a < 0) + { + a = -a; + neg = 1; + } + + if (b < 0) + b = -b; + + res = C3(udivmod,NAME_MODE,4) (a, b, 1); + + if (neg) + res = -res; + + return res; +} + +UINT_TYPE +C3(__udiv,NAME_MODE,3) (UINT_TYPE a, UINT_TYPE b) +{ + return C3(udivmod,NAME_MODE,4) (a, b, 0); +} + +UINT_TYPE +C3(__umod,NAME_MODE,3) (UINT_TYPE a, UINT_TYPE b) +{ + return C3(udivmod,NAME_MODE,4) (a, b, 1); +} Index: libgcc/config/msp430/lib2divHI.c =================================================================== --- libgcc/config/msp430/lib2divHI.c (revision 0) +++ libgcc/config/msp430/lib2divHI.c (revision 0) @@ -0,0 +1,43 @@ +/* HI mode divide routines for libgcc for MSP430 + Copyright (C) 2012 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +typedef int sint32_type __attribute__ ((mode (SI))); +typedef unsigned int uint32_type __attribute__ ((mode (SI))); +typedef int sint16_type __attribute__ ((mode (HI))); +typedef unsigned int uint16_type __attribute__ ((mode (HI))); +typedef int sint08_type __attribute__ ((mode (QI))); +typedef unsigned int uint08_type __attribute__ ((mode (QI))); +typedef int word_type __attribute__ ((mode (__word__))); + +#define C3B(a,b,c) a##b##c +#define C3(a,b,c) C3B(a,b,c) + +#define UINT_TYPE uint16_type +#define SINT_TYPE sint16_type +#define BITS_MINUS_1 15 +#define NAME_MODE hi + +#include "msp430-divmod.h" Index: libgcc/config/msp430/cmpsi2.S =================================================================== --- libgcc/config/msp430/cmpsi2.S (revision 0) +++ libgcc/config/msp430/cmpsi2.S (revision 0) @@ -0,0 +1,98 @@ +; Copyright (C) 2012, 2013 Free Software Foundation, Inc. +; Contributed by Red Hat. +; +; This file 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 3, or (at your option) any +; later version. +; +; This file 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. +; +; Under Section 7 of GPL version 3, you are granted additional +; permissions described in the GCC Runtime Library Exception, version +; 3.1, as published by the Free Software Foundation. +; +; You should have received a copy of the GNU General Public License and +; a copy of the GCC Runtime Library Exception along with this program; +; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +; . + +#ifdef __MSP430X_LARGE__ +#define ret_ RETA +#else +#define ret_ RET +#endif + + .text + + ;; int __cmpsi2 (signed long A, signed long B) + ;; + ;; Performs a signed comparison of A and B. + ;; If A is less than B it returns 0. If A is greater + ;; than B it returns 2. If they are equal it returns 1. + + ;; Note - this code is also used by the __ucmpsi2 routine below. + + .global __cmpsi2 + .type __cmpsi2, @function +__cmpsi2: + ;; A is in r12 (low), r13 (high) + ;; B is in r14 (low), r15 (high) + ;; Result put in r12 + + cmp.w r13, r15 + jeq .L_compare_low + jge .L_less_than +.L_greater_than: + mov.w #2, r12 + ret_ +.L_less_than: + mov.w #0, r12 + ret_ + +.L_compare_low: + cmp.w r12, r14 + jl .L_greater_than + jne .L_less_than + mov.w #1, r12 + ret_ + + .size __cmpsi2, . - __cmpsi2 + + + ;; int __ucmpsi2 (unsigned long A, unsigned long B) + ;; + ;; Performs an unsigned comparison of A and B. + ;; If A is less than B it returns 0. If A is greater + ;; than B it returns 2. If they are equal it returns 1. + +;;; Note - this function branches into the __cmpsi2 code above. + + .global __ucmpsi2 + .type __ucmpsi2, @function +__ucmpsi2: + ;; A is in r12 (low), r13 (high) + ;; B is in r14 (low), r15 (high) + ;; Result put in r12 + + tst r13 + jn .L_top_bit_set_in_A + tst r15 +;;; If the top bit of B is set, but A's is clear we know that A < B. + jn .L_less_than +;;; Neither A nor B has their top bit set so we can use the __cmpsi2 routine. +;;; Note we use Jc rather than BR as that saves two bytes. The TST insn always +;;; sets the C bit. + jc __cmpsi2 + +.L_top_bit_set_in_A: + tst r15 +;;; If both A and B have their top bit set we can use the __cmpsi2 routine. + jn __cmpsi2 +;;; Otherwise A has its top bit set and B does not so A > B. + jc .L_greater_than + + .size __ucmpsi2, . - __ucmpsi2 Index: libgcc/config/msp430/srai.S =================================================================== --- libgcc/config/msp430/srai.S (revision 0) +++ libgcc/config/msp430/srai.S (revision 0) @@ -0,0 +1,106 @@ +; Copyright (C) 2012, 2013 Free Software Foundation, Inc. +; Contributed by Red Hat. +; +; This file 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 3, or (at your option) any +; later version. +; +; This file 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. +; +; Under Section 7 of GPL version 3, you are granted additional +; permissions described in the GCC Runtime Library Exception, version +; 3.1, as published by the Free Software Foundation. +; +; You should have received a copy of the GNU General Public License and +; a copy of the GCC Runtime Library Exception along with this program; +; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +; . + + .text + + .macro _srai n + .global __mspabi_srai_\n +__mspabi_srai_\n: + RRA.W R12 + .endm + +/* Logical Right Shift - R12 -> R12 */ + _srai 15 + _srai 14 + _srai 13 + _srai 12 + _srai 11 + _srai 10 + _srai 9 + _srai 8 + _srai 7 + _srai 6 + _srai 5 + _srai 4 + _srai 3 + _srai 2 + _srai 1 +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif + +1: ADD.W #-1,R13 + RRA.W R12,R12 + .global __mspabi_srai +__mspabi_srai: + CMP #0,R13 + JNZ 1b +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif + +/* Logical Right Shift - R12:R13 -> R12:R13 */ + + .macro _sral n + .global __mspabi_sral_\n +__mspabi_sral_\n: + RRA.W R13 + RRC.W R12 + .endm + + _sral 15 + _sral 14 + _sral 13 + _sral 12 + _sral 11 + _sral 10 + _sral 9 + _sral 8 + _sral 7 + _sral 6 + _sral 5 + _sral 4 + _sral 3 + _sral 2 + _sral 1 +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif + +1: ADD.W #-1,R14 + RRA.W R13 + RRC.W R12 + .global __mspabi_sral +__mspabi_sral: + CMP #0,R14 + JNZ 1b +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif Index: libgcc/config/msp430/floathisf.c =================================================================== --- libgcc/config/msp430/floathisf.c (revision 0) +++ libgcc/config/msp430/floathisf.c (revision 0) @@ -0,0 +1,36 @@ +/* libgcc routines for MSP430 + Copyright (C) 2013 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +typedef int HItype __attribute__ ((mode (HI))); +typedef float SFtype __attribute__ ((mode (SF))); + +extern SFtype __floatsisf (unsigned long); + +SFtype +__floathisf (HItype u) +{ + return __floatsisf ((unsigned long)u); +} Index: libgcc/config/msp430/lib2bitcountHI.c =================================================================== --- libgcc/config/msp430/lib2bitcountHI.c (revision 0) +++ libgcc/config/msp430/lib2bitcountHI.c (revision 0) @@ -0,0 +1,50 @@ +/* libgcc routines for MSP430 + Copyright (C) 2012 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +typedef int sint32_type __attribute__ ((mode (SI))); +typedef unsigned int uint32_type __attribute__ ((mode (SI))); +typedef int sint16_type __attribute__ ((mode (HI))); +typedef unsigned int uint16_type __attribute__ ((mode (HI))); +typedef int sint08_type __attribute__ ((mode (QI))); +typedef unsigned int uint08_type __attribute__ ((mode (QI))); +typedef int word_type __attribute__ ((mode (__word__))); + +#define C3B(a,b,c) a##b##c +#define C3(a,b,c) C3B(a,b,c) + +/* See the comment by the definition of LIBGCC2_UNITS_PER_WORD in + msp430.h for why we are creating extra versions of some of the + functions defined in libgcc2.c. */ + +#define LIBGCC2_UNITS_PER_WORD 2 + +#define L_clzsi2 +#define L_ctzsi2 +#define L_ffssi2 +#define L_paritysi2 +#define L_popcountsi2 + +#include "libgcc2.c" Index: libgcc/config/msp430/floatunhisf.c =================================================================== --- libgcc/config/msp430/floatunhisf.c (revision 0) +++ libgcc/config/msp430/floatunhisf.c (revision 0) @@ -0,0 +1,37 @@ +/* libgcc routines for MSP430 + Copyright (C) 2013 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +typedef int HItype __attribute__ ((mode (HI))); +typedef unsigned int UHItype __attribute__ ((mode (HI))); +typedef float SFtype __attribute__ ((mode (SF))); + +extern SFtype __floatunsisf (unsigned long); + +SFtype +__floatunhisf (UHItype u) +{ + return __floatunsisf ((unsigned long)u); +} Index: libgcc/config/msp430/cmpd.c =================================================================== --- libgcc/config/msp430/cmpd.c (revision 0) +++ libgcc/config/msp430/cmpd.c (revision 0) @@ -0,0 +1,44 @@ +/* libgcc routines for MSP430 + Copyright (C) 2013 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +int +__mspabi_cmpf (float x, float y) +{ + if (x < y) + return -1; + if (x > y) + return 1; + return 0; +} +int +__mspabi_cmpd (double x, double y) +{ + if (x < y) + return -1; + if (x > y) + return 1; + return 0; +} Index: libgcc/config/msp430/slli.S =================================================================== --- libgcc/config/msp430/slli.S (revision 0) +++ libgcc/config/msp430/slli.S (revision 0) @@ -0,0 +1,108 @@ +; Copyright (C) 2012, 2013 Free Software Foundation, Inc. +; Contributed by Red Hat. +; +; This file 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 3, or (at your option) any +; later version. +; +; This file 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. +; +; Under Section 7 of GPL version 3, you are granted additional +; permissions described in the GCC Runtime Library Exception, version +; 3.1, as published by the Free Software Foundation. +; +; You should have received a copy of the GNU General Public License and +; a copy of the GCC Runtime Library Exception along with this program; +; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +; . + + .text + +/* Logical Left Shift - R12 -> R12 */ + + .macro _slli n + .global __mspabi_slli_\n +__mspabi_slli_\n: + ADD.W R12,R12 + .endm + + _slli 15 + _slli 14 + _slli 13 + _slli 12 + _slli 11 + _slli 10 + _slli 9 + _slli 8 + _slli 7 + _slli 6 + _slli 5 + _slli 4 + _slli 3 + _slli 2 + _slli 1 +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif + +1: ADD.W #-1,R13 + ADD.W R12,R12 + .global __mspabi_slli +__mspabi_slli: + CMP #0,R13 + JNZ 1b +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif + +/* Logical Left Shift - R12:R13 -> R12:R13 */ + + .macro _slll n + .global __mspabi_slll_\n +__mspabi_slll_\n: + ADD.W R12,R12 + ADDC.W R13,R13 + .endm + + _slll 15 + _slll 14 + _slll 13 + _slll 12 + _slll 11 + _slll 10 + _slll 9 + _slll 8 + _slll 7 + _slll 6 + _slll 5 + _slll 4 + _slll 3 + _slll 2 + _slll 1 +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif + +1: ADD.W #-1,R14 + ADD.W R12,R12 + ADDC.W R13,R13 + .global __mspabi_slll +__mspabi_slll: + CMP #0,R14 + JNZ 1b +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif + Index: libgcc/config/msp430/lib2divQI.c =================================================================== --- libgcc/config/msp430/lib2divQI.c (revision 0) +++ libgcc/config/msp430/lib2divQI.c (revision 0) @@ -0,0 +1,44 @@ +/* QI mode divide routines for libgcc for MSP430 + Copyright (C) 2012 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +typedef int sint32_type __attribute__ ((mode (SI))); +typedef unsigned int uint32_type __attribute__ ((mode (SI))); +typedef int sint16_type __attribute__ ((mode (HI))); +typedef unsigned int uint16_type __attribute__ ((mode (HI))); +typedef int sint08_type __attribute__ ((mode (QI))); +typedef unsigned int uint08_type __attribute__ ((mode (QI))); +typedef int word_type __attribute__ ((mode (__word__))); + +#define C3B(a,b,c) a##b##c +#define C3(a,b,c) C3B(a,b,c) + +#define UINT_TYPE uint08_type +#define SINT_TYPE sint08_type +#define BITS_MINUS_1 7 +#define NAME_MODE qi + +#include "msp430-divmod.h" + Index: libgcc/config/msp430/lib2shift.c =================================================================== --- libgcc/config/msp430/lib2shift.c (revision 0) +++ libgcc/config/msp430/lib2shift.c (revision 0) @@ -0,0 +1,113 @@ +/* Shift functions for the GCC support library for the MSP430 + Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +typedef int sint32_type __attribute__ ((mode (SI))); +typedef unsigned int uint32_type __attribute__ ((mode (SI))); +typedef int sint16_type __attribute__ ((mode (HI))); +typedef unsigned int uint16_type __attribute__ ((mode (HI))); + +uint32_type __ashlsi3 (uint32_type in, char bit); +sint32_type __ashrsi3 (sint32_type in, char bit); +int __clrsbhi2 (sint16_type x); +extern int __clrsbsi2 (sint32_type x); + +typedef struct +{ + union + { + uint32_type u; + uint16_type h[2]; + } u; +} dd; + +uint32_type +__ashlsi3 (uint32_type in, char bit) +{ + uint16_type h, l; + dd d; + + if (bit > 32) + return 0; + if (bit < 0) + return in; + + d.u.u = in; + h = d.u.h[1]; + l = d.u.h[0]; + + if (bit > 15) + { + h = l; + l = 0; + bit -= 16; + } + + while (bit) + { + h = (h << 1) | (l >> 15); + l <<= 1; + bit --; + } + + d.u.h[1] = h; + d.u.h[0] = l; + return d.u.u; +} + +sint32_type +__ashrsi3 (sint32_type in, char bit) +{ + sint16_type h; + uint16_type l; + dd d; + + if (bit > 32) + return 0; + if (bit < 0) + return in; + + d.u.u = in; + h = d.u.h[1]; + l = d.u.h[0]; + + while (bit) + { + l = (h << 15) | (l >> 1); + h >>= 1; + bit --; + } + + d.u.h[1] = h; + d.u.h[0] = l; + return d.u.u; +} + +int +__clrsbhi2 (sint16_type x) +{ + if (x == 0) + return 15; + return __clrsbsi2 ((sint32_type) x) - 16; +} Index: libgcc/config/msp430/msp430-mul.h =================================================================== --- libgcc/config/msp430/msp430-mul.h (revision 0) +++ libgcc/config/msp430/msp430-mul.h (revision 0) @@ -0,0 +1,43 @@ +/* libgcc routines for RL78 + Copyright (C) 2005, 2009, 2011 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +UINT_TYPE C3(__mul,NAME_MODE,3) (UINT_TYPE, UINT_TYPE); +UINT_TYPE +C3(__mul,NAME_MODE,3) (UINT_TYPE a, UINT_TYPE b) +{ + UINT_TYPE rv = 0; + + char bit; + + for (bit=0; b && bit>= 1; + } + return rv; +} Index: libgcc/config/msp430/lib2divSI.c =================================================================== --- libgcc/config/msp430/lib2divSI.c (revision 0) +++ libgcc/config/msp430/lib2divSI.c (revision 0) @@ -0,0 +1,43 @@ +/* SI mode divide routines for libgcc for MSP430 + Copyright (C) 2012 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +typedef int sint32_type __attribute__ ((mode (SI))); +typedef unsigned int uint32_type __attribute__ ((mode (SI))); +typedef int sint16_type __attribute__ ((mode (HI))); +typedef unsigned int uint16_type __attribute__ ((mode (HI))); +typedef int sint08_type __attribute__ ((mode (QI))); +typedef unsigned int uint08_type __attribute__ ((mode (QI))); +typedef int word_type __attribute__ ((mode (__word__))); + +#define C3B(a,b,c) a##b##c +#define C3(a,b,c) C3B(a,b,c) + +#define UINT_TYPE uint32_type +#define SINT_TYPE sint32_type +#define BITS_MINUS_1 31 +#define NAME_MODE si + +#include "msp430-divmod.h" Index: libgcc/config/msp430/epilogue.S =================================================================== --- libgcc/config/msp430/epilogue.S (revision 0) +++ libgcc/config/msp430/epilogue.S (revision 0) @@ -0,0 +1,51 @@ +; Copyright (C) 2012, 2013 Free Software Foundation, Inc. +; Contributed by Red Hat. +; +; This file 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 3, or (at your option) any +; later version. +; +; This file 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. +; +; Under Section 7 of GPL version 3, you are granted additional +; permissions described in the GCC Runtime Library Exception, version +; 3.1, as published by the Free Software Foundation. +; +; You should have received a copy of the GNU General Public License and +; a copy of the GCC Runtime Library Exception along with this program; +; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +; . + + .text + + .global __mspabi_func_epilog_7 + .global __mspabi_func_epilog_6 + .global __mspabi_func_epilog_5 + .global __mspabi_func_epilog_4 + .global __mspabi_func_epilog_3 + .global __mspabi_func_epilog_2 + .global __mspabi_func_epilog_1 + +__mspabi_func_epilog_7: + POP R4 +__mspabi_func_epilog_6: + POP R5 +__mspabi_func_epilog_5: + POP R6 +__mspabi_func_epilog_4: + POP R7 +__mspabi_func_epilog_3: + POP R8 +__mspabi_func_epilog_2: + POP R9 +__mspabi_func_epilog_1: + POP R10 +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif Index: libgcc/config/msp430/srli.S =================================================================== --- libgcc/config/msp430/srli.S (revision 0) +++ libgcc/config/msp430/srli.S (revision 0) @@ -0,0 +1,110 @@ +; Copyright (C) 2012, 2013 Free Software Foundation, Inc. +; Contributed by Red Hat. +; +; This file 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 3, or (at your option) any +; later version. +; +; This file 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. +; +; Under Section 7 of GPL version 3, you are granted additional +; permissions described in the GCC Runtime Library Exception, version +; 3.1, as published by the Free Software Foundation. +; +; You should have received a copy of the GNU General Public License and +; a copy of the GCC Runtime Library Exception along with this program; +; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +; . + + .text + + .macro _srli n + .global __mspabi_srli_\n +__mspabi_srli_\n: + CLRC + RRC.W R12 + .endm + +/* Logical Right Shift - R12 -> R12 */ + _srli 15 + _srli 14 + _srli 13 + _srli 12 + _srli 11 + _srli 10 + _srli 9 + _srli 8 + _srli 7 + _srli 6 + _srli 5 + _srli 4 + _srli 3 + _srli 2 + _srli 1 +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif + +1: ADD.W #-1,R13 + CLRC + RRC.W R12,R12 + .global __mspabi_srli +__mspabi_srli: + CMP #0,R13 + JNZ 1b +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif + +/* Logical Right Shift - R12:R13 -> R12:R13 */ + + .macro _srll n + .global __mspabi_srll_\n +__mspabi_srll_\n: + CLRC + RRC.W R13 + RRC.W R12 + .endm + + _srll 15 + _srll 14 + _srll 13 + _srll 12 + _srll 11 + _srll 10 + _srll 9 + _srll 8 + _srll 7 + _srll 6 + _srll 5 + _srll 4 + _srll 3 + _srll 2 + _srll 1 +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif + +1: ADD.W #-1,R14 + CLRC + RRC.W R13 + RRC.W R12 + .global __mspabi_srll +__mspabi_srll: + CMP #0,R14 + JNZ 1b +#ifdef __MSP430X_LARGE__ + RETA +#else + RET +#endif Index: gcc/doc/invoke.texi =================================================================== --- gcc/doc/invoke.texi (revision 201184) +++ gcc/doc/invoke.texi (working copy) @@ -794,12 +794,15 @@ Objective-C and Objective-C++ Dialects}. -mreturn-pointer-on-d0 @gol -mno-crt0 -mrelax -mliw -msetlb} @emph{Moxie Options} @gccoptlist{-meb -mel -mno-crt0} +@emph{MSP430 Options} +@gccoptlist{-msim -masm-hex -mmcu= -mlarge -msmall -mrelax} + @emph{PDP-11 Options} @gccoptlist{-mfpu -msoft-float -mac0 -mno-ac0 -m40 -m45 -m10 @gol -mbcopy -mbcopy-builtin -mint32 -mno-int16 @gol -mint16 -mno-int32 -mfloat32 -mno-float64 @gol -mfloat64 -mno-float32 -mabshi -mno-abshi @gol -mbranch-expensive -mbranch-cheap @gol @@ -10936,12 +10939,13 @@ platform. * MeP Options:: * MicroBlaze Options:: * MIPS Options:: * MMIX Options:: * MN10300 Options:: * Moxie Options:: +* MSP430 Options:: * PDP-11 Options:: * picoChip Options:: * PowerPC Options:: * RL78 Options:: * RS/6000 and PowerPC Options:: * RX Options:: @@ -15872,13 +15876,13 @@ compatibility with other tools, like @co @item -msdram @opindex msdram Link the SDRAM-based runtime instead of the default ROM-based runtime. @item -msim @opindex msim -Link the simulator runtime libraries. +Link the simulator run-time libraries. @item -msimnovec @opindex msimnovec Link the simulator runtime libraries, excluding built-in support for reset and exception vectors and tables. @@ -17094,12 +17098,52 @@ Generate little-endian code. @item -mno-crt0 @opindex mno-crt0 Do not link in the C run-time initialization object file. @end table +@node MSP430 Options +@subsection MSP430 Options +@cindex MSP430 Options + +These options are defined for the MSP430: + +@table @gcctabopt + +@item -msim +@opindex msim +Link the simulator runtime libraries. + +@item -masm-hex +@opindex masm-hex +Force assembly output to always use hex constants. Normally such +constants are signed decimals, but this option is available for +testsuite and/or aesthetic purposes. + +@item -mmcu= +@opindex mmcu= +Select the MCU to target. Note that there are two ``generic'' MCUs, +@code{msp430} and @code{msp430x}, which should be used most of the +time. This option is also passed to the assembler. + +@item -mlarge +@opindex mlarge +Use large-model addressing (20-bit pointers, 32-bit @code{size_t}). + +@item -msmall +@opindex msmall +Use small-model addressing (16-bit pointers, 16-bit @code{size_t}). + +@item -mrelax +@opindex mrelax +This option is passed to the assembler and linker, and allows the +linker to perform certain optimizations that cannot be done until +the final link. + +@end table + @node PDP-11 Options @subsection PDP-11 Options @cindex PDP-11 Options These options are defined for the PDP-11: Index: gcc/doc/contrib.texi =================================================================== --- gcc/doc/contrib.texi (revision 201184) +++ gcc/doc/contrib.texi (working copy) @@ -173,13 +173,13 @@ Branko Cibej for more warning contributi @item The @uref{http://www.gnu.org/software/classpath/,,GNU Classpath project} for all of their merged runtime code. @item -Nick Clifton for arm, mcore, fr30, v850, m32r, rx work, +Nick Clifton for arm, mcore, fr30, v850, m32r, msp430 rx work, @option{--help}, and other random hacking. @item Michael Cook for libstdc++ cleanup patches to reduce warnings. @item @@ -215,13 +215,13 @@ Bud Davis for work on the G77 and GNU Fo @item Mo DeJong for GCJ and libgcj bug fixes. @item DJ Delorie for the DJGPP port, build and libiberty maintenance, -various bug fixes, and the M32C, MeP, and RL78 ports. +various bug fixes, and the M32C, MeP, MSP430, and RL78 ports. @item Arnaud Desitter for helping to debug GNU Fortran. @item Gabriel Dos Reis for contributions to G++, contributions and Index: gcc/doc/md.texi =================================================================== --- gcc/doc/md.texi (revision 201184) +++ gcc/doc/md.texi (working copy) @@ -3060,12 +3060,41 @@ A constant in the range of 0 to 255. @item N A constant in the range of 0 to @minus{}255. @end table +@item MSP430--@file{config/msp430/constraints.md} +@table @code + +@item R12 +Register R12. + +@item R13 +Register R13. + +@item K +Integer constant 1. + +@item L +Integer constant -1^20..1^19. + +@item M +Integer constant 1-4. + +@item Ya +Memory references which do not require an extended MOVX instruction. + +@item Yl +Memory reference, labels only. + +@item Ys +Memory reference, stack only. + +@end table + @item PDP-11---@file{config/pdp11/constraints.md} @table @code @item a Floating point registers AC0 through AC3. These can be loaded from/to memory with a single instruction. Index: gcc/doc/install.texi =================================================================== --- gcc/doc/install.texi (revision 201184) +++ gcc/doc/install.texi (working copy) @@ -3951,12 +3951,19 @@ the O32 ABI. @heading @anchor{moxie-x-elf}moxie-*-elf The moxie processor. @html
@end html +@heading @anchor{msp430-x-elf}msp430-*-elf +TI MSP430 processor. +This configuration is intended for embedded systems. + +@html +
+@end html @heading @anchor{powerpc-x-x}powerpc-*-* You can specify a default version for the @option{-mcpu=@var{cpu_type}} switch by using the configure option @option{--with-cpu-@var{cpu_type}}. You will need Index: gcc/cfgexpand.c =================================================================== --- gcc/cfgexpand.c (revision 201184) +++ gcc/cfgexpand.c (working copy) @@ -3151,13 +3151,20 @@ expand_debug_expr (tree exp) size_t, we need to check for mis-matched modes and correct the addend. */ if (op0 && op1 && GET_MODE (op0) != VOIDmode && GET_MODE (op1) != VOIDmode && GET_MODE (op0) != GET_MODE (op1)) { - if (GET_MODE_BITSIZE (GET_MODE (op0)) < GET_MODE_BITSIZE (GET_MODE (op1))) + if (GET_MODE_BITSIZE (GET_MODE (op0)) < GET_MODE_BITSIZE (GET_MODE (op1)) + /* Don't try to sign-extend SImode to PSImode, for + example. The sign extension code in simplify_unary_operation_1() + asserts extension to a larger bit size. */ + || (GET_MODE_BITSIZE (GET_MODE (op0)) == GET_MODE_BITSIZE (GET_MODE (op1)) + && GET_MODE_CLASS (GET_MODE (op0)) == MODE_PARTIAL_INT + && GET_MODE_CLASS (GET_MODE (op1)) == MODE_INT) + ) op1 = simplify_gen_unary (TRUNCATE, GET_MODE (op0), op1, GET_MODE (op1)); else /* We always sign-extend, regardless of the signedness of the operand, because the operand is always unsigned here even if the original C expression is signed. */ Index: gcc/simplify-rtx.c =================================================================== --- gcc/simplify-rtx.c (revision 201184) +++ gcc/simplify-rtx.c (working copy) @@ -5884,12 +5884,23 @@ simplify_immed_subreg (enum machine_mode /* Simplify SUBREG:OUTERMODE(OP:INNERMODE, BYTE) Return 0 if no simplifications are possible. */ rtx simplify_subreg (enum machine_mode outermode, rtx op, enum machine_mode innermode, unsigned int byte) { + /* FIXME: hack to allow building of newlib/libc.a for msp430/430x/large multilib. + The problem is the var-tracking is generating paradoxical SUBREGs. Not sure why... */ + if (!(GET_MODE (op) == innermode + || GET_MODE (op) == VOIDmode) + || (innermode == VOIDmode) + ) + { + debug_rtx (op); + return NULL_RTX; + } + /* Little bit of sanity checking. */ gcc_assert (innermode != VOIDmode); gcc_assert (outermode != VOIDmode); gcc_assert (innermode != BLKmode); gcc_assert (outermode != BLKmode); Index: gcc/dwarf2cfi.c =================================================================== --- gcc/dwarf2cfi.c (revision 201184) +++ gcc/dwarf2cfi.c (working copy) @@ -277,12 +277,19 @@ expand_builtin_init_dwarf_reg_sizes (tre { if (save_mode == VOIDmode) continue; wrote_return_column = true; } size = GET_MODE_SIZE (save_mode); + + /* Entries in the dwarf_reg_size_table must be big enough to hold an _Unwind_Word + even if this is bigger than reg_raw_mode. This can happen on targets where the + pointer size is larger than the integer size, and not a power-of-two. (Eg MSP430). */ + if (size < GET_MODE_SIZE (targetm.unwind_word_mode ())) + size = GET_MODE_SIZE (targetm.unwind_word_mode ()); + if (offset < 0) continue; emit_move_insn (adjust_address (mem, mode, offset), gen_int_mode (size, mode)); } Index: gcc/config.gcc =================================================================== --- gcc/config.gcc (revision 201184) +++ gcc/config.gcc (working copy) @@ -2034,12 +2034,19 @@ mn10300-*-*) then tm_file="${tm_file} dbx.h" fi use_collect2=no use_gcc_stdint=wrap ;; +msp430*-*-*) + tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + c_target_objs="msp430-c.o" + cxx_target_objs="msp430-c.o" + target_has_targetm_common=no + tmake_file="${tmake_file} msp430/t-msp430" + ;; pdp11-*-*) tm_file="${tm_file} newlib-stdint.h" use_gcc_stdint=wrap ;; picochip-*) tm_file="${tm_file} newlib-stdint.h" Index: gcc/config/msp430/msp430-protos.h =================================================================== --- gcc/config/msp430/msp430-protos.h (revision 0) +++ gcc/config/msp430/msp430-protos.h (revision 0) @@ -0,0 +1,44 @@ +/* Exported function prototypes from the TI MSP430 backend. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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 COPYING3. If not see + . */ + +#ifndef GCC_MSP430_PROTOS_H +#define GCC_MSP430_PROTOS_H + +void msp430_expand_eh_return (rtx); +void msp430_expand_epilogue (int); +void msp430_expand_helper (rtx *operands, const char *, bool); +void msp430_expand_prologue (void); +const char * msp430x_extendhisi (rtx *); +void msp430_fixup_compare_operands (enum machine_mode, rtx *); +int msp430_hard_regno_mode_ok (int, enum machine_mode); +int msp430_hard_regno_nregs (int, enum machine_mode); +rtx msp430_incoming_return_addr_rtx (void); +void msp430_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); +int msp430_initial_elimination_offset (int, int); +const char * msp430x_logical_shift_right (rtx); +void msp430_output_labelref (FILE *, const char *); +void msp430_register_pragmas (void); +rtx msp430_return_addr_rtx (int); +void msp430_split_movsi (rtx *); +rtx msp430_subreg (enum machine_mode, rtx, enum machine_mode, int); +rtx msp430_eh_return_stackadj_rtx (void); +bool msp430_modes_tieable_p (enum machine_mode, enum machine_mode); + +#endif /* GCC_MSP430_PROTOS_H */ Index: gcc/config/msp430/predicates.md =================================================================== --- gcc/config/msp430/predicates.md (revision 0) +++ gcc/config/msp430/predicates.md (revision 0) @@ -0,0 +1,80 @@ +;; Machine Description for TI MSP43* processors +;; Copyright (C) 2013 Free Software Foundation, Inc. +;; Contributed by Red Hat. + +;; 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 3, 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 COPYING3. If not see +;; . + +(define_predicate "msp_volatile_memory_operand" + (and (match_code "mem") + (match_test ("memory_address_addr_space_p (GET_MODE (op), XEXP (op, 0), MEM_ADDR_SPACE (op))"))) +) + +; TRUE for any valid general operand. We do this because +; general_operand refuses to match volatile memory refs. + +(define_predicate "msp_general_operand" + (ior (match_operand 0 "general_operand") + (match_operand 0 "msp_volatile_memory_operand")) +) + +; Likewise for nonimmediate_operand. + +(define_predicate "msp_nonimmediate_operand" + (ior (match_operand 0 "nonimmediate_operand") + (match_operand 0 "msp_volatile_memory_operand")) +) + +(define_predicate "ubyte_operand" + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 0, 255)"))) + +; TRUE for comparisons we support. +(define_predicate "msp430_cmp_operator" + (match_code "eq,ne,lt,ltu,ge,geu")) + +; TRUE for comparisons we need to reverse. +(define_predicate "msp430_reversible_cmp_operator" + (match_code "gt,gtu,le,leu")) + +; TRUE for constants the constant generator can produce +(define_predicate "msp430_constgen_operator" + (and (match_code "const_int") + (match_test (" INTVAL (op) == 0 + || INTVAL (op) == 1 + || INTVAL (op) == 2 + || INTVAL (op) == 4 + || INTVAL (op) == 8 + || INTVAL (op) == -1 ")))) + +; TRUE for constants the constant generator can produce +(define_predicate "msp430_inv_constgen_operator" + (and (match_code "const_int") + (match_test (" INTVAL (op) == ~0 + || INTVAL (op) == ~1 + || INTVAL (op) == ~2 + || INTVAL (op) == ~4 + || INTVAL (op) == ~8 + || INTVAL (op) == ~(-1) ")))) + +(define_predicate "msp430_nonsubreg_operand" + (match_code "reg,mem")) + +; TRUE for constants which are bit positions for zero_extract +(define_predicate "msp430_bitpos" + (and (match_code "const_int") + (match_test (" INTVAL (op) >= 0 + && INTVAL (op) <= 15 ")))) Index: gcc/config/msp430/msp430.md =================================================================== --- gcc/config/msp430/msp430.md (revision 0) +++ gcc/config/msp430/msp430.md (revision 0) @@ -0,0 +1,1287 @@ +;; Machine Description for TI MSP43* processors +;; Copyright (C) 2013 Free Software Foundation, Inc. +;; Contributed by Red Hat. + +;; 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 3, 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 COPYING3. If not see +;; . + + +(define_constants + [ + (PC_REGNO 0) + (SP_REGNO 1) + (CARRY 2) + ]) + +(define_c_enum "unspec" + [ + UNS_PROLOGUE_START_MARKER + UNS_PROLOGUE_END_MARKER + UNS_EPILOGUE_START_MARKER + UNS_EPILOGUE_HELPER + + UNS_PUSHM + UNS_POPM + + UNS_GROW_AND_SWAP + UNS_SWAP_AND_SHRINK + ]) + +(include "predicates.md") +(include "constraints.md") + +(define_mode_iterator QHI [QI HI PSI]) + +;; There are two basic "family" tests we do here: +;; +;; msp430x - true if 430X instructions are available. +;; TARGET_LARGE - true if pointers are 20-bits +;; +;; Note that there are three supported cases, since the base 430 +;; doesn't have 20-bit pointers: +;; +;; 1. MSP430 cpu, small model +;; 2. MSP430X cpu, small model. +;; 3. MSP430X cpu, large model. + +;;------------------------------------------------------------ +;; Moves + +;; Push/Pop must be before the generic move patterns + +(define_insn "push" + [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNO))) + (match_operand:HI 0 "register_operand" "r"))] + "" + "PUSH\t%0" + ) + +(define_insn "pusha" + [(set (mem:PSI (pre_dec:PSI (reg:PSI SP_REGNO))) + (match_operand:PSI 0 "register_operand" "r"))] + "TARGET_LARGE" + "PUSHX.A\t%0" + ) + +(define_insn "pushm" + [(unspec_volatile [(match_operand 0 "register_operand" "r") + (match_operand 1 "immediate_operand" "i")] UNS_PUSHM)] + "" + "PUSHM%B0\t%1, %0" + ) + +(define_insn "pop" + [(set (match_operand:HI 0 "register_operand" "=r") + (mem:HI (post_inc:HI (reg:HI SP_REGNO))))] + "" + "POP\t%0" + ) + +(define_insn "popa" + [(set (match_operand:PSI 0 "register_operand" "=r") + (mem:PSI (post_inc:PSI (reg:PSI SP_REGNO))))] + "TARGET_LARGE" + "POPX.A\t%0" + ) + +;; This is nasty. Operand0 is bogus. It is only there so that we can get a +;; mode for the %B0 to work. We should use operand1 for this, but that does +;; not have a mode. +;; +;; Operand1 is actually a register, but we cannot accept (REG...) because the +;; cprop_hardreg pass can and will renumber registers even inside +;; unspec_volatiles. So we take an integer register number parameter and +;; fudge it to be a register name when we generate the assembler. +;; +;; The pushm pattern does not have this problem because of all of the +;; frame info cruft attached to it, so cprop_hardreg leaves it alone. +(define_insn "popm" + [(unspec_volatile [(match_operand 0 "register_operand" "r") + (match_operand 1 "immediate_operand" "i") + (match_operand 2 "immediate_operand" "i")] UNS_POPM)] + "" + "POPM%B0\t%2, r%D1" + ) + +;; The next two patterns are here to support a "feature" of how GCC implements +;; varargs. When a function uses varargs and the *second* to last named +;; argument is split between argument registers and the stack, gcc expects the +;; callee to allocate space on the stack that can contain the register-based +;; part of the argument. This space *has* to be just before the remaining +;; arguments (ie the ones that are fully on the stack). +;; +;; The problem is that the MSP430 CALL instruction pushes the return address +;; onto the stack in the exact place where the callee wants to allocate +;; this extra space. So we need a sequence of instructions that can allocate +;; the extra space and then move the return address down the stack, so that +;; the extra space is now adjacent to the remaining arguments. +;; +;; This could be constructed through regular insns, but they might be split up +;; by a misguided optimization, so an unspec volatile is used instead. + +(define_insn "grow_and_swap" + [(unspec_volatile [(const_int 0)] UNS_GROW_AND_SWAP) + (clobber (reg:CC CARRY)) + ] + "" + { if (TARGET_LARGE) + return "SUBA\t#2, r1 \n MOVX.A\t2(r1), 0(r1)"; + return "SUB\t#2, r1 \n MOV.W\t2(r1), 0(r1)"; + } + ) + +(define_insn "swap_and_shrink" + [(unspec_volatile [(const_int 0)] UNS_SWAP_AND_SHRINK) + (clobber (reg:CC CARRY)) + ] + "" + { return TARGET_LARGE + ? "MOVX.A\t0(r1), 2(r1) \n ADDA\t#2, SP" + : "MOV.W\t0(r1), 2(r1) \n ADD\t#2, SP"; + }) + +(define_insn "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "=rYs,rm") + (match_operand:QI 1 "general_operand" "riYs,rmi"))] + "" + "@ + MOV.B\t%1, %0 + MOV%X0.B\t%1, %0" +) + +(define_insn "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs,rm") + (match_operand:HI 1 "general_operand" "riYs,rmi"))] + "" + "@ + MOV.W\t%1, %0 + MOV%X0.W\t%1, %0" +) + +(define_expand "movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + "" + ) + +(define_insn_and_split "movsi_x" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (match_operand:SI 1 "general_operand" "rmi"))] + "" + "#" + "reload_completed" + [(set (match_operand:HI 2 "nonimmediate_operand") + (match_operand:HI 4 "general_operand")) + (set (match_operand:HI 3 "nonimmediate_operand") + (match_operand:HI 5 "general_operand"))] + "msp430_split_movsi (operands);" +) + +;; Some MOVX.A cases can be done with MOVA, this is only a few of them. +(define_insn "movpsi" + [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,Ya,rm") + (match_operand:PSI 1 "general_operand" "riYa,r,rmi"))] + "" + "@ + MOV%A0\t%1, %0 + MOV%A0\t%1, %0 + MOV%X0.%A0\t%1, %0") + +; This pattern is identical to the truncsipsi2 pattern except +; that it uses a SUBREG instead of a TRUNC. It is needed in +; order to prevent reload from converting (set:SI (SUBREG:PSI (SI))) +; into (SET:PSI (PSI)). +; +; Note: using POPM.A #1 is two bytes smaller than using POPX.A.... + +(define_insn "movsipsi2" + [(set (match_operand:PSI 0 "register_operand" "=r") + (subreg:PSI (match_operand:SI 1 "register_operand" "r") 0))] + "TARGET_LARGE" + "PUSH.W %H1 { PUSH.W %1 { POPM.A #1, %0" +) + +;;------------------------------------------------------------ +;; Math + +(define_insn "addpsi3" + [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,rm") + (plus:PSI (match_operand:PSI 1 "nonimmediate_operand" "%0,0") + (match_operand:PSI 2 "general_operand" "rLs,rmi"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + ADDA\t%2, %0 + ADDX.A\t%2, %0" +) + +(define_insn "addqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=rYs,rm") + (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") + (match_operand:QI 2 "general_operand" "riYs,rmi"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + ADD.B\t%2, %0 + ADD%X0.B\t%2, %0" +) + +(define_insn "addqi3_ze" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r") + (zero_extend:HI (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") + (match_operand:QI 2 "general_operand" "riYs,rmi")))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + ADD.B\t%2, %0 + ADD%X0.B\t%2, %0" +) + +(define_insn "addhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs,rm") + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "riYs,rmi"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + ADD.W\t%2, %0 + ADD%X0.W\t%2, %0" +) + +; This pattern is needed in order to avoid reload problems. +; It takes an SI pair of registers, adds a value to them, and +; then converts them into a single PSI register. + +(define_insn "addsipsi3" + [(set (subreg:SI (match_operand:PSI 0 "register_operand" "=&r") 0) + (plus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand 2 "general_operand" "rmi"))) + (clobber (reg:CC CARRY)) + ] + "" + "ADD.W\t%L2, %L0 { ADDC.W\t%H2, %H0 { PUSH.W %H0 { PUSH.W %L0 { POPM.A #1, %0" +) + +(define_insn "addsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,rm") + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") + (match_operand:SI 2 "general_operand" "r,mi"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + ADD\t%L2, %L0 { ADDC\t%H2, %H0 + ADD%X0\t%L2, %L0 { ADDC%X0\t%H2, %H0" +) + +; Version of addhi that exposes the carry operations, for SImode adds. +; +; We have these two add patterns and the splitter that follows because +; our tests have shown that this results in a significant reduction in +; code size - because GCC is able to discard any unused part of the +; addition. We have to annotate the patterns with the set and use of +; the carry flag because otherwise GCC will discard parts of the +; addition when they are actually needed. + +(define_insn "addhi3_cy" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "ri,rmi"))) + (set (reg:CC CARRY) + (compare (plus:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + ] + "" + "@ + ADD %2, %1 ; cy + ADD%X0 %2, %1 ; cy" + ) + +; Version of addhi that adds the carry, for SImode adds. +(define_insn "addchi4_cy" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") + (plus:HI (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "ri,rmi")) + (ltu:HI (reg:CC CARRY) (const_int 0)))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + ADDC %2, %1 + ADDC%X0 %2, %1" + ) + +; Split an SImode add into two HImode adds, keeping track of the carry +; so that gcc knows when it can and can't optimize away the two +; halves. +(define_split + [(set (match_operand:SI 0 "msp430_nonsubreg_operand" "=&rm") + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "rmi"))) + (clobber (reg:CC CARRY)) + ] + "" + [(parallel [(set (match_operand:HI 3 "nonimmediate_operand" "=&rm") + (plus:HI (match_dup 4) + (match_dup 5))) + (set (reg:CC CARRY) + (compare (plus:SI (match_dup 4) (match_dup 5)) + (const_int 0)))] + + ) + (parallel [(set (match_operand:HI 6 "nonimmediate_operand" "=&rm") + (plus:HI (plus:HI (match_dup 7) + (match_dup 8)) + (ltu:HI (reg:CC CARRY) (const_int 0)))) + (clobber (reg:CC CARRY)) + ]) + ] + " + operands[3] = msp430_subreg (HImode, operands[0], SImode, 0); + operands[4] = msp430_subreg (HImode, operands[1], SImode, 0); + operands[5] = msp430_subreg (HImode, operands[2], SImode, 0); + operands[6] = msp430_subreg (HImode, operands[0], SImode, 2); + operands[7] = msp430_subreg (HImode, operands[1], SImode, 2); + operands[8] = msp430_subreg (HImode, operands[2], SImode, 2); + if (GET_CODE (operands[5]) == CONST_INT) + { + operands[9] = GEN_INT (INTVAL (operands[5]) & 0xffff); + } + else + { + operands[9] = gen_rtx_ZERO_EXTEND (SImode, operands[5]); + } + " + ) + + +;; Alternatives 2 and 3 are to handle cases generated by reload. +(define_insn "subpsi3" + [(set (match_operand:PSI 0 "nonimmediate_operand" "=r, rm, &?r, ?&r") + (minus:PSI (match_operand:PSI 1 "general_operand" "0, 0, !r, !i") + (match_operand:PSI 2 "general_operand" "rLs, rmi, rmi, r"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + SUBA\t%2, %0 + SUBX.A\t%2, %0 + MOVX.A\t%1, %0 { SUBX.A\t%2, %0 + MOVX.A\t%1, %0 { SUBA\t%2, %0" +) + +;; Alternatives 2 and 3 are to handle cases generated by reload. +(define_insn "subqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=rYs, rm, &?r, ?&r") + (minus:QI (match_operand:QI 1 "general_operand" "0, 0, !r, !i") + (match_operand:QI 2 "general_operand" " riYs, rmi, rmi, r"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + SUB.B\t%2, %0 + SUB%X0.B\t%2, %0 + MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0 + MOV%X0.B\t%1, %0 { SUB%X0.B\t%2, %0" +) + +;; Alternatives 2 and 3 are to handle cases generated by reload. +(define_insn "subhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs, rm, &?r, ?&r") + (minus:HI (match_operand:HI 1 "general_operand" "0, 0, !r, !i") + (match_operand:HI 2 "general_operand" " riYs, rmi, rmi, r"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + SUB.W\t%2, %0 + SUB%X0.W\t%2, %0 + MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0 + MOV%X0.W\t%1, %0 { SUB%X0.W\t%2, %0" +) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=&rm") + (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:SI 2 "general_operand" "rmi"))) + (clobber (reg:CC CARRY)) + ] + "" + "SUB%X0\t%L2, %L0 { SUBC%X0\t%H2, %H0" +) + +(define_insn "*bic_cg" + [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,m") + (and:QHI (match_operand:QHI 1 "msp_general_operand" "0,0") + (match_operand 2 "msp430_inv_constgen_operator" "n,n")))] + "" + "@ + BIC%x0%B0\t#%I2, %0 + BIC%X0%B0\t#%I2, %0" +) + +(define_insn "bic3" + [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm") + (and:QHI (not:QHI (match_operand:QHI 1 "msp_general_operand" "rYs,rmn")) + (match_operand:QHI 2 "msp_nonimmediate_operand" "0,0")))] + "" + "@ + BIC%x0%B0\t%1, %0 + BIC%X0%B0\t%1, %0" +) + +(define_insn "and3" + [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm") + (and:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0") + (match_operand:QHI 2 "msp_general_operand" "riYs,rmi"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + AND%x0%B0\t%2, %0 + AND%X0%B0\t%2, %0" +) + +(define_insn "ior3" + [(set (match_operand:QHI 0 "msp_nonimmediate_operand" "=rYs,rm") + (ior:QHI (match_operand:QHI 1 "msp_nonimmediate_operand" "%0,0") + (match_operand:QHI 2 "msp_general_operand" "riYs,rmi"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + BIS%x0%B0\t%2, %0 + BIS%X0%B0\t%2, %0" +) + +(define_insn "xor3" + [(set (match_operand:QHI 0 "nonimmediate_operand" "=rYs,rm") + (xor:QHI (match_operand:QHI 1 "nonimmediate_operand" "%0,0") + (match_operand:QHI 2 "general_operand" "riYs,rmi"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + XOR%x0%B0\t%2, %0 + XOR%X0%B0\t%2, %0" +) + +;; Macro : XOR #~0, %0 +(define_insn "one_cmpl2" + [(set (match_operand:QHI 0 "nonimmediate_operand" "=rYs,m") + (not:QHI (match_operand:QHI 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + INV%x0%B0\t%0 + INV%X0%B0\t%0" +) + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs,m") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,0"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + SXT%X0\t%0 + SXT%X0\t%0" +) + +;; Note: QImode moves to registers clear the top byte +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rYs,m,r,r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,0,rYs,m"))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + AND\t#0xff, %0 + AND%X0\t#0xff, %0 + MOV.B\t%1,%0 + MOV%X0.B\t%1,%0" +) + +;; Eliminate extraneous zero-extends mysteriously created by gcc. +(define_peephole2 + [(set (match_operand:HI 0 "register_operand") + (zero_extend:HI (match_operand:QI 1 "general_operand"))) + (set (match_operand:HI 2 "register_operand") + (zero_extend:HI (match_operand:QI 3 "register_operand")))] + "REGNO (operands[0]) == REGNO (operands[2]) && REGNO (operands[2]) == REGNO (operands[3])" + [(set (match_dup 0) + (zero_extend:HI (match_dup 1)))] +) + +(define_insn "zero_extendhipsi2" + [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,m") + (zero_extend:PSI (match_operand:HI 1 "nonimmediate_operand" "rm,r")))] + "" + "MOVX\t%1, %0" +) + +(define_insn "truncpsihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (truncate:HI (match_operand:PSI 1 "register_operand" "r")))] + "" + "MOVX\t%1, %0" +) + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r"))) + (clobber (reg:CC CARRY)) + ] + "" + { return msp430x_extendhisi (operands); } +) + +(define_insn "extendhipsi2" + [(set (match_operand:PSI 0 "nonimmediate_operand" "=r") + (subreg:PSI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) 0)) + (clobber (reg:CC CARRY)) + ] + "TARGET_LARGE" + "RLAM #4, %0 { RRAM #4, %0" +) + +;; Look for cases where integer/pointer conversions are suboptimal due +;; to missing patterns, despite us not having opcodes for these +;; patterns. Doing these manually allows for alternate optimization +;; paths. +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")))] + "TARGET_LARGE" + "MOV.W\t#0,%H0" +) + +(define_insn "zero_extendhisipsi2" + [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,r") + (subreg:PSI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,r")) 0)) + (clobber (reg:CC CARRY)) + ] + "TARGET_LARGE" + "@ + AND.W\t#-1,%0 + MOV.W\t%1,%0" +) + +(define_insn "extend_and_shift1_hipsi2" + [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0) + (ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) + (const_int 1))) + (clobber (reg:CC CARRY)) + ] + "TARGET_LARGE" + "RLAM #4, %0 { RRAM #3, %0" +) + +(define_insn "extend_and_shift2_hipsi2" + [(set (subreg:SI (match_operand:PSI 0 "nonimmediate_operand" "=r") 0) + (ashift:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0")) + (const_int 2))) + (clobber (reg:CC CARRY)) + ] + "TARGET_LARGE" + "RLAM #4, %0 { RRAM #2, %0" +) + +; Nasty - we are sign-extending a 20-bit PSI value in one register into +; two adjacent 16-bit registers to make an SI value. There is no MSP430X +; instruction that will do this, so we push the 20-bit value onto the stack +; and then pop it off as two 16-bit values. +; +; FIXME: The MSP430X documentation does not specify if zero-extension or +; sign-extension happens when the 20-bit value is pushed onto the stack. +; It is probably zero-extension, but if not this pattern will not work +; when the PSI value is negative.. +; +; Note: using PUSHM.A #1 is two bytes smaller than using PUSHX.A.... + +(define_insn "zero_extendpsisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (zero_extend:SI (match_operand:PSI 1 "register_operand" "r"))) + (clobber (reg:CC CARRY)) + ] + "" + "* + if (REGNO (operands[1]) == SP_REGNO) + /* If the source register is the stack pointer, the value + stored in the stack slot will be the value *after* the + stack pointer has been decremented. So allow for that + here. */ + return \"PUSHM.A #1, %1 { ADDX.W #4, @r1 { POPX.W %0 { POPX.W %H0\"; + else + return \"PUSHM.A #1, %1 { POPX.W %0 { POPX.W %H0\"; + " +) + +; See the movsipsi2 pattern above for another way that GCC performs this +; conversion. +(define_insn "truncsipsi2" + [(set (match_operand:PSI 0 "register_operand" "=r") + (truncate:PSI (match_operand:SI 1 "register_operand" "r")))] + "" + "PUSH.W %H1 { PUSH.W %1 { POPM.A #1, %0" +) + +;;------------------------------------------------------------ +;; Shift Functions + +;; Note: We do not use the RPT ... SHIFT instruction sequence +;; when the repeat count is in a register, because even though RPT +;; accepts counts in registers, it does not work if the count is +;; zero, and the actual count in the register has to be one less +;; than the required number of iterations. We could encode a +;; seqeunce like this: +;; +;; bit #0xf, Rn +;; bz 1f +;; dec Rn +;; rpt Rn +;; Rm +;; inc Rn +;; 1: +;; +;; But is longer than calling a helper function, and we are mostly +;; concerned with code size. FIXME: Maybe enable a sequence like +;; this at -O3 and above ? +;; +;; Note - we ignore shift counts of less than one or more than 15. +;; This is permitted by the ISO C99 standard as such shifts result +;; in "undefined" behaviour. [6.5.7 (3)] + +;; signed A << C + +(define_expand "ashlhi3" + [(set (match_operand:HI 0 "nonimmediate_operand") + (ashift:HI (match_operand:HI 1 "general_operand") + (match_operand:HI 2 "general_operand"))) + (clobber (reg:CC CARRY)) + ] + "" + { + if (msp430x + && REG_P (operands[0]) + && REG_P (operands[1]) + && CONST_INT_P (operands[2])) + emit_insn (gen_430x_shift_left (operands[0], operands[1], operands[2])); + else + msp430_expand_helper (operands, \"__mspabi_slli\", true); + DONE; + } +) + +(define_insn "slli_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (ashift:HI (match_operand:HI 1 "general_operand" "0") + (const_int 1))) + (clobber (reg:CC CARRY)) + ] + "" + "RLA.W\t%0" ;; Note - this is a macro for ADD +) + +(define_insn "430x_shift_left" + [(set (match_operand:HI 0 "register_operand" "=r") + (ashift:HI (match_operand:HI 1 "register_operand" "0") + (match_operand 2 "immediate_operand" "n"))) + (clobber (reg:CC CARRY)) + ] + "msp430x" + "* + if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 16) + return \"rpt\t%2 { rlax.w\t%0\"; + return \"# nop left shift\"; + " +) + +(define_insn "slll_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (ashift:SI (match_operand:SI 1 "general_operand" "0") + (const_int 1))) + (clobber (reg:CC CARRY)) + ] + "" + "RLA.W\t%L0 { RLC.W\t%H0" +) + +(define_insn "slll_2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (ashift:SI (match_operand:SI 1 "general_operand" "0") + (const_int 2))) + (clobber (reg:CC CARRY)) + ] + "" + "RLA.W\t%L0 { RLC.W\t%H0 { RLA.W\t%L0 { RLC.W\t%H0" +) + +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "nonimmediate_operand") + (ashift:SI (match_operand:SI 1 "general_operand") + (match_operand:SI 2 "general_operand"))) + (clobber (reg:CC CARRY)) + ] + "" + "msp430_expand_helper (operands, \"__mspabi_slll\", true); + DONE;" +) + +;;---------- + +;; signed A >> C + +(define_expand "ashrhi3" + [(set (match_operand:HI 0 "nonimmediate_operand") + (ashiftrt:HI (match_operand:HI 1 "general_operand") + (match_operand:HI 2 "general_operand"))) + (clobber (reg:CC CARRY)) + ] + "" + { + if (msp430x + && REG_P (operands[0]) + && REG_P (operands[1]) + && CONST_INT_P (operands[2])) + emit_insn (gen_430x_arithmetic_shift_right (operands[0], operands[1], operands[2])); + else + msp430_expand_helper (operands, \"__mspabi_srai\", true); + DONE; + } +) + +(define_insn "srai_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (ashiftrt:HI (match_operand:HI 1 "general_operand" "0") + (const_int 1))) + (clobber (reg:CC CARRY)) + ] + "" + "RRA.W\t%0" +) + +(define_insn "430x_arithmetic_shift_right" + [(set (match_operand:HI 0 "register_operand" "=r") + (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") + (match_operand 2 "immediate_operand" "n"))) + (clobber (reg:CC CARRY)) + ] + "msp430x" + "* + if (INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 16) + return \"rpt\t%2 { rrax.w\t%0\"; + return \"# nop arith right shift\"; + " +) + +(define_insn "srap_1" + [(set (match_operand:PSI 0 "register_operand" "=r") + (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0") + (const_int 1))) + (clobber (reg:CC CARRY)) + ] + "msp430x" + "RRAM.A #1,%0" +) + +(define_insn "srap_2" + [(set (match_operand:PSI 0 "register_operand" "=r") + (ashiftrt:PSI (match_operand:PSI 1 "general_operand" "0") + (const_int 2))) + (clobber (reg:CC CARRY)) + ] + "msp430x" + "RRAM.A #2,%0" +) + +(define_insn "sral_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") + (const_int 1))) + (clobber (reg:CC CARRY)) + ] + "" + "RRA.W\t%H0 { RRC.W\t%L0" +) + +(define_insn "sral_2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (ashiftrt:SI (match_operand:SI 1 "general_operand" "0") + (const_int 2))) + (clobber (reg:CC CARRY)) + ] + "" + "RRA.W\t%H0 { RRC.W\t%L0 { RRA.W\t%H0 { RRC.W\t%L0" +) + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "nonimmediate_operand") + (ashiftrt:SI (match_operand:SI 1 "general_operand") + (match_operand:SI 2 "general_operand"))) + (clobber (reg:CC CARRY)) + ] + "" + "msp430_expand_helper (operands, \"__mspabi_sral\", true); + DONE;" +) + +;;---------- + +;; unsigned A >> C + +(define_expand "lshrhi3" + [(set (match_operand:HI 0 "nonimmediate_operand") + (lshiftrt:HI (match_operand:HI 1 "general_operand") + (match_operand:HI 2 "general_operand"))) + (clobber (reg:CC CARRY)) + ] + "" + { + if (msp430x + && REG_P (operands[0]) + && REG_P (operands[1]) + && CONST_INT_P (operands[2])) + emit_insn (gen_430x_logical_shift_right (operands[0], operands[1], operands[2])); + else + msp430_expand_helper (operands, \"__mspabi_srli\", true); + DONE; + } +) + +(define_insn "srli_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm") + (lshiftrt:HI (match_operand:HI 1 "general_operand" "0") + (const_int 1))) + (clobber (reg:CC CARRY)) + ] + "" + "CLRC { RRC.W\t%0" +) + +(define_insn "430x_logical_shift_right" + [(set (match_operand:HI 0 "register_operand" "=r") + (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") + (match_operand 2 "immediate_operand" "n"))) + (clobber (reg:CC CARRY)) + ] + "msp430x" + { + return msp430x_logical_shift_right (operands[2]); + } +) + +(define_insn "srlp_1" + [(set (match_operand:PSI 0 "register_operand" "=r") + (lshiftrt:PSI (match_operand:PSI 1 "general_operand" "0") + (const_int 1))) + (clobber (reg:CC CARRY)) + ] + "" + "RRUM.A #1,%0" +) + +(define_insn "srll_1" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") + (const_int 1))) + (clobber (reg:CC CARRY)) + ] + "" + "CLRC { RRC.W\t%H0 { RRC.W\t%L0" +) + +(define_insn "srll_2x" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") + (const_int 2))) + (clobber (reg:CC CARRY)) + ] + "msp430x" + "RRUX.W\t%H0 { RRC.W\t%L0 { RRUX.W\t%H0 { RRC.W\t%L0" +) + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "nonimmediate_operand") + (lshiftrt:SI (match_operand:SI 1 "general_operand") + (match_operand:SI 2 "general_operand"))) + (clobber (reg:CC CARRY)) + ] + "" + "msp430_expand_helper (operands, \"__mspabi_srll\", true); + DONE;" +) + +;;------------------------------------------------------------ +;; Function Entry/Exit + +(define_expand "prologue" + [(const_int 0)] + "" + "msp430_expand_prologue (); DONE;" + ) + +(define_expand "epilogue" + [(const_int 0)] + "" + "msp430_expand_epilogue (0); DONE;" + ) + + +(define_insn "epilogue_helper" + [(unspec_volatile [(match_operand 0 "immediate_operand" "i")] UNS_EPILOGUE_HELPER)] + "" + "BR%A0\t#__mspabi_func_epilog_%D0" + ) + + +(define_insn "prologue_start_marker" + [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_START_MARKER)] + "" + "; start of prologue" + ) + +(define_insn "prologue_end_marker" + [(unspec_volatile [(const_int 0)] UNS_PROLOGUE_END_MARKER)] + "" + "; end of prologue" + ) + +(define_insn "epilogue_start_marker" + [(unspec_volatile [(const_int 0)] UNS_EPILOGUE_START_MARKER)] + "" + "; start of epilogue" + ) + +;;------------------------------------------------------------ +;; Jumps + +(define_expand "call" + [(call:HI (match_operand 0 "") + (match_operand 1 ""))] + "" + "" +) + +(define_insn "call_internal" + [(call (mem:HI (match_operand 0 "general_operand" "rmi")) + (match_operand 1 ""))] + "" + "CALL%A0\t%0" +) + +(define_expand "call_value" + [(set (match_operand 0 "register_operand") + (call:HI (match_operand 1 "general_operand") + (match_operand 2 "")))] + "" + "" +) + +(define_insn "call_value_internal" + [(set (match_operand 0 "register_operand" "=r") + (call (mem:HI (match_operand 1 "general_operand" "rmi")) + (match_operand 2 "")))] + "" + "CALL%A0\t%1" +) + +(define_insn "msp_return" + [(return)] + "" + { return TARGET_LARGE ? "RETA" : "RET"; } +) + +;; This pattern is NOT, as expected, a return pattern. It's called +;; before reload and must only store its operands, and emit a +;; placeholder where the epilog needs to be. AFTER reload, the +;; placeholder should get expanded into a regular-type epilogue that +;; also does the EH return. +(define_expand "eh_return" + [(match_operand:HI 0 "" "")] + "" + "msp430_expand_eh_return (operands[0]); + emit_jump_insn (gen_msp430_eh_epilogue ()); + emit_barrier (); + DONE;" +) + +;; This is the actual EH epilogue. We emit it in the pattern above, +;; before reload, and convert it to a real epilogue after reload. +(define_insn_and_split "msp430_eh_epilogue" + [(eh_return)] + "" + "#" + "reload_completed" + [(const_int 0)] + "msp430_expand_epilogue (1); DONE;" + ) + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "BR%A0\t#%l0" +) + +;; FIXME: GCC currently (8/feb/2013) cannot handle symbol_refs +;; in indirect jumps (cf gcc.c-torture/compile/991213-3.c). +(define_insn "indirect_jump" + [(set (pc) + (match_operand 0 "nonimmediate_operand" "rYl"))] + "" + "BR%A0\t%0" +) + +;;------------------------------------------------------------ +;; Various Conditionals + +(define_expand "cbranch4" + [(parallel [(set (pc) (if_then_else + (match_operator 0 "" + [(match_operand:QHI 1 "nonimmediate_operand") + (match_operand:QHI 2 "general_operand")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CC CARRY))] + )] + "" + "msp430_fixup_compare_operands (mode, operands);" + ) + +(define_insn "cbranchpsi4_real" + [(set (pc) (if_then_else + (match_operator 0 "msp430_cmp_operator" + [(match_operand:PSI 1 "nonimmediate_operand" "r,rYs,rm") + (match_operand:PSI 2 "general_operand" "rLs,rYsi,rmi")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + CMP%A0\t%2, %1 { J%0\t%l3 + CMPX.A\t%2, %1 { J%0\t%l3 + CMPX.A\t%2, %1 { J%0\t%l3" + ) + +(define_insn "cbranchqi4_real" + [(set (pc) (if_then_else + (match_operator 0 "msp430_cmp_operator" + [(match_operand:QI 1 "nonimmediate_operand" "rYs,rm") + (match_operand:QI 2 "general_operand" "rYsi,rmi")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + CMP.B\t%2, %1 { J%0\t%l3 + CMP%X0.B\t%2, %1 { J%0\t%l3" + ) + +(define_insn "cbranchhi4_real" + [(set (pc) (if_then_else + (match_operator 0 "msp430_cmp_operator" + [(match_operand:HI 1 "nonimmediate_operand" "rYs,rm") + (match_operand:HI 2 "general_operand" "rYsi,rmi")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + CMP.W\t%2, %1 { J%0\t%l3 + CMP%X0.W\t%2, %1 { J%0\t%l3" + ) + +(define_insn "cbranchpsi4_reversed" + [(set (pc) (if_then_else + (match_operator 0 "msp430_reversible_cmp_operator" + [(match_operand:PSI 1 "general_operand" "rLs,rYsi,rmi") + (match_operand:PSI 2 "general_operand" "r,rYs,rm")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + CMP%A0\t%1, %2 { J%R0\t%l3 + CMPX.A\t%1, %2 { J%R0\t%l3 + CMPX.A\t%1, %2 { J%R0\t%l3" + ) + +(define_insn "cbranchqi4_reversed" + [(set (pc) (if_then_else + (match_operator 0 "msp430_reversible_cmp_operator" + [(match_operand:QI 1 "general_operand" "rYsi,rmi") + (match_operand:QI 2 "general_operand" "rYs,rm")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + CMP.B\t%1, %2 { J%R0\t%l3 + CMP%X0.B\t%1, %2 { J%R0\t%l3" + ) + +(define_insn "cbranchhi4_reversed" + [(set (pc) (if_then_else + (match_operator 0 "msp430_reversible_cmp_operator" + [(match_operand:HI 1 "general_operand" "rYsi,rmi") + (match_operand:HI 2 "general_operand" "rYs,rm")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + CMP.W\t%1, %2 { J%R0\t%l3 + CMP%X0.W\t%1, %2 { J%R0\t%l3" + ) + + +(define_insn "*bitbranch4" + [(set (pc) (if_then_else + (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYs,rm") + (match_operand:QHI 1 "msp_general_operand" "rYsi,rmi")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + BIT%x0%B0\t%1, %0 { JNE\t%l2 + BIT%X0%B0\t%1, %0 { JNE\t%l2" + ) + +(define_insn "*bitbranch4" + [(set (pc) (if_then_else + (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") + (match_operand:QHI 1 "msp_general_operand" "rmi")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (clobber (reg:CC CARRY)) + ] + "" + "BIT%x0%X0%B0\t%1, %0 { JEQ\t%l2" + ) + +(define_insn "*bitbranch4" + [(set (pc) (if_then_else + (eq (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") + (match_operand:QHI 1 "msp_general_operand" "rmi")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + (clobber (reg:CC CARRY)) + ] + "" + "BIT%X0%B0\t%1, %0 { JNE\t%l2" + ) + +(define_insn "*bitbranch4" + [(set (pc) (if_then_else + (ne (and:QHI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") + (match_operand:QHI 1 "msp_general_operand" "rmi")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + (clobber (reg:CC CARRY)) + ] + "" + "BIT%X0%B0\t%1, %0 { JEQ\t%l2" + ) + +;;------------------------------------------------------------ +;; zero-extend versions of the above + +(define_insn "*bitbranch4_z" + [(set (pc) (if_then_else + (ne (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rYs,rm") + (const_int 1) + (match_operand 1 "msp430_bitpos" "i,i")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (clobber (reg:CC CARRY)) + ] + "" + "@ + BIT%x0%B0\t%p1, %0 { JNE\t%l2 + BIT%X0%B0\t%p1, %0 { JNE\t%l2" + ) + +(define_insn "*bitbranch4_z" + [(set (pc) (if_then_else + (eq (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") + (const_int 1) + (match_operand 1 "msp430_bitpos" "i")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (clobber (reg:CC CARRY)) + ] + "" + "BIT%x0%X0%B0\t%p1, %0 { JEQ\t%l2" + ) + +(define_insn "*bitbranch4_z" + [(set (pc) (if_then_else + (eq (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") + (const_int 1) + (match_operand 1 "msp430_bitpos" "i")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + (clobber (reg:CC CARRY)) + ] + "" + "BIT%X0%B0\t%p1, %0 { JNE\t%l2" + ) + +(define_insn "*bitbranch4_z" + [(set (pc) (if_then_else + (ne (zero_extract:HI (match_operand:QHI 0 "msp_nonimmediate_operand" "rm") + (const_int 1) + (match_operand 1 "msp430_bitpos" "i")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + (clobber (reg:CC CARRY)) + ] + "" + "BIT%X0%B0\t%p1, %0 { JEQ\t%l2" + ) + +;;------------------------------------------------------------ +;; Misc + +(define_insn "nop" + [(const_int 0)] + "1" + "NOP" +) + Index: gcc/config/msp430/constraints.md =================================================================== --- gcc/config/msp430/constraints.md (revision 0) +++ gcc/config/msp430/constraints.md (revision 0) @@ -0,0 +1,74 @@ +;; Machine Description for TI MSP43* processors +;; Copyright (C) 2013 Free Software Foundation, Inc. +;; Contributed by Red Hat. + +;; 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 3, 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 COPYING3. If not see +;; . + +(define_register_constraint "R12" "R12_REGS" + "Register R12.") + +(define_register_constraint "R13" "R13_REGS" + "Register R13.") + +(define_constraint "K" + "Integer constant 1." + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 1, 1)"))) + +(define_constraint "L" + "Integer constant -1^20..1^19." + (and (match_code "const_int") + (match_test "IN_RANGE (ival, -1 << 20, 1 << 19)"))) + +(define_constraint "M" + "Integer constant 1-4." + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 1, 4)"))) + +;; We do not allow arbitrary constants, eg symbols or labels, +;; because their address may be above the 16-bit address limit +;; supported by the offset used in the MOVA instruction. +(define_constraint "Ya" + "Memory reference, any type, but restricted range of constants" + (and (match_code "mem") + (ior (match_code "reg" "0") + (and (match_code "plus" "0") + (match_code "reg" "00") + (match_test ("CONST_INT_P (XEXP (XEXP (op, 0), 1))"))) + (match_test "CONSTANT_P (XEXP (op, 0))") + ))) + +(define_constraint "Yl" + "Memory reference, labels only." + (and (match_code "mem") + (match_code "label_ref" "0"))) + + +;; These are memory references that are safe to use with the X suffix, +;; because we know/assume they need not index across the 64k boundary. +(define_constraint "Ys" + "Memory reference, stack only." + (and (match_code "mem") + (ior + (and (match_code "plus" "0") + (and (match_code "reg" "00") + (match_test ("CONST_INT_P (XEXP (XEXP (op, 0), 1))")) + (match_test ("IN_RANGE (INTVAL (XEXP (XEXP (op, 0), 1)), -1 << 15, (1 << 15)-1)")))) + (match_code "reg" "0") + ))) + + Index: gcc/config/msp430/t-msp430 =================================================================== --- gcc/config/msp430/t-msp430 (revision 0) +++ gcc/config/msp430/t-msp430 (revision 0) @@ -0,0 +1,43 @@ +# Makefile fragment for building GCC for the TI MSP430 target. +# Copyright (C) 2012-2013 Free Software Foundation, Inc. +# Contributed by Red Hat. +# +# 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 3, 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 COPYING3. If not see +# . + +# Enable multilibs: + +MULTILIB_OPTIONS = mmcu=msp430x mlarge +MULTILIB_DIRNAMES = 430x large + +# Match msp430X with msp430x. +MULTILIB_MATCHES = mmcu?msp430x=mmcu?msp430X + +# each supported MCU needs a line like this: +# MULTILIB_MATCHES += mmcu?msp430x123=mmcu?msp430x + +# The only way I figured this out was to hack the script to SHOW me +# what it's doing. It's non-obvious, but it matches the directory +# structure of the multilib tree, but using the options, not the +# directory names. A shell CASE statement is generated from these, so +# the usual CASE wildcards are supported. + +MULTILIB_EXCEPTIONS = mlarge + +MULTILIB_EXTRA_OPTS = + +msp430-c.o: $(srcdir)/config/msp430/msp430-c.c $(RTL_H) $(TREE_H) $(CONFIG_H) $(TM_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< Index: gcc/config/msp430/msp430.c =================================================================== --- gcc/config/msp430/msp430.c (revision 0) +++ gcc/config/msp430/msp430.c (revision 0) @@ -0,0 +1,1754 @@ +/* Subroutines used for code generation on TI MSP430 processors. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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 COPYING3. If not see + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "insn-config.h" +#include "conditions.h" +#include "output.h" +#include "insn-attr.h" +#include "flags.h" +#include "function.h" +#include "expr.h" +#include "optabs.h" +#include "libfuncs.h" +#include "recog.h" +#include "diagnostic-core.h" +#include "toplev.h" +#include "reload.h" +#include "df.h" +#include "ggc.h" +#include "tm_p.h" +#include "debug.h" +#include "target.h" +#include "target-def.h" +#include "langhooks.h" +#include "msp430-protos.h" +#include "dumpfile.h" +#include "opts.h" + + + +static void msp430_compute_frame_info (void); + + + +/* Run-time Target Specification */ + +bool msp430x = false; + +struct GTY(()) machine_function +{ + /* If set, the rest of the fields have been computed. */ + int computed; + /* Which registers need to be saved in the pro/epilogue. */ + int need_to_save [FIRST_PSEUDO_REGISTER]; + + /* These fields describe the frame layout... */ + /* arg pointer */ + /* 2/4 bytes for saved PC */ + int framesize_regs; + /* frame pointer */ + int framesize_locals; + int framesize_outgoing; + /* stack pointer */ + int framesize; + + /* How much we adjust the stack when returning from an exception + handler. */ + rtx eh_stack_adjust; +}; + +/* This is our init_machine_status, as set in + msp_option_override. */ +static struct machine_function * +msp430_init_machine_status (void) +{ + struct machine_function *m; + + m = ggc_alloc_cleared_machine_function (); + + return m; +} + +#undef TARGET_HANDLE_OPTION +#define TARGET_HANDLE_OPTION msp430_handle_option + +bool +msp430_handle_option (struct gcc_options *opts ATTRIBUTE_UNUSED, + struct gcc_options *opts_set ATTRIBUTE_UNUSED, + const struct cl_decoded_option *decoded ATTRIBUTE_UNUSED, + location_t loc ATTRIBUTE_UNUSED) +{ + return true; +} + +#undef TARGET_OPTION_OVERRIDE +#define TARGET_OPTION_OVERRIDE msp430_option_override + +static void +msp430_option_override (void) +{ + init_machine_status = msp430_init_machine_status; + + if (target_cpu + && (strstr (target_cpu, "430x") + || strstr (target_cpu, "430X"))) + msp430x = true; + + if (TARGET_LARGE && !msp430x) + error ("-mlarge requires a 430X-compatible -mcpu="); + + if (flag_exceptions || flag_non_call_exceptions + || flag_unwind_tables || flag_asynchronous_unwind_tables) + flag_omit_frame_pointer = false; + else + flag_omit_frame_pointer = true; + + /* This is a hack to work around a problem with the newlib build + mechanism. Newlib always appends CFLAGS to the end of the GCC + command line and always sets -O2 in CFLAGS. Thus it is not + possible to build newlib with -Os enabled. Until now... */ + if (TARGET_OPT_SPACE && optimize < 3) + optimize_size = 1; +} + + + +/* Storage Layout */ + +#undef TARGET_MS_BITFIELD_LAYOUT_P +#define TARGET_MS_BITFIELD_LAYOUT_P msp430_ms_bitfield_layout_p + +bool +msp430_ms_bitfield_layout_p (const_tree record_type ATTRIBUTE_UNUSED) +{ + return false; +} + + + +/* Register Usage */ + +/* Implements HARD_REGNO_NREGS. MSP430X registers can hold a single + PSImode value, but not an SImode value. */ +int +msp430_hard_regno_nregs (int regno ATTRIBUTE_UNUSED, + enum machine_mode mode) +{ + if (mode == PSImode && msp430x) + return 1; + return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) + / UNITS_PER_WORD); +} + +/* Implements HARD_REGNO_MODE_OK. */ +int +msp430_hard_regno_mode_ok (int regno ATTRIBUTE_UNUSED, + enum machine_mode mode) +{ + return regno <= (ARG_POINTER_REGNUM - msp430_hard_regno_nregs (regno, mode)); +} + +/* Implements MODES_TIEABLE_P. */ +bool +msp430_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2) +{ + if ((mode1 == PSImode || mode2 == SImode) + || (mode1 == SImode || mode2 == PSImode)) + return false; + + return ((GET_MODE_CLASS (mode1) == MODE_FLOAT + || GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT) + == (GET_MODE_CLASS (mode2) == MODE_FLOAT + || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT)); +} + +#undef TARGET_FRAME_POINTER_REQUIRED +#define TARGET_FRAME_POINTER_REQUIRED msp430_frame_pointer_required + +static bool +msp430_frame_pointer_required (void) +{ + return false; +} + +#undef TARGET_CAN_ELIMINATE +#define TARGET_CAN_ELIMINATE msp430_can_eliminate + +static bool +msp430_can_eliminate (const int from_reg ATTRIBUTE_UNUSED, + const int to_reg ATTRIBUTE_UNUSED) +{ + return true; +} + +/* Implements INITIAL_ELIMINATION_OFFSET. */ +int +msp430_initial_elimination_offset (int from ATTRIBUTE_UNUSED, + int to ATTRIBUTE_UNUSED) +{ + int rv = 0; /* as if arg to arg */ + + msp430_compute_frame_info (); + + switch (to) + { + case STACK_POINTER_REGNUM: + rv += cfun->machine->framesize_outgoing; + rv += cfun->machine->framesize_locals; + /* Fall through. */ + case FRAME_POINTER_REGNUM: + rv += cfun->machine->framesize_regs; + /* Allow for the saved return address. */ + rv += (TARGET_LARGE ? 4 : 2); + /* NB/ No need to allow for crtl->args.pretend_args_size. + GCC does that for us. */ + break; + default: + gcc_unreachable (); + } + + switch (from) + { + case FRAME_POINTER_REGNUM: + /* Allow for the fall through above. */ + rv -= (TARGET_LARGE ? 4 : 2); + rv -= cfun->machine->framesize_regs; + case ARG_POINTER_REGNUM: + break; + default: + gcc_unreachable (); + } + + return rv; +} + +/* Named Address Space support */ + + +/* Return the appropriate mode for a named address pointer. */ +#undef TARGET_ADDR_SPACE_POINTER_MODE +#define TARGET_ADDR_SPACE_POINTER_MODE msp430_addr_space_pointer_mode +#undef TARGET_ADDR_SPACE_ADDRESS_MODE +#define TARGET_ADDR_SPACE_ADDRESS_MODE msp430_addr_space_pointer_mode + +static enum machine_mode +msp430_addr_space_pointer_mode (addr_space_t addrspace) +{ + switch (addrspace) + { + default: + case ADDR_SPACE_GENERIC: + return Pmode; + case ADDR_SPACE_NEAR: + return HImode; + case ADDR_SPACE_FAR: + return PSImode; + } +} + +/* Function pointers are stored in unwind_word sized + variables, so make sure that unwind_word is big enough. */ +#undef TARGET_UNWIND_WORD_MODE +#define TARGET_UNWIND_WORD_MODE msp430_unwind_word_mode + +static enum machine_mode +msp430_unwind_word_mode (void) +{ + return TARGET_LARGE ? SImode : HImode; +} + +/* Determine if one named address space is a subset of another. */ +#undef TARGET_ADDR_SPACE_SUBSET_P +#define TARGET_ADDR_SPACE_SUBSET_P msp430_addr_space_subset_p +static bool +msp430_addr_space_subset_p (addr_space_t subset, addr_space_t superset) +{ + if (subset == superset) + return true; + else + return (subset != ADDR_SPACE_FAR && superset == ADDR_SPACE_FAR); +} + +#undef TARGET_ADDR_SPACE_CONVERT +#define TARGET_ADDR_SPACE_CONVERT msp430_addr_space_convert +/* Convert from one address space to another. */ +static rtx +msp430_addr_space_convert (rtx op, tree from_type, tree to_type) +{ + addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type)); + addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type)); + rtx result; + + if (to_as != ADDR_SPACE_FAR && from_as == ADDR_SPACE_FAR) + { + /* This is unpredictable, as we're truncating off usable address + bits. */ + + if (CONSTANT_P (op)) + return gen_rtx_CONST (HImode, op); + + result = gen_reg_rtx (HImode); + emit_insn (gen_truncpsihi2 (result, op)); + return result; + } + else if (to_as == ADDR_SPACE_FAR && from_as != ADDR_SPACE_FAR) + { + /* This always works. */ + + if (CONSTANT_P (op)) + return gen_rtx_CONST (PSImode, op); + + result = gen_reg_rtx (PSImode); + emit_insn (gen_zero_extendhipsi2 (result, op)); + return result; + } + else + gcc_unreachable (); +} + +/* Stack Layout and Calling Conventions. */ + +/* For each function, we list the gcc version and the TI version on + each line, where we're converting the function names. */ +static char const * const special_convention_function_names [] = +{ + "__muldi3", "__mspabi_mpyll", + "__udivdi3", "__mspabi_divull", + "__umoddi3", "__mspabi_remull", + "__divdi3", "__mspabi_divlli", + "__moddi3", "__mspabi_remlli", + "__mspabi_srall", + "__mspabi_srlll", + "__mspabi_sllll", + "__adddf3", "__mspabi_addd", + "__subdf3", "__mspabi_subd", + "__muldf3", "__mspabi_mpyd", + "__divdf3", "__mspabi_divd", + "__mspabi_cmpd", + NULL +}; + +/* TRUE if the function passed is a "speical" function. Special + functions pass two DImode parameters in registers. */ +static bool +msp430_special_register_convention_p (const char *name) +{ + int i; + + for (i = 0; special_convention_function_names [i]; i++) + if (! strcmp (name, special_convention_function_names [i])) + return true; + + return false; +} + +#undef TARGET_FUNCTION_VALUE_REGNO_P +#define TARGET_FUNCTION_VALUE_REGNO_P msp430_function_value_regno_p + +bool +msp430_function_value_regno_p (unsigned int regno) +{ + return regno == 12; +} + + +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE msp430_function_value + +rtx +msp430_function_value (const_tree ret_type, + const_tree fn_decl_or_type ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (TYPE_MODE (ret_type), 12); +} + +#undef TARGET_LIBCALL_VALUE +#define TARGET_LIBCALL_VALUE msp430_libcall_value + +rtx +msp430_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (mode, 12); +} + +/* Implements INIT_CUMULATIVE_ARGS. */ +void +msp430_init_cumulative_args (CUMULATIVE_ARGS *ca, + tree fntype ATTRIBUTE_UNUSED, + rtx libname ATTRIBUTE_UNUSED, + tree fndecl ATTRIBUTE_UNUSED, + int n_named_args ATTRIBUTE_UNUSED) +{ + const char *fname; + memset (ca, 0, sizeof(*ca)); + + ca->can_split = 1; + + if (fndecl) + fname = IDENTIFIER_POINTER (DECL_NAME (fndecl)); + else if (libname) + fname = XSTR (libname, 0); + else + fname = NULL; + + if (fname && msp430_special_register_convention_p (fname)) + ca->special_p = 1; +} + +/* Helper function for argument passing; this function is the common + code that determines where an argument will be passed. */ +static void +msp430_evaluate_arg (cumulative_args_t cap, + enum machine_mode mode, + const_tree type ATTRIBUTE_UNUSED, + bool named) +{ + CUMULATIVE_ARGS *ca = get_cumulative_args (cap); + int nregs = GET_MODE_SIZE (mode); + int i; + + ca->reg_count = 0; + ca->mem_count = 0; + + if (!named) + return; + + if (mode == PSImode) + nregs = 1; + else + nregs = (nregs + 1) / 2; + + if (ca->special_p) + { + /* Function is passed two DImode operands, in R8:R11 and + R12:15. */ + ca->start_reg = 8; + ca->reg_count = 4; + return; + } + + switch (nregs) + { + case 1: + for (i = 0; i < 4; i++) + if (! ca->reg_used [i]) + { + ca->reg_count = 1; + ca->start_reg = CA_FIRST_REG + i; + return; + } + break; + case 2: + for (i = 0; i < 3; i++) + if (! ca->reg_used [i] && ! ca->reg_used [i + 1]) + { + ca->reg_count = 2; + ca->start_reg = CA_FIRST_REG + i; + return; + } + if (! ca->reg_used [3] && ca->can_split) + { + ca->reg_count = 1; + ca->mem_count = 2; + ca->start_reg = CA_FIRST_REG + 3; + return; + } + break; + case 3: + case 4: + ca->can_split = 0; + if (! ca->reg_used [0] + && ! ca->reg_used [1] + && ! ca->reg_used [2] + && ! ca->reg_used [3]) + { + ca->reg_count = 4; + ca->start_reg = CA_FIRST_REG; + return; + } + break; + } +} + +#undef TARGET_PROMOTE_PROTOTYPES +#define TARGET_PROMOTE_PROTOTYPES msp430_promote_prototypes + +bool +msp430_promote_prototypes (const_tree fntype ATTRIBUTE_UNUSED) +{ + return false; +} + +#undef TARGET_FUNCTION_ARG +#define TARGET_FUNCTION_ARG msp430_function_arg + +rtx +msp430_function_arg (cumulative_args_t cap, + enum machine_mode mode, + const_tree type, + bool named) +{ + CUMULATIVE_ARGS *ca = get_cumulative_args (cap); + + msp430_evaluate_arg (cap, mode, type, named); + + if (ca->reg_count) + return gen_rtx_REG (mode, ca->start_reg); + + return 0; +} + +#undef TARGET_ARG_PARTIAL_BYTES +#define TARGET_ARG_PARTIAL_BYTES msp430_arg_partial_bytes + +int +msp430_arg_partial_bytes (cumulative_args_t cap, + enum machine_mode mode, + tree type, + bool named) +{ + CUMULATIVE_ARGS *ca = get_cumulative_args (cap); + + msp430_evaluate_arg (cap, mode, type, named); + + if (ca->reg_count && ca->mem_count) + return ca->reg_count * UNITS_PER_WORD; + + return 0; +} + +#undef TARGET_PASS_BY_REFERENCE +#define TARGET_PASS_BY_REFERENCE msp430_pass_by_reference + +static bool +msp430_pass_by_reference (cumulative_args_t cap ATTRIBUTE_UNUSED, + enum machine_mode mode, + const_tree type, + bool named ATTRIBUTE_UNUSED) +{ + return (mode == BLKmode + || (type && TREE_CODE (type) == RECORD_TYPE) + || (type && TREE_CODE (type) == UNION_TYPE)); +} + +#undef TARGET_CALLEE_COPIES +#define TARGET_CALLEE_COPIES msp430_callee_copies + +static bool +msp430_callee_copies (cumulative_args_t cap ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + const_tree type ATTRIBUTE_UNUSED, + bool named ATTRIBUTE_UNUSED) +{ + return true; +} + +#undef TARGET_FUNCTION_ARG_ADVANCE +#define TARGET_FUNCTION_ARG_ADVANCE msp430_function_arg_advance + +void +msp430_function_arg_advance (cumulative_args_t cap, + enum machine_mode mode, + const_tree type, + bool named) +{ + CUMULATIVE_ARGS *ca = get_cumulative_args (cap); + int i; + + msp430_evaluate_arg (cap, mode, type, named); + + if (ca->start_reg >= CA_FIRST_REG) + for (i = 0; i < ca->reg_count; i ++) + ca->reg_used [i + ca->start_reg - CA_FIRST_REG] = 1; + + ca->special_p = 0; +} + +#undef TARGET_FUNCTION_ARG_BOUNDARY +#define TARGET_FUNCTION_ARG_BOUNDARY msp430_function_arg_boundary + +static unsigned int +msp430_function_arg_boundary (enum machine_mode mode, const_tree type) +{ + if (mode == BLKmode + && int_size_in_bytes (type) > 1) + return 16; + if (GET_MODE_BITSIZE (mode) > 8) + return 16; + return 8; +} + +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY msp430_return_in_memory + +static bool +msp430_return_in_memory (const_tree ret_type, const_tree fntype ATTRIBUTE_UNUSED) +{ + enum machine_mode mode = TYPE_MODE (ret_type); + + if (mode == BLKmode + || (fntype && TREE_CODE (TREE_TYPE (fntype)) == RECORD_TYPE) + || (fntype && TREE_CODE (TREE_TYPE (fntype)) == UNION_TYPE)) + return true; + + if (GET_MODE_SIZE (mode) > 8) + return true; + + return false; +} + +#undef TARGET_GET_RAW_ARG_MODE +#define TARGET_GET_RAW_ARG_MODE msp430_get_raw_arg_mode + +static enum machine_mode +msp430_get_raw_arg_mode (int regno) +{ + return (regno == ARG_POINTER_REGNUM) ? VOIDmode : Pmode; +} + +#undef TARGET_GET_RAW_RESULT_MODE +#define TARGET_GET_RAW_RESULT_MODE msp430_get_raw_result_mode + +static enum machine_mode +msp430_get_raw_result_mode (int regno ATTRIBUTE_UNUSED) +{ + return Pmode; +} + +/* Addressing Modes */ + +#undef TARGET_LEGITIMATE_ADDRESS_P +#define TARGET_LEGITIMATE_ADDRESS_P msp430_legitimate_address_p + +static bool +reg_ok_for_addr (rtx r, bool strict) +{ + int rn = REGNO (r); + + if (strict && rn >= FIRST_PSEUDO_REGISTER) + rn = reg_renumber [rn]; + if (strict && 0 <= rn && rn < FIRST_PSEUDO_REGISTER) + return true; + if (!strict) + return true; + return false; +} + +bool +msp430_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, + rtx x ATTRIBUTE_UNUSED, + bool strict ATTRIBUTE_UNUSED) +{ + switch (GET_CODE (x)) + { + case MEM: + return false; + + case PLUS: + if (REG_P (XEXP (x, 0))) + { + if (GET_MODE (x) != GET_MODE (XEXP (x, 0))) + return false; + if (!reg_ok_for_addr (XEXP (x, 0), strict)) + return false; + switch (GET_CODE (XEXP (x, 1))) + { + case CONST: + case SYMBOL_REF: + case CONST_INT: + return true; + default: + return false; + } + } + return false; + + case REG: + if (!reg_ok_for_addr (x, strict)) + return false; + /* else... */ + case CONST: + case SYMBOL_REF: + case CONST_INT: + return true; + + default: + return false; + } +} + +#undef TARGET_LEGITIMATE_CONSTANT_P +#define TARGET_LEGITIMATE_CONSTANT_P msp430_legitimate_constant + +static bool +msp430_legitimate_constant (enum machine_mode mode, rtx x) +{ + return ! CONST_INT_P (x) + || mode != PSImode + /* GCC does not know the width of the PSImode, so make + sure that it does not try to use a constant value that + is out of range. */ + || (INTVAL (x) < (1 << 20) && INTVAL (x) >= (-1 << 20)); +} + + +#undef TARGET_RTX_COSTS +#define TARGET_RTX_COSTS msp430_rtx_costs + +static bool msp430_rtx_costs (rtx x ATTRIBUTE_UNUSED, + int code, + int outer_code ATTRIBUTE_UNUSED, + int opno ATTRIBUTE_UNUSED, + int * total, + bool speed ATTRIBUTE_UNUSED) +{ + switch (code) + { + case SIGN_EXTEND: + if (GET_MODE (x) == SImode && outer_code == SET) + { + *total = COSTS_N_INSNS (4); + return true; + } + break; + case ASHIFT: + case ASHIFTRT: + case LSHIFTRT: + if (!msp430x) + { + *total = COSTS_N_INSNS (100); + return true; + } + break; + } + return false; +} + +/* Function Entry and Exit */ + +/* The MSP430 call frame looks like this: + + + +--------------------+ + | | + | Stack Arguments | + | | + +--------------------+ <-- "arg pointer" + | | + | PC from call | (2 bytes for 430, 4 for TARGET_LARGE) + | | + +--------------------+ <-- SP before prologue, also AP + | | + | Saved Regs | (2 bytes per reg for 430, 4 per for TARGET_LARGE) + | | + +--------------------+ <-- "frame pointer" + | | + | Locals | + | | + +--------------------+ + | | + | Outgoing Args | + | | + +--------------------+ <-- SP during function + + +*/ + +/* We use this to wrap all emitted insns in the prologue, so they get + the "frame-related" (/f) flag set. */ +static rtx +F (rtx x) +{ + RTX_FRAME_RELATED_P (x) = 1; + return x; +} + +/* This is the one spot that decides if a register is to be saved and + restored in the prologue/epilogue. */ +static bool +msp430_preserve_reg_p (int regno) +{ + /* PC, SP, SR, and the constant generator. */ + if (regno <= 3) + return false; + + /* FIXME: add interrupt, EH, etc. */ + if (crtl->calls_eh_return) + return true; + + /* Shouldn't be more than the above, but just in case... */ + if (fixed_regs [regno]) + return false; + + if (!call_used_regs [regno] + && df_regs_ever_live_p (regno)) + return true; + + return false; +} + +/* Compute all the frame-related fields in our machine_function + structure. */ +static void +msp430_compute_frame_info (void) +{ + int i; + + cfun->machine->computed = 1; + cfun->machine->framesize_regs = 0; + cfun->machine->framesize_locals = get_frame_size (); + cfun->machine->framesize_outgoing = crtl->outgoing_args_size; + + for (i = 0; i < 16; i ++) + if (msp430_preserve_reg_p (i)) + { + cfun->machine->need_to_save [i] = 1; + cfun->machine->framesize_regs += (TARGET_LARGE ? 4 : 2); + } + else + cfun->machine->need_to_save [i] = 0; + + if ((cfun->machine->framesize_locals + cfun->machine->framesize_outgoing) & 1) + cfun->machine->framesize_locals ++; + + cfun->machine->framesize = (cfun->machine->framesize_regs + + cfun->machine->framesize_locals + + cfun->machine->framesize_outgoing); +} + +#undef TARGET_ASM_FUNCTION_PROLOGUE +#define TARGET_ASM_FUNCTION_PROLOGUE msp430_start_function + +static void +msp430_start_function (FILE *outfile, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED) +{ + int r, n; + + fprintf (outfile, "; start of function\n"); + fprintf (outfile, "; framesize_regs: %d\n", cfun->machine->framesize_regs); + fprintf (outfile, "; framesize_locals: %d\n", cfun->machine->framesize_locals); + fprintf (outfile, "; framesize_outgoing: %d\n", cfun->machine->framesize_outgoing); + fprintf (outfile, "; framesize: %d\n", cfun->machine->framesize); + fprintf (outfile, "; elim ap -> fp %d\n", msp430_initial_elimination_offset (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM)); + fprintf (outfile, "; elim fp -> sp %d\n", msp430_initial_elimination_offset (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM)); + + n = 0; + fprintf (outfile, "; saved regs:"); + for (r = 0; r < 16; r++) + if (cfun->machine->need_to_save [r]) + { + fprintf (outfile, " %s", reg_names [r]); + n = 1; + } + if (n == 0) + fprintf (outfile, "(none)"); + fprintf (outfile, "\n"); +} + +/* Common code to change the stack pointer. */ +static void +increment_stack (HOST_WIDE_INT amount) +{ + rtx inc; + rtx sp = stack_pointer_rtx; + + if (amount == 0) + return; + + if (amount < 0) + { + inc = GEN_INT (- amount); + if (TARGET_LARGE) + F (emit_insn (gen_subpsi3 (sp, sp, inc))); + else + F (emit_insn (gen_subhi3 (sp, sp, inc))); + } + else + { + inc = GEN_INT (amount); + if (TARGET_LARGE) + emit_insn (gen_addpsi3 (sp, sp, inc)); + else + emit_insn (gen_addhi3 (sp, sp, inc)); + } +} + +void +msp430_expand_prologue (void) +{ + int i, j; + int fs; + /* Always use stack_pointer_rtx instead of calling + rtx_gen_REG ourselves. Code elsewhere in GCC assumes + that there is a single rtx representing the stack pointer, + namely stack_pointer_rtx, and uses == to recognize it. */ + rtx sp = stack_pointer_rtx; + rtx p; + + emit_insn (gen_prologue_start_marker ()); + + if (!cfun->machine->computed) + msp430_compute_frame_info (); + + if (flag_stack_usage_info) + current_function_static_stack_size = cfun->machine->framesize; + + if (crtl->args.pretend_args_size) + { + rtx note; + + gcc_assert (crtl->args.pretend_args_size == 2); + + p = emit_insn (gen_grow_and_swap ()); + + /* Document the stack decrement... */ + note = F (gen_rtx_SET (Pmode, stack_pointer_rtx, + gen_rtx_MINUS (Pmode, stack_pointer_rtx, GEN_INT (2)))); + add_reg_note (p, REG_FRAME_RELATED_EXPR, note); + + /* ...and the establishment of a new location for the return address. */ + note = F (gen_rtx_SET (Pmode, gen_rtx_MEM (Pmode, + gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (-2))), + pc_rtx)); + add_reg_note (p, REG_CFA_OFFSET, note); + F (p); + } + + for (i = 15; i >= 4; i--) + if (cfun->machine->need_to_save [i]) + { + int seq, count; + rtx note; + + for (seq = i - 1; seq >= 4 && cfun->machine->need_to_save[seq]; seq --) + ; + count = i - seq; + + if (msp430x) + { + /* Note: with TARGET_LARGE we still use PUSHM as PUSHX.A is two bytes bigger. */ + p = F (emit_insn (gen_pushm (gen_rtx_REG (Pmode, i), + GEN_INT (count)))); + + note = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1)); + + XVECEXP (note, 0, 0) + = F (gen_rtx_SET (VOIDmode, + stack_pointer_rtx, + gen_rtx_PLUS (Pmode, + stack_pointer_rtx, + GEN_INT (count * (TARGET_LARGE ? -4 : -2))))); + + /* *sp-- = R[i-j] */ + /* sp+N R10 + ... + sp R4 */ + for (j = 0; j < count; j ++) + { + rtx addr; + int ofs = (count - j - 1) * (TARGET_LARGE ? 4 : 2); + + if (ofs) + addr = gen_rtx_PLUS (Pmode, sp, GEN_INT (ofs)); + else + addr = stack_pointer_rtx; + + XVECEXP (note, 0, j + 1) = + F (gen_rtx_SET (VOIDmode, + gen_rtx_MEM (Pmode, addr), + gen_rtx_REG (Pmode, i - j)) ); + } + + add_reg_note (p, REG_FRAME_RELATED_EXPR, note); + i -= count - 1; + } + else + F (emit_insn (gen_push (gen_rtx_REG (Pmode, i)))); + } + + if (frame_pointer_needed) + F (emit_move_insn (gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM), sp)); + + fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing; + + increment_stack (- fs); + + emit_insn (gen_prologue_end_marker ()); +} + +void +msp430_expand_epilogue (int is_eh) +{ + int i; + int fs; + int helper_n = 0; + + if (cfun->machine->need_to_save [10]) + { + /* Check for a helper function. */ + helper_n = 7; /* for when the loop below never sees a match. */ + for (i = 9; i >= 4; i--) + if (!cfun->machine->need_to_save [i]) + { + helper_n = 10 - i; + for (; i >= 4; i--) + if (cfun->machine->need_to_save [i]) + { + helper_n = 0; + break; + } + break; + } + } + + emit_insn (gen_epilogue_start_marker ()); + + fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing; + + increment_stack (fs); + + if (is_eh) + { + /* We need to add the right "SP" register save just after the + regular ones, so that when we pop it off we're in the EH + return frame, not this one. This overwrites our own return + address, but we're not going to be returning anyway. */ + rtx r12 = gen_rtx_REG (Pmode, 12); + rtx (*addPmode)(rtx, rtx, rtx) = TARGET_LARGE ? gen_addpsi3 : gen_addhi3; + + /* R12 will hold the new SP. */ + i = cfun->machine->framesize_regs; + emit_move_insn (r12, stack_pointer_rtx); + emit_insn (addPmode (r12, r12, EH_RETURN_STACKADJ_RTX)); + emit_insn (addPmode (r12, r12, GEN_INT (i))); + emit_move_insn (gen_rtx_MEM (Pmode, plus_constant (Pmode, stack_pointer_rtx, i)), r12); + } + + for (i = 4; i <= 15; i++) + if (cfun->machine->need_to_save [i]) + { + int seq, count; + + for (seq = i + 1; seq <= 15 && cfun->machine->need_to_save[seq]; seq ++) + ; + count = seq - i; + + if (msp430x) + { + /* Note: With TARGET_LARGE we still use POPM as POPX.A is two + bytes bigger. + Note: See the popm pattern for the explanation of the strange + arguments. */ + emit_insn (gen_popm (stack_pointer_rtx, GEN_INT (seq - 1), + GEN_INT (count))); + i += count - 1; + } + else if (i == 11 - helper_n + && crtl->args.pretend_args_size == 0 + /* Calling the helper takes as many bytes as the POP;RET sequence. */ + && helper_n != 1 + && !is_eh) + { + emit_insn (gen_epilogue_helper (GEN_INT (helper_n))); + return; + } + else + emit_insn (gen_pop (gen_rtx_REG (Pmode, i))); + } + + if (is_eh) + { + /* Also pop SP, which puts us into the EH return frame. Except + that you can't "pop" sp, you have to just load it off the + stack. */ + emit_move_insn (stack_pointer_rtx, gen_rtx_MEM (Pmode, stack_pointer_rtx)); + } + + if (crtl->args.pretend_args_size) + emit_insn (gen_swap_and_shrink ()); + + emit_jump_insn (gen_msp_return ()); +} + +/* Implements EH_RETURN_STACKADJ_RTX. Saved and used later in + m32c_emit_eh_epilogue. */ +rtx +msp430_eh_return_stackadj_rtx (void) +{ + if (!cfun->machine->eh_stack_adjust) + { + rtx sa; + + sa = gen_rtx_REG (Pmode, 15); + cfun->machine->eh_stack_adjust = sa; + } + return cfun->machine->eh_stack_adjust; +} + +/* This function is called before reload, to "fix" the stack in + preparation for an EH return. */ +void +msp430_expand_eh_return (rtx eh_handler) +{ + /* These are all Pmode */ + rtx ap, sa, ra, tmp; + + ap = arg_pointer_rtx; + sa = msp430_eh_return_stackadj_rtx (); + ra = eh_handler; + + tmp = ap; + tmp = gen_rtx_PLUS (Pmode, ap, sa); + tmp = plus_constant (Pmode, tmp, TARGET_LARGE ? -4 : -2); + tmp = gen_rtx_MEM (Pmode, tmp); + emit_move_insn (tmp, ra); +} + +/* This is a list of MD patterns that implement fixed-count shifts. */ +static struct { + const char *name; + int count; + int need_430x; + rtx (*genfunc)(rtx,rtx); +} const_shift_helpers[] = { +#define CSH(N,C,X,G) { "__mspabi_"N, C, X, gen_##G } + + CSH ("slli", 1, 1, slli_1), + CSH ("slll", 1, 1, slll_1), + CSH ("slll", 2, 1, slll_2), + + CSH ("srai", 1, 0, srai_1), + CSH ("sral", 1, 0, sral_1), + CSH ("sral", 2, 0, sral_2), + + CSH ("srll", 1, 0, srll_1), + CSH ("srll", 2, 1, srll_2x), + { 0, 0, 0, 0 } +#undef CSH +}; + +/* The MSP430 ABI defines a number of helper functions that should be + used for, for example, 32-bit shifts. This function is called to + emit such a function, using the table above to optimize some + cases. */ +void +msp430_expand_helper (rtx *operands, const char *helper_name, bool const_variants) +{ + rtx c, f; + char *helper_const = NULL; + int arg2 = 13; + int arg1sz = 1; + enum machine_mode arg0mode = GET_MODE (operands[0]); + enum machine_mode arg1mode = GET_MODE (operands[1]); + enum machine_mode arg2mode = GET_MODE (operands[2]); + int have_430x = msp430x ? 1 : 0; + + if (CONST_INT_P (operands[2])) + { + int i; + + for (i=0; const_shift_helpers[i].name; i++) + { + if (const_shift_helpers[i].need_430x <= have_430x + && strcmp (helper_name, const_shift_helpers[i].name) == 0 + && INTVAL (operands[2]) == const_shift_helpers[i].count) + { + emit_insn (const_shift_helpers[i].genfunc (operands[0], operands[1])); + return; + } + } + } + + if (arg1mode == VOIDmode) + arg1mode = arg0mode; + if (arg2mode == VOIDmode) + arg2mode = arg0mode; + + if (arg1mode == SImode) + { + arg2 = 14; + arg1sz = 2; + } + + if (const_variants + && CONST_INT_P (operands[2]) + && INTVAL (operands[2]) >= 1 + && INTVAL (operands[2]) <= 15) + { + /* Note that the INTVAL is limited in value and length by the conditional above. */ + int len = strlen (helper_name) + 4; + helper_const = (char *) xmalloc (len); + snprintf (helper_const, len, "%s_%ld", helper_name, (int) INTVAL (operands[2])); + } + + emit_move_insn (gen_rtx_REG (arg1mode, 12), + operands[1]); + if (!helper_const) + emit_move_insn (gen_rtx_REG (arg2mode, arg2), + operands[2]); + + c = gen_call_value_internal (gen_rtx_REG (arg0mode, 12), + gen_rtx_SYMBOL_REF (VOIDmode, helper_const ? helper_const : helper_name), + GEN_INT (0)); + c = emit_call_insn (c); + RTL_CONST_CALL_P (c) = 1; + + f = 0; + use_regs (&f, 12, arg1sz); + if (!helper_const) + use_regs (&f, arg2, 1); + add_function_usage_to (c, f); + + emit_move_insn (operands[0], + gen_rtx_REG (arg0mode, 12)); +} + +/* Called by cbranch4 to coerce operands into usable forms. */ +void +msp430_fixup_compare_operands (enum machine_mode my_mode, rtx * operands) +{ + /* constants we're looking for, not constants which are allowed. */ + int const_op_idx = 1; + + if (msp430_reversible_cmp_operator (operands[0], VOIDmode)) + const_op_idx = 2; + + if (GET_CODE (operands[const_op_idx]) != REG + && GET_CODE (operands[const_op_idx]) != MEM) + operands[const_op_idx] = copy_to_mode_reg (my_mode, operands[const_op_idx]); +} + +/* Simplify_gen_subreg() doesn't handle memory references the way we + need it to below, so we use this function for when we must get a + valid subreg in a "natural" state. */ +rtx +msp430_subreg (enum machine_mode mode, rtx r, enum machine_mode omode, int byte) +{ + rtx rv; + + if (GET_CODE (r) == SUBREG + && SUBREG_BYTE (r) == 0) + { + rtx ireg = SUBREG_REG (r); + enum machine_mode imode = GET_MODE (ireg); + + /* special case for (HI (SI (PSI ...), 0)) */ + if (imode == PSImode + && mode == HImode + && byte == 0) + rv = gen_rtx_SUBREG (mode, ireg, byte); + else + rv = simplify_gen_subreg (mode, ireg, imode, byte); + } + else if (GET_CODE (r) == MEM) + rv = adjust_address (r, mode, byte); + else + rv = simplify_gen_subreg (mode, r, omode, byte); + + if (!rv) + gcc_unreachable (); + + return rv; +} + +/* Called by movsi_x to generate the HImode operands. */ +void +msp430_split_movsi (rtx *operands) +{ + rtx op00, op02, op10, op12; + + op00 = msp430_subreg (HImode, operands[0], SImode, 0); + op02 = msp430_subreg (HImode, operands[0], SImode, 2); + + if (GET_CODE (operands[1]) == CONST + || GET_CODE (operands[1]) == SYMBOL_REF) + { + op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0)); + op10 = gen_rtx_CONST (HImode, op10); + op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16)); + op12 = gen_rtx_CONST (HImode, op12); + } + else + { + op10 = msp430_subreg (HImode, operands[1], SImode, 0); + op12 = msp430_subreg (HImode, operands[1], SImode, 2); + } + + if (rtx_equal_p (operands[0], operands[1])) + { + operands[2] = op02; + operands[4] = op12; + operands[3] = op00; + operands[5] = op10; + } + else if (rtx_equal_p (op00, op12) + /* Catch the case where we are loading (rN, rN+1) from mem (rN). */ + || (REG_P (op00) && reg_mentioned_p (op00, op10)) + /* Or storing (rN) into mem (rN). */ + || (REG_P (op10) && reg_mentioned_p (op10, op00)) + ) + { + operands[2] = op02; + operands[4] = op12; + operands[3] = op00; + operands[5] = op10; + } + else + { + operands[2] = op00; + operands[4] = op10; + operands[3] = op02; + operands[5] = op12; + } +} + + + +/* The MSPABI specifies the names of various helper functions, many of + which are compatible with GCC's helpers. This table maps the GCC + name to the MSPABI name. */ +static const struct +{ + char const * const gcc_name; + char const * const ti_name; +} + helper_function_name_mappings [] = +{ + /* Floating point to/from integer conversions. */ + { "__truncdfsf2", "__mspabi_cvtdf" }, + { "__extendsfdf2", "__mspabi_cvtfd" }, + { "__fixdfhi", "__mspabi_fixdi" }, + { "__fixdfsi", "__mspabi_fixdli" }, + { "__fixdfdi", "__mspabi_fixdlli" }, + { "__fixunsdfhi", "__mspabi_fixdu" }, + { "__fixunsdfsi", "__mspabi_fixdul" }, + { "__fixunsdfdi", "__mspabi_fixdull" }, + { "__fixsfhi", "__mspabi_fixfi" }, + { "__fixsfsi", "__mspabi_fixfli" }, + { "__fixsfdi", "__mspabi_fixflli" }, + { "__fixunsfhi", "__mspabi_fixfu" }, + { "__fixunsfsi", "__mspabi_fixful" }, + { "__fixunsfdi", "__mspabi_fixfull" }, + { "__floathisf", "__mspabi_fltif" }, + { "__floatsisf", "__mspabi_fltlif" }, + { "__floatdisf", "__mspabi_fltllif" }, + { "__floathidf", "__mspabi_fltid" }, + { "__floatsidf", "__mspabi_fltlid" }, + { "__floatdidf", "__mspabi_fltllid" }, + { "__floatunhisf", "__mspabi_fltuf" }, + { "__floatunsisf", "__mspabi_fltulf" }, + { "__floatundisf", "__mspabi_fltullf" }, + { "__floatunhidf", "__mspabi_fltud" }, + { "__floatunsidf", "__mspabi_fltuld" }, + { "__floatundidf", "__mspabi_fltulld" }, + + /* Floating point comparisons. */ + /* GCC uses individual functions for each comparison, TI uses one + compare <=> function. */ + + /* Floating point arithmatic */ + { "__adddf3", "__mspabi_addd" }, + { "__addsf3", "__mspabi_addf" }, + { "__divdf3", "__mspabi_divd" }, + { "__divsf3", "__mspabi_divf" }, + { "__muldf3", "__mspabi_mpyd" }, + { "__mulsf3", "__mspabi_mpyf" }, + { "__subdf3", "__mspabi_subd" }, + { "__subsf3", "__mspabi_subf" }, + /* GCC does not use helper functions for negation */ + + /* Integer multiply, divide, remainder. */ + /* Note: gcc doesn't know about hardware multiply options (yet?) */ + { "__mulhi3", "__mspabi_mpyi" }, + { "__mulsi3", "__mspabi_mpyl" }, + { "__muldi3", "__mspabi_mpyll" }, +#if 0 + /* Clarify signed vs unsigned first. */ + { "__mulhisi3", "__mspabi_mpysl" }, /* gcc doesn't use widening multiply (yet?) */ + { "__mulsidi3", "__mspabi_mpysll" }, /* gcc doesn't use widening multiply (yet?) */ +#endif + + { "__divhi3", "__mspabi_divi" }, + { "__divsi3", "__mspabi_divli" }, + { "__divdi3", "__mspabi_divlli" }, + { "__udivhi3", "__mspabi_divu" }, + { "__udivsi3", "__mspabi_divlu" }, + { "__udivdi3", "__mspabi_divllu" }, + { "__modhi3", "__mspabi_remi" }, + { "__modsi3", "__mspabi_remli" }, + { "__moddi3", "__mspabi_remlli" }, + { "__umodhi3", "__mspabi_remu" }, + { "__umodsi3", "__mspabi_remul" }, + { "__umoddi3", "__mspabi_remull" }, + + /* Bitwise operations. */ + /* Rotation - no rotation support yet. */ + /* Logical left shift - gcc already does these itself. */ + /* Arithmetic left shift - gcc already does these itself. */ + /* Arithmetic right shift - gcc already does these itself. */ + + { NULL, NULL } +}; + +/* This function does the same as the default, but it will replace GCC + function names with the MSPABI-specified ones. */ +void +msp430_output_labelref (FILE *file, const char *name) +{ + int i; + + for (i = 0; helper_function_name_mappings [i].gcc_name; i++) + if (! strcmp (helper_function_name_mappings [i].gcc_name, name)) + { + fputs (helper_function_name_mappings [i].ti_name, file); + return; + } + + fputs (name, file); +} + +#undef TARGET_PRINT_OPERAND +#define TARGET_PRINT_OPERAND msp430_print_operand + +/* Common code for msp430_print_operand(). */ +static void +msp430_print_operand_raw (FILE * file, rtx op, int letter ATTRIBUTE_UNUSED) +{ + int i; + + switch (GET_CODE (op)) + { + case REG: + fprintf (file, "%s", reg_names [REGNO (op)]); + break; + + case CONST_INT: + i = INTVAL (op); + if (TARGET_ASM_HEX) + fprintf (file, "%#x", i); + else + fprintf (file, "%d", i); + break; + + case CONST: + case PLUS: + case MINUS: + case SYMBOL_REF: + case LABEL_REF: + output_addr_const (file, op); + break; + + default: + print_rtl (file, op); + break; + } +} + +static void +msp430_print_operand (FILE * file, rtx op, int letter) +{ + rtx addr; + + /* We can't use c, n, a, or l. */ + switch (letter) + { + case 'Z': + gcc_assert (CONST_INT_P (op)); + /* Print the constant value, less one. */ + fprintf (file, "#%ld", INTVAL (op) - 1); + return; + case 'Y': + gcc_assert (CONST_INT_P (op)); + /* Print the constant value, less four. */ + fprintf (file, "#%ld", INTVAL (op) - 4); + return; + case 'D': + /* print a decimal value without a leading '#'. */ + if (GET_CODE (op) == CONST_INT) + { + int i = INTVAL (op); + fprintf (file, "%d", i); + return; + } + break; + case 'I': + if (GET_CODE (op) == CONST_INT) + { + /* Inverse of constants */ + int i = INTVAL (op); + fprintf (file, "%d", ~i); + return; + } + op = XEXP (op, 0); + break; + case 'r': /* Conditional jump where the condition is reversed. */ + switch (GET_CODE (op)) + { + case EQ: fprintf (file, "NE"); break; + case NE: fprintf (file, "EQ"); break; + case GEU: fprintf (file, "LO"); break; + case LTU: fprintf (file, "HS"); break; + case GE: fprintf (file, "L"); break; + case LT: fprintf (file, "GE"); break; + /* Assume these have reversed operands. */ + case GTU: fprintf (file, "HS"); break; + case LEU: fprintf (file, "LO"); break; + case GT: fprintf (file, "GE"); break; + case LE: fprintf (file, "L"); break; + default: + msp430_print_operand_raw (file, op, letter); + break; + } + return; + case 'R': /* Conditional jump where the operands are reversed. */ + switch (GET_CODE (op)) + { + case GTU: fprintf (file, "LO"); break; + case LEU: fprintf (file, "HS"); break; + case GT: fprintf (file, "L"); break; + case LE: fprintf (file, "GE"); break; + default: + msp430_print_operand_raw (file, op, letter); + break; + } + return; + case 'p': /* Bit position. 0 == 0x01, 3 = 0x08 etc. */ + gcc_assert (CONST_INT_P (op)); + fprintf (file, "#%d", 1 << INTVAL (op)); + return; + case 'B': + switch (GET_MODE (op)) + { + case QImode: fprintf (file, ".B"); return; + case HImode: fprintf (file, ".W"); return; + case PSImode: fprintf (file, ".A"); return; + case SImode: fprintf (file, ".A"); return; + default: + return; + } + case 'L': /* Low half. */ + switch (GET_CODE (op)) + { + case MEM: + op = adjust_address (op, Pmode, 0); + break; + case REG: + break; + case CONST_INT: + op = GEN_INT (INTVAL (op) & 0xffff); + letter = 0; + break; + default: + /* If you get here, figure out a test case :-) */ + gcc_unreachable (); + } + break; + case 'H': /* high half */ + switch (GET_CODE (op)) + { + case MEM: + op = adjust_address (op, Pmode, 2); + break; + case REG: + op = gen_rtx_REG (Pmode, REGNO (op) + 1); + break; + case CONST_INT: + op = GEN_INT (INTVAL (op) >> 16); + letter = 0; + break; + default: + /* If you get here, figure out a test case :-) */ + gcc_unreachable (); + } + break; + + case 'X': + /* This is used to turn, for example, an ADD opcode into an ADDX + opcode when we're using 20-bit addresses. */ + if (TARGET_LARGE) + fprintf (file, "X"); + /* We don't care which operand we use, but we want 'X' in the MD + file, so we do it this way. */ + return; + + case 'x': + /* Similarly, but only for PSImodes. BIC, for example, needs this. */ + if (TARGET_LARGE && GET_MODE (op) == PSImode) + fprintf (file, "X"); + return; + + case 'A': + /* Likewise, for BR -> BRA. */ + if (TARGET_LARGE) + fprintf (file, "A"); + return; + } + + switch (GET_CODE (op)) + { + case REG: + msp430_print_operand_raw (file, op, letter); + break; + + case MEM: + addr = XEXP (op, 0); + switch (GET_CODE (addr)) + { + case REG: + fprintf (file, "@%s", reg_names [REGNO (addr)]); + break; + case PLUS: + msp430_print_operand_raw (file, XEXP (addr, 1), letter); + fprintf (file, "(%s)", reg_names [REGNO (XEXP (addr, 0))]); + break; + case CONST: + case CONST_INT: + case SYMBOL_REF: + case LABEL_REF: + fprintf (file, "&"); + msp430_print_operand_raw (file, addr, letter); + break; + + default: + print_rtl (file, addr); + break; + } + break; + + case CONST_INT: + case CONST: + case SYMBOL_REF: + case LABEL_REF: + if (letter == 0) + fprintf (file, "#"); + msp430_print_operand_raw (file, op, letter); + break; + + case EQ: fprintf (file, "EQ"); break; + case NE: fprintf (file, "NE"); break; + case GEU: fprintf (file, "HS"); break; + case LTU: fprintf (file, "LO"); break; + case GE: fprintf (file, "GE"); break; + case LT: fprintf (file, "L"); break; + + default: + print_rtl (file, op); + break; + } + +} + + +/* Frame stuff. */ + +rtx +msp430_return_addr_rtx (int count) +{ + int ra_size; + if (count) + return NULL_RTX; + + ra_size = TARGET_LARGE ? 4 : 2; + if (crtl->args.pretend_args_size) + ra_size += 2; + + return gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, arg_pointer_rtx, GEN_INT (- ra_size))); +} + +rtx +msp430_incoming_return_addr_rtx (void) +{ + return gen_rtx_MEM (Pmode, stack_pointer_rtx); +} + +/* Instruction generation stuff. */ + +/* Generate a sequence of instructions to sign-extend an HI + value into an SI value. Handles the tricky case where + we are overwriting the destination. */ + +const char * +msp430x_extendhisi (rtx * operands) +{ + if (REGNO (operands[0]) == REGNO (operands[1])) + /* Low word of dest == source word. */ + return "BIT.W #0x8000, %L0 { SUBC.W %H0, %H0 { INV.W %H0, %H0"; /* 8-bytes. */ + + if (! msp430x) + /* Note: This sequence is approximately the same length as invoking a helper + function to perform the sign-extension, as in: + + MOV.W %1, %L0 + MOV.W %1, r12 + CALL __mspabi_srai_15 + MOV.W r12, %H0 + + but this version does not involve any function calls or using argument + registers, so it reduces register pressure. */ + return "MOV.W %1, %L0 { BIT.W #0x8000, %L0 { SUBC.W %H0, %H0 { INV.W %H0, %H0"; /* 10-bytes. */ + + if (REGNO (operands[0]) + 1 == REGNO (operands[1])) + /* High word of dest == source word. */ + return "MOV.W %1, %L0 { RPT #15 { RRAX.W %H0"; /* 6-bytes. */ + + /* No overlap between dest and source. */ + return "MOV.W %1, %L0 { MOV.W %1, %H0 { RPT #15 { RRAX.W %H0"; /* 8-bytes. */ +} + +/* Likewise for logical right shifts. */ +const char * +msp430x_logical_shift_right (rtx amount) +{ + /* The MSP430X's logical right shift instruction - RRUM - does + not use an extension word, so we cannot encode a repeat count. + Try various alternatives to work around this. If the count + is in a register we are stuck, hence the assert. */ + gcc_assert (CONST_INT_P (amount)); + + if (INTVAL (amount) <= 0 + || INTVAL (amount) >= 16) + return "# nop logical shift."; + + if (INTVAL (amount) > 0 + && INTVAL (amount) < 5) + return "rrum.w\t%2, %0"; /* Two bytes. */ + + if (INTVAL (amount) > 4 + && INTVAL (amount) < 9) + return "rrum.w\t#4, %0 { rrum.w\t%Y2, %0 "; /* Four bytes. */ + + /* First we logically shift right by one. Now we know + that the top bit is zero and we can use the arithmetic + right shift instruction to perform the rest of the shift. */ + return "rrum.w\t#1, %0 { rpt\t%Z2 { rrax.w\t%0"; /* Six bytes. */ +} + +struct gcc_target targetm = TARGET_INITIALIZER; + +#include "gt-msp430.h" Index: gcc/config/msp430/msp430-c.c =================================================================== --- gcc/config/msp430/msp430-c.c (revision 0) +++ gcc/config/msp430/msp430-c.c (revision 0) @@ -0,0 +1,36 @@ +/* MSP430 C-specific support + Copyright (C) 2013 Free Software Foundation, Inc. + Contributed by Red Hat, Inc. + + 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 3, 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 COPYING3. If not see + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "c-family/c-common.h" +#include "msp430-protos.h" + +/* Implements REGISTER_TARGET_PRAGMAS. */ +void +msp430_register_pragmas (void) +{ + c_register_addr_space ("__near", ADDR_SPACE_NEAR); + if (msp430x) + c_register_addr_space ("__far", ADDR_SPACE_FAR); +} Index: gcc/config/msp430/msp430.opt =================================================================== --- gcc/config/msp430/msp430.opt (revision 0) +++ gcc/config/msp430/msp430.opt (revision 0) @@ -0,0 +1,26 @@ +msim +Target +Use simulator runtime + +masm-hex +Target Mask(ASM_HEX) +Force assembly output to always use hex constants + +mmcu= +Target Joined RejectNegative Var(target_cpu) +Specify the cpu to build for. If the name begins with 'msp430x' then the 430X instructions are enabled + +mlarge +Target Mask(LARGE) RejectNegative +Select large model - 20-bit addresses/pointers + +msmall +Target InverseMask(LARGE) RejectNegative +Select small model - 16-bit addresses/pointers (default) + +mrelax +Target Report +Optimize opcode sizes at link time + +mOs +Target Undocumented Mask(OPT_SPACE) Index: gcc/config/msp430/msp430-modes.def =================================================================== --- gcc/config/msp430/msp430-modes.def (revision 0) +++ gcc/config/msp430/msp430-modes.def (revision 0) @@ -0,0 +1,3 @@ +/* 20-bit address */ +PARTIAL_INT_MODE (SI); + Index: gcc/config/msp430/README.txt =================================================================== --- gcc/config/msp430/README.txt (revision 0) +++ gcc/config/msp430/README.txt (revision 0) @@ -0,0 +1,7 @@ +Random Notes +------------ + +The MSP430 port does not use leading underscores. However, the +assembler has no way of differentiating between, for example, register +R12 and symbol R12. So, if you do "int r12;" in your C program, you +may get an assembler error, and will certainly have runtime problems. Index: gcc/config/msp430/msp430.h =================================================================== --- gcc/config/msp430/msp430.h (revision 0) +++ gcc/config/msp430/msp430.h (revision 0) @@ -0,0 +1,399 @@ +/* GCC backend definitions for the TI MSP430 Processor + Copyright (C) 2012 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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 COPYING3. If not see + . */ + + +/* Run-time Target Specification */ + +/* True if the MSP430x extensions are enabled. */ +#ifndef IN_LIBGCC2 +extern bool msp430x; +#endif + +#define TARGET_CPU_CPP_BUILTINS() \ + do \ + { \ + builtin_define ("__MSP430__"); \ + if (msp430x) \ + { \ + builtin_define ("__MSP430X__"); \ + builtin_assert ("cpu=MSP430X"); \ + if (TARGET_LARGE) \ + builtin_define ("__MSP430X_LARGE__"); \ + } \ + else \ + builtin_assert ("cpu=MSP430"); \ + } \ + while (0) + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{pg:gcrt0.o%s}%{!pg:crt0.o%s} crtbegin.o%s" + +/* -lgcc is included because crtend.o needs __mspabi_func_epilog_1. */ +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s crtn.o%s -lgcc" + +#define ASM_SPEC "-mP " /* Enable polymorphic instructions. */ \ + "%{mmcu=msp430x:-mmcu=msp430X;mmcu=*:-mmcu=%*} " /* Pass the MCU type on to the assembler. */ \ + "%{mrelax=-mQ} " /* Pass the relax option on to the assembler. */ \ + "%{mlarge:-ml} " /* Tell the assembler if we are building for the LARGE pointer model. */ \ + "%{ffunction-sections:-gdwarf-sections}" /* If function sections are being created then create DWARF line number sections as well. */ + +/* Enable linker section garbage collection by default, unless we + are creating a relocatable binary (gc does not work) or debugging + is enabled (the GDB testsuite relies upon unused entities not being deleted). */ +#define LINK_SPEC "%{mrelax:--relax} %{mlarge:%{!r:%{!g:--gc-sections}}}" + +#undef LIB_SPEC +#define LIB_SPEC " \ +--start-group \ +-lc \ +-lgcc \ +%{msim:-lsim} \ +%{!msim:-lnosys} \ +--end-group \ +%{!T*: %{msim: %{mlarge:%Tmsp430xl-sim.ld}%{!mlarge:%Tmsp430-sim.ld}}%{!msim:%Tmsp430.ld}} \ +" + + +/* Storage Layout */ + +#define BITS_BIG_ENDIAN 0 +#define BYTES_BIG_ENDIAN 0 +#define WORDS_BIG_ENDIAN 0 + + +#ifdef IN_LIBGCC2 +/* This is to get correct SI and DI modes in libgcc2.c (32 and 64 bits). */ +#define UNITS_PER_WORD 4 +/* We have a problem with libgcc2. It only defines two versions of + each function, one for "int" and one for "long long". Ie it assumes + that "sizeof (int) == sizeof (long)". For the MSP430 this is not true + and we need a third set of functions. We explicitly define + LIBGCC2_UNITS_PER_WORD here so that it is clear that we are expecting + to get the SI and DI versions from the libgcc2.c sources, and we + provide our own set of HI functions, which is why this + definition is surrounded by #ifndef..#endif. */ +#ifndef LIBGCC2_UNITS_PER_WORD +#define LIBGCC2_UNITS_PER_WORD 4 +#endif +#else +/* Actual width of a word, in units (bytes). */ +#define UNITS_PER_WORD 2 +#endif + +#define SHORT_TYPE_SIZE 16 +#define INT_TYPE_SIZE 16 +#define LONG_TYPE_SIZE 32 +#define LONG_LONG_TYPE_SIZE 64 + +#define FLOAT_TYPE_SIZE 32 +#define DOUBLE_TYPE_SIZE 64 +#define LONG_DOUBLE_TYPE_SIZE 64 /*DOUBLE_TYPE_SIZE*/ + +#define LIBGCC2_HAS_DF_MODE 1 +#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64 + +#define DEFAULT_SIGNED_CHAR 0 + +#define STRICT_ALIGNMENT 1 +#define FUNCTION_BOUNDARY 16 +#define BIGGEST_ALIGNMENT 16 +#define STACK_BOUNDARY 16 +#define PARM_BOUNDARY 8 +#define PCC_BITFIELD_TYPE_MATTERS 1 + +#define STACK_GROWS_DOWNWARD 1 +#define FRAME_GROWS_DOWNWARD 1 +#define FIRST_PARM_OFFSET(FNDECL) 0 + +#define MAX_REGS_PER_ADDRESS 1 + +#define Pmode (TARGET_LARGE ? PSImode : HImode) +/* Note: 32 is a lie. Large pointers are actually 20-bits wide. But gcc + thinks that any non-power-of-2 pointer size equates to BLKmode, which + causes all kinds of problems... */ +#define POINTER_SIZE (TARGET_LARGE ? 32 : 16) +#define POINTERS_EXTEND_UNSIGNED 1 + +#define ADDR_SPACE_NEAR 1 +#define ADDR_SPACE_FAR 2 + +#define REGISTER_TARGET_PRAGMAS() msp430_register_pragmas() + +#if 1 /* XXX */ +/* Define this macro if it is advisable to hold scalars in registers + in a wider mode than that declared by the program. In such cases, + the value is constrained to be within the bounds of the declared + type, but kept valid in the wider mode. The signedness of the + extension may differ from that of the type. */ + +#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < 2) \ + (MODE) = HImode; +#endif + +/* Layout of Source Language Data Types */ + +#undef SIZE_TYPE +#define SIZE_TYPE (TARGET_LARGE ? "long unsigned int" : "unsigned int") +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE (TARGET_LARGE ? "long int" : "int") +#undef WCHAR_TYPE +#define WCHAR_TYPE "long int" +#undef WCHAR_TYPE_SIZE +#define WCHAR_TYPE_SIZE BITS_PER_WORD +#define FUNCTION_MODE HImode +#define CASE_VECTOR_MODE Pmode +#define HAS_LONG_COND_BRANCH 0 +#define HAS_LONG_UNCOND_BRANCH 0 + +#define LOAD_EXTEND_OP(M) ZERO_EXTEND +/*#define WORD_REGISTER_OPERATIONS 1*/ + +#define MOVE_MAX 8 +#define STARTING_FRAME_OFFSET 0 + +#define INCOMING_RETURN_ADDR_RTX \ + msp430_incoming_return_addr_rtx () + +#define RETURN_ADDR_RTX(COUNT, FA) \ + msp430_return_addr_rtx (COUNT) + +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +#define SLOW_BYTE_ACCESS 0 + + +/* Register Usage */ + +/* gas doesn't recognize PC (R0), SP (R1), and SR (R2) as register + names. */ +#define REGISTER_NAMES \ +{ \ + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", \ + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", \ + "argptr" \ +} + +enum reg_class +{ + NO_REGS, + R12_REGS, + R13_REGS, + GEN_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "R12_REGS", \ + "R13_REGS", \ + "GEN_REGS", \ + "ALL_REGS" \ +} + +#define REG_CLASS_CONTENTS \ +{ \ + 0x00000000, \ + 0x00001000, \ + 0x00002000, \ + 0x0000fff2, \ + 0x0001ffff \ +} + +#define GENERAL_REGS GEN_REGS +#define BASE_REG_CLASS GEN_REGS +#define INDEX_REG_CLASS GEN_REGS +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define PC_REGNUM 0 +#define STACK_POINTER_REGNUM 1 +#define CC_REGNUM 2 +#define FRAME_POINTER_REGNUM 4 /* not usually used, call preserved */ +#define ARG_POINTER_REGNUM 16 +#define STATIC_CHAIN_REGNUM 5 /* FIXME */ + +#define FIRST_PSEUDO_REGISTER 17 + +#define REGNO_REG_CLASS(REGNO) ((REGNO) < 17 \ + ? GEN_REGS : NO_REGS) + +#define TRAMPOLINE_SIZE 4 /* FIXME */ +#define TRAMPOLINE_ALIGNMENT 16 /* FIXME */ + +#define ELIMINABLE_REGS \ +{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ + { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM }, \ + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }} + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + (OFFSET) = msp430_initial_elimination_offset ((FROM), (TO)) + + +#define FUNCTION_ARG_REGNO_P(N) ((N) >= 8 && (N) < ARG_POINTER_REGNUM) +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* 1 == register can't be used by gcc, in general + 0 == register can be used by gcc, in general */ +#define FIXED_REGISTERS \ +{ \ + 1,0,1,1, 0,0,0,0, \ + 0,0,0,0, 0,0,0,0, \ + 1, \ +} + +/* 1 == value changes across function calls + 0 == value is the same after a call */ +/* R4 through R10 are callee-saved */ +#define CALL_USED_REGISTERS \ +{ \ + 1,0,1,1, 0,0,0,0, \ + 0,0,0,1, 1,1,1,1, \ + 1, \ +} + +#define REG_ALLOC_ORDER \ + { 12, 13, 14, 15, 10, 9, 8, 7, 6, 5, 4, 11, 0, 1, 2, 3, 16 } +/* { 11, 15, 14, 13, 12, 10, 9, 8, 7, 6, 5, 4, 0, 1, 2, 3, 16 }*/ + +#define REGNO_OK_FOR_BASE_P(regno) 1 +#define REGNO_OK_FOR_INDEX_P(regno) 1 + + + +typedef struct { + /* These two are the current argument status. */ + char reg_used[4]; +#define CA_FIRST_REG 12 + char can_split; + /* These two are temporaries used internally. */ + char start_reg; + char reg_count; + char mem_count; + char special_p; +} CUMULATIVE_ARGS; + +#define INIT_CUMULATIVE_ARGS(CA, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \ + msp430_init_cumulative_args (&CA, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) + + +/* FIXME */ +#define NO_PROFILE_COUNTERS 1 +#define PROFILE_BEFORE_PROLOGUE 1 + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tcall\t__mcount\n"); + +#define HARD_REGNO_NREGS(REGNO, MODE) \ + msp430_hard_regno_nregs (REGNO, MODE) + +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + msp430_hard_regno_mode_ok (REGNO, MODE) + +#define MODES_TIEABLE_P(MODE1, MODE2) \ + msp430_modes_tieable_p (MODE1, MODE2) + +/* Exception Handling */ + +/* R12,R13,R14 - EH data + R15 - stack adjustment */ + +#define EH_RETURN_DATA_REGNO(N) \ + (((N) < 3) ? ((N) + 12) : INVALID_REGNUM) + +#define EH_RETURN_HANDLER_RTX \ + gen_rtx_MEM(Pmode, gen_rtx_PLUS (Pmode, gen_rtx_REG(Pmode, SP_REGNO), gen_rtx_REG (Pmode, 15))) + +#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 15) + +#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) DW_EH_PE_udata4 + + +/* Stack Layout and Calling Conventions */ + + +/* Addressing Modes */ + + + +#define TEXT_SECTION_ASM_OP ".text" +#define DATA_SECTION_ASM_OP ".data" +#define BSS_SECTION_ASM_OP "\t.section .bss" + +#define ASM_COMMENT_START " ;" +#define ASM_APP_ON "" +#define ASM_APP_OFF "" +#define LOCAL_LABEL_PREFIX ".L" +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" + +#define GLOBAL_ASM_OP "\t.global\t" + +#define ASM_OUTPUT_LABELREF(FILE, SYM) msp430_output_labelref ((FILE), (SYM)) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, "\t.long .L%d\n", VALUE) + +/* This is how to output an element of a case-vector that is relative. + Note: The local label referenced by the "3b" below is emitted by + the tablejump insn. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, "\t.long .L%d - 1b\n", VALUE) + + +#define ASM_OUTPUT_ALIGN(STREAM, LOG) \ + do \ + { \ + if ((LOG) == 0) \ + break; \ + fprintf (STREAM, "\t.balign %d\n", 1 << (LOG)); \ + } \ + while (0) + +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +#undef DWARF2_ADDR_SIZE +#define DWARF2_ADDR_SIZE 4 + +#define INCOMING_FRAME_SP_OFFSET (POINTER_SIZE / BITS_PER_UNIT) + +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG + +#define DWARF2_ASM_LINE_DEBUG_INFO 1 + +/* Prevent reload (and others) from choosing HImode stack slots + when spilling hard registers when they may contain PSImode values. */ +#define HARD_REGNO_CALLER_SAVE_MODE(REGNO,NREGS,MODE) \ + ((TARGET_LARGE && ((NREGS) <= 2)) ? PSImode : choose_hard_reg_mode ((REGNO), (NREGS), false)) + +/* Also stop GCC from thinking that it can eliminate (SUBREG:PSI (SI)). */ +#define CANNOT_CHANGE_MODE_CLASS(FROM,TO,CLASS) \ + ( ((TO) == PSImode && (FROM) == SImode) \ + || ((TO) == SImode && (FROM) == PSImode) \ + || ((TO) == DImode && (FROM) == PSImode) \ + || ((TO) == PSImode && (FROM) == DImode) \ + ) + +#define ACCUMULATE_OUTGOING_ARGS 1 [wwwdocs] ? htdocs/.#index.html.1.882 Index: htdocs/backends.html =================================================================== RCS file: /cvs/gcc/wwwdocs/htdocs/backends.html,v retrieving revision 1.46 diff -p -U 5 -r1.46 backends.html --- htdocs/backends.html 16 Jul 2012 21:19:20 -0000 1.46 +++ htdocs/backends.html 23 Jul 2013 21:17:58 -0000 @@ -90,10 +90,11 @@ mep | F C p g d t s microblaze CB bd s mips | Q CB qr p bda s mmix | HM Q C q p b a e mn10300 | ?? c g s ms1 | S F B p g bd +msp430 | L FI l p g s pa | ? Q CBD qr m da e pdp11 | L IC qrcp e rs6000 | Q C qr da s390 | ? Q qr p g bda e sh | Q CB qr bda Index: htdocs/index.html =================================================================== RCS file: /cvs/gcc/wwwdocs/htdocs/index.html,v retrieving revision 1.887 diff -p -U 5 -r1.887 index.html --- htdocs/index.html 31 May 2013 11:41:08 -0000 1.887 +++ htdocs/index.html 23 Jul 2013 21:17:58 -0000 @@ -51,10 +51,14 @@ mission statement.

News

+
TI MSP430 support + [2013-05-09]
+
A port for the TI MSP430 has been contributed by Red Hat Inc.
+
GCC 4.8.1 released [2013-05-31]
GCC 4.6.4 released Index: htdocs/readings.html =================================================================== RCS file: /cvs/gcc/wwwdocs/htdocs/readings.html,v retrieving revision 1.231 diff -p -U 5 -r1.231 readings.html --- htdocs/readings.html 1 Apr 2013 10:49:54 -0000 1.231 +++ htdocs/readings.html 23 Jul 2013 21:17:58 -0000 @@ -213,10 +213,15 @@ Intel®64 and IA-32 Architectures Sof
  • mn10300
    Manufacturer: Matsushita
    Alternate chip name: AM30
    GDB includes a simulator.
  • + +
  • msp430 +
    Manufacturer: Texas Instruments +
    GDB includes a simulator. +
  • ns32k
    Manufacturer: National Semiconductor
    NS32FX200 Home Page