Mercurial > hg > index.cgi
changeset 439:ff4b6095ee72
Bump patch number on gcc6809 patch.
The previous update from Brett Gordon <beretta42@gmail.com> updated the
gcc6809 patch but didn't update it's patch number tag. Update the tag now.
author | William Astle <lost@l-w.ca> |
---|---|
date | Tue, 15 Aug 2017 20:49:58 -0600 |
parents | f18cc0c87a7e |
children | fda62f676ed4 |
files | extra/gcc6809lw-4.6.4-6.patch extra/gcc6809lw-4.6.4-7.patch |
diffstat | 2 files changed, 8164 insertions(+), 8164 deletions(-) [+] |
line wrap: on
line diff
--- a/extra/gcc6809lw-4.6.4-6.patch Tue Aug 15 20:48:40 2017 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8164 +0,0 @@ -diff -urN gcc-4.6.4-clean/config.sub gcc-4.6.4/config.sub ---- gcc-4.6.4-clean/config.sub 2010-05-25 07:22:07.000000000 -0600 -+++ gcc-4.6.4/config.sub 2015-07-20 19:44:52.766843181 -0600 -@@ -313,7 +313,7 @@ - c6x) - basic_machine=tic6x-unknown - ;; -- m6811 | m68hc11 | m6812 | m68hc12 | picochip) -+ m6809 | m6811 | m68hc11 | m6812 | m68hc12 | picochip) - # Motorola 68HC11/12. - basic_machine=$basic_machine-unknown - os=-none -@@ -354,7 +354,7 @@ - | i*86-* | i860-* | i960-* | ia64-* \ - | ip2k-* | iq2000-* \ - | lm32-* \ -- | m32c-* | m32r-* | m32rle-* \ -+ | m32c-* | m32r-* | m32rle-* | m6809-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ -@@ -509,6 +509,10 @@ - basic_machine=arm-unknown - os=-cegcc - ;; -+ coco) -+ basic_machine=coco -+ os=-none -+ ;; - convex-c1) - basic_machine=c1-convex - os=-bsd -diff -urN gcc-4.6.4-clean/configure gcc-4.6.4/configure ---- gcc-4.6.4-clean/configure 2011-12-18 03:03:44.000000000 -0700 -+++ gcc-4.6.4/configure 2015-07-20 19:44:52.766843181 -0600 -@@ -3439,6 +3439,9 @@ - m32r-*-*) - noconfigdirs="$noconfigdirs ${libgcj}" - ;; -+ m6809*) -+ noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 target-libgloss ${libgcj}" -+ ;; - m68hc11-*-*|m6811-*-*|m68hc12-*-*|m6812-*-*) - noconfigdirs="$noconfigdirs target-libstdc++-v3 ${libgcj}" - libgloss_dir=m68hc11 -diff -urN gcc-4.6.4-clean/configure.ac gcc-4.6.4/configure.ac ---- gcc-4.6.4-clean/configure.ac 2011-11-18 04:45:44.000000000 -0700 -+++ gcc-4.6.4/configure.ac 2015-07-20 19:44:52.766843181 -0600 -@@ -885,6 +885,9 @@ - m32r-*-*) - noconfigdirs="$noconfigdirs ${libgcj}" - ;; -+ m6809*) -+ noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 target-libgloss ${libgcj}" -+ ;; - m68hc11-*-*|m6811-*-*|m68hc12-*-*|m6812-*-*) - noconfigdirs="$noconfigdirs target-libstdc++-v3 ${libgcj}" - libgloss_dir=m68hc11 -diff -urN gcc-4.6.4-clean/gcc/calls.c gcc-4.6.4/gcc/calls.c ---- gcc-4.6.4-clean/gcc/calls.c 2012-02-09 10:27:25.000000000 -0700 -+++ gcc-4.6.4/gcc/calls.c 2015-07-20 19:44:52.766843181 -0600 -@@ -2561,7 +2561,7 @@ - call sequence. - Also do the adjustments before a throwing call, otherwise - exception handling can fail; PR 19225. */ -- if (pending_stack_adjust >= 32 -+ if (pending_stack_adjust >= 8 - || (pending_stack_adjust > 0 - && (flags & ECF_MAY_BE_ALLOCA)) - || (pending_stack_adjust > 0 -diff -urN gcc-4.6.4-clean/gcc/config/m6809/crt0.S gcc-4.6.4/gcc/config/m6809/crt0.S ---- gcc-4.6.4-clean/gcc/config/m6809/crt0.S 1969-12-31 17:00:00.000000000 -0700 -+++ gcc-4.6.4/gcc/config/m6809/crt0.S 2015-07-20 19:44:52.766843181 -0600 -@@ -0,0 +1,173 @@ -+;;; -+;;; Copyright 2006, 2007, 2008, 2009 by Brian Dominy <brian@oddchange.com> -+;;; -+;;; 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 -+;;; <http://www.gnu.org/licenses/>. -+ -+ /* Declare external for main() */ -+ .globl _main -+ -+ -+/* The startup is heavily dependent on the type of machine and -+OS environment that is available at the start point. -+For the most part, the general idea is the same across machines, -+but the implementation is vastly different. This is managed via -+conditional compiles throughout the startup code for each of the -+supported machines. */ -+ -+#ifdef TARGET_COCO /* CoCo memory map */ -+ -+#define COCO_RAMROM_MODE 0xFFDE -+#define COCO_ALLRAM_MODE 0xFFDF -+#define COCO_PAGE1 0xFFD5 -+ -+/* SAM M1 and M0 adjusts the memory size */ -+ -+#define BASIC_WARMSTART_FLAG 0x0071 -+#define BASIC_START 0xA027 -+ -+#define __STACK_TOP 0x6800 -+ -+#else /* Simulator (default) memory map */ -+ -+#define SIM_EXIT_REG 0xFF01 -+ -+#define __STACK_TOP 0xFE00 -+ -+#endif -+ -+ -+ .area .data -+ .area .ctors -+ .area .dtors -+ .area .bss -+ -+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+ ;;; -+ ;;; __exit : Exit point from the program -+ ;;; For simulation, this writes to a special I/O register that -+ ;;; the simulator interprets as end-of-program. -+ ;;; -+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+ .area .text -+ .globl __exit -+__exit: -+#ifdef TARGET_COCO -+ ;; Go back to ROM/RAM mode -+ sta COCO_RAMROM_MODE -+ clr BASIC_WARMSTART_FLAG -+ jmp BASIC_START -+#else -+ tfr x,d -+ stb SIM_EXIT_REG -+ bra __exit -+#endif -+ -+ -+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+ ;;; -+ ;;; __start : Entry point to the program -+ ;;; -+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+ .area .text -+ .globl __start -+__start: -+ -+#ifdef HAVE_DIRECT -+ ;; Initialize the direct page pointer -+ lda #<s_.direct -+ tfr a,dp -+#endif -+ -+#ifdef TARGET_COCO -+ ;; Turn off interrupts -+ orcc #(0x10|0x40) -+ -+ ;; Setup All RAM Mode -+ sta COCO_ALLRAM_MODE -+#endif /* TARGET_COCO */ -+ -+ ;; Initialize the stack -+ lds #__STACK_TOP - 2 -+ -+ ;; Call any "initializer" functions -+ ldu #s_.ctors -+__ctors_loop: -+ ldy ,u++ -+ cmpy #0 -+ beq __ctors_done -+ jsr ,y -+ bra __ctors_loop -+__ctors_done: -+ -+ ;; Enable interrupts on the simulator -+#ifndef TARGET_COCO -+ andcc #~(0x10|0x40) -+#endif -+ -+ ;; Set up the environment -+ -+ ;; Set up argc/argv arrays -+ -+ ;; Call the main function. The exit code will -+ ;; be returned in the X register, unless compiled -+ ;; with -mdret, in which case it comes back in D. -+ jsr _main -+ -+ ;; Call any finalizer functions -+ ldu #s_.dtors -+__dtors_loop: -+ ldy ,u++ -+ cmpy #0 -+ beq __dtors_done -+ jsr ,y -+ bra __dtors_loop -+__dtors_done: -+ -+ ;; If main returns, then invoke _exit() to stop the program -+ ;; The C library doesn't support -mdret yet, so move the -+ ;; argument first. -+#ifdef __DRET__ -+ tfr d,x -+#endif -+ jmp _exit -+ -+ -+ -+ ;;; -+ ;;; __crt0_vector : Default handler for interrupts -+ ;;; -+ .area .text -+___crt0_vector: -+ ;; The default behavior is to simply ignore all -+ ;; non-reset interrupts. -+ rti -+ -+ -+ ;;; -+ ;;; vector : The interrupt vector table -+ ;;; The linker will ensure that this gets loaded at address 0xFFF0. -+ ;;; -+ .area vector -+vectors: -+ .word ___crt0_vector -+ .word ___crt0_vector -+ .word ___crt0_vector -+ .word ___crt0_vector -+ .word ___crt0_vector -+ .word ___crt0_vector -+ .word ___crt0_vector -+ .word __start -diff -urN gcc-4.6.4-clean/gcc/config/m6809/libgcc1.s gcc-4.6.4/gcc/config/m6809/libgcc1.s ---- gcc-4.6.4-clean/gcc/config/m6809/libgcc1.s 1969-12-31 17:00:00.000000000 -0700 -+++ gcc-4.6.4/gcc/config/m6809/libgcc1.s 2015-07-20 19:44:52.766843181 -0600 -@@ -0,0 +1,511 @@ -+/* libgcc routines for m6809 -+ Copyright (C) 2006 Free Software Foundation, 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 -+<http://www.gnu.org/licenses/>. */ -+ -+/* As a special exception, if you link this library with other files, -+ some of which are compiled with GCC, to produce an executable, -+ this library does not by itself cause the resulting executable -+ to be covered by the GNU General Public License. -+ This exception does not however invalidate any other reasons why -+ the executable file might be covered by the GNU General Public License. */ -+ -+ -+#define SIGFPE jmp _abort -+ -+ -+ ; Shift functions -+ ; On input, D is value to be shifted, and X has shift count. -+ ; Result is also in D. -+ -+#ifdef L_ashlhi3 -+ .area .text -+ .globl _ashlhi3 -+_ashlhi3: -+ pshs x -+1$: -+ leax -1,x -+ cmpx #-1 -+ beq 2$ -+ aslb -+ rola -+ bra 1$ -+2$: -+ puls x,pc -+#endif -+ -+#ifdef L_ashrhi3 -+ .area .text -+ .globl _ashrhi3 -+_ashrhi3: -+ pshs x -+1$: -+ leax -1,x -+ cmpx #-1 -+ beq 2$ -+ asra -+ rorb -+ bra 1$ -+2$: -+ puls x,pc -+#endif -+ -+ -+#ifdef L_lshrhi3 -+ .area .text -+ .globl _lshrhi3 -+_lshrhi3: -+ pshs x -+1$: -+ leax -1,x -+ cmpx #-1 -+ beq 2$ -+ lsra -+ rorb -+ bra 1$ -+2$: -+ puls x,pc -+#endif -+ -+ -+ -+#ifdef L_softregs -+ .area direct -+ .globl m0, m1, m2, m3, m4, m5, m6, m7 -+ .globl m8, m9, m10, m11, m12, m13, m14, m15 -+m0: .blkb 1 -+m1: .blkb 1 -+m2: .blkb 1 -+m3: .blkb 1 -+m4: .blkb 1 -+m5: .blkb 1 -+m6: .blkb 1 -+m7: .blkb 1 -+m8: .blkb 1 -+m9: .blkb 1 -+m10: .blkb 1 -+m11: .blkb 1 -+m12: .blkb 1 -+m13: .blkb 1 -+m14: .blkb 1 -+m15: .blkb 1 -+#endif -+ -+ -+#ifdef L_ashlsi3_one -+ .area .text -+ .globl _ashlsi3_one -+_ashlsi3_one: -+ asl 3,x -+ rol 2,x -+ rol 1,x -+ rol ,x -+ rts -+#endif -+ -+#ifdef L_ashlsi3 -+ /* X points to the SImode (source/dest) -+ B is the count */ -+_ashlsi3: -+ pshs u -+ cmpb #16 -+ blt try8 -+ subb #16 -+ ; Shift by 16 -+ ldu 2,x -+ stu ,x -+try8: -+ cmpb #8 -+ blt try_rest -+ subb #8 -+ ; Shift by 8 -+ -+try_rest: -+ tstb -+ beq done -+do_rest: -+ ; Shift by 1 -+ asl 3,x -+ rol 2,x -+ rol 1,x -+ rol ,x -+ decb -+ bne do_rest -+done: -+ puls u,pc -+#endif -+ -+#ifdef L_ashrsi3_one -+ .area .text -+ .globl _ashlsi3_one -+_ashrsi3_one: -+ asr ,x -+ ror 1,x -+ ror 2,x -+ ror 3,x -+ rts -+#endif -+ -+ -+#ifdef L_lshrsi3_one -+ .area .text -+ .globl _lshrsi3_one -+_lshrsi3_one: -+ lsr ,x -+ ror 1,x -+ ror 2,x -+ ror 3,x -+ rts -+#endif -+ -+ -+#ifdef L_clzsi2 -+ .area .text -+ .globl ___clzhi2 -+ ; Input: X = 16-bit unsigned integer -+ ; Output: X = number of leading zeros -+ ; This function destroys the value in D. -+___clzhi2: -+ pshs x -+ ; Find the offset of the leftmost '1' bit in -+ ; the left half of the word. -+ ; -+ ; Bits are numbered in the table with 1 meaning the -+ ; LSB and 8 meaning the MSB. -+ ; -+ ; If nonzero, then clz is 8-a. -+ tfr x,d -+ ldx #___clz_tab -+ tfr a,b -+ clra -+ ldb d,x -+ bne upper_bit_set -+ -+lower_bit_set: -+ ; If the upper byte is zero, then check the lower -+ ; half of the word. Return 16-a. -+ puls d -+ clra -+ ldb d,x -+ negb -+ addb #16 -+ bra done -+ -+upper_bit_set: -+ negb -+ addb #8 -+ puls x -+ -+done: -+ tfr d,x -+ puls pc -+#endif -+ -+#ifdef L_clzdi2 -+ .area .text -+ .globl ___clzsi2 -+ ; Input: 32-bit unsigned integer is on the stack, just -+ ; above the return address -+ ; Output: X = number of leading zeros -+___clzsi2: -+ ; Check the upper 16-bit word -+ ; If it is not zero, then return clzhi2(X). -+ ; A branch can be used instead of a call since no -+ ; postprocessing is needed. Use long branch form -+ ; though since functions may not be near each other. -+ ldx 2,s -+ lbne ___clzhi2 -+ ldx 4,s -+ jsr ___clzhi2 -+ leax 16,x -+ rts -+#endif -+ -+#ifdef L_ctzsi2 -+ .area .text -+ .globl ___ctzhi2 -+ ; Input: X = 16-bit unsigned integer -+ ; Output: X = number of trailing zeros -+ ; F(x) = 15 - clzhi2(X & -x) -+ ; This function destroys the value in D. -+___ctzhi2: -+ tfr x,d -+ coma -+ comb -+ addd #1 -+ pshs a -+ pshs b -+ tfr x,d -+ andb ,s+ -+ anda ,s+ -+ tfr d,x -+ jsr ___clzhi2 -+ tfr x,d -+ subd #16 -+ coma -+ comb -+ tfr d,x -+ rts -+#endif -+ -+ -+#ifdef L_ctzdi2 -+ .area .text -+ .globl ___ctzsi2 -+ ; Input: 32-bit unsigned integer is on the stack, just -+ ; above the return address -+ ; Output: X = number of leading zeros -+___ctzsi2: -+ ; Check the lower 16-bit word -+ ; If it is not zero, then return ctzhi2(X). -+ ; A branch can be used instead of a call since no -+ ; postprocessing is needed. Use long branch form -+ ; though since functions may not be near each other. -+ ldx 4,s -+ lbne ___ctzhi2 -+ ldx 2,s -+ jsr ___ctzhi2 -+ leax 16,x -+ rts -+#endif -+ -+ -+#ifdef L_mulhi3 -+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+;;; ___mulhi3 - signed/unsigned multiply -+;;; Called by GCC to implement 16x16 multiplication -+;;; Arguments: Two 16-bit values, one in stack, one in X. -+;;; Result: 16-bit result in X -+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+ .area .text -+ .globl _mulhi3 -+_mulhi3: -+ pshs x -+ lda 5,s ; left msb * right lsb * 256 -+ ldb ,s -+ mul -+ tfr b,a -+ clrb -+ tfr d,x -+ ldb 1,s ; left lsb * right msb * 256 -+ lda 4,s -+ mul -+ tfr b,a -+ clrb -+ leax d,x -+ ldb 1,s ; left lsb * right lsb -+ lda 5,s -+ mul -+ leax d,x -+ puls d,pc ; kill D to remove initial push -+#endif -+ -+ -+#ifdef L_divhi3 -+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+;;; ___divhi3 - signed division -+;;; Arguments: Dividend in X, divisor on the stack -+;;; Returns result in X. -+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+ .area .text -+ .globl _divhi3 -+_divhi3: -+ ldd 2,s -+ bne do_div ; check dividend -+ SIGFPE -+do_div: -+ pshs x -+ jsr _seuclid -+ puls x,pc -+#endif -+ -+ -+#ifdef L_modhi3 -+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+;;; ___modhi3 - signed modulo -+;;; Arguments: Dividend in X, divisor on the stack -+;;; Returns result in X. -+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+ .area .text -+ .globl _modhi3 -+_modhi3: -+ ldd 2,s -+ bne do_mod ; check dividend -+ SIGFPE -+do_mod: -+ pshs x -+ jsr _seuclid -+ leas 2,s -+ tfr d,x -+ rts -+#endif -+ -+ -+ -+#ifdef L_udivhi3 -+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+;;; ___udivhi3 - unsigned division -+;;; Arguments: Dividend in X, divisor on the stack -+;;; Returns result in X. -+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+ .area .text -+ .globl _udivhi3 -+_udivhi3: -+ ldd 2,s -+ bne do_udiv ; check dividend -+ SIGFPE -+do_udiv: -+ pshs x -+ jsr _euclid -+ puls x,pc -+#endif -+ -+ -+#ifdef L_umodhi3 -+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+;;; ___umodhi3 - unsigned modulo -+;;; Arguments: Dividend in X, divisor on the stack -+;;; Returns result in X. -+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -+ .area .text -+ .globl _umodhi3 -+_umodhi3: -+ ldd 2,s -+ bne do_umod ; check dividend -+ SIGFPE -+do_umod: -+ pshs x -+ jsr _euclid -+ leas 2,s -+ tfr d,x -+ rts -+#endif -+ -+ -+#ifdef L_euclid -+; unsigned euclidean division -+; calling: (left / right) -+; push left -+; ldd right -+; jsr _euclid -+; quotient on the stack (left) -+; modulus in d -+ -+ .area .text -+ .globl _euclid -+ left=5 -+ right=1 ; word -+ count=0 ; byte -+ CARRY=1 ; alias -+_euclid: -+ leas -3,s ; 2 local variables -+ clr count,s ; prescale divisor -+ inc count,s -+ tsta -+presc: -+ bmi presc_done -+ inc count,s -+ aslb -+ rola -+ bra presc -+presc_done: -+ std right,s -+ ldd left,s -+ clr left,s ; quotient = 0 -+ clr left+1,s -+mod1: -+ subd right,s ; check subtract -+ bcc mod2 -+ addd right,s -+ andcc #~CARRY -+ bra mod3 -+mod2: -+ orcc #CARRY -+mod3: -+ rol left+1,s ; roll in carry -+ rol left,s -+ lsr right,s -+ ror right+1,s -+ dec count,s -+ bne mod1 -+ leas 3,s -+ rts -+#endif -+ -+#ifdef L_seuclid -+; signed euclidean division -+; calling: (left / right) -+; push left -+; ldd right -+; jsr _seuclid -+; quotient on the stack (left) -+; modulus in d -+ .area .text -+ .globl _seuclid -+ left=6 -+ right=2 -+ quot_sign=1 -+ mod_sign=0 -+_seuclid: -+ leas -4,s ; 3 local variables -+ std right,s -+ clr mod_sign,s -+ clr quot_sign,s -+ ldd left,s -+ bge mod_abs -+ inc mod_sign,s ; sign(mod) = sign(left) -+ inc quot_sign,s -+ bsr negd ; abs(left) -> D -+mod_abs: -+ pshs b,a ; push abs(left) -+ ldd right+2,s ; all references shifted by 2 -+ bge quot_abs -+ dec quot_sign+2,s ; sign(quot) = sign(left) XOR sign(right) -+ bsr negd ; abs(right) -> D -+quot_abs: -+ jsr _euclid ; call (unsigned) euclidean division -+ std right+2,s -+ puls a,b ; quot -> D -+ tst quot_sign,s ; all references no longer shifted -+ beq quot_done -+ bsr negd -+quot_done: -+ std left,s ; quot -> left -+ ldd right,s -+ tst mod_sign,s -+ beq mod_done -+ bsr negd -+mod_done: -+ leas 4,s ; destroy stack frame -+ rts -+ -+negd: ; self-explanatory ! -+ nega -+ negb -+ sbca #0 -+ rts -+#endif -+ -+ -+ -+#ifdef L_pending_addsi3 -+_addsi3: -+ rts -+#endif /* L_pending_addsi3 */ -+ -+ -+ -diff -urN gcc-4.6.4-clean/gcc/config/m6809/m6809.c gcc-4.6.4/gcc/config/m6809/m6809.c ---- gcc-4.6.4-clean/gcc/config/m6809/m6809.c 1969-12-31 17:00:00.000000000 -0700 -+++ gcc-4.6.4/gcc/config/m6809/m6809.c 2015-07-20 22:11:37.726714746 -0600 -@@ -0,0 +1,3025 @@ -+/*------------------------------------------------------------------- -+ FILE: m6809.c -+-------------------------------------------------------------------*/ -+/* Subroutines for insn-output.c for MC6809. -+ Copyright (C) 1989-2007 Free Software Foundation, Inc. -+ -+ MC6809 Version by Tom Jones (jones@sal.wisc.edu) -+ Space Astronomy Laboratory -+ University of Wisconsin at Madison -+ -+ minor changes to adapt it to gcc-2.5.8 by Matthias Doerfel -+ ( msdoerfe@informatik.uni-erlangen.de ) -+ also added #pragma interrupt (inspired by gcc-6811) -+ -+ minor changes to adapt it to gcc-2.8.0 by Eric Botcazou -+ (ebotcazou@multimania.com) -+ -+ minor changes to adapt it to gcc-2.95.3 by Eric Botcazou -+ (ebotcazou@multimania.com) -+ -+ major cleanup, improvements, and upgrade to gcc 3.4 by Brian Dominy -+ (brian@oddchange.com) -+ -+ additional adjustments, etc., for gcc 4.6.1 by William Astle (lost@l-w.ca) -+ -+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 -+<http://www.gnu.org/licenses/>. */ -+ -+#include <string.h> -+#include <time.h> -+#include <sys/types.h> -+#include <sys/timeb.h> -+#include <stdio.h> -+#include "config.h" -+#include "system.h" -+#include "coretypes.h" -+#include "tm.h" -+#include "tree.h" -+#include "rtl.h" -+#include "tm_p.h" -+#include "regs.h" -+#include "flags.h" -+#include "hard-reg-set.h" -+#include "real.h" -+#include "tree.h" -+#include "insn-config.h" -+#include "conditions.h" -+#include "insn-flags.h" -+#include "output.h" -+#include "insn-attr.h" -+#include "function.h" -+#include "target.h" -+#include "target-def.h" -+#include "expr.h" -+#include "recog.h" -+#include "cpplib.h" -+#include "c-family/c-pragma.h" -+#include "c-family/c-common.h" -+#include "toplev.h" -+#include "optabs.h" -+#include "version.h" -+#include "df.h" -+#include "rtlhooks-def.h" -+ -+/* macro to return TRUE if length of operand mode is one byte */ -+#define BYTE_MODE(X) ((GET_MODE_SIZE (GET_MODE (X))) == 1) -+ -+ -+/* REAL_REG_P(x) is a true if the rtx 'x' represents a real CPU -+register and not a fake one that is emulated in software. */ -+#define REAL_REG_P(x) (REG_P(x) && !M_REG_P(x)) -+ -+/*------------------------------------------------------------------- -+ Target hooks, moved from target.h -+-------------------------------------------------------------------*/ -+static void m6809_encode_section_info (tree decl, rtx rtl, int new_decl_p ATTRIBUTE_UNUSED); -+ -+#undef TARGET_ENCODE_SECTION_INFO -+#define TARGET_ENCODE_SECTION_INFO m6809_encode_section_info -+ -+#undef TARGET_ASM_FILE_START -+#define TARGET_ASM_FILE_START m6809_asm_file_start -+ -+#undef TARGET_ASM_ALIGNED_HI_OP -+#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" -+ -+#undef TARGET_ASM_ALIGNED_SI_OP -+#define TARGET_ASM_ALIGNED_SI_OP NULL -+ -+#undef TARGET_ASM_UNALIGNED_HI_OP -+#define TARGET_ASM_UNALIGNED_HI_OP "\t.word\t" -+ -+#undef TARGET_ASM_UNALIGNED_SI_OP -+#define TARGET_ASM_UNALIGNED_SI_OP NULL -+ -+#undef TARGET_RTX_COSTS -+#define TARGET_RTX_COSTS m6809_rtx_costs -+ -+#undef TARGET_ATTRIBUTE_TABLE -+#define TARGET_ATTRIBUTE_TABLE m6809_attribute_table -+ -+#undef TARGET_INIT_BUILTINS -+#define TARGET_INIT_BUILTINS m6809_init_builtins -+ -+#undef TARGET_EXPAND_BUILTIN -+#define TARGET_EXPAND_BUILTIN m6809_expand_builtin -+ -+#undef TARGET_DEFAULT_TARGET_FLAGS -+#define TARGET_DEFAULT_TARGET_FLAGS (MASK_REG_ARGS | MASK_DIRECT) -+ -+#undef TARGET_FUNCTION_OK_FOR_SIBCALL -+#define TARGET_FUNCTION_OK_FOR_SIBCALL m6809_function_ok_for_sibcall -+ -+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE -+#define TARGET_ASM_TRAMPOLINE_TEMPLATE m6809_asm_trampoline_template -+ -+#undef TARGET_TRAMPOLINE_INIT -+#define TARGET_TRAMPOLINE_INIT m6809_initialize_trampoline -+ -+#undef TARGET_FRAME_POINTER_REQUIRED -+#define TARGET_FRAME_POINTER_REQUIRED m6809_frame_pointer_required -+ -+#undef TARGET_OPTION_OVERRIDE -+#define TARGET_OPTION_OVERRIDE m6809_override_options -+ -+/* External variables used */ -+extern int reload_completed; /* set in toplev.c */ -+extern FILE *asm_out_file; -+ -+static int last_mem_size; /* operand size (bytes) */ -+ -+/* True if the section was recently changed and another .area -+ * directive needs to be output before emitting the next label. */ -+int section_changed = 0; -+ -+/* Section names. The defaults here are used until an -+ * __attribute__((section)) is seen that changes it. */ -+char code_section_op[128] = "\t.area .text"; -+char data_section_op[128] = "\t.area .data"; -+char bss_section_op[128] = "\t.area .bss"; -+const char *code_bank_option = 0; -+ -+/* TRUE if the direct mode prefix might be valid in this context. -+ * This is set by 'print_address' prior to calling output_addr_const, -+ * which performs into 'print_direct_prefix' to do the final checks. */ -+static int check_direct_prefix_flag; -+ -+/* Nonzero if an address is being printed in a context which does not -+ * permit any PIC modifications to the address */ -+static int pic_ok_for_addr_p = 1; -+ -+/* Current code page. This supports machines which can do bank -+ * switching to allow for more than 64KB of code/data. */ -+char far_code_page[64]; -+ -+/* Current bank name */ -+static char current_bank_name[8] = "-1"; -+ -+/* Default bank name */ -+static char default_code_bank_name[8] = "-1"; -+ -+/* Direct memory reserved as soft registers */ -+unsigned int m6809_soft_regs = 0; -+ -+/* ABI version */ -+unsigned int m6809_abi_version = M6809_ABI_VERSION_REGS; -+ -+ -+/** -+ * Called after options have been parsed. -+ * If overrides have been specified on the command-line, then -+ * these values are copied into the main storage variables. -+ */ -+void -+m6809_override_options (void) -+{ -+ /* Handle -mfar-code-page */ -+ if (far_code_page_option == 0) -+ far_code_page_option = "__default_code_page"; -+ strcpy (far_code_page, far_code_page_option); -+ -+ /* Handle -mcode-section, -mdata-section, and -mbss-section */ -+ if (code_section_ptr != 0) -+ sprintf (code_section_op, "\t.area %s", code_section_ptr); -+ if (data_section_ptr != 0) -+ sprintf (data_section_op, "\t.area %s", data_section_ptr); -+ if (bss_section_ptr != 0) -+ sprintf (bss_section_op, "\t.area %s", bss_section_ptr); -+ -+ /* Handle -mcode-bank */ -+ if (code_bank_option != 0) -+ sprintf (default_code_bank_name, "%s", code_bank_option); -+ -+ /* Handle -mabi-version or -mno-reg-args */ -+ if (m6809_abi_version_ptr != 0) -+ { -+ if (!strcmp (m6809_abi_version_ptr, "stack")) -+ m6809_abi_version = M6809_ABI_VERSION_STACK; -+ else if (!strcmp (m6809_abi_version_ptr, "regs")) -+ m6809_abi_version = M6809_ABI_VERSION_REGS; -+ else if (!strcmp (m6809_abi_version_ptr, "bx")) -+ m6809_abi_version = M6809_ABI_VERSION_BX; -+ else if (!strcmp (m6809_abi_version_ptr, "latest")) -+ m6809_abi_version = M6809_ABI_VERSION_LATEST; -+ else -+ m6809_abi_version = atoi (m6809_abi_version_ptr); -+ } -+ -+ /* The older -mno-reg-args option is deprecated, and treated -+ as -mabi=stack. */ -+ if (!TARGET_REG_ARGS) -+ { -+ warning (WARNING_OPT "-mno-reg-args deprecated; use -mabi=stack instead."); -+ m6809_abi_version = M6809_ABI_VERSION_STACK; -+ } -+ -+ /* -fexceptions is unsupported */ -+ flag_exceptions = 0; -+ flag_non_call_exceptions = 0; -+ flag_unwind_tables = 0; -+} -+ -+ -+/** -+ * Output prefix that directs the assembler to use a direct-mode -+ * instruction if globally enabled, address is a symbol, and symbol -+ * has been marked as in direct page. Also, never do this if -+ * using the indirect mode. */ -+void -+print_direct_prefix (FILE * file, rtx addr) -+{ -+ if (TARGET_DIRECT && -+ (GET_CODE (addr) == SYMBOL_REF) && -+ SYMBOL_REF_FLAG (addr) && -+ check_direct_prefix_flag) -+ { -+ putc ('*', file); -+ } -+} -+ -+ -+/** Prints an operand (that is not an address) in assembly from RTL. */ -+void -+print_operand (FILE * file, rtx x, int code) -+{ -+ if (REG_P (x)) { -+ /* gcc currently allocates the entire 16-bit 'd' register -+ * even when it only needs an 8-bit value. So here it -+ * is tricked into printing only the lower 8-bit 'b' -+ * register into the assembly output. -+ * -+ * Eventually gcc should be modified to allocate a/b -+ * independently and this hack can be removed. -+ * -+ * Occasionally, we may want to do an operation using -+ * the 'a' register instead of 'b'; use the 'A' code -+ * to specify that. -+ */ -+ if (code == 'A') -+ fputs ("a", file); -+ else if ((BYTE_MODE (x)) && (REGNO (x) == HARD_D_REGNUM)) -+ fputs ("b", file); -+ else if (M_REG_P (x) && code == 'L') -+ /* Soft registers can be treated like memory and accessed -+ * at a particular offset. TODO : handle 'W' */ -+ fputs (reg_names[REGNO (x)+1], file); -+ else -+ fputs (reg_names[REGNO (x)], file); -+ } -+ -+ else if (MEM_P (x)) { -+ last_mem_size = GET_MODE_SIZE (GET_MODE (x)); -+ if (code == 'L') { /* LSH of word address */ -+ if (GET_CODE (XEXP (x, 0)) == MEM) -+ { -+ /* Offseting an indirect addressing mode is not supported */ -+ error ("expression too complex for 6809 (offset indirect mode)"); -+ debug_rtx (x); -+ } -+ else -+ x = adjust_address (x, QImode, 1); -+ } -+ else if (code == 'M') { /* MSH of word address */ -+ if (GET_CODE (XEXP (x, 0)) == MEM) -+ { -+ /* Offseting an indirect addressing mode is not supported */ -+ error ("expression too complex for 6809 (offset indirect mode)"); -+ debug_rtx (x); -+ } -+ else -+ x = adjust_address (x, QImode, 0); -+ } -+ else if (code == 'W') { /* least significant half of 32-bit */ -+ x = adjust_address (x, HImode, 2); -+ } -+ -+ pic_ok_for_addr_p = (code != 'C'); -+ output_address (XEXP (x, 0)); -+ } -+ -+ else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode) { -+ union { double d; int i[2]; } u; -+ u.i[0] = CONST_DOUBLE_LOW (x); -+ u.i[1] = CONST_DOUBLE_HIGH (x); -+ fprintf (file, "#%#9.9g", u.d); -+ } -+ -+ else if (code == 'R') { -+ fprintf (file, "%s", -+ m6809_get_regs_printable (INTVAL (x))); -+ } -+ -+ else { -+ if (code == 'L') { /* LSH of word address */ -+ x = gen_rtx_CONST_INT (VOIDmode, (INTVAL(x) & 0xff)); -+ } -+ else if (code == 'M') { /* MSH of word address */ -+ x = gen_rtx_CONST_INT (VOIDmode, ((INTVAL(x) >> 8) & 0xff)); -+ } -+ -+ putc ('#', file); -+ output_addr_const (file, x); -+ } -+} -+ -+ -+/** Prints an address operand to assembler from its RTL representation. */ -+void -+print_operand_address (FILE *file, rtx addr) -+{ -+ register rtx base = 0; -+ register rtx offset = 0; -+ int regno; -+ int indirect_flag = 0; -+ -+ check_direct_prefix_flag = 0; -+ -+ /*** check for indirect addressing ***/ -+ if (MEM_P (addr)) { -+ last_mem_size = GET_MODE_SIZE (GET_MODE (addr)); -+ addr = XEXP (addr, 0); -+ if (pic_ok_for_addr_p) -+ { -+ indirect_flag = 1; -+ fprintf (file, "["); -+ } -+ } -+ -+ -+ switch (GET_CODE (addr)) { -+ case REG: -+ regno = REGNO (addr); -+ fprintf (file, ",%s", reg_names[regno]); -+ break; -+ -+ case PRE_DEC: -+ regno = REGNO (XEXP (addr, 0)); -+ fputs (((last_mem_size == 1) ? ",-" : ",--"), file); -+ fprintf (file, "%s", reg_names[regno]); -+ break; -+ -+ case POST_INC: -+ regno = REGNO (XEXP (addr, 0)); -+ fprintf (file, ",%s", reg_names[regno]); -+ fputs (((last_mem_size == 1) ? "+" : "++"), file); -+ break; -+ -+ case PLUS: -+ base = XEXP (addr, 0); -+ if (MEM_P (base)) -+ base = XEXP (base, 0); -+ -+ offset = XEXP (addr, 1); -+ if (MEM_P (offset)) -+ offset = XEXP (offset, 0); -+ -+ if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset))) { -+ if (!indirect_flag) -+ check_direct_prefix_flag = 1; -+ output_addr_const (file, base); -+ check_direct_prefix_flag = 0; -+ fputs ("+", file); -+ output_addr_const (file, offset); -+ } -+ -+ else if ((CONSTANT_ADDRESS_P (base)) && (A_REG_P (offset))) { -+ output_addr_const (file, base); -+ fprintf (file, ",%s", reg_names[REGNO (offset)]); -+ } -+ -+ else if ((CONSTANT_ADDRESS_P (offset)) && (A_REG_P (base))) { -+ output_addr_const (file, offset); -+ fprintf (file, ",%s", reg_names[REGNO (base)]); -+ } -+ -+ /*** accumulator offset ***/ -+ else if (((D_REG_P (offset)) || (Q_REG_P (offset))) -+ && (A_REG_P (base))) { -+ fprintf (file, "%s,%s", -+ reg_names[REGNO (offset)], reg_names[REGNO (base)]); -+ } -+ -+ else if (((D_REG_P (base)) || (Q_REG_P (base))) -+ && (A_REG_P (offset))) { -+ fprintf (file, "%s,%s", -+ reg_names[REGNO (base)], reg_names[REGNO (offset)]); -+ } -+ -+ else if (GET_CODE (base) == PRE_DEC) { -+ regno = REGNO (XEXP (base, 0)); -+ fputs (((last_mem_size == 1) ? ",-" : ",--"), file); -+ fprintf (file, "%s", reg_names[regno]); -+ } -+ -+ else -+ abort (); -+ -+ break; -+ -+ default: -+ /* Set this global before calling output_addr_const() */ -+ if (!indirect_flag) -+ check_direct_prefix_flag = 1; -+ -+ /* When printing a SYMBOL_REF in PIC mode, do not print the leading -+ * '#' and follow it by ',pcr' to enable relative addressing. */ -+ if (flag_pic && pic_ok_for_addr_p && GET_CODE (addr) == SYMBOL_REF) -+ { -+ ASM_OUTPUT_SYMBOL_REF (file, addr); -+ fputs (",pcr", file); -+ pic_ok_for_addr_p = 1; -+ } -+ else -+ { -+ output_addr_const (file, addr); -+ } -+ -+ check_direct_prefix_flag = 0; -+ break; -+ } -+ -+ if (indirect_flag) -+ fprintf (file, "]"); -+} -+ -+/*------------------------------------------------------------------- -+ Update the CC Status -+--------------------------------------------------------------------- -+ Set the cc_status for the results of an insn whose pattern is EXP. -+ We assume that jumps don't affect the condition codes. -+ All else, clobbers the condition codes, by assumption. -+ -+ We assume that ALL add, minus, etc. instructions effect the condition -+ codes. -+-------------------------------------------------------------------*/ -+void -+notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED) -+{ -+ int src_code; -+ int dst_code; -+ -+ /*** recognize SET insn's ***/ -+ if (GET_CODE (exp) == SET) -+ { -+ src_code = GET_CODE (SET_SRC (exp)); -+ dst_code = GET_CODE (SET_DEST (exp)); -+ -+ /* Jumps do not alter the cc's. */ -+ if (SET_DEST (exp) == pc_rtx) -+ return; -+ -+ /* Moving one register into another register (tfr): -+ Doesn't alter the cc's. */ -+ if (REG_P (SET_DEST (exp)) && (REG_P (SET_SRC (exp)))) -+ return; -+ -+ /* Moving memory into a register (load): Sets cc's. */ -+ if (REG_P (SET_DEST (exp)) && src_code == MEM) { -+ cc_status.value1 = SET_SRC (exp); -+ cc_status.value2 = SET_DEST (exp); -+ cc_status.flags |= CC_NO_OVERFLOW; -+ return; -+ } -+ -+ /* Moving register into memory (store): Sets cc's. */ -+ if (dst_code == MEM && REG_P (SET_SRC (exp))) { -+ cc_status.value1 = SET_SRC (exp); -+ cc_status.value2 = SET_DEST (exp); -+ cc_status.flags |= CC_NO_OVERFLOW; -+ return; -+ } -+ -+ /* Function calls clobber the cc's. */ -+ else if (GET_CODE (SET_SRC (exp)) == CALL) { -+ CC_STATUS_INIT; -+ return; -+ } -+ -+ /* Tests and compares set the cc's in predictable ways. */ -+ else if (SET_DEST (exp) == cc0_rtx) -+ { -+ cc_status.flags = 0; -+ cc_status.value1 = SET_SRC (exp); -+ cc_status.value2 = SET_DEST (exp); -+ return; -+ } -+ -+ else if (A_REG_P (SET_DEST (exp))) -+ { -+ CC_STATUS_INIT; -+ return; -+ } -+ -+ else -+ { -+ /* Certain instructions affect the condition codes. */ -+ switch (src_code) -+ { -+ case PLUS: -+ case MINUS: -+ case NEG: -+ case ASHIFT: -+ /* These instructions set the condition codes, -+ * and may modify the V bit. */ -+ cc_status.flags |= CC_NO_OVERFLOW; -+ /* FALLTHRU */ -+ -+ case AND: -+ case IOR: -+ case XOR: -+ case ASHIFTRT: -+ case LSHIFTRT: -+ /* These instructions set the condition codes, -+ * but cannot overflow (V=0). */ -+ cc_status.value1 = SET_SRC (exp); -+ cc_status.value2 = SET_DEST (exp); -+ break; -+ -+ default: -+ /* Everything else is clobbered */ -+ CC_STATUS_INIT; -+ } -+ return; -+ } -+ } /* SET */ -+ -+ else if (GET_CODE (exp) == PARALLEL -+ && GET_CODE (XVECEXP (exp, 0, 0)) == SET) -+ { -+ if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx) -+ return; -+ if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx) -+ { -+ CC_STATUS_INIT; -+ cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0)); -+ return; -+ } -+ } -+ -+ /*** default action if we haven't recognized something -+ and returned earlier ***/ -+ CC_STATUS_INIT; -+} -+ -+ -+/** Returns nonzero if the expression EXP can be implemented using one -+ * of the 6809's single operand instructions. */ -+int -+m6809_single_operand_operator (rtx exp) -+{ -+ rtx op1; -+ HOST_WIDE_INT val; -+ enum rtx_code code; -+ -+ debug_rtx(exp); -+ -+ code = GET_CODE (exp); -+ -+ /* Unary operators always qualify */ -+ switch (code) -+ { -+ case NEG: -+ case NOT: -+ return 1; -+ -+ default: -+ break; -+ } -+ -+ /* Binary operators can only qualify if the second -+ * argument is a CONST_INT of certain value. */ -+ op1 = XEXP (exp, 1); -+ if (GET_CODE (op1) != CONST_INT) -+ return 0; -+ val = INTVAL (op1); -+ switch (code) -+ { -+ case PLUS: -+ case MINUS: -+ if (val == -1 || val == 1) -+ return 1; -+ break; -+ -+ case ASHIFT: -+ case ASHIFTRT: -+ case LSHIFTRT: -+ case ROTATE: -+ case ROTATERT: -+ if (val == 1) -+ return 1; -+ break; -+ -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+ -+/** Return a bitarray of the hard registers which are used by a function. */ -+unsigned int -+m6809_get_live_regs (void) -+{ -+ unsigned int regs = 0; -+ int regno; -+ -+ if (frame_pointer_needed) -+ regs |= (1 << HARD_FRAME_POINTER_REGNUM); -+ -+ for (regno = HARD_X_REGNUM; regno <= HARD_U_REGNUM; regno++) -+ if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) -+ regs |= (1 << regno); -+ -+ return regs; -+} -+ -+ -+/** Return a printable version of a list of hard registers, suitable -+ * for use in a PSHx or PULx insn. */ -+const char * -+m6809_get_regs_printable (unsigned int regs) -+{ -+ static char list[64]; -+ char *listp = list; -+ unsigned int regno; -+ -+ for (regno=0; regno < FIRST_PSEUDO_REGISTER; regno++) -+ if ((regs & (1 << regno)) && !S_REGNO_P (regno)) -+ listp += sprintf (listp, -+ (listp == list) ? "%s" : ",%s", reg_names[regno]); -+ -+ return list; -+} -+ -+ -+/** Return the total number of bytes covered by a set of hard registers. */ -+unsigned int -+m6809_get_regs_size (unsigned int regs) -+{ -+ unsigned int regno; -+ unsigned int size = 0; -+ -+ for (regno=0; regno < FIRST_PSEUDO_REGISTER; regno++) -+ { -+ /* Only count register in the given register set */ -+ if (REGSET_CONTAINS_P (regno, regs)) -+ { -+ /* Add 1 or 2 byte, depending on the size of the register. -+ * Since 'D' may be in both sets, check for WORD_REGSET first. */ -+ if (REGSET_CONTAINS_P(regno, WORD_REGSET)) -+ size += 2; -+ else if (REGSET_CONTAINS_P(regno, BYTE_REGSET)) -+ size++; -+ } -+ } -+ return size; -+} -+ -+ -+/* Given the target of call instruction in X, -+ * return the tree node that contains the function declaration for -+ * that target. -+ * -+ * If the rtx or the tree do not appear valid for any reason, -+ * then return NULL_TREE. -+ */ -+static tree call_target_decl (rtx x) -+{ -+ tree decl; -+ -+ /* Make sure the target is really a MEM. */ -+ if (!x || !MEM_P (x)) -+ return NULL_TREE; -+ -+ /* Make sure the address is a SYMBOL_REF. */ -+ x = XEXP (x, 0); -+ if (!x || (GET_CODE (x) != SYMBOL_REF)) -+ return NULL_TREE; -+ -+ /* Get the declaration of this symbol */ -+ decl = SYMBOL_REF_DECL (x); -+ -+ /* Make sure the declaration is really a function. */ -+ if (!decl || (TREE_CODE(decl) != FUNCTION_DECL)) -+ return NULL_TREE; -+ -+ return decl; -+} -+ -+ -+/** Returns nonzero if a function, whose declaration is in DECL, -+ * was declared to have the attribute given by ATTR_NAME. */ -+int -+m6809_function_has_type_attr_p (tree decl, const char *attr_name) -+{ -+ tree type; -+ -+ type = TREE_TYPE (decl); -+ return lookup_attribute (attr_name, TYPE_ATTRIBUTES (type)) != NULL; -+} -+ -+ -+ -+/** Returns nonzero if the current function was declared to have the -+ * attribute given by ATTR_NAME. */ -+int -+m6809_current_function_has_type_attr_p (const char *attr_name) -+{ -+ return m6809_function_has_type_attr_p (current_function_decl, attr_name); -+} -+ -+ -+/** Return nonzero if the current function has no return value. */ -+int -+m6809_current_function_is_void (void) -+{ -+ return (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))); -+} -+ -+ -+/** Get the value of a declaration's 'bank', as set by the 'bank' -+ * attribute. If no bank was declared, it returns NULL by default. */ -+const char * -+m6809_get_decl_bank (tree decl) -+{ -+ tree attr; -+ -+ /* Lookup the 'bank' attribute. If it does not exist, then -+ * return NULL */ -+ attr = lookup_attribute ("bank", DECL_ATTRIBUTES (decl)); -+ if (attr == NULL_TREE) -+ return NULL; -+ -+ /* Make sure it has a value assigned to it */ -+ attr = TREE_VALUE (attr); -+ if (attr == NULL_TREE) -+ { -+ warning (WARNING_OPT "banked function did not declare a bank number"); -+ return NULL; -+ } -+ -+ /* Return the bank name */ -+ attr = TREE_VALUE (attr); -+ return TREE_STRING_POINTER (attr); -+} -+ -+ -+void -+m6809_declare_function_name (FILE *asm_out_file, const char *name, tree decl) -+{ -+ /* Check the function declaration for special properties. -+ * -+ * If the function was declare with __attribute__((bank)), output -+ * assembler definitions to force the function to go into the named -+ * bank. -+ */ -+ const char *bank_name = m6809_get_decl_bank (decl); -+ if (bank_name != NULL) -+ { -+ /* Declare __self_bank as a local assembler value that denotes -+ * which bank the current function is in. This is required only -+ * when the bank actually changes. */ -+ if (strcmp (bank_name, current_bank_name)) -+ { -+ fprintf (asm_out_file, "__self_bank\t.equ %s\n", bank_name); -+ strcpy (current_bank_name, bank_name); -+ } -+ -+ /* Declare a global assembler value that denotes which bank the -+ * named function is in. */ -+ fprintf (asm_out_file, "__%s_bank\t.gblequ %s\n", name, bank_name); -+ -+ /* Force the current function into a new area */ -+ fprintf (asm_out_file, "\t.bank bank_%s (FSFX=_%s)\n", -+ bank_name, bank_name); -+ fprintf (asm_out_file, "\t.area bank_%s (BANK=bank_%s)\n", -+ bank_name, bank_name); -+ } -+ -+ /* Emit the label for the function's name */ -+ ASM_OUTPUT_LABEL (asm_out_file, name); -+} -+ -+#if 0 -+/** -+ * Handle pragmas. Note that only the last branch pragma seen in the -+ * source has any affect on code generation. -+ */ -+ -+#define BAD_PRAGMA(msgid, arg) \ -+ do { warning (WARNING_OPT msgid, arg); return -1; } while (0) -+ -+static int -+pragma_parse (const char *name, tree *sect) -+{ -+ tree s, x; -+ -+ if (pragma_lex (&x) != CPP_OPEN_PAREN) -+ BAD_PRAGMA ("missing '(' after '#pragma %s' - ignored", name); -+ -+ if (pragma_lex (&s) != CPP_STRING) -+ BAD_PRAGMA ("missing section name in '#pragma %s' - ignored", name); -+ -+ if (pragma_lex (&x) != CPP_CLOSE_PAREN) -+ BAD_PRAGMA ("missing ')' for '#pragma %s' - ignored", name); -+ -+ if (pragma_lex (&x) != CPP_EOF) -+ warning (WARNING_OPT "junk at end of '#pragma %s'", name); -+ -+ *sect = s; -+ return 0; -+} -+ -+ -+/* -+ * Handle #pragma section. -+ * This is deprecated; code should use __attribute__(section("name")) -+ * instead. -+ */ -+void pragma_section (cpp_reader *pfile ATTRIBUTE_UNUSED) -+{ -+ tree sect; -+ -+ if (pragma_parse ("section", §)) -+ return; -+ -+ snprintf (code_section_op, 6+TREE_STRING_LENGTH (sect), -+ ".area\t%s", TREE_STRING_POINTER (sect)); -+ snprintf (data_section_op, 6+TREE_STRING_LENGTH (sect), -+ ".area\t%s", TREE_STRING_POINTER (sect)); -+ -+ /* Mark a flag that sections have changed. Upon emitting another -+ * declaration, the new .area directive will be written. */ -+ section_changed++; -+} -+#endif -+ -+/** -+ * Check a `double' value for validity for a particular machine mode. -+ * Called by the CHECK_FLOAT_VALUE() machine-dependent macro. -+ */ -+int -+check_float_value (enum machine_mode mode, double *d, int overflow) -+{ -+ if (mode == SFmode) { -+ if (*d > 1.7014117331926443e+38) { -+ error("magnitude of constant too large for `float'"); -+ *d = 1.7014117331926443e+38; -+ } -+ else if (*d < -1.7014117331926443e+38) { -+ error("magnitude of constant too large for `float'"); -+ *d = -1.7014117331926443e+38; -+ } -+ else if ((*d > 0) && (*d < 2.9387358770557188e-39)) { -+ warning(WARNING_OPT "`float' constant truncated to zero"); -+ *d = 0.0; -+ } -+ else if ((*d < 0) && (*d > -2.9387358770557188e-39)) { -+ warning(WARNING_OPT "`float' constant truncated to zero"); -+ *d = 0.0; -+ } -+ } -+ return overflow; -+} -+ -+ -+ -+/** Declare that the target supports named output sections. */ -+bool m6809_have_named_section = (bool)1; -+ -+ -+/** Write to the assembler file a directive to place -+ * subsequent objects to a different section in the -+ * object file. ASxxxx uses the "area" directive for -+ * this purpose. It does not however support generalized -+ * alignment, and can only place items on an odd/even -+ * boundary. */ -+void -+m6809_asm_named_section ( -+ const char *name, -+ unsigned int flags ATTRIBUTE_UNUSED, -+ tree decl) -+{ -+ fprintf (asm_out_file, "\t.area\t%s\n", name); -+} -+ -+ -+enum reg_class -+m6809_preferred_reload_class (rtx x, enum reg_class regclass) -+{ -+ /* Check cases based on type code of rtx */ -+ switch (GET_CODE(x)) -+ { -+ /* -+ * Observation, 2015-07-19, William Astle -+ * -+ * The original comparison for range for 16 bits was wrong, adding 0x80 -+ * instead of 0x8000. Replaced both 8 bit and 16 bit comparisions with -+ * a more straight forward range comparison - excessive cleverness isn't -+ * really required here. -+ */ -+ case CONST_INT: -+ /* Constants that can fit into 1 byte should be -+ * loaded into a Q_REGS reg */ -+ if ((INTVAL(x) >= -128 && INTVAL(x) <= 127) && -+// if (((unsigned) (INTVAL(x) + 0x80) < 0x100) && -+ (regclass > A_REGS)) -+ return Q_REGS; -+ -+ /* 16-bit constants should be loaded into A_REGS -+ * when possible. gcc may already require A_REGS -+ * or D_REGS for certain types of instructions. -+ * This case applies mostly to simple copy operations -+ * to/from memory when any register will do, but -+ * it's best to avoid using D register since it is -+ * needed for other things. -+ */ -+ else if ((INTVAL(x) >= -32768 && INTVAL(x) <= 32767) && -+// else if (((unsigned) (INTVAL(x) + 0x80) < 0x10000) && -+ (regclass > A_REGS)) -+ return A_REGS; -+ break; -+ -+ case SYMBOL_REF: -+ case LABEL_REF: -+ /* Addresses should always be loaded into A_REGS */ -+ if (regclass >= A_REGS) -+ return (A_REGS); -+ -+ default: -+ break; -+ } -+ -+ /* Check cases based on mode of rtx */ -+ if ((GET_MODE(x) == QImode) && (regclass != A_REGS)) -+ return Q_REGS; -+ -+ /* Default: return whatever class reload suggested */ -+ return regclass; -+} -+ -+ -+/** -+ * Check a new declaration for the "section" attribute. -+ * If it exists, and the target section is "direct", then mark -+ * the declaration (in RTL) to indicate special treatment. -+ * When the variable is referenced later, we test for this flag -+ * and can emit special asm text to force the assembler to use -+ * short instructions. -+ */ -+static void -+m6809_encode_section_info (tree decl, rtx rtl, int new_decl_p ATTRIBUTE_UNUSED) -+{ -+ tree attr, id; -+ const char *name; -+ const char *decl_name; -+ -+ /* We only care about variable declarations, not functions */ -+ if (TREE_CODE (decl) != VAR_DECL) -+ return; -+ -+ /* For debugging purposes only; grab the decl's name */ -+ decl_name = IDENTIFIER_POINTER (DECL_NAME (decl)); -+ -+ /* Give up if the decl doesn't have any RTL */ -+ if (!DECL_RTL (decl)) -+ return; -+ -+ /* See if it has a section attribute */ -+ attr = lookup_attribute ("section", DECL_ATTRIBUTES (decl)); -+ if (!attr) -+ return; -+ -+ /* See if the section attribute has a value */ -+ id = TREE_VALUE (TREE_VALUE (attr)); -+ if (!id) -+ return; -+ name = TREE_STRING_POINTER (id); -+ if (!name) -+ return; -+ -+ /* See if the value is 'direct'. If so, mark it. */ -+ if (!strcmp (name, "direct")) -+ SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1; -+} -+ -+ -+/** -+ * Output code to perform a complex shift, for which there is no -+ * direct support in the instruction set. -+ * -+ * shift1 is an instruction pattern for performing a 1-bit modification. -+ * This code wraps that pattern in a loop to perform the shift N times, -+ * where N is given by the address register in operands[2]. -+ * -+ * To support 16-bit shifts, shift2 can also be provided: it is -+ * a second instruction to be included in the loop. 8-bit shift -+ * insns will pass NULL here. -+ * -+ * The insn length of shift1/shift2 is assumed to be 1 byte, -+ * which works in all of the cases it is needed so far. -+ */ -+static void -+m6809_gen_register_shift ( -+ rtx *operands, -+ const char *shift1, -+ const char *shift2 ) -+{ -+ char beq_pattern[32]; -+ char bra_pattern[32]; -+ -+ int shiftlen = (shift1 && shift2) ? 2 : 1; -+ int cmplen = (REGNO (operands[2]) == HARD_X_REGNUM) ? 3 : 4; -+ -+ int beq_offset = 2 + shiftlen + 2; -+ int bra_offset = shiftlen + 2 + cmplen + 2; -+ -+ sprintf (beq_pattern, "beq\t.+%d", beq_offset); -+ sprintf (bra_pattern, "bra\t.-%d", bra_offset); -+ -+ output_asm_insn ("pshs\t%2", operands); -+ output_asm_insn ("lea%2\t-1,%2", operands); -+ output_asm_insn ("cmp%2\t#-1", operands); -+ output_asm_insn (beq_pattern, operands); -+ if (shift1) -+ output_asm_insn (shift1, operands); -+ if (shift2) -+ output_asm_insn (shift2, operands); -+ output_asm_insn (bra_pattern, operands); -+ output_asm_insn ("puls\t%2", operands); -+} -+ -+ -+/** Generate RTL for the upper 8-bits of a 16-bit constant. */ -+rtx -+gen_rtx_const_high (rtx r) -+{ -+ unsigned char v = (INTVAL (r) >> 8) & 0xFF; -+ signed char s = (signed char)v; -+ return gen_int_mode (s, QImode); -+} -+ -+ -+/** Generate RTL for the lower 8-bits of a 16-bit constant. */ -+rtx -+gen_rtx_const_low (rtx r) -+{ -+ unsigned char v = INTVAL (r) & 0xFF; -+ signed char s = (signed char)v; -+ return gen_int_mode (s, QImode); -+} -+ -+ -+/** Generate RTL to allocate/free bytes on the stack. -+ * CODE is given as MINUS when allocating and PLUS when freeing, -+ * to match the semantics of a downward-growing stack. SIZE -+ * is always given as a positive integer. -+ */ -+static rtx -+gen_rtx_stack_adjust (enum rtx_code code, int size) -+{ -+ if (size <= 0) -+ return NULL_RTX; -+ -+ if (code == MINUS) -+ size = -size; -+ -+ return gen_rtx_SET (Pmode, stack_pointer_rtx, -+ gen_rtx_PLUS (Pmode, stack_pointer_rtx, -+ gen_int_mode (size, HImode))); -+} -+ -+ -+/** Generate RTL to push/pop a set of registers. */ -+rtx -+gen_rtx_register_pushpop (int op, int regs) -+{ -+ rtx nregs = gen_int_mode (regs, QImode); -+ -+ if (op == UNSPEC_PUSH_RS) -+ return gen_register_push (nregs); -+ else -+ return gen_register_pop (nregs); -+} -+ -+ -+/* Given a register set REGS, where the bit positions correspond to -+ * hard register numbers, return another bitmask that represents the -+ * order in which those registers would be pushed/popped. -+ * Registers that are pushed first have higher bit positions. -+ * The pop order is just the reverse bitmask. -+ * These values are the same as the bitmasks actually used in the -+ * machine instructions. */ -+static unsigned int -+register_push_order (int regs) -+{ -+ unsigned int order = 0; -+ -+ if (REGSET_CONTAINS_P (HARD_PC_REGNUM, regs)) -+ order |= 0x80; -+ if (REGSET_CONTAINS_P (HARD_U_REGNUM, regs)) -+ order |= 0x40; -+ if (REGSET_CONTAINS_P (HARD_Y_REGNUM, regs)) -+ order |= 0x20; -+ if (REGSET_CONTAINS_P (HARD_X_REGNUM, regs)) -+ order |= 0x10; -+ if (REGSET_CONTAINS_P (HARD_DP_REGNUM, regs)) -+ order |= 0x8; -+ if (REGSET_CONTAINS_P (HARD_B_REGNUM, regs)) -+ order |= 0x4; -+ if (REGSET_CONTAINS_P (HARD_A_REGNUM, regs)) -+ order |= 0x2; -+ if (REGSET_CONTAINS_P (HARD_CC_REGNUM, regs)) -+ order |= 0x1; -+ -+ if (REGSET_CONTAINS_P (HARD_D_REGNUM, regs)) -+ order |= (0x4 | 0x2); -+ return order; -+} -+ -+ -+/* Returns nonzero if two consecutive push or pop instructions, -+ * as determined by the OP, can be merged into a single instruction. -+ * The first instruction in the sequence pushes/pops REGS1; the -+ * second applies to REGS2. -+ * -+ * If true, the resulting instruction can use (regs1 | regs2) -+ * safely. -+ */ -+int -+m6809_can_merge_pushpop_p (int op, int regs1, int regs2) -+{ -+ /* Register sets must not overlap */ -+ if (regs1 & regs2) -+ return 0; -+ -+ if (op == UNSPEC_PUSH_RS) -+ return (register_push_order (regs1) > register_push_order (regs2)); -+ else if (op == UNSPEC_POP_RS) -+ return (register_push_order (regs1) < register_push_order (regs2)); -+ else -+ return 0; -+} -+ -+ -+/** Emit instructions for making a library call. -+ * MODE is the mode of the operation. -+ * NAME is the library function name. -+ * OPERANDS is the rtx array provided by the recognizer. -+ * COUNT is the number of input operands to the call, and -+ * should be 1 for a unary op or 2 for a binary op. -+ */ -+void -+emit_libcall_insns (enum machine_mode mode, -+ const char *name, -+ rtx *operands, -+ int count) -+{ -+ /* Generate an rtx for the call target. */ -+ rtx symbol = gen_rtx_SYMBOL_REF (Pmode, name); -+ -+ /* Emit the library call. Slightly different based -+ on the number of operands */ -+ if (count == 2) -+ emit_library_call (symbol, LCT_NORMAL, mode, -+ 2, operands[1], mode, operands[2], mode); -+ else -+ emit_library_call (symbol, LCT_NORMAL, mode, -+ 1, operands[1], mode); -+ -+ /* The library call is expected to put its result -+ in LIBCALL_VALUE, so need to copy it into the destination. */ -+ emit_move_insn (operands[0], LIBCALL_VALUE(mode)); -+} -+ -+ -+/** -+ * A small helper function that writes out a single branch instruction. -+ * OPCODE is the short name, e.g. "ble". -+ * OPERANDS has the rtx for the target label. -+ * LONG_P is nonzero if we are emitting a long branch, and need to -+ * prepend an 'l' to the opcode name. -+ */ -+void output_branch_insn1 (const char *opcode, rtx *operands, int long_p) -+{ -+ char pattern[64]; -+ sprintf (pattern, "%s%s\t%%l0", long_p ? "l" : "", opcode); -+ output_asm_insn (pattern, operands); -+} -+ -+/** -+ * Output a branch/conditional branch insn of the proper -+ * length. code identifies the particular branch insn. -+ * operands holds the branch target in operands[0]. -+ * length says what the size of this insn should be. -+ * Based on the length, we know whether it should be a -+ * short (8-bit) or long (16-bit) branch. -+ */ -+const char * -+output_branch_insn (enum rtx_code code, rtx *operands, int length) -+{ -+ int shortform; -+ -+ /* Decide whether or not to use the long or short form. -+ * Calculate automatically based on insn lengths. */ -+ shortform = ((length > 2) ? 0 : 1); -+ -+ /* Determine the proper opcode. -+ * Use the short (2-byte) opcode if the target is within -+ * reach. Otherwise, use jmp (3-byte opcode), unless -+ * compiling with -fpic, in which case we'll need to use -+ * lbra (4-byte opcode). -+ */ -+ switch (code) -+ { -+ case LABEL_REF: -+ if (shortform) -+ output_branch_insn1 ("bra", operands, 0); -+ else if (flag_pic) -+ output_branch_insn1 ("bra", operands, 1); -+ else -+ output_branch_insn1 ("jmp", operands, 0); -+ break; -+ case EQ: -+ output_branch_insn1 ("beq", operands, !shortform); -+ break; -+ case NE: -+ output_branch_insn1 ("bne", operands, !shortform); -+ break; -+ case GT: -+ output_branch_insn1 ("bgt", operands, !shortform); -+ break; -+ case GTU: -+ output_branch_insn1 ("bhi", operands, !shortform); -+ break; -+ case LT: -+ if (cc_prev_status.flags & CC_NO_OVERFLOW) -+ { -+ output_branch_insn1 ("bmi", operands, !shortform); -+ } -+ else -+ { -+ output_branch_insn1 ("blt", operands, !shortform); -+ } -+ break; -+ case LTU: -+ output_branch_insn1 ("blo", operands, !shortform); -+ break; -+ case GE: -+ if (cc_prev_status.flags & CC_NO_OVERFLOW) -+ { -+ output_branch_insn1 ("bpl", operands, !shortform); -+ } -+ else -+ { -+ output_branch_insn1 ("bge", operands, !shortform); -+ } -+ break; -+ case GEU: -+ output_branch_insn1 ("bhs", operands, !shortform); -+ break; -+ case LE: -+ if (cc_prev_status.flags & CC_NO_OVERFLOW) -+ { -+ output_branch_insn1 ("bmi", operands, !shortform); -+ output_branch_insn1 ("beq", operands, !shortform); -+ } -+ else -+ { -+ output_branch_insn1 ("ble", operands, !shortform); -+ } -+ break; -+ case LEU: -+ output_branch_insn1 ("bls", operands, !shortform); -+ break; -+ default: -+ abort(); -+ break; -+ } -+ return ""; -+} -+ -+ -+/** Returns the "cost" of an RTL expression. -+ * In general, the expression "COSTS_N_INSNS(1)" is used to represent -+ * the cost of a fast 8-bit arithmetic instruction that operates on -+ * a reg/mem or a reg/immed. Other costs are relative to this. -+ * -+ * Notes: -+ * - The cost of a REG is always zero; this cannot be changed. -+ * -+ * - On the 6809, instructions on two registers will nearly always take -+ * longer than those that operate on a register and a constant/memory, -+ * because of the way the instruction set is structured. -+ * -+ * TODO: multiply HImode by 2 should be done via shifts, instead of add. -+ */ -+static bool -+m6809_rtx_costs (rtx X, int code, int outer_code ATTRIBUTE_UNUSED, -+ int *total, bool speed) -+{ -+ int has_const_arg = 0; -+ HOST_WIDE_INT const_arg; -+ enum machine_mode mode; -+ int nargs = 1; -+ rtx op0, op1; -+ -+ /* Data RTXs return a value between 0-3, depending on complexity. -+ All of these are less than COSTS_N_INSNS(1). */ -+ switch (code) -+ { -+ case CC0: -+ case PC: -+ *total = 0; -+ return true; -+ -+ case CONST_INT: -+ if (X == const0_rtx) -+ { -+ *total = 0; -+ return true; -+ } -+ else if ((unsigned) INTVAL (X) < 077) -+ { -+ *total = 1; -+ return true; -+ } -+ else -+ { -+ *total = 2; -+ return true; -+ } -+ -+ case LABEL_REF: case CONST: -+ *total = 2; -+ return true; -+ -+ case SYMBOL_REF: -+ /* References to memory are made cheaper if they have -+ * the 'direct' mode attribute set */ -+ *total = (SYMBOL_REF_FLAG (X)) ? 1 : 2; -+ return true; -+ -+ case MEM: -+ /* See what form of address was given */ -+ X = XEXP (X, 0); -+ switch (GET_CODE (X)) -+ { -+ case SYMBOL_REF: -+ *total = (SYMBOL_REF_FLAG (X)) ? 1 : 2; -+ break; -+ -+ case CONST_INT: -+ *total = 2; -+ break; -+ -+ case MEM: -+ *total = COSTS_N_INSNS (1) + 2; -+ break; -+ -+ default: -+ break; -+ } -+ return true; -+ -+ case CONST_DOUBLE: -+ /* TODO : not sure about this value. */ -+ *total = 3; -+ return true; -+ -+ default: -+ break; -+ } -+ -+ /* Decode the rtx */ -+ mode = GET_MODE (X); -+ op0 = XEXP (X, 0); -+ op1 = XEXP (X, 1); -+ -+ /* We don't implement anything in SImode or greater. */ -+ if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (SImode)) -+ { -+ *total = COSTS_N_INSNS (100); -+ return true; -+ } -+ -+ /* Figure out if there is a constant argument, and its value. */ -+ if (GET_RTX_CLASS (code) == RTX_BIN_ARITH -+ || GET_RTX_CLASS (code) == RTX_COMM_ARITH) -+ { -+ nargs = 2; -+ if (GET_CODE (op1) == CONST_INT) -+ { -+ has_const_arg = 1; -+ const_arg = INTVAL (op1); -+ } -+ } -+ -+ /* Penalize a reg/reg operation by adding MEMORY_MOVE_COST, -+ * Ignore soft registers, since these are really in memory. -+ * -+ * TODO: penalize HImode reg/reg for most operations, except maybe -+ * additions since index registers allow for that. -+ * -+ * TODO: shifts by constant N do not always require N instructions; -+ * some of this can be done cheaper. The number of actual insns can be -+ * predicted well. -+ */ -+ if (nargs == 2 && REAL_REG_P (op0) && REAL_REG_P (op1)) -+ { -+ *total = MEMORY_MOVE_COST (mode, Q_REGS, 0); -+ } -+ else -+ { -+ *total = 0; -+ } -+ -+ /* Operator RTXs are counted as COSTS_N_INSNS(N), where N is -+ the estimated number of actual machine instructions needed to -+ perform the computation. Some small adjustments are made since -+ some "instructions" are more complex than others. */ -+ switch (code) -+ { -+ case PLUS: case MINUS: case COMPARE: -+ /* 6809 handles these natively in QImode, and in HImode as long -+ * as operand 1 is constant. */ -+ if (mode == QImode || (mode == HImode && has_const_arg)) -+ *total += COSTS_N_INSNS (1); -+ else -+ *total += COSTS_N_INSNS (GET_MODE_SIZE (mode)); -+ -+ /* -1, 0, and 1 can be done using inherent instructions -+ * for PLUS and MINUS in QImode, so don't add extra cost. */ -+ if (has_const_arg -+ && (mode == QImode || mode == HImode) -+ && (const_arg == -1 || const_arg == 0 || const_arg == 1) -+ && (code == PLUS || code == MINUS)) -+ { -+ return true; -+ } -+ break; -+ -+ case AND: case IOR: case XOR: -+ case NEG: case NOT: -+ /* 6809 handles these natively in QImode, but requires -+ * splitting in HImode. Treat these as 2 insns. */ -+ *total += COSTS_N_INSNS (1) * GET_MODE_SIZE (mode); -+ break; -+ -+ case ASHIFT: case ASHIFTRT: case LSHIFTRT: -+ case ROTATE: case ROTATERT: -+ /* 6809 can do shift/rotates of a QImode by a constant in -+ * 1 insn times the shift count, or in HImode by a constant -+ * by splitting to 2 insns. -+ * -+ * Shift by a nonconstant will take significantly longer -+ * than any of these. */ -+ if (has_const_arg) -+ { -+ const_arg %= (GET_MODE_SIZE (mode) * 8); -+ if (const_arg == 0) -+ { -+ *total += COSTS_N_INSNS(1); -+ return true; -+ } -+ -+ /* HImode shifts greater than 8 get optimized due -+ * to register transfer from b to a; this cuts down the -+ * cost. */ -+ if (const_arg >= 8) -+ { -+ *total += COSTS_N_INSNS (1); -+ const_arg -= 8; -+ } -+ -+ /* The computed cost is 'const_arg' 1-bit shifts, doubled -+ if in HImode, minus the cost of the constant itself which -+ will be added in later but really shouldn't be. */ -+ *total += COSTS_N_INSNS (const_arg) * GET_MODE_SIZE (mode) - 1; -+ return true; -+ } -+ else -+ { -+ /* It may take up to 7 iterations of about 6-7 real -+ * instructions, so make this expensive. */ -+ *total += COSTS_N_INSNS (50); -+ } -+ break; -+ -+ case MULT: -+ { -+ /* Multiply is cheap when both arguments are 8-bits. They -+ could be QImode, or QImode widened to HImode, or a constant -+ that fits into 8-bits. As long as both operands qualify, -+ we can use a single mul instruction. -+ -+ Assume that fast multiply can be used, and change this if we find -+ differently... */ -+ int ok_for_qihi3 = 1; -+ -+ /* Check the first operand */ -+ switch (GET_MODE (op0)) -+ { -+ case QImode: -+ break; -+ case HImode: -+ if (GET_CODE (op0) != SIGN_EXTEND && GET_CODE (op0) != ZERO_EXTEND) -+ ok_for_qihi3 = 0; -+ break; -+ default: -+ ok_for_qihi3 = 0; -+ break; -+ } -+ -+ /* Likewise, check the second operand. This is where constants may appear. */ -+ switch (GET_MODE (op1)) -+ { -+ case QImode: -+ break; -+ case HImode: -+ if (GET_CODE (op1) != SIGN_EXTEND && GET_CODE (op1) != ZERO_EXTEND) -+ ok_for_qihi3 = 0; -+ break; -+ case VOIDmode: -+ if (!CONST_OK_FOR_LETTER_P (const_arg, 'K')) -+ ok_for_qihi3 = 0; -+ break; -+ default: -+ ok_for_qihi3 = 0; -+ break; -+ } -+ -+ /* Fast multiply takes about 4 times as many cycles as a normal -+ arithmetic operation. Otherwise, it will take an expensive libcall. */ -+ if (ok_for_qihi3) -+ *total += COSTS_N_INSNS (4); -+ else -+ *total = COSTS_N_INSNS (50); -+ break; -+ } -+ -+ case DIV: case UDIV: case MOD: case UMOD: -+ /* These all require more expensive libcalls. */ -+ *total += COSTS_N_INSNS (100); -+ break; -+ -+ /* TODO : TRUNCATE, SIGN_EXTEND, and ZERO_EXTEND */ -+ -+ /* These can normally be done with autoincrement, etc., so -+ * don't charge for them. */ -+ case PRE_DEC: -+ case PRE_INC: -+ case POST_DEC: -+ case POST_INC: -+ break; -+ -+ default: -+ break; -+ } -+ -+ /* Always return false, and let the caller gather the costs -+ * of the operands */ -+ return false; -+} -+ -+ -+static tree -+m6809_handle_fntype_attribute (tree *node, tree name, -+ tree args ATTRIBUTE_UNUSED, -+ int flags ATTRIBUTE_UNUSED, -+ bool *no_add_attrs) -+{ -+ if (TREE_CODE (*node) != FUNCTION_TYPE) -+ { -+ warning (WARNING_OPT "'%s' only valid for functions", -+ IDENTIFIER_POINTER (name)); -+ *no_add_attrs = TRUE; -+ } -+ -+ return NULL_TREE; -+} -+ -+ -+static tree -+m6809_handle_data_type_attribute (tree *node ATTRIBUTE_UNUSED, -+ tree name ATTRIBUTE_UNUSED, -+ tree args ATTRIBUTE_UNUSED, -+ int flags ATTRIBUTE_UNUSED, -+ bool *no_add_attrs ATTRIBUTE_UNUSED) -+{ -+ return NULL_TREE; -+} -+ -+ -+ -+static tree -+m6809_handle_default_attribute (tree *node ATTRIBUTE_UNUSED, -+ tree name ATTRIBUTE_UNUSED, -+ tree args ATTRIBUTE_UNUSED, -+ int flags ATTRIBUTE_UNUSED, -+ bool *no_add_attrs ATTRIBUTE_UNUSED ) -+{ -+ return NULL_TREE; -+} -+ -+ -+/* Table of valid machine attributes */ -+const struct attribute_spec m6809_attribute_table[] = { /* -+{ name, min, max, decl, type, fntype, handler } */ -+{ "interrupt", 0, 0, false, true, true, m6809_handle_fntype_attribute }, -+{ "naked", 0, 0, false, true, true, m6809_handle_fntype_attribute }, -+{ "far", 0, 1, false, true, true, m6809_handle_fntype_attribute }, -+{ "bank", 0, 1, true, false, false, m6809_handle_default_attribute }, -+{ "boolean", 0, 0, false, true, false, m6809_handle_data_type_attribute }, -+{ NULL, 0, 0, false, true, false, NULL }, -+}; -+ -+ -+/** Initialize builtin routines for the 6809. */ -+void -+m6809_init_builtins (void) -+{ -+ /* Create type trees for each function signature required. -+ * -+ * void_ftype_void = void f(void) -+ * void_ftype_uchar = void f(unsigned char) -+ * uchar_ftype_uchar2 = unsigned char f (unsigned char, unsigned char) -+ */ -+ tree void_ftype_void = -+ build_function_type (void_type_node, void_list_node); -+ -+ tree void_ftype_uchar = -+ build_function_type (void_type_node, -+ tree_cons (NULL_TREE, unsigned_char_type_node, void_list_node)); -+ -+ tree uchar_ftype_uchar2 = -+ build_function_type (unsigned_char_type_node, -+ tree_cons (NULL_TREE, unsigned_char_type_node, -+ tree_cons (NULL_TREE, unsigned_char_type_node, void_list_node))); -+ -+ /* Register each builtin function. */ -+ add_builtin_function ("__builtin_swi", void_ftype_void, -+ M6809_SWI, BUILT_IN_MD, NULL, NULL_TREE); -+ -+ add_builtin_function ("__builtin_swi2", void_ftype_void, -+ M6809_SWI2, BUILT_IN_MD, NULL, NULL_TREE); -+ -+ add_builtin_function ("__builtin_swi3", void_ftype_void, -+ M6809_SWI3, BUILT_IN_MD, NULL, NULL_TREE); -+ -+ add_builtin_function ("__builtin_cwai", void_ftype_uchar, -+ M6809_CWAI, BUILT_IN_MD, NULL, NULL_TREE); -+ -+ add_builtin_function ("__builtin_sync", void_ftype_void, -+ M6809_SYNC, BUILT_IN_MD, NULL, NULL_TREE); -+ -+ add_builtin_function ("__builtin_nop", void_ftype_void, -+ M6809_NOP, BUILT_IN_MD, NULL, NULL_TREE); -+ -+ add_builtin_function ("__builtin_blockage", void_ftype_void, -+ M6809_BLOCKAGE, BUILT_IN_MD, NULL, NULL_TREE); -+ -+ add_builtin_function ("__builtin_add_decimal", uchar_ftype_uchar2, -+ M6809_ADD_DECIMAL, BUILT_IN_MD, NULL, NULL_TREE); -+ -+ add_builtin_function ("__builtin_add_carry", uchar_ftype_uchar2, -+ M6809_ADD_CARRY, BUILT_IN_MD, NULL, NULL_TREE); -+ -+ add_builtin_function ("__builtin_sub_carry", uchar_ftype_uchar2, -+ M6809_SUB_CARRY, BUILT_IN_MD, NULL, NULL_TREE); -+} -+ -+ -+/** Used by m6809_expand_builtin, given a tree ARGLIST which -+ * refers to the operands of a builtin call, return an rtx -+ * that represents the nth operand, as denoted by OPNUM, which -+ * is a zero-based integer. MODE gives the expected mode -+ * of the operand. -+ * -+ * This rtx is suitable for use in the emitted RTL for the -+ * builtin instruction. */ -+rtx -+m6809_builtin_operand (tree arglist, enum machine_mode mode, int opnum) -+{ -+ tree arg; -+ rtx r; -+ -+ arg = CALL_EXPR_ARG (arglist, opnum); -+ -+ /* Convert the tree to RTL */ -+ r = expand_expr (arg, NULL_RTX, mode, EXPAND_NORMAL); -+ if (r == NULL_RTX) -+ return NULL_RTX; -+ return r; -+} -+ -+ -+/** Expand a builtin that was registered in init_builtins into -+ * RTL. */ -+rtx -+m6809_expand_builtin (tree exp, -+ rtx target, -+ rtx subtarget ATTRIBUTE_UNUSED, -+ enum machine_mode mode ATTRIBUTE_UNUSED, -+ int ignore ATTRIBUTE_UNUSED ) -+{ -+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); -+ tree arglist = exp; -+ unsigned int fcode = DECL_FUNCTION_CODE (fndecl); -+ rtx r0, r1; -+ -+ switch (fcode) -+ { -+ case M6809_SWI: -+ r0 = gen_rtx_CONST_INT (VOIDmode, 1); -+ emit_insn (target = gen_m6809_swi (r0)); -+ return target; -+ -+ case M6809_SWI2: -+ r0 = gen_rtx_CONST_INT (VOIDmode, 2); -+ emit_insn (target = gen_m6809_swi (r0)); -+ return target; -+ -+ case M6809_SWI3: -+ r0 = gen_rtx_CONST_INT (VOIDmode, 3); -+ emit_insn (target = gen_m6809_swi (r0)); -+ return target; -+ -+ case M6809_CWAI: -+ r0 = m6809_builtin_operand (arglist, QImode, 0); -+ emit_insn (target = gen_m6809_cwai (r0)); -+ return target; -+ -+ case M6809_SYNC: -+ emit_insn (target = gen_m6809_sync ()); -+ return target; -+ -+ case M6809_ADD_CARRY: -+ r0 = m6809_builtin_operand (arglist, QImode, 0); -+ r1 = m6809_builtin_operand (arglist, QImode, 1); -+ if (!target) -+ target = gen_reg_rtx (QImode); -+ emit_insn (gen_addqi3_carry (target, r0, r1)); -+ return target; -+ -+ case M6809_SUB_CARRY: -+ r0 = m6809_builtin_operand (arglist, QImode, 0); -+ r1 = m6809_builtin_operand (arglist, QImode, 1); -+ if (!target) -+ target = gen_reg_rtx (QImode); -+ emit_insn (gen_subqi3_carry (target, r0, r1)); -+ return target; -+ -+ case M6809_NOP: -+ emit_insn (target = gen_nop ()); -+ return target; -+ -+ case M6809_BLOCKAGE: -+ emit_insn (target = gen_blockage ()); -+ return target; -+ -+ case M6809_ADD_DECIMAL: -+ r0 = m6809_builtin_operand (arglist, QImode, 0); -+ r1 = m6809_builtin_operand (arglist, QImode, 1); -+ if (!target) -+ target = gen_reg_rtx (QImode); -+ emit_insn (gen_addqi3_decimal (target, r0, r1)); -+ return target; -+ -+ default: -+ warning (WARNING_OPT "unknown builtin expansion ignored"); -+ return NULL_RTX; -+ } -+} -+ -+ -+ -+/* Returns nonzero if 'x' represents a function that was declared -+ * as __noreturn__. */ -+int -+noreturn_functionp (rtx x) -+{ -+ tree decl = call_target_decl (x); -+ -+ if (decl == NULL_TREE) -+ return 0; -+ else -+ return TREE_THIS_VOLATILE (decl); -+} -+ -+ -+const char * -+far_function_type_p (tree type) -+{ -+ tree attr; -+ const char *page; -+ -+ /* Return whether or not this decl has the far attribute */ -+ attr = lookup_attribute ("far", TYPE_ATTRIBUTES (type)); -+ if (attr == NULL_TREE) -+ return NULL; -+ -+ /* If it is far, check for a value */ -+ attr = TREE_VALUE (attr); -+ if (attr == NULL_TREE) -+ { -+ warning (WARNING_OPT "far code page not specified, using local value"); -+ return far_code_page; -+ } -+ -+ /* We have a TREE_LIST of attribute values, get the first one. -+ * It should be an INTEGER_CST. */ -+ attr = TREE_VALUE (attr); -+ page = TREE_STRING_POINTER (attr); -+ return page; -+} -+ -+ -+/* For a far function, returns the identifier that states which page -+ * it resides in. Otherwise, returns NULL for ordinary functions. */ -+const char * -+far_functionp (rtx x) -+{ -+ tree decl, decl_type; -+ const char *page; -+ -+ /* Find the FUNCTION_DECL corresponding to the rtx being called. */ -+ decl = call_target_decl (x); -+ if (decl == NULL_TREE) -+ return NULL; -+ -+ /* See if the function has the new 'banked' attribute. These -+ * are numeric instead of text */ -+ page = m6809_get_decl_bank (decl); -+ if (page) -+ return page; -+ -+ /* No, lookup the type of the function and see if the type -+ * specifies far or not. */ -+ decl_type = TREE_TYPE (decl); -+ if (decl_type == NULL_TREE) -+ return NULL; -+ return far_function_type_p (decl_type); -+} -+ -+ -+ -+/** Outputs the assembly language for a far call. */ -+void -+output_far_call_insn (rtx *operands, int has_return) -+{ -+ static char page_data[64]; -+ const char *called_page; -+ -+ /* The logic is the same for functions whether or not there -+ * is a return value. Skip over the return value in this -+ * case, so that the call location is always operands[0]. */ -+ if (has_return) -+ operands++; -+ -+ /* Get the name of the page being called */ -+ called_page = far_functionp (operands[0]); -+ -+#if 0 /* TODO : broken logic */ -+ /* See if the called page name is a 'bank' */ -+ if (isdigit (*called_page)) -+ { -+ /* New style banking */ -+ if (!strcmp (called_page, current_bank_name)) -+ { -+ /* Same page */ -+ output_asm_insn ("jsr\t%0", operands); -+ } -+ else -+ { -+ /* Different page */ -+ output_asm_insn ("jsr\t__far_call_handler\t;new style", operands); -+ output_asm_insn ("\t.dw\t%0", operands); -+ sprintf (page_data, "\t.db\t%s", called_page); -+ output_asm_insn (page_data, operands); -+ } -+ return; -+ } -+#endif -+ -+ /* Are we calling a different page than we are running in? */ -+ if (!strcmp (called_page, far_code_page)) -+ { -+ /* Same page : no need to execute a far call */ -+ if (flag_pic) -+ output_asm_insn ("lbsr\t%C0", operands); -+ else -+ output_asm_insn ("jsr\t%0", operands); -+ } -+ else -+ { -+ /* Different page : need to emit far call thunk */ -+ -+ /* First output a call to the thunk for making far calls. */ -+ if (flag_pic) -+ output_asm_insn ("lbsr\t__far_call_handler", operands); -+ else -+ output_asm_insn ("jsr\t__far_call_handler\t;old style", operands); -+ -+ /* Now output the name of the call site */ -+ output_asm_insn ("\t.dw\t%C0", operands); -+ -+ /* Finally output the page number */ -+ sprintf (page_data, "\t.db\t%s", far_functionp (operands[0])); -+ output_asm_insn (page_data, operands); -+ } -+} -+ -+ -+int -+m6809_init_cumulative_args (CUMULATIVE_ARGS cum ATTRIBUTE_UNUSED, -+ tree fntype, -+ rtx libname ATTRIBUTE_UNUSED) -+{ -+ cum = 0; -+ -+ /* For far functions, the current implementation does not allow for -+ * stack parameters. So note whenever the called function is far -+ * and in a different page than the current one; such a function -+ * should give an error if a stack parameter is generated. */ -+ if (fntype) -+ { -+ const char *called_page = far_function_type_p (fntype); -+ if (called_page && strcmp (called_page, far_code_page) && !TARGET_FAR_STACK_PARAM) -+ cum |= CUM_STACK_INVALID; -+ } -+ -+ if (fntype && TYPE_ARG_TYPES (fntype) != 0 && -+ (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)) -+ { -+ /* has variable arguments, cannot use registers */ -+ cum |= (CUM_X_MASK | CUM_B_MASK | CUM_STACK_ONLY); -+ } -+ -+ if (m6809_abi_version == M6809_ABI_VERSION_STACK) -+ { -+ /* cannot use registers ; only use the stack */ -+ cum |= (CUM_STACK_ONLY | CUM_X_MASK | CUM_B_MASK); -+ } -+ -+ return cum; -+} -+ -+ -+rtx -+m6809_function_arg_on_stack (CUMULATIVE_ARGS *cump) -+{ -+ if (*cump & CUM_STACK_INVALID) -+ { -+ *cump &= ~CUM_STACK_INVALID; -+ error ("far function needs stack, will not work"); -+ } -+ return NULL_RTX; -+} -+ -+void m6809_asm_trampoline_template(FILE *f) -+{ -+ fprintf(f, "ldy #0000\n"); -+ fprintf(f, "jmp 0x0000\n"); -+} -+ -+/* -+ * Trampoline output: -+ * -+ * ldu #&cxt 4 bytes --LDY- ?? ?? -+ * jmp fnaddr 3 bytes JMP ?? ?? -+ */ -+void -+m6809_initialize_trampoline (rtx tramp, tree fndecl, rtx cxt) -+{ -+ rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); -+ /* TODO - optimize by generating the entire trampoline code here, -+ * and removing the template altogether, since there are only two -+ * bytes there that matter. */ -+ emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt); -+ emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 5)), fnaddr); -+} -+ -+ -+/** Echo the version of the compiler and the name of the source file -+ * at the beginning of each assembler output file. asm_out_file -+ * is a global FILE * pointing to the output stream. */ -+void -+m6809_asm_file_start (void) -+{ -+ const char *module_name; -+ -+ fprintf (asm_out_file, "\n;;; gcc for m6809 : %s %s\n", -+ __DATE__, __TIME__); -+ fprintf (asm_out_file, ";;; %s\n", version_string); -+ -+ fprintf (asm_out_file, ";;; ABI version %d\n", m6809_abi_version); -+ fprintf (asm_out_file, ";;; %s\n", -+ (TARGET_BYTE_INT ? "-mint8" : "-mint16")); -+ if (TARGET_EXPERIMENT) -+ fprintf (asm_out_file, ";;; -mexperiment\n"); -+ if (TARGET_WPC) -+ fprintf (asm_out_file, ";;; -mwpc\n"); -+ if (TARGET_6309) -+ fprintf (asm_out_file, ";;; -m6309\n"); -+ -+ /* Print the name of the module, which is taken as the base name -+ * of the input file. -+ * See the 'User-Defined Symbols' section of the assembler -+ * documentation for the rules on valid symbols. -+ */ -+ module_name = lbasename (main_input_filename); -+ -+ fprintf (asm_out_file, "\t.module\t"); -+ -+ if (*module_name >= '0' && *module_name <= '9') -+ fprintf (asm_out_file, "_"); -+ -+ while (*module_name) -+ { -+ if ((*module_name >= '0' && *module_name <= '9') -+ || (*module_name >= 'A' && *module_name <= 'Z') -+ || (*module_name >= 'a' && *module_name <= 'z') -+ || *module_name == '$' -+ || *module_name == '.' -+ || *module_name == '_') -+ { -+ fprintf (asm_out_file, "%c", *module_name); -+ } -+ else -+ { -+ fprintf (asm_out_file, "_"); -+ } -+ module_name++; -+ } -+ -+ fprintf (asm_out_file, "\n"); -+} -+ -+ -+/** Returns true if prologue/epilogue code is required for the -+ * current function being compiled. -+ * -+ * This is just the inverse of whether the function is declared as -+ * 'naked'. -+ */ -+int -+prologue_epilogue_required (void) -+{ -+ return !m6809_current_function_has_type_attr_p ("naked") -+ && !m6809_current_function_has_type_attr_p ("noreturn"); -+} -+ -+ -+/** Expand RTL for function entry */ -+void -+emit_prologue_insns (void) -+{ -+ rtx insn; -+ unsigned int live_regs = m6809_get_live_regs (); -+ unsigned int frame_size = get_frame_size (); -+ -+ /* Save all registers used, including the frame pointer */ -+ if (live_regs && !m6809_current_function_has_type_attr_p ("interrupt")) -+ { -+ insn = emit_insn ( -+ gen_rtx_register_pushpop (UNSPEC_PUSH_RS, live_regs)); -+ RTX_FRAME_RELATED_P (insn) = 1; -+ } -+ -+ /* Allocate space for local variables */ -+ if (frame_size != 0) -+ { -+ insn = emit_insn (gen_rtx_stack_adjust (MINUS, frame_size)); -+ RTX_FRAME_RELATED_P (insn) = 1; -+ } -+ -+ /* Set the frame pointer if it is needed */ -+ if (frame_pointer_needed) -+ { -+ insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); -+ RTX_FRAME_RELATED_P (insn) = 1; -+ } -+} -+ -+ -+/** Expand RTL for function exit */ -+void -+emit_epilogue_insns (bool sibcall_p) -+{ -+ unsigned int live_regs = m6809_get_live_regs (); -+ unsigned int frame_size = get_frame_size (); -+ -+ if (frame_size != 0) -+ emit_insn (gen_rtx_stack_adjust (PLUS, frame_size)); -+ -+ if (sibcall_p) -+ { -+ if (live_regs) -+ emit_insn (gen_rtx_register_pushpop (UNSPEC_POP_RS, live_regs)); -+ } -+ else -+ { -+ if (live_regs && !m6809_current_function_has_type_attr_p ("interrupt")) -+ emit_insn ( -+ gen_rtx_register_pushpop (UNSPEC_POP_RS, PC_REGBIT | live_regs)); -+ -+ if (m6809_current_function_has_type_attr_p ("interrupt")) -+ emit_jump_insn (gen_return_rti ()); -+ else -+ emit_jump_insn (gen_return_rts ()); -+ } -+} -+ -+#if 0 -+/** Predefine some preprocessor names according to the currently -+ * selected compiler options */ -+void -+m6809_cpu_cpp_builtins (void) -+{ -+ if (TARGET_6309) -+ { -+ builtin_define_std ("__M6309__"); -+ builtin_define_std ("__m6309__"); -+ } -+ else -+ { -+ builtin_define_std ("__M6809__"); -+ builtin_define_std ("__m6809__"); -+ } -+ -+ if (TARGET_BYTE_INT) -+ builtin_define_std ("__int8__"); -+ else -+ builtin_define_std ("__int16__"); -+ -+ switch (m6809_abi_version) -+ { -+ case M6809_ABI_VERSION_STACK: -+ builtin_define_std ("__regargs__"); -+ builtin_define_std ("__ABI_STACK__"); -+ break; -+ case M6809_ABI_VERSION_REGS: -+ builtin_define_std ("__ABI_REGS__"); -+ break; -+ case M6809_ABI_VERSION_BX: -+ builtin_define_std ("__ABI_BX__"); -+ break; -+ default: -+ break; -+ } -+ -+ if (TARGET_WPC) -+ builtin_define_std ("__WPC__"); -+ -+ if (TARGET_DRET) -+ builtin_define_std ("__DRET__"); -+} -+#endif -+ -+#define MAX_ASM_ASCII_STRING 48 -+ -+void -+m6809_output_ascii (FILE *fp, const char *str, unsigned long size) -+{ -+ unsigned long i; -+ bool use_ascii = true; -+ -+ /* If the size is too large, then break this up into multiple -+ outputs. The assembler can only output roughly 48 bytes at a -+ time. Note that if there are lots of escape sequences in -+ the string, this may fail. */ -+ if (size > MAX_ASM_ASCII_STRING) -+ { -+ m6809_output_ascii (fp, str, MAX_ASM_ASCII_STRING); -+ m6809_output_ascii (fp, str + MAX_ASM_ASCII_STRING, -+ size - MAX_ASM_ASCII_STRING); -+ return; -+ } -+ -+ /* Check for 8-bit codes, which cannot be embedded in an .ascii */ -+ for (i = 0; i < size; i++) -+ { -+ int c = str[i] & 0377; -+ if (c >= 0x80) -+ { -+ use_ascii = false; -+ break; -+ } -+ } -+ -+ if (use_ascii) -+ fprintf (fp, "\t.ascii \""); -+ -+ for (i = 0; i < size; i++) -+ { -+ int c = str[i] & 0377; -+ -+ if (use_ascii) -+ { -+ /* Just output the plain character if it is printable, -+ otherwise output the escape code for the character. -+ The assembler recognizes the same C-style octal escape sequences, -+ except that it only supports 7-bit codes. */ -+ if (c >= ' ' && c < 0177 && c != '\\' && c != '"') -+ putc (c, fp); -+ else switch (c) -+ { -+ case '\n': -+#ifndef TARGET_COCO -+ fputs ("\\n", fp); -+ break; -+#endif -+ /* On the CoCo, we fallthrough and treat '\n' like '\r'. */ -+ case '\r': -+ fputs ("\\r", fp); -+ break; -+ case '\t': -+ fputs ("\\t", fp); -+ break; -+ case '\f': -+ fputs ("\\f", fp); -+ break; -+ case 0: -+ fputs ("\\0", fp); -+ break; -+ default: -+ fprintf (fp, "\\%03o", c); -+ break; -+ } -+ } -+ else -+ { -+ fprintf (fp, "\t.byte\t0x%02X\n", c); -+ } -+ } -+ -+ if (use_ascii) -+ fprintf (fp, "\"\n"); -+} -+ -+ -+void -+m6809_output_quoted_string (FILE *asm_file, const char *string) -+{ -+ char c; -+ -+ if (strlen (string) > MAX_ASM_ASCII_STRING) -+ { -+ /* The string length is too large. We'll have to truncate it. -+ This is only called from debugging functions, so it's usually -+ not critical. */ -+ -+ char truncated_string[MAX_ASM_ASCII_STRING+1]; -+ -+ /* Copy as many characters as we can. */ -+ strncpy (truncated_string, string, MAX_ASM_ASCII_STRING); -+ truncated_string[MAX_ASM_ASCII_STRING] = '\0'; -+ string = truncated_string; -+ } -+ -+ /* Copied from toplev.c */ -+ -+ putc ('\"', asm_file); -+ while ((c = *string++) != 0) { -+ if (ISPRINT (c)) { -+ if (c == '\"' || c == '\\') -+ putc ('\\', asm_file); -+ putc (c, asm_file); -+ } -+ else -+ fprintf (asm_file, "\\%03o", (unsigned char) c); -+ } -+ putc ('\"', asm_file); -+} -+ -+ -+/** Output the assembly code for a shift instruction where the -+ * shift count is not constant. */ -+void -+m6809_output_shift_insn (int rtx_code, rtx *operands) -+{ -+ struct shift_opcode *op; -+ -+ if (GET_CODE (operands[2]) == CONST_INT) -+ abort (); -+ -+ if (optimize_size && GET_MODE (operands[0]) == HImode) -+ { -+ switch (rtx_code) -+ { -+ case ASHIFT: -+ output_asm_insn ("jsr\t_ashlhi3", operands); -+ break; -+ case ASHIFTRT: -+ output_asm_insn ("jsr\t_ashrhi3", operands); -+ break; -+ case LSHIFTRT: -+ output_asm_insn ("jsr\t_lshrhi3", operands); -+ break; -+ } -+ } -+ else if (GET_MODE (operands[0]) == HImode) -+ { -+ switch (rtx_code) -+ { -+ case ASHIFT: -+ m6809_gen_register_shift (operands, "aslb", "rola"); -+ break; -+ case ASHIFTRT: -+ m6809_gen_register_shift (operands, "asra", "rorb"); -+ break; -+ case LSHIFTRT: -+ m6809_gen_register_shift (operands, "lsra", "rorb"); -+ break; -+ } -+ } -+ else -+ { -+ switch (rtx_code) -+ { -+ case ASHIFT: -+ m6809_gen_register_shift (operands, "aslb", NULL); -+ break; -+ case ASHIFTRT: -+ m6809_gen_register_shift (operands, "asrb", NULL); -+ break; -+ case LSHIFTRT: -+ m6809_gen_register_shift (operands, "lsrb", NULL); -+ break; -+ } -+ } -+} -+ -+ -+void -+m6809_emit_move_insn (rtx dst, rtx src) -+{ -+ emit_insn (gen_rtx_SET (VOIDmode, dst, src)); -+ if (ACC_A_REG_P (dst)) -+ emit_insn (gen_rtx_USE (VOIDmode, dst)); -+} -+ -+ -+/** Split a complex shift instruction into multiple CPU -+ * shift instructions. */ -+void -+m6809_split_shift (enum rtx_code code, rtx *operands) -+{ -+ enum machine_mode mode; -+ int count; -+ -+ mode = GET_MODE (operands[0]); -+ count = INTVAL (operands[2]); -+ -+ /* Handle a shift count outside the range of 0 .. N-1, where -+ * N is the mode size in bits. We normalize the count, and -+ * for negative counts we also invert the direction of the -+ * shift. */ -+ if ((count < 0) || (count >= 8 * GET_MODE_SIZE (mode))) -+ { -+ if (count < 0) -+ { -+ count = -count; -+ code = (code == ASHIFT) ? ASHIFTRT : ASHIFT; -+ } -+ count %= (8 * GET_MODE_SIZE (mode)); -+ m6809_emit_move_insn (operands[0], -+ gen_rtx_fmt_ee (code, mode, operands[1], -+ gen_rtx_CONST_INT (VOIDmode, count))); -+ } -+ -+ /* Handle shift by zero explicitly as a no-op. */ -+ if (count == 0) -+ { -+ emit_insn (gen_nop ()); -+ return; -+ } -+ -+ /* Decompose the shift by a constant N > 8 into two -+ * shifts, first by 8 and then by N-8. -+ * This "speeds up" the process for large shifts that would be -+ * handled below, but allows for some optimization. -+ * In some cases shift by 8 can be implemented fast. If an -+ * instruction to shift by 8 is defined, it will be used here; -+ * otherwise it will be further decomposed as below. */ -+ if (mode == HImode && count > 8) -+ { -+ rtx output = operands[0]; -+ -+ m6809_emit_move_insn (operands[0], -+ gen_rtx_fmt_ee (code, mode, operands[1], -+ gen_rtx_CONST_INT (VOIDmode, 8))); -+ -+ /* Unsigned shifts always produce a zero in either the -+ * upper or lower half of the output; then, that part -+ * does not need to be shifted anymore. We modify the -+ * output and the subsequent instructions to operate in -+ * QImode only on the relevant part. */ -+ if (REG_P (output)) -+ { -+ if (code == ASHIFT) -+ { -+ output = gen_rtx_REG (QImode, HARD_A_REGNUM); -+ mode = QImode; -+ } -+ else -+ { -+ output = gen_rtx_REG (QImode, HARD_D_REGNUM); -+ mode = QImode; -+ } -+ } -+ -+ m6809_emit_move_insn (output, -+ gen_rtx_fmt_ee (code, mode, copy_rtx (output), -+ gen_rtx_CONST_INT (VOIDmode, count-8))); -+ return; -+ } -+ -+ /* Rewrite the unsigned shift of an 8-bit register by a large constant N -+ * (near to the maximum of 8) as a rotate and mask. */ -+ if (mode == QImode && REG_P (operands[0]) && count >= ((code == ASHIFTRT) ? 7 : 6)) -+ { -+ unsigned int mask; -+ unsigned int was_signed = (code == ASHIFTRT); -+ -+ code = (code == ASHIFT) ? ROTATERT : ROTATE; -+ if (code == ROTATE) -+ mask = (count == 6) ? 0x03 : 0x01; -+ else -+ mask = (count == 6) ? 0xC0 - 0x100 : 0x80 - 0x100; -+ count = 9 - count; -+ -+ do { -+ m6809_emit_move_insn (operands[0], -+ gen_rtx_fmt_ee (code, QImode, operands[1], const1_rtx)); -+ } while (--count != 0); -+ -+ m6809_emit_move_insn (operands[0], -+ gen_rtx_fmt_ee (AND, QImode, operands[1], -+ gen_rtx_CONST_INT (VOIDmode, mask))); -+ -+ if (was_signed) -+ { -+ emit_insn (gen_negqi2 (operands[0], copy_rtx (operands[0]))); -+ if (ACC_A_REG_P (operands[0])) -+ emit_insn (gen_rtx_USE (VOIDmode, operands[0])); -+ } -+ return; -+ } -+ -+ /* Decompose the shift by any constant N > 1 into a sequence -+ * of N shifts. -+ * This is done recursively, by creating a shift by 1 and a -+ * shift by N-1, as long as N>1. */ -+ if (count > 1) -+ { -+ m6809_emit_move_insn (operands[0], -+ gen_rtx_fmt_ee (code, mode, operands[1], const1_rtx)); -+ -+ m6809_emit_move_insn (operands[0], -+ gen_rtx_fmt_ee (code, mode, operands[1], -+ gen_rtx_CONST_INT (VOIDmode, count-1))); -+ return; -+ } -+ -+ /* Decompose the single shift of a 16-bit quantity into two -+ * CPU instructions, one for each 8-bit half. -+ */ -+ if (mode == HImode && count == 1) -+ { -+ rtx first, second; -+ enum rtx_code rotate_code; -+ -+ rotate_code = (code == ASHIFT) ? ROTATE : ROTATERT; -+ -+ /* Split the operand into two 8-bit entities. -+ * FIRST is the one that will get shifted via a regular CPU -+ * instruction. -+ * SECOND is the one that will have the result of the first shift -+ * rotated in. -+ * -+ * We initialize first and second as if we are doing a left shift, -+ * then swap the operands if it's a right shift. -+ */ -+ if (REG_P (operands[0])) -+ { -+ first = gen_rtx_REG (QImode, HARD_D_REGNUM); /* HARD_B_REGNUM? */ -+ second = gen_rtx_REG (QImode, HARD_A_REGNUM); -+ } -+ else -+ { -+ first = adjust_address (operands[0], QImode, 1); -+ second = adjust_address (operands[0], QImode, 0); -+ } -+ -+ if (rotate_code == ROTATERT) -+ { -+ rtx tmp; tmp = first; first = second; second = tmp; -+ } -+ -+ /* Decompose into a shift and a rotate instruction. */ -+ m6809_emit_move_insn (first, -+ gen_rtx_fmt_ee (code, QImode, copy_rtx (first), const1_rtx)); -+ m6809_emit_move_insn (second, -+ gen_rtx_fmt_ee (rotate_code, QImode, copy_rtx (second), const1_rtx)); -+ return; -+ } -+} -+ -+ -+/** Adjust register usage based on compile-time flags. */ -+void -+m6809_conditional_register_usage (void) -+{ -+ unsigned int soft_regno; -+ -+#ifdef CONFIG_SOFT_REGS_ALWAYS -+ m6809_soft_regs = CONFIG_SOFT_REGS_ALWAYS; -+#else -+ if (!m6809_soft_reg_count) -+ return; -+ m6809_soft_regs = atoi (m6809_soft_reg_count); -+#endif -+ -+ if (m6809_soft_regs == 0) -+ return; -+ -+ if (m6809_soft_regs > NUM_M_REGS) -+ m6809_soft_regs = NUM_M_REGS; -+ -+ /* Registers are marked FIXED by default. Free up if -+ the user wishes. */ -+ for (soft_regno = 1; soft_regno < m6809_soft_regs; soft_regno++) -+ { -+ fixed_regs[SOFT_M0_REGNUM + soft_regno] = 0; -+ -+ /* Mark the softregs as call-clobbered, so that they need -+ * not be saved/restored on function entry/exit. */ -+ call_used_regs[SOFT_M0_REGNUM + soft_regno] = 1; -+ } -+} -+ -+ -+/** Return a RTX representing how to return a value from a function. -+ VALTYPE gives the type of the value, FUNC identifies the function -+ itself. -+ -+ In general, we only care about the width of the result. */ -+rtx -+m6809_function_value (const tree valtype, const tree func ATTRIBUTE_UNUSED) -+{ -+ unsigned int regno; -+ enum machine_mode mode; -+ -+ /* Get the mode (i.e. width) of the result. */ -+ mode = TYPE_MODE (valtype); -+ -+ if (lookup_attribute ("boolean", TYPE_ATTRIBUTES (valtype))) -+ regno = HARD_Z_REGNUM; -+ else if (mode == QImode || (TARGET_DRET && mode == HImode)) -+ regno = HARD_D_REGNUM; -+ else -+ regno = HARD_X_REGNUM; -+ return gen_rtx_REG (mode, regno); -+} -+ -+ -+/** Return 1 if REGNO is possibly needed to return the result -+of a function, 0 otherwise. */ -+int -+m6809_function_value_regno_p (unsigned int regno) -+{ -+ if (regno == HARD_Z_REGNUM) -+ return 1; -+ else if ((TARGET_BYTE_INT || TARGET_DRET) && regno == HARD_D_REGNUM) -+ return 1; -+ else if (!TARGET_DRET && regno == HARD_X_REGNUM) -+ return 1; -+ else -+ return 0; -+} -+ -+ -+#ifdef TRACE_PEEPHOLE -+int -+m6809_match_peephole2 (unsigned int peephole_id, unsigned int stage) -+{ -+ if (stage == PEEP_END) -+ { -+ printf ("%s: peephole %d pattern and predicate matched\n", -+ main_input_filename, peephole_id); -+ fflush (stdout); -+ } -+ else if (stage == PEEP_COND) -+ { -+ printf ("%s: peephole %d? at least pattern matched\n", -+ main_input_filename, peephole_id); -+ fflush (stdout); -+ } -+ return 1; -+} -+#else -+int -+m6809_match_peephole2 (unsigned int peephole_id ATTRIBUTE_UNUSED, -+ unsigned int stage ATTRIBUTE_UNUSED) -+{ -+ return 1; -+} -+#endif /* TRACE_PEEPHOLE */ -+ -+ -+/** Return 1 if it is OK to store a value of MODE in REGNO. */ -+int -+m6809_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) -+{ -+ /* Soft registers, as they are just memory, can really hold -+ values of any type. However we restrict them to values of -+ size HImode or QImode to prevent exhausting them for larger -+ values. -+ Word values cannot be placed into the first soft register, -+ as it is the low byte that is being placed there, which -+ corrupts the (non-soft) register before it. */ -+ if (M_REGNO_P (regno)) -+ { -+ switch (GET_MODE_SIZE (mode)) -+ { -+ case 1: -+ return 1; -+ case 2: -+ return regno != SOFT_M0_REGNUM; -+ default: -+ return 0; -+ } -+ } -+ -+ /* VOIDmode can be stored anywhere */ -+ else if (mode == VOIDmode) -+ return 1; -+ -+ /* Zero is a reserved register, but problems occur if we don't -+ say yes here??? */ -+ else if (regno == 0) -+ return 1; -+ -+ /* For other registers, return true only if the requested size -+ exactly matches the hardware size. */ -+ else if ((G_REGNO_P (regno)) && (GET_MODE_SIZE (mode) == 2)) -+ return 1; -+ else if ((BYTE_REGNO_P (regno)) && (GET_MODE_SIZE (mode) == 1)) -+ return 1; -+ else -+ return 0; -+} -+ -+ -+/* exp is the call expression. DECL is the called function, -+ * or NULL for an indirect call */ -+bool -+m6809_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) -+{ -+ tree type, arg; -+ const char *name; -+ bool result = 0; -+ int argcount = 0; -+ int step = 1; -+ -+ /* If there is no DECL, it is an indirect call. -+ * Never optimize this??? */ -+ if (decl == NULL) -+ goto done; -+ -+ /* Never allow an interrupt handler to be optimized this way. */ -+ if (m6809_function_has_type_attr_p (decl, "interrupt")) -+ goto done; -+ -+ /* Skip sibcall if the type can't be found for -+ * some reason */ -+ step++; -+ name = IDENTIFIER_POINTER (DECL_NAME (decl)); -+ type = TREE_TYPE (decl); -+ if (type == NULL) -+ goto done; -+ -+ /* Skip sibcall if the target is a far function */ -+ step++; -+ if (far_function_type_p (type) != NULL) -+ goto done; -+ -+ /* Skip sibcall if the called function's arguments are -+ * variable */ -+ step++; -+ if (TYPE_ARG_TYPES (type) == NULL) -+ goto done; -+ -+ /* Allow sibcalls in other cases. */ -+ result = 1; -+done: -+ /* printf ("%s ok for sibcall? %s, step %d, args %d\n", name, result ? "yes" : "no", step, argcount); */ -+ return result; -+} -+ -+ -+/** Emit code for the 'casesi' pattern. -+ * This pattern is only used in 8-bit mode, and can be disabled -+ * with -mold-case there as well. The rationale for this is to -+ * do a better job than the simpler but well-tested 'tablejump' -+ * method. -+ * -+ * For small jumptables, where the switch expression is an -+ * 8-bit value, the lookup can be done more efficiently -+ * using the "B,X" style index mode. */ -+void -+m6809_do_casesi (rtx index, rtx lower_bound, rtx range, -+ rtx table_label, rtx default_label) -+{ -+ enum machine_mode mode; -+ rtx scaled; -+ rtx table_in_reg; -+ -+ /* expr.c has to be patched so that it does not promote -+ * the expression to SImode, but rather to HImode. -+ * Fail now if that isn't the case. */ -+ if (GET_MODE_SIZE (GET_MODE (index)) > GET_MODE_SIZE (HImode)) -+ error ("try_casesi promotion bug"); -+ -+ /* Determine whether or not we are going to work primarily in -+ * QImode or HImode. This depends on the size of the index -+ * into the lookup table. QImode can only be used when the -+ * index is less than 0x40, since it will be doubled but -+ * must remain unsigned. */ -+ if ((GET_CODE (range) == CONST_INT) && (INTVAL (range) < 0x40)) -+ mode = QImode; -+ else -+ mode = HImode; -+ -+ /* Convert to QImode if necessary */ -+ if (mode == QImode) -+ { -+ index = gen_lowpart_general (mode, index); -+ lower_bound = gen_lowpart_general (mode, lower_bound); -+ } -+ -+ /* Translate from case value to table index by subtraction */ -+ if (lower_bound != const0_rtx) -+ index = expand_binop (mode, sub_optab, index, lower_bound, -+ NULL_RTX, 0, OPTAB_LIB_WIDEN); -+ -+ /* Emit compare-and-jump to test for index out-of-range */ -+ emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, mode, 1, -+ default_label); -+ -+ /* Put the table address is in a register */ -+ table_in_reg = gen_reg_rtx (Pmode); -+ emit_move_insn (table_in_reg, gen_rtx_LABEL_REF (Pmode, table_label)); -+ -+ /* Emit table lookup and jump */ -+ if (mode == QImode) -+ { -+ /* Scale the index */ -+ scaled = gen_reg_rtx (QImode); -+ emit_insn (gen_ashlqi3 (scaled, index, const1_rtx)); -+ -+ /* Emit the jump */ -+ emit_jump_insn (gen_tablejump_short_offset (scaled, table_in_reg)); -+ } -+ else -+ { -+ /* Scale the index */ -+ emit_insn (gen_ashlhi3 (index, index, const1_rtx)); -+ -+ /* Emit the jump */ -+ emit_jump_insn (gen_tablejump_long_offset (index, table_in_reg)); -+ } -+ -+ /* Copied from expr.c */ -+ if (!CASE_VECTOR_PC_RELATIVE && !flag_pic) -+ emit_barrier (); -+} -+ -+ -+/** Output the assembly code for a 32-bit add/subtract. */ -+void -+m6809_output_addsi3 (int rtx_code, rtx *operands) -+{ -+ rtx xoperands[8]; -+ rtx dst = operands[0]; -+ -+ /* Prepare the operands by splitting each SImode into two HImodes -+ that can be operated independently. The high word of operand 1 -+ is further divided into two QImode components for use with 'adc' -+ style instructions. */ -+ xoperands[7] = operands[3]; -+ -+ xoperands[0] = adjust_address (dst, HImode, 2); -+ xoperands[3] = adjust_address (dst, HImode, 0); -+ -+#if 1 -+ xoperands[2] = adjust_address (operands[1], HImode, 2); -+ xoperands[6] = adjust_address (operands[1], HImode, 0); -+ -+ /* Operand 2 may be a MEM or a CONST_INT */ -+ if (GET_CODE (operands[2]) == CONST_INT) -+ { -+ xoperands[1] = gen_int_mode (INTVAL (operands[2]) & 0xFFFF, HImode); -+ xoperands[4] = gen_int_mode ((INTVAL (operands[2]) >> 24) & 0xFF, QImode); -+ xoperands[5] = gen_int_mode ((INTVAL (operands[2]) >> 16) & 0xFF, QImode); -+ } -+ else -+ { -+ xoperands[1] = adjust_address (operands[2], HImode, 2); -+ xoperands[4] = adjust_address (operands[2], QImode, 0); -+ xoperands[5] = adjust_address (operands[2], QImode, 1); -+ } -+ -+#endif -+ -+#if 0 -+ xoperands[1] = adjust_address (operands[1], HImode, 2); -+ xoperands[4] = adjust_address (operands[1], QImode, 0); -+ xoperands[5] = adjust_address (operands[1], QImode, 1); -+ -+ /* Operand 2 may be a MEM or a CONST_INT */ -+ if (GET_CODE (operands[2]) == CONST_INT) -+ { -+ xoperands[2] = gen_int_mode ((INTVAL (operands[2])) & 0xFFFF, HImode); -+ xoperands[6] = gen_int_mode ((INTVAL (operands[2]) >> 16) & 0xFFFF, HImode); -+ } -+ else -+ { -+ xoperands[2] = adjust_address (operands[2], HImode, 2); -+ xoperands[6] = adjust_address (operands[2], HImode, 0); -+ } -+#endif -+ -+ /* Output the assembly code. */ -+ if (rtx_code == PLUS) -+ { -+ output_asm_insn ("ld%7\t%2", xoperands); -+ output_asm_insn ("add%7\t%1", xoperands); -+ output_asm_insn ("st%7\t%0", xoperands); -+ output_asm_insn ("ld%7\t%6", xoperands); -+ output_asm_insn ("adcb\t%5", xoperands); -+ output_asm_insn ("adca\t%4", xoperands); -+ output_asm_insn ("st%7\t%3", xoperands); -+ } -+ else -+ { -+ output_asm_insn ("ld%7\t%2", xoperands); -+ output_asm_insn ("sub%7\t%1", xoperands); -+ output_asm_insn ("st%7\t%0", xoperands); -+ output_asm_insn ("ld%7\t%6", xoperands); -+ output_asm_insn ("sbcb\t%5", xoperands); -+ output_asm_insn ("sbca\t%4", xoperands); -+ output_asm_insn ("st%7\t%3", xoperands); -+ } -+} -+ -+ -+#if 0 -+/** Output the assembly code for a 32-bit shift. -+Operands 0 and 1 must be the same rtx, forced by a matching -+constraint. Operand 2 must be a CONST_INT. Operand 3 is -+"d" in case a temporary reg is needed. */ -+void -+m6809_output_shiftsi3 (int rtx_code, rtx *operands) -+{ -+ unsigned int count = INTVAL (operands[2]) % 32; -+ unsigned int size = 4; /* sizeof (SImode) */ -+ int s; -+ rtx xoperands[4]; -+ int op; -+ int start, end, step; -+ -+ /* Initialize */ -+ if (rtx_code == ASHIFT) -+ { -+ start = size-1; -+ end = -1; -+ step = -1; -+ } -+ else -+ { -+ start = 0; -+ end = size; -+ step = 1; -+ } -+ -+ xoperands[2] = operands[2]; -+ xoperands[3] = operands[3]; -+ -+ if (count <= 0) -+ abort (); -+ if (rtx_code == ROTATE || rtx_code == ROTATERT) -+ abort (); -+ -+ /* Extract bit shifts over 16 bits by HImode moves. */ -+ if (count >= 16) -+ { -+ } -+ -+ /* Extract bit shifts over 8 bits by QImode moves. */ -+ if (count >= 8) -+ { -+ } -+ -+ /* Iterate over the number of bits to be shifted. */ -+ while (count > 0) -+ { -+ /* Each bit to be shifted requires 1 proper bit shift -+ and 3 rotates. */ -+ -+ /* First, do the arithmetic/logical shift. Left shifts -+ start from the LSB; right shifts start from the MSB. */ -+ xoperands[0] = adjust_address (operands[0], QImode, start); -+ switch (rtx_code) -+ { -+ case ASHIFT: -+ output_asm_insn ("asl\t%0", xoperands); -+ start--; -+ break; -+ case ASHIFTRT: -+ output_asm_insn ("asr\t%0", xoperands); -+ start++; -+ break; -+ case LSHIFTRT: -+ output_asm_insn ("lsr\t%0", xoperands); -+ start++; -+ break; -+ } -+ -+ /* Next, rotate the other bytes */ -+ for (s = start; s != end; s += step) -+ { -+ xoperands[0] = adjust_address (operands[0], QImode, s); -+ switch (rtx_code) -+ { -+ case ASHIFT: -+ output_asm_insn ("rol\t%0", xoperands); -+ break; -+ case ASHIFTRT: -+ case LSHIFTRT: -+ output_asm_insn ("ror\t%0", xoperands); -+ break; -+ } -+ } -+ count--; -+ } -+} -+#endif -+ -+int -+power_of_two_p (unsigned int n) -+{ -+ return (n & (n-1)) == 0; -+} -+ -+ -+int -+m6809_can_eliminate (int from, int to) -+{ -+ if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) -+ return !frame_pointer_needed; -+ return 1; -+} -+ -+ -+int -+m6809_initial_elimination_offset (int from, int to) -+{ -+ switch (from) -+ { -+ case ARG_POINTER_REGNUM: -+ return get_frame_size () + m6809_get_regs_size (m6809_get_live_regs ()); -+ case FRAME_POINTER_REGNUM: -+ return get_frame_size (); -+ default: -+ gcc_unreachable (); -+ } -+} -+ -+ -+bool -+m6809_frame_pointer_required (void) -+{ -+ return false; -+} -+ -+ -+/* Defines the target-specific hooks structure. */ -+struct gcc_target targetm = TARGET_INITIALIZER; -diff -urN gcc-4.6.4-clean/gcc/config/m6809/m6809.h gcc-4.6.4/gcc/config/m6809/m6809.h ---- gcc-4.6.4-clean/gcc/config/m6809/m6809.h 1969-12-31 17:00:00.000000000 -0700 -+++ gcc-4.6.4/gcc/config/m6809/m6809.h 2015-07-20 21:56:53.518727644 -0600 -@@ -0,0 +1,1352 @@ -+/* Definitions of target machine for GNU compiler. MC6809 version. -+ -+ MC6809 Version by Tom Jones (jones@sal.wisc.edu) -+ Space Astronomy Laboratory -+ University of Wisconsin at Madison -+ -+ minor changes to adapt it to gcc-2.5.8 by Matthias Doerfel -+ ( msdoerfe@informatik.uni-erlangen.de ) -+ also added #pragma interrupt (inspired by gcc-6811) -+ -+ minor changes to adapt it to gcc-2.8.0 by Eric Botcazou -+ (ebotcazou@multimania.com) -+ -+ minor changes to adapt it to egcs-1.1.2 by Eric Botcazou -+ (ebotcazou@multimania.com) -+ -+ minor changes to adapt it to gcc-2.95.3 by Eric Botcazou -+ (ebotcazou@multimania.com) -+ -+ changes for gcc-3.1.1 by ??? -+ -+ further changes for gcc-3.1.1 and beyond by Brian Dominy -+ (brian@oddchange.com) -+ -+ even more changes for gcc-4.6.1 by William Astle (lost@l-w.ca) -+ -+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 -+<http://www.gnu.org/licenses/>. */ -+ -+ -+/* Helper macros for creating strings with macros */ -+#define C_STRING(x) C_STR(x) -+#define C_STR(x) #x -+ -+/* Certain parts of GCC include host-side includes, which is bad. -+ * Some things that get pulled in need to be undone. -+ */ -+#undef HAVE_GAS_HIDDEN -+ -+/* Names to predefine in the preprocessor for this target machine. */ -+/*#define TARGET_CPU_CPP_BUILTINS() m6809_cpu_cpp_builtins () */ -+#define TARGET_CPU_CPP_BUILTINS() do \ -+ { \ -+ if (TARGET_6309) \ -+ { \ -+ builtin_define_std ("__M6309__"); \ -+ builtin_define_std ("__m6309__"); \ -+ } \ -+ else \ -+ { \ -+ builtin_define_std ("__M6809__"); \ -+ builtin_define_std ("__m6809__"); \ -+ } \ -+ \ -+ if (TARGET_BYTE_INT) \ -+ builtin_define_std ("__int8__"); \ -+ else \ -+ builtin_define_std ("__int16__"); \ -+ \ -+ switch (m6809_abi_version) \ -+ { \ -+ case M6809_ABI_VERSION_STACK: \ -+ builtin_define_std ("__regargs__"); \ -+ builtin_define_std ("__ABI_STACK__"); \ -+ break; \ -+ case M6809_ABI_VERSION_REGS: \ -+ builtin_define_std ("__ABI_REGS__"); \ -+ break; \ -+ case M6809_ABI_VERSION_BX: \ -+ builtin_define_std ("__ABI_BX__"); \ -+ break; \ -+ default: \ -+ break; \ -+ } \ -+ \ -+ if (TARGET_WPC) \ -+ builtin_define_std ("__WPC__"); \ -+ \ -+ if (TARGET_DRET) \ -+ builtin_define_std ("__DRET__"); \ -+ } while (0) -+ -+/* As an embedded target, we have no libc. */ -+#ifndef inhibit_libc -+#define inhibit_libc -+#endif -+ -+/* Print subsidiary information on the compiler version in use. */ -+#define TARGET_VERSION fprintf (stderr, " (MC6809)"); -+ -+/* Run-time compilation parameters selecting different hardware subsets. */ -+/*extern int target_flags; */ -+extern short *reg_renumber; /* def in local_alloc.c */ -+ -+/* Runtime current values of section names */ -+extern int section_changed; -+extern char code_section_op[], data_section_op[], bss_section_op[]; -+ -+#define WARNING_OPT 0, -+/*extern const char *m6809_abi_version_ptr; */ -+extern unsigned int m6809_soft_regs; -+extern unsigned int m6809_abi_version; -+ -+/* ABI versions */ -+ -+#define M6809_ABI_VERSION_STACK 0 -+#define M6809_ABI_VERSION_REGS 1 -+#define M6809_ABI_VERSION_BX 2 -+#define M6809_ABI_VERSION_LATEST (M6809_ABI_VERSION_BX) -+ -+/* Allow $ in identifiers */ -+#define DOLLARS_IN_IDENTIFIERS 1 -+ -+/*-------------------------------------------------------------- -+ Target machine storage layout -+--------------------------------------------------------------*/ -+ -+/* Define this if most significant bit is lowest numbered -+ in instructions that operate on numbered bit-fields. */ -+#define BITS_BIG_ENDIAN 0 -+ -+/* Define to 1 if most significant byte of a word is the lowest numbered. */ -+#define BYTES_BIG_ENDIAN 1 -+ -+/* Define to 1 if most significant word of a multiword value is the lowest numbered. */ -+#define WORDS_BIG_ENDIAN 1 -+ -+/* Number of bits in an addressible storage unit */ -+#define BITS_PER_UNIT 8 -+ -+/* Width in bits of a "word", or the contents of a machine register. -+ * Although the 6809 has a few byte registers, define this to 16-bits -+ * since this is the natural size of most registers. */ -+#define BITS_PER_WORD 16 -+ -+/* Width of a word, in units (bytes). */ -+#define UNITS_PER_WORD (BITS_PER_WORD/8) -+ -+/* Width in bits of a pointer. See also the macro `Pmode' defined below. */ -+#define POINTER_SIZE 16 -+ -+/* Allocation boundary (bits) for storing pointers in memory. */ -+#define POINTER_BOUNDARY 8 -+ -+/* Allocation boundary (bits) for storing arguments in argument list. */ -+/* PARM_BOUNDARY is divided by BITS_PER_WORD in expr.c -- tej */ -+#define PARM_BOUNDARY 8 -+ -+/* Boundary (bits) on which stack pointer should be aligned. */ -+#define STACK_BOUNDARY 8 -+ -+/* Allocation boundary (bits) for the code of a function. */ -+#define FUNCTION_BOUNDARY 8 -+ -+/* Alignment of field after `int : 0' in a structure. */ -+#define EMPTY_FIELD_BOUNDARY 8 -+ -+/* Every structure's size must be a multiple of this. */ -+#define STRUCTURE_SIZE_BOUNDARY 8 -+ -+/* Largest mode size to use when putting an object, including -+ * a structure, into a register. By limiting this to 16, no -+ * 32-bit objects will ever be allocated to a pair of hard -+ * registers. This is a good thing, since there aren't that -+ * many of them. 32-bit objects are only needed for floats -+ * and "long long"s. Larger values have been tried and did not -+ * work. */ -+#define MAX_FIXED_MODE_SIZE 16 -+ -+/* No data type wants to be aligned rounder than this. */ -+#define BIGGEST_ALIGNMENT 8 -+ -+/* Define this if move instructions will actually fail to work -+ when given unaligned data. */ -+#define STRICT_ALIGNMENT 0 -+ -+/*-------------------------------------------------------------- -+ Standard register usage. -+--------------------------------------------------------------*/ -+ -+/* Register values as bitmasks. -+ * TODO : merge D_REGBIT and B_REGBIT, and treat this as the same -+ * register. */ -+#define RSVD1_REGBIT (1 << HARD_RSVD1_REGNUM) -+#define D_REGBIT (1 << HARD_D_REGNUM) -+#define X_REGBIT (1 << HARD_X_REGNUM) -+#define Y_REGBIT (1 << HARD_Y_REGNUM) -+#define U_REGBIT (1 << HARD_U_REGNUM) -+#define S_REGBIT (1 << HARD_S_REGNUM) -+#define PC_REGBIT (1 << HARD_PC_REGNUM) -+#define Z_REGBIT (1 << HARD_Z_REGNUM) -+#define A_REGBIT (1 << HARD_A_REGNUM) -+#define B_REGBIT (1 << HARD_B_REGNUM) -+#define CC_REGBIT (1 << HARD_CC_REGNUM) -+#define DP_REGBIT (1 << HARD_DP_REGNUM) -+#define SOFT_FP_REGBIT (1 << SOFT_FP_REGNUM) -+#define SOFT_AP_REGBIT (1 << SOFT_AP_REGNUM) -+#define M_REGBIT(n) (1 << (SOFT_M0_REGNUM + n)) -+ -+/* Macros for dealing with set of registers. -+ * A register set is just a bitwise-OR of all the register -+ * bitmask values. */ -+ -+/* Which registers can hold 8-bits */ -+#define BYTE_REGSET \ -+ (Z_REGBIT | A_REGBIT | D_REGBIT | CC_REGBIT | DP_REGBIT) -+ -+/* Which registers can hold 16-bits. -+ * Note: D_REGBIT is defined as both an 8-bit and 16-bit register */ -+#define WORD_REGSET \ -+ (D_REGBIT | X_REGBIT | Y_REGBIT | U_REGBIT | S_REGBIT | PC_REGBIT | SOFT_FP_REGBIT | SOFT_AP_REGBIT | RSVD1_REGBIT) -+ -+/* Returns nonzero if a given REGNO is in the REGSET. */ -+#define REGSET_CONTAINS_P(regno, regset) (((1 << (regno)) & (regset)) != 0) -+ -+/* Defines related to the number of soft registers supported. -+ * The actual number used may be less depending on -msoft-reg-count. -+ * If you change one of these, you should change them all. */ -+#define NUM_M_REGS 8 -+#define M_REGS_FIXED 1, 1, 1, 1, 1, 1, 1, 1 -+#define M_REGS_CALL_USED 1, 1, 1, 1, 1, 1, 1, 1 -+#define HARD_M_REGNUMS \ -+ SOFT_M0_REGNUM+0, SOFT_M0_REGNUM+1, SOFT_M0_REGNUM+2, SOFT_M0_REGNUM+3, \ -+ SOFT_M0_REGNUM+4, SOFT_M0_REGNUM+5, SOFT_M0_REGNUM+6, SOFT_M0_REGNUM+7 -+ -+#define SOFT_M_REGBITS (((1UL << NUM_M_REGS) - 1) << (SOFT_M0_REGNUM)) -+ -+/* Number of actual hardware registers. -+ The hardware registers are assigned numbers for the compiler -+ from 0 to just below FIRST_PSEUDO_REGISTER. -+ All registers that the compiler knows about must be given numbers, -+ even those that are not normally considered general registers. -+ Make sure the constant below matches the value of SOFT_M0_REGNUM; -+ for some reason, GCC won't compile if that name is used here directly. */ -+#ifdef SOFT_M0_REGNUM -+#if (SOFT_M0_REGNUM != 14) -+#error "bad register numbering" -+#endif -+#endif -+#define FIRST_PSEUDO_REGISTER (14 + NUM_M_REGS) -+ -+/* 1 for registers that have pervasive standard uses -+ and are not available for the register allocator. -+ The psuedoregisters (M_REGS) are declared fixed here, but -+ will be unfixed if -msoft-reg-count is seen later. */ -+#define FIXED_REGISTERS \ -+ {1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, M_REGS_FIXED, } -+ /* -, X, Y, U, S, PC,D, Z, A, B, C, DP,FP,AP,M... */ -+ -+/* 1 for registers not available across function calls. -+ These must include the FIXED_REGISTERS and also any -+ registers that can be used without being saved. -+ The latter must include the registers where values are returned -+ and the register where structure-value addresses are passed. -+ Aside from that, you can include as many other registers as you like. */ -+#define CALL_USED_REGISTERS \ -+ {1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, M_REGS_CALL_USED, } -+ /* -, X, Y, U, S, PC,D, Z, A, B, C, DP,FP,AP,M... */ -+ -+/* Return number of consecutive hard regs needed starting at reg REGNO -+ to hold something of mode MODE. -+ For the 6809, we distinguish between word-length and byte-length -+ registers. */ -+#define HARD_REGNO_NREGS(REGNO, MODE) \ -+ (REGSET_CONTAINS_P (REGNO, WORD_REGSET) ? \ -+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) : \ -+ (GET_MODE_SIZE (MODE))) -+ -+ -+/* Value is 1 if hard register REGNO can hold a value -+of machine-mode MODE. */ -+#define HARD_REGNO_MODE_OK(REGNO, MODE) m6809_hard_regno_mode_ok (REGNO, MODE) -+ -+/* Value is 1 if it is a good idea to tie two pseudo registers -+ when one has mode MODE1 and one has mode MODE2. -+ If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, -+ for any hard reg, then this must be 0 for correct output. */ -+#define MODES_TIEABLE_P(MODE1, MODE2) 0 -+ -+/* Specify the registers used for certain standard purposes. -+ The values of these macros are register numbers. */ -+ -+/* program counter if referenced as a register */ -+#define PC_REGNUM HARD_PC_REGNUM -+ -+/* Register to use for pushing function arguments. */ -+#define STACK_POINTER_REGNUM HARD_S_REGNUM -+ -+/* Base register for access to local variables of the function. -+ * Before reload, FRAME_POINTER_REGNUM will be used. Later, -+ * the elimination pass will convert these to STACK_POINTER_REGNUM -+ * if possible, or else HARD_FRAME_POINTER_REGNUM. The idea is to -+ * avoid tying up a hard register (U) for the frame pointer if -+ * it can be eliminated entirely, making it available for use as -+ * a general register. */ -+#define FRAME_POINTER_REGNUM SOFT_FP_REGNUM -+#define HARD_FRAME_POINTER_REGNUM HARD_U_REGNUM -+ -+/* Define a table of possible eliminations. -+ * The idea is to try to avoid using hard registers for the argument -+ * and frame pointers if they can be derived from the stack pointer -+ * instead, which already has a hard register reserved for it. -+ * -+ * The order of entries in this table will try to convert -+ * ARG_POINTER_REGNUM and FRAME_POINTER_REGNUM into stack pointer -+ * references first, but if that fails, they will be converted to use -+ * HARD_FRAME_POINTER_REGNUM. -+ */ -+#define ELIMINABLE_REGS \ -+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ -+ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }, \ -+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ -+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }} -+ -+/* #define CAN_ELIMINATE(FROM, TO) m6809_can_eliminate (FROM, TO) */ -+ -+/* Define how to offset the frame or argument pointer to turn it -+ * into a stack pointer reference. This is based on the way that -+ * the frame is constructed in the function prologue. */ -+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ -+ (OFFSET) = m6809_initial_elimination_offset (FROM, TO) -+ -+/* Base register for access to arguments of the function. -+ * This is only used prior to reload; no instructions will ever -+ * be output referring to this register. */ -+#define ARG_POINTER_REGNUM SOFT_AP_REGNUM -+ -+/* Register in which static-chain is passed to a function. */ -+#define STATIC_CHAIN_REGNUM HARD_Y_REGNUM -+ -+/* #define CONDITIONAL_REGISTER_USAGE (m6809_conditional_register_usage ()) */ -+ -+/* Order in which hard registers are allocated to pseudos. -+ * -+ * Since the D register is the only valid reg for 8-bit values -+ * now, avoid using it for 16-bit values by putting it after all -+ * other 16-bits. -+ * -+ * Prefer X first since the first 16-bit function argument goes -+ * there. We may be able to pass in to a subroutine without -+ * a copy. -+ * -+ * Prefer U over Y since instructions using Y take one extra -+ * byte, and thus one extra cycle to execute. -+ */ -+#define REG_ALLOC_ORDER \ -+ { HARD_X_REGNUM, HARD_U_REGNUM, HARD_Y_REGNUM, HARD_D_REGNUM, \ -+ HARD_M_REGNUMS, HARD_S_REGNUM, HARD_PC_REGNUM, \ -+ HARD_B_REGNUM, HARD_A_REGNUM, HARD_CC_REGNUM, \ -+ HARD_DP_REGNUM, SOFT_FP_REGNUM, SOFT_AP_REGNUM, \ -+ 6, HARD_Z_REGNUM } -+ -+/*-------------------------------------------------------------- -+ classes of registers -+--------------------------------------------------------------*/ -+ -+/* Define the classes of registers for register constraints in the -+ machine description. Also define ranges of constants. -+ -+ One of the classes must always be named ALL_REGS and include all hard regs. -+ If there is more than one class, another class must be named NO_REGS -+ and contain no registers. -+ -+ The name GENERAL_REGS must be the name of a class (or an alias for -+ another name such as ALL_REGS). This is the class of registers -+ that is allowed by "g" or "r" in a register constraint. -+ Also, registers outside this class are allocated only when -+ instructions express preferences for them. -+ -+ The classes must be numbered in nondecreasing order; that is, -+ a larger-numbered class must never be contained completely -+ in a smaller-numbered class. -+ -+ For any two classes, it is very desirable that there be another -+ class that represents their union. */ -+ -+enum reg_class { -+ NO_REGS, /* The trivial class with no registers in it */ -+ D_REGS, /* 16-bit (word (HI)) data (D) */ -+ ACC_A_REGS, /* The A register */ -+ ACC_B_REGS, /* The B register */ -+ X_REGS, /* The X register */ -+ Z_REGS, /* The Z (zero-bit) register */ -+ Q_REGS, /* 8-bit (byte (QI)) data (A,B) */ -+ M_REGS, /* 8-bit (byte (QI)) soft registers */ -+ CC_REGS, /* 8-bit condition code register */ -+ I_REGS, /* An index register (A,B,D) */ -+ T_REGS, /* 16-bit addresses, not including stack or PC (X,Y,U) */ -+ A_REGS, /* 16-bit addresses (X,Y,U,S,PC) */ -+ S_REGS, /* 16-bit soft registers (FP, AP) */ -+ P_REGS, /* 16-bit pushable registers (D,X,Y,U); omit PC and S */ -+ G_REGS, /* 16-bit data and address (D,X,Y,U,S,PC) */ -+ ALL_REGS, /* All registers */ -+ LIM_REG_CLASSES -+}; -+ -+#define N_REG_CLASSES (int) LIM_REG_CLASSES -+ -+/* Since GENERAL_REGS is a smaller class than ALL_REGS, -+ it is not an alias to ALL_REGS, but to G_REGS. */ -+#define GENERAL_REGS G_REGS -+ -+/* Give names of register classes as strings for dump file. */ -+#define REG_CLASS_NAMES \ -+ { "NO_REGS", "D_REGS", "ACC_A_REGS", "ACC_B_REGS", "X_REGS", "Z_REGS", "Q_REGS", "M_REGS", \ -+ "CC_REGS", "I_REGS", "T_REGS", "A_REGS", "S_REGS", "P_REGS", "G_REGS", \ -+ "ALL_REGS" } -+ -+/* Define which registers fit in which classes. -+ This is an initializer for a vector of HARD_REG_SET -+ of length N_REG_CLASSES. */ -+ -+#define D_REGSET (D_REGBIT) -+#define ACC_A_REGSET (A_REGBIT) -+#define ACC_B_REGSET (D_REGBIT) -+#define X_REGSET (X_REGBIT) -+#define Z_REGSET (Z_REGBIT) -+#define Q_REGSET (D_REGBIT | A_REGBIT) -+#define M_REGSET (SOFT_M_REGBITS) -+#define CC_REGSET (CC_REGBIT) -+#define I_REGSET (A_REGBIT | B_REGBIT | D_REGBIT) -+#define T_REGSET (X_REGBIT | Y_REGBIT | U_REGBIT) -+#define A_REGSET (X_REGBIT | Y_REGBIT | U_REGBIT | S_REGBIT | PC_REGBIT) -+#define S_REGSET (SOFT_FP_REGBIT | SOFT_AP_REGBIT) -+#define P_REGSET (D_REGBIT | X_REGBIT | Y_REGBIT | U_REGBIT) -+#define G_REGSET \ -+ (D_REGSET | Q_REGSET | I_REGSET | A_REGSET | M_REGSET | S_REGSET) -+#define ALL_REGSET (G_REGSET) -+ -+#define REG_CLASS_CONTENTS { \ -+ {0}, \ -+ {D_REGSET}, \ -+ {ACC_A_REGSET}, \ -+ {ACC_B_REGSET}, \ -+ {X_REGSET}, \ -+ {Z_REGSET}, \ -+ {Q_REGSET}, \ -+ {M_REGSET}, \ -+ {CC_REGSET}, \ -+ {I_REGSET}, \ -+ {T_REGSET}, \ -+ {A_REGSET}, \ -+ {S_REGSET}, \ -+ {P_REGSET}, \ -+ {G_REGSET}, \ -+ {ALL_REGSET}, \ -+} -+ -+/* The same information, inverted. -+ * This is defined to use the REG_CLASS_CONTENTS defines above, so that -+ * these two sets of definitions are always consistent. */ -+ -+#define REGNO_REG_CLASS(REGNO) \ -+ (D_REGNO_P (REGNO) ? D_REGS : \ -+ (Z_REGNO_P (REGNO) ? Z_REGS : \ -+ (ACC_A_REGNO_P (REGNO) ? ACC_A_REGS : \ -+ (ACC_B_REGNO_P (REGNO) ? ACC_B_REGS : \ -+ (X_REGNO_P (REGNO) ? X_REGS : \ -+ (Q_REGNO_P (REGNO) ? Q_REGS : \ -+ (M_REGNO_P (REGNO) ? M_REGS : \ -+ (CC_REGNO_P (REGNO) ? CC_REGS : \ -+ (I_REGNO_P (REGNO) ? I_REGS : \ -+ (T_REGNO_P (REGNO) ? T_REGS : \ -+ (A_REGNO_P (REGNO) ? A_REGS : \ -+ (S_REGNO_P (REGNO) ? S_REGS : \ -+ (P_REGNO_P (REGNO) ? P_REGS : \ -+ (G_REGNO_P (REGNO) ? G_REGS : ALL_REGS)))))))))))))) -+ -+#define D_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, D_REGSET)) -+#define ACC_A_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, ACC_A_REGSET)) -+#define ACC_B_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, ACC_B_REGSET)) -+#define X_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, X_REGSET)) -+#define Z_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, Z_REGSET)) -+#define Q_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, Q_REGSET)) -+#define M_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, M_REGSET)) -+#define CC_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, CC_REGSET)) -+#define I_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, I_REGSET)) -+#define T_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, T_REGSET)) -+#define A_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, A_REGSET)) -+#define S_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, S_REGSET)) -+#define P_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, P_REGSET)) -+#define G_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, G_REGSET)) -+ -+/* Macros that test an rtx 'X' to see if it's in a particular -+ * register class. 'X' need not be a REG necessarily. */ -+ -+#define D_REG_P(X) (REG_P (X) && D_REGNO_P (REGNO (X))) -+#define ACC_A_REG_P(X) (REG_P (X) && ACC_A_REGNO_P (REGNO (X))) -+#define ACC_B_REG_P(X) (REG_P (X) && ACC_B_REGNO_P (REGNO (X))) -+#define X_REG_P(X) (REG_P (X) && X_REGNO_P (REGNO (X))) -+#define Z_REG_P(X) (REG_P (X) && Z_REGNO_P (REGNO (X))) -+#define I_REG_P(X) (REG_P (X) && I_REGNO_P (REGNO (X))) -+#define T_REG_P(X) (REG_P (X) && T_REGNO_P (REGNO (X))) -+#define A_REG_P(X) (REG_P (X) && A_REGNO_P (REGNO (X))) -+#define S_REG_P(X) (REG_P (X) && S_REGNO_P (REGNO (X))) -+#define P_REG_P(X) (REG_P (X) && P_REGNO_P (REGNO (X))) -+#define Q_REG_P(X) (REG_P (X) && Q_REGNO_P (REGNO (X))) -+#define M_REG_P(X) (REG_P (X) && M_REGNO_P (REGNO (X))) -+#define CC_REG_P(X) (REG_P (X) && CC_REGNO_P (REGNO (X))) -+ -+/* Redefine this in terms of BYTE_REGSET */ -+#define BYTE_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, BYTE_REGSET)) -+ -+/* The class value for index registers, and the one for base regs. */ -+#define INDEX_REG_CLASS I_REGS -+#define BASE_REG_CLASS A_REGS -+ -+/* Get reg_class from a letter in the machine description. */ -+#define REG_CLASS_FROM_LETTER(C) \ -+ (((C) == 'a' ? A_REGS : \ -+ ((C) == 'd' ? D_REGS : \ -+ ((C) == 'x' ? I_REGS : \ -+ ((C) == 't' ? M_REGS : \ -+ ((C) == 'c' ? CC_REGS : \ -+ ((C) == 'A' ? ACC_A_REGS : \ -+ ((C) == 'B' ? ACC_B_REGS : \ -+ ((C) == 'v' ? X_REGS : \ -+ ((C) == 'u' ? S_REGS : \ -+ ((C) == 'U' ? P_REGS : \ -+ ((C) == 'T' ? T_REGS : \ -+ ((C) == 'z' ? Z_REGS : \ -+ ((C) == 'q' ? Q_REGS : NO_REGS)))))))))))))) -+ -+/*-------------------------------------------------------------- -+ The letters I through O in a register constraint string -+ can be used to stand for particular ranges of immediate operands. -+ This macro defines what the ranges are. -+ C is the letter, and VALUE is a constant value. -+ Return 1 if VALUE is in the range specified by C. -+ -+ For the 6809, J, K, L are used for indexed addressing. -+ `I' is used for the constant 1. -+ `J' is used for the 5-bit offsets. -+ `K' is used for the 8-bit offsets. -+ `L' is used for the range of signed numbers that fit in 16 bits. -+ `M' is used for the exact value '8'. -+ `N' is used for the constant -1. -+ `O' is used for the constant 0. -+--------------------------------------------------------------*/ -+ -+#define CONST_OK_FOR_LETTER_P(VALUE, C) \ -+ ((C) == 'I' ? ((VALUE) == 1) : \ -+ (C) == 'J' ? ((VALUE) >= -16 && (VALUE) <= 15) : \ -+ (C) == 'K' ? ((VALUE) >= -128 && (VALUE) <= 127) : \ -+ (C) == 'L' ? ((VALUE) >= -32768 && (VALUE) <= 32767) : \ -+ (C) == 'M' ? ((VALUE) == 8) : \ -+ (C) == 'N' ? ((VALUE) == -1) : \ -+ (C) == 'O' ? ((VALUE) == 0) : 0) -+ -+/* Similar, but for floating constants, and defining letters G and H. -+ No floating-point constants are valid on MC6809. */ -+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ -+ ((C) == 'G' ? (GET_MODE_CLASS (GET_MODE (VALUE)) == MODE_FLOAT \ -+ && VALUE == CONST0_RTX (GET_MODE (VALUE))) : 0) -+ -+/* Given an rtx X being reloaded into a reg required to be -+ in class CLASS, return the class of reg to actually use. -+ In general this is just CLASS; but on some machines -+ in some cases it is preferable to use a more restrictive class. */ -+#define PREFERRED_RELOAD_CLASS(X,CLASS) m6809_preferred_reload_class(X,CLASS) -+ -+#define SMALL_REGISTER_CLASSES 1 -+ -+/* Return the maximum number of consecutive registers -+ needed to represent mode MODE in a register of class CLASS. */ -+#define CLASS_MAX_NREGS(CLASS, MODE) \ -+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) -+ -+/*-------------------------------------------------------------- -+ Stack layout; function entry, exit and calling. -+--------------------------------------------------------------*/ -+ -+/* Define this if pushing a word on the stack -+ makes the stack pointer a smaller address. */ -+#define STACK_GROWS_DOWNWARD -+ -+ -+/* Define this if the nominal address of the stack frame -+ is at the high-address end of the local variables; -+ that is, each additional local variable allocated -+ goes at a more negative offset in the frame. */ -+#define FRAME_GROWS_DOWNWARD 1 -+ -+ -+/* Offset within stack frame to start allocating local variables at. -+ If FRAME_GROWS_DOWNWARD, this is the offset to the END of the -+ first local allocated. Otherwise, it is the offset to the BEGINNING -+ of the first local allocated. */ -+#define STARTING_FRAME_OFFSET 0 -+ -+ -+/* Always push stack arguments for now. Accumulation is not yet working. */ -+#define PUSH_ROUNDING(BYTES) (BYTES) -+ -+ -+/* Offset of first parameter from the argument pointer register value. -+ * ARG_POINTER_REGNUM is defined to point to the return address pushed -+ * onto the stack, so we must offset by 2 bytes to get to the arguments. */ -+#define FIRST_PARM_OFFSET(FNDECL) 2 -+ -+/* Value is 1 if returning from a function call automatically -+ pops the arguments described by the number-of-args field in the call. -+ FUNTYPE is the data type of the function (as a tree), -+ or for a library call it is an identifier node for the subroutine name. */ -+/* #define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 */ -+ -+/* Define how to find the value returned by a function. -+ VALTYPE is the data type of the value (as a tree). -+ If the precise function being called is known, FUNC is its FUNCTION_DECL; -+ otherwise, FUNC is 0. */ -+#define FUNCTION_VALUE(VALTYPE, FUNC) m6809_function_value (VALTYPE, FUNC) -+ -+/* Define how to find the value returned by a library function -+ assuming the value has mode MODE. */ -+ -+/* All return values are in the X-register. */ -+#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, HARD_X_REGNUM) -+ -+/* Define this if using the nonreentrant convention for returning -+ structure and union values. No; it is inefficient and buggy. */ -+#undef PCC_STATIC_STRUCT_RETURN -+ -+/* 1 if N is a possible register number for a function value. */ -+#define FUNCTION_VALUE_REGNO_P(N) m6809_function_value_regno_p (N) -+ -+/* Define this to be true when FUNCTION_VALUE_REGNO_P is true for -+ more than one register. */ -+#define NEEDS_UNTYPED_CALL 1 -+ -+/* 1 if N is a possible register number for function argument passing. */ -+#define FUNCTION_ARG_REGNO_P(N) \ -+ ((m6809_abi_version != M6809_ABI_VERSION_STACK) ? \ -+ (((N) == HARD_D_REGNUM) || ((N) == HARD_X_REGNUM)) : \ -+ 0) -+ -+/*-------------------------------------------------------------- -+ Argument Lists -+--------------------------------------------------------------*/ -+ -+/* Cumulative arguments are tracked in a single integer, -+ * which is the number of bytes of arguments scanned so far, -+ * plus which registers have already been used. The register -+ * info is kept in some of the upper bits */ -+#define CUMULATIVE_ARGS unsigned int -+ -+#define CUM_STACK_ONLY 0x80000000 -+#define CUM_X_MASK 0x40000000 -+#define CUM_B_MASK 0x20000000 -+#define CUM_STACK_INVALID 0x10000000 -+#define CUM_STACK_MASK 0xFFFFFFF -+ -+#define CUM_ADVANCE_8BIT(cum) \ -+ (((cum) & CUM_B_MASK) ? (cum)++ : ((cum) |= CUM_B_MASK)) -+ -+#define CUM_ADVANCE_16BIT(cum) \ -+ (((cum) & CUM_X_MASK) ? (cum) += 2 : ((cum) |= CUM_X_MASK)) -+ -+/* Initialize a variable CUM of type CUMULATIVE_ARGS -+ for a call to a function whose data type is FNTYPE. -+ For a library call, FNTYPE is 0. -+ N_NAMED was added in gcc 3.4 and is not used currently. */ -+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT,N_NAMED) \ -+ ((CUM) = m6809_init_cumulative_args (CUM, FNTYPE, LIBNAME)) -+ -+#define FUNCTION_ARG_SIZE(MODE, TYPE) \ -+ ((MODE) != BLKmode ? GET_MODE_SIZE (MODE) \ -+ : (unsigned) int_size_in_bytes (TYPE)) -+ -+/* Update the data in CUM to advance over an argument -+ of mode MODE and data type TYPE. -+ (TYPE is null for libcalls where that information may not be available.) */ -+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ -+ (((MODE == QImode) && !((CUM) & CUM_STACK_ONLY)) ? \ -+ CUM_ADVANCE_8BIT (CUM) : \ -+ ((MODE == HImode) && !((CUM) & CUM_STACK_ONLY)) ? \ -+ CUM_ADVANCE_16BIT (CUM) : \ -+ ((CUM) = ((CUM) + (TYPE ? int_size_in_bytes (TYPE) : 2)))) -+ -+/* Define where to put the arguments to a function. -+ Value is zero to push the argument on the stack, -+ or a hard register rtx in which to store the argument. -+ This macro is used _before_ FUNCTION_ARG_ADVANCE. -+ -+ For the 6809, the first 8-bit function argument can be placed into B, -+ and the first 16-bit arg can go into X. All other arguments -+ will be pushed onto the stack. -+ -+ Command-line options can adjust this behavior somewhat. -+ */ -+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ -+ ((MODE == VOIDmode) ? NULL_RTX : \ -+ ((MODE == BLKmode) || (GET_MODE_SIZE (MODE) > 2)) ? NULL_RTX : \ -+ ((MODE == QImode) && !((CUM) & (CUM_STACK_ONLY | CUM_B_MASK))) ? \ -+ gen_rtx_REG (QImode, HARD_D_REGNUM) : \ -+ ((MODE == HImode) && !((CUM) & (CUM_STACK_ONLY | CUM_X_MASK))) ? \ -+ gen_rtx_REG (HImode, HARD_X_REGNUM) : m6809_function_arg_on_stack (&CUM)) -+ -+/* Output assembler code to FILE to increment profiler label # LABELNO -+ for profiling a function entry. */ -+#define FUNCTION_PROFILER(FILE, LABELNO) \ -+ fprintf (FILE, "\tldd\t#LP%u\n\tjsr\tmcount\n", (LABELNO)); -+ -+/* Stack pointer must be correct on function exit */ -+#define EXIT_IGNORE_STACK 0 -+ -+/***************************************************************************** -+** -+** Trampolines for Nested Functions -+** -+*****************************************************************************/ -+ -+/* Length in units of the trampoline for entering a nested function. */ -+#define TRAMPOLINE_SIZE 7 -+ -+/*-------------------------------------------------------------- -+ Addressing modes, -+ and classification of registers for them. -+--------------------------------------------------------------*/ -+ -+/* 6809 has postincrement and predecrement addressing modes */ -+#define HAVE_POST_INCREMENT 1 -+#define HAVE_PRE_DECREMENT 1 -+ -+/* Whether or not to use index registers is configurable. -+ * Experiments show that things work better when this is off, so -+ * that's the way it is for now. */ -+#undef USE_INDEX_REGISTERS -+ -+ -+/* Macros to check register numbers against specific register classes. */ -+#define REG_VALID_FOR_BASE_P(REGNO) \ -+ (((REGNO) < FIRST_PSEUDO_REGISTER) && A_REGNO_P (REGNO)) -+ -+/* MC6809 index registers do not allow scaling, */ -+/* but there is "accumulator-offset" mode. */ -+#ifdef USE_INDEX_REGISTERS -+#define REG_VALID_FOR_INDEX_P(REGNO) \ -+ (((REGNO) < FIRST_PSEUDO_REGISTER) && I_REGNO_P (REGNO)) -+#else -+#define REG_VALID_FOR_INDEX_P(REGNO) 0 -+#endif -+ -+/* Internal macro, the nonstrict definition for REGNO_OK_FOR_BASE_P */ -+#define REGNO_OK_FOR_BASE_NONSTRICT_P(REGNO) \ -+ ((REGNO) >= FIRST_PSEUDO_REGISTER \ -+ || REG_VALID_FOR_BASE_P (REGNO) \ -+ || (REGNO) == FRAME_POINTER_REGNUM \ -+ || (REGNO) == HARD_FRAME_POINTER_REGNUM \ -+ || (REGNO) == ARG_POINTER_REGNUM \ -+ || (reg_renumber && REG_VALID_FOR_BASE_P (reg_renumber[REGNO]))) -+ -+/* Internal macro, the nonstrict definition for REGNO_OK_FOR_INDEX_P */ -+#define REGNO_OK_FOR_INDEX_NONSTRICT_P(REGNO) \ -+ ((REGNO) >= FIRST_PSEUDO_REGISTER \ -+ || REG_VALID_FOR_INDEX_P (REGNO) \ -+ || (reg_renumber && REG_VALID_FOR_INDEX_P (reg_renumber[REGNO]))) -+ -+ -+/* Internal macro, the strict definition for REGNO_OK_FOR_BASE_P */ -+#define REGNO_OK_FOR_BASE_STRICT_P(REGNO) \ -+ ((REGNO) < FIRST_PSEUDO_REGISTER ? REG_VALID_FOR_BASE_P (REGNO) \ -+ : (reg_renumber && REG_VALID_FOR_BASE_P (reg_renumber[REGNO]))) -+ -+ -+/* Internal macro, the strict definition for REGNO_OK_FOR_INDEX_P */ -+#define REGNO_OK_FOR_INDEX_STRICT_P(REGNO) \ -+ ((REGNO) < FIRST_PSEUDO_REGISTER ? REG_VALID_FOR_INDEX_P (REGNO) \ -+ : (reg_renumber && REG_VALID_FOR_INDEX_P (reg_renumber[REGNO]))) -+ -+ -+#define REGNO_OK_FOR_BASE_P(REGNO) REGNO_OK_FOR_BASE_STRICT_P (REGNO) -+ -+#define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_INDEX_STRICT_P (REGNO) -+ -+#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_STRICT_P (REGNO (X)) -+#define REG_OK_FOR_BASE_NONSTRICT_P(X) REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (X)) -+#define REG_OK_FOR_INDEX_STRICT_P(X) REGNO_OK_FOR_INDEX_STRICT_P (REGNO (X)) -+#define REG_OK_FOR_INDEX_NONSTRICT_P(X) REGNO_OK_FOR_INDEX_NONSTRICT_P (REGNO (X)) -+ -+#ifndef REG_OK_STRICT -+#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NONSTRICT_P(X) -+#ifdef USE_INDEX_REGISTERS -+#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_NONSTRICT_P(X) -+#else -+#define REG_OK_FOR_INDEX_P(X) 0 -+#endif -+#else -+#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P (X) -+#ifdef USE_INDEX_REGISTERS -+#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_STRICT_P (X) -+#else -+#define REG_OK_FOR_INDEX_P(X) 0 -+#endif -+#endif -+ -+/* Maximum number of registers that can appear in a valid memory address */ -+#ifdef USE_INDEX_REGISTERS -+#define MAX_REGS_PER_ADDRESS 2 -+#else -+#define MAX_REGS_PER_ADDRESS 1 -+#endif -+ -+/* 1 if X is an rtx for a constant that is a valid address. -+ * We allow any constant, plus the sum of any two constants (this allows -+ * offsetting a symbol ref) */ -+#define CONSTANT_ADDRESS_P(X) \ -+ ((CONSTANT_P (X)) \ -+ || ((GET_CODE (X) == PLUS) \ -+ && (CONSTANT_P (XEXP (X, 0))) && (CONSTANT_P (XEXP (X, 1))))) -+ -+/* Nonzero if the constant value X is a legitimate general operand. -+ It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ -+/* Any single-word constant is ok; the only contexts -+ allowing general_operand of mode DI or DF are movdi and movdf. */ -+#define LEGITIMATE_CONSTANT_P(X) (GET_CODE (X) != CONST_DOUBLE) -+ -+/* Nonzero if the X is a legitimate immediate operand in PIC mode. */ -+#define LEGITIMATE_PIC_OPERAND_P(X) !symbolic_operand (X, VOIDmode) -+ -+/*-------------------------------------------------------------- -+ Test for valid memory addresses -+--------------------------------------------------------------*/ -+/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression -+ that is a valid memory address for an instruction. -+ The MODE argument is the machine mode for the MEM expression -+ that wants to use this address. */ -+ -+/*-------------------------------------------------------------- -+ Valid addresses are either direct or indirect (MEM) versions -+ of the following forms. -+ constant N -+ register ,X -+ constant indexed N,X -+ accumulator indexed D,X -+ auto_increment ,X++ -+ auto_decrement ,--X -+--------------------------------------------------------------*/ -+ -+#define REGISTER_ADDRESS_P(X) \ -+ (REG_P (X) && REG_OK_FOR_BASE_P (X)) -+ -+#define EXTENDED_ADDRESS_P(X) \ -+ CONSTANT_ADDRESS_P (X) \ -+ -+#define LEGITIMATE_BASE_P(X) \ -+ ((REG_P (X) && REG_OK_FOR_BASE_P (X)) \ -+ || (GET_CODE (X) == SIGN_EXTEND \ -+ && GET_CODE (XEXP (X, 0)) == REG \ -+ && GET_MODE (XEXP (X, 0)) == HImode \ -+ && REG_OK_FOR_BASE_P (XEXP (X, 0)))) -+ -+#define LEGITIMATE_OFFSET_P(X) \ -+ (CONSTANT_ADDRESS_P (X) || (REG_P (X) && REG_OK_FOR_INDEX_P (X))) -+ -+/* 1 if X is the sum of a base register and an offset. */ -+#define INDEXED_ADDRESS(X) \ -+ ((GET_CODE (X) == PLUS \ -+ && LEGITIMATE_BASE_P (XEXP (X, 0)) \ -+ && LEGITIMATE_OFFSET_P (XEXP (X, 1))) \ -+ || (GET_CODE (X) == PLUS \ -+ && LEGITIMATE_BASE_P (XEXP (X, 1)) \ -+ && LEGITIMATE_OFFSET_P (XEXP (X, 0)))) -+ -+#define STACK_REG_P(X) (REG_P(X) && REGNO(X) == HARD_S_REGNUM) -+ -+#define STACK_PUSH_P(X) \ -+ (MEM_P (X) && GET_CODE (XEXP (X, 0)) == PRE_DEC && STACK_REG_P (XEXP (XEXP (X, 0), 0))) -+ -+#define STACK_POP_P(X) \ -+ (MEM_P (X) && GET_CODE (XEXP (X, 0)) == POST_INC && STACK_REG_P (XEXP (XEXP (X, 0), 0))) -+ -+#define PUSH_POP_ADDRESS_P(X) \ -+ (((GET_CODE (X) == PRE_DEC) || (GET_CODE (X) == POST_INC)) \ -+ && (LEGITIMATE_BASE_P (XEXP (X, 0)))) -+ -+/* Go to ADDR if X is a valid address. */ -+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ -+{ \ -+ if (REGISTER_ADDRESS_P(X)) goto ADDR; \ -+ if (PUSH_POP_ADDRESS_P (X)) goto ADDR; \ -+ if (EXTENDED_ADDRESS_P (X)) goto ADDR; \ -+ if (INDEXED_ADDRESS (X)) goto ADDR; \ -+ if (MEM_P (X) && REGISTER_ADDRESS_P(XEXP (X, 0))) goto ADDR; \ -+ if (MEM_P (X) && PUSH_POP_ADDRESS_P (XEXP (X, 0))) goto ADDR; \ -+ if (MEM_P (X) && EXTENDED_ADDRESS_P (XEXP (X, 0))) goto ADDR; \ -+ if (MEM_P (X) && INDEXED_ADDRESS (XEXP (X, 0))) goto ADDR; \ -+} -+ -+/*-------------------------------------------------------------- -+ Address Fix-up -+--------------------------------------------------------------*/ -+/* Go to LABEL if ADDR (a legitimate address expression) -+ has an effect that depends on the machine mode it is used for. -+ In the latest GCC, this case is already handled by the core code -+ so no action is required here. */ -+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) {} -+ -+ -+/*-------------------------------------------------------------- -+ Miscellaneous Parameters -+--------------------------------------------------------------*/ -+/* Specify the machine mode that this machine uses -+ for the index in the tablejump instruction. */ -+#define CASE_VECTOR_MODE Pmode -+ -+/* Define this as 1 if `char' should by default be signed; else as 0. */ -+#define DEFAULT_SIGNED_CHAR 0 -+ -+/* This flag, if defined, says the same insns that convert to a signed fixnum -+ also convert validly to an unsigned one. */ -+#define FIXUNS_TRUNC_LIKE_FIX_TRUNC -+ -+/* Max number of bytes we can move from memory to memory/register -+ in one reasonably fast instruction. */ -+#define MOVE_MAX 2 -+ -+/* Int can be 8 or 16 bits (default is 16) */ -+#define INT_TYPE_SIZE (TARGET_BYTE_INT ? 8 : 16) -+ -+/* Short is always 16 bits */ -+#define SHORT_TYPE_SIZE (TARGET_BYTE_INT ? 8 : 16) -+ -+/* Size (bits) of the type "long" on target machine */ -+#define LONG_TYPE_SIZE (TARGET_BYTE_INT ? 16 : 32) -+ -+/* Size (bits) of the type "long long" on target machine */ -+#define LONG_LONG_TYPE_SIZE 32 -+ -+/* Size (bits) of the type "char" on target machine */ -+#define CHAR_TYPE_SIZE 8 -+ -+/* Size (bits) of the type "float" on target machine */ -+#define FLOAT_TYPE_SIZE 32 -+ -+/* Size (bits) of the type "double" on target machine. -+ * Note that the C standard does not require that doubles -+ * hold any more bits than float. Since the 6809 has so few -+ * registers, we cannot really support more than 32-bits. */ -+#define DOUBLE_TYPE_SIZE 32 -+ -+/* Size (bits) of the type "long double" on target machine */ -+#define LONG_DOUBLE_TYPE_SIZE 32 -+ -+/* Define the type used for "size_t". With a 64KB address space, -+ * only a 16-bit value here makes sense. */ -+#define SIZE_TYPE (TARGET_BYTE_INT ? "long unsigned int" : "unsigned int") -+ -+/* Likewise, the difference between two pointers is also a 16-bit -+ * signed value. */ -+#define PTRDIFF_TYPE (TARGET_BYTE_INT ? "long int" : "int") -+ -+/* Nonzero if access to memory by bytes is slow and undesirable. */ -+#define SLOW_BYTE_ACCESS 0 -+ -+/* Define if shifts truncate the shift count -+ which implies one can omit a sign-extension or zero-extension -+ of a shift count. */ -+#define SHIFT_COUNT_TRUNCATED 0 -+ -+/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits -+ is done just by pretending it is already truncated. */ -+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 -+ -+/* It is as good to call a constant function address as to -+ call an address kept in a register. */ -+#define NO_FUNCTION_CSE -+ -+/* Specify the machine mode that pointers have. -+ After generation of rtl, the compiler makes no further distinction -+ between pointers and any other objects of this machine mode. */ -+#define Pmode HImode -+ -+/* A function address in a call instruction -+ is a byte address (for indexing purposes) -+ so give the MEM rtx a byte's mode. */ -+#define FUNCTION_MODE HImode -+ -+/* Define the cost of moving a value from a register in CLASS1 -+ * to CLASS2, of a given MODE. -+ * -+ * On the 6809, hard register transfers are all basically equivalent. -+ * But soft register moves are treated more like memory moves. */ -+#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \ -+ (((CLASS1 == M_REGS) || (CLASS2 == M_REGS)) ? 4 : 7) -+ -+/* Define the cost of moving a value between a register and memory. */ -+#define MEMORY_MOVE_COST(MODE, CLASS, IN) 5 -+ -+/* Check a `double' value for validity for a particular machine mode. */ -+ -+#define CHECK_FLOAT_VALUE(MODE, D, OVERFLOW) \ -+ ((OVERFLOW) = check_float_value (MODE, &D, OVERFLOW)) -+ -+ -+/*-------------------------------------------------------------- -+ machine-dependent -+--------------------------------------------------------------*/ -+/* Tell final.c how to eliminate redundant test instructions. */ -+ -+/* Here we define machine-dependent flags and fields in cc_status -+ (see `conditions.h'). */ -+ -+/* Store in cc_status the expressions -+ that the condition codes will describe -+ after execution of an instruction whose pattern is EXP. -+ Do not alter them if the instruction would not alter the cc's. */ -+ -+/* On the 6809, most of the insns to store in an address register -+ fail to set the cc's. However, in some cases these instructions -+ can make it possibly invalid to use the saved cc's. In those -+ cases we clear out some or all of the saved cc's so they won't be used. */ -+ -+#define NOTICE_UPDATE_CC(EXP, INSN) \ -+ notice_update_cc((EXP), (INSN)) -+ -+/***************************************************************************** -+** -+** pragma support -+** -+*****************************************************************************/ -+ -+#if 0 -+#define REGISTER_TARGET_PRAGMAS() \ -+do { \ -+ extern void pragma_section PARAMS ((cpp_reader *)); \ -+ c_register_pragma (0, "section", pragma_section); \ -+} while (0) -+ -+#endif -+ -+/*-------------------------------------------------------------- -+ ASSEMBLER FORMAT -+--------------------------------------------------------------*/ -+ -+#define FMT_HOST_WIDE_INT "%ld" -+ -+/* Output to assembler file text saying following lines -+ may contain character constants, extra white space, comments, etc. */ -+#define ASM_APP_ON ";----- asm -----\n" -+ -+/* Output to assembler file text saying following lines -+ no longer contain unusual constructs. */ -+#define ASM_APP_OFF ";--- end asm ---\n" -+ -+/* Use a semicolon to begin a comment. */ -+#define ASM_COMMENT_START "; " -+ -+/* Output assembly directives to switch to section 'name' */ -+#undef TARGET_ASM_NAMED_SECTION -+#define TARGET_ASM_NAMED_SECTION m6809_asm_named_section -+ -+#undef TARGET_HAVE_NAMED_SECTION -+#define TARGET_HAVE_NAMED_SECTION m6809_have_named_section -+ -+/* Output before read-only data. */ -+#define TEXT_SECTION_ASM_OP (code_section_op) -+ -+/* Output before writable data. */ -+#define DATA_SECTION_ASM_OP (data_section_op) -+ -+/* Output before uninitialized data. */ -+#define BSS_SECTION_ASM_OP (bss_section_op) -+ -+/* Support the ctors and dtors sections for g++. */ -+ -+#undef CTORS_SECTION_ASM_OP -+#define CTORS_SECTION_ASM_OP "\t.area .ctors" -+#undef DTORS_SECTION_ASM_OP -+#define DTORS_SECTION_ASM_OP "\t.area .dtors" -+ -+ -+#undef DO_GLOBAL_CTORS_BODY -+#undef DO_GLOBAL_DTORS_BODY -+ -+#define HAS_INIT_SECTION -+ -+/* This is how to output an assembler line -+ that says to advance the location counter -+ to a multiple of 2**LOG bytes. */ -+ -+#define ASM_OUTPUT_ALIGN(FILE,LOG) \ -+ if ((LOG) > 1) \ -+ fprintf (FILE, "\t.bndry %u\n", 1 << (LOG)) -+ -+/* The .set foo,bar construct doesn't work by default */ -+#undef SET_ASM_OP -+#define ASM_OUTPUT_DEF(FILE, LABEL1, LABEL2) \ -+ do \ -+ { \ -+ fputc ('\t', FILE); \ -+ assemble_name (FILE, LABEL1); \ -+ fputs (" = ", FILE); \ -+ assemble_name (FILE, LABEL2); \ -+ fputc ('\n', FILE); \ -+ } \ -+ while (0) -+ -+/* How to refer to registers in assembler output. -+ This sequence is indexed by compiler's hard-register-number (see above). */ -+#define MNAME(x) [SOFT_M0_REGNUM+(x)] = "*m" C_STRING(x) , -+ -+#define REGISTER_NAMES { \ -+ [HARD_D_REGNUM]= "d", \ -+ [HARD_X_REGNUM]= "x", \ -+ [HARD_Y_REGNUM]= "y", \ -+ [HARD_U_REGNUM]= "u", \ -+ [HARD_S_REGNUM]= "s", \ -+ [HARD_PC_REGNUM]= "pc", \ -+ [HARD_A_REGNUM]= "a", \ -+ [HARD_B_REGNUM]= "b", \ -+ [HARD_CC_REGNUM]= "cc",\ -+ [HARD_DP_REGNUM]= "dp", \ -+ [SOFT_FP_REGNUM]= "soft_fp", \ -+ [SOFT_AP_REGNUM]= "soft_ap", \ -+ MNAME(0) MNAME(1) MNAME(2) MNAME(3) \ -+ MNAME(4) MNAME(5) MNAME(6) MNAME(7) \ -+ [HARD_RSVD1_REGNUM] = "-", \ -+ [HARD_Z_REGNUM] = "z" /* bit 2 of CC */ } -+ -+/***************************************************************************** -+** -+** Debug Support -+** -+*****************************************************************************/ -+ -+/* Default to DBX-style debugging */ -+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG -+ -+#define DBX_DEBUGGING_INFO -+ -+#define DEFAULT_GDB_EXTENSIONS 0 -+ -+#define ASM_STABS_OP ";\t.stabs\t" -+#define ASM_STABD_OP ";\t.stabd\t" -+#define ASM_STABN_OP ";\t.stabn\t" -+ -+#define DBX_CONTIN_LENGTH 54 -+ -+#define DBX_OUTPUT_MAIN_SOURCE_FILENAME(ASMFILE, FILENAME) \ -+do { \ -+ const char *p = FILENAME; \ -+ while ((p = strchr (p, '/')) != NULL) { \ -+ p = FILENAME = p+1; \ -+ } \ -+ fprintf (ASMFILE, "%s", ASM_STABS_OP); \ -+ output_quoted_string (ASMFILE, FILENAME); \ -+ fprintf (ASMFILE, ",%d,0,0,", N_SO); \ -+ assemble_name (ASMFILE, ltext_label_name); \ -+ fputc ('\n', ASMFILE); \ -+ switch_to_section (text_section); \ -+ (*targetm.asm_out.internal_label) (ASMFILE, "Ltext", 0); \ -+} while (0) -+ -+/* With -g, GCC sometimes outputs string literals that are longer than -+ * the assembler can handle. Without actual debug support, these are -+ * not really required. Redefine the function to output strings to -+ * output as much as possible. */ -+#define OUTPUT_QUOTED_STRING(FILE, STR) m6809_output_quoted_string (FILE, STR) -+ -+/***************************************************************************** -+** -+** Output and Generation of Labels -+** -+*****************************************************************************/ -+ -+/* Prefixes for various assembly-time objects */ -+ -+#define REGISTER_PREFIX "" -+ -+#define LOCAL_LABEL_PREFIX "" -+ -+#define USER_LABEL_PREFIX "_" -+ -+#define IMMEDIATE_PREFIX "#" -+ -+/* This is how to output the definition of a user-level label named NAME, -+ such as the label on a static function or variable NAME. */ -+ -+#define ASM_OUTPUT_LABEL(FILE,NAME) \ -+do { \ -+ if (section_changed) { \ -+ fprintf (FILE, "\n%s\n\n", code_section_op); \ -+ section_changed = 0; \ -+ } \ -+ assemble_name (FILE, NAME); \ -+ fputs (":\n", FILE); \ -+} while (0) -+ -+/* This is how to output the label for a function definition. It -+ invokes ASM_OUTPUT_LABEL, but may examine the DECL tree node for -+ other properties. */ -+#define ASM_DECLARE_FUNCTION_NAME(FILE,NAME,DECL) \ -+ m6809_declare_function_name (FILE,NAME,DECL) -+ -+/* This is how to output a command to make the user-level label -+ named NAME defined for reference from other files. */ -+ -+#define GLOBAL_ASM_OP "\t.globl " -+ -+/* This is how to output a reference to a user label named NAME. */ -+#define ASM_OUTPUT_LABELREF(FILE,NAME) \ -+ fprintf (FILE, "_%s", NAME) -+ -+/* This is how to output a reference to a symbol ref -+ * Check to see if the symbol is in the direct page */ -+#define ASM_OUTPUT_SYMBOL_REF(FILE,sym) \ -+{ \ -+ print_direct_prefix (FILE, sym); \ -+ assemble_name (FILE, XSTR (sym, 0)); \ -+} -+ -+/* External references aren't necessary, so don't emit anything */ -+#define ASM_OUTPUT_EXTERNAL(FILE,DECL,NAME) -+ -+/* This is how to store into the string LABEL -+ the symbol_ref name of an internal numbered label where -+ PREFIX is the class of label and NUM is the number within the class. -+ This is suitable for output with `assemble_name'. */ -+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ -+ sprintf (LABEL, "*%s%lu", PREFIX, (unsigned long int)NUM) -+ -+/* This is how to output an assembler line defining an `int' constant. */ -+#define ASM_OUTPUT_INT(FILE,VALUE) \ -+( fprintf (FILE, "\t.word "), \ -+ output_addr_const (FILE, (VALUE)), \ -+ fprintf (FILE, "\n")) -+ -+/* Likewise for `char' and `short' constants. */ -+#define ASM_OUTPUT_SHORT(FILE,VALUE) \ -+( fprintf (FILE, "\t.word "), \ -+ output_addr_const (FILE, (VALUE)), \ -+ fprintf (FILE, "\n")) -+ -+/* This is how to output a string. */ -+#define ASM_OUTPUT_ASCII(FILE,STR,SIZE) m6809_output_ascii (FILE, STR, SIZE) -+ -+/* This is how to output an insn to push a register on the stack. -+ It need not be very fast code. */ -+ -+#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ -+ fprintf (FILE, "\tpshs\t%s\n", reg_names[REGNO]) -+ -+/* This is how to output an insn to pop a register from the stack. -+ It need not be very fast code. */ -+ -+#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ -+ fprintf (FILE, "\tpuls\t%s\n", reg_names[REGNO]) -+ -+/* This is how to output an element of a case-vector that is absolute. */ -+ -+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ -+ fprintf (FILE, "\t.word L%u\n", VALUE) -+ -+/* This is how to output an element of a case-vector that is relative. */ -+ -+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ -+ fprintf (FILE, "\t.word L%u-L%u\n", VALUE, REL) -+ -+ -+/***************************************************************************** -+** -+** Assembler Commands for Alignment -+** -+*****************************************************************************/ -+ -+/* ASM_OUTPUT_SKIP is supposed to zero initialize the data. -+ * So use the .byte and .word directives instead of .blkb */ -+#define ASM_OUTPUT_SKIP(FILE,SIZE) \ -+ do { \ -+ int __size = SIZE; \ -+ while (__size > 0) { \ -+ if (__size >= 2) \ -+ { \ -+ fprintf (FILE, "\t.word\t0\t;skip space %d\n", __size); \ -+ __size -= 2; \ -+ } \ -+ else \ -+ { \ -+ fprintf (FILE, "\t.byte\t0\t;skip space\n"); \ -+ __size--; \ -+ } \ -+ } \ -+ } while (0) -+ -+/* This says how to output an assembler line -+ to define a global common symbol. */ -+ -+#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ -+ do { \ -+ switch_to_section (bss_section); \ -+ fputs ("\t.globl\t", FILE); \ -+ assemble_name ((FILE), (NAME)); \ -+ fputs ("\n", FILE); \ -+ assemble_name ((FILE), (NAME)); \ -+ fprintf ((FILE), ":\t.blkb\t" FMT_HOST_WIDE_INT "\n", (ROUNDED));} while(0) -+ -+/* This says how to output an assembler line -+ to define a local common symbol. */ -+ -+#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ -+do { \ -+ switch_to_section (bss_section); \ -+ assemble_name ((FILE), (NAME)); \ -+ fprintf ((FILE), ":\t.blkb\t" FMT_HOST_WIDE_INT "\n", (ROUNDED));} while(0) -+ -+/* Store in OUTPUT a string (made with alloca) containing -+ an assembler-name for a local static variable named NAME. -+ LABELNO is an integer which is different for each call. */ -+ -+#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ -+( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ -+ sprintf ((OUTPUT), "%s.%lu", (NAME), (unsigned long int)(LABELNO))) -+ -+/* Print an instruction operand X on file FILE. -+ CODE is the code from the %-spec for printing this operand. -+ If `%z3' was used to print operand 3, then CODE is 'z'. */ -+#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE) -+ -+/* Print a memory operand whose address is X, on file FILE. */ -+#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR) -+ -+/* Don't let stack pushes build up too much. */ -+#define MAX_PENDING_STACK 8 -+ -+/* Define values for builtin operations */ -+enum m6809_builtins -+{ -+ M6809_SWI, -+ M6809_SWI2, -+ M6809_SWI3, -+ M6809_CWAI, -+ M6809_SYNC, -+ M6809_ADD_CARRY, -+ M6809_SUB_CARRY, -+ M6809_ADD_DECIMAL, -+ M6809_NOP, -+ M6809_BLOCKAGE -+}; -+ -diff -urN gcc-4.6.4-clean/gcc/config/m6809/m6809.md gcc-4.6.4/gcc/config/m6809/m6809.md ---- gcc-4.6.4-clean/gcc/config/m6809/m6809.md 1969-12-31 17:00:00.000000000 -0700 -+++ gcc-4.6.4/gcc/config/m6809/m6809.md 2015-07-20 22:05:21.702720231 -0600 -@@ -0,0 +1,2358 @@ -+;; GCC machine description for Motorola 6809 -+;; Copyright (C) 1989, 2005, 2006, 2007, 2008, -+;; 2009 Free Software Foundation, Inc. -+;; -+;; Mostly by Brian Dominy (brian@oddchange.com) with substantial renovations -+;; by William Astle (lost@l-w.ca). -+;; -+;; Based on earlier work by Tom Jones (jones@sal.wisc.edu) and -+;; Matthias Doerfel (msdoerfe@informatik.uni-erlangen.de) -+;; -+;; 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 -+;; <http://www.gnu.org/licenses/>. -+;; -+;; General information: -+;; -------------------- -+;; * This backend is mostly a rewrite from earlier (3.1.1 and before) -+;; versions. -+;; -+;; * The 'A' and 'B' registers are treated as a single register by the -+;; register allocator; hence, the instruction templates assume that -+;; both can be modified if either one is available for use. No -+;; attempt is made to split instructions to refer to a particular half -+;; of the register. It is always referred to as the 'D' register, even -+;; in QImode (when it will be displayed as 'B'). -+;; -+;; * There is full support for proper branch instruction generation, -+;; based on instruction lengths. However, many instruction patterns -+;; are still overloaded to emit lots of real instructions, which can -+;; make the length calculation difficult; in those cases, I've tried -+;; to be pessimistic and assume the worst-case. -+;; -+;; * The instruction type attributes are only defined for branch -+;; vs. non branch instructions for now, since there is seemingly no -+;; reason to define these for other types anyway. -+;; -+;; * The limited number of total registers presents the greatest -+;; challenge. There are 'soft registers' -- memory locations -+;; used to simulate real regs -- which can be helpful. -+;; -+;; * Position-independent code (PIC) is supported and has been tested -+;; but not to the extent of absolute code generation. -+;; -+;; * All of the 6809 special opcodes, e.g. SWI and SYNC, are defined -+;; as UNSPEC instructions, and can be accessed from C code using -+;; __builtin_xxxx() style functions. -+;; -+;; What still needs to be done: -+;; ---------------------------- -+;; * Replace remaining instances of (define_peephole) with -+;; (define_peephole2), or remove them completely if they are not -+;; matching anyway. Add more peepholes for things actually encountered. -+;; -+;; * Indexing addressing can lead to crashes in complex functions when -+;; register pressure is high. Only the 'D' register can actually be -+;; used as an index register, and its demand by other instructions -+;; can sometimes mean that it is impossible to satisfy constraints. -+;; Currently, indexing is completely disabled to avoid these types -+;; of problems, although code is slightly more inefficient in some -+;; working cases. -+;; -+;; * 32-bit math is terribly inefficient. -+;; -+ -+ -+;;-------------------------------------------------------------------- -+;;- Constants -+;;-------------------------------------------------------------------- -+ -+; -+; Define constants for hard register numbers. -+; -+(define_constants [ -+ (HARD_RSVD1_REGNUM 0) -+ (HARD_X_REGNUM 1) (HARD_Y_REGNUM 2) (HARD_U_REGNUM 3) -+ (HARD_S_REGNUM 4) (HARD_PC_REGNUM 5) (HARD_D_REGNUM 6) -+ (HARD_Z_REGNUM 7) -+ (HARD_A_REGNUM 8) (HARD_B_REGNUM 9) -+ (HARD_CC_REGNUM 10) (HARD_DP_REGNUM 11) -+ (SOFT_FP_REGNUM 12) (SOFT_AP_REGNUM 13) -+ (SOFT_M0_REGNUM 14) (SOFT_M1_REGNUM 15) -+ (SOFT_M2_REGNUM 16) (SOFT_M3_REGNUM 17) -+]) -+ -+ -+; -+; The range in which a short branch insn can be used. -+; -+(define_constants [ -+ (MIN_SHORT_BRANCH_OFFSET -127) -+ (MAX_SHORT_BRANCH_OFFSET 128) -+]) -+ -+ -+; -+; The lengths of various types of real 6809 instructions. -+; -+; By default, ordinary insns are 4 bytes long. This is often not -+; right, and the insn patterns below will redefine this to the -+; correct value. -+; -+; Branch instruction lengths (conditional and unconditionals) are -+; well known and declared here. The short insns are used when the -+; offset is within the range declared above (between MIN_SHORT -+; and MAX_SHORT) ; otherwise the long form is used. -+; -+(define_constants [ -+ (DEFAULT_INSN_LENGTH 4) -+ (SHORT_CBRANCH_LENGTH 2) -+ (LONG_CBRANCH_LENGTH 4) -+ (SHORT_BRANCH_LENGTH 2) -+ (LONG_BRANCH_LENGTH 3) -+]) -+ -+ -+; -+; Constants for insn cycle counts. -+; Note that these counts all assume 1-byte opcodes. 2-byte -+; opcodes require 1 extra cycles for fetching the extra byte. -+; -+(define_constants [ -+ ;; The default insn length, when it cannot be calculated. -+ ;; Take a conservative approach and estimate high. -+ (DEFAULT_INSN_CYCLES 10) -+ -+ ;; Cycle counts for ALU and load operations. -+ (ALU_INHERENT_CYCLES 2) -+ (ALU_IMMED_CYCLES 2) -+ (ALU_DIRECT_CYCLES 4) -+ (ALU_INDEXED_BASE_CYCLES 4) -+ (ALU_EXTENDED_CYCLES 5) -+ -+ ;; If an ALU operation is on a 16-bit register (D), then -+ ;; add this number of cycles to the total count. -+ (ALU_16BIT_CYCLES 2) -+ -+ ;; A load of a 16-bit register incurs this extra amount. -+ (LOAD_16BIT_CYCLES 1) -+ -+ ;; Cycle counts for memory-only operations (bit shifts, clear, test) -+ (MEM_DIRECT_CYCLES 6) -+ (MEM_INDEXED_BASE_CYCLES 6) -+ (MEM_EXTENDED_CYCLES 7) -+ -+ ;; Cycle count for any reg-reg transfer (regardless of size) -+ (EXG_CYCLES 8) -+ (TFR_CYCLES 6) -+ -+ ;; Cycle count for a condition code update (andcc/orcc) -+ (CC_CYCLES 3) -+ -+ (JMP_DIRECT_CYCLES 3) -+ (JMP_INDEXED_BASE_CYCLES 3) -+ (JMP_EXTENDED_CYCLES 4) -+ -+ (JSR_DIRECT_CYCLES 7) -+ (JSR_INDEXED_BASE_CYCLES 7) -+ (JSR_EXTENDED_CYCLES 8) -+ -+ (LEA_BASE_CYCLES 4) -+ -+ ;; Cycle count for a psh/pul operations. Add to this the -+ ;; total number of bytes moved for the correct count. -+ (PSH_PUL_CYCLES 5) -+ -+ ;; Miscellaneous cycle counts -+ (CWAI_CYCLES 20) -+ (MUL_CYCLES 11) -+ (NOP_CYCLES 2) -+ (RTI_CYCLES 15) -+ (RTS_CYCLES 5) -+ (SWI_CYCLES 20) -+ (SYNC_CYCLES 4) -+]) -+ -+ -+; -+; An enumeration of values for each "unspec"; i.e. unspecified -+; instruction. These represent insns that are meaningful on the -+; 6809 but which have no intrinsic meaning to GCC itself. -+; These insns can be generated explicitly using the __builtin_xxx -+; syntax; they are also implicitly generated by the backend -+; as needed to implement other insns. -+; -+(define_constants [ -+ (UNSPEC_BLOCKAGE 0) -+ (UNSPEC_PUSH_RS 1) -+ (UNSPEC_POP_RS 2) -+ (UNSPEC_SWI 3) -+ (UNSPEC_CWAI 4) -+ (UNSPEC_ADD_CARRY 5) -+ (UNSPEC_SUB_CARRY 6) -+ (UNSPEC_SYNC 7) -+ (UNSPEC_ADD_DECIMAL 8) -+]) -+ -+ -+;;-------------------------------------------------------------------- -+;;- Predicates -+;;-------------------------------------------------------------------- -+ -+(include "predicates.md") -+ -+;;-------------------------------------------------------------------- -+;;- Attributes -+;;-------------------------------------------------------------------- -+ -+;; -+;; The type attribute is used to distinguish between different -+;; types of branch instructions, so that their lengths can be -+;; calculated correctly. -+;; -+(define_attr "type" "branch,cbranch,unknown" (const_string "unknown")) -+ -+;; -+;; The length of a branch instruction is calculated based on how -+;; far away the branch target is. Lengths of other insns default -+;; to 4. set_attr is used in instruction templates to specify -+;; the length when it is known exactly. When not sure, err on -+;; the high side to avoid compile errors. -+;; -+(define_attr "length" "" -+ (cond [ -+ (eq_attr "type" "branch") -+ (if_then_else (lt (minus (match_dup 0) (pc)) -+ (const_int MIN_SHORT_BRANCH_OFFSET)) -+ (const_int LONG_BRANCH_LENGTH) -+ (if_then_else (gt (minus (match_dup 0) (pc)) -+ (const_int MAX_SHORT_BRANCH_OFFSET)) -+ (const_int LONG_BRANCH_LENGTH) -+ (const_int SHORT_BRANCH_LENGTH))) -+ (eq_attr "type" "cbranch") -+ (if_then_else (lt (minus (match_dup 0) (pc)) -+ (const_int MIN_SHORT_BRANCH_OFFSET)) -+ (const_int LONG_CBRANCH_LENGTH) -+ (if_then_else (gt (minus (match_dup 0) (pc)) -+ (const_int MAX_SHORT_BRANCH_OFFSET)) -+ (const_int LONG_CBRANCH_LENGTH) -+ (const_int SHORT_CBRANCH_LENGTH))) -+ ] (const_int DEFAULT_INSN_LENGTH))) -+ -+ -+;; -+;; The default attributes for 'asm' statements. -+;; The default length is the longest possible single 6809 instruction, -+;; which is 5 bytes. GCC will automatically multiply this by the -+;; number of real insns contained in an asm statement. -+;; -+(define_asm_attributes -+ [(set_attr "length" "5") -+ (set_attr "type" "unknown")]) -+ -+;; -+;; An attribute for the number of cycles that it takes an instruction -+;; to execute. -+;; -+(define_attr "cycles" "" (const_int DEFAULT_INSN_CYCLES)) -+ -+ -+;;-------------------------------------------------------------------- -+;;- Instruction patterns. When multiple patterns apply, -+;;- the first one in the file is chosen. -+;;- -+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. -+;;- -+;;- Note: NOTICE_UPDATE_CC in m6809.h handles condition code updates -+;;- for most instructions. -+;;-------------------------------------------------------------------- -+ -+;;-------------------------------------------------------------------- -+;;- Test -+;;-------------------------------------------------------------------- -+ -+;; cmpx is 3 bytes, not 4 -+(define_insn "*tsthi_x" -+ [(set (cc0) (match_operand:HI 0 "register_operand_x" "v"))] -+ "" -+ "cmpx\t#0" -+ [(set_attr "length" "3")]) -+ -+;; subd #0 is 3 bytes, better than cmpd #0 which is 4 bytes -+(define_insn "*tsthi_d" -+ [(set (cc0) (match_operand:HI 0 "register_operand_d" "d"))] -+ "" -+ "subd\t#0" -+ [(set_attr "length" "3")]) -+ -+(define_insn "*tsthi" -+ [(set (cc0) (match_operand:HI 0 "register_operand" "a"))] -+ "" -+ "cmp%0\t#0" -+ [(set_attr "length" "4")]) -+ -+(define_insn "*bitqi3" -+ [(set (cc0) -+ (and:QI (match_operand:QI 0 "register_operand" "%q") -+ (match_operand:QI 1 "general_operand" "mi")))] -+ "" -+ "bit%0\t%1" -+ [(set_attr "length" "3")]) -+ -+ -+(define_insn "tstqi" -+ [(set (cc0) (match_operand:QI 0 "nonimmediate_operand" "q,mt"))] -+ "" -+ "@ -+ tst%0 -+ tst\t%0" -+ [(set_attr "length" "1,3")]) -+ -+;;-------------------------------------------------------------------- -+;;- Compare instructions -+;;-------------------------------------------------------------------- -+ -+;; - cmphi for register to memory or register compares -+(define_insn "cmphi" -+ [(set (cc0) -+ (compare -+ (match_operand:HI 0 "general_operand" "da, mi, ??Ud") -+ (match_operand:HI 1 "general_operand" "mi, da, dU")))] -+ "" -+{ -+ if ((REG_P (operands[0])) && (REG_P (operands[1]))) { -+ output_asm_insn ("pshs\t%1\t;cmphi: R:%1 with R:%0", operands); -+ return "cmp%0\t,s++\t;cmphi:"; -+ } -+ if (GET_CODE (operands[0]) == REG) -+ return "cmp%0\t%1\t;cmphi:"; -+ else { -+ cc_status.flags |= CC_REVERSED; -+ return "cmp%1\t%0\t;cmphi:(R)"; -+ } -+} -+ [(set_attr "length" "5,5,7")]) -+ -+ -+(define_insn "cmpqi" -+ [(set (cc0) -+ (compare (match_operand:QI 0 "whole_general_operand" "q,q, q,O,mt,K") -+ (match_operand:QI 1 "whole_general_operand" "O,mt,K,q,q, q")))] -+ "" -+{ -+ if (REG_P (operands[0]) && !M_REG_P (operands[0])) -+ { -+ if (operands[1] == const0_rtx) -+ return "tst%0\t;cmpqi:(ZERO)"; -+ else -+ return "cmp%0\t%1\t;cmpqi:"; -+ } -+ else -+ { -+ cc_status.flags |= CC_REVERSED; -+ -+ if (operands[0] == const0_rtx) -+ return "tst%1\t;cmpqi:(RZERO)"; -+ else -+ return "cmp%1\t%0\t;cmpqi:(R)"; -+ } -+} -+ [(set_attr "length" "1,3,2,1,3,2")]) -+ -+ -+;;-------------------------------------------------------------------- -+;;- Compare/branch pattern -+;;-------------------------------------------------------------------- -+ -+(define_expand "cbranchhi4" -+ [(set (cc0) -+ (compare -+ (match_operand:HI 1 "general_operand" "da, mi, ??Ud") -+ (match_operand:HI 2 "general_operand" "mi, da, dU"))) -+ (set (pc) -+ (if_then_else -+ (match_operator 0 "ordered_comparison_operator" [(cc0) (const_int 0)]) -+ (label_ref (match_operand 3 "" "")) -+ (pc)))] -+ "" -+ "" -+) -+ -+(define_expand "cbranchqi4" -+ [(set (cc0) -+ (compare -+ (match_operand:QI 1 "whole_general_operand" "q,q, q,O,mt,K") -+ (match_operand:QI 2 "whole_general_operand" "O,mt,K,q,q, q"))) -+ (set (pc) -+ (if_then_else -+ (match_operator 0 "ordered_comparison_operator" [(cc0) (const_int 0)]) -+ (label_ref (match_operand 3 "" "")) -+ (pc)))] -+ "" -+ "" -+) -+ -+;;-------------------------------------------------------------------- -+;;- Move -+;;-------------------------------------------------------------------- -+ -+; this looks good (obviously not finished) but I still see 'movsi' -+; places in udivsi3 where it's broken -+; (define_insn "pushsi1" -+; [(set (mem:SI (pre_dec (reg:HI HARD_S_REGNUM))) -+; (match_operand:SI 0 "general_operand" "o")) -+; (set (reg:HI HARD_S_REGNUM) -+; (plus:HI (reg:HI HARD_S_REGNUM) (const_int -4))) ] -+; "" -+; "; pushsi %0" -+; [(set_attr "length" "12")]) -+; -+; (define_insn "popsi1" -+; [(set (match_operand:SI 0 "general_operand" "=o") -+; (mem:SI (post_inc (reg:HI HARD_S_REGNUM)))) -+; (set (reg:HI HARD_S_REGNUM) -+; (plus:HI (reg:HI HARD_S_REGNUM) (const_int 4))) ] -+; "" -+; "; popsi %0" -+; [(set_attr "length" "12")]) -+ -+; (define_insn "movsi" -+; [(set (match_operand:SI 0 "nonimmediate_operand" "=o") -+; (match_operand:SI 1 "general_operand" " oi"))] -+; "" -+; "; movsi %0 <- %1" -+; [(set_attr "length" "1")]) -+ -+; this doesn't work -+; (define_expand "movsi" -+; [(parallel [ -+; (set (match_operand:SI 0 "nonimmediate_operand" "") -+; (match_operand:SI 1 "general_operand" "")) -+; (clobber (match_scratch:HI 2 ""))])] -+; "" -+; { -+; rtx insn; -+; if (STACK_PUSH_P (operands[0]) || STACK_POP_P (operands[1])) -+; { -+; REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, stack_pointer_rtx, REG_NOTES (insn)); -+; } -+; insn = emit_move_multi_word (SImode, operands[0], operands[1]); -+; DONE; -+; }) -+ -+ -+(define_expand "movhi" -+ [(set (match_operand:HI 0 "nonimmediate_operand" "") -+ (match_operand:HI 1 "general_operand" ""))] -+ "" -+{ -+ /* One of the ops has to be in a register prior to reload */ -+ if (!register_operand (operand0, HImode) && -+ !register_operand (operand1, HImode)) -+ operands[1] = copy_to_mode_reg (HImode, operand1); -+}) -+ -+;;; Try a splitter to handle failure cases where we try to move -+;;; an immediate constant (zero usually) directly to memory. -+;;; This absolutely requires an intermediate register. -+(define_split -+ [(set (match_operand:HI 0 "memory_operand" "") -+ (match_operand:HI 1 "immediate_operand" "")) -+ (clobber (match_operand:HI 2 "register_operand" ""))] -+ "" -+ [(set (match_dup 2) (match_dup 1)) -+ (set (match_dup 0) (match_dup 2))] -+ "") -+ -+ -+;;; This would be a nice method for loading from a word array, -+;;; but it is never generated because the combiner cannot merge -+;;; more than 3 instructions (there are four here). This is -+;;; perhaps better done via a peephole. -+(define_insn "*movhi_array_load" -+ [(set (match_operand:HI 0 "nonimmediate_operand" "=da") -+ (mem:HI (plus:HI (ashift:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%B")) (const_int 1)) -+ (match_operand:HI 2 "immediate_operand" "i")))) -+ (clobber (match_scratch:HI 3 "=X"))] -+ "" -+ "ldx\t%2\;abx\;abx\;ld%0\t,x" -+ [(set_attr "length" "7")]) -+ -+ -+;;; Optimize the move of a byte to the stack using the pshs instruction -+;;; instead of a store with pre-increment. -+(define_insn "movhi_push" -+ [(set (match_operand:HI 0 "push_operand" "=m") -+ (match_operand:HI 1 "register_operand" "U"))] -+ "" -+ "pshs\t%1" -+ [(set_attr "length" "2")]) -+ -+ -+(define_insn "*movhi_pic_symbolref" -+ [(set (match_operand:HI 0 "register_operand" "=a") -+ (match_operand:HI 1 "symbolic_operand" ""))] -+ "flag_pic" -+ "lea%0\t%c1,pcr" -+ [(set_attr "length" "4")]) -+ -+ -+(define_insn "*movhi_1" -+ [(set (match_operand:HI 0 "nonimmediate_operand" "=a,d,a,ad,mu") -+ (match_operand:HI 1 "general_operand" " a,a,d,miu,ad"))] -+ "" -+ "@ -+ lea%0\t,%1 -+ tfr\t%1,%0 -+ tfr\t%1,%0 -+ ld%0\t%1 -+ st%1\t%0" -+ [(set_attr "length" "2,2,2,*,*")]) -+ -+ -+;;; Generated by the combiner to merge an address calculation with -+;;; a byte load. We can use the 'abx' instruction here. -+(define_insn "*movqi_array_load" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q") -+ (mem:QI (plus:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%B")) -+ (match_operand:HI 2 "immediate_operand" "i")))) -+ (clobber (match_scratch:HI 3 "=X"))] -+ "" -+ "ldx\t%2\;abx\;ld%0\t,x" -+ [(set_attr "length" "6")]) -+ -+ -+;;; Optimize the move of a byte to the stack using the pshs instruction -+;;; instead of a store with pre-increment. -+(define_insn "movqi_push" -+ [(set (match_operand:QI 0 "push_operand" "=m") -+ (match_operand:QI 1 "register_operand" " q"))] -+ "" -+ "pshs\t%1" -+ [(set_attr "length" "2")]) -+ -+ -+;;; Optimize the move of a byte from the stack using the puls instruction -+;;; instead of a store with post-decrement. -+(define_insn "movqi_pop" -+ [(set (match_operand:QI 0 "register_operand" "=q") -+ (match_operand:QI 1 "pop_operand" "m"))] -+ "" -+ "puls\t%0" -+ [(set_attr "length" "2")]) -+ -+ -+;;- load low byte of 16-bit data into 8-bit register/memory -+(define_insn "*mov_lsb" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q,q,m,!q") -+ (subreg:QI (match_operand:HI 1 "general_operand" "d,m,a,d, U") 1))] -+ "" -+ "@ -+ \t;movlsbqihi: D->B -+ ld%0\t%L1\t;movlsbqihi: msb:%1 -> R:%0 -+ tfr\t%1,d\t;movlsbqihi: R:%1 -> R:%0 -+ stb\t%0\t;movlsbqihi: R:%1 -> %0 -+ pshs\t%1\t;movlsbqihi: R:%1 -> R:%0\;leas\t1,s\;puls\t%0" -+ [(set_attr "length" "0,*,2,*,6")]) -+ -+ -+;;- load high byte of 16-bit data into 8-bit register/memory -+(define_insn "*mov_msb" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q,q,q,m,!q") -+ (subreg:QI (match_operand:HI 1 "general_operand" "d,O,a,m,d, U") 0))] -+ "" -+ "@ -+ tfr\ta,b\t;movmsbqihi: D->B -+ clr%0\t\t;movmsbqihi: ZERO -> R:%0 -+ tfr\t%1,d\t;movmsbqihi: R:%1 -> R:%0\;tfr\ta,b -+ ld%0\t%L1\t;movmsbqihi: lsb:%1 -> R:%0 -+ sta\t%0\t;movmsbqihi: R:%1 -> %0 -+ pshs\t%1\t;movmsbqihi: R:%1 -> R:%0\;puls\t%0\;leas\t1,s" -+ [(set_attr "length" "2,1,4,*,*,6")]) -+ -+ -+(define_insn "*movqi_boolean" -+ [(set (reg:QI HARD_Z_REGNUM) -+ (match_operand:QI 0 "general_operand" "q,O,i,m"))] -+ "" -+ "@ -+ tst%0 -+ andcc\t#~4 -+ orcc\t#4 -+ tst\t%0") -+ -+ -+(define_insn "movqi" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q,m,q,m,q,z") -+ (match_operand:QI 1 "general_operand" " q,O,O,mi,q,z,q"))] -+ "" -+ "@ -+ tfr\t%1,%0 -+ clr%0 -+ clr\t%0 -+ ld%0\t%1 -+ st%1\t%0 -+ tfr\tcc,%0\;and%0\t#4 -+ tst%0" -+ [(set_attr "length" "2,1,3,*,*,4,1")]) -+ -+ -+;;-------------------------------------------------------------------- -+;;- Swap registers -+;;-------------------------------------------------------------------- -+ -+; Note: 8-bit swap is never needed so it is not defined. -+ -+(define_insn "swaphi" -+ [(set (match_operand:HI 0 "register_operand" "+r") -+ (match_operand:HI 1 "register_operand" "+r")) -+ (set (match_dup 1) (match_dup 0))] -+ "" -+ "exg\t%1,%0" -+ [(set_attr "length" "2") -+ (set (attr "cycles") (const_int EXG_CYCLES))]) -+ -+ -+(define_insn "bswaphi2" -+ [(set (match_operand:HI 0 "register_operand" "=d") -+ (bswap:HI (match_operand:HI 1 "register_operand" "0")))] -+ "" -+ "exg\ta,b" -+ [(set_attr "length" "2")]) -+ -+ -+;;-------------------------------------------------------------------- -+;;- Extension and truncation insns. -+;;-------------------------------------------------------------------- -+ -+(define_insn "extendqihi2" -+ [(set (match_operand:HI 0 "register_operand" "=d") -+ (sign_extend:HI (match_operand:QI 1 "general_operand" "B")))] -+ "" -+ "sex\t\t;extendqihi2: R:%1 -> R:%0" -+ [(set_attr "length" "1")]) -+ -+ -+(define_insn "zero_extendqihi2" -+ [(set (match_operand:HI 0 "register_operand" "=d") -+ (zero_extend:HI (match_operand:QI 1 "general_operand" "B")))] -+ "" -+ "clra\t\t;zero_extendqihi: R:%1 -> R:%0" -+ [(set_attr "length" "1")]) -+ -+ -+;;-------------------------------------------------------------------- -+;;- All kinds of add instructions. -+;;-------------------------------------------------------------------- -+ -+ -+;; -+;; gcc's automatic version of addsi3 doesn't know about adcb,adca -+;; so it is MUCH less efficient. Define this one ourselves. -+;; -+;; TODO - can't always get 'd' for the clobber... allow other registers -+;; as well and use exg d,R ... exg R,d around the code sequence to -+;; use others, at a price. Also consider libcall for this when -+;; optimizing for size. -+;; -+(define_insn "addsi3" -+ [(set (match_operand:SI 0 "nonimmediate_operand" "=o") -+ (plus:SI (match_operand:SI 1 "general_operand" "%o") -+ (match_operand:SI 2 "general_operand" " oi"))) -+ (clobber (match_scratch:HI 3 "=d"))] -+ "" -+{ -+ m6809_output_addsi3 (PLUS, operands); -+ return ""; -+} -+ [(set_attr "length" "21")]) -+ -+ -+; Increment of a 16-bit MEM by 1 can be done without a register. -+(define_insn "*addhi_mem_1" -+ [(set (match_operand:HI 0 "memory_operand" "=m") -+ (plus:HI (match_dup 0) (const_int 1)))] -+ "GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF" -+{ -+ rtx xoperands[2]; -+ -+ xoperands[0] = operands[0]; -+ xoperands[1] = adjust_address (operands[0], QImode, 1); -+ -+ output_asm_insn ("inc\t%1", xoperands); -+ output_asm_insn ("bne\t__IL%=", xoperands); -+ output_asm_insn ("inc\t%0\;__IL%=:", xoperands); -+ return ""; -+} -+ [(set_attr "length" "7")]) -+ -+ -+; Decrement of a 16-bit MEM by 1 can be done without a register. -+(define_insn "*addhi_mem_minus1" -+ [(set (match_operand:HI 0 "memory_operand" "=m") -+ (plus:HI (match_dup 0) (const_int -1)))] -+ "GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF" -+{ -+ rtx xoperands[2]; -+ -+ xoperands[0] = operands[0]; -+ xoperands[1] = adjust_address (operands[0], QImode, 1); -+ -+ output_asm_insn ("tst\t%1", xoperands); -+ output_asm_insn ("bne\t__IL%=", xoperands); -+ output_asm_insn ("dec\t%0", xoperands); -+ output_asm_insn ("__IL%=:", xoperands); -+ output_asm_insn ("dec\t%1", xoperands); -+ return ""; -+} -+ [(set_attr "length" "7")]) -+ -+ -+; Allow the addition of an 8-bit quantity to a 16-bit quantity -+; using the LEAX B,Y addressing mode, where X and Y are both -+; index registers. This will only get generated via the peephole -+; which removes a sign extension. -+(define_insn "*addhi_b" -+ [(set (match_operand:HI 0 "index_register_operand" "=a") -+ (plus:HI(match_operand:HI 1 "index_register_operand" "%a") -+ (match_operand:QI 2 "register_operand" "q") -+ ))] -+ "" -+ "lea%0\t%2,%1\t;addhi_b: R:%0 = R:%2 + R:%1" -+ [(set_attr "length" "*")]) -+ -+ -+; Splitter for addhi pattern #5 below -+(define_split -+ [(set (match_operand:HI 0 "index_register_operand" "") -+ (plus:HI (match_dup 0) (match_operand:HI 1 "memory_operand" "")))] -+ "reload_completed" -+ [ -+ (parallel [(set (match_dup 0) (reg:HI HARD_D_REGNUM)) -+ (set (reg:HI HARD_D_REGNUM) (match_dup 0))]) -+ (set (reg:HI HARD_D_REGNUM) -+ (plus:HI (reg:HI HARD_D_REGNUM) (match_dup 1))) -+ (parallel [(set (match_dup 0) (reg:HI HARD_D_REGNUM)) -+ (set (reg:HI HARD_D_REGNUM) (match_dup 0))]) -+ ] -+{ -+}) -+ -+ -+; Splitter for addhi pattern #7 below -+(define_split -+ [(set (match_operand:HI 0 "index_register_operand" "") -+ (plus:HI (match_dup 0) (match_operand:HI 1 "index_register_operand" "")))] -+ "reload_completed" -+ [ -+ (parallel [(set (match_dup 1) (reg:HI HARD_D_REGNUM)) -+ (set (reg:HI HARD_D_REGNUM) (match_dup 1))]) -+ (set (match_dup 0) -+ (plus:HI (reg:HI HARD_D_REGNUM) (match_dup 0))) -+ (parallel [(set (match_dup 1) (reg:HI HARD_D_REGNUM)) -+ (set (reg:HI HARD_D_REGNUM) (match_dup 1))]) -+ ] -+{ -+}) -+ -+ -+; TODO - this is ugly. During RTL generation, we don't know what registers -+; are available, so the multiple-insn sequences can only be solved -+; via 'define_split's during matching. See andhi3 for an example. -+; Keep the constraints with ? modifiers to help reload pick the right -+; registers. -+; -+; The forms are: -+; 1. D += D, expand this into a shift instead. (rtx costs should be corrected -+; to avoid this even happening...) -+; 2. D += U, require U to be pushed to memory. (Lots of patterns do this -+; now, is this a better way?) -+; 3. Best choice: 'addd' -+; 4. Next best choice: 'lea' -+; 5. Hybrid of 3 and 4 -+; 6. Same as 4, not bad -+; 7. BAD, no D register at all -+; 8. 'lea', as good as 4. -+(define_insn "addhi3" -+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d, d, d, a,?a, a,???T,a") -+ (plus:HI(match_operand:HI 1 "add_general_operand" "%0, 0, 0, d, 0, a, 0, a") -+ (match_operand:HI 2 "general_operand" " 0, !U, mi, a, m, d, T, i") -+ ))] -+ "" -+ "@ -+ lslb\t\t;addhi: R:%0 += R:%2\;rola\t\t;also R:%0 *= 2 -+ pshs\t%2\t;addhi: R:%0 += R:%2\;add%0\t,s++ -+ add%0\t%2 -+ lea%0\t%1,%2 -+ # -+ lea%0\t%2,%1 -+ # -+ lea%0\t%a2,%1" -+ [(set_attr "length" "2,6,*,*,7,*,7,*")]) -+ -+ -+(define_insn "addqi3_carry" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q") -+ (unspec:QI [ -+ (match_operand:QI 1 "whole_general_operand" "%0") -+ (match_operand:QI 2 "whole_general_operand" "tmi")] UNSPEC_ADD_CARRY))] -+ "" -+ "adc%0\t%2\t;addqi_carry: R:%0 += %2" -+ [(set_attr "length" "*")]) -+ -+ -+; TODO: specifying 'A' for the first constraint, to force into the A register -+; is not working because of the way registers are currently set up. This will -+; take some work to get right. Thus the second alternative as a backup. -+(define_insn "addqi3_decimal" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=A,?q") -+ (unspec:QI [ -+ (match_operand:QI 1 "general_operand" "%0,0") -+ (match_operand:QI 2 "general_operand" "mi,mi")] UNSPEC_ADD_DECIMAL))] -+ "" -+ "@ -+ adda\t%2\;daa -+ tfr\t%0,a\;adda\t%2\;daa\;tfr\ta,%0" -+ [(set_attr "length" "5,9")]) -+ -+ -+(define_insn "addqi3" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q,q,m,m,q") -+ (plus:QI (match_operand:QI 1 "whole_general_operand" "%0,0,0,0,0,0") -+ (match_operand:QI 2 "whole_general_operand" " 0,I,N,I,N,mi")))] -+ "" -+ "@ -+ asl%0\t\t;addqi: R:%0 = R:%0 + R:%0 -+ inc%0 -+ dec%0 -+ inc\t%0 -+ dec\t%0 -+ add%0\t%2" -+ [(set_attr "length" "1,1,1,3,3,*")]) -+ -+ -+;;-------------------------------------------------------------------- -+;;- Subtract instructions. -+;;-------------------------------------------------------------------- -+ -+(define_insn "subsi3" -+ [(set (match_operand:SI 0 "nonimmediate_operand" "=o") -+ (minus:SI (match_operand:SI 1 "general_operand" " o") -+ (match_operand:SI 2 "general_operand" " oi"))) -+ (clobber (match_scratch:HI 3 "=d"))] -+ "" -+{ -+ m6809_output_addsi3 (MINUS, operands); -+ return ""; -+} -+ [(set_attr "length" "21")]) -+ -+ -+(define_insn "subhi3" -+ [(set (match_operand:HI 0 "register_operand" "=d, d, a") -+ (minus:HI (match_operand:HI 1 "register_operand" "0, 0, 0") -+ (match_operand:HI 2 "general_operand" "mi, ?U,n")))] -+ "" -+ "@ -+ sub%0\t%2\t;subhi: R:%0 -= %2 -+ pshs\t%2\t;subhi: R:%0 -= R:%2\;sub%0\t,s++ -+ lea%0\t%n2,%1\t;subhi: R:%0 = R:%1 + %n2" -+ [(set_attr "length" "*,5,3")]) -+ -+ -+(define_insn "subqi3_carry" -+ [(set (match_operand:QI 0 "register_operand" "=q") -+ (unspec:QI [ -+ (match_operand:QI 1 "whole_general_operand" "%0") -+ (match_operand:QI 2 "whole_general_operand" "tmi")] UNSPEC_SUB_CARRY))] -+ "" -+ "sbc%0\t%2\t;subqi_carry: R:%0 += %2" -+ [(set_attr "length" "*")]) -+ -+ -+(define_insn "subqi3" -+ [(set (match_operand:QI 0 "register_operand" "=q, q, !q, q") -+ (minus:QI (match_operand:QI 1 "whole_register_operand" "0, 0, I, 0") -+ (match_operand:QI 2 "whole_general_operand" "I, mi, 0, t")))] -+ "" -+ "@ -+ dec%0 -+ sub%0\t%2 -+ dec%0\;neg%0 -+ sub%0\t%2" -+ [(set_attr "length" "1,3,2,3")]) -+ -+ -+;;-------------------------------------------------------------------- -+;;- Multiply instructions. -+;;-------------------------------------------------------------------- -+ -+; TODO - merge these two instructions, using 'extend_operator' to match -+; either signed or zero extension. Everything else is the same. -+(define_insn "mulqihi3" -+ [(set (match_operand:HI 0 "register_operand" "=d") -+ (mult:HI (sign_extend:HI (match_operand:QI 1 "general_operand" "%q")) -+ (match_operand:QI 2 "general_operand" "tmK")))] -+ "" -+ "lda\t%2\t;mulqihi3\;mul" -+ [(set_attr "length" "3")]) -+ -+ -+(define_insn "umulqihi3" -+ [(set (match_operand:HI 0 "register_operand" "=d") -+ (mult:HI (zero_extend:HI (match_operand:QI 1 "general_operand" "%q")) -+ (match_operand:QI 2 "general_operand" "tmK")))] -+ "" -+ "lda\t%2\t;umulqihi3\;mul" -+ [(set_attr "length" "3")]) -+ -+ -+; Expand a 16x16 multiplication into either a libcall or a shift. -+; If the second operand is a small constant, use the above form. -+; Otherwise, do a libcall. -+(define_expand "mulhi3" -+ [(set (match_operand:HI 0 "nonimmediate_operand" "") -+ (mult:HI (match_operand:HI 1 "general_operand" "") -+ (match_operand:HI 2 "nonmemory_operand" "")))] -+ "" -+{ -+ emit_libcall_insns (HImode, "mulhi3", operands, 2); -+ DONE; -+}) -+ -+ -+;;-------------------------------------------------------------------- -+;;- Divide instructions. -+;;-------------------------------------------------------------------- -+ -+(define_expand "divhi3" -+ [(set (match_operand:HI 0 "register_operand" "") -+ (div:HI (match_operand:HI 1 "register_operand" "") -+ (match_operand:HI 2 "register_operand" "")))] -+ "" -+{ -+ emit_libcall_insns (HImode, "divhi3", operands, 2); -+ DONE; -+}) -+ -+ -+(define_expand "divqi3" -+ [(set (match_operand:QI 0 "register_operand" "") -+ (div:QI (match_operand:QI 1 "register_operand" "") -+ (match_operand:QI 2 "register_operand" "")))] -+ "" -+{ -+ emit_libcall_insns (QImode, "divqi3", operands, 2); -+ DONE; -+}) -+ -+ -+(define_expand "udivhi3" -+ [(set (match_operand:HI 0 "register_operand" "") -+ (udiv:HI (match_operand:HI 1 "register_operand" "") -+ (match_operand:HI 2 "register_operand" "")))] -+ "" -+{ -+ emit_libcall_insns (HImode, "udivhi3", operands, 2); -+ DONE; -+}) -+ -+ -+;;-------------------------------------------------------------------- -+;;- mod -+;;-------------------------------------------------------------------- -+ -+(define_expand "modhi3" -+ [(set (match_operand:HI 0 "register_operand" "") -+ (mod:HI (match_operand:HI 1 "register_operand" "") -+ (match_operand:HI 2 "register_operand" "")))] -+ "" -+{ -+ emit_libcall_insns (HImode, "modhi3", operands, 2); -+ DONE; -+}) -+ -+ -+(define_expand "modqi3" -+ [(set (match_operand:QI 0 "register_operand" "") -+ (mod:QI (match_operand:QI 1 "register_operand" "") -+ (match_operand:QI 2 "register_operand" "")))] -+ "" -+{ -+ emit_libcall_insns (QImode, "modqi3", operands, 2); -+ DONE; -+}) -+ -+ -+(define_expand "umodhi3" -+ [(set (match_operand:HI 0 "register_operand" "") -+ (umod:HI (match_operand:HI 1 "register_operand" "") -+ (match_operand:HI 2 "register_operand" "")))] -+ "" -+{ -+ emit_libcall_insns (HImode, "umodhi3", operands, 2); -+ DONE; -+}) -+ -+ -+ -+;;-------------------------------------------------------------------- -+;;- and, or, xor common patterns -+;;-------------------------------------------------------------------- -+ -+; Split a bitwise HImode into two QImode instructions, with one of -+; the sources in a pushable register. The register is pushed onto -+; the stack and memory pop operands (,s+) are used in the QI forms. -+(define_split -+ [(set (match_operand:HI 0 "register_operand" "") -+ (match_operator:HI 3 "logical_bit_operator" -+ [(match_operand:HI 1 "register_operand" "") -+ (match_operand:HI 2 "register_operand" "")]))] -+ "reload_completed" -+ [(set (mem:HI (pre_dec:HI (reg:HI HARD_S_REGNUM))) (match_dup 2)) -+ (set (reg:QI HARD_A_REGNUM) (match_op_dup:QI 3 -+ [(reg:QI HARD_A_REGNUM) -+ (mem:QI (post_inc:QI (reg:HI HARD_S_REGNUM)))])) -+ (set (reg:QI HARD_D_REGNUM) (match_op_dup:QI 3 -+ [(reg:QI HARD_D_REGNUM) -+ (mem:QI (post_inc:QI (reg:HI HARD_S_REGNUM)))])) -+ (use (reg:QI HARD_A_REGNUM))] -+{ -+}) -+ -+; Split a bitwise HImode into two QImode instructions, with one -+; of the sources being a (MEM (MEM (...)); i.e. an indirect memory -+; reference. This requires dereferencing the pointer into a -+; temporary register (X), which must be saved/restored around the -+; compute instructions. -+(define_split -+ [(set (match_operand:HI 0 "register_operand" "") -+ (match_operator:HI 3 "logical_bit_operator" -+ [(match_operand:HI 1 "register_operand" "") -+ (mem:HI (match_operand:HI 2 "memory_operand" ""))]))] -+ "reload_completed" -+ [ -+ (set (mem:HI (pre_dec:HI (reg:HI HARD_S_REGNUM))) (match_dup 4)) -+ (set (match_dup 4) (match_dup 2)) -+ (set (match_dup 4) (mem:HI (match_dup 4))) -+ (set (reg:QI HARD_A_REGNUM) (match_op_dup:QI 3 -+ [(reg:QI HARD_A_REGNUM) -+ (mem:QI (post_inc:QI (match_dup 4)))])) -+ (set (reg:QI HARD_D_REGNUM) (match_op_dup:QI 3 -+ [(reg:QI HARD_D_REGNUM) -+ (mem:QI (post_inc:QI (match_dup 4)))])) -+ (use (reg:QI HARD_A_REGNUM)) -+ (set (match_dup 4) (mem:HI (post_inc:HI (reg:HI HARD_S_REGNUM)))) -+ ] -+{ -+ /* Use X for a temporary index register */ -+ operands[4] = gen_rtx_REG (HImode, HARD_X_REGNUM); -+}) -+ -+ -+; Split a bitwise HImode into two QImode instructions. This is -+; the common case. This handles splitting when neither of the -+; above two cases applies. -+(define_split -+ [(set (match_operand:HI 0 "register_operand" "") -+ (match_operator:HI 3 "logical_bit_operator" -+ [(match_operand:HI 1 "register_operand" "") -+ (match_operand:HI 2 "general_operand" "")]))] -+ "reload_completed" -+ [(set (reg:QI HARD_A_REGNUM) (match_op_dup:QI 3 -+ [(reg:QI HARD_A_REGNUM) (match_dup 4)])) -+ (set (reg:QI HARD_D_REGNUM) (match_op_dup:QI 3 -+ [(reg:QI HARD_D_REGNUM) (match_dup 5)])) -+ (use (reg:QI HARD_A_REGNUM))] -+{ -+ if (GET_CODE (operands[2]) == CONST_INT) -+ { -+ operands[4] = gen_rtx_const_high (operands[2]); -+ operands[5] = gen_rtx_const_low (operands[2]); -+ } -+ else if ((GET_CODE (operands[2]) == MEM) -+ && (GET_CODE (XEXP (operands[2], 0)) == MEM)) -+ { -+ FAIL; -+ } -+ else -+ { -+ operands[4] = gen_highpart (QImode, operands[2]); -+ operands[5] = gen_lowpart (QImode, operands[2]); -+ } -+}) -+ -+; Below are the specific cases for each of the operators. -+; The QImode versions are the simplest and can be implemented -+; directly on the hardware. The HImode cases are all output -+; using one of the above splitting techniques. -+ -+;;-------------------------------------------------------------------- -+;;- and -+;;-------------------------------------------------------------------- -+ -+(define_insn "andhi3" -+ [(set (match_operand:HI 0 "register_operand" "=d") -+ (and:HI (match_operand:HI 1 "register_operand" "%0") -+ (match_operand:HI 2 "general_operand" "mnU")))] -+ "" -+ "#") -+ -+;; it is not clear that this is correct -+(define_insn "*andqi_2" -+ [(set -+ (match_operand:QI 0 "register_operand" "=q") -+ (and:QI (match_operand:QI 1 "register_operand" "q") -+ (match_operand 2 "const_int_operand" "i")))] -+ "" -+{ -+ if (GET_CODE (operands[2]) == CONST_INT) -+ { -+ operands[3] = GEN_INT(INTVAL(operands[2]) & 0xff); -+ return "and%0 %3"; -+ } -+ -+ return "and%0 %2"; -+} -+ [(set_attr "length" "2")]) -+ -+(define_insn "andqi3" -+ [(set (match_operand:QI 0 "register_operand" "=q,q,q,qc") -+ (and:QI (match_operand:QI 1 "whole_register_operand" "%0,0,0,0") -+ (match_operand:QI 2 "whole_general_operand" " O,N,m,i")))] -+ "" -+ "@ -+ clr%0\t;andqi(ZERO) -+ \t;andqi(-1) -+ and%0\t%2 -+ and%0\t%2" -+ [(set_attr "length" "1,0,3,2")]) -+ -+ -+;;-------------------------------------------------------------------- -+;;- or -+;;-------------------------------------------------------------------- -+ -+(define_insn "iorhi3" -+ [(set (match_operand:HI 0 "register_operand" "=d") -+ (ior:HI (match_operand:HI 1 "register_operand" "%0") -+ (match_operand:HI 2 "general_operand" "mnU")))] -+ "" -+ "#") -+ -+ -+(define_insn "iorqi3" -+ [(set (match_operand:QI 0 "register_operand" "=q,q, qc") -+ (ior:QI (match_operand:QI 1 "whole_register_operand" "%0,0, 0") -+ (match_operand:QI 2 "whole_general_operand" " O,m,i")))] -+ "" -+ "@ -+ \t;iorqi(ZERO) -+ or%0\t%2 -+ or%0\t%2" -+ [(set_attr "length" "0,3,2")]) -+ -+;;-------------------------------------------------------------------- -+;;- xor -+;;-------------------------------------------------------------------- -+ -+(define_insn "xorhi3" -+ [(set (match_operand:HI 0 "register_operand" "=d") -+ (xor:HI (match_operand:HI 1 "register_operand" "%0") -+ (match_operand:HI 2 "general_operand" "mnU")))] -+ "" -+ "#") -+ -+ -+(define_insn "xorqi3" -+ [(set (match_operand:QI 0 "register_operand" "=q,q,q,q") -+ (xor:QI (match_operand:QI 1 "whole_register_operand" "%0,0,0,0") -+ (match_operand:QI 2 "whole_general_operand" " O,N,m,i")))] -+ "" -+ "@ -+ \t;xorqi(ZERO) -+ com%0\t;xorqi(-1) -+ eor%0\t%2 -+ eor%0\t%2" -+ [(set_attr "length" "0,1,3,2")]) -+ -+;;-------------------------------------------------------------------- -+;;- Two's Complements -+;;-------------------------------------------------------------------- -+ -+(define_insn "neghi2" -+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,!a") -+ (neg:HI (match_operand:HI 1 "general_operand" "0, 0")))] -+ "" -+ "@ -+ nega\;negb\;sbca\t#0 -+ exg\td,%0\;nega\;negb\;sbca\t#0\;exg\td,%0" -+ [(set_attr "length" "5,9")]) -+ -+ -+(define_insn "negqi2" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m") -+ (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")))] -+ "" -+ "@ -+ neg%0 -+ neg\t%0" -+ [(set_attr "length" "1,3")]) -+ -+ -+;;-------------------------------------------------------------------- -+;;- One's Complements -+;;-------------------------------------------------------------------- -+ -+(define_insn "one_cmplhi2" -+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,?tm,???a") -+ (not:HI (match_operand:HI 1 "general_operand" "0, 0, 0")))] -+ "" -+ "@ -+ coma\;comb -+ com\t%0\;com\t%L0 -+ exg\td,%0\;coma\;comb\;exg\td,%0" -+ [(set_attr "length" "2,6,6")]) -+ -+ -+(define_insn "one_cmplqi2" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m") -+ (not:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")))] -+ "" -+ "@ -+ com%0 -+ com\t%0" -+ [(set_attr "length" "1,3")]) -+ -+;;-------------------------------------------------------------------- -+;;- Shifts/rotates -+;;-------------------------------------------------------------------- -+ -+(define_code_iterator bit_code [ashift ashiftrt lshiftrt]) -+(define_code_attr bit_code_name [(ashift "ashl") (ashiftrt "ashr") (lshiftrt "lshr")]) -+ -+(define_mode_iterator bit_mode [QI HI]) -+(define_mode_attr bit_mode_name [(QI "qi3") (HI "hi3")]) -+ -+;; Emit RTL for any shift (handles all 3 opcodes and 2 mode sizes) -+ -+(define_expand "<bit_code:bit_code_name><bit_mode:bit_mode_name>" -+ [(set (match_operand:bit_mode 0 "nonimmediate_operand" "") -+ (bit_code:bit_mode (match_operand:bit_mode 1 "general_operand" "") -+ (match_operand:bit_mode 2 "nonmemory_operand" "")))] -+ "" -+{ -+}) -+ -+; Individual instructions implemented in the CPU. -+ -+ -+(define_insn "*ashift1" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=m,q") -+ (ashift:QI (match_operand:QI 1 "general_operand" "0,0") (const_int 1)))] -+ "" -+ "@ -+ asl\t%0 -+ asl%0" -+ [(set_attr "length" "3,1")]) -+ -+(define_insn "*lshiftrt1" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=m,q") -+ (lshiftrt:QI (match_operand:QI 1 "general_operand" "0,0") (const_int 1)))] -+ "" -+ "@ -+ lsr\t%0 -+ lsr%0" -+ [(set_attr "length" "3,1")]) -+ -+(define_insn "*ashiftrt1" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=m,q") -+ (ashiftrt:QI (match_operand:QI 1 "general_operand" "0,0") (const_int 1)))] -+ "" -+ "@ -+ asr\t%0 -+ asr%0" -+ [(set_attr "length" "3,1")]) -+ -+(define_insn "*rotate1" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=m,q") -+ (rotate:QI (match_operand:QI 1 "general_operand" "0,0") (const_int 1)))] -+ "" -+ "@ -+ rol\t%0 -+ rol%0" -+ [(set_attr "length" "3,1")]) -+ -+ -+(define_insn "*rotatert1" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=m,q") -+ (rotatert:QI (match_operand:QI 1 "general_operand" "0,0") (const_int 1)))] -+ "" -+ "@ -+ ror\t%0 -+ ror%0" -+ [(set_attr "length" "3,1")]) -+ -+ -+; A shift by 8 for D reg can be optimized by just moving -+; between the A/B halves, and then zero/sign extending or -+; filling in zeroes. -+; Because GCC does not understand that 'A' and 'D' refer to -+; the same storage location, we must use 'USE' throughout -+; to prevent deletion of 'unnecessary' instructions. -+; Similar optimization for MEM would require a scratch register -+; so is not done here. -+ -+(define_split -+ [(set (reg:HI HARD_D_REGNUM) (ashift:HI (reg:HI HARD_D_REGNUM) (const_int 8)))] -+ "reload_completed" -+ [ -+ (use (reg:HI HARD_D_REGNUM)) -+ (set (reg:QI HARD_A_REGNUM) (reg:QI HARD_D_REGNUM)) -+ (use (reg:QI HARD_A_REGNUM)) -+ (set (reg:QI HARD_D_REGNUM) (const_int 0)) -+ ] -+ "") -+ -+(define_split -+ [(set (reg:HI HARD_D_REGNUM) (lshiftrt:HI (reg:HI HARD_D_REGNUM) (const_int 8)))] -+ "reload_completed" -+ [ -+ (use (reg:HI HARD_D_REGNUM)) -+ (set (reg:QI HARD_D_REGNUM) (reg:QI HARD_A_REGNUM)) -+ (use (reg:QI HARD_D_REGNUM)) -+ (set (reg:HI HARD_D_REGNUM) (zero_extend:HI (reg:QI HARD_D_REGNUM))) -+ ] -+ "") -+ -+(define_split -+ [(set (reg:HI HARD_D_REGNUM) (ashiftrt:HI (reg:HI HARD_D_REGNUM) (const_int 8)))] -+ "reload_completed" -+ [ -+ (use (reg:HI HARD_D_REGNUM)) -+ (set (reg:QI HARD_D_REGNUM) (reg:QI HARD_A_REGNUM)) -+ (use (reg:QI HARD_D_REGNUM)) -+ (set (reg:HI HARD_D_REGNUM) (sign_extend:HI (reg:QI HARD_D_REGNUM))) -+ ] -+ "") -+ -+ -+; On the WPC hardware, there is a shift register that can be used -+; to compute (1<<n) efficiently in two instructions. Note that this -+; form only works when using -mint8 though, because C will promote -+; to 'int' when doing this operation. TODO : we need a 16-bit form too. -+(define_insn "ashlqi3_wpc" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q") -+ (ashift:QI (match_operand:QI 1 "immediate_operand" "I") -+ (match_operand:QI 2 "general_operand" "q")))] -+ "TARGET_WPC" -+ "st%2\t0x3FF7\;ld%0\t0x3FF7" -+ [(set_attr "length" "6")]) -+ -+ -+; Internal instructions for shifting by a constant. -+; Two forms are provided, one for QImode, one for HImode. -+; These are always split into the above instructions -+; (except for QImode forms that directly match one of the -+; above instructions, in which the condition will not -+; allow the splitter to match). -+ -+(define_insn_and_split "<bit_code:bit_code_name>hi3_const" -+ [(set (match_operand:HI 0 "nonimmediate_operand" "=dm") -+ (bit_code:HI (match_operand:HI 1 "general_operand" "0") -+ (match_operand:HI 2 "immediate_operand" "n")))] -+ "" -+ "#" -+ "reload_completed" -+ [(const_int 0)] -+{ -+ m6809_split_shift (<bit_code:CODE>, operands); -+ DONE; -+}) -+ -+ -+(define_insn_and_split "<bit_code:bit_code_name>qi3_const" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") -+ (bit_code:QI (match_operand:QI 1 "general_operand" "0") -+ (match_operand:QI 2 "immediate_operand" "n")))] -+ "INTVAL (operands[2]) > 1" -+ "#" -+ "&& reload_completed" -+ [(const_int 0)] -+{ -+ m6809_split_shift (<bit_code:CODE>, operands); -+ DONE; -+}) -+ -+; Internal instructions for shifting by a nonconstant. -+; These expand into complex assembly. -+ -+(define_insn "<bit_code:bit_code_name>hi3_reg" -+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d") -+ (bit_code:HI (match_operand:HI 1 "general_operand" "0") -+ (match_operand:HI 2 "nonimmediate_operand" "v")))] -+ "" -+{ -+ m6809_output_shift_insn (<bit_code:CODE>, operands); -+ return ""; -+} -+ [(set_attr "length" "20")]) -+ -+ -+(define_insn "<bit_code:bit_code_name>qi3_reg" -+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q") -+ (bit_code:QI (match_operand:QI 1 "general_operand" "0") -+ (match_operand:QI 2 "nonimmediate_operand" "v")))] -+ "" -+{ -+ m6809_output_shift_insn (<bit_code:CODE>, operands); -+ return ""; -+} -+ [(set_attr "length" "16")]) -+ -+ -+ -+;;-------------------------------------------------------------------- -+;;- Jumps and transfers -+;;-------------------------------------------------------------------- -+ -+;;; The casesi pattern is normally *not* defined; see 'tablejump' instead. -+(define_expand "casesi" -+ [(match_operand:HI 0 "register_operand" "") ; index to jump on -+ (match_operand:HI 1 "immediate_operand" "") ; lower bound -+ (match_operand:HI 2 "immediate_operand" "") ; total range -+ (match_operand 3 "" "") ; table label -+ (match_operand 4 "" "")] ; out of range label -+ "TARGET_BYTE_INT && TARGET_CASESI" -+{ -+ m6809_do_casesi (operands[0], operands[1], operands[2], -+ operands[3], operands[4]); -+ DONE; -+}) -+ -+(define_insn "tablejump_short_offset" -+ [(set (pc) -+ (mem:HI (plus:HI (match_operand:HI 1 "register_operand" "U") -+ (zero_extend:HI (match_operand:QI 0 "register_operand" "q")))))] -+ "" -+ "jmp\t[b,x]\t;tablejump_short_offset" -+ [(set_attr "length" "3")]) -+ -+(define_insn "tablejump_long_offset" -+ [(set (pc) -+ (mem:HI (plus:HI (match_operand:HI 1 "register_operand" "U") -+ (match_operand:HI 0 "register_operand" "d"))))] -+ "" -+ "jmp\t[d,x]\t;tablejump_long_offset" -+ [(set_attr "length" "3")]) -+ -+ -+ ;; A tablejump operation gives the address in operand 0, with the -+ ;; CODE_LABEL for the table in operand 1. The 'define_expand' -+ ;; shows the arguments as GCC presents them. For a register -+ ;; operand, the assembly code is straightforward. For a MEM, -+ ;; assumed to be a SYMBOL_REF, two forms are given, one normal -+ ;; and one for PIC mode. -+ (define_expand "tablejump" -+ [(parallel [ -+ (set (pc) (match_operand:HI 0 "" "")) -+ (use (label_ref (match_operand 1 "" ""))) -+ (clobber (match_scratch:HI 2 "")) -+ ])] -+ "" -+ { -+ }) -+ -+ -+(define_insn "*tablejump_reg" -+ [(parallel [ -+ (set (pc) -+ (match_operand:HI 0 "register_operand" "a")) -+ (use (label_ref (match_operand 1 "" ""))) -+ (clobber (match_scratch:HI 2 "")) -+ ])] -+ "" -+ "jmp\t,%0" -+ [(set_attr "length" "3")]) -+ -+ -+(define_insn "*tablejump_symbol" -+ [(parallel [ -+ (set (pc) -+ (mem:HI -+ (plus:HI (match_operand:HI 0 "register_operand" "a") -+ (label_ref (match_operand 1 "" ""))))) -+ (use (label_ref (match_dup 1))) -+ (clobber (match_scratch:HI 2 "")) -+ ])] -+ "!flag_pic" -+{ -+ output_asm_insn ("jmp\t[%a1,%0]", operands); -+ return ""; -+} -+ [(set_attr "length" "4")]) -+ -+ -+(define_insn "*tablejump_symbol_pic" -+ [(parallel [ -+ (set (pc) -+ (mem:HI -+ (plus:HI (match_operand:HI 0 "register_operand" "d") -+ (label_ref (match_operand 1 "" ""))))) -+ (use (label_ref (match_dup 1))) -+ (clobber (match_scratch:HI 2 "=&a")) -+ ])] -+ "flag_pic" -+{ -+ output_asm_insn ("lea%2\t%a1,pcr", operands); -+ output_asm_insn ("ld%0\t%0,%2", operands); -+ output_asm_insn ("jmp\t%0,%2", operands); -+ return ""; -+} -+ [(set_attr "length" "8")]) -+ -+ -+(define_insn "indirect_jump" -+ [(set (pc) -+ (match_operand:HI 0 "register_operand" "a"))] -+ "" -+ "jmp\t,%0" -+ [(set_attr "length" "3")]) -+ -+ -+(define_insn "jump" -+ [(set (pc) (label_ref (match_operand 0 "" "")))] -+ "" -+{ -+ return output_branch_insn ( LABEL_REF, operands, get_attr_length (insn)); -+} -+ [(set (attr "type") (const_string "branch"))]) -+ -+; Output assembly for a condition branch instruction. -+(define_insn "*cond_branch" -+ [(set (pc) -+ (if_then_else -+ (match_operator 1 "comparison_operator" [(cc0) (const_int 0)]) -+ (label_ref (match_operand 0 "" "")) (pc)))] -+ "" -+{ -+ return output_branch_insn ( GET_CODE(operands[1]), -+ operands, get_attr_length (insn)); -+} -+ [(set (attr "type") (const_string "cbranch"))]) -+ -+ -+; Similar to above, but for a condition branch instruction that -+; had its operands reversed at some point. -+(define_insn "*cond_branch_reverse" -+ [(set (pc) -+ (if_then_else -+ (match_operator 1 "comparison_operator" [(cc0) (const_int 0)]) -+ (pc) (label_ref (match_operand 0 "" ""))))] -+ "" -+{ -+ return output_branch_insn ( reverse_condition (GET_CODE(operands[1])), -+ operands, get_attr_length (insn)); -+} -+ [(set (attr "type") (const_string "cbranch"))]) -+ -+ -+ -+;;-------------------------------------------------------------------- -+;;- Calls -+;;-------------------------------------------------------------------- -+ -+;; Generate a call instruction for a function that does not -+;; return a value. The expander is used during RTL generation. -+;; The instructions below are used during matching; only one -+;; of them will be used, depending on the type of function -+;; being called. The different conditions are: -+;; -+;; 1) far_functionp - is this a far function? Those need -+;; to be output as indirect calls through a far-function -+;; handler. -+;; -+;; 2) noreturn_functionp - if the function does not return, -+;; we can use a 'jmp' instead of a 'jsr' to call it. -+;; -+;; 3) is PIC mode enabled? If so, we'll always use -+;; relative calls (lbsr or lbra). -+;; -+;; Note: not all combinations are fully supported, especially -+;; relating to PIC. -+;; -+;; The 'bsr' instruction is never generated. -+ -+(define_expand "call" -+ [(call (match_operand:HI 0 "memory_operand" "") -+ (match_operand:HI 1 "general_operand" ""))] -+ "" -+ "") -+ -+(define_insn "*call_nopic_far" -+ [(call (match_operand:HI 0 "memory_operand" "m") -+ (match_operand:HI 1 "general_operand" "g"))] -+ "far_functionp (operands[0])" -+{ -+ output_far_call_insn (operands, 0); -+ return ""; -+} -+ [(set_attr "length" "6")]) -+ -+ -+; PIC forms come first, and should only match -+; (MEM (SYMBOL_REF)). Other MEM forms are treated as usual. -+(define_insn "*call_pic" -+ [(call (mem:HI (match_operand:HI 0 "symbolic_operand" "")) -+ (match_operand:HI 1 "general_operand" "g"))] -+ "flag_pic && !noreturn_functionp (operands[0])" -+ "lbsr\t%C0" -+ [(set_attr "length" "4")]) -+ -+ -+(define_insn "*call_nopic" -+ [(call (match_operand:HI 0 "memory_operand" "m") -+ (match_operand:HI 1 "general_operand" "g"))] -+ "!noreturn_functionp (operands[0])" -+ "jsr\t%0" -+ [(set_attr "length" "3") -+ (set (attr "cycles") (const_int JSR_EXTENDED_CYCLES))]) -+ -+ -+(define_insn "*call_noreturn_pic" -+ [(call (mem:HI (match_operand:HI 0 "symbolic_operand" "")) -+ (match_operand:HI 1 "general_operand" "g"))] -+ "flag_pic && noreturn_functionp (operands[0])" -+ "lbra\t%C0" -+ [(set_attr "length" "4")]) -+ -+ -+(define_insn "*call_noreturn_nopic" -+ [(call (match_operand:HI 0 "memory_operand" "m") -+ (match_operand:HI 1 "general_operand" "g"))] -+ "noreturn_functionp (operands[0])" -+ "jmp\t%0" -+ [(set_attr "length" "3")]) -+ -+ -+;; -+;; Same as above, but for functions that do return a value. -+;; -+(define_expand "call_value" -+ [(set (match_operand 0 "" "") -+ (call (match_operand:HI 1 "memory_operand" "") -+ (match_operand:HI 2 "general_operand" "")))] -+ "" -+ "") -+ -+ -+(define_insn "*call_value_far" -+ [(set (match_operand 0 "" "=gz") -+ (call (match_operand:HI 1 "memory_operand" "m") -+ (match_operand:HI 2 "general_operand" "g")))] -+ "far_functionp (operands[1])" -+{ -+ output_far_call_insn (operands, 1); -+ return ""; -+} -+ [(set_attr "length" "6")]) -+ -+ -+(define_insn "*call_value_pic" -+ [(set (match_operand 0 "" "=gz") -+ (call (mem:HI (match_operand:HI 1 "symbolic_operand" "")) -+ (match_operand:HI 2 "general_operand" "g")))] -+ "flag_pic" -+ "lbsr\t%C1" -+ [(set_attr "length" "4")]) -+ -+ -+(define_insn "*call_value_nopic" -+ [(set (match_operand 0 "" "=gz") -+ (call (match_operand:HI 1 "memory_operand" "m") -+ (match_operand:HI 2 "general_operand" "g")))] -+ "" -+ "jsr\t%1" -+ [(set_attr "length" "3") -+ (set (attr "cycles") (const_int JSR_EXTENDED_CYCLES))]) -+ -+ -+ -+;; -+;; How to generate an untyped call. -+;; -+(define_expand "untyped_call" -+ [(parallel [(call (match_operand 0 "" "") -+ (const_int 0)) -+ (match_operand 1 "" "") -+ (match_operand 2 "" "")])] -+ "" -+{ -+ int i; -+ -+ emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx)); -+ for (i=0; i < XVECLEN (operands[2], 0); i++) -+ { -+ rtx set = XVECEXP (operands[2], 0, i); -+ emit_move_insn (SET_DEST (set), SET_SRC (set)); -+ } -+ emit_insn (gen_blockage ()); -+ DONE; -+}) -+ -+ -+(define_expand "sibcall" -+ [(parallel -+ [(call (match_operand:HI 0 "memory_operand" "") -+ (match_operand:HI 1 "immediate_operand" "")) -+ (use (reg:HI HARD_PC_REGNUM))])] -+ "" -+ "") -+ -+(define_insn "*sibcall_1" -+ [(parallel -+ [(call (match_operand:HI 0 "memory_operand" "m") -+ (match_operand:HI 1 "immediate_operand" "i")) -+ (use (reg:HI HARD_PC_REGNUM))])] -+ "SIBLING_CALL_P(insn)" -+ "jmp\t%0" -+ [(set_attr "length" "4")]) -+ -+ -+(define_expand "sibcall_value" -+ [(parallel -+ [(set (match_operand 0 "" "") -+ (call (match_operand:HI 1 "memory_operand" "") -+ (match_operand:HI 2 "immediate_operand" ""))) -+ (use (reg:HI HARD_PC_REGNUM))])] -+ "" -+ "") -+ -+(define_insn "*sibcall_value_1" -+ [(parallel -+ [(set (match_operand 0 "" "=gz") -+ (call (match_operand:HI 1 "memory_operand" "m") -+ (match_operand:HI 2 "immediate_operand" "i"))) -+ (use (reg:HI HARD_PC_REGNUM))])] -+ "SIBLING_CALL_P(insn)" -+ "jmp\t%1" -+ [(set_attr "length" "4")]) -+ -+ -+;;-------------------------------------------------------------------- -+;;- Function Entry and Exit -+;;-------------------------------------------------------------------- -+ -+;; On entry to a function, the stack frame looks as follows: -+;; - return address (pushed by the caller) -+;; - saved registers -+;; - local variable storage -+;; -+;; If the function does not modify the stack after that, then -+;; any of these can be accessed directly as an offset from -+;; STACK_POINTER_REGNUM. Otherwise, a frame pointer is required. -+;; In that case, the prologue must also initialize HARD_FRAME_POINTER_REGNUM -+;; and all references to the stack frame will use that as a base instead. -+;; -+(define_expand "prologue" -+ [(const_int 0)] -+ "prologue_epilogue_required ()" -+{ -+ emit_prologue_insns (); -+ DONE; -+}) -+ -+ -+;; The function epilogue does exactly the reverse of the prologue, -+;; deallocating local variable space, restoring saved registers, -+;; and returning. -+;; -+;; For the 6809, the return may be 'rti' if the function was -+;; declared as an interrupt function, but is normally 'rts'. -+;; -+;; Also, as an optimization, the register restore and the 'rts' -+;; can be combined into a single instruction, by adding 'PC' to the -+;; list of registers to be restored. This is only done if there are -+;; any saved registers, as 'rts' is more efficient by itself. -+;; -+(define_expand "epilogue" -+ [(const_int 0)] -+ "prologue_epilogue_required ()" -+{ -+ emit_epilogue_insns (false); -+ DONE; -+}) -+ -+ -+(define_expand "sibcall_epilogue" -+ [(const_int 0)] -+ "prologue_epilogue_required ()" -+{ -+ emit_epilogue_insns (true); -+ DONE; -+}) -+ -+ -+;; The RTS instruction -+(define_insn "return_rts" -+ [(return) -+ (use (reg:HI HARD_PC_REGNUM))] -+ "!m6809_current_function_has_type_attr_p (\"interrupt\") -+ && m6809_get_live_regs () == 0" -+ "rts" -+ [(set_attr "length" "1") -+ (set (attr "cycles") (const_int RTS_CYCLES))]) -+ -+(define_insn "return_puls_pc" -+ [(return) -+ (use (reg:HI HARD_PC_REGNUM))] -+ "!m6809_current_function_has_type_attr_p (\"interrupt\") -+ && m6809_get_live_regs () != 0" -+ "" -+ [(set_attr "length" "1") -+ (set (attr "cycles") (const_int RTS_CYCLES))]) -+ -+;; The RTI instruction -+(define_insn "return_rti" -+ [(return) -+ (use (reg:HI HARD_PC_REGNUM))] -+ "m6809_current_function_has_type_attr_p (\"interrupt\")" -+ "rti" -+ [(set_attr "length" "1") -+ (set (attr "cycles") (const_int RTI_CYCLES))]) -+ -+ -+;;-------------------------------------------------------------------- -+;;- Unspecified instructions -+;;-------------------------------------------------------------------- -+ -+;; An instruction that has the effect of an unspec_volatile, but -+;; which doesn't require emitting any assembly code. -+(define_insn "blockage" -+ [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] -+ "" -+ "" -+ [(set_attr "length" "0") -+ (set (attr "cycles") (const_int 0))]) -+ -+ -+;; Say how to push multiple registers onto the stack, using -+;; the 6809 'pshs' instruction. The operand is a regset -+;; specifying which registers to push. -+;; -+;; The operand mode is not given intentionally, so as to allow -+;; any possible integer mode for the regset. -+;; -+;; See below for a peephole that can combine consecutive push -+;; instructions that qualify for merging. -+(define_insn "register_push" -+ [(use (reg:HI HARD_S_REGNUM)) -+ (unspec_volatile -+ [(match_operand 0 "immediate_operand" "")] UNSPEC_PUSH_RS) -+ (clobber (reg:HI HARD_S_REGNUM))] -+ "" -+ "pshs\t%R0" -+ [(set_attr "length" "2") -+ (set (attr "cycles") (const_int PSH_PUL_CYCLES))]) -+ -+ -+;; Say how to pop multiple registers from the stack, using -+;; the 6809 'puls' instruction. The operand is the register -+;; bitset value. -+(define_insn "register_pop" -+ [(use (reg:HI HARD_S_REGNUM)) -+ (unspec_volatile -+ [(match_operand 0 "immediate_operand" "")] UNSPEC_POP_RS) -+ (clobber (reg:HI HARD_S_REGNUM))] -+ "" -+ "puls\t%R0" -+ [(set_attr "length" "2") -+ (set (attr "cycles") (const_int PSH_PUL_CYCLES))]) -+ -+ -+(define_insn "m6809_swi" -+ [(unspec_volatile -+ [(match_operand:QI 0 "immediate_operand" "I,n")] UNSPEC_SWI)] -+ "" -+ "@ -+ swi -+ swi%c0" -+ [(set_attr "length" "1,2") -+ (set (attr "cycles") (const_int SWI_CYCLES))]) -+ -+ -+;; Generate the CWAI instruction -+(define_insn "m6809_cwai" -+ [(unspec_volatile -+ [(match_operand:QI 0 "immediate_operand" "")] UNSPEC_CWAI)] -+ "" -+ "cwai\t%0" -+ [(set_attr "length" "2") -+ (set (attr "cycles") (const_int CWAI_CYCLES))]) -+ -+ -+;; Generate the SYNC instruction -+(define_insn "m6809_sync" -+ [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)] -+ "" -+ "sync" -+ [(set_attr "length" "1") -+ (set (attr "cycles") (const_int SYNC_CYCLES))]) -+ -+ -+;; Generate the NOP instruction -+(define_insn "nop" -+ [(const_int 0)] -+ "" -+ "nop" -+ [(set_attr "length" "1") -+ (set (attr "cycles") (const_int NOP_CYCLES))]) -+ -+ -+;;-------------------------------------------------------------------- -+;;- Peepholes -+;;-------------------------------------------------------------------- -+ -+;;; Each peephole has an ID that is used for debugging. -+;;; Each peephole condition is bracketed by calls to -+;;; m6809_match_peephole2() also for debugging. -+(define_constants [ -+ (PEEP_END 0) -+ (PEEP_COND 1) -+ -+ (PEEP_STACK_STORE_INC 0) -+ (PEEP_STACK_CLEAR_INC 1) -+ (PEEP_LSRB_ADCB 2) -+ (PEEP_ABX 3) -+ (PEEP_ABX2 4) -+ (PEEP_INDEXED_INC 5) -+ (PEEP_MEM_DEC 6) -+ (PEEP_MEM_INC 7) -+ (PEEP_MEM_DEC_CMP 8) -+ (PEEP_PUSH2 9) -+ (PEEP_STORE_IMPLIES_CC 10) -+ (PEEP_DEC_IMPLIES_CC 11) -+ (PEEP_LEAB 12) -+ (PEEP_LDX_INDIRECT 13) -+ (PEEP_POP_JUNK 14) -+]) -+ -+ -+;;; Optimize 'leas -1,s' followed by 'stb ,s'. This can happen if the -+;;; function prologue needs to allocate stack space and 'b' is placed -+;;; into that local right away. Combine the stack allocation with the -+;;; store using preincrement mode. -+(define_peephole2 -+ [(set (reg:HI HARD_S_REGNUM) -+ (plus:HI (reg:HI HARD_S_REGNUM) (const_int -1))) -+ (set (mem:QI (reg:HI HARD_S_REGNUM)) -+ (match_operand:QI 0 "register_operand" ""))] -+ "m6809_match_peephole2 (PEEP_STACK_STORE_INC, PEEP_END)" -+ [(set (mem:QI (pre_dec:HI (reg:HI HARD_S_REGNUM))) (match_dup 0))] -+ "") -+ -+ -+;;; Same as above, but for a 'clr ,s' that follows the prologue. -+(define_peephole2 -+ [(set (reg:HI HARD_S_REGNUM) (plus:HI (reg:HI HARD_S_REGNUM) (const_int -1))) -+ (set (mem:QI (reg:HI HARD_S_REGNUM)) (const_int 0))] -+ "m6809_match_peephole2 (PEEP_STACK_CLEAR_INC, PEEP_END)" -+ [(set (mem:QI (pre_dec:HI (reg:HI HARD_S_REGNUM))) (const_int 0))] -+ "") -+ -+ -+;;; Merge two consecutive push instructions into a single register_push. -+(define_peephole2 -+ [(set (match_operand 0 "push_operand" "") -+ (match_operand 1 "register_operand" "")) -+ (set (match_operand 2 "push_operand" "") -+ (match_operand 3 "register_operand" ""))] -+ "m6809_match_peephole2 (PEEP_PUSH2, PEEP_COND) -+ && reload_completed -+ && GET_MODE (operands[1]) == GET_MODE (operands[3]) -+ && m6809_can_merge_pushpop_p (UNSPEC_PUSH_RS, 1 << REGNO (operands[1]), 1 << REGNO (operands[3])) -+ && m6809_match_peephole2 (PEEP_PUSH2, PEEP_END)" -+ [(parallel [ -+ (use (reg:HI HARD_S_REGNUM)) -+ (unspec_volatile [(match_dup 4)] UNSPEC_PUSH_RS) -+ (clobber (reg:HI HARD_S_REGNUM))]) -+ (use (match_dup 1)) -+ (use (match_dup 3))] -+{ -+ operands[4] = gen_rtx_CONST_INT (QImode, -+ (1 << REGNO (operands[1])) | (1 << REGNO (operands[3]))); -+}) -+ -+ -+;;; Convert 'stX ,--s' into a push instruction. Use the regset -+;;; notation, so that it may be combined with an adjacent regset. -+;;; TBD - this doesn't compile some code cleanly. -+;(define_peephole2 -+; [(set (mem:HI (pre_dec:HI (reg:HI HARD_S_REGNUM))) -+; (reg:HI HARD_X_REGNUM))] -+; "reload_completed" -+; [(parallel [ -+; (use (reg:HI HARD_S_REGNUM)) -+; (unspec_volatile [(match_dup 0)] UNSPEC_PUSH_RS) -+; (clobber (reg:HI HARD_S_REGNUM))])] -+;{ -+; operands[0] = gen_rtx_CONST_INT (HImode, X_REGBIT); -+;}) -+ -+ -+;;; -+;;; q = (q+1)/2 can be optimized as "lsrb; adcb". This also -+;;; won't overflow when q=0xFF. -+;;; TODO : this form isn't accounting for promotion when -+;;; using 16-bit ints. -+;;; -+(define_peephole -+ [(set (reg:QI HARD_D_REGNUM) -+ (lshiftrt:QI (plus:HI (match_dup 0) (const_int 1)) (const_int 1)))] -+ "m6809_match_peephole2 (PEEP_LSRB_ADCB, PEEP_END)" -+ "lsrb\;adcb\t#0; peephole" -+ [(set_attr "length" "2")]) -+ -+ -+;; -+;; Optimize the case of following a register store with a test -+;; of reg or mem just moved. -+;; -+(define_peephole -+ [(set (match_operand:HI 0 "memory_operand" "=m") -+ (match_operand:HI 1 "register_operand" "r")) -+ (set (cc0) (match_operand:HI 2 "general_operand" "g"))] -+ "m6809_match_peephole2 (PEEP_STORE_IMPLIES_CC, PEEP_COND) -+ && (operands[2] == operands[0] || operands[2] == operands[1]) -+ && m6809_match_peephole2 (PEEP_STORE_IMPLIES_CC, PEEP_END)" -+ "st%1\t%0\t;movhi: R:%1 -> %0 w/ implied test of %2" -+ [(set_attr "length" "4")]) -+ -+ -+;; Optimize a pair of SET instructions in which the second insn -+;; is the reverse of the first one. I.e. -+;; -+;; A = B -+;; ----> A = B -+;; B = A -+;; -+;; The second insn is redundant. Define two patterns, one for QI, one for HI. -+;; But don't do this if either is a VOLATILE MEM. -+(define_peephole2 -+ [(set (match_operand:HI 0 "nonimmediate_operand" "") -+ (match_operand:HI 1 "nonimmediate_operand" "")) -+ (set (match_dup 1) (match_dup 0))] -+ "!MEM_P (operands[0]) || !MEM_P (operands[1]) || (!MEM_VOLATILE_P (operands[0]) && !MEM_VOLATILE_P (operands[1]))" -+ [(set (match_dup 0) (match_dup 1))] -+ "") -+ -+(define_peephole2 -+ [(set (match_operand:QI 0 "nonimmediate_operand" "") -+ (match_operand:QI 1 "nonimmediate_operand" "")) -+ (set (match_dup 1) (match_dup 0))] -+ "!MEM_P (operands[0]) || !MEM_P (operands[1]) || (!MEM_VOLATILE_P (operands[0]) && !MEM_VOLATILE_P (operands[1]))" -+ [(set (match_dup 0) (match_dup 1))] -+ "") -+ -+ -+;; -+;; Optimize the sum of an 8-bit and 16-bit using the 'abx' instruction -+;; if B and X can be used. Two patterns are provided to catch both -+;; X=X+D and X=D+X. -+;; -+(define_peephole -+ [(set (reg:HI HARD_D_REGNUM) -+ (zero_extend:HI (match_operand:QI 0 "general_operand" "q"))) -+ (set (reg:HI HARD_X_REGNUM) -+ (plus:HI (reg:HI HARD_D_REGNUM) (reg:HI HARD_X_REGNUM)))] -+ "m6809_match_peephole2 (PEEP_ABX, PEEP_END)" -+ "abx" -+ [(set_attr "length" "1")]) -+ -+(define_peephole -+ [(set (reg:HI HARD_D_REGNUM) -+ (zero_extend:HI (match_operand:QI 0 "general_operand" "q"))) -+ (set (reg:HI HARD_X_REGNUM) -+ (plus:HI (reg:HI HARD_X_REGNUM) (reg:HI HARD_D_REGNUM)))] -+ "m6809_match_peephole2 (PEEP_ABX, PEEP_END)" -+ "abx" -+ [(set_attr "length" "1")]) -+ -+;;; Likewise, handle when B is scaled by 2 prior to the add. -+;;; Instead of shifting B in 4 cycles, just do the ABX a second -+;;; time, in only 3 cycles. -+ -+(define_peephole -+ [(set (reg:HI HARD_D_REGNUM) -+ (zero_extend:HI (match_operand:QI 0 "general_operand" "q"))) -+ (set (reg:HI HARD_D_REGNUM) -+ (ashift:HI (reg:HI HARD_D_REGNUM) (const_int 1))) -+ (set (reg:HI HARD_X_REGNUM) -+ (plus:HI (reg:HI HARD_D_REGNUM) (reg:HI HARD_X_REGNUM)))] -+ "m6809_match_peephole2 (PEEP_ABX2, PEEP_END)" -+ "abx\;abx" -+ [(set_attr "length" "2")]) -+ -+(define_peephole -+ [(set (reg:HI HARD_D_REGNUM) -+ (zero_extend:HI (match_operand:QI 0 "general_operand" "q"))) -+ (set (reg:HI HARD_D_REGNUM) -+ (ashift:HI (reg:HI HARD_D_REGNUM) (const_int 1))) -+ (set (reg:HI HARD_X_REGNUM) -+ (plus:HI (reg:HI HARD_X_REGNUM) (reg:HI HARD_D_REGNUM)))] -+ "m6809_match_peephole2 (PEEP_ABX2, PEEP_END)" -+ "abx\;abx" -+ [(set_attr "length" "2")]) -+ -+ -+;; -+;; Work around a compiler bug that generates bad code when copying -+;; between 32-bit memory addresses after a libcall. The problem seen is -+;; that the source is MEM (REG X), but X is used as the reload register. -+;; The second half of the copy therefore fails. -+;; -+;; The solution is to switch the reload register to D, since that is guaranteed -+;; not to be in use right after a libcall. -+;; -+(define_peephole2 -+ [(set (reg:HI HARD_X_REGNUM) (mem:HI (reg:HI HARD_X_REGNUM))) -+ (set (match_operand:HI 0 "nonimmediate_operand" "") (reg:HI HARD_X_REGNUM)) -+ (set (reg:HI HARD_X_REGNUM) -+ (mem:HI (plus:HI (reg:HI HARD_X_REGNUM) (const_int 2)))) -+ (set (match_operand:HI 1 "nonimmediate_operand" "") (reg:HI HARD_X_REGNUM))] -+ "reload_completed" -+ [(set (reg:HI HARD_D_REGNUM) (mem:HI (reg:HI HARD_X_REGNUM))) -+ (set (match_dup 0) (reg:HI HARD_D_REGNUM)) -+ (set (reg:HI HARD_X_REGNUM) -+ (mem:HI (plus:HI (reg:HI HARD_X_REGNUM) (const_int 2)))) -+ (set (match_dup 1) (reg:HI HARD_X_REGNUM))] -+ "") -+ -+ -+;; Turn "and then test" into a "bit test" operation. -+;; Provide variants for immediate and memory sources -+;; This is the most used peephople. -+; (define_peephole -+; [(set (match_operand:QI 0 "register_operand" "=q") -+; (and:QI (match_operand:QI 1 "register_operand" "0") -+; (match_operand:QI 2 "immediate_operand" "i"))) -+; (set (cc0) (match_dup 0))] -+; "" -+; "bit%0\t%2" -+; [(set_attr "length" "3")]) -+; -+; (define_peephole -+; [(set (match_operand:QI 0 "register_operand" "=q") -+; (and:QI (match_operand:QI 1 "register_operand" "0") -+; (match_operand:QI 2 "memory_operand" "m"))) -+; (set (cc0) (match_dup 0))] -+; "" -+; "bit%0\t%2" -+; [(set_attr "length" "4")]) -+ -+ -+;; Turn a "decrement, then test" sequence into just a "decrement". -+;; The test can be omitted, since it is implicitly done. -+(define_peephole2 -+ [(set (match_operand:QI 0 "nonimmediate_operand" "") -+ (plus:QI (match_operand:QI 1 "whole_general_operand" "") -+ (match_operand:QI 2 "immediate_operand" ""))) -+ (set (cc0) (match_dup 0))] -+ "m6809_match_peephole2 (PEEP_DEC_IMPLIES_CC, PEEP_END)" -+ [(set (match_dup 0) (plus:QI (match_dup 1) (match_dup 2)))] -+ "") -+ -+ -+;; Merge an indexed register increment with a previous usage. -+;; This is usually done automatically, but not always -+;; The 'use' should be optional; in all cases where this has been -+;; seen, it is required though. -+(define_peephole2 -+ [(set (match_operand:QI 0 "register_operand" "") -+ (mem:QI (match_operand:HI 1 "index_register_operand" ""))) -+ (use (match_dup 0)) -+ (set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))] -+ "m6809_match_peephole2 (PEEP_INDEXED_INC, PEEP_END)" -+ [(set (match_dup 0) (mem:QI (post_inc:HI (match_dup 1)))) -+ (use (match_dup 0))] -+ "") -+ -+ -+;;; Merge "ldX MEM; ldX ,X" into a single instruction using -+;;; the indirect mode. -+(define_peephole2 -+ [(set (reg:HI HARD_X_REGNUM) -+ (mem:HI (match_operand:HI 0 "general_operand" ""))) -+ (set (reg:HI HARD_X_REGNUM) (mem:HI (reg:HI HARD_X_REGNUM)))] -+ "reload_completed && m6809_match_peephole2 (PEEP_LDX_INDIRECT, PEEP_END)" -+ [(set (reg:HI HARD_X_REGNUM) -+ (mem:HI (mem:HI (match_dup 0))))] -+ "") -+ -+ -+;;; Reorder a store followed by a unary operation on that memory -+;;; so that the unary is performed and then the store. Consider -+;;; a binary shift operation, which will be decomposed into -+;;; identical single shifts, also. -+;;; TODO - recognize more than just 'ashift' here. -+(define_peephole2 -+ [(set (match_operand:QI 0 "memory_operand" "") -+ (match_operand:QI 1 "register_operand" "")) -+ (set (match_dup 0) -+ (ashift:QI (match_dup 0) (match_operand:QI 2 "immediate_operand")))] -+ "reload_completed" -+ [(set (match_dup 1) -+ (ashift:QI (match_dup 1) (match_operand:QI 2 "immediate_operand"))) -+ (set (match_dup 0) (match_dup 1))] -+ "") -+ -+;;; Likewise, reorder a unary MEM followed by a load, so that the load -+;;; is done first, then use the REG instead of the MEM. -+;;;(define_peephole2 -+;;; [(set (match_dup 0) -+;;; (ashift:QI (match_dup 0) (match_operand:QI 2 "immediate_operand"))) -+;;; (set (match_operand:QI 0 "register_operand" "") -+;;; (match_operand:QI 1 "memory_operand" ""))] -+;;; "reload_completed" -+;;; [(set (match_dup 0) (match_dup 1)) -+;;; (set (match_dup 0) -+;;; (ashift:QI (match_dup 0) (match_operand:QI 2 "immediate_operand")))] -+;;; "") -+ -+ -+;;; Replace sex; leaX d,Y with leaX b,Y. -+;;; -+(define_peephole2 -+ [(set (reg:HI HARD_D_REGNUM) (sign_extend:HI (reg:QI HARD_D_REGNUM))) -+ (set (match_operand:HI 0 "index_register_operand" "") -+ (plus:HI (match_operand:HI 1 "index_register_operand" "") -+ (reg:HI HARD_D_REGNUM)))] -+ "reload_completed && m6809_match_peephole2 (PEEP_LEAB, PEEP_END)" -+ [(set (match_dup 0) -+ (plus:HI (match_dup 1) (reg:QI HARD_D_REGNUM)))] -+ "") -+ -+(define_peephole2 -+ [(set (reg:HI HARD_D_REGNUM) (sign_extend:HI (reg:QI HARD_D_REGNUM))) -+ (set (match_operand:HI 0 "index_register_operand" "") -+ (plus:HI (reg:HI HARD_D_REGNUM) -+ (match_operand:HI 1 "index_register_operand" "")))] -+ "reload_completed && m6809_match_peephole2 (PEEP_LEAB, PEEP_END)" -+ [(set (match_dup 0) -+ (plus:HI (match_dup 1) (reg:QI HARD_D_REGNUM)))] -+ "") -+ -+ -+;;; Replace ldb; decb; stb; tstb with dec(mem). If the -+;;; register is not needed, then the load will get deleted -+;;; automatically, but it may be needed for comparisons. -+;;; Same for incb/inc. -+(define_peephole2 -+ [(set (match_operand:QI 0 "register_operand" "") -+ (match_operand:QI 1 "nonimmediate_operand" "")) -+ (set (match_dup 0) (plus:QI (match_dup 0) (const_int -1))) -+ (set (match_dup 1) (match_dup 0)) -+ (set (cc0) (match_dup 0))] -+ "m6809_match_peephole2 (PEEP_MEM_DEC_CMP, PEEP_END)" -+ [(set (match_dup 1) (plus:QI (match_dup 1) (const_int -1)))] -+ "") -+ -+ -+;;; Replace ldb; decb; stb with dec(mem); ldb. If the -+;;; register is not needed, then the load will get deleted -+;;; automatically, but it may be needed for comparisons. -+;;; Same for incb/inc. -+(define_peephole2 -+ [(set (match_operand:QI 0 "register_operand" "") -+ (match_operand:QI 1 "nonimmediate_operand" "")) -+ (set (match_dup 0) (plus:QI (match_dup 0) (const_int -1))) -+ (set (match_dup 1) (match_dup 0))] -+ "m6809_match_peephole2 (PEEP_MEM_DEC, PEEP_END)" -+ [(set (match_dup 1) (plus:QI (match_dup 1) (const_int -1))) -+ (set (match_dup 0) (match_dup 1))] -+ "") -+ -+(define_peephole2 -+ [(set (match_operand:QI 0 "register_operand" "") -+ (match_operand:QI 1 "nonimmediate_operand" "")) -+ (set (match_dup 0) (plus:QI (match_dup 0) (const_int 1))) -+ (set (match_dup 1) (match_dup 0))] -+ "m6809_match_peephole2 (PEEP_MEM_INC, PEEP_END)" -+ [(set (match_dup 1) (plus:QI (match_dup 1) (const_int 1))) -+ (set (match_dup 0) (match_dup 1))] -+ "") -+ -+ -+;;; Replace "andb #N; cmpb #N; bhi" with "andb #N", if it can be proven -+;;; that the branch can never occur because of the limited range of B. -+;;; N must be a power of two for this to make sense. This helps with -+;;; the default cases of switch statements on a value (x & N). -+(define_peephole2 -+ [(set (match_operand:QI 0 "register_operand" "") -+ (and:QI (match_dup 0) (match_operand:QI 1 "immediate_operand" ""))) -+ (set (cc0) -+ (compare (match_dup 0) (match_dup 1))) -+ (set (pc) (if_then_else (gtu (cc0) (const_int 0)) (match_operand 2 "" "") (match_operand 3 "" ""))) -+ ] -+ "reload_completed && power_of_two_p (INTVAL (operands[1]) + 1)" -+ [(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))] -+ "") -+ -+;;; Replace ldd <mem>; addd #1; std <mem> with 16-bit increment -+;;; of the mem, but only if D is dead. Same for 16-bit decrement. -+;;; <mem> must be offsettable for the instruction to match. -+(define_peephole2 -+ [(set (match_operand:HI 0 "register_operand" "") (match_operand:HI 1 "memory_operand" "")) -+ (set (match_dup 0) (plus:HI (match_dup 0) (const_int 1))) -+ (set (match_dup 1) (match_dup 0))] -+ "reload_completed -+ && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF -+ && peep2_reg_dead_p (3, operands[0])" -+ [(set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))] -+ "") -+ -+(define_peephole2 -+ [(set (match_operand:HI 0 "register_operand" "") (match_operand:HI 1 "memory_operand" "")) -+ (set (match_dup 0) (plus:HI (match_dup 0) (const_int -1))) -+ (set (match_dup 1) (match_dup 0))] -+ "reload_completed -+ && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF -+ && peep2_reg_dead_p (3, operands[0])" -+ [(set (match_dup 1) (plus:HI (match_dup 1) (const_int -1)))] -+ "") -+ -+ -+;;; Replace a load or store using an indexed register, followed by an increment of that -+;;; register, with the combined form using autoincrement. -+(define_peephole2 -+ [(set (match_operand:QI 0 "register_operand" "") -+ (mem:QI (match_operand:HI 1 "index_register_operand" ""))) -+ (set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))] -+ "reload_completed" -+ [(set (match_dup 0) (mem:QI (post_inc (match_dup 1))))] -+ "") -+ -+ -+;;- mode:emacs-lisp -+;;- comment-start: ";;- " -+;;- eval: (set-syntax-table (copy-sequence (syntax-table))) -+;;- eval: (modify-syntax-entry ?[ "(]") -+;;- eval: (modify-syntax-entry ?] ")[") -+;;- eval: (modify-syntax-entry ?{ "(}") -+;;- eval: (modify-syntax-entry ?} "){") -+;-; vim: set ts=2: -+;-; vim: set expandtab: -+;-; vim: set filetype=lisp: -+;;- End: -diff -urN gcc-4.6.4-clean/gcc/config/m6809/m6809.opt gcc-4.6.4/gcc/config/m6809/m6809.opt ---- gcc-4.6.4-clean/gcc/config/m6809/m6809.opt 1969-12-31 17:00:00.000000000 -0700 -+++ gcc-4.6.4/gcc/config/m6809/m6809.opt 2015-07-20 19:44:52.770843181 -0600 -@@ -0,0 +1,98 @@ -+; Options for the M6809 port of the compiler -+; -+; Copyright (C) 2005 Free Software Foundation, 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 2, or (at your option) any later -+; version. -+; -+; GCC is distributed in the hope that it will be useful, but WITHOUT -+; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -+; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -+; License for more details. -+; -+; You should have received a copy of the GNU General Public License -+; along with GCC; see the file COPYING. If not, write to the Free -+; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -+; 02110-1301, USA. -+ -+margcount -+Target Mask(ARGCOUNT) -+Push argument count -+ -+mint8 -+Target RejectNegative Mask(BYTE_INT) -+Use 8-bit integers -+ -+mint16 -+Target RejectNegative -+Use 16-bit integers InverseMask(BYTE_INT) -+ -+mreg-args -+Target Mask(REG_ARGS) -+Use registers for function arguments -+ -+mshort_size -+Target RejectNegative Mask(SMALL_SIZE_T) -+Use 8-bit size_t -+ -+mlong_size -+Target RejectNegative InverseMask(SMALL_SIZE_T) -+Use 16-bit size_t -+ -+mdirect -+Target Mask(DIRECT) -+Enable direct addressing -+ -+mwpc -+Target RejectNegative Mask(WPC) -+Enable WPC platform extensions -+ -+mexperiment -+Target RejectNegative Mask(EXPERIMENT) -+Enable current experimental feature -+ -+m6309 -+Target RejectNegative Mask(6309) -+Enable Hitachi 6309 extensions -+ -+mcasesi -+Target RejectNegative Mask(CASESI) -+Enable the casesi pattern -+ -+mfar-code-page= -+Target RejectNegative Joined Var(far_code_page_option) -+Sets the far code page value for this compilation unit -+ -+mcode-section= -+Target RejectNegative Joined Var(code_section_ptr) -+Sets the name of the section for code -+ -+mdata-section= -+Target RejectNegative Joined Var(data_section_ptr) -+Sets the name of the section for initialized data -+ -+mbss-section= -+Target RejectNegative Joined Var(bss_section_ptr) -+Sets the name of the section for uninitialized data -+ -+mabi_version= -+Target RejectNegative Joined Var(m6809_abi_version_ptr) -+Sets the calling convention -+ -+msoft-reg-count= -+Target RejectNegative Joined Var(m6809_soft_reg_count) -+Sets the number of soft registers that can be used -+ -+mdret -+Target RejectNegative Mask(DRET) -+Put function call results in D, not X -+ -+mfar-stack-param -+Target Mask(FAR_STACK_PARAM) -+Enable stack parameters to a farcall -+ -+ -diff -urN gcc-4.6.4-clean/gcc/config/m6809/m6809-protos.h gcc-4.6.4/gcc/config/m6809/m6809-protos.h ---- gcc-4.6.4-clean/gcc/config/m6809/m6809-protos.h 1969-12-31 17:00:00.000000000 -0700 -+++ gcc-4.6.4/gcc/config/m6809/m6809-protos.h 2015-07-20 19:44:52.770843181 -0600 -@@ -0,0 +1,94 @@ -+/* GCC for 6809 : machine-specific function prototypes -+ -+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 -+<http://www.gnu.org/licenses/>. */ -+ -+#ifndef __M6809_PROTOS_H__ -+#define __M6809_PROTOS_H__ -+ -+void print_options (FILE *file); -+void m6809_cpu_cpp_builtins (void); -+void m6809_override_options (void); -+void m6809_init_builtins (void); -+unsigned int m6809_get_live_regs (void); -+const char * m6809_get_regs_printable (unsigned int regs); -+unsigned int m6809_get_regs_size (unsigned int regs); -+int m6809_function_has_type_attr_p (tree decl, const char *); -+int m6809_current_function_has_type_attr_p (const char *); -+int prologue_epilogue_required (void); -+int noreturn_functionp (rtx x); -+void output_function_prologue (FILE *file, int size); -+void output_function_epilogue (FILE *file, int size); -+int check_float_value (enum machine_mode mode, double *d, int overflow); -+void m6809_asm_named_section (const char *name, unsigned int flags, tree decl); -+void m6809_asm_file_start (void); -+void m6809_output_ascii (FILE *fp, const char *str, unsigned long size); -+void m6809_declare_function_name (FILE *asm_out_file, const char *name, tree decl); -+void m6809_reorg (void); -+int m6809_current_function_is_void (void); -+int m6809_can_merge_pushpop_p (int op, int regs1, int regs2); -+int m6809_function_value_regno_p (unsigned int regno); -+void emit_prologue_insns (void); -+void emit_epilogue_insns (bool); -+void m6809_conditional_register_usage (void); -+void m6809_output_quoted_string (FILE *asm_file, const char *string); -+int m6809_match_peephole2 (unsigned int peephole_id, unsigned int stage); -+int m6809_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode); -+int power_of_two_p (unsigned int n); -+void m6809_do_casesi (rtx index, rtx lower_bound, rtx range, rtx table_label, rtx default_label); -+void m6809_output_addsi3 (int rtx_code, rtx *operands); -+rtx m6809_function_arg_on_stack (CUMULATIVE_ARGS *cump); -+void expand_constant_shift (int code, rtx dst, rtx src, rtx count); -+int m6809_single_operand_operator (rtx exp); -+ -+#ifdef TREE_CODE -+int m6809_init_cumulative_args (CUMULATIVE_ARGS cum, tree fntype, rtx libname); -+#endif /* TREE_CODE */ -+ -+#ifdef RTX_CODE -+void print_direct_prefix (FILE *file, rtx addr); -+void print_operand (FILE *file, rtx x, int code); -+void print_operand_address (FILE *file, rtx addr); -+void notice_update_cc (rtx exp, rtx insn); -+enum reg_class m6809_preferred_reload_class (rtx x, enum reg_class regclass); -+rtx gen_rtx_const_high (rtx r); -+rtx gen_rtx_const_low (rtx r); -+rtx gen_rtx_register_pushpop (int pop_flag, int regs); -+void emit_libcall_insns (enum machine_mode mode, const char *name, rtx *operands, int count); -+const char * output_branch_insn (enum rtx_code code, rtx *operands, int length); -+void output_far_call_insn (rtx *operands, int has_return); -+void m6809_initialize_trampoline (rtx tramp, tree fndecl, rtx cxt); -+rtx m6809_expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, int ignore); -+const char * far_functionp (rtx x); -+rtx m6809_function_value (const tree valtype, const tree func); -+void m6809_output_shift_insn (int rtx_code, rtx *operands); -+ -+const char * m6809_get_decl_bank (tree decl); -+void output_branch_insn1 (const char *opcode, rtx *operands, int long_p); -+rtx m6809_builtin_operand (tree arglist, enum machine_mode mode, int opnum); -+const char * far_function_type_p (tree type); -+void m6809_asm_trampoline_template(FILE *f); -+bool m6809_frame_pointer_required (void); -+int m6809_can_eliminate (int from, int to); -+int m6809_initial_elimination_offset (int from, int to); -+void m6809_emit_move_insn (rtx dst, rtx src); -+void m6809_split_shift (enum rtx_code code, rtx *operands); -+bool m6809_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED); -+ -+ -+#endif /* RTX_CODE */ -+ -+#endif /* __M6809_PROTOS_H__ */ -diff -urN gcc-4.6.4-clean/gcc/config/m6809/predicates.md gcc-4.6.4/gcc/config/m6809/predicates.md ---- gcc-4.6.4-clean/gcc/config/m6809/predicates.md 1969-12-31 17:00:00.000000000 -0700 -+++ gcc-4.6.4/gcc/config/m6809/predicates.md 2015-07-20 19:44:52.770843181 -0600 -@@ -0,0 +1,78 @@ -+;; Predicate definitions for Motorola 6809 -+;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, 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 -+;; <http://www.gnu.org/licenses/>. -+ -+;; whole_register_operand is like register_operand, but it -+;; does not allow SUBREGs. -+(define_predicate "whole_register_operand" -+ (and (match_code "reg") -+ (match_operand 0 "register_operand"))) -+ -+ -+;; A predicate that matches any index register. This can be used in nameless -+;; patterns and peepholes which need a 16-bit reg, but not D. -+(define_predicate "index_register_operand" -+ (and (match_code "reg") -+ (match_test "REGNO (op) == HARD_X_REGNUM || REGNO (op) == HARD_Y_REGNUM || REGNO (op) == HARD_U_REGNUM"))) -+ -+ -+;; match only X -+(define_predicate "register_operand_x" -+ (and (match_code "reg") -+ (match_test "REGNO (op) == HARD_X_REGNUM"))) -+ -+;; match only D -+(define_predicate "register_operand_d" -+ (and (match_code "reg") -+ (match_test "REGNO (op) == HARD_D_REGNUM"))) -+ -+ -+;; Likwise, a replacement for general_operand which excludes -+;; SUBREGs. -+(define_predicate "whole_general_operand" -+ (and (match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem") -+ (match_operand 0 "general_operand"))) -+ -+ -+(define_predicate "add_general_operand" -+ (and (match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem") -+ (match_operand 0 "general_operand") -+ (match_test "REGNO (op) != SOFT_AP_REGNUM"))) -+ -+ -+(define_predicate "shift_count_operand" -+ (and (match_code "const_int") -+ (and (match_operand 0 "const_int_operand") -+ (match_test "INTVAL (op) == 1 || INTVAL (op) == 8")))) -+ -+ -+;; A predicate that matches any bitwise logical operator. This -+;; allows for a single RTL pattern to be used for multiple operations. -+(define_predicate "logical_bit_operator" -+ (ior (match_code "and") (match_code "ior") (match_code "xor"))) -+ -+ -+;; A predicate that matches any shift or rotate operator. This -+;; allows for a single RTL pattern to be used for multiple operations. -+(define_predicate "shift_rotate_operator" -+ (ior (match_code "ashift") (match_code "ashiftrt") (match_code "lshiftrt") -+ (match_code "rotate") (match_code "rotatert"))) -+ -+ -+(define_predicate "symbolic_operand" (match_code "symbol_ref")) -+ -diff -urN gcc-4.6.4-clean/gcc/config/m6809/t-coco gcc-4.6.4/gcc/config/m6809/t-coco ---- gcc-4.6.4-clean/gcc/config/m6809/t-coco 1969-12-31 17:00:00.000000000 -0700 -+++ gcc-4.6.4/gcc/config/m6809/t-coco 2015-07-20 19:44:52.770843181 -0600 -@@ -0,0 +1,6 @@ -+# For a few minor differences in code generation on the CoCo... -+T_CFLAGS = -DTARGET_COCO -+ -+# For doing the startup differently on the CoCo... -+CRT0STUFF_T_CFLAGS += -Wa,--globalize-symbols -DTARGET_COCO -+# vim: set filetype=make: -diff -urN gcc-4.6.4-clean/gcc/config/m6809/t-m6809 gcc-4.6.4/gcc/config/m6809/t-m6809 ---- gcc-4.6.4-clean/gcc/config/m6809/t-m6809 1969-12-31 17:00:00.000000000 -0700 -+++ gcc-4.6.4/gcc/config/m6809/t-m6809 2015-07-20 19:44:52.770843181 -0600 -@@ -0,0 +1,64 @@ -+ -+# ranlib doesn't exist, so define it to 'true' to make it a no-op -+RANLIB_FOR_TARGET = true -+ -+# Stubs for libgcc defined by m6809 are here -+LIB1ASMSRC = m6809/libgcc1.s -+ -+# Here are the functions that are implemented within libgcc1.s -+LIB1ASMFUNCS = _mulhi3 _divhi3 _modhi3 _udivhi3 _umodhi3 \ -+ _euclid _seuclid _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _softregs \ -+ _ashlhi3 _ashrhi3 _lshrhi3 -+ -+# Flags to use when building libgcc. IN_GCC does not seem necessary, -+# although the compile breaks without it. -DDF=SF is required to set -+# the size of "double" to the same as the size of a "float". -+TARGET_LIBGCC2_CFLAGS =-DIN_GCC -Dinhibit_libc -DDF=SF -DLIBGCC2_HAS_SF_MODE=0 -DLIBGCC2_HAS_DF_MODE=0 -+ -+LIB2ADDEH = -+LIB2ADDEHSTATIC = -+LIB2ADDEHSHARED = -+ -+LIBGCC2_DEBUG_CFLAGS = -+LIBGCC2_CFLAGS = -Os $(LIBGCC2_INCLUDES) $(TARGET_LIBGCC2_CFLAGS) $(LIBGCC2_DEBUG_CFLAGS) $(GTHREAD_FLAGS) -DIN_LIBGCC2 -+ -+# Multilib information -+# This creates multiple versions of libgcc.a for each set of incompatible -+# -mxxx options. -+MULTILIB_OPTIONS = fpic mdret -+MULTILIB_DIRNAMES = -+MULTILIB_MATCHES = -+MULTILIB_EXCEPTIONS = -+EXTRA_MULTILIB_PARTS = crt0.o -+ -+LIBGCC = stmp-multilib -+INSTALL_LIBGCC = install-multilib -+ -+# We want fine grained libraries, so use the new code to build the -+# floating point emulation libraries. -+FPBIT = fp-bit.c -+ -+fp-bit.c: $(srcdir)/config/fp-bit.c -+ echo '#define FLOAT' > fp-bit.c -+ echo '#define FLOAT_ONLY' >> fp-bit.c -+ echo '#define CMPtype HItype' >> fp-bit.c -+ echo '#define SMALL_MACHINE' >> fp-bit.c -+ echo '#ifdef __LITTLE_ENDIAN__' >> fp-bit.c -+ echo '#define FLOAT_BIT_ORDER_MISMATCH' >>fp-bit.c -+ echo '#endif' >> fp-bit.c -+ echo '#define DI SI' >> fp-bit.c -+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c -+ -+# crt0.o is built from the following source file -+CRT0_S = $(srcdir)/config/m6809/crt0.S -+MCRT0_S = $(srcdir)/config/m6809/crt0.S -+ -+# Flags to use when building crt0.o -+CRT0STUFF_T_CFLAGS += -fno-builtin -nostartfiles -nostdlib -+ -+# Assemble startup files. -+$(T)crt0.o: $(CRT0_S) $(GCC_PASSES) -+ $(GCC_FOR_TARGET) $(CRT0STUFF_T_CFLAGS) $(MULTILIB_CFLAGS) -c -o $(T)crt0.o -x assembler-with-cpp $(CRT0_S) -+ -+$(T)mcrt0.o: $(MCRT0_S) $(GCC_PASSES) -+ $(GCC_FOR_TARGET) $(CRT0STUFF_T_CFLAGS) $(MULTILIB_CFLAGS) -c -o $(T)mcrt0.o -x assembler-with-cpp $(MCRT0_S) -diff -urN gcc-4.6.4-clean/gcc/config/m6809/t-sim gcc-4.6.4/gcc/config/m6809/t-sim ---- gcc-4.6.4-clean/gcc/config/m6809/t-sim 1969-12-31 17:00:00.000000000 -0700 -+++ gcc-4.6.4/gcc/config/m6809/t-sim 2015-07-20 19:44:52.770843181 -0600 -@@ -0,0 +1 @@ -+CRT0STUFF_T_CFLAGS += -DTARGET_SIM -diff -urN gcc-4.6.4-clean/gcc/config.gcc gcc-4.6.4/gcc/config.gcc ---- gcc-4.6.4-clean/gcc/config.gcc 2013-03-06 10:40:07.000000000 -0700 -+++ gcc-4.6.4/gcc/config.gcc 2015-07-20 19:44:52.770843181 -0600 -@@ -375,6 +375,9 @@ - cpu_type=m32r - extra_options="${extra_options} g.opt" - ;; -+m6809-*-*) -+ cpu_type=m6809 -+ ;; - m68k-*-*) - extra_headers=math-68881.h - ;; -@@ -1706,6 +1709,12 @@ - thread_file='posix' - fi - ;; -+m6809-coco-*) -+ tmake_file="${tmake_file} m6809/t-m6809 m6809/t-coco" -+ ;; -+m6809-*-*) -+ tmake_file="${tmake_file} m6809/t-m6809 m6809/t-sim" -+ ;; - # m68hc11 and m68hc12 share the same machine description. - m68hc11-*-*|m6811-*-*) - tm_file="dbxelf.h elfos.h usegas.h newlib-stdint.h m68hc11/m68hc11.h" -diff -urN gcc-4.6.4-clean/gcc/gcse.c gcc-4.6.4/gcc/gcse.c ---- gcc-4.6.4-clean/gcc/gcse.c 2011-02-02 23:04:04.000000000 -0700 -+++ gcc-4.6.4/gcc/gcse.c 2015-07-20 19:44:52.770843181 -0600 -@@ -833,7 +833,6 @@ - max_distance = (GCSE_COST_DISTANCE_RATIO * cost) / 10; - if (max_distance == 0) - return 0; -- - gcc_assert (max_distance > 0); - } - else -diff -urN gcc-4.6.4-clean/gcc/libgcc2.c gcc-4.6.4/gcc/libgcc2.c ---- gcc-4.6.4-clean/gcc/libgcc2.c 2011-01-03 13:52:22.000000000 -0700 -+++ gcc-4.6.4/gcc/libgcc2.c 2015-07-20 19:44:52.770843181 -0600 -@@ -485,6 +485,7 @@ - #endif - - #ifdef L_bswapsi2 -+#if MIN_UNITS_PER_WORD > 1 - SItype - __bswapsi2 (SItype u) - { -@@ -494,7 +495,9 @@ - | (((u) & 0x000000ff) << 24)); - } - #endif -+#endif - #ifdef L_bswapdi2 -+#if LONG_LONG_TYPE_SIZE > 32 - DItype - __bswapdi2 (DItype u) - { -@@ -508,6 +511,7 @@ - | (((u) & 0x00000000000000ffull) << 56)); - } - #endif -+#endif - #ifdef L_ffssi2 - #undef int - int -@@ -1280,7 +1284,7 @@ - UDWtype - __fixunssfDI (SFtype a) - { --#if LIBGCC2_HAS_DF_MODE -+#if LIBGCC2_HAS_DF_MODE || (FLT_MANT_DIG >= W_TYPE_SIZE) - /* Convert the SFtype to a DFtype, because that is surely not going - to lose any bits. Some day someone else can write a faster version - that avoids converting to DFtype, and verify it really works right. */ -@@ -1298,7 +1302,7 @@ - - /* Assemble result from the two parts. */ - return ((UDWtype) hi << W_TYPE_SIZE) | lo; --#elif FLT_MANT_DIG < W_TYPE_SIZE -+#else - if (a < 1) - return 0; - if (a < Wtype_MAXp1_F) -@@ -1334,8 +1338,6 @@ - return (DWtype)counter << shift; - } - return -1; --#else --# error - #endif - } - #endif -diff -urN gcc-4.6.4-clean/gcc/longlong.h gcc-4.6.4/gcc/longlong.h ---- gcc-4.6.4-clean/gcc/longlong.h 2011-10-04 01:28:50.000000000 -0600 -+++ gcc-4.6.4/gcc/longlong.h 2015-07-20 19:44:52.770843181 -0600 -@@ -528,6 +528,11 @@ - : "cbit") - #endif /* __M32R__ */ - -+#if defined (__m6309__) || defined (__m6809__) -+#define count_leading_zeros(COUNT,X) ((COUNT) = __builtin_clz (X)) -+#define count_trailing_zeros(COUNT,X) ((COUNT) = __builtin_ctz (X)) -+#endif -+ - #if defined (__mc68000__) && W_TYPE_SIZE == 32 - #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ - __asm__ ("add%.l %5,%1\n\taddx%.l %3,%0" \ -diff -urN gcc-4.6.4-clean/gcc/Makefile.in gcc-4.6.4/gcc/Makefile.in ---- gcc-4.6.4-clean/gcc/Makefile.in 2013-04-01 02:32:34.000000000 -0600 -+++ gcc-4.6.4/gcc/Makefile.in 2015-07-20 19:44:52.770843181 -0600 -@@ -2003,14 +2003,14 @@ - - # Compile the start modules crt0.o and mcrt0.o that are linked with - # every program --$(T)crt0.o: s-crt0 ; @true --$(T)mcrt0.o: s-crt0; @true -+crt0.o: s-crt0 ; @true -+mcrt0.o: s-crt0; @true - - s-crt0: $(CRT0_S) $(MCRT0_S) $(GCC_PASSES) $(CONFIG_H) - $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(CRT0STUFF_T_CFLAGS) \ -- -o $(T)crt0.o -c $(CRT0_S) -+ -o crt0.o -c $(CRT0_S) - $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(CRT0STUFF_T_CFLAGS) \ -- -o $(T)mcrt0.o -c $(MCRT0_S) -+ -o mcrt0.o -c $(MCRT0_S) - $(STAMP) s-crt0 - # - # Compiling object files from source files. -diff -urN gcc-4.6.4-clean/gcc/opth-gen.awk gcc-4.6.4/gcc/opth-gen.awk ---- gcc-4.6.4-clean/gcc/opth-gen.awk 2011-02-08 10:41:00.000000000 -0700 -+++ gcc-4.6.4/gcc/opth-gen.awk 2015-07-20 19:44:52.774843181 -0600 -@@ -121,7 +121,7 @@ - END { - print "/* This file is auto-generated by opth-gen.awk. */" - print "" --print "#ifndef OPTIONS_H" -+print "#if !defined(OPTIONS_H) && !defined(IN_LIBGCC2)" - print "#define OPTIONS_H" - print "" - print "#include \"flag-types.h\"" -@@ -432,18 +432,9 @@ - - for (i = 0; i < n_opts; i++) { - opt = opt_args("InverseMask", flags[i]) -- if (opt ~ ",") { -- vname = var_name(flags[i]) -- macro = "OPTION_" -- mask = "OPTION_MASK_" -- if (vname == "") { -- vname = "target_flags" -- macro = "TARGET_" -- mask = "MASK_" -- } -- print "#define " macro nth_arg(1, opt) \ -- " ((" vname " & " mask nth_arg(0, opt) ") == 0)" -- } -+ if (opt ~ ",") -+ print "#define TARGET_" nth_arg(1, opt) \ -+ " ((target_flags & MASK_" nth_arg(0, opt) ") == 0)" - } - print "" - -diff -urN gcc-4.6.4-clean/gcc/tree.h gcc-4.6.4/gcc/tree.h ---- gcc-4.6.4-clean/gcc/tree.h 2011-10-06 13:57:52.000000000 -0600 -+++ gcc-4.6.4/gcc/tree.h 2015-07-20 19:44:52.774843181 -0600 -@@ -3563,6 +3563,8 @@ - TI_UINTDI_TYPE, - TI_UINTTI_TYPE, - -+ TI_UINT8_TYPE, -+ TI_UINT16_TYPE, - TI_UINT32_TYPE, - TI_UINT64_TYPE, - -diff -urN gcc-4.6.4-clean/gcc/version.c gcc-4.6.4/gcc/version.c ---- gcc-4.6.4-clean/gcc/version.c 2009-04-21 13:03:23.000000000 -0600 -+++ gcc-4.6.4/gcc/version.c 2015-07-20 19:44:52.774843181 -0600 -@@ -21,16 +21,16 @@ - - /* This is the location of the online document giving instructions for - reporting bugs. If you distribute a modified version of GCC, -- please configure with --with-bugurl pointing to a document giving -- instructions for reporting bugs to you, not us. (You are of course -- welcome to forward us bugs reported to you, if you determine that -- they are not bugs in your modifications.) */ -+ please change this to refer to a document giving instructions for -+ reporting bugs to you, not us. (You are of course welcome to -+ forward us bugs reported to you, if you determine that they are -+ not bugs in your modifications.) */ - --const char bug_report_url[] = BUGURL; -+const char bug_report_url[] = "<URL:http://lost.l-w.ca/coco/lwtools/>"; - - /* The complete version string, assembled from several pieces. - BASEVER, DATESTAMP, DEVPHASE, and REVISION are defined by the - Makefile. */ - --const char version_string[] = BASEVER DATESTAMP DEVPHASE REVISION; -+const char version_string[] = BASEVER DATESTAMP DEVPHASE REVISION " (gcc6809lw pl6)"; - const char pkgversion_string[] = PKGVERSION; -diff -urN gcc-4.6.4-clean/libgcc/config.host gcc-4.6.4/libgcc/config.host ---- gcc-4.6.4-clean/libgcc/config.host 2011-11-23 15:15:54.000000000 -0700 -+++ gcc-4.6.4/libgcc/config.host 2015-07-20 19:44:52.774843181 -0600 -@@ -371,6 +371,8 @@ - ;; - m32rle-*-linux*) - ;; -+m6809*) -+ ;; - m68hc11-*-*|m6811-*-*) - ;; - m68hc12-*-*|m6812-*-*) -diff -urN gcc-4.6.4-clean/libgcc/fixed-obj.mk gcc-4.6.4/libgcc/fixed-obj.mk ---- gcc-4.6.4-clean/libgcc/fixed-obj.mk 2007-09-17 16:18:13.000000000 -0600 -+++ gcc-4.6.4/libgcc/fixed-obj.mk 2015-07-20 19:44:52.774843181 -0600 -@@ -23,7 +23,7 @@ - #$(info $o$(objext): -DL$($o-label) $($o-opt)) - - $o$(objext): %$(objext): $(gcc_srcdir)/config/fixed-bit.c -- $(gcc_compile) -DL$($*-label) $($*-opt) -c $(gcc_srcdir)/config/fixed-bit.c $(vis_hide) -+ $(gcc_compile) -DL$($*-label) $($*-opt) -c $(gcc_srcdir)/config/fixed-bit.c $(vis_hide) -save-temps - - ifeq ($(enable_shared),yes) - $(o)_s$(objext): %_s$(objext): $(gcc_srcdir)/config/fixed-bit.c -diff -urN gcc-4.6.4-clean/libgcc/Makefile.in gcc-4.6.4/libgcc/Makefile.in ---- gcc-4.6.4-clean/libgcc/Makefile.in 2012-12-04 12:11:33.000000000 -0700 -+++ gcc-4.6.4/libgcc/Makefile.in 2015-07-20 19:44:52.774843181 -0600 -@@ -374,8 +374,8 @@ - # Build lib2funcs. For the static library also include LIB2FUNCS_ST. - lib2funcs-o = $(patsubst %,%$(objext),$(lib2funcs) $(LIB2FUNCS_ST)) - $(lib2funcs-o): %$(objext): $(gcc_srcdir)/libgcc2.c -- $(gcc_compile) -DL$* -c $(gcc_srcdir)/libgcc2.c \ -- $(vis_hide) -+ ln -sf $(gcc_srcdir)/libgcc2.c $*.c && \ -+ $(gcc_compile) -DL$* -c $*.c $(vis_hide) -save-temps - libgcc-objects += $(lib2funcs-o) - - ifeq ($(enable_shared),yes) -@@ -410,8 +410,9 @@ - # Build LIB2_DIVMOD_FUNCS. - lib2-divmod-o = $(patsubst %,%$(objext),$(LIB2_DIVMOD_FUNCS)) - $(lib2-divmod-o): %$(objext): $(gcc_srcdir)/libgcc2.c -- $(gcc_compile) -DL$* -c $(gcc_srcdir)/libgcc2.c \ -- -fexceptions -fnon-call-exceptions $(vis_hide) -+ ln -sf $(gcc_srcdir)/libgcc2.c $*.c && \ -+ $(gcc_compile) -DL$* -c $*.c \ -+ -fexceptions -fnon-call-exceptions $(vis_hide) -save-temps - libgcc-objects += $(lib2-divmod-o) - - ifeq ($(enable_shared),yes) -@@ -443,7 +444,8 @@ - ifneq ($(FPBIT),) - fpbit-o = $(patsubst %,%$(objext),$(FPBIT_FUNCS)) - $(fpbit-o): %$(objext): $(FPBIT) -- $(gcc_compile) -DFINE_GRAINED_LIBRARIES -DL$* -c $(FPBIT) $(vis_hide) -+ ln -sf $(FPBIT) $*.c && \ -+ $(gcc_compile) -DFINE_GRAINED_LIBRARIES -DL$* -c $*.c $(vis_hide) -save-temps - libgcc-objects += $(fpbit-o) - - ifeq ($(enable_shared),yes) -@@ -458,7 +460,8 @@ - ifneq ($(DPBIT),) - dpbit-o = $(patsubst %,%$(objext),$(DPBIT_FUNCS)) - $(dpbit-o): %$(objext): $(DPBIT) -- $(gcc_compile) -DFINE_GRAINED_LIBRARIES -DL$* -c $(DPBIT) $(vis_hide) -+ ln -sf $(DPBIT) $*.c && \ -+ $(gcc_compile) -DFINE_GRAINED_LIBRARIES -DL$* -c $*.c $(vis_hide) -save-temps - libgcc-objects += $(dpbit-o) - - ifeq ($(enable_shared),yes) -diff -urN gcc-4.6.4-clean/README.LW gcc-4.6.4/README.LW ---- gcc-4.6.4-clean/README.LW 1969-12-31 17:00:00.000000000 -0700 -+++ gcc-4.6.4/README.LW 2015-07-20 19:44:52.774843181 -0600 -@@ -0,0 +1,14 @@ -+This is a port of gcc6809 which is designed to work with the lwtools -+cross-assembler and linker package. You will need several scripts from that -+package, available at http://lost.l-w.ca/coco/lwtools/, in order to use -+this. Instructions for building are present in the lwtools package. -+ -+This work is based extensively on the gcc6809 4.3.4-3 release by Brian -+Dominy (brian@oddchange.com) with some significant renovations to make it -+work with gcc 4.6.1. -+ -+There is no guarantee that it will work for any particular purpose you -+choose to put it to. -+ -+If you run into any problems, contact William Astle (lost@l-w.ca). DO NOT -+contact the main GCC developers!
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extra/gcc6809lw-4.6.4-7.patch Tue Aug 15 20:49:58 2017 -0600 @@ -0,0 +1,8164 @@ +diff -urN gcc-4.6.4-clean/config.sub gcc-4.6.4/config.sub +--- gcc-4.6.4-clean/config.sub 2010-05-25 07:22:07.000000000 -0600 ++++ gcc-4.6.4/config.sub 2015-07-20 19:44:52.766843181 -0600 +@@ -313,7 +313,7 @@ + c6x) + basic_machine=tic6x-unknown + ;; +- m6811 | m68hc11 | m6812 | m68hc12 | picochip) ++ m6809 | m6811 | m68hc11 | m6812 | m68hc12 | picochip) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none +@@ -354,7 +354,7 @@ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ +- | m32c-* | m32r-* | m32rle-* \ ++ | m32c-* | m32r-* | m32rle-* | m6809-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ +@@ -509,6 +509,10 @@ + basic_machine=arm-unknown + os=-cegcc + ;; ++ coco) ++ basic_machine=coco ++ os=-none ++ ;; + convex-c1) + basic_machine=c1-convex + os=-bsd +diff -urN gcc-4.6.4-clean/configure gcc-4.6.4/configure +--- gcc-4.6.4-clean/configure 2011-12-18 03:03:44.000000000 -0700 ++++ gcc-4.6.4/configure 2015-07-20 19:44:52.766843181 -0600 +@@ -3439,6 +3439,9 @@ + m32r-*-*) + noconfigdirs="$noconfigdirs ${libgcj}" + ;; ++ m6809*) ++ noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 target-libgloss ${libgcj}" ++ ;; + m68hc11-*-*|m6811-*-*|m68hc12-*-*|m6812-*-*) + noconfigdirs="$noconfigdirs target-libstdc++-v3 ${libgcj}" + libgloss_dir=m68hc11 +diff -urN gcc-4.6.4-clean/configure.ac gcc-4.6.4/configure.ac +--- gcc-4.6.4-clean/configure.ac 2011-11-18 04:45:44.000000000 -0700 ++++ gcc-4.6.4/configure.ac 2015-07-20 19:44:52.766843181 -0600 +@@ -885,6 +885,9 @@ + m32r-*-*) + noconfigdirs="$noconfigdirs ${libgcj}" + ;; ++ m6809*) ++ noconfigdirs="$noconfigdirs target-libiberty target-libstdc++-v3 target-libgloss ${libgcj}" ++ ;; + m68hc11-*-*|m6811-*-*|m68hc12-*-*|m6812-*-*) + noconfigdirs="$noconfigdirs target-libstdc++-v3 ${libgcj}" + libgloss_dir=m68hc11 +diff -urN gcc-4.6.4-clean/gcc/calls.c gcc-4.6.4/gcc/calls.c +--- gcc-4.6.4-clean/gcc/calls.c 2012-02-09 10:27:25.000000000 -0700 ++++ gcc-4.6.4/gcc/calls.c 2015-07-20 19:44:52.766843181 -0600 +@@ -2561,7 +2561,7 @@ + call sequence. + Also do the adjustments before a throwing call, otherwise + exception handling can fail; PR 19225. */ +- if (pending_stack_adjust >= 32 ++ if (pending_stack_adjust >= 8 + || (pending_stack_adjust > 0 + && (flags & ECF_MAY_BE_ALLOCA)) + || (pending_stack_adjust > 0 +diff -urN gcc-4.6.4-clean/gcc/config/m6809/crt0.S gcc-4.6.4/gcc/config/m6809/crt0.S +--- gcc-4.6.4-clean/gcc/config/m6809/crt0.S 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-4.6.4/gcc/config/m6809/crt0.S 2015-07-20 19:44:52.766843181 -0600 +@@ -0,0 +1,173 @@ ++;;; ++;;; Copyright 2006, 2007, 2008, 2009 by Brian Dominy <brian@oddchange.com> ++;;; ++;;; 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 ++;;; <http://www.gnu.org/licenses/>. ++ ++ /* Declare external for main() */ ++ .globl _main ++ ++ ++/* The startup is heavily dependent on the type of machine and ++OS environment that is available at the start point. ++For the most part, the general idea is the same across machines, ++but the implementation is vastly different. This is managed via ++conditional compiles throughout the startup code for each of the ++supported machines. */ ++ ++#ifdef TARGET_COCO /* CoCo memory map */ ++ ++#define COCO_RAMROM_MODE 0xFFDE ++#define COCO_ALLRAM_MODE 0xFFDF ++#define COCO_PAGE1 0xFFD5 ++ ++/* SAM M1 and M0 adjusts the memory size */ ++ ++#define BASIC_WARMSTART_FLAG 0x0071 ++#define BASIC_START 0xA027 ++ ++#define __STACK_TOP 0x6800 ++ ++#else /* Simulator (default) memory map */ ++ ++#define SIM_EXIT_REG 0xFF01 ++ ++#define __STACK_TOP 0xFE00 ++ ++#endif ++ ++ ++ .area .data ++ .area .ctors ++ .area .dtors ++ .area .bss ++ ++ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ;;; ++ ;;; __exit : Exit point from the program ++ ;;; For simulation, this writes to a special I/O register that ++ ;;; the simulator interprets as end-of-program. ++ ;;; ++ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ .area .text ++ .globl __exit ++__exit: ++#ifdef TARGET_COCO ++ ;; Go back to ROM/RAM mode ++ sta COCO_RAMROM_MODE ++ clr BASIC_WARMSTART_FLAG ++ jmp BASIC_START ++#else ++ tfr x,d ++ stb SIM_EXIT_REG ++ bra __exit ++#endif ++ ++ ++ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ;;; ++ ;;; __start : Entry point to the program ++ ;;; ++ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ .area .text ++ .globl __start ++__start: ++ ++#ifdef HAVE_DIRECT ++ ;; Initialize the direct page pointer ++ lda #<s_.direct ++ tfr a,dp ++#endif ++ ++#ifdef TARGET_COCO ++ ;; Turn off interrupts ++ orcc #(0x10|0x40) ++ ++ ;; Setup All RAM Mode ++ sta COCO_ALLRAM_MODE ++#endif /* TARGET_COCO */ ++ ++ ;; Initialize the stack ++ lds #__STACK_TOP - 2 ++ ++ ;; Call any "initializer" functions ++ ldu #s_.ctors ++__ctors_loop: ++ ldy ,u++ ++ cmpy #0 ++ beq __ctors_done ++ jsr ,y ++ bra __ctors_loop ++__ctors_done: ++ ++ ;; Enable interrupts on the simulator ++#ifndef TARGET_COCO ++ andcc #~(0x10|0x40) ++#endif ++ ++ ;; Set up the environment ++ ++ ;; Set up argc/argv arrays ++ ++ ;; Call the main function. The exit code will ++ ;; be returned in the X register, unless compiled ++ ;; with -mdret, in which case it comes back in D. ++ jsr _main ++ ++ ;; Call any finalizer functions ++ ldu #s_.dtors ++__dtors_loop: ++ ldy ,u++ ++ cmpy #0 ++ beq __dtors_done ++ jsr ,y ++ bra __dtors_loop ++__dtors_done: ++ ++ ;; If main returns, then invoke _exit() to stop the program ++ ;; The C library doesn't support -mdret yet, so move the ++ ;; argument first. ++#ifdef __DRET__ ++ tfr d,x ++#endif ++ jmp _exit ++ ++ ++ ++ ;;; ++ ;;; __crt0_vector : Default handler for interrupts ++ ;;; ++ .area .text ++___crt0_vector: ++ ;; The default behavior is to simply ignore all ++ ;; non-reset interrupts. ++ rti ++ ++ ++ ;;; ++ ;;; vector : The interrupt vector table ++ ;;; The linker will ensure that this gets loaded at address 0xFFF0. ++ ;;; ++ .area vector ++vectors: ++ .word ___crt0_vector ++ .word ___crt0_vector ++ .word ___crt0_vector ++ .word ___crt0_vector ++ .word ___crt0_vector ++ .word ___crt0_vector ++ .word ___crt0_vector ++ .word __start +diff -urN gcc-4.6.4-clean/gcc/config/m6809/libgcc1.s gcc-4.6.4/gcc/config/m6809/libgcc1.s +--- gcc-4.6.4-clean/gcc/config/m6809/libgcc1.s 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-4.6.4/gcc/config/m6809/libgcc1.s 2015-07-20 19:44:52.766843181 -0600 +@@ -0,0 +1,511 @@ ++/* libgcc routines for m6809 ++ Copyright (C) 2006 Free Software Foundation, 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 ++<http://www.gnu.org/licenses/>. */ ++ ++/* As a special exception, if you link this library with other files, ++ some of which are compiled with GCC, to produce an executable, ++ this library does not by itself cause the resulting executable ++ to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. */ ++ ++ ++#define SIGFPE jmp _abort ++ ++ ++ ; Shift functions ++ ; On input, D is value to be shifted, and X has shift count. ++ ; Result is also in D. ++ ++#ifdef L_ashlhi3 ++ .area .text ++ .globl _ashlhi3 ++_ashlhi3: ++ pshs x ++1$: ++ leax -1,x ++ cmpx #-1 ++ beq 2$ ++ aslb ++ rola ++ bra 1$ ++2$: ++ puls x,pc ++#endif ++ ++#ifdef L_ashrhi3 ++ .area .text ++ .globl _ashrhi3 ++_ashrhi3: ++ pshs x ++1$: ++ leax -1,x ++ cmpx #-1 ++ beq 2$ ++ asra ++ rorb ++ bra 1$ ++2$: ++ puls x,pc ++#endif ++ ++ ++#ifdef L_lshrhi3 ++ .area .text ++ .globl _lshrhi3 ++_lshrhi3: ++ pshs x ++1$: ++ leax -1,x ++ cmpx #-1 ++ beq 2$ ++ lsra ++ rorb ++ bra 1$ ++2$: ++ puls x,pc ++#endif ++ ++ ++ ++#ifdef L_softregs ++ .area direct ++ .globl m0, m1, m2, m3, m4, m5, m6, m7 ++ .globl m8, m9, m10, m11, m12, m13, m14, m15 ++m0: .blkb 1 ++m1: .blkb 1 ++m2: .blkb 1 ++m3: .blkb 1 ++m4: .blkb 1 ++m5: .blkb 1 ++m6: .blkb 1 ++m7: .blkb 1 ++m8: .blkb 1 ++m9: .blkb 1 ++m10: .blkb 1 ++m11: .blkb 1 ++m12: .blkb 1 ++m13: .blkb 1 ++m14: .blkb 1 ++m15: .blkb 1 ++#endif ++ ++ ++#ifdef L_ashlsi3_one ++ .area .text ++ .globl _ashlsi3_one ++_ashlsi3_one: ++ asl 3,x ++ rol 2,x ++ rol 1,x ++ rol ,x ++ rts ++#endif ++ ++#ifdef L_ashlsi3 ++ /* X points to the SImode (source/dest) ++ B is the count */ ++_ashlsi3: ++ pshs u ++ cmpb #16 ++ blt try8 ++ subb #16 ++ ; Shift by 16 ++ ldu 2,x ++ stu ,x ++try8: ++ cmpb #8 ++ blt try_rest ++ subb #8 ++ ; Shift by 8 ++ ++try_rest: ++ tstb ++ beq done ++do_rest: ++ ; Shift by 1 ++ asl 3,x ++ rol 2,x ++ rol 1,x ++ rol ,x ++ decb ++ bne do_rest ++done: ++ puls u,pc ++#endif ++ ++#ifdef L_ashrsi3_one ++ .area .text ++ .globl _ashlsi3_one ++_ashrsi3_one: ++ asr ,x ++ ror 1,x ++ ror 2,x ++ ror 3,x ++ rts ++#endif ++ ++ ++#ifdef L_lshrsi3_one ++ .area .text ++ .globl _lshrsi3_one ++_lshrsi3_one: ++ lsr ,x ++ ror 1,x ++ ror 2,x ++ ror 3,x ++ rts ++#endif ++ ++ ++#ifdef L_clzsi2 ++ .area .text ++ .globl ___clzhi2 ++ ; Input: X = 16-bit unsigned integer ++ ; Output: X = number of leading zeros ++ ; This function destroys the value in D. ++___clzhi2: ++ pshs x ++ ; Find the offset of the leftmost '1' bit in ++ ; the left half of the word. ++ ; ++ ; Bits are numbered in the table with 1 meaning the ++ ; LSB and 8 meaning the MSB. ++ ; ++ ; If nonzero, then clz is 8-a. ++ tfr x,d ++ ldx #___clz_tab ++ tfr a,b ++ clra ++ ldb d,x ++ bne upper_bit_set ++ ++lower_bit_set: ++ ; If the upper byte is zero, then check the lower ++ ; half of the word. Return 16-a. ++ puls d ++ clra ++ ldb d,x ++ negb ++ addb #16 ++ bra done ++ ++upper_bit_set: ++ negb ++ addb #8 ++ puls x ++ ++done: ++ tfr d,x ++ puls pc ++#endif ++ ++#ifdef L_clzdi2 ++ .area .text ++ .globl ___clzsi2 ++ ; Input: 32-bit unsigned integer is on the stack, just ++ ; above the return address ++ ; Output: X = number of leading zeros ++___clzsi2: ++ ; Check the upper 16-bit word ++ ; If it is not zero, then return clzhi2(X). ++ ; A branch can be used instead of a call since no ++ ; postprocessing is needed. Use long branch form ++ ; though since functions may not be near each other. ++ ldx 2,s ++ lbne ___clzhi2 ++ ldx 4,s ++ jsr ___clzhi2 ++ leax 16,x ++ rts ++#endif ++ ++#ifdef L_ctzsi2 ++ .area .text ++ .globl ___ctzhi2 ++ ; Input: X = 16-bit unsigned integer ++ ; Output: X = number of trailing zeros ++ ; F(x) = 15 - clzhi2(X & -x) ++ ; This function destroys the value in D. ++___ctzhi2: ++ tfr x,d ++ coma ++ comb ++ addd #1 ++ pshs a ++ pshs b ++ tfr x,d ++ andb ,s+ ++ anda ,s+ ++ tfr d,x ++ jsr ___clzhi2 ++ tfr x,d ++ subd #16 ++ coma ++ comb ++ tfr d,x ++ rts ++#endif ++ ++ ++#ifdef L_ctzdi2 ++ .area .text ++ .globl ___ctzsi2 ++ ; Input: 32-bit unsigned integer is on the stack, just ++ ; above the return address ++ ; Output: X = number of leading zeros ++___ctzsi2: ++ ; Check the lower 16-bit word ++ ; If it is not zero, then return ctzhi2(X). ++ ; A branch can be used instead of a call since no ++ ; postprocessing is needed. Use long branch form ++ ; though since functions may not be near each other. ++ ldx 4,s ++ lbne ___ctzhi2 ++ ldx 2,s ++ jsr ___ctzhi2 ++ leax 16,x ++ rts ++#endif ++ ++ ++#ifdef L_mulhi3 ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++;;; ___mulhi3 - signed/unsigned multiply ++;;; Called by GCC to implement 16x16 multiplication ++;;; Arguments: Two 16-bit values, one in stack, one in X. ++;;; Result: 16-bit result in X ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ .area .text ++ .globl _mulhi3 ++_mulhi3: ++ pshs x ++ lda 5,s ; left msb * right lsb * 256 ++ ldb ,s ++ mul ++ tfr b,a ++ clrb ++ tfr d,x ++ ldb 1,s ; left lsb * right msb * 256 ++ lda 4,s ++ mul ++ tfr b,a ++ clrb ++ leax d,x ++ ldb 1,s ; left lsb * right lsb ++ lda 5,s ++ mul ++ leax d,x ++ puls d,pc ; kill D to remove initial push ++#endif ++ ++ ++#ifdef L_divhi3 ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++;;; ___divhi3 - signed division ++;;; Arguments: Dividend in X, divisor on the stack ++;;; Returns result in X. ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ .area .text ++ .globl _divhi3 ++_divhi3: ++ ldd 2,s ++ bne do_div ; check dividend ++ SIGFPE ++do_div: ++ pshs x ++ jsr _seuclid ++ puls x,pc ++#endif ++ ++ ++#ifdef L_modhi3 ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++;;; ___modhi3 - signed modulo ++;;; Arguments: Dividend in X, divisor on the stack ++;;; Returns result in X. ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ .area .text ++ .globl _modhi3 ++_modhi3: ++ ldd 2,s ++ bne do_mod ; check dividend ++ SIGFPE ++do_mod: ++ pshs x ++ jsr _seuclid ++ leas 2,s ++ tfr d,x ++ rts ++#endif ++ ++ ++ ++#ifdef L_udivhi3 ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++;;; ___udivhi3 - unsigned division ++;;; Arguments: Dividend in X, divisor on the stack ++;;; Returns result in X. ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ .area .text ++ .globl _udivhi3 ++_udivhi3: ++ ldd 2,s ++ bne do_udiv ; check dividend ++ SIGFPE ++do_udiv: ++ pshs x ++ jsr _euclid ++ puls x,pc ++#endif ++ ++ ++#ifdef L_umodhi3 ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++;;; ___umodhi3 - unsigned modulo ++;;; Arguments: Dividend in X, divisor on the stack ++;;; Returns result in X. ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ .area .text ++ .globl _umodhi3 ++_umodhi3: ++ ldd 2,s ++ bne do_umod ; check dividend ++ SIGFPE ++do_umod: ++ pshs x ++ jsr _euclid ++ leas 2,s ++ tfr d,x ++ rts ++#endif ++ ++ ++#ifdef L_euclid ++; unsigned euclidean division ++; calling: (left / right) ++; push left ++; ldd right ++; jsr _euclid ++; quotient on the stack (left) ++; modulus in d ++ ++ .area .text ++ .globl _euclid ++ left=5 ++ right=1 ; word ++ count=0 ; byte ++ CARRY=1 ; alias ++_euclid: ++ leas -3,s ; 2 local variables ++ clr count,s ; prescale divisor ++ inc count,s ++ tsta ++presc: ++ bmi presc_done ++ inc count,s ++ aslb ++ rola ++ bra presc ++presc_done: ++ std right,s ++ ldd left,s ++ clr left,s ; quotient = 0 ++ clr left+1,s ++mod1: ++ subd right,s ; check subtract ++ bcc mod2 ++ addd right,s ++ andcc #~CARRY ++ bra mod3 ++mod2: ++ orcc #CARRY ++mod3: ++ rol left+1,s ; roll in carry ++ rol left,s ++ lsr right,s ++ ror right+1,s ++ dec count,s ++ bne mod1 ++ leas 3,s ++ rts ++#endif ++ ++#ifdef L_seuclid ++; signed euclidean division ++; calling: (left / right) ++; push left ++; ldd right ++; jsr _seuclid ++; quotient on the stack (left) ++; modulus in d ++ .area .text ++ .globl _seuclid ++ left=6 ++ right=2 ++ quot_sign=1 ++ mod_sign=0 ++_seuclid: ++ leas -4,s ; 3 local variables ++ std right,s ++ clr mod_sign,s ++ clr quot_sign,s ++ ldd left,s ++ bge mod_abs ++ inc mod_sign,s ; sign(mod) = sign(left) ++ inc quot_sign,s ++ bsr negd ; abs(left) -> D ++mod_abs: ++ pshs b,a ; push abs(left) ++ ldd right+2,s ; all references shifted by 2 ++ bge quot_abs ++ dec quot_sign+2,s ; sign(quot) = sign(left) XOR sign(right) ++ bsr negd ; abs(right) -> D ++quot_abs: ++ jsr _euclid ; call (unsigned) euclidean division ++ std right+2,s ++ puls a,b ; quot -> D ++ tst quot_sign,s ; all references no longer shifted ++ beq quot_done ++ bsr negd ++quot_done: ++ std left,s ; quot -> left ++ ldd right,s ++ tst mod_sign,s ++ beq mod_done ++ bsr negd ++mod_done: ++ leas 4,s ; destroy stack frame ++ rts ++ ++negd: ; self-explanatory ! ++ nega ++ negb ++ sbca #0 ++ rts ++#endif ++ ++ ++ ++#ifdef L_pending_addsi3 ++_addsi3: ++ rts ++#endif /* L_pending_addsi3 */ ++ ++ ++ +diff -urN gcc-4.6.4-clean/gcc/config/m6809/m6809.c gcc-4.6.4/gcc/config/m6809/m6809.c +--- gcc-4.6.4-clean/gcc/config/m6809/m6809.c 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-4.6.4/gcc/config/m6809/m6809.c 2015-07-20 22:11:37.726714746 -0600 +@@ -0,0 +1,3025 @@ ++/*------------------------------------------------------------------- ++ FILE: m6809.c ++-------------------------------------------------------------------*/ ++/* Subroutines for insn-output.c for MC6809. ++ Copyright (C) 1989-2007 Free Software Foundation, Inc. ++ ++ MC6809 Version by Tom Jones (jones@sal.wisc.edu) ++ Space Astronomy Laboratory ++ University of Wisconsin at Madison ++ ++ minor changes to adapt it to gcc-2.5.8 by Matthias Doerfel ++ ( msdoerfe@informatik.uni-erlangen.de ) ++ also added #pragma interrupt (inspired by gcc-6811) ++ ++ minor changes to adapt it to gcc-2.8.0 by Eric Botcazou ++ (ebotcazou@multimania.com) ++ ++ minor changes to adapt it to gcc-2.95.3 by Eric Botcazou ++ (ebotcazou@multimania.com) ++ ++ major cleanup, improvements, and upgrade to gcc 3.4 by Brian Dominy ++ (brian@oddchange.com) ++ ++ additional adjustments, etc., for gcc 4.6.1 by William Astle (lost@l-w.ca) ++ ++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 ++<http://www.gnu.org/licenses/>. */ ++ ++#include <string.h> ++#include <time.h> ++#include <sys/types.h> ++#include <sys/timeb.h> ++#include <stdio.h> ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "tree.h" ++#include "rtl.h" ++#include "tm_p.h" ++#include "regs.h" ++#include "flags.h" ++#include "hard-reg-set.h" ++#include "real.h" ++#include "tree.h" ++#include "insn-config.h" ++#include "conditions.h" ++#include "insn-flags.h" ++#include "output.h" ++#include "insn-attr.h" ++#include "function.h" ++#include "target.h" ++#include "target-def.h" ++#include "expr.h" ++#include "recog.h" ++#include "cpplib.h" ++#include "c-family/c-pragma.h" ++#include "c-family/c-common.h" ++#include "toplev.h" ++#include "optabs.h" ++#include "version.h" ++#include "df.h" ++#include "rtlhooks-def.h" ++ ++/* macro to return TRUE if length of operand mode is one byte */ ++#define BYTE_MODE(X) ((GET_MODE_SIZE (GET_MODE (X))) == 1) ++ ++ ++/* REAL_REG_P(x) is a true if the rtx 'x' represents a real CPU ++register and not a fake one that is emulated in software. */ ++#define REAL_REG_P(x) (REG_P(x) && !M_REG_P(x)) ++ ++/*------------------------------------------------------------------- ++ Target hooks, moved from target.h ++-------------------------------------------------------------------*/ ++static void m6809_encode_section_info (tree decl, rtx rtl, int new_decl_p ATTRIBUTE_UNUSED); ++ ++#undef TARGET_ENCODE_SECTION_INFO ++#define TARGET_ENCODE_SECTION_INFO m6809_encode_section_info ++ ++#undef TARGET_ASM_FILE_START ++#define TARGET_ASM_FILE_START m6809_asm_file_start ++ ++#undef TARGET_ASM_ALIGNED_HI_OP ++#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t" ++ ++#undef TARGET_ASM_ALIGNED_SI_OP ++#define TARGET_ASM_ALIGNED_SI_OP NULL ++ ++#undef TARGET_ASM_UNALIGNED_HI_OP ++#define TARGET_ASM_UNALIGNED_HI_OP "\t.word\t" ++ ++#undef TARGET_ASM_UNALIGNED_SI_OP ++#define TARGET_ASM_UNALIGNED_SI_OP NULL ++ ++#undef TARGET_RTX_COSTS ++#define TARGET_RTX_COSTS m6809_rtx_costs ++ ++#undef TARGET_ATTRIBUTE_TABLE ++#define TARGET_ATTRIBUTE_TABLE m6809_attribute_table ++ ++#undef TARGET_INIT_BUILTINS ++#define TARGET_INIT_BUILTINS m6809_init_builtins ++ ++#undef TARGET_EXPAND_BUILTIN ++#define TARGET_EXPAND_BUILTIN m6809_expand_builtin ++ ++#undef TARGET_DEFAULT_TARGET_FLAGS ++#define TARGET_DEFAULT_TARGET_FLAGS (MASK_REG_ARGS | MASK_DIRECT) ++ ++#undef TARGET_FUNCTION_OK_FOR_SIBCALL ++#define TARGET_FUNCTION_OK_FOR_SIBCALL m6809_function_ok_for_sibcall ++ ++#undef TARGET_ASM_TRAMPOLINE_TEMPLATE ++#define TARGET_ASM_TRAMPOLINE_TEMPLATE m6809_asm_trampoline_template ++ ++#undef TARGET_TRAMPOLINE_INIT ++#define TARGET_TRAMPOLINE_INIT m6809_initialize_trampoline ++ ++#undef TARGET_FRAME_POINTER_REQUIRED ++#define TARGET_FRAME_POINTER_REQUIRED m6809_frame_pointer_required ++ ++#undef TARGET_OPTION_OVERRIDE ++#define TARGET_OPTION_OVERRIDE m6809_override_options ++ ++/* External variables used */ ++extern int reload_completed; /* set in toplev.c */ ++extern FILE *asm_out_file; ++ ++static int last_mem_size; /* operand size (bytes) */ ++ ++/* True if the section was recently changed and another .area ++ * directive needs to be output before emitting the next label. */ ++int section_changed = 0; ++ ++/* Section names. The defaults here are used until an ++ * __attribute__((section)) is seen that changes it. */ ++char code_section_op[128] = "\t.area .text"; ++char data_section_op[128] = "\t.area .data"; ++char bss_section_op[128] = "\t.area .bss"; ++const char *code_bank_option = 0; ++ ++/* TRUE if the direct mode prefix might be valid in this context. ++ * This is set by 'print_address' prior to calling output_addr_const, ++ * which performs into 'print_direct_prefix' to do the final checks. */ ++static int check_direct_prefix_flag; ++ ++/* Nonzero if an address is being printed in a context which does not ++ * permit any PIC modifications to the address */ ++static int pic_ok_for_addr_p = 1; ++ ++/* Current code page. This supports machines which can do bank ++ * switching to allow for more than 64KB of code/data. */ ++char far_code_page[64]; ++ ++/* Current bank name */ ++static char current_bank_name[8] = "-1"; ++ ++/* Default bank name */ ++static char default_code_bank_name[8] = "-1"; ++ ++/* Direct memory reserved as soft registers */ ++unsigned int m6809_soft_regs = 0; ++ ++/* ABI version */ ++unsigned int m6809_abi_version = M6809_ABI_VERSION_REGS; ++ ++ ++/** ++ * Called after options have been parsed. ++ * If overrides have been specified on the command-line, then ++ * these values are copied into the main storage variables. ++ */ ++void ++m6809_override_options (void) ++{ ++ /* Handle -mfar-code-page */ ++ if (far_code_page_option == 0) ++ far_code_page_option = "__default_code_page"; ++ strcpy (far_code_page, far_code_page_option); ++ ++ /* Handle -mcode-section, -mdata-section, and -mbss-section */ ++ if (code_section_ptr != 0) ++ sprintf (code_section_op, "\t.area %s", code_section_ptr); ++ if (data_section_ptr != 0) ++ sprintf (data_section_op, "\t.area %s", data_section_ptr); ++ if (bss_section_ptr != 0) ++ sprintf (bss_section_op, "\t.area %s", bss_section_ptr); ++ ++ /* Handle -mcode-bank */ ++ if (code_bank_option != 0) ++ sprintf (default_code_bank_name, "%s", code_bank_option); ++ ++ /* Handle -mabi-version or -mno-reg-args */ ++ if (m6809_abi_version_ptr != 0) ++ { ++ if (!strcmp (m6809_abi_version_ptr, "stack")) ++ m6809_abi_version = M6809_ABI_VERSION_STACK; ++ else if (!strcmp (m6809_abi_version_ptr, "regs")) ++ m6809_abi_version = M6809_ABI_VERSION_REGS; ++ else if (!strcmp (m6809_abi_version_ptr, "bx")) ++ m6809_abi_version = M6809_ABI_VERSION_BX; ++ else if (!strcmp (m6809_abi_version_ptr, "latest")) ++ m6809_abi_version = M6809_ABI_VERSION_LATEST; ++ else ++ m6809_abi_version = atoi (m6809_abi_version_ptr); ++ } ++ ++ /* The older -mno-reg-args option is deprecated, and treated ++ as -mabi=stack. */ ++ if (!TARGET_REG_ARGS) ++ { ++ warning (WARNING_OPT "-mno-reg-args deprecated; use -mabi=stack instead."); ++ m6809_abi_version = M6809_ABI_VERSION_STACK; ++ } ++ ++ /* -fexceptions is unsupported */ ++ flag_exceptions = 0; ++ flag_non_call_exceptions = 0; ++ flag_unwind_tables = 0; ++} ++ ++ ++/** ++ * Output prefix that directs the assembler to use a direct-mode ++ * instruction if globally enabled, address is a symbol, and symbol ++ * has been marked as in direct page. Also, never do this if ++ * using the indirect mode. */ ++void ++print_direct_prefix (FILE * file, rtx addr) ++{ ++ if (TARGET_DIRECT && ++ (GET_CODE (addr) == SYMBOL_REF) && ++ SYMBOL_REF_FLAG (addr) && ++ check_direct_prefix_flag) ++ { ++ putc ('*', file); ++ } ++} ++ ++ ++/** Prints an operand (that is not an address) in assembly from RTL. */ ++void ++print_operand (FILE * file, rtx x, int code) ++{ ++ if (REG_P (x)) { ++ /* gcc currently allocates the entire 16-bit 'd' register ++ * even when it only needs an 8-bit value. So here it ++ * is tricked into printing only the lower 8-bit 'b' ++ * register into the assembly output. ++ * ++ * Eventually gcc should be modified to allocate a/b ++ * independently and this hack can be removed. ++ * ++ * Occasionally, we may want to do an operation using ++ * the 'a' register instead of 'b'; use the 'A' code ++ * to specify that. ++ */ ++ if (code == 'A') ++ fputs ("a", file); ++ else if ((BYTE_MODE (x)) && (REGNO (x) == HARD_D_REGNUM)) ++ fputs ("b", file); ++ else if (M_REG_P (x) && code == 'L') ++ /* Soft registers can be treated like memory and accessed ++ * at a particular offset. TODO : handle 'W' */ ++ fputs (reg_names[REGNO (x)+1], file); ++ else ++ fputs (reg_names[REGNO (x)], file); ++ } ++ ++ else if (MEM_P (x)) { ++ last_mem_size = GET_MODE_SIZE (GET_MODE (x)); ++ if (code == 'L') { /* LSH of word address */ ++ if (GET_CODE (XEXP (x, 0)) == MEM) ++ { ++ /* Offseting an indirect addressing mode is not supported */ ++ error ("expression too complex for 6809 (offset indirect mode)"); ++ debug_rtx (x); ++ } ++ else ++ x = adjust_address (x, QImode, 1); ++ } ++ else if (code == 'M') { /* MSH of word address */ ++ if (GET_CODE (XEXP (x, 0)) == MEM) ++ { ++ /* Offseting an indirect addressing mode is not supported */ ++ error ("expression too complex for 6809 (offset indirect mode)"); ++ debug_rtx (x); ++ } ++ else ++ x = adjust_address (x, QImode, 0); ++ } ++ else if (code == 'W') { /* least significant half of 32-bit */ ++ x = adjust_address (x, HImode, 2); ++ } ++ ++ pic_ok_for_addr_p = (code != 'C'); ++ output_address (XEXP (x, 0)); ++ } ++ ++ else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode) { ++ union { double d; int i[2]; } u; ++ u.i[0] = CONST_DOUBLE_LOW (x); ++ u.i[1] = CONST_DOUBLE_HIGH (x); ++ fprintf (file, "#%#9.9g", u.d); ++ } ++ ++ else if (code == 'R') { ++ fprintf (file, "%s", ++ m6809_get_regs_printable (INTVAL (x))); ++ } ++ ++ else { ++ if (code == 'L') { /* LSH of word address */ ++ x = gen_rtx_CONST_INT (VOIDmode, (INTVAL(x) & 0xff)); ++ } ++ else if (code == 'M') { /* MSH of word address */ ++ x = gen_rtx_CONST_INT (VOIDmode, ((INTVAL(x) >> 8) & 0xff)); ++ } ++ ++ putc ('#', file); ++ output_addr_const (file, x); ++ } ++} ++ ++ ++/** Prints an address operand to assembler from its RTL representation. */ ++void ++print_operand_address (FILE *file, rtx addr) ++{ ++ register rtx base = 0; ++ register rtx offset = 0; ++ int regno; ++ int indirect_flag = 0; ++ ++ check_direct_prefix_flag = 0; ++ ++ /*** check for indirect addressing ***/ ++ if (MEM_P (addr)) { ++ last_mem_size = GET_MODE_SIZE (GET_MODE (addr)); ++ addr = XEXP (addr, 0); ++ if (pic_ok_for_addr_p) ++ { ++ indirect_flag = 1; ++ fprintf (file, "["); ++ } ++ } ++ ++ ++ switch (GET_CODE (addr)) { ++ case REG: ++ regno = REGNO (addr); ++ fprintf (file, ",%s", reg_names[regno]); ++ break; ++ ++ case PRE_DEC: ++ regno = REGNO (XEXP (addr, 0)); ++ fputs (((last_mem_size == 1) ? ",-" : ",--"), file); ++ fprintf (file, "%s", reg_names[regno]); ++ break; ++ ++ case POST_INC: ++ regno = REGNO (XEXP (addr, 0)); ++ fprintf (file, ",%s", reg_names[regno]); ++ fputs (((last_mem_size == 1) ? "+" : "++"), file); ++ break; ++ ++ case PLUS: ++ base = XEXP (addr, 0); ++ if (MEM_P (base)) ++ base = XEXP (base, 0); ++ ++ offset = XEXP (addr, 1); ++ if (MEM_P (offset)) ++ offset = XEXP (offset, 0); ++ ++ if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset))) { ++ if (!indirect_flag) ++ check_direct_prefix_flag = 1; ++ output_addr_const (file, base); ++ check_direct_prefix_flag = 0; ++ fputs ("+", file); ++ output_addr_const (file, offset); ++ } ++ ++ else if ((CONSTANT_ADDRESS_P (base)) && (A_REG_P (offset))) { ++ output_addr_const (file, base); ++ fprintf (file, ",%s", reg_names[REGNO (offset)]); ++ } ++ ++ else if ((CONSTANT_ADDRESS_P (offset)) && (A_REG_P (base))) { ++ output_addr_const (file, offset); ++ fprintf (file, ",%s", reg_names[REGNO (base)]); ++ } ++ ++ /*** accumulator offset ***/ ++ else if (((D_REG_P (offset)) || (Q_REG_P (offset))) ++ && (A_REG_P (base))) { ++ fprintf (file, "%s,%s", ++ reg_names[REGNO (offset)], reg_names[REGNO (base)]); ++ } ++ ++ else if (((D_REG_P (base)) || (Q_REG_P (base))) ++ && (A_REG_P (offset))) { ++ fprintf (file, "%s,%s", ++ reg_names[REGNO (base)], reg_names[REGNO (offset)]); ++ } ++ ++ else if (GET_CODE (base) == PRE_DEC) { ++ regno = REGNO (XEXP (base, 0)); ++ fputs (((last_mem_size == 1) ? ",-" : ",--"), file); ++ fprintf (file, "%s", reg_names[regno]); ++ } ++ ++ else ++ abort (); ++ ++ break; ++ ++ default: ++ /* Set this global before calling output_addr_const() */ ++ if (!indirect_flag) ++ check_direct_prefix_flag = 1; ++ ++ /* When printing a SYMBOL_REF in PIC mode, do not print the leading ++ * '#' and follow it by ',pcr' to enable relative addressing. */ ++ if (flag_pic && pic_ok_for_addr_p && GET_CODE (addr) == SYMBOL_REF) ++ { ++ ASM_OUTPUT_SYMBOL_REF (file, addr); ++ fputs (",pcr", file); ++ pic_ok_for_addr_p = 1; ++ } ++ else ++ { ++ output_addr_const (file, addr); ++ } ++ ++ check_direct_prefix_flag = 0; ++ break; ++ } ++ ++ if (indirect_flag) ++ fprintf (file, "]"); ++} ++ ++/*------------------------------------------------------------------- ++ Update the CC Status ++--------------------------------------------------------------------- ++ Set the cc_status for the results of an insn whose pattern is EXP. ++ We assume that jumps don't affect the condition codes. ++ All else, clobbers the condition codes, by assumption. ++ ++ We assume that ALL add, minus, etc. instructions effect the condition ++ codes. ++-------------------------------------------------------------------*/ ++void ++notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED) ++{ ++ int src_code; ++ int dst_code; ++ ++ /*** recognize SET insn's ***/ ++ if (GET_CODE (exp) == SET) ++ { ++ src_code = GET_CODE (SET_SRC (exp)); ++ dst_code = GET_CODE (SET_DEST (exp)); ++ ++ /* Jumps do not alter the cc's. */ ++ if (SET_DEST (exp) == pc_rtx) ++ return; ++ ++ /* Moving one register into another register (tfr): ++ Doesn't alter the cc's. */ ++ if (REG_P (SET_DEST (exp)) && (REG_P (SET_SRC (exp)))) ++ return; ++ ++ /* Moving memory into a register (load): Sets cc's. */ ++ if (REG_P (SET_DEST (exp)) && src_code == MEM) { ++ cc_status.value1 = SET_SRC (exp); ++ cc_status.value2 = SET_DEST (exp); ++ cc_status.flags |= CC_NO_OVERFLOW; ++ return; ++ } ++ ++ /* Moving register into memory (store): Sets cc's. */ ++ if (dst_code == MEM && REG_P (SET_SRC (exp))) { ++ cc_status.value1 = SET_SRC (exp); ++ cc_status.value2 = SET_DEST (exp); ++ cc_status.flags |= CC_NO_OVERFLOW; ++ return; ++ } ++ ++ /* Function calls clobber the cc's. */ ++ else if (GET_CODE (SET_SRC (exp)) == CALL) { ++ CC_STATUS_INIT; ++ return; ++ } ++ ++ /* Tests and compares set the cc's in predictable ways. */ ++ else if (SET_DEST (exp) == cc0_rtx) ++ { ++ cc_status.flags = 0; ++ cc_status.value1 = SET_SRC (exp); ++ cc_status.value2 = SET_DEST (exp); ++ return; ++ } ++ ++ else if (A_REG_P (SET_DEST (exp))) ++ { ++ CC_STATUS_INIT; ++ return; ++ } ++ ++ else ++ { ++ /* Certain instructions affect the condition codes. */ ++ switch (src_code) ++ { ++ case PLUS: ++ case MINUS: ++ case NEG: ++ case ASHIFT: ++ /* These instructions set the condition codes, ++ * and may modify the V bit. */ ++ cc_status.flags |= CC_NO_OVERFLOW; ++ /* FALLTHRU */ ++ ++ case AND: ++ case IOR: ++ case XOR: ++ case ASHIFTRT: ++ case LSHIFTRT: ++ /* These instructions set the condition codes, ++ * but cannot overflow (V=0). */ ++ cc_status.value1 = SET_SRC (exp); ++ cc_status.value2 = SET_DEST (exp); ++ break; ++ ++ default: ++ /* Everything else is clobbered */ ++ CC_STATUS_INIT; ++ } ++ return; ++ } ++ } /* SET */ ++ ++ else if (GET_CODE (exp) == PARALLEL ++ && GET_CODE (XVECEXP (exp, 0, 0)) == SET) ++ { ++ if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx) ++ return; ++ if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx) ++ { ++ CC_STATUS_INIT; ++ cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0)); ++ return; ++ } ++ } ++ ++ /*** default action if we haven't recognized something ++ and returned earlier ***/ ++ CC_STATUS_INIT; ++} ++ ++ ++/** Returns nonzero if the expression EXP can be implemented using one ++ * of the 6809's single operand instructions. */ ++int ++m6809_single_operand_operator (rtx exp) ++{ ++ rtx op1; ++ HOST_WIDE_INT val; ++ enum rtx_code code; ++ ++ debug_rtx(exp); ++ ++ code = GET_CODE (exp); ++ ++ /* Unary operators always qualify */ ++ switch (code) ++ { ++ case NEG: ++ case NOT: ++ return 1; ++ ++ default: ++ break; ++ } ++ ++ /* Binary operators can only qualify if the second ++ * argument is a CONST_INT of certain value. */ ++ op1 = XEXP (exp, 1); ++ if (GET_CODE (op1) != CONST_INT) ++ return 0; ++ val = INTVAL (op1); ++ switch (code) ++ { ++ case PLUS: ++ case MINUS: ++ if (val == -1 || val == 1) ++ return 1; ++ break; ++ ++ case ASHIFT: ++ case ASHIFTRT: ++ case LSHIFTRT: ++ case ROTATE: ++ case ROTATERT: ++ if (val == 1) ++ return 1; ++ break; ++ ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++/** Return a bitarray of the hard registers which are used by a function. */ ++unsigned int ++m6809_get_live_regs (void) ++{ ++ unsigned int regs = 0; ++ int regno; ++ ++ if (frame_pointer_needed) ++ regs |= (1 << HARD_FRAME_POINTER_REGNUM); ++ ++ for (regno = HARD_X_REGNUM; regno <= HARD_U_REGNUM; regno++) ++ if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) ++ regs |= (1 << regno); ++ ++ return regs; ++} ++ ++ ++/** Return a printable version of a list of hard registers, suitable ++ * for use in a PSHx or PULx insn. */ ++const char * ++m6809_get_regs_printable (unsigned int regs) ++{ ++ static char list[64]; ++ char *listp = list; ++ unsigned int regno; ++ ++ for (regno=0; regno < FIRST_PSEUDO_REGISTER; regno++) ++ if ((regs & (1 << regno)) && !S_REGNO_P (regno)) ++ listp += sprintf (listp, ++ (listp == list) ? "%s" : ",%s", reg_names[regno]); ++ ++ return list; ++} ++ ++ ++/** Return the total number of bytes covered by a set of hard registers. */ ++unsigned int ++m6809_get_regs_size (unsigned int regs) ++{ ++ unsigned int regno; ++ unsigned int size = 0; ++ ++ for (regno=0; regno < FIRST_PSEUDO_REGISTER; regno++) ++ { ++ /* Only count register in the given register set */ ++ if (REGSET_CONTAINS_P (regno, regs)) ++ { ++ /* Add 1 or 2 byte, depending on the size of the register. ++ * Since 'D' may be in both sets, check for WORD_REGSET first. */ ++ if (REGSET_CONTAINS_P(regno, WORD_REGSET)) ++ size += 2; ++ else if (REGSET_CONTAINS_P(regno, BYTE_REGSET)) ++ size++; ++ } ++ } ++ return size; ++} ++ ++ ++/* Given the target of call instruction in X, ++ * return the tree node that contains the function declaration for ++ * that target. ++ * ++ * If the rtx or the tree do not appear valid for any reason, ++ * then return NULL_TREE. ++ */ ++static tree call_target_decl (rtx x) ++{ ++ tree decl; ++ ++ /* Make sure the target is really a MEM. */ ++ if (!x || !MEM_P (x)) ++ return NULL_TREE; ++ ++ /* Make sure the address is a SYMBOL_REF. */ ++ x = XEXP (x, 0); ++ if (!x || (GET_CODE (x) != SYMBOL_REF)) ++ return NULL_TREE; ++ ++ /* Get the declaration of this symbol */ ++ decl = SYMBOL_REF_DECL (x); ++ ++ /* Make sure the declaration is really a function. */ ++ if (!decl || (TREE_CODE(decl) != FUNCTION_DECL)) ++ return NULL_TREE; ++ ++ return decl; ++} ++ ++ ++/** Returns nonzero if a function, whose declaration is in DECL, ++ * was declared to have the attribute given by ATTR_NAME. */ ++int ++m6809_function_has_type_attr_p (tree decl, const char *attr_name) ++{ ++ tree type; ++ ++ type = TREE_TYPE (decl); ++ return lookup_attribute (attr_name, TYPE_ATTRIBUTES (type)) != NULL; ++} ++ ++ ++ ++/** Returns nonzero if the current function was declared to have the ++ * attribute given by ATTR_NAME. */ ++int ++m6809_current_function_has_type_attr_p (const char *attr_name) ++{ ++ return m6809_function_has_type_attr_p (current_function_decl, attr_name); ++} ++ ++ ++/** Return nonzero if the current function has no return value. */ ++int ++m6809_current_function_is_void (void) ++{ ++ return (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))); ++} ++ ++ ++/** Get the value of a declaration's 'bank', as set by the 'bank' ++ * attribute. If no bank was declared, it returns NULL by default. */ ++const char * ++m6809_get_decl_bank (tree decl) ++{ ++ tree attr; ++ ++ /* Lookup the 'bank' attribute. If it does not exist, then ++ * return NULL */ ++ attr = lookup_attribute ("bank", DECL_ATTRIBUTES (decl)); ++ if (attr == NULL_TREE) ++ return NULL; ++ ++ /* Make sure it has a value assigned to it */ ++ attr = TREE_VALUE (attr); ++ if (attr == NULL_TREE) ++ { ++ warning (WARNING_OPT "banked function did not declare a bank number"); ++ return NULL; ++ } ++ ++ /* Return the bank name */ ++ attr = TREE_VALUE (attr); ++ return TREE_STRING_POINTER (attr); ++} ++ ++ ++void ++m6809_declare_function_name (FILE *asm_out_file, const char *name, tree decl) ++{ ++ /* Check the function declaration for special properties. ++ * ++ * If the function was declare with __attribute__((bank)), output ++ * assembler definitions to force the function to go into the named ++ * bank. ++ */ ++ const char *bank_name = m6809_get_decl_bank (decl); ++ if (bank_name != NULL) ++ { ++ /* Declare __self_bank as a local assembler value that denotes ++ * which bank the current function is in. This is required only ++ * when the bank actually changes. */ ++ if (strcmp (bank_name, current_bank_name)) ++ { ++ fprintf (asm_out_file, "__self_bank\t.equ %s\n", bank_name); ++ strcpy (current_bank_name, bank_name); ++ } ++ ++ /* Declare a global assembler value that denotes which bank the ++ * named function is in. */ ++ fprintf (asm_out_file, "__%s_bank\t.gblequ %s\n", name, bank_name); ++ ++ /* Force the current function into a new area */ ++ fprintf (asm_out_file, "\t.bank bank_%s (FSFX=_%s)\n", ++ bank_name, bank_name); ++ fprintf (asm_out_file, "\t.area bank_%s (BANK=bank_%s)\n", ++ bank_name, bank_name); ++ } ++ ++ /* Emit the label for the function's name */ ++ ASM_OUTPUT_LABEL (asm_out_file, name); ++} ++ ++#if 0 ++/** ++ * Handle pragmas. Note that only the last branch pragma seen in the ++ * source has any affect on code generation. ++ */ ++ ++#define BAD_PRAGMA(msgid, arg) \ ++ do { warning (WARNING_OPT msgid, arg); return -1; } while (0) ++ ++static int ++pragma_parse (const char *name, tree *sect) ++{ ++ tree s, x; ++ ++ if (pragma_lex (&x) != CPP_OPEN_PAREN) ++ BAD_PRAGMA ("missing '(' after '#pragma %s' - ignored", name); ++ ++ if (pragma_lex (&s) != CPP_STRING) ++ BAD_PRAGMA ("missing section name in '#pragma %s' - ignored", name); ++ ++ if (pragma_lex (&x) != CPP_CLOSE_PAREN) ++ BAD_PRAGMA ("missing ')' for '#pragma %s' - ignored", name); ++ ++ if (pragma_lex (&x) != CPP_EOF) ++ warning (WARNING_OPT "junk at end of '#pragma %s'", name); ++ ++ *sect = s; ++ return 0; ++} ++ ++ ++/* ++ * Handle #pragma section. ++ * This is deprecated; code should use __attribute__(section("name")) ++ * instead. ++ */ ++void pragma_section (cpp_reader *pfile ATTRIBUTE_UNUSED) ++{ ++ tree sect; ++ ++ if (pragma_parse ("section", §)) ++ return; ++ ++ snprintf (code_section_op, 6+TREE_STRING_LENGTH (sect), ++ ".area\t%s", TREE_STRING_POINTER (sect)); ++ snprintf (data_section_op, 6+TREE_STRING_LENGTH (sect), ++ ".area\t%s", TREE_STRING_POINTER (sect)); ++ ++ /* Mark a flag that sections have changed. Upon emitting another ++ * declaration, the new .area directive will be written. */ ++ section_changed++; ++} ++#endif ++ ++/** ++ * Check a `double' value for validity for a particular machine mode. ++ * Called by the CHECK_FLOAT_VALUE() machine-dependent macro. ++ */ ++int ++check_float_value (enum machine_mode mode, double *d, int overflow) ++{ ++ if (mode == SFmode) { ++ if (*d > 1.7014117331926443e+38) { ++ error("magnitude of constant too large for `float'"); ++ *d = 1.7014117331926443e+38; ++ } ++ else if (*d < -1.7014117331926443e+38) { ++ error("magnitude of constant too large for `float'"); ++ *d = -1.7014117331926443e+38; ++ } ++ else if ((*d > 0) && (*d < 2.9387358770557188e-39)) { ++ warning(WARNING_OPT "`float' constant truncated to zero"); ++ *d = 0.0; ++ } ++ else if ((*d < 0) && (*d > -2.9387358770557188e-39)) { ++ warning(WARNING_OPT "`float' constant truncated to zero"); ++ *d = 0.0; ++ } ++ } ++ return overflow; ++} ++ ++ ++ ++/** Declare that the target supports named output sections. */ ++bool m6809_have_named_section = (bool)1; ++ ++ ++/** Write to the assembler file a directive to place ++ * subsequent objects to a different section in the ++ * object file. ASxxxx uses the "area" directive for ++ * this purpose. It does not however support generalized ++ * alignment, and can only place items on an odd/even ++ * boundary. */ ++void ++m6809_asm_named_section ( ++ const char *name, ++ unsigned int flags ATTRIBUTE_UNUSED, ++ tree decl) ++{ ++ fprintf (asm_out_file, "\t.area\t%s\n", name); ++} ++ ++ ++enum reg_class ++m6809_preferred_reload_class (rtx x, enum reg_class regclass) ++{ ++ /* Check cases based on type code of rtx */ ++ switch (GET_CODE(x)) ++ { ++ /* ++ * Observation, 2015-07-19, William Astle ++ * ++ * The original comparison for range for 16 bits was wrong, adding 0x80 ++ * instead of 0x8000. Replaced both 8 bit and 16 bit comparisions with ++ * a more straight forward range comparison - excessive cleverness isn't ++ * really required here. ++ */ ++ case CONST_INT: ++ /* Constants that can fit into 1 byte should be ++ * loaded into a Q_REGS reg */ ++ if ((INTVAL(x) >= -128 && INTVAL(x) <= 127) && ++// if (((unsigned) (INTVAL(x) + 0x80) < 0x100) && ++ (regclass > A_REGS)) ++ return Q_REGS; ++ ++ /* 16-bit constants should be loaded into A_REGS ++ * when possible. gcc may already require A_REGS ++ * or D_REGS for certain types of instructions. ++ * This case applies mostly to simple copy operations ++ * to/from memory when any register will do, but ++ * it's best to avoid using D register since it is ++ * needed for other things. ++ */ ++ else if ((INTVAL(x) >= -32768 && INTVAL(x) <= 32767) && ++// else if (((unsigned) (INTVAL(x) + 0x80) < 0x10000) && ++ (regclass > A_REGS)) ++ return A_REGS; ++ break; ++ ++ case SYMBOL_REF: ++ case LABEL_REF: ++ /* Addresses should always be loaded into A_REGS */ ++ if (regclass >= A_REGS) ++ return (A_REGS); ++ ++ default: ++ break; ++ } ++ ++ /* Check cases based on mode of rtx */ ++ if ((GET_MODE(x) == QImode) && (regclass != A_REGS)) ++ return Q_REGS; ++ ++ /* Default: return whatever class reload suggested */ ++ return regclass; ++} ++ ++ ++/** ++ * Check a new declaration for the "section" attribute. ++ * If it exists, and the target section is "direct", then mark ++ * the declaration (in RTL) to indicate special treatment. ++ * When the variable is referenced later, we test for this flag ++ * and can emit special asm text to force the assembler to use ++ * short instructions. ++ */ ++static void ++m6809_encode_section_info (tree decl, rtx rtl, int new_decl_p ATTRIBUTE_UNUSED) ++{ ++ tree attr, id; ++ const char *name; ++ const char *decl_name; ++ ++ /* We only care about variable declarations, not functions */ ++ if (TREE_CODE (decl) != VAR_DECL) ++ return; ++ ++ /* For debugging purposes only; grab the decl's name */ ++ decl_name = IDENTIFIER_POINTER (DECL_NAME (decl)); ++ ++ /* Give up if the decl doesn't have any RTL */ ++ if (!DECL_RTL (decl)) ++ return; ++ ++ /* See if it has a section attribute */ ++ attr = lookup_attribute ("section", DECL_ATTRIBUTES (decl)); ++ if (!attr) ++ return; ++ ++ /* See if the section attribute has a value */ ++ id = TREE_VALUE (TREE_VALUE (attr)); ++ if (!id) ++ return; ++ name = TREE_STRING_POINTER (id); ++ if (!name) ++ return; ++ ++ /* See if the value is 'direct'. If so, mark it. */ ++ if (!strcmp (name, "direct")) ++ SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1; ++} ++ ++ ++/** ++ * Output code to perform a complex shift, for which there is no ++ * direct support in the instruction set. ++ * ++ * shift1 is an instruction pattern for performing a 1-bit modification. ++ * This code wraps that pattern in a loop to perform the shift N times, ++ * where N is given by the address register in operands[2]. ++ * ++ * To support 16-bit shifts, shift2 can also be provided: it is ++ * a second instruction to be included in the loop. 8-bit shift ++ * insns will pass NULL here. ++ * ++ * The insn length of shift1/shift2 is assumed to be 1 byte, ++ * which works in all of the cases it is needed so far. ++ */ ++static void ++m6809_gen_register_shift ( ++ rtx *operands, ++ const char *shift1, ++ const char *shift2 ) ++{ ++ char beq_pattern[32]; ++ char bra_pattern[32]; ++ ++ int shiftlen = (shift1 && shift2) ? 2 : 1; ++ int cmplen = (REGNO (operands[2]) == HARD_X_REGNUM) ? 3 : 4; ++ ++ int beq_offset = 2 + shiftlen + 2; ++ int bra_offset = shiftlen + 2 + cmplen + 2; ++ ++ sprintf (beq_pattern, "beq\t.+%d", beq_offset); ++ sprintf (bra_pattern, "bra\t.-%d", bra_offset); ++ ++ output_asm_insn ("pshs\t%2", operands); ++ output_asm_insn ("lea%2\t-1,%2", operands); ++ output_asm_insn ("cmp%2\t#-1", operands); ++ output_asm_insn (beq_pattern, operands); ++ if (shift1) ++ output_asm_insn (shift1, operands); ++ if (shift2) ++ output_asm_insn (shift2, operands); ++ output_asm_insn (bra_pattern, operands); ++ output_asm_insn ("puls\t%2", operands); ++} ++ ++ ++/** Generate RTL for the upper 8-bits of a 16-bit constant. */ ++rtx ++gen_rtx_const_high (rtx r) ++{ ++ unsigned char v = (INTVAL (r) >> 8) & 0xFF; ++ signed char s = (signed char)v; ++ return gen_int_mode (s, QImode); ++} ++ ++ ++/** Generate RTL for the lower 8-bits of a 16-bit constant. */ ++rtx ++gen_rtx_const_low (rtx r) ++{ ++ unsigned char v = INTVAL (r) & 0xFF; ++ signed char s = (signed char)v; ++ return gen_int_mode (s, QImode); ++} ++ ++ ++/** Generate RTL to allocate/free bytes on the stack. ++ * CODE is given as MINUS when allocating and PLUS when freeing, ++ * to match the semantics of a downward-growing stack. SIZE ++ * is always given as a positive integer. ++ */ ++static rtx ++gen_rtx_stack_adjust (enum rtx_code code, int size) ++{ ++ if (size <= 0) ++ return NULL_RTX; ++ ++ if (code == MINUS) ++ size = -size; ++ ++ return gen_rtx_SET (Pmode, stack_pointer_rtx, ++ gen_rtx_PLUS (Pmode, stack_pointer_rtx, ++ gen_int_mode (size, HImode))); ++} ++ ++ ++/** Generate RTL to push/pop a set of registers. */ ++rtx ++gen_rtx_register_pushpop (int op, int regs) ++{ ++ rtx nregs = gen_int_mode (regs, QImode); ++ ++ if (op == UNSPEC_PUSH_RS) ++ return gen_register_push (nregs); ++ else ++ return gen_register_pop (nregs); ++} ++ ++ ++/* Given a register set REGS, where the bit positions correspond to ++ * hard register numbers, return another bitmask that represents the ++ * order in which those registers would be pushed/popped. ++ * Registers that are pushed first have higher bit positions. ++ * The pop order is just the reverse bitmask. ++ * These values are the same as the bitmasks actually used in the ++ * machine instructions. */ ++static unsigned int ++register_push_order (int regs) ++{ ++ unsigned int order = 0; ++ ++ if (REGSET_CONTAINS_P (HARD_PC_REGNUM, regs)) ++ order |= 0x80; ++ if (REGSET_CONTAINS_P (HARD_U_REGNUM, regs)) ++ order |= 0x40; ++ if (REGSET_CONTAINS_P (HARD_Y_REGNUM, regs)) ++ order |= 0x20; ++ if (REGSET_CONTAINS_P (HARD_X_REGNUM, regs)) ++ order |= 0x10; ++ if (REGSET_CONTAINS_P (HARD_DP_REGNUM, regs)) ++ order |= 0x8; ++ if (REGSET_CONTAINS_P (HARD_B_REGNUM, regs)) ++ order |= 0x4; ++ if (REGSET_CONTAINS_P (HARD_A_REGNUM, regs)) ++ order |= 0x2; ++ if (REGSET_CONTAINS_P (HARD_CC_REGNUM, regs)) ++ order |= 0x1; ++ ++ if (REGSET_CONTAINS_P (HARD_D_REGNUM, regs)) ++ order |= (0x4 | 0x2); ++ return order; ++} ++ ++ ++/* Returns nonzero if two consecutive push or pop instructions, ++ * as determined by the OP, can be merged into a single instruction. ++ * The first instruction in the sequence pushes/pops REGS1; the ++ * second applies to REGS2. ++ * ++ * If true, the resulting instruction can use (regs1 | regs2) ++ * safely. ++ */ ++int ++m6809_can_merge_pushpop_p (int op, int regs1, int regs2) ++{ ++ /* Register sets must not overlap */ ++ if (regs1 & regs2) ++ return 0; ++ ++ if (op == UNSPEC_PUSH_RS) ++ return (register_push_order (regs1) > register_push_order (regs2)); ++ else if (op == UNSPEC_POP_RS) ++ return (register_push_order (regs1) < register_push_order (regs2)); ++ else ++ return 0; ++} ++ ++ ++/** Emit instructions for making a library call. ++ * MODE is the mode of the operation. ++ * NAME is the library function name. ++ * OPERANDS is the rtx array provided by the recognizer. ++ * COUNT is the number of input operands to the call, and ++ * should be 1 for a unary op or 2 for a binary op. ++ */ ++void ++emit_libcall_insns (enum machine_mode mode, ++ const char *name, ++ rtx *operands, ++ int count) ++{ ++ /* Generate an rtx for the call target. */ ++ rtx symbol = gen_rtx_SYMBOL_REF (Pmode, name); ++ ++ /* Emit the library call. Slightly different based ++ on the number of operands */ ++ if (count == 2) ++ emit_library_call (symbol, LCT_NORMAL, mode, ++ 2, operands[1], mode, operands[2], mode); ++ else ++ emit_library_call (symbol, LCT_NORMAL, mode, ++ 1, operands[1], mode); ++ ++ /* The library call is expected to put its result ++ in LIBCALL_VALUE, so need to copy it into the destination. */ ++ emit_move_insn (operands[0], LIBCALL_VALUE(mode)); ++} ++ ++ ++/** ++ * A small helper function that writes out a single branch instruction. ++ * OPCODE is the short name, e.g. "ble". ++ * OPERANDS has the rtx for the target label. ++ * LONG_P is nonzero if we are emitting a long branch, and need to ++ * prepend an 'l' to the opcode name. ++ */ ++void output_branch_insn1 (const char *opcode, rtx *operands, int long_p) ++{ ++ char pattern[64]; ++ sprintf (pattern, "%s%s\t%%l0", long_p ? "l" : "", opcode); ++ output_asm_insn (pattern, operands); ++} ++ ++/** ++ * Output a branch/conditional branch insn of the proper ++ * length. code identifies the particular branch insn. ++ * operands holds the branch target in operands[0]. ++ * length says what the size of this insn should be. ++ * Based on the length, we know whether it should be a ++ * short (8-bit) or long (16-bit) branch. ++ */ ++const char * ++output_branch_insn (enum rtx_code code, rtx *operands, int length) ++{ ++ int shortform; ++ ++ /* Decide whether or not to use the long or short form. ++ * Calculate automatically based on insn lengths. */ ++ shortform = ((length > 2) ? 0 : 1); ++ ++ /* Determine the proper opcode. ++ * Use the short (2-byte) opcode if the target is within ++ * reach. Otherwise, use jmp (3-byte opcode), unless ++ * compiling with -fpic, in which case we'll need to use ++ * lbra (4-byte opcode). ++ */ ++ switch (code) ++ { ++ case LABEL_REF: ++ if (shortform) ++ output_branch_insn1 ("bra", operands, 0); ++ else if (flag_pic) ++ output_branch_insn1 ("bra", operands, 1); ++ else ++ output_branch_insn1 ("jmp", operands, 0); ++ break; ++ case EQ: ++ output_branch_insn1 ("beq", operands, !shortform); ++ break; ++ case NE: ++ output_branch_insn1 ("bne", operands, !shortform); ++ break; ++ case GT: ++ output_branch_insn1 ("bgt", operands, !shortform); ++ break; ++ case GTU: ++ output_branch_insn1 ("bhi", operands, !shortform); ++ break; ++ case LT: ++ if (cc_prev_status.flags & CC_NO_OVERFLOW) ++ { ++ output_branch_insn1 ("bmi", operands, !shortform); ++ } ++ else ++ { ++ output_branch_insn1 ("blt", operands, !shortform); ++ } ++ break; ++ case LTU: ++ output_branch_insn1 ("blo", operands, !shortform); ++ break; ++ case GE: ++ if (cc_prev_status.flags & CC_NO_OVERFLOW) ++ { ++ output_branch_insn1 ("bpl", operands, !shortform); ++ } ++ else ++ { ++ output_branch_insn1 ("bge", operands, !shortform); ++ } ++ break; ++ case GEU: ++ output_branch_insn1 ("bhs", operands, !shortform); ++ break; ++ case LE: ++ if (cc_prev_status.flags & CC_NO_OVERFLOW) ++ { ++ output_branch_insn1 ("bmi", operands, !shortform); ++ output_branch_insn1 ("beq", operands, !shortform); ++ } ++ else ++ { ++ output_branch_insn1 ("ble", operands, !shortform); ++ } ++ break; ++ case LEU: ++ output_branch_insn1 ("bls", operands, !shortform); ++ break; ++ default: ++ abort(); ++ break; ++ } ++ return ""; ++} ++ ++ ++/** Returns the "cost" of an RTL expression. ++ * In general, the expression "COSTS_N_INSNS(1)" is used to represent ++ * the cost of a fast 8-bit arithmetic instruction that operates on ++ * a reg/mem or a reg/immed. Other costs are relative to this. ++ * ++ * Notes: ++ * - The cost of a REG is always zero; this cannot be changed. ++ * ++ * - On the 6809, instructions on two registers will nearly always take ++ * longer than those that operate on a register and a constant/memory, ++ * because of the way the instruction set is structured. ++ * ++ * TODO: multiply HImode by 2 should be done via shifts, instead of add. ++ */ ++static bool ++m6809_rtx_costs (rtx X, int code, int outer_code ATTRIBUTE_UNUSED, ++ int *total, bool speed) ++{ ++ int has_const_arg = 0; ++ HOST_WIDE_INT const_arg; ++ enum machine_mode mode; ++ int nargs = 1; ++ rtx op0, op1; ++ ++ /* Data RTXs return a value between 0-3, depending on complexity. ++ All of these are less than COSTS_N_INSNS(1). */ ++ switch (code) ++ { ++ case CC0: ++ case PC: ++ *total = 0; ++ return true; ++ ++ case CONST_INT: ++ if (X == const0_rtx) ++ { ++ *total = 0; ++ return true; ++ } ++ else if ((unsigned) INTVAL (X) < 077) ++ { ++ *total = 1; ++ return true; ++ } ++ else ++ { ++ *total = 2; ++ return true; ++ } ++ ++ case LABEL_REF: case CONST: ++ *total = 2; ++ return true; ++ ++ case SYMBOL_REF: ++ /* References to memory are made cheaper if they have ++ * the 'direct' mode attribute set */ ++ *total = (SYMBOL_REF_FLAG (X)) ? 1 : 2; ++ return true; ++ ++ case MEM: ++ /* See what form of address was given */ ++ X = XEXP (X, 0); ++ switch (GET_CODE (X)) ++ { ++ case SYMBOL_REF: ++ *total = (SYMBOL_REF_FLAG (X)) ? 1 : 2; ++ break; ++ ++ case CONST_INT: ++ *total = 2; ++ break; ++ ++ case MEM: ++ *total = COSTS_N_INSNS (1) + 2; ++ break; ++ ++ default: ++ break; ++ } ++ return true; ++ ++ case CONST_DOUBLE: ++ /* TODO : not sure about this value. */ ++ *total = 3; ++ return true; ++ ++ default: ++ break; ++ } ++ ++ /* Decode the rtx */ ++ mode = GET_MODE (X); ++ op0 = XEXP (X, 0); ++ op1 = XEXP (X, 1); ++ ++ /* We don't implement anything in SImode or greater. */ ++ if (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (SImode)) ++ { ++ *total = COSTS_N_INSNS (100); ++ return true; ++ } ++ ++ /* Figure out if there is a constant argument, and its value. */ ++ if (GET_RTX_CLASS (code) == RTX_BIN_ARITH ++ || GET_RTX_CLASS (code) == RTX_COMM_ARITH) ++ { ++ nargs = 2; ++ if (GET_CODE (op1) == CONST_INT) ++ { ++ has_const_arg = 1; ++ const_arg = INTVAL (op1); ++ } ++ } ++ ++ /* Penalize a reg/reg operation by adding MEMORY_MOVE_COST, ++ * Ignore soft registers, since these are really in memory. ++ * ++ * TODO: penalize HImode reg/reg for most operations, except maybe ++ * additions since index registers allow for that. ++ * ++ * TODO: shifts by constant N do not always require N instructions; ++ * some of this can be done cheaper. The number of actual insns can be ++ * predicted well. ++ */ ++ if (nargs == 2 && REAL_REG_P (op0) && REAL_REG_P (op1)) ++ { ++ *total = MEMORY_MOVE_COST (mode, Q_REGS, 0); ++ } ++ else ++ { ++ *total = 0; ++ } ++ ++ /* Operator RTXs are counted as COSTS_N_INSNS(N), where N is ++ the estimated number of actual machine instructions needed to ++ perform the computation. Some small adjustments are made since ++ some "instructions" are more complex than others. */ ++ switch (code) ++ { ++ case PLUS: case MINUS: case COMPARE: ++ /* 6809 handles these natively in QImode, and in HImode as long ++ * as operand 1 is constant. */ ++ if (mode == QImode || (mode == HImode && has_const_arg)) ++ *total += COSTS_N_INSNS (1); ++ else ++ *total += COSTS_N_INSNS (GET_MODE_SIZE (mode)); ++ ++ /* -1, 0, and 1 can be done using inherent instructions ++ * for PLUS and MINUS in QImode, so don't add extra cost. */ ++ if (has_const_arg ++ && (mode == QImode || mode == HImode) ++ && (const_arg == -1 || const_arg == 0 || const_arg == 1) ++ && (code == PLUS || code == MINUS)) ++ { ++ return true; ++ } ++ break; ++ ++ case AND: case IOR: case XOR: ++ case NEG: case NOT: ++ /* 6809 handles these natively in QImode, but requires ++ * splitting in HImode. Treat these as 2 insns. */ ++ *total += COSTS_N_INSNS (1) * GET_MODE_SIZE (mode); ++ break; ++ ++ case ASHIFT: case ASHIFTRT: case LSHIFTRT: ++ case ROTATE: case ROTATERT: ++ /* 6809 can do shift/rotates of a QImode by a constant in ++ * 1 insn times the shift count, or in HImode by a constant ++ * by splitting to 2 insns. ++ * ++ * Shift by a nonconstant will take significantly longer ++ * than any of these. */ ++ if (has_const_arg) ++ { ++ const_arg %= (GET_MODE_SIZE (mode) * 8); ++ if (const_arg == 0) ++ { ++ *total += COSTS_N_INSNS(1); ++ return true; ++ } ++ ++ /* HImode shifts greater than 8 get optimized due ++ * to register transfer from b to a; this cuts down the ++ * cost. */ ++ if (const_arg >= 8) ++ { ++ *total += COSTS_N_INSNS (1); ++ const_arg -= 8; ++ } ++ ++ /* The computed cost is 'const_arg' 1-bit shifts, doubled ++ if in HImode, minus the cost of the constant itself which ++ will be added in later but really shouldn't be. */ ++ *total += COSTS_N_INSNS (const_arg) * GET_MODE_SIZE (mode) - 1; ++ return true; ++ } ++ else ++ { ++ /* It may take up to 7 iterations of about 6-7 real ++ * instructions, so make this expensive. */ ++ *total += COSTS_N_INSNS (50); ++ } ++ break; ++ ++ case MULT: ++ { ++ /* Multiply is cheap when both arguments are 8-bits. They ++ could be QImode, or QImode widened to HImode, or a constant ++ that fits into 8-bits. As long as both operands qualify, ++ we can use a single mul instruction. ++ ++ Assume that fast multiply can be used, and change this if we find ++ differently... */ ++ int ok_for_qihi3 = 1; ++ ++ /* Check the first operand */ ++ switch (GET_MODE (op0)) ++ { ++ case QImode: ++ break; ++ case HImode: ++ if (GET_CODE (op0) != SIGN_EXTEND && GET_CODE (op0) != ZERO_EXTEND) ++ ok_for_qihi3 = 0; ++ break; ++ default: ++ ok_for_qihi3 = 0; ++ break; ++ } ++ ++ /* Likewise, check the second operand. This is where constants may appear. */ ++ switch (GET_MODE (op1)) ++ { ++ case QImode: ++ break; ++ case HImode: ++ if (GET_CODE (op1) != SIGN_EXTEND && GET_CODE (op1) != ZERO_EXTEND) ++ ok_for_qihi3 = 0; ++ break; ++ case VOIDmode: ++ if (!CONST_OK_FOR_LETTER_P (const_arg, 'K')) ++ ok_for_qihi3 = 0; ++ break; ++ default: ++ ok_for_qihi3 = 0; ++ break; ++ } ++ ++ /* Fast multiply takes about 4 times as many cycles as a normal ++ arithmetic operation. Otherwise, it will take an expensive libcall. */ ++ if (ok_for_qihi3) ++ *total += COSTS_N_INSNS (4); ++ else ++ *total = COSTS_N_INSNS (50); ++ break; ++ } ++ ++ case DIV: case UDIV: case MOD: case UMOD: ++ /* These all require more expensive libcalls. */ ++ *total += COSTS_N_INSNS (100); ++ break; ++ ++ /* TODO : TRUNCATE, SIGN_EXTEND, and ZERO_EXTEND */ ++ ++ /* These can normally be done with autoincrement, etc., so ++ * don't charge for them. */ ++ case PRE_DEC: ++ case PRE_INC: ++ case POST_DEC: ++ case POST_INC: ++ break; ++ ++ default: ++ break; ++ } ++ ++ /* Always return false, and let the caller gather the costs ++ * of the operands */ ++ return false; ++} ++ ++ ++static tree ++m6809_handle_fntype_attribute (tree *node, tree name, ++ tree args ATTRIBUTE_UNUSED, ++ int flags ATTRIBUTE_UNUSED, ++ bool *no_add_attrs) ++{ ++ if (TREE_CODE (*node) != FUNCTION_TYPE) ++ { ++ warning (WARNING_OPT "'%s' only valid for functions", ++ IDENTIFIER_POINTER (name)); ++ *no_add_attrs = TRUE; ++ } ++ ++ return NULL_TREE; ++} ++ ++ ++static tree ++m6809_handle_data_type_attribute (tree *node ATTRIBUTE_UNUSED, ++ tree name ATTRIBUTE_UNUSED, ++ tree args ATTRIBUTE_UNUSED, ++ int flags ATTRIBUTE_UNUSED, ++ bool *no_add_attrs ATTRIBUTE_UNUSED) ++{ ++ return NULL_TREE; ++} ++ ++ ++ ++static tree ++m6809_handle_default_attribute (tree *node ATTRIBUTE_UNUSED, ++ tree name ATTRIBUTE_UNUSED, ++ tree args ATTRIBUTE_UNUSED, ++ int flags ATTRIBUTE_UNUSED, ++ bool *no_add_attrs ATTRIBUTE_UNUSED ) ++{ ++ return NULL_TREE; ++} ++ ++ ++/* Table of valid machine attributes */ ++const struct attribute_spec m6809_attribute_table[] = { /* ++{ name, min, max, decl, type, fntype, handler } */ ++{ "interrupt", 0, 0, false, true, true, m6809_handle_fntype_attribute }, ++{ "naked", 0, 0, false, true, true, m6809_handle_fntype_attribute }, ++{ "far", 0, 1, false, true, true, m6809_handle_fntype_attribute }, ++{ "bank", 0, 1, true, false, false, m6809_handle_default_attribute }, ++{ "boolean", 0, 0, false, true, false, m6809_handle_data_type_attribute }, ++{ NULL, 0, 0, false, true, false, NULL }, ++}; ++ ++ ++/** Initialize builtin routines for the 6809. */ ++void ++m6809_init_builtins (void) ++{ ++ /* Create type trees for each function signature required. ++ * ++ * void_ftype_void = void f(void) ++ * void_ftype_uchar = void f(unsigned char) ++ * uchar_ftype_uchar2 = unsigned char f (unsigned char, unsigned char) ++ */ ++ tree void_ftype_void = ++ build_function_type (void_type_node, void_list_node); ++ ++ tree void_ftype_uchar = ++ build_function_type (void_type_node, ++ tree_cons (NULL_TREE, unsigned_char_type_node, void_list_node)); ++ ++ tree uchar_ftype_uchar2 = ++ build_function_type (unsigned_char_type_node, ++ tree_cons (NULL_TREE, unsigned_char_type_node, ++ tree_cons (NULL_TREE, unsigned_char_type_node, void_list_node))); ++ ++ /* Register each builtin function. */ ++ add_builtin_function ("__builtin_swi", void_ftype_void, ++ M6809_SWI, BUILT_IN_MD, NULL, NULL_TREE); ++ ++ add_builtin_function ("__builtin_swi2", void_ftype_void, ++ M6809_SWI2, BUILT_IN_MD, NULL, NULL_TREE); ++ ++ add_builtin_function ("__builtin_swi3", void_ftype_void, ++ M6809_SWI3, BUILT_IN_MD, NULL, NULL_TREE); ++ ++ add_builtin_function ("__builtin_cwai", void_ftype_uchar, ++ M6809_CWAI, BUILT_IN_MD, NULL, NULL_TREE); ++ ++ add_builtin_function ("__builtin_sync", void_ftype_void, ++ M6809_SYNC, BUILT_IN_MD, NULL, NULL_TREE); ++ ++ add_builtin_function ("__builtin_nop", void_ftype_void, ++ M6809_NOP, BUILT_IN_MD, NULL, NULL_TREE); ++ ++ add_builtin_function ("__builtin_blockage", void_ftype_void, ++ M6809_BLOCKAGE, BUILT_IN_MD, NULL, NULL_TREE); ++ ++ add_builtin_function ("__builtin_add_decimal", uchar_ftype_uchar2, ++ M6809_ADD_DECIMAL, BUILT_IN_MD, NULL, NULL_TREE); ++ ++ add_builtin_function ("__builtin_add_carry", uchar_ftype_uchar2, ++ M6809_ADD_CARRY, BUILT_IN_MD, NULL, NULL_TREE); ++ ++ add_builtin_function ("__builtin_sub_carry", uchar_ftype_uchar2, ++ M6809_SUB_CARRY, BUILT_IN_MD, NULL, NULL_TREE); ++} ++ ++ ++/** Used by m6809_expand_builtin, given a tree ARGLIST which ++ * refers to the operands of a builtin call, return an rtx ++ * that represents the nth operand, as denoted by OPNUM, which ++ * is a zero-based integer. MODE gives the expected mode ++ * of the operand. ++ * ++ * This rtx is suitable for use in the emitted RTL for the ++ * builtin instruction. */ ++rtx ++m6809_builtin_operand (tree arglist, enum machine_mode mode, int opnum) ++{ ++ tree arg; ++ rtx r; ++ ++ arg = CALL_EXPR_ARG (arglist, opnum); ++ ++ /* Convert the tree to RTL */ ++ r = expand_expr (arg, NULL_RTX, mode, EXPAND_NORMAL); ++ if (r == NULL_RTX) ++ return NULL_RTX; ++ return r; ++} ++ ++ ++/** Expand a builtin that was registered in init_builtins into ++ * RTL. */ ++rtx ++m6809_expand_builtin (tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED ) ++{ ++ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); ++ tree arglist = exp; ++ unsigned int fcode = DECL_FUNCTION_CODE (fndecl); ++ rtx r0, r1; ++ ++ switch (fcode) ++ { ++ case M6809_SWI: ++ r0 = gen_rtx_CONST_INT (VOIDmode, 1); ++ emit_insn (target = gen_m6809_swi (r0)); ++ return target; ++ ++ case M6809_SWI2: ++ r0 = gen_rtx_CONST_INT (VOIDmode, 2); ++ emit_insn (target = gen_m6809_swi (r0)); ++ return target; ++ ++ case M6809_SWI3: ++ r0 = gen_rtx_CONST_INT (VOIDmode, 3); ++ emit_insn (target = gen_m6809_swi (r0)); ++ return target; ++ ++ case M6809_CWAI: ++ r0 = m6809_builtin_operand (arglist, QImode, 0); ++ emit_insn (target = gen_m6809_cwai (r0)); ++ return target; ++ ++ case M6809_SYNC: ++ emit_insn (target = gen_m6809_sync ()); ++ return target; ++ ++ case M6809_ADD_CARRY: ++ r0 = m6809_builtin_operand (arglist, QImode, 0); ++ r1 = m6809_builtin_operand (arglist, QImode, 1); ++ if (!target) ++ target = gen_reg_rtx (QImode); ++ emit_insn (gen_addqi3_carry (target, r0, r1)); ++ return target; ++ ++ case M6809_SUB_CARRY: ++ r0 = m6809_builtin_operand (arglist, QImode, 0); ++ r1 = m6809_builtin_operand (arglist, QImode, 1); ++ if (!target) ++ target = gen_reg_rtx (QImode); ++ emit_insn (gen_subqi3_carry (target, r0, r1)); ++ return target; ++ ++ case M6809_NOP: ++ emit_insn (target = gen_nop ()); ++ return target; ++ ++ case M6809_BLOCKAGE: ++ emit_insn (target = gen_blockage ()); ++ return target; ++ ++ case M6809_ADD_DECIMAL: ++ r0 = m6809_builtin_operand (arglist, QImode, 0); ++ r1 = m6809_builtin_operand (arglist, QImode, 1); ++ if (!target) ++ target = gen_reg_rtx (QImode); ++ emit_insn (gen_addqi3_decimal (target, r0, r1)); ++ return target; ++ ++ default: ++ warning (WARNING_OPT "unknown builtin expansion ignored"); ++ return NULL_RTX; ++ } ++} ++ ++ ++ ++/* Returns nonzero if 'x' represents a function that was declared ++ * as __noreturn__. */ ++int ++noreturn_functionp (rtx x) ++{ ++ tree decl = call_target_decl (x); ++ ++ if (decl == NULL_TREE) ++ return 0; ++ else ++ return TREE_THIS_VOLATILE (decl); ++} ++ ++ ++const char * ++far_function_type_p (tree type) ++{ ++ tree attr; ++ const char *page; ++ ++ /* Return whether or not this decl has the far attribute */ ++ attr = lookup_attribute ("far", TYPE_ATTRIBUTES (type)); ++ if (attr == NULL_TREE) ++ return NULL; ++ ++ /* If it is far, check for a value */ ++ attr = TREE_VALUE (attr); ++ if (attr == NULL_TREE) ++ { ++ warning (WARNING_OPT "far code page not specified, using local value"); ++ return far_code_page; ++ } ++ ++ /* We have a TREE_LIST of attribute values, get the first one. ++ * It should be an INTEGER_CST. */ ++ attr = TREE_VALUE (attr); ++ page = TREE_STRING_POINTER (attr); ++ return page; ++} ++ ++ ++/* For a far function, returns the identifier that states which page ++ * it resides in. Otherwise, returns NULL for ordinary functions. */ ++const char * ++far_functionp (rtx x) ++{ ++ tree decl, decl_type; ++ const char *page; ++ ++ /* Find the FUNCTION_DECL corresponding to the rtx being called. */ ++ decl = call_target_decl (x); ++ if (decl == NULL_TREE) ++ return NULL; ++ ++ /* See if the function has the new 'banked' attribute. These ++ * are numeric instead of text */ ++ page = m6809_get_decl_bank (decl); ++ if (page) ++ return page; ++ ++ /* No, lookup the type of the function and see if the type ++ * specifies far or not. */ ++ decl_type = TREE_TYPE (decl); ++ if (decl_type == NULL_TREE) ++ return NULL; ++ return far_function_type_p (decl_type); ++} ++ ++ ++ ++/** Outputs the assembly language for a far call. */ ++void ++output_far_call_insn (rtx *operands, int has_return) ++{ ++ static char page_data[64]; ++ const char *called_page; ++ ++ /* The logic is the same for functions whether or not there ++ * is a return value. Skip over the return value in this ++ * case, so that the call location is always operands[0]. */ ++ if (has_return) ++ operands++; ++ ++ /* Get the name of the page being called */ ++ called_page = far_functionp (operands[0]); ++ ++#if 0 /* TODO : broken logic */ ++ /* See if the called page name is a 'bank' */ ++ if (isdigit (*called_page)) ++ { ++ /* New style banking */ ++ if (!strcmp (called_page, current_bank_name)) ++ { ++ /* Same page */ ++ output_asm_insn ("jsr\t%0", operands); ++ } ++ else ++ { ++ /* Different page */ ++ output_asm_insn ("jsr\t__far_call_handler\t;new style", operands); ++ output_asm_insn ("\t.dw\t%0", operands); ++ sprintf (page_data, "\t.db\t%s", called_page); ++ output_asm_insn (page_data, operands); ++ } ++ return; ++ } ++#endif ++ ++ /* Are we calling a different page than we are running in? */ ++ if (!strcmp (called_page, far_code_page)) ++ { ++ /* Same page : no need to execute a far call */ ++ if (flag_pic) ++ output_asm_insn ("lbsr\t%C0", operands); ++ else ++ output_asm_insn ("jsr\t%0", operands); ++ } ++ else ++ { ++ /* Different page : need to emit far call thunk */ ++ ++ /* First output a call to the thunk for making far calls. */ ++ if (flag_pic) ++ output_asm_insn ("lbsr\t__far_call_handler", operands); ++ else ++ output_asm_insn ("jsr\t__far_call_handler\t;old style", operands); ++ ++ /* Now output the name of the call site */ ++ output_asm_insn ("\t.dw\t%C0", operands); ++ ++ /* Finally output the page number */ ++ sprintf (page_data, "\t.db\t%s", far_functionp (operands[0])); ++ output_asm_insn (page_data, operands); ++ } ++} ++ ++ ++int ++m6809_init_cumulative_args (CUMULATIVE_ARGS cum ATTRIBUTE_UNUSED, ++ tree fntype, ++ rtx libname ATTRIBUTE_UNUSED) ++{ ++ cum = 0; ++ ++ /* For far functions, the current implementation does not allow for ++ * stack parameters. So note whenever the called function is far ++ * and in a different page than the current one; such a function ++ * should give an error if a stack parameter is generated. */ ++ if (fntype) ++ { ++ const char *called_page = far_function_type_p (fntype); ++ if (called_page && strcmp (called_page, far_code_page) && !TARGET_FAR_STACK_PARAM) ++ cum |= CUM_STACK_INVALID; ++ } ++ ++ if (fntype && TYPE_ARG_TYPES (fntype) != 0 && ++ (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)) ++ { ++ /* has variable arguments, cannot use registers */ ++ cum |= (CUM_X_MASK | CUM_B_MASK | CUM_STACK_ONLY); ++ } ++ ++ if (m6809_abi_version == M6809_ABI_VERSION_STACK) ++ { ++ /* cannot use registers ; only use the stack */ ++ cum |= (CUM_STACK_ONLY | CUM_X_MASK | CUM_B_MASK); ++ } ++ ++ return cum; ++} ++ ++ ++rtx ++m6809_function_arg_on_stack (CUMULATIVE_ARGS *cump) ++{ ++ if (*cump & CUM_STACK_INVALID) ++ { ++ *cump &= ~CUM_STACK_INVALID; ++ error ("far function needs stack, will not work"); ++ } ++ return NULL_RTX; ++} ++ ++void m6809_asm_trampoline_template(FILE *f) ++{ ++ fprintf(f, "ldy #0000\n"); ++ fprintf(f, "jmp 0x0000\n"); ++} ++ ++/* ++ * Trampoline output: ++ * ++ * ldu #&cxt 4 bytes --LDY- ?? ?? ++ * jmp fnaddr 3 bytes JMP ?? ?? ++ */ ++void ++m6809_initialize_trampoline (rtx tramp, tree fndecl, rtx cxt) ++{ ++ rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); ++ /* TODO - optimize by generating the entire trampoline code here, ++ * and removing the template altogether, since there are only two ++ * bytes there that matter. */ ++ emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt); ++ emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 5)), fnaddr); ++} ++ ++ ++/** Echo the version of the compiler and the name of the source file ++ * at the beginning of each assembler output file. asm_out_file ++ * is a global FILE * pointing to the output stream. */ ++void ++m6809_asm_file_start (void) ++{ ++ const char *module_name; ++ ++ fprintf (asm_out_file, "\n;;; gcc for m6809 : %s %s\n", ++ __DATE__, __TIME__); ++ fprintf (asm_out_file, ";;; %s\n", version_string); ++ ++ fprintf (asm_out_file, ";;; ABI version %d\n", m6809_abi_version); ++ fprintf (asm_out_file, ";;; %s\n", ++ (TARGET_BYTE_INT ? "-mint8" : "-mint16")); ++ if (TARGET_EXPERIMENT) ++ fprintf (asm_out_file, ";;; -mexperiment\n"); ++ if (TARGET_WPC) ++ fprintf (asm_out_file, ";;; -mwpc\n"); ++ if (TARGET_6309) ++ fprintf (asm_out_file, ";;; -m6309\n"); ++ ++ /* Print the name of the module, which is taken as the base name ++ * of the input file. ++ * See the 'User-Defined Symbols' section of the assembler ++ * documentation for the rules on valid symbols. ++ */ ++ module_name = lbasename (main_input_filename); ++ ++ fprintf (asm_out_file, "\t.module\t"); ++ ++ if (*module_name >= '0' && *module_name <= '9') ++ fprintf (asm_out_file, "_"); ++ ++ while (*module_name) ++ { ++ if ((*module_name >= '0' && *module_name <= '9') ++ || (*module_name >= 'A' && *module_name <= 'Z') ++ || (*module_name >= 'a' && *module_name <= 'z') ++ || *module_name == '$' ++ || *module_name == '.' ++ || *module_name == '_') ++ { ++ fprintf (asm_out_file, "%c", *module_name); ++ } ++ else ++ { ++ fprintf (asm_out_file, "_"); ++ } ++ module_name++; ++ } ++ ++ fprintf (asm_out_file, "\n"); ++} ++ ++ ++/** Returns true if prologue/epilogue code is required for the ++ * current function being compiled. ++ * ++ * This is just the inverse of whether the function is declared as ++ * 'naked'. ++ */ ++int ++prologue_epilogue_required (void) ++{ ++ return !m6809_current_function_has_type_attr_p ("naked") ++ && !m6809_current_function_has_type_attr_p ("noreturn"); ++} ++ ++ ++/** Expand RTL for function entry */ ++void ++emit_prologue_insns (void) ++{ ++ rtx insn; ++ unsigned int live_regs = m6809_get_live_regs (); ++ unsigned int frame_size = get_frame_size (); ++ ++ /* Save all registers used, including the frame pointer */ ++ if (live_regs && !m6809_current_function_has_type_attr_p ("interrupt")) ++ { ++ insn = emit_insn ( ++ gen_rtx_register_pushpop (UNSPEC_PUSH_RS, live_regs)); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ /* Allocate space for local variables */ ++ if (frame_size != 0) ++ { ++ insn = emit_insn (gen_rtx_stack_adjust (MINUS, frame_size)); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ /* Set the frame pointer if it is needed */ ++ if (frame_pointer_needed) ++ { ++ insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++} ++ ++ ++/** Expand RTL for function exit */ ++void ++emit_epilogue_insns (bool sibcall_p) ++{ ++ unsigned int live_regs = m6809_get_live_regs (); ++ unsigned int frame_size = get_frame_size (); ++ ++ if (frame_size != 0) ++ emit_insn (gen_rtx_stack_adjust (PLUS, frame_size)); ++ ++ if (sibcall_p) ++ { ++ if (live_regs) ++ emit_insn (gen_rtx_register_pushpop (UNSPEC_POP_RS, live_regs)); ++ } ++ else ++ { ++ if (live_regs && !m6809_current_function_has_type_attr_p ("interrupt")) ++ emit_insn ( ++ gen_rtx_register_pushpop (UNSPEC_POP_RS, PC_REGBIT | live_regs)); ++ ++ if (m6809_current_function_has_type_attr_p ("interrupt")) ++ emit_jump_insn (gen_return_rti ()); ++ else ++ emit_jump_insn (gen_return_rts ()); ++ } ++} ++ ++#if 0 ++/** Predefine some preprocessor names according to the currently ++ * selected compiler options */ ++void ++m6809_cpu_cpp_builtins (void) ++{ ++ if (TARGET_6309) ++ { ++ builtin_define_std ("__M6309__"); ++ builtin_define_std ("__m6309__"); ++ } ++ else ++ { ++ builtin_define_std ("__M6809__"); ++ builtin_define_std ("__m6809__"); ++ } ++ ++ if (TARGET_BYTE_INT) ++ builtin_define_std ("__int8__"); ++ else ++ builtin_define_std ("__int16__"); ++ ++ switch (m6809_abi_version) ++ { ++ case M6809_ABI_VERSION_STACK: ++ builtin_define_std ("__regargs__"); ++ builtin_define_std ("__ABI_STACK__"); ++ break; ++ case M6809_ABI_VERSION_REGS: ++ builtin_define_std ("__ABI_REGS__"); ++ break; ++ case M6809_ABI_VERSION_BX: ++ builtin_define_std ("__ABI_BX__"); ++ break; ++ default: ++ break; ++ } ++ ++ if (TARGET_WPC) ++ builtin_define_std ("__WPC__"); ++ ++ if (TARGET_DRET) ++ builtin_define_std ("__DRET__"); ++} ++#endif ++ ++#define MAX_ASM_ASCII_STRING 48 ++ ++void ++m6809_output_ascii (FILE *fp, const char *str, unsigned long size) ++{ ++ unsigned long i; ++ bool use_ascii = true; ++ ++ /* If the size is too large, then break this up into multiple ++ outputs. The assembler can only output roughly 48 bytes at a ++ time. Note that if there are lots of escape sequences in ++ the string, this may fail. */ ++ if (size > MAX_ASM_ASCII_STRING) ++ { ++ m6809_output_ascii (fp, str, MAX_ASM_ASCII_STRING); ++ m6809_output_ascii (fp, str + MAX_ASM_ASCII_STRING, ++ size - MAX_ASM_ASCII_STRING); ++ return; ++ } ++ ++ /* Check for 8-bit codes, which cannot be embedded in an .ascii */ ++ for (i = 0; i < size; i++) ++ { ++ int c = str[i] & 0377; ++ if (c >= 0x80) ++ { ++ use_ascii = false; ++ break; ++ } ++ } ++ ++ if (use_ascii) ++ fprintf (fp, "\t.ascii \""); ++ ++ for (i = 0; i < size; i++) ++ { ++ int c = str[i] & 0377; ++ ++ if (use_ascii) ++ { ++ /* Just output the plain character if it is printable, ++ otherwise output the escape code for the character. ++ The assembler recognizes the same C-style octal escape sequences, ++ except that it only supports 7-bit codes. */ ++ if (c >= ' ' && c < 0177 && c != '\\' && c != '"') ++ putc (c, fp); ++ else switch (c) ++ { ++ case '\n': ++#ifndef TARGET_COCO ++ fputs ("\\n", fp); ++ break; ++#endif ++ /* On the CoCo, we fallthrough and treat '\n' like '\r'. */ ++ case '\r': ++ fputs ("\\r", fp); ++ break; ++ case '\t': ++ fputs ("\\t", fp); ++ break; ++ case '\f': ++ fputs ("\\f", fp); ++ break; ++ case 0: ++ fputs ("\\0", fp); ++ break; ++ default: ++ fprintf (fp, "\\%03o", c); ++ break; ++ } ++ } ++ else ++ { ++ fprintf (fp, "\t.byte\t0x%02X\n", c); ++ } ++ } ++ ++ if (use_ascii) ++ fprintf (fp, "\"\n"); ++} ++ ++ ++void ++m6809_output_quoted_string (FILE *asm_file, const char *string) ++{ ++ char c; ++ ++ if (strlen (string) > MAX_ASM_ASCII_STRING) ++ { ++ /* The string length is too large. We'll have to truncate it. ++ This is only called from debugging functions, so it's usually ++ not critical. */ ++ ++ char truncated_string[MAX_ASM_ASCII_STRING+1]; ++ ++ /* Copy as many characters as we can. */ ++ strncpy (truncated_string, string, MAX_ASM_ASCII_STRING); ++ truncated_string[MAX_ASM_ASCII_STRING] = '\0'; ++ string = truncated_string; ++ } ++ ++ /* Copied from toplev.c */ ++ ++ putc ('\"', asm_file); ++ while ((c = *string++) != 0) { ++ if (ISPRINT (c)) { ++ if (c == '\"' || c == '\\') ++ putc ('\\', asm_file); ++ putc (c, asm_file); ++ } ++ else ++ fprintf (asm_file, "\\%03o", (unsigned char) c); ++ } ++ putc ('\"', asm_file); ++} ++ ++ ++/** Output the assembly code for a shift instruction where the ++ * shift count is not constant. */ ++void ++m6809_output_shift_insn (int rtx_code, rtx *operands) ++{ ++ struct shift_opcode *op; ++ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ abort (); ++ ++ if (optimize_size && GET_MODE (operands[0]) == HImode) ++ { ++ switch (rtx_code) ++ { ++ case ASHIFT: ++ output_asm_insn ("jsr\t_ashlhi3", operands); ++ break; ++ case ASHIFTRT: ++ output_asm_insn ("jsr\t_ashrhi3", operands); ++ break; ++ case LSHIFTRT: ++ output_asm_insn ("jsr\t_lshrhi3", operands); ++ break; ++ } ++ } ++ else if (GET_MODE (operands[0]) == HImode) ++ { ++ switch (rtx_code) ++ { ++ case ASHIFT: ++ m6809_gen_register_shift (operands, "aslb", "rola"); ++ break; ++ case ASHIFTRT: ++ m6809_gen_register_shift (operands, "asra", "rorb"); ++ break; ++ case LSHIFTRT: ++ m6809_gen_register_shift (operands, "lsra", "rorb"); ++ break; ++ } ++ } ++ else ++ { ++ switch (rtx_code) ++ { ++ case ASHIFT: ++ m6809_gen_register_shift (operands, "aslb", NULL); ++ break; ++ case ASHIFTRT: ++ m6809_gen_register_shift (operands, "asrb", NULL); ++ break; ++ case LSHIFTRT: ++ m6809_gen_register_shift (operands, "lsrb", NULL); ++ break; ++ } ++ } ++} ++ ++ ++void ++m6809_emit_move_insn (rtx dst, rtx src) ++{ ++ emit_insn (gen_rtx_SET (VOIDmode, dst, src)); ++ if (ACC_A_REG_P (dst)) ++ emit_insn (gen_rtx_USE (VOIDmode, dst)); ++} ++ ++ ++/** Split a complex shift instruction into multiple CPU ++ * shift instructions. */ ++void ++m6809_split_shift (enum rtx_code code, rtx *operands) ++{ ++ enum machine_mode mode; ++ int count; ++ ++ mode = GET_MODE (operands[0]); ++ count = INTVAL (operands[2]); ++ ++ /* Handle a shift count outside the range of 0 .. N-1, where ++ * N is the mode size in bits. We normalize the count, and ++ * for negative counts we also invert the direction of the ++ * shift. */ ++ if ((count < 0) || (count >= 8 * GET_MODE_SIZE (mode))) ++ { ++ if (count < 0) ++ { ++ count = -count; ++ code = (code == ASHIFT) ? ASHIFTRT : ASHIFT; ++ } ++ count %= (8 * GET_MODE_SIZE (mode)); ++ m6809_emit_move_insn (operands[0], ++ gen_rtx_fmt_ee (code, mode, operands[1], ++ gen_rtx_CONST_INT (VOIDmode, count))); ++ } ++ ++ /* Handle shift by zero explicitly as a no-op. */ ++ if (count == 0) ++ { ++ emit_insn (gen_nop ()); ++ return; ++ } ++ ++ /* Decompose the shift by a constant N > 8 into two ++ * shifts, first by 8 and then by N-8. ++ * This "speeds up" the process for large shifts that would be ++ * handled below, but allows for some optimization. ++ * In some cases shift by 8 can be implemented fast. If an ++ * instruction to shift by 8 is defined, it will be used here; ++ * otherwise it will be further decomposed as below. */ ++ if (mode == HImode && count > 8) ++ { ++ rtx output = operands[0]; ++ ++ m6809_emit_move_insn (operands[0], ++ gen_rtx_fmt_ee (code, mode, operands[1], ++ gen_rtx_CONST_INT (VOIDmode, 8))); ++ ++ /* Unsigned shifts always produce a zero in either the ++ * upper or lower half of the output; then, that part ++ * does not need to be shifted anymore. We modify the ++ * output and the subsequent instructions to operate in ++ * QImode only on the relevant part. */ ++ if (REG_P (output)) ++ { ++ if (code == ASHIFT) ++ { ++ output = gen_rtx_REG (QImode, HARD_A_REGNUM); ++ mode = QImode; ++ } ++ else ++ { ++ output = gen_rtx_REG (QImode, HARD_D_REGNUM); ++ mode = QImode; ++ } ++ } ++ ++ m6809_emit_move_insn (output, ++ gen_rtx_fmt_ee (code, mode, copy_rtx (output), ++ gen_rtx_CONST_INT (VOIDmode, count-8))); ++ return; ++ } ++ ++ /* Rewrite the unsigned shift of an 8-bit register by a large constant N ++ * (near to the maximum of 8) as a rotate and mask. */ ++ if (mode == QImode && REG_P (operands[0]) && count >= ((code == ASHIFTRT) ? 7 : 6)) ++ { ++ unsigned int mask; ++ unsigned int was_signed = (code == ASHIFTRT); ++ ++ code = (code == ASHIFT) ? ROTATERT : ROTATE; ++ if (code == ROTATE) ++ mask = (count == 6) ? 0x03 : 0x01; ++ else ++ mask = (count == 6) ? 0xC0 - 0x100 : 0x80 - 0x100; ++ count = 9 - count; ++ ++ do { ++ m6809_emit_move_insn (operands[0], ++ gen_rtx_fmt_ee (code, QImode, operands[1], const1_rtx)); ++ } while (--count != 0); ++ ++ m6809_emit_move_insn (operands[0], ++ gen_rtx_fmt_ee (AND, QImode, operands[1], ++ gen_rtx_CONST_INT (VOIDmode, mask))); ++ ++ if (was_signed) ++ { ++ emit_insn (gen_negqi2 (operands[0], copy_rtx (operands[0]))); ++ if (ACC_A_REG_P (operands[0])) ++ emit_insn (gen_rtx_USE (VOIDmode, operands[0])); ++ } ++ return; ++ } ++ ++ /* Decompose the shift by any constant N > 1 into a sequence ++ * of N shifts. ++ * This is done recursively, by creating a shift by 1 and a ++ * shift by N-1, as long as N>1. */ ++ if (count > 1) ++ { ++ m6809_emit_move_insn (operands[0], ++ gen_rtx_fmt_ee (code, mode, operands[1], const1_rtx)); ++ ++ m6809_emit_move_insn (operands[0], ++ gen_rtx_fmt_ee (code, mode, operands[1], ++ gen_rtx_CONST_INT (VOIDmode, count-1))); ++ return; ++ } ++ ++ /* Decompose the single shift of a 16-bit quantity into two ++ * CPU instructions, one for each 8-bit half. ++ */ ++ if (mode == HImode && count == 1) ++ { ++ rtx first, second; ++ enum rtx_code rotate_code; ++ ++ rotate_code = (code == ASHIFT) ? ROTATE : ROTATERT; ++ ++ /* Split the operand into two 8-bit entities. ++ * FIRST is the one that will get shifted via a regular CPU ++ * instruction. ++ * SECOND is the one that will have the result of the first shift ++ * rotated in. ++ * ++ * We initialize first and second as if we are doing a left shift, ++ * then swap the operands if it's a right shift. ++ */ ++ if (REG_P (operands[0])) ++ { ++ first = gen_rtx_REG (QImode, HARD_D_REGNUM); /* HARD_B_REGNUM? */ ++ second = gen_rtx_REG (QImode, HARD_A_REGNUM); ++ } ++ else ++ { ++ first = adjust_address (operands[0], QImode, 1); ++ second = adjust_address (operands[0], QImode, 0); ++ } ++ ++ if (rotate_code == ROTATERT) ++ { ++ rtx tmp; tmp = first; first = second; second = tmp; ++ } ++ ++ /* Decompose into a shift and a rotate instruction. */ ++ m6809_emit_move_insn (first, ++ gen_rtx_fmt_ee (code, QImode, copy_rtx (first), const1_rtx)); ++ m6809_emit_move_insn (second, ++ gen_rtx_fmt_ee (rotate_code, QImode, copy_rtx (second), const1_rtx)); ++ return; ++ } ++} ++ ++ ++/** Adjust register usage based on compile-time flags. */ ++void ++m6809_conditional_register_usage (void) ++{ ++ unsigned int soft_regno; ++ ++#ifdef CONFIG_SOFT_REGS_ALWAYS ++ m6809_soft_regs = CONFIG_SOFT_REGS_ALWAYS; ++#else ++ if (!m6809_soft_reg_count) ++ return; ++ m6809_soft_regs = atoi (m6809_soft_reg_count); ++#endif ++ ++ if (m6809_soft_regs == 0) ++ return; ++ ++ if (m6809_soft_regs > NUM_M_REGS) ++ m6809_soft_regs = NUM_M_REGS; ++ ++ /* Registers are marked FIXED by default. Free up if ++ the user wishes. */ ++ for (soft_regno = 1; soft_regno < m6809_soft_regs; soft_regno++) ++ { ++ fixed_regs[SOFT_M0_REGNUM + soft_regno] = 0; ++ ++ /* Mark the softregs as call-clobbered, so that they need ++ * not be saved/restored on function entry/exit. */ ++ call_used_regs[SOFT_M0_REGNUM + soft_regno] = 1; ++ } ++} ++ ++ ++/** Return a RTX representing how to return a value from a function. ++ VALTYPE gives the type of the value, FUNC identifies the function ++ itself. ++ ++ In general, we only care about the width of the result. */ ++rtx ++m6809_function_value (const tree valtype, const tree func ATTRIBUTE_UNUSED) ++{ ++ unsigned int regno; ++ enum machine_mode mode; ++ ++ /* Get the mode (i.e. width) of the result. */ ++ mode = TYPE_MODE (valtype); ++ ++ if (lookup_attribute ("boolean", TYPE_ATTRIBUTES (valtype))) ++ regno = HARD_Z_REGNUM; ++ else if (mode == QImode || (TARGET_DRET && mode == HImode)) ++ regno = HARD_D_REGNUM; ++ else ++ regno = HARD_X_REGNUM; ++ return gen_rtx_REG (mode, regno); ++} ++ ++ ++/** Return 1 if REGNO is possibly needed to return the result ++of a function, 0 otherwise. */ ++int ++m6809_function_value_regno_p (unsigned int regno) ++{ ++ if (regno == HARD_Z_REGNUM) ++ return 1; ++ else if ((TARGET_BYTE_INT || TARGET_DRET) && regno == HARD_D_REGNUM) ++ return 1; ++ else if (!TARGET_DRET && regno == HARD_X_REGNUM) ++ return 1; ++ else ++ return 0; ++} ++ ++ ++#ifdef TRACE_PEEPHOLE ++int ++m6809_match_peephole2 (unsigned int peephole_id, unsigned int stage) ++{ ++ if (stage == PEEP_END) ++ { ++ printf ("%s: peephole %d pattern and predicate matched\n", ++ main_input_filename, peephole_id); ++ fflush (stdout); ++ } ++ else if (stage == PEEP_COND) ++ { ++ printf ("%s: peephole %d? at least pattern matched\n", ++ main_input_filename, peephole_id); ++ fflush (stdout); ++ } ++ return 1; ++} ++#else ++int ++m6809_match_peephole2 (unsigned int peephole_id ATTRIBUTE_UNUSED, ++ unsigned int stage ATTRIBUTE_UNUSED) ++{ ++ return 1; ++} ++#endif /* TRACE_PEEPHOLE */ ++ ++ ++/** Return 1 if it is OK to store a value of MODE in REGNO. */ ++int ++m6809_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) ++{ ++ /* Soft registers, as they are just memory, can really hold ++ values of any type. However we restrict them to values of ++ size HImode or QImode to prevent exhausting them for larger ++ values. ++ Word values cannot be placed into the first soft register, ++ as it is the low byte that is being placed there, which ++ corrupts the (non-soft) register before it. */ ++ if (M_REGNO_P (regno)) ++ { ++ switch (GET_MODE_SIZE (mode)) ++ { ++ case 1: ++ return 1; ++ case 2: ++ return regno != SOFT_M0_REGNUM; ++ default: ++ return 0; ++ } ++ } ++ ++ /* VOIDmode can be stored anywhere */ ++ else if (mode == VOIDmode) ++ return 1; ++ ++ /* Zero is a reserved register, but problems occur if we don't ++ say yes here??? */ ++ else if (regno == 0) ++ return 1; ++ ++ /* For other registers, return true only if the requested size ++ exactly matches the hardware size. */ ++ else if ((G_REGNO_P (regno)) && (GET_MODE_SIZE (mode) == 2)) ++ return 1; ++ else if ((BYTE_REGNO_P (regno)) && (GET_MODE_SIZE (mode) == 1)) ++ return 1; ++ else ++ return 0; ++} ++ ++ ++/* exp is the call expression. DECL is the called function, ++ * or NULL for an indirect call */ ++bool ++m6809_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) ++{ ++ tree type, arg; ++ const char *name; ++ bool result = 0; ++ int argcount = 0; ++ int step = 1; ++ ++ /* If there is no DECL, it is an indirect call. ++ * Never optimize this??? */ ++ if (decl == NULL) ++ goto done; ++ ++ /* Never allow an interrupt handler to be optimized this way. */ ++ if (m6809_function_has_type_attr_p (decl, "interrupt")) ++ goto done; ++ ++ /* Skip sibcall if the type can't be found for ++ * some reason */ ++ step++; ++ name = IDENTIFIER_POINTER (DECL_NAME (decl)); ++ type = TREE_TYPE (decl); ++ if (type == NULL) ++ goto done; ++ ++ /* Skip sibcall if the target is a far function */ ++ step++; ++ if (far_function_type_p (type) != NULL) ++ goto done; ++ ++ /* Skip sibcall if the called function's arguments are ++ * variable */ ++ step++; ++ if (TYPE_ARG_TYPES (type) == NULL) ++ goto done; ++ ++ /* Allow sibcalls in other cases. */ ++ result = 1; ++done: ++ /* printf ("%s ok for sibcall? %s, step %d, args %d\n", name, result ? "yes" : "no", step, argcount); */ ++ return result; ++} ++ ++ ++/** Emit code for the 'casesi' pattern. ++ * This pattern is only used in 8-bit mode, and can be disabled ++ * with -mold-case there as well. The rationale for this is to ++ * do a better job than the simpler but well-tested 'tablejump' ++ * method. ++ * ++ * For small jumptables, where the switch expression is an ++ * 8-bit value, the lookup can be done more efficiently ++ * using the "B,X" style index mode. */ ++void ++m6809_do_casesi (rtx index, rtx lower_bound, rtx range, ++ rtx table_label, rtx default_label) ++{ ++ enum machine_mode mode; ++ rtx scaled; ++ rtx table_in_reg; ++ ++ /* expr.c has to be patched so that it does not promote ++ * the expression to SImode, but rather to HImode. ++ * Fail now if that isn't the case. */ ++ if (GET_MODE_SIZE (GET_MODE (index)) > GET_MODE_SIZE (HImode)) ++ error ("try_casesi promotion bug"); ++ ++ /* Determine whether or not we are going to work primarily in ++ * QImode or HImode. This depends on the size of the index ++ * into the lookup table. QImode can only be used when the ++ * index is less than 0x40, since it will be doubled but ++ * must remain unsigned. */ ++ if ((GET_CODE (range) == CONST_INT) && (INTVAL (range) < 0x40)) ++ mode = QImode; ++ else ++ mode = HImode; ++ ++ /* Convert to QImode if necessary */ ++ if (mode == QImode) ++ { ++ index = gen_lowpart_general (mode, index); ++ lower_bound = gen_lowpart_general (mode, lower_bound); ++ } ++ ++ /* Translate from case value to table index by subtraction */ ++ if (lower_bound != const0_rtx) ++ index = expand_binop (mode, sub_optab, index, lower_bound, ++ NULL_RTX, 0, OPTAB_LIB_WIDEN); ++ ++ /* Emit compare-and-jump to test for index out-of-range */ ++ emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, mode, 1, ++ default_label); ++ ++ /* Put the table address is in a register */ ++ table_in_reg = gen_reg_rtx (Pmode); ++ emit_move_insn (table_in_reg, gen_rtx_LABEL_REF (Pmode, table_label)); ++ ++ /* Emit table lookup and jump */ ++ if (mode == QImode) ++ { ++ /* Scale the index */ ++ scaled = gen_reg_rtx (QImode); ++ emit_insn (gen_ashlqi3 (scaled, index, const1_rtx)); ++ ++ /* Emit the jump */ ++ emit_jump_insn (gen_tablejump_short_offset (scaled, table_in_reg)); ++ } ++ else ++ { ++ /* Scale the index */ ++ emit_insn (gen_ashlhi3 (index, index, const1_rtx)); ++ ++ /* Emit the jump */ ++ emit_jump_insn (gen_tablejump_long_offset (index, table_in_reg)); ++ } ++ ++ /* Copied from expr.c */ ++ if (!CASE_VECTOR_PC_RELATIVE && !flag_pic) ++ emit_barrier (); ++} ++ ++ ++/** Output the assembly code for a 32-bit add/subtract. */ ++void ++m6809_output_addsi3 (int rtx_code, rtx *operands) ++{ ++ rtx xoperands[8]; ++ rtx dst = operands[0]; ++ ++ /* Prepare the operands by splitting each SImode into two HImodes ++ that can be operated independently. The high word of operand 1 ++ is further divided into two QImode components for use with 'adc' ++ style instructions. */ ++ xoperands[7] = operands[3]; ++ ++ xoperands[0] = adjust_address (dst, HImode, 2); ++ xoperands[3] = adjust_address (dst, HImode, 0); ++ ++#if 1 ++ xoperands[2] = adjust_address (operands[1], HImode, 2); ++ xoperands[6] = adjust_address (operands[1], HImode, 0); ++ ++ /* Operand 2 may be a MEM or a CONST_INT */ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ xoperands[1] = gen_int_mode (INTVAL (operands[2]) & 0xFFFF, HImode); ++ xoperands[4] = gen_int_mode ((INTVAL (operands[2]) >> 24) & 0xFF, QImode); ++ xoperands[5] = gen_int_mode ((INTVAL (operands[2]) >> 16) & 0xFF, QImode); ++ } ++ else ++ { ++ xoperands[1] = adjust_address (operands[2], HImode, 2); ++ xoperands[4] = adjust_address (operands[2], QImode, 0); ++ xoperands[5] = adjust_address (operands[2], QImode, 1); ++ } ++ ++#endif ++ ++#if 0 ++ xoperands[1] = adjust_address (operands[1], HImode, 2); ++ xoperands[4] = adjust_address (operands[1], QImode, 0); ++ xoperands[5] = adjust_address (operands[1], QImode, 1); ++ ++ /* Operand 2 may be a MEM or a CONST_INT */ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ xoperands[2] = gen_int_mode ((INTVAL (operands[2])) & 0xFFFF, HImode); ++ xoperands[6] = gen_int_mode ((INTVAL (operands[2]) >> 16) & 0xFFFF, HImode); ++ } ++ else ++ { ++ xoperands[2] = adjust_address (operands[2], HImode, 2); ++ xoperands[6] = adjust_address (operands[2], HImode, 0); ++ } ++#endif ++ ++ /* Output the assembly code. */ ++ if (rtx_code == PLUS) ++ { ++ output_asm_insn ("ld%7\t%2", xoperands); ++ output_asm_insn ("add%7\t%1", xoperands); ++ output_asm_insn ("st%7\t%0", xoperands); ++ output_asm_insn ("ld%7\t%6", xoperands); ++ output_asm_insn ("adcb\t%5", xoperands); ++ output_asm_insn ("adca\t%4", xoperands); ++ output_asm_insn ("st%7\t%3", xoperands); ++ } ++ else ++ { ++ output_asm_insn ("ld%7\t%2", xoperands); ++ output_asm_insn ("sub%7\t%1", xoperands); ++ output_asm_insn ("st%7\t%0", xoperands); ++ output_asm_insn ("ld%7\t%6", xoperands); ++ output_asm_insn ("sbcb\t%5", xoperands); ++ output_asm_insn ("sbca\t%4", xoperands); ++ output_asm_insn ("st%7\t%3", xoperands); ++ } ++} ++ ++ ++#if 0 ++/** Output the assembly code for a 32-bit shift. ++Operands 0 and 1 must be the same rtx, forced by a matching ++constraint. Operand 2 must be a CONST_INT. Operand 3 is ++"d" in case a temporary reg is needed. */ ++void ++m6809_output_shiftsi3 (int rtx_code, rtx *operands) ++{ ++ unsigned int count = INTVAL (operands[2]) % 32; ++ unsigned int size = 4; /* sizeof (SImode) */ ++ int s; ++ rtx xoperands[4]; ++ int op; ++ int start, end, step; ++ ++ /* Initialize */ ++ if (rtx_code == ASHIFT) ++ { ++ start = size-1; ++ end = -1; ++ step = -1; ++ } ++ else ++ { ++ start = 0; ++ end = size; ++ step = 1; ++ } ++ ++ xoperands[2] = operands[2]; ++ xoperands[3] = operands[3]; ++ ++ if (count <= 0) ++ abort (); ++ if (rtx_code == ROTATE || rtx_code == ROTATERT) ++ abort (); ++ ++ /* Extract bit shifts over 16 bits by HImode moves. */ ++ if (count >= 16) ++ { ++ } ++ ++ /* Extract bit shifts over 8 bits by QImode moves. */ ++ if (count >= 8) ++ { ++ } ++ ++ /* Iterate over the number of bits to be shifted. */ ++ while (count > 0) ++ { ++ /* Each bit to be shifted requires 1 proper bit shift ++ and 3 rotates. */ ++ ++ /* First, do the arithmetic/logical shift. Left shifts ++ start from the LSB; right shifts start from the MSB. */ ++ xoperands[0] = adjust_address (operands[0], QImode, start); ++ switch (rtx_code) ++ { ++ case ASHIFT: ++ output_asm_insn ("asl\t%0", xoperands); ++ start--; ++ break; ++ case ASHIFTRT: ++ output_asm_insn ("asr\t%0", xoperands); ++ start++; ++ break; ++ case LSHIFTRT: ++ output_asm_insn ("lsr\t%0", xoperands); ++ start++; ++ break; ++ } ++ ++ /* Next, rotate the other bytes */ ++ for (s = start; s != end; s += step) ++ { ++ xoperands[0] = adjust_address (operands[0], QImode, s); ++ switch (rtx_code) ++ { ++ case ASHIFT: ++ output_asm_insn ("rol\t%0", xoperands); ++ break; ++ case ASHIFTRT: ++ case LSHIFTRT: ++ output_asm_insn ("ror\t%0", xoperands); ++ break; ++ } ++ } ++ count--; ++ } ++} ++#endif ++ ++int ++power_of_two_p (unsigned int n) ++{ ++ return (n & (n-1)) == 0; ++} ++ ++ ++int ++m6809_can_eliminate (int from, int to) ++{ ++ if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) ++ return !frame_pointer_needed; ++ return 1; ++} ++ ++ ++int ++m6809_initial_elimination_offset (int from, int to) ++{ ++ switch (from) ++ { ++ case ARG_POINTER_REGNUM: ++ return get_frame_size () + m6809_get_regs_size (m6809_get_live_regs ()); ++ case FRAME_POINTER_REGNUM: ++ return get_frame_size (); ++ default: ++ gcc_unreachable (); ++ } ++} ++ ++ ++bool ++m6809_frame_pointer_required (void) ++{ ++ return false; ++} ++ ++ ++/* Defines the target-specific hooks structure. */ ++struct gcc_target targetm = TARGET_INITIALIZER; +diff -urN gcc-4.6.4-clean/gcc/config/m6809/m6809.h gcc-4.6.4/gcc/config/m6809/m6809.h +--- gcc-4.6.4-clean/gcc/config/m6809/m6809.h 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-4.6.4/gcc/config/m6809/m6809.h 2015-07-20 21:56:53.518727644 -0600 +@@ -0,0 +1,1352 @@ ++/* Definitions of target machine for GNU compiler. MC6809 version. ++ ++ MC6809 Version by Tom Jones (jones@sal.wisc.edu) ++ Space Astronomy Laboratory ++ University of Wisconsin at Madison ++ ++ minor changes to adapt it to gcc-2.5.8 by Matthias Doerfel ++ ( msdoerfe@informatik.uni-erlangen.de ) ++ also added #pragma interrupt (inspired by gcc-6811) ++ ++ minor changes to adapt it to gcc-2.8.0 by Eric Botcazou ++ (ebotcazou@multimania.com) ++ ++ minor changes to adapt it to egcs-1.1.2 by Eric Botcazou ++ (ebotcazou@multimania.com) ++ ++ minor changes to adapt it to gcc-2.95.3 by Eric Botcazou ++ (ebotcazou@multimania.com) ++ ++ changes for gcc-3.1.1 by ??? ++ ++ further changes for gcc-3.1.1 and beyond by Brian Dominy ++ (brian@oddchange.com) ++ ++ even more changes for gcc-4.6.1 by William Astle (lost@l-w.ca) ++ ++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 ++<http://www.gnu.org/licenses/>. */ ++ ++ ++/* Helper macros for creating strings with macros */ ++#define C_STRING(x) C_STR(x) ++#define C_STR(x) #x ++ ++/* Certain parts of GCC include host-side includes, which is bad. ++ * Some things that get pulled in need to be undone. ++ */ ++#undef HAVE_GAS_HIDDEN ++ ++/* Names to predefine in the preprocessor for this target machine. */ ++/*#define TARGET_CPU_CPP_BUILTINS() m6809_cpu_cpp_builtins () */ ++#define TARGET_CPU_CPP_BUILTINS() do \ ++ { \ ++ if (TARGET_6309) \ ++ { \ ++ builtin_define_std ("__M6309__"); \ ++ builtin_define_std ("__m6309__"); \ ++ } \ ++ else \ ++ { \ ++ builtin_define_std ("__M6809__"); \ ++ builtin_define_std ("__m6809__"); \ ++ } \ ++ \ ++ if (TARGET_BYTE_INT) \ ++ builtin_define_std ("__int8__"); \ ++ else \ ++ builtin_define_std ("__int16__"); \ ++ \ ++ switch (m6809_abi_version) \ ++ { \ ++ case M6809_ABI_VERSION_STACK: \ ++ builtin_define_std ("__regargs__"); \ ++ builtin_define_std ("__ABI_STACK__"); \ ++ break; \ ++ case M6809_ABI_VERSION_REGS: \ ++ builtin_define_std ("__ABI_REGS__"); \ ++ break; \ ++ case M6809_ABI_VERSION_BX: \ ++ builtin_define_std ("__ABI_BX__"); \ ++ break; \ ++ default: \ ++ break; \ ++ } \ ++ \ ++ if (TARGET_WPC) \ ++ builtin_define_std ("__WPC__"); \ ++ \ ++ if (TARGET_DRET) \ ++ builtin_define_std ("__DRET__"); \ ++ } while (0) ++ ++/* As an embedded target, we have no libc. */ ++#ifndef inhibit_libc ++#define inhibit_libc ++#endif ++ ++/* Print subsidiary information on the compiler version in use. */ ++#define TARGET_VERSION fprintf (stderr, " (MC6809)"); ++ ++/* Run-time compilation parameters selecting different hardware subsets. */ ++/*extern int target_flags; */ ++extern short *reg_renumber; /* def in local_alloc.c */ ++ ++/* Runtime current values of section names */ ++extern int section_changed; ++extern char code_section_op[], data_section_op[], bss_section_op[]; ++ ++#define WARNING_OPT 0, ++/*extern const char *m6809_abi_version_ptr; */ ++extern unsigned int m6809_soft_regs; ++extern unsigned int m6809_abi_version; ++ ++/* ABI versions */ ++ ++#define M6809_ABI_VERSION_STACK 0 ++#define M6809_ABI_VERSION_REGS 1 ++#define M6809_ABI_VERSION_BX 2 ++#define M6809_ABI_VERSION_LATEST (M6809_ABI_VERSION_BX) ++ ++/* Allow $ in identifiers */ ++#define DOLLARS_IN_IDENTIFIERS 1 ++ ++/*-------------------------------------------------------------- ++ Target machine storage layout ++--------------------------------------------------------------*/ ++ ++/* Define this if most significant bit is lowest numbered ++ in instructions that operate on numbered bit-fields. */ ++#define BITS_BIG_ENDIAN 0 ++ ++/* Define to 1 if most significant byte of a word is the lowest numbered. */ ++#define BYTES_BIG_ENDIAN 1 ++ ++/* Define to 1 if most significant word of a multiword value is the lowest numbered. */ ++#define WORDS_BIG_ENDIAN 1 ++ ++/* Number of bits in an addressible storage unit */ ++#define BITS_PER_UNIT 8 ++ ++/* Width in bits of a "word", or the contents of a machine register. ++ * Although the 6809 has a few byte registers, define this to 16-bits ++ * since this is the natural size of most registers. */ ++#define BITS_PER_WORD 16 ++ ++/* Width of a word, in units (bytes). */ ++#define UNITS_PER_WORD (BITS_PER_WORD/8) ++ ++/* Width in bits of a pointer. See also the macro `Pmode' defined below. */ ++#define POINTER_SIZE 16 ++ ++/* Allocation boundary (bits) for storing pointers in memory. */ ++#define POINTER_BOUNDARY 8 ++ ++/* Allocation boundary (bits) for storing arguments in argument list. */ ++/* PARM_BOUNDARY is divided by BITS_PER_WORD in expr.c -- tej */ ++#define PARM_BOUNDARY 8 ++ ++/* Boundary (bits) on which stack pointer should be aligned. */ ++#define STACK_BOUNDARY 8 ++ ++/* Allocation boundary (bits) for the code of a function. */ ++#define FUNCTION_BOUNDARY 8 ++ ++/* Alignment of field after `int : 0' in a structure. */ ++#define EMPTY_FIELD_BOUNDARY 8 ++ ++/* Every structure's size must be a multiple of this. */ ++#define STRUCTURE_SIZE_BOUNDARY 8 ++ ++/* Largest mode size to use when putting an object, including ++ * a structure, into a register. By limiting this to 16, no ++ * 32-bit objects will ever be allocated to a pair of hard ++ * registers. This is a good thing, since there aren't that ++ * many of them. 32-bit objects are only needed for floats ++ * and "long long"s. Larger values have been tried and did not ++ * work. */ ++#define MAX_FIXED_MODE_SIZE 16 ++ ++/* No data type wants to be aligned rounder than this. */ ++#define BIGGEST_ALIGNMENT 8 ++ ++/* Define this if move instructions will actually fail to work ++ when given unaligned data. */ ++#define STRICT_ALIGNMENT 0 ++ ++/*-------------------------------------------------------------- ++ Standard register usage. ++--------------------------------------------------------------*/ ++ ++/* Register values as bitmasks. ++ * TODO : merge D_REGBIT and B_REGBIT, and treat this as the same ++ * register. */ ++#define RSVD1_REGBIT (1 << HARD_RSVD1_REGNUM) ++#define D_REGBIT (1 << HARD_D_REGNUM) ++#define X_REGBIT (1 << HARD_X_REGNUM) ++#define Y_REGBIT (1 << HARD_Y_REGNUM) ++#define U_REGBIT (1 << HARD_U_REGNUM) ++#define S_REGBIT (1 << HARD_S_REGNUM) ++#define PC_REGBIT (1 << HARD_PC_REGNUM) ++#define Z_REGBIT (1 << HARD_Z_REGNUM) ++#define A_REGBIT (1 << HARD_A_REGNUM) ++#define B_REGBIT (1 << HARD_B_REGNUM) ++#define CC_REGBIT (1 << HARD_CC_REGNUM) ++#define DP_REGBIT (1 << HARD_DP_REGNUM) ++#define SOFT_FP_REGBIT (1 << SOFT_FP_REGNUM) ++#define SOFT_AP_REGBIT (1 << SOFT_AP_REGNUM) ++#define M_REGBIT(n) (1 << (SOFT_M0_REGNUM + n)) ++ ++/* Macros for dealing with set of registers. ++ * A register set is just a bitwise-OR of all the register ++ * bitmask values. */ ++ ++/* Which registers can hold 8-bits */ ++#define BYTE_REGSET \ ++ (Z_REGBIT | A_REGBIT | D_REGBIT | CC_REGBIT | DP_REGBIT) ++ ++/* Which registers can hold 16-bits. ++ * Note: D_REGBIT is defined as both an 8-bit and 16-bit register */ ++#define WORD_REGSET \ ++ (D_REGBIT | X_REGBIT | Y_REGBIT | U_REGBIT | S_REGBIT | PC_REGBIT | SOFT_FP_REGBIT | SOFT_AP_REGBIT | RSVD1_REGBIT) ++ ++/* Returns nonzero if a given REGNO is in the REGSET. */ ++#define REGSET_CONTAINS_P(regno, regset) (((1 << (regno)) & (regset)) != 0) ++ ++/* Defines related to the number of soft registers supported. ++ * The actual number used may be less depending on -msoft-reg-count. ++ * If you change one of these, you should change them all. */ ++#define NUM_M_REGS 8 ++#define M_REGS_FIXED 1, 1, 1, 1, 1, 1, 1, 1 ++#define M_REGS_CALL_USED 1, 1, 1, 1, 1, 1, 1, 1 ++#define HARD_M_REGNUMS \ ++ SOFT_M0_REGNUM+0, SOFT_M0_REGNUM+1, SOFT_M0_REGNUM+2, SOFT_M0_REGNUM+3, \ ++ SOFT_M0_REGNUM+4, SOFT_M0_REGNUM+5, SOFT_M0_REGNUM+6, SOFT_M0_REGNUM+7 ++ ++#define SOFT_M_REGBITS (((1UL << NUM_M_REGS) - 1) << (SOFT_M0_REGNUM)) ++ ++/* Number of actual hardware registers. ++ The hardware registers are assigned numbers for the compiler ++ from 0 to just below FIRST_PSEUDO_REGISTER. ++ All registers that the compiler knows about must be given numbers, ++ even those that are not normally considered general registers. ++ Make sure the constant below matches the value of SOFT_M0_REGNUM; ++ for some reason, GCC won't compile if that name is used here directly. */ ++#ifdef SOFT_M0_REGNUM ++#if (SOFT_M0_REGNUM != 14) ++#error "bad register numbering" ++#endif ++#endif ++#define FIRST_PSEUDO_REGISTER (14 + NUM_M_REGS) ++ ++/* 1 for registers that have pervasive standard uses ++ and are not available for the register allocator. ++ The psuedoregisters (M_REGS) are declared fixed here, but ++ will be unfixed if -msoft-reg-count is seen later. */ ++#define FIXED_REGISTERS \ ++ {1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, M_REGS_FIXED, } ++ /* -, X, Y, U, S, PC,D, Z, A, B, C, DP,FP,AP,M... */ ++ ++/* 1 for registers not available across function calls. ++ These must include the FIXED_REGISTERS and also any ++ registers that can be used without being saved. ++ The latter must include the registers where values are returned ++ and the register where structure-value addresses are passed. ++ Aside from that, you can include as many other registers as you like. */ ++#define CALL_USED_REGISTERS \ ++ {1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, M_REGS_CALL_USED, } ++ /* -, X, Y, U, S, PC,D, Z, A, B, C, DP,FP,AP,M... */ ++ ++/* Return number of consecutive hard regs needed starting at reg REGNO ++ to hold something of mode MODE. ++ For the 6809, we distinguish between word-length and byte-length ++ registers. */ ++#define HARD_REGNO_NREGS(REGNO, MODE) \ ++ (REGSET_CONTAINS_P (REGNO, WORD_REGSET) ? \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) : \ ++ (GET_MODE_SIZE (MODE))) ++ ++ ++/* Value is 1 if hard register REGNO can hold a value ++of machine-mode MODE. */ ++#define HARD_REGNO_MODE_OK(REGNO, MODE) m6809_hard_regno_mode_ok (REGNO, MODE) ++ ++/* Value is 1 if it is a good idea to tie two pseudo registers ++ when one has mode MODE1 and one has mode MODE2. ++ If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, ++ for any hard reg, then this must be 0 for correct output. */ ++#define MODES_TIEABLE_P(MODE1, MODE2) 0 ++ ++/* Specify the registers used for certain standard purposes. ++ The values of these macros are register numbers. */ ++ ++/* program counter if referenced as a register */ ++#define PC_REGNUM HARD_PC_REGNUM ++ ++/* Register to use for pushing function arguments. */ ++#define STACK_POINTER_REGNUM HARD_S_REGNUM ++ ++/* Base register for access to local variables of the function. ++ * Before reload, FRAME_POINTER_REGNUM will be used. Later, ++ * the elimination pass will convert these to STACK_POINTER_REGNUM ++ * if possible, or else HARD_FRAME_POINTER_REGNUM. The idea is to ++ * avoid tying up a hard register (U) for the frame pointer if ++ * it can be eliminated entirely, making it available for use as ++ * a general register. */ ++#define FRAME_POINTER_REGNUM SOFT_FP_REGNUM ++#define HARD_FRAME_POINTER_REGNUM HARD_U_REGNUM ++ ++/* Define a table of possible eliminations. ++ * The idea is to try to avoid using hard registers for the argument ++ * and frame pointers if they can be derived from the stack pointer ++ * instead, which already has a hard register reserved for it. ++ * ++ * The order of entries in this table will try to convert ++ * ARG_POINTER_REGNUM and FRAME_POINTER_REGNUM into stack pointer ++ * references first, but if that fails, they will be converted to use ++ * HARD_FRAME_POINTER_REGNUM. ++ */ ++#define ELIMINABLE_REGS \ ++{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ ++ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }, \ ++ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ ++ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }} ++ ++/* #define CAN_ELIMINATE(FROM, TO) m6809_can_eliminate (FROM, TO) */ ++ ++/* Define how to offset the frame or argument pointer to turn it ++ * into a stack pointer reference. This is based on the way that ++ * the frame is constructed in the function prologue. */ ++#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ ++ (OFFSET) = m6809_initial_elimination_offset (FROM, TO) ++ ++/* Base register for access to arguments of the function. ++ * This is only used prior to reload; no instructions will ever ++ * be output referring to this register. */ ++#define ARG_POINTER_REGNUM SOFT_AP_REGNUM ++ ++/* Register in which static-chain is passed to a function. */ ++#define STATIC_CHAIN_REGNUM HARD_Y_REGNUM ++ ++/* #define CONDITIONAL_REGISTER_USAGE (m6809_conditional_register_usage ()) */ ++ ++/* Order in which hard registers are allocated to pseudos. ++ * ++ * Since the D register is the only valid reg for 8-bit values ++ * now, avoid using it for 16-bit values by putting it after all ++ * other 16-bits. ++ * ++ * Prefer X first since the first 16-bit function argument goes ++ * there. We may be able to pass in to a subroutine without ++ * a copy. ++ * ++ * Prefer U over Y since instructions using Y take one extra ++ * byte, and thus one extra cycle to execute. ++ */ ++#define REG_ALLOC_ORDER \ ++ { HARD_X_REGNUM, HARD_U_REGNUM, HARD_Y_REGNUM, HARD_D_REGNUM, \ ++ HARD_M_REGNUMS, HARD_S_REGNUM, HARD_PC_REGNUM, \ ++ HARD_B_REGNUM, HARD_A_REGNUM, HARD_CC_REGNUM, \ ++ HARD_DP_REGNUM, SOFT_FP_REGNUM, SOFT_AP_REGNUM, \ ++ 6, HARD_Z_REGNUM } ++ ++/*-------------------------------------------------------------- ++ classes of registers ++--------------------------------------------------------------*/ ++ ++/* Define the classes of registers for register constraints in the ++ machine description. Also define ranges of constants. ++ ++ One of the classes must always be named ALL_REGS and include all hard regs. ++ If there is more than one class, another class must be named NO_REGS ++ and contain no registers. ++ ++ The name GENERAL_REGS must be the name of a class (or an alias for ++ another name such as ALL_REGS). This is the class of registers ++ that is allowed by "g" or "r" in a register constraint. ++ Also, registers outside this class are allocated only when ++ instructions express preferences for them. ++ ++ The classes must be numbered in nondecreasing order; that is, ++ a larger-numbered class must never be contained completely ++ in a smaller-numbered class. ++ ++ For any two classes, it is very desirable that there be another ++ class that represents their union. */ ++ ++enum reg_class { ++ NO_REGS, /* The trivial class with no registers in it */ ++ D_REGS, /* 16-bit (word (HI)) data (D) */ ++ ACC_A_REGS, /* The A register */ ++ ACC_B_REGS, /* The B register */ ++ X_REGS, /* The X register */ ++ Z_REGS, /* The Z (zero-bit) register */ ++ Q_REGS, /* 8-bit (byte (QI)) data (A,B) */ ++ M_REGS, /* 8-bit (byte (QI)) soft registers */ ++ CC_REGS, /* 8-bit condition code register */ ++ I_REGS, /* An index register (A,B,D) */ ++ T_REGS, /* 16-bit addresses, not including stack or PC (X,Y,U) */ ++ A_REGS, /* 16-bit addresses (X,Y,U,S,PC) */ ++ S_REGS, /* 16-bit soft registers (FP, AP) */ ++ P_REGS, /* 16-bit pushable registers (D,X,Y,U); omit PC and S */ ++ G_REGS, /* 16-bit data and address (D,X,Y,U,S,PC) */ ++ ALL_REGS, /* All registers */ ++ LIM_REG_CLASSES ++}; ++ ++#define N_REG_CLASSES (int) LIM_REG_CLASSES ++ ++/* Since GENERAL_REGS is a smaller class than ALL_REGS, ++ it is not an alias to ALL_REGS, but to G_REGS. */ ++#define GENERAL_REGS G_REGS ++ ++/* Give names of register classes as strings for dump file. */ ++#define REG_CLASS_NAMES \ ++ { "NO_REGS", "D_REGS", "ACC_A_REGS", "ACC_B_REGS", "X_REGS", "Z_REGS", "Q_REGS", "M_REGS", \ ++ "CC_REGS", "I_REGS", "T_REGS", "A_REGS", "S_REGS", "P_REGS", "G_REGS", \ ++ "ALL_REGS" } ++ ++/* Define which registers fit in which classes. ++ This is an initializer for a vector of HARD_REG_SET ++ of length N_REG_CLASSES. */ ++ ++#define D_REGSET (D_REGBIT) ++#define ACC_A_REGSET (A_REGBIT) ++#define ACC_B_REGSET (D_REGBIT) ++#define X_REGSET (X_REGBIT) ++#define Z_REGSET (Z_REGBIT) ++#define Q_REGSET (D_REGBIT | A_REGBIT) ++#define M_REGSET (SOFT_M_REGBITS) ++#define CC_REGSET (CC_REGBIT) ++#define I_REGSET (A_REGBIT | B_REGBIT | D_REGBIT) ++#define T_REGSET (X_REGBIT | Y_REGBIT | U_REGBIT) ++#define A_REGSET (X_REGBIT | Y_REGBIT | U_REGBIT | S_REGBIT | PC_REGBIT) ++#define S_REGSET (SOFT_FP_REGBIT | SOFT_AP_REGBIT) ++#define P_REGSET (D_REGBIT | X_REGBIT | Y_REGBIT | U_REGBIT) ++#define G_REGSET \ ++ (D_REGSET | Q_REGSET | I_REGSET | A_REGSET | M_REGSET | S_REGSET) ++#define ALL_REGSET (G_REGSET) ++ ++#define REG_CLASS_CONTENTS { \ ++ {0}, \ ++ {D_REGSET}, \ ++ {ACC_A_REGSET}, \ ++ {ACC_B_REGSET}, \ ++ {X_REGSET}, \ ++ {Z_REGSET}, \ ++ {Q_REGSET}, \ ++ {M_REGSET}, \ ++ {CC_REGSET}, \ ++ {I_REGSET}, \ ++ {T_REGSET}, \ ++ {A_REGSET}, \ ++ {S_REGSET}, \ ++ {P_REGSET}, \ ++ {G_REGSET}, \ ++ {ALL_REGSET}, \ ++} ++ ++/* The same information, inverted. ++ * This is defined to use the REG_CLASS_CONTENTS defines above, so that ++ * these two sets of definitions are always consistent. */ ++ ++#define REGNO_REG_CLASS(REGNO) \ ++ (D_REGNO_P (REGNO) ? D_REGS : \ ++ (Z_REGNO_P (REGNO) ? Z_REGS : \ ++ (ACC_A_REGNO_P (REGNO) ? ACC_A_REGS : \ ++ (ACC_B_REGNO_P (REGNO) ? ACC_B_REGS : \ ++ (X_REGNO_P (REGNO) ? X_REGS : \ ++ (Q_REGNO_P (REGNO) ? Q_REGS : \ ++ (M_REGNO_P (REGNO) ? M_REGS : \ ++ (CC_REGNO_P (REGNO) ? CC_REGS : \ ++ (I_REGNO_P (REGNO) ? I_REGS : \ ++ (T_REGNO_P (REGNO) ? T_REGS : \ ++ (A_REGNO_P (REGNO) ? A_REGS : \ ++ (S_REGNO_P (REGNO) ? S_REGS : \ ++ (P_REGNO_P (REGNO) ? P_REGS : \ ++ (G_REGNO_P (REGNO) ? G_REGS : ALL_REGS)))))))))))))) ++ ++#define D_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, D_REGSET)) ++#define ACC_A_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, ACC_A_REGSET)) ++#define ACC_B_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, ACC_B_REGSET)) ++#define X_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, X_REGSET)) ++#define Z_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, Z_REGSET)) ++#define Q_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, Q_REGSET)) ++#define M_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, M_REGSET)) ++#define CC_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, CC_REGSET)) ++#define I_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, I_REGSET)) ++#define T_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, T_REGSET)) ++#define A_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, A_REGSET)) ++#define S_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, S_REGSET)) ++#define P_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, P_REGSET)) ++#define G_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, G_REGSET)) ++ ++/* Macros that test an rtx 'X' to see if it's in a particular ++ * register class. 'X' need not be a REG necessarily. */ ++ ++#define D_REG_P(X) (REG_P (X) && D_REGNO_P (REGNO (X))) ++#define ACC_A_REG_P(X) (REG_P (X) && ACC_A_REGNO_P (REGNO (X))) ++#define ACC_B_REG_P(X) (REG_P (X) && ACC_B_REGNO_P (REGNO (X))) ++#define X_REG_P(X) (REG_P (X) && X_REGNO_P (REGNO (X))) ++#define Z_REG_P(X) (REG_P (X) && Z_REGNO_P (REGNO (X))) ++#define I_REG_P(X) (REG_P (X) && I_REGNO_P (REGNO (X))) ++#define T_REG_P(X) (REG_P (X) && T_REGNO_P (REGNO (X))) ++#define A_REG_P(X) (REG_P (X) && A_REGNO_P (REGNO (X))) ++#define S_REG_P(X) (REG_P (X) && S_REGNO_P (REGNO (X))) ++#define P_REG_P(X) (REG_P (X) && P_REGNO_P (REGNO (X))) ++#define Q_REG_P(X) (REG_P (X) && Q_REGNO_P (REGNO (X))) ++#define M_REG_P(X) (REG_P (X) && M_REGNO_P (REGNO (X))) ++#define CC_REG_P(X) (REG_P (X) && CC_REGNO_P (REGNO (X))) ++ ++/* Redefine this in terms of BYTE_REGSET */ ++#define BYTE_REGNO_P(REGNO) (REGSET_CONTAINS_P (REGNO, BYTE_REGSET)) ++ ++/* The class value for index registers, and the one for base regs. */ ++#define INDEX_REG_CLASS I_REGS ++#define BASE_REG_CLASS A_REGS ++ ++/* Get reg_class from a letter in the machine description. */ ++#define REG_CLASS_FROM_LETTER(C) \ ++ (((C) == 'a' ? A_REGS : \ ++ ((C) == 'd' ? D_REGS : \ ++ ((C) == 'x' ? I_REGS : \ ++ ((C) == 't' ? M_REGS : \ ++ ((C) == 'c' ? CC_REGS : \ ++ ((C) == 'A' ? ACC_A_REGS : \ ++ ((C) == 'B' ? ACC_B_REGS : \ ++ ((C) == 'v' ? X_REGS : \ ++ ((C) == 'u' ? S_REGS : \ ++ ((C) == 'U' ? P_REGS : \ ++ ((C) == 'T' ? T_REGS : \ ++ ((C) == 'z' ? Z_REGS : \ ++ ((C) == 'q' ? Q_REGS : NO_REGS)))))))))))))) ++ ++/*-------------------------------------------------------------- ++ The letters I through O in a register constraint string ++ can be used to stand for particular ranges of immediate operands. ++ This macro defines what the ranges are. ++ C is the letter, and VALUE is a constant value. ++ Return 1 if VALUE is in the range specified by C. ++ ++ For the 6809, J, K, L are used for indexed addressing. ++ `I' is used for the constant 1. ++ `J' is used for the 5-bit offsets. ++ `K' is used for the 8-bit offsets. ++ `L' is used for the range of signed numbers that fit in 16 bits. ++ `M' is used for the exact value '8'. ++ `N' is used for the constant -1. ++ `O' is used for the constant 0. ++--------------------------------------------------------------*/ ++ ++#define CONST_OK_FOR_LETTER_P(VALUE, C) \ ++ ((C) == 'I' ? ((VALUE) == 1) : \ ++ (C) == 'J' ? ((VALUE) >= -16 && (VALUE) <= 15) : \ ++ (C) == 'K' ? ((VALUE) >= -128 && (VALUE) <= 127) : \ ++ (C) == 'L' ? ((VALUE) >= -32768 && (VALUE) <= 32767) : \ ++ (C) == 'M' ? ((VALUE) == 8) : \ ++ (C) == 'N' ? ((VALUE) == -1) : \ ++ (C) == 'O' ? ((VALUE) == 0) : 0) ++ ++/* Similar, but for floating constants, and defining letters G and H. ++ No floating-point constants are valid on MC6809. */ ++#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ ++ ((C) == 'G' ? (GET_MODE_CLASS (GET_MODE (VALUE)) == MODE_FLOAT \ ++ && VALUE == CONST0_RTX (GET_MODE (VALUE))) : 0) ++ ++/* Given an rtx X being reloaded into a reg required to be ++ in class CLASS, return the class of reg to actually use. ++ In general this is just CLASS; but on some machines ++ in some cases it is preferable to use a more restrictive class. */ ++#define PREFERRED_RELOAD_CLASS(X,CLASS) m6809_preferred_reload_class(X,CLASS) ++ ++#define SMALL_REGISTER_CLASSES 1 ++ ++/* Return the maximum number of consecutive registers ++ needed to represent mode MODE in a register of class CLASS. */ ++#define CLASS_MAX_NREGS(CLASS, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) ++ ++/*-------------------------------------------------------------- ++ Stack layout; function entry, exit and calling. ++--------------------------------------------------------------*/ ++ ++/* Define this if pushing a word on the stack ++ makes the stack pointer a smaller address. */ ++#define STACK_GROWS_DOWNWARD ++ ++ ++/* Define this if the nominal address of the stack frame ++ is at the high-address end of the local variables; ++ that is, each additional local variable allocated ++ goes at a more negative offset in the frame. */ ++#define FRAME_GROWS_DOWNWARD 1 ++ ++ ++/* Offset within stack frame to start allocating local variables at. ++ If FRAME_GROWS_DOWNWARD, this is the offset to the END of the ++ first local allocated. Otherwise, it is the offset to the BEGINNING ++ of the first local allocated. */ ++#define STARTING_FRAME_OFFSET 0 ++ ++ ++/* Always push stack arguments for now. Accumulation is not yet working. */ ++#define PUSH_ROUNDING(BYTES) (BYTES) ++ ++ ++/* Offset of first parameter from the argument pointer register value. ++ * ARG_POINTER_REGNUM is defined to point to the return address pushed ++ * onto the stack, so we must offset by 2 bytes to get to the arguments. */ ++#define FIRST_PARM_OFFSET(FNDECL) 2 ++ ++/* Value is 1 if returning from a function call automatically ++ pops the arguments described by the number-of-args field in the call. ++ FUNTYPE is the data type of the function (as a tree), ++ or for a library call it is an identifier node for the subroutine name. */ ++/* #define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 */ ++ ++/* Define how to find the value returned by a function. ++ VALTYPE is the data type of the value (as a tree). ++ If the precise function being called is known, FUNC is its FUNCTION_DECL; ++ otherwise, FUNC is 0. */ ++#define FUNCTION_VALUE(VALTYPE, FUNC) m6809_function_value (VALTYPE, FUNC) ++ ++/* Define how to find the value returned by a library function ++ assuming the value has mode MODE. */ ++ ++/* All return values are in the X-register. */ ++#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, HARD_X_REGNUM) ++ ++/* Define this if using the nonreentrant convention for returning ++ structure and union values. No; it is inefficient and buggy. */ ++#undef PCC_STATIC_STRUCT_RETURN ++ ++/* 1 if N is a possible register number for a function value. */ ++#define FUNCTION_VALUE_REGNO_P(N) m6809_function_value_regno_p (N) ++ ++/* Define this to be true when FUNCTION_VALUE_REGNO_P is true for ++ more than one register. */ ++#define NEEDS_UNTYPED_CALL 1 ++ ++/* 1 if N is a possible register number for function argument passing. */ ++#define FUNCTION_ARG_REGNO_P(N) \ ++ ((m6809_abi_version != M6809_ABI_VERSION_STACK) ? \ ++ (((N) == HARD_D_REGNUM) || ((N) == HARD_X_REGNUM)) : \ ++ 0) ++ ++/*-------------------------------------------------------------- ++ Argument Lists ++--------------------------------------------------------------*/ ++ ++/* Cumulative arguments are tracked in a single integer, ++ * which is the number of bytes of arguments scanned so far, ++ * plus which registers have already been used. The register ++ * info is kept in some of the upper bits */ ++#define CUMULATIVE_ARGS unsigned int ++ ++#define CUM_STACK_ONLY 0x80000000 ++#define CUM_X_MASK 0x40000000 ++#define CUM_B_MASK 0x20000000 ++#define CUM_STACK_INVALID 0x10000000 ++#define CUM_STACK_MASK 0xFFFFFFF ++ ++#define CUM_ADVANCE_8BIT(cum) \ ++ (((cum) & CUM_B_MASK) ? (cum)++ : ((cum) |= CUM_B_MASK)) ++ ++#define CUM_ADVANCE_16BIT(cum) \ ++ (((cum) & CUM_X_MASK) ? (cum) += 2 : ((cum) |= CUM_X_MASK)) ++ ++/* Initialize a variable CUM of type CUMULATIVE_ARGS ++ for a call to a function whose data type is FNTYPE. ++ For a library call, FNTYPE is 0. ++ N_NAMED was added in gcc 3.4 and is not used currently. */ ++#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT,N_NAMED) \ ++ ((CUM) = m6809_init_cumulative_args (CUM, FNTYPE, LIBNAME)) ++ ++#define FUNCTION_ARG_SIZE(MODE, TYPE) \ ++ ((MODE) != BLKmode ? GET_MODE_SIZE (MODE) \ ++ : (unsigned) int_size_in_bytes (TYPE)) ++ ++/* Update the data in CUM to advance over an argument ++ of mode MODE and data type TYPE. ++ (TYPE is null for libcalls where that information may not be available.) */ ++#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ ++ (((MODE == QImode) && !((CUM) & CUM_STACK_ONLY)) ? \ ++ CUM_ADVANCE_8BIT (CUM) : \ ++ ((MODE == HImode) && !((CUM) & CUM_STACK_ONLY)) ? \ ++ CUM_ADVANCE_16BIT (CUM) : \ ++ ((CUM) = ((CUM) + (TYPE ? int_size_in_bytes (TYPE) : 2)))) ++ ++/* Define where to put the arguments to a function. ++ Value is zero to push the argument on the stack, ++ or a hard register rtx in which to store the argument. ++ This macro is used _before_ FUNCTION_ARG_ADVANCE. ++ ++ For the 6809, the first 8-bit function argument can be placed into B, ++ and the first 16-bit arg can go into X. All other arguments ++ will be pushed onto the stack. ++ ++ Command-line options can adjust this behavior somewhat. ++ */ ++#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ ++ ((MODE == VOIDmode) ? NULL_RTX : \ ++ ((MODE == BLKmode) || (GET_MODE_SIZE (MODE) > 2)) ? NULL_RTX : \ ++ ((MODE == QImode) && !((CUM) & (CUM_STACK_ONLY | CUM_B_MASK))) ? \ ++ gen_rtx_REG (QImode, HARD_D_REGNUM) : \ ++ ((MODE == HImode) && !((CUM) & (CUM_STACK_ONLY | CUM_X_MASK))) ? \ ++ gen_rtx_REG (HImode, HARD_X_REGNUM) : m6809_function_arg_on_stack (&CUM)) ++ ++/* Output assembler code to FILE to increment profiler label # LABELNO ++ for profiling a function entry. */ ++#define FUNCTION_PROFILER(FILE, LABELNO) \ ++ fprintf (FILE, "\tldd\t#LP%u\n\tjsr\tmcount\n", (LABELNO)); ++ ++/* Stack pointer must be correct on function exit */ ++#define EXIT_IGNORE_STACK 0 ++ ++/***************************************************************************** ++** ++** Trampolines for Nested Functions ++** ++*****************************************************************************/ ++ ++/* Length in units of the trampoline for entering a nested function. */ ++#define TRAMPOLINE_SIZE 7 ++ ++/*-------------------------------------------------------------- ++ Addressing modes, ++ and classification of registers for them. ++--------------------------------------------------------------*/ ++ ++/* 6809 has postincrement and predecrement addressing modes */ ++#define HAVE_POST_INCREMENT 1 ++#define HAVE_PRE_DECREMENT 1 ++ ++/* Whether or not to use index registers is configurable. ++ * Experiments show that things work better when this is off, so ++ * that's the way it is for now. */ ++#undef USE_INDEX_REGISTERS ++ ++ ++/* Macros to check register numbers against specific register classes. */ ++#define REG_VALID_FOR_BASE_P(REGNO) \ ++ (((REGNO) < FIRST_PSEUDO_REGISTER) && A_REGNO_P (REGNO)) ++ ++/* MC6809 index registers do not allow scaling, */ ++/* but there is "accumulator-offset" mode. */ ++#ifdef USE_INDEX_REGISTERS ++#define REG_VALID_FOR_INDEX_P(REGNO) \ ++ (((REGNO) < FIRST_PSEUDO_REGISTER) && I_REGNO_P (REGNO)) ++#else ++#define REG_VALID_FOR_INDEX_P(REGNO) 0 ++#endif ++ ++/* Internal macro, the nonstrict definition for REGNO_OK_FOR_BASE_P */ ++#define REGNO_OK_FOR_BASE_NONSTRICT_P(REGNO) \ ++ ((REGNO) >= FIRST_PSEUDO_REGISTER \ ++ || REG_VALID_FOR_BASE_P (REGNO) \ ++ || (REGNO) == FRAME_POINTER_REGNUM \ ++ || (REGNO) == HARD_FRAME_POINTER_REGNUM \ ++ || (REGNO) == ARG_POINTER_REGNUM \ ++ || (reg_renumber && REG_VALID_FOR_BASE_P (reg_renumber[REGNO]))) ++ ++/* Internal macro, the nonstrict definition for REGNO_OK_FOR_INDEX_P */ ++#define REGNO_OK_FOR_INDEX_NONSTRICT_P(REGNO) \ ++ ((REGNO) >= FIRST_PSEUDO_REGISTER \ ++ || REG_VALID_FOR_INDEX_P (REGNO) \ ++ || (reg_renumber && REG_VALID_FOR_INDEX_P (reg_renumber[REGNO]))) ++ ++ ++/* Internal macro, the strict definition for REGNO_OK_FOR_BASE_P */ ++#define REGNO_OK_FOR_BASE_STRICT_P(REGNO) \ ++ ((REGNO) < FIRST_PSEUDO_REGISTER ? REG_VALID_FOR_BASE_P (REGNO) \ ++ : (reg_renumber && REG_VALID_FOR_BASE_P (reg_renumber[REGNO]))) ++ ++ ++/* Internal macro, the strict definition for REGNO_OK_FOR_INDEX_P */ ++#define REGNO_OK_FOR_INDEX_STRICT_P(REGNO) \ ++ ((REGNO) < FIRST_PSEUDO_REGISTER ? REG_VALID_FOR_INDEX_P (REGNO) \ ++ : (reg_renumber && REG_VALID_FOR_INDEX_P (reg_renumber[REGNO]))) ++ ++ ++#define REGNO_OK_FOR_BASE_P(REGNO) REGNO_OK_FOR_BASE_STRICT_P (REGNO) ++ ++#define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_INDEX_STRICT_P (REGNO) ++ ++#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_STRICT_P (REGNO (X)) ++#define REG_OK_FOR_BASE_NONSTRICT_P(X) REGNO_OK_FOR_BASE_NONSTRICT_P (REGNO (X)) ++#define REG_OK_FOR_INDEX_STRICT_P(X) REGNO_OK_FOR_INDEX_STRICT_P (REGNO (X)) ++#define REG_OK_FOR_INDEX_NONSTRICT_P(X) REGNO_OK_FOR_INDEX_NONSTRICT_P (REGNO (X)) ++ ++#ifndef REG_OK_STRICT ++#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NONSTRICT_P(X) ++#ifdef USE_INDEX_REGISTERS ++#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_NONSTRICT_P(X) ++#else ++#define REG_OK_FOR_INDEX_P(X) 0 ++#endif ++#else ++#define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P (X) ++#ifdef USE_INDEX_REGISTERS ++#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_INDEX_STRICT_P (X) ++#else ++#define REG_OK_FOR_INDEX_P(X) 0 ++#endif ++#endif ++ ++/* Maximum number of registers that can appear in a valid memory address */ ++#ifdef USE_INDEX_REGISTERS ++#define MAX_REGS_PER_ADDRESS 2 ++#else ++#define MAX_REGS_PER_ADDRESS 1 ++#endif ++ ++/* 1 if X is an rtx for a constant that is a valid address. ++ * We allow any constant, plus the sum of any two constants (this allows ++ * offsetting a symbol ref) */ ++#define CONSTANT_ADDRESS_P(X) \ ++ ((CONSTANT_P (X)) \ ++ || ((GET_CODE (X) == PLUS) \ ++ && (CONSTANT_P (XEXP (X, 0))) && (CONSTANT_P (XEXP (X, 1))))) ++ ++/* Nonzero if the constant value X is a legitimate general operand. ++ It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ ++/* Any single-word constant is ok; the only contexts ++ allowing general_operand of mode DI or DF are movdi and movdf. */ ++#define LEGITIMATE_CONSTANT_P(X) (GET_CODE (X) != CONST_DOUBLE) ++ ++/* Nonzero if the X is a legitimate immediate operand in PIC mode. */ ++#define LEGITIMATE_PIC_OPERAND_P(X) !symbolic_operand (X, VOIDmode) ++ ++/*-------------------------------------------------------------- ++ Test for valid memory addresses ++--------------------------------------------------------------*/ ++/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression ++ that is a valid memory address for an instruction. ++ The MODE argument is the machine mode for the MEM expression ++ that wants to use this address. */ ++ ++/*-------------------------------------------------------------- ++ Valid addresses are either direct or indirect (MEM) versions ++ of the following forms. ++ constant N ++ register ,X ++ constant indexed N,X ++ accumulator indexed D,X ++ auto_increment ,X++ ++ auto_decrement ,--X ++--------------------------------------------------------------*/ ++ ++#define REGISTER_ADDRESS_P(X) \ ++ (REG_P (X) && REG_OK_FOR_BASE_P (X)) ++ ++#define EXTENDED_ADDRESS_P(X) \ ++ CONSTANT_ADDRESS_P (X) \ ++ ++#define LEGITIMATE_BASE_P(X) \ ++ ((REG_P (X) && REG_OK_FOR_BASE_P (X)) \ ++ || (GET_CODE (X) == SIGN_EXTEND \ ++ && GET_CODE (XEXP (X, 0)) == REG \ ++ && GET_MODE (XEXP (X, 0)) == HImode \ ++ && REG_OK_FOR_BASE_P (XEXP (X, 0)))) ++ ++#define LEGITIMATE_OFFSET_P(X) \ ++ (CONSTANT_ADDRESS_P (X) || (REG_P (X) && REG_OK_FOR_INDEX_P (X))) ++ ++/* 1 if X is the sum of a base register and an offset. */ ++#define INDEXED_ADDRESS(X) \ ++ ((GET_CODE (X) == PLUS \ ++ && LEGITIMATE_BASE_P (XEXP (X, 0)) \ ++ && LEGITIMATE_OFFSET_P (XEXP (X, 1))) \ ++ || (GET_CODE (X) == PLUS \ ++ && LEGITIMATE_BASE_P (XEXP (X, 1)) \ ++ && LEGITIMATE_OFFSET_P (XEXP (X, 0)))) ++ ++#define STACK_REG_P(X) (REG_P(X) && REGNO(X) == HARD_S_REGNUM) ++ ++#define STACK_PUSH_P(X) \ ++ (MEM_P (X) && GET_CODE (XEXP (X, 0)) == PRE_DEC && STACK_REG_P (XEXP (XEXP (X, 0), 0))) ++ ++#define STACK_POP_P(X) \ ++ (MEM_P (X) && GET_CODE (XEXP (X, 0)) == POST_INC && STACK_REG_P (XEXP (XEXP (X, 0), 0))) ++ ++#define PUSH_POP_ADDRESS_P(X) \ ++ (((GET_CODE (X) == PRE_DEC) || (GET_CODE (X) == POST_INC)) \ ++ && (LEGITIMATE_BASE_P (XEXP (X, 0)))) ++ ++/* Go to ADDR if X is a valid address. */ ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++{ \ ++ if (REGISTER_ADDRESS_P(X)) goto ADDR; \ ++ if (PUSH_POP_ADDRESS_P (X)) goto ADDR; \ ++ if (EXTENDED_ADDRESS_P (X)) goto ADDR; \ ++ if (INDEXED_ADDRESS (X)) goto ADDR; \ ++ if (MEM_P (X) && REGISTER_ADDRESS_P(XEXP (X, 0))) goto ADDR; \ ++ if (MEM_P (X) && PUSH_POP_ADDRESS_P (XEXP (X, 0))) goto ADDR; \ ++ if (MEM_P (X) && EXTENDED_ADDRESS_P (XEXP (X, 0))) goto ADDR; \ ++ if (MEM_P (X) && INDEXED_ADDRESS (XEXP (X, 0))) goto ADDR; \ ++} ++ ++/*-------------------------------------------------------------- ++ Address Fix-up ++--------------------------------------------------------------*/ ++/* Go to LABEL if ADDR (a legitimate address expression) ++ has an effect that depends on the machine mode it is used for. ++ In the latest GCC, this case is already handled by the core code ++ so no action is required here. */ ++#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) {} ++ ++ ++/*-------------------------------------------------------------- ++ Miscellaneous Parameters ++--------------------------------------------------------------*/ ++/* Specify the machine mode that this machine uses ++ for the index in the tablejump instruction. */ ++#define CASE_VECTOR_MODE Pmode ++ ++/* Define this as 1 if `char' should by default be signed; else as 0. */ ++#define DEFAULT_SIGNED_CHAR 0 ++ ++/* This flag, if defined, says the same insns that convert to a signed fixnum ++ also convert validly to an unsigned one. */ ++#define FIXUNS_TRUNC_LIKE_FIX_TRUNC ++ ++/* Max number of bytes we can move from memory to memory/register ++ in one reasonably fast instruction. */ ++#define MOVE_MAX 2 ++ ++/* Int can be 8 or 16 bits (default is 16) */ ++#define INT_TYPE_SIZE (TARGET_BYTE_INT ? 8 : 16) ++ ++/* Short is always 16 bits */ ++#define SHORT_TYPE_SIZE (TARGET_BYTE_INT ? 8 : 16) ++ ++/* Size (bits) of the type "long" on target machine */ ++#define LONG_TYPE_SIZE (TARGET_BYTE_INT ? 16 : 32) ++ ++/* Size (bits) of the type "long long" on target machine */ ++#define LONG_LONG_TYPE_SIZE 32 ++ ++/* Size (bits) of the type "char" on target machine */ ++#define CHAR_TYPE_SIZE 8 ++ ++/* Size (bits) of the type "float" on target machine */ ++#define FLOAT_TYPE_SIZE 32 ++ ++/* Size (bits) of the type "double" on target machine. ++ * Note that the C standard does not require that doubles ++ * hold any more bits than float. Since the 6809 has so few ++ * registers, we cannot really support more than 32-bits. */ ++#define DOUBLE_TYPE_SIZE 32 ++ ++/* Size (bits) of the type "long double" on target machine */ ++#define LONG_DOUBLE_TYPE_SIZE 32 ++ ++/* Define the type used for "size_t". With a 64KB address space, ++ * only a 16-bit value here makes sense. */ ++#define SIZE_TYPE (TARGET_BYTE_INT ? "long unsigned int" : "unsigned int") ++ ++/* Likewise, the difference between two pointers is also a 16-bit ++ * signed value. */ ++#define PTRDIFF_TYPE (TARGET_BYTE_INT ? "long int" : "int") ++ ++/* Nonzero if access to memory by bytes is slow and undesirable. */ ++#define SLOW_BYTE_ACCESS 0 ++ ++/* Define if shifts truncate the shift count ++ which implies one can omit a sign-extension or zero-extension ++ of a shift count. */ ++#define SHIFT_COUNT_TRUNCATED 0 ++ ++/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits ++ is done just by pretending it is already truncated. */ ++#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 ++ ++/* It is as good to call a constant function address as to ++ call an address kept in a register. */ ++#define NO_FUNCTION_CSE ++ ++/* Specify the machine mode that pointers have. ++ After generation of rtl, the compiler makes no further distinction ++ between pointers and any other objects of this machine mode. */ ++#define Pmode HImode ++ ++/* A function address in a call instruction ++ is a byte address (for indexing purposes) ++ so give the MEM rtx a byte's mode. */ ++#define FUNCTION_MODE HImode ++ ++/* Define the cost of moving a value from a register in CLASS1 ++ * to CLASS2, of a given MODE. ++ * ++ * On the 6809, hard register transfers are all basically equivalent. ++ * But soft register moves are treated more like memory moves. */ ++#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \ ++ (((CLASS1 == M_REGS) || (CLASS2 == M_REGS)) ? 4 : 7) ++ ++/* Define the cost of moving a value between a register and memory. */ ++#define MEMORY_MOVE_COST(MODE, CLASS, IN) 5 ++ ++/* Check a `double' value for validity for a particular machine mode. */ ++ ++#define CHECK_FLOAT_VALUE(MODE, D, OVERFLOW) \ ++ ((OVERFLOW) = check_float_value (MODE, &D, OVERFLOW)) ++ ++ ++/*-------------------------------------------------------------- ++ machine-dependent ++--------------------------------------------------------------*/ ++/* Tell final.c how to eliminate redundant test instructions. */ ++ ++/* Here we define machine-dependent flags and fields in cc_status ++ (see `conditions.h'). */ ++ ++/* Store in cc_status the expressions ++ that the condition codes will describe ++ after execution of an instruction whose pattern is EXP. ++ Do not alter them if the instruction would not alter the cc's. */ ++ ++/* On the 6809, most of the insns to store in an address register ++ fail to set the cc's. However, in some cases these instructions ++ can make it possibly invalid to use the saved cc's. In those ++ cases we clear out some or all of the saved cc's so they won't be used. */ ++ ++#define NOTICE_UPDATE_CC(EXP, INSN) \ ++ notice_update_cc((EXP), (INSN)) ++ ++/***************************************************************************** ++** ++** pragma support ++** ++*****************************************************************************/ ++ ++#if 0 ++#define REGISTER_TARGET_PRAGMAS() \ ++do { \ ++ extern void pragma_section PARAMS ((cpp_reader *)); \ ++ c_register_pragma (0, "section", pragma_section); \ ++} while (0) ++ ++#endif ++ ++/*-------------------------------------------------------------- ++ ASSEMBLER FORMAT ++--------------------------------------------------------------*/ ++ ++#define FMT_HOST_WIDE_INT "%ld" ++ ++/* Output to assembler file text saying following lines ++ may contain character constants, extra white space, comments, etc. */ ++#define ASM_APP_ON ";----- asm -----\n" ++ ++/* Output to assembler file text saying following lines ++ no longer contain unusual constructs. */ ++#define ASM_APP_OFF ";--- end asm ---\n" ++ ++/* Use a semicolon to begin a comment. */ ++#define ASM_COMMENT_START "; " ++ ++/* Output assembly directives to switch to section 'name' */ ++#undef TARGET_ASM_NAMED_SECTION ++#define TARGET_ASM_NAMED_SECTION m6809_asm_named_section ++ ++#undef TARGET_HAVE_NAMED_SECTION ++#define TARGET_HAVE_NAMED_SECTION m6809_have_named_section ++ ++/* Output before read-only data. */ ++#define TEXT_SECTION_ASM_OP (code_section_op) ++ ++/* Output before writable data. */ ++#define DATA_SECTION_ASM_OP (data_section_op) ++ ++/* Output before uninitialized data. */ ++#define BSS_SECTION_ASM_OP (bss_section_op) ++ ++/* Support the ctors and dtors sections for g++. */ ++ ++#undef CTORS_SECTION_ASM_OP ++#define CTORS_SECTION_ASM_OP "\t.area .ctors" ++#undef DTORS_SECTION_ASM_OP ++#define DTORS_SECTION_ASM_OP "\t.area .dtors" ++ ++ ++#undef DO_GLOBAL_CTORS_BODY ++#undef DO_GLOBAL_DTORS_BODY ++ ++#define HAS_INIT_SECTION ++ ++/* This is how to output an assembler line ++ that says to advance the location counter ++ to a multiple of 2**LOG bytes. */ ++ ++#define ASM_OUTPUT_ALIGN(FILE,LOG) \ ++ if ((LOG) > 1) \ ++ fprintf (FILE, "\t.bndry %u\n", 1 << (LOG)) ++ ++/* The .set foo,bar construct doesn't work by default */ ++#undef SET_ASM_OP ++#define ASM_OUTPUT_DEF(FILE, LABEL1, LABEL2) \ ++ do \ ++ { \ ++ fputc ('\t', FILE); \ ++ assemble_name (FILE, LABEL1); \ ++ fputs (" = ", FILE); \ ++ assemble_name (FILE, LABEL2); \ ++ fputc ('\n', FILE); \ ++ } \ ++ while (0) ++ ++/* How to refer to registers in assembler output. ++ This sequence is indexed by compiler's hard-register-number (see above). */ ++#define MNAME(x) [SOFT_M0_REGNUM+(x)] = "*m" C_STRING(x) , ++ ++#define REGISTER_NAMES { \ ++ [HARD_D_REGNUM]= "d", \ ++ [HARD_X_REGNUM]= "x", \ ++ [HARD_Y_REGNUM]= "y", \ ++ [HARD_U_REGNUM]= "u", \ ++ [HARD_S_REGNUM]= "s", \ ++ [HARD_PC_REGNUM]= "pc", \ ++ [HARD_A_REGNUM]= "a", \ ++ [HARD_B_REGNUM]= "b", \ ++ [HARD_CC_REGNUM]= "cc",\ ++ [HARD_DP_REGNUM]= "dp", \ ++ [SOFT_FP_REGNUM]= "soft_fp", \ ++ [SOFT_AP_REGNUM]= "soft_ap", \ ++ MNAME(0) MNAME(1) MNAME(2) MNAME(3) \ ++ MNAME(4) MNAME(5) MNAME(6) MNAME(7) \ ++ [HARD_RSVD1_REGNUM] = "-", \ ++ [HARD_Z_REGNUM] = "z" /* bit 2 of CC */ } ++ ++/***************************************************************************** ++** ++** Debug Support ++** ++*****************************************************************************/ ++ ++/* Default to DBX-style debugging */ ++#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG ++ ++#define DBX_DEBUGGING_INFO ++ ++#define DEFAULT_GDB_EXTENSIONS 0 ++ ++#define ASM_STABS_OP ";\t.stabs\t" ++#define ASM_STABD_OP ";\t.stabd\t" ++#define ASM_STABN_OP ";\t.stabn\t" ++ ++#define DBX_CONTIN_LENGTH 54 ++ ++#define DBX_OUTPUT_MAIN_SOURCE_FILENAME(ASMFILE, FILENAME) \ ++do { \ ++ const char *p = FILENAME; \ ++ while ((p = strchr (p, '/')) != NULL) { \ ++ p = FILENAME = p+1; \ ++ } \ ++ fprintf (ASMFILE, "%s", ASM_STABS_OP); \ ++ output_quoted_string (ASMFILE, FILENAME); \ ++ fprintf (ASMFILE, ",%d,0,0,", N_SO); \ ++ assemble_name (ASMFILE, ltext_label_name); \ ++ fputc ('\n', ASMFILE); \ ++ switch_to_section (text_section); \ ++ (*targetm.asm_out.internal_label) (ASMFILE, "Ltext", 0); \ ++} while (0) ++ ++/* With -g, GCC sometimes outputs string literals that are longer than ++ * the assembler can handle. Without actual debug support, these are ++ * not really required. Redefine the function to output strings to ++ * output as much as possible. */ ++#define OUTPUT_QUOTED_STRING(FILE, STR) m6809_output_quoted_string (FILE, STR) ++ ++/***************************************************************************** ++** ++** Output and Generation of Labels ++** ++*****************************************************************************/ ++ ++/* Prefixes for various assembly-time objects */ ++ ++#define REGISTER_PREFIX "" ++ ++#define LOCAL_LABEL_PREFIX "" ++ ++#define USER_LABEL_PREFIX "_" ++ ++#define IMMEDIATE_PREFIX "#" ++ ++/* This is how to output the definition of a user-level label named NAME, ++ such as the label on a static function or variable NAME. */ ++ ++#define ASM_OUTPUT_LABEL(FILE,NAME) \ ++do { \ ++ if (section_changed) { \ ++ fprintf (FILE, "\n%s\n\n", code_section_op); \ ++ section_changed = 0; \ ++ } \ ++ assemble_name (FILE, NAME); \ ++ fputs (":\n", FILE); \ ++} while (0) ++ ++/* This is how to output the label for a function definition. It ++ invokes ASM_OUTPUT_LABEL, but may examine the DECL tree node for ++ other properties. */ ++#define ASM_DECLARE_FUNCTION_NAME(FILE,NAME,DECL) \ ++ m6809_declare_function_name (FILE,NAME,DECL) ++ ++/* This is how to output a command to make the user-level label ++ named NAME defined for reference from other files. */ ++ ++#define GLOBAL_ASM_OP "\t.globl " ++ ++/* This is how to output a reference to a user label named NAME. */ ++#define ASM_OUTPUT_LABELREF(FILE,NAME) \ ++ fprintf (FILE, "_%s", NAME) ++ ++/* This is how to output a reference to a symbol ref ++ * Check to see if the symbol is in the direct page */ ++#define ASM_OUTPUT_SYMBOL_REF(FILE,sym) \ ++{ \ ++ print_direct_prefix (FILE, sym); \ ++ assemble_name (FILE, XSTR (sym, 0)); \ ++} ++ ++/* External references aren't necessary, so don't emit anything */ ++#define ASM_OUTPUT_EXTERNAL(FILE,DECL,NAME) ++ ++/* This is how to store into the string LABEL ++ the symbol_ref name of an internal numbered label where ++ PREFIX is the class of label and NUM is the number within the class. ++ This is suitable for output with `assemble_name'. */ ++#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ ++ sprintf (LABEL, "*%s%lu", PREFIX, (unsigned long int)NUM) ++ ++/* This is how to output an assembler line defining an `int' constant. */ ++#define ASM_OUTPUT_INT(FILE,VALUE) \ ++( fprintf (FILE, "\t.word "), \ ++ output_addr_const (FILE, (VALUE)), \ ++ fprintf (FILE, "\n")) ++ ++/* Likewise for `char' and `short' constants. */ ++#define ASM_OUTPUT_SHORT(FILE,VALUE) \ ++( fprintf (FILE, "\t.word "), \ ++ output_addr_const (FILE, (VALUE)), \ ++ fprintf (FILE, "\n")) ++ ++/* This is how to output a string. */ ++#define ASM_OUTPUT_ASCII(FILE,STR,SIZE) m6809_output_ascii (FILE, STR, SIZE) ++ ++/* This is how to output an insn to push a register on the stack. ++ It need not be very fast code. */ ++ ++#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \ ++ fprintf (FILE, "\tpshs\t%s\n", reg_names[REGNO]) ++ ++/* This is how to output an insn to pop a register from the stack. ++ It need not be very fast code. */ ++ ++#define ASM_OUTPUT_REG_POP(FILE,REGNO) \ ++ fprintf (FILE, "\tpuls\t%s\n", reg_names[REGNO]) ++ ++/* This is how to output an element of a case-vector that is absolute. */ ++ ++#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ ++ fprintf (FILE, "\t.word L%u\n", VALUE) ++ ++/* This is how to output an element of a case-vector that is relative. */ ++ ++#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ ++ fprintf (FILE, "\t.word L%u-L%u\n", VALUE, REL) ++ ++ ++/***************************************************************************** ++** ++** Assembler Commands for Alignment ++** ++*****************************************************************************/ ++ ++/* ASM_OUTPUT_SKIP is supposed to zero initialize the data. ++ * So use the .byte and .word directives instead of .blkb */ ++#define ASM_OUTPUT_SKIP(FILE,SIZE) \ ++ do { \ ++ int __size = SIZE; \ ++ while (__size > 0) { \ ++ if (__size >= 2) \ ++ { \ ++ fprintf (FILE, "\t.word\t0\t;skip space %d\n", __size); \ ++ __size -= 2; \ ++ } \ ++ else \ ++ { \ ++ fprintf (FILE, "\t.byte\t0\t;skip space\n"); \ ++ __size--; \ ++ } \ ++ } \ ++ } while (0) ++ ++/* This says how to output an assembler line ++ to define a global common symbol. */ ++ ++#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ ++ do { \ ++ switch_to_section (bss_section); \ ++ fputs ("\t.globl\t", FILE); \ ++ assemble_name ((FILE), (NAME)); \ ++ fputs ("\n", FILE); \ ++ assemble_name ((FILE), (NAME)); \ ++ fprintf ((FILE), ":\t.blkb\t" FMT_HOST_WIDE_INT "\n", (ROUNDED));} while(0) ++ ++/* This says how to output an assembler line ++ to define a local common symbol. */ ++ ++#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ ++do { \ ++ switch_to_section (bss_section); \ ++ assemble_name ((FILE), (NAME)); \ ++ fprintf ((FILE), ":\t.blkb\t" FMT_HOST_WIDE_INT "\n", (ROUNDED));} while(0) ++ ++/* Store in OUTPUT a string (made with alloca) containing ++ an assembler-name for a local static variable named NAME. ++ LABELNO is an integer which is different for each call. */ ++ ++#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ ++( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ ++ sprintf ((OUTPUT), "%s.%lu", (NAME), (unsigned long int)(LABELNO))) ++ ++/* Print an instruction operand X on file FILE. ++ CODE is the code from the %-spec for printing this operand. ++ If `%z3' was used to print operand 3, then CODE is 'z'. */ ++#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE) ++ ++/* Print a memory operand whose address is X, on file FILE. */ ++#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR) ++ ++/* Don't let stack pushes build up too much. */ ++#define MAX_PENDING_STACK 8 ++ ++/* Define values for builtin operations */ ++enum m6809_builtins ++{ ++ M6809_SWI, ++ M6809_SWI2, ++ M6809_SWI3, ++ M6809_CWAI, ++ M6809_SYNC, ++ M6809_ADD_CARRY, ++ M6809_SUB_CARRY, ++ M6809_ADD_DECIMAL, ++ M6809_NOP, ++ M6809_BLOCKAGE ++}; ++ +diff -urN gcc-4.6.4-clean/gcc/config/m6809/m6809.md gcc-4.6.4/gcc/config/m6809/m6809.md +--- gcc-4.6.4-clean/gcc/config/m6809/m6809.md 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-4.6.4/gcc/config/m6809/m6809.md 2015-07-20 22:05:21.702720231 -0600 +@@ -0,0 +1,2358 @@ ++;; GCC machine description for Motorola 6809 ++;; Copyright (C) 1989, 2005, 2006, 2007, 2008, ++;; 2009 Free Software Foundation, Inc. ++;; ++;; Mostly by Brian Dominy (brian@oddchange.com) with substantial renovations ++;; by William Astle (lost@l-w.ca). ++;; ++;; Based on earlier work by Tom Jones (jones@sal.wisc.edu) and ++;; Matthias Doerfel (msdoerfe@informatik.uni-erlangen.de) ++;; ++;; 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 ++;; <http://www.gnu.org/licenses/>. ++;; ++;; General information: ++;; -------------------- ++;; * This backend is mostly a rewrite from earlier (3.1.1 and before) ++;; versions. ++;; ++;; * The 'A' and 'B' registers are treated as a single register by the ++;; register allocator; hence, the instruction templates assume that ++;; both can be modified if either one is available for use. No ++;; attempt is made to split instructions to refer to a particular half ++;; of the register. It is always referred to as the 'D' register, even ++;; in QImode (when it will be displayed as 'B'). ++;; ++;; * There is full support for proper branch instruction generation, ++;; based on instruction lengths. However, many instruction patterns ++;; are still overloaded to emit lots of real instructions, which can ++;; make the length calculation difficult; in those cases, I've tried ++;; to be pessimistic and assume the worst-case. ++;; ++;; * The instruction type attributes are only defined for branch ++;; vs. non branch instructions for now, since there is seemingly no ++;; reason to define these for other types anyway. ++;; ++;; * The limited number of total registers presents the greatest ++;; challenge. There are 'soft registers' -- memory locations ++;; used to simulate real regs -- which can be helpful. ++;; ++;; * Position-independent code (PIC) is supported and has been tested ++;; but not to the extent of absolute code generation. ++;; ++;; * All of the 6809 special opcodes, e.g. SWI and SYNC, are defined ++;; as UNSPEC instructions, and can be accessed from C code using ++;; __builtin_xxxx() style functions. ++;; ++;; What still needs to be done: ++;; ---------------------------- ++;; * Replace remaining instances of (define_peephole) with ++;; (define_peephole2), or remove them completely if they are not ++;; matching anyway. Add more peepholes for things actually encountered. ++;; ++;; * Indexing addressing can lead to crashes in complex functions when ++;; register pressure is high. Only the 'D' register can actually be ++;; used as an index register, and its demand by other instructions ++;; can sometimes mean that it is impossible to satisfy constraints. ++;; Currently, indexing is completely disabled to avoid these types ++;; of problems, although code is slightly more inefficient in some ++;; working cases. ++;; ++;; * 32-bit math is terribly inefficient. ++;; ++ ++ ++;;-------------------------------------------------------------------- ++;;- Constants ++;;-------------------------------------------------------------------- ++ ++; ++; Define constants for hard register numbers. ++; ++(define_constants [ ++ (HARD_RSVD1_REGNUM 0) ++ (HARD_X_REGNUM 1) (HARD_Y_REGNUM 2) (HARD_U_REGNUM 3) ++ (HARD_S_REGNUM 4) (HARD_PC_REGNUM 5) (HARD_D_REGNUM 6) ++ (HARD_Z_REGNUM 7) ++ (HARD_A_REGNUM 8) (HARD_B_REGNUM 9) ++ (HARD_CC_REGNUM 10) (HARD_DP_REGNUM 11) ++ (SOFT_FP_REGNUM 12) (SOFT_AP_REGNUM 13) ++ (SOFT_M0_REGNUM 14) (SOFT_M1_REGNUM 15) ++ (SOFT_M2_REGNUM 16) (SOFT_M3_REGNUM 17) ++]) ++ ++ ++; ++; The range in which a short branch insn can be used. ++; ++(define_constants [ ++ (MIN_SHORT_BRANCH_OFFSET -127) ++ (MAX_SHORT_BRANCH_OFFSET 128) ++]) ++ ++ ++; ++; The lengths of various types of real 6809 instructions. ++; ++; By default, ordinary insns are 4 bytes long. This is often not ++; right, and the insn patterns below will redefine this to the ++; correct value. ++; ++; Branch instruction lengths (conditional and unconditionals) are ++; well known and declared here. The short insns are used when the ++; offset is within the range declared above (between MIN_SHORT ++; and MAX_SHORT) ; otherwise the long form is used. ++; ++(define_constants [ ++ (DEFAULT_INSN_LENGTH 4) ++ (SHORT_CBRANCH_LENGTH 2) ++ (LONG_CBRANCH_LENGTH 4) ++ (SHORT_BRANCH_LENGTH 2) ++ (LONG_BRANCH_LENGTH 3) ++]) ++ ++ ++; ++; Constants for insn cycle counts. ++; Note that these counts all assume 1-byte opcodes. 2-byte ++; opcodes require 1 extra cycles for fetching the extra byte. ++; ++(define_constants [ ++ ;; The default insn length, when it cannot be calculated. ++ ;; Take a conservative approach and estimate high. ++ (DEFAULT_INSN_CYCLES 10) ++ ++ ;; Cycle counts for ALU and load operations. ++ (ALU_INHERENT_CYCLES 2) ++ (ALU_IMMED_CYCLES 2) ++ (ALU_DIRECT_CYCLES 4) ++ (ALU_INDEXED_BASE_CYCLES 4) ++ (ALU_EXTENDED_CYCLES 5) ++ ++ ;; If an ALU operation is on a 16-bit register (D), then ++ ;; add this number of cycles to the total count. ++ (ALU_16BIT_CYCLES 2) ++ ++ ;; A load of a 16-bit register incurs this extra amount. ++ (LOAD_16BIT_CYCLES 1) ++ ++ ;; Cycle counts for memory-only operations (bit shifts, clear, test) ++ (MEM_DIRECT_CYCLES 6) ++ (MEM_INDEXED_BASE_CYCLES 6) ++ (MEM_EXTENDED_CYCLES 7) ++ ++ ;; Cycle count for any reg-reg transfer (regardless of size) ++ (EXG_CYCLES 8) ++ (TFR_CYCLES 6) ++ ++ ;; Cycle count for a condition code update (andcc/orcc) ++ (CC_CYCLES 3) ++ ++ (JMP_DIRECT_CYCLES 3) ++ (JMP_INDEXED_BASE_CYCLES 3) ++ (JMP_EXTENDED_CYCLES 4) ++ ++ (JSR_DIRECT_CYCLES 7) ++ (JSR_INDEXED_BASE_CYCLES 7) ++ (JSR_EXTENDED_CYCLES 8) ++ ++ (LEA_BASE_CYCLES 4) ++ ++ ;; Cycle count for a psh/pul operations. Add to this the ++ ;; total number of bytes moved for the correct count. ++ (PSH_PUL_CYCLES 5) ++ ++ ;; Miscellaneous cycle counts ++ (CWAI_CYCLES 20) ++ (MUL_CYCLES 11) ++ (NOP_CYCLES 2) ++ (RTI_CYCLES 15) ++ (RTS_CYCLES 5) ++ (SWI_CYCLES 20) ++ (SYNC_CYCLES 4) ++]) ++ ++ ++; ++; An enumeration of values for each "unspec"; i.e. unspecified ++; instruction. These represent insns that are meaningful on the ++; 6809 but which have no intrinsic meaning to GCC itself. ++; These insns can be generated explicitly using the __builtin_xxx ++; syntax; they are also implicitly generated by the backend ++; as needed to implement other insns. ++; ++(define_constants [ ++ (UNSPEC_BLOCKAGE 0) ++ (UNSPEC_PUSH_RS 1) ++ (UNSPEC_POP_RS 2) ++ (UNSPEC_SWI 3) ++ (UNSPEC_CWAI 4) ++ (UNSPEC_ADD_CARRY 5) ++ (UNSPEC_SUB_CARRY 6) ++ (UNSPEC_SYNC 7) ++ (UNSPEC_ADD_DECIMAL 8) ++]) ++ ++ ++;;-------------------------------------------------------------------- ++;;- Predicates ++;;-------------------------------------------------------------------- ++ ++(include "predicates.md") ++ ++;;-------------------------------------------------------------------- ++;;- Attributes ++;;-------------------------------------------------------------------- ++ ++;; ++;; The type attribute is used to distinguish between different ++;; types of branch instructions, so that their lengths can be ++;; calculated correctly. ++;; ++(define_attr "type" "branch,cbranch,unknown" (const_string "unknown")) ++ ++;; ++;; The length of a branch instruction is calculated based on how ++;; far away the branch target is. Lengths of other insns default ++;; to 4. set_attr is used in instruction templates to specify ++;; the length when it is known exactly. When not sure, err on ++;; the high side to avoid compile errors. ++;; ++(define_attr "length" "" ++ (cond [ ++ (eq_attr "type" "branch") ++ (if_then_else (lt (minus (match_dup 0) (pc)) ++ (const_int MIN_SHORT_BRANCH_OFFSET)) ++ (const_int LONG_BRANCH_LENGTH) ++ (if_then_else (gt (minus (match_dup 0) (pc)) ++ (const_int MAX_SHORT_BRANCH_OFFSET)) ++ (const_int LONG_BRANCH_LENGTH) ++ (const_int SHORT_BRANCH_LENGTH))) ++ (eq_attr "type" "cbranch") ++ (if_then_else (lt (minus (match_dup 0) (pc)) ++ (const_int MIN_SHORT_BRANCH_OFFSET)) ++ (const_int LONG_CBRANCH_LENGTH) ++ (if_then_else (gt (minus (match_dup 0) (pc)) ++ (const_int MAX_SHORT_BRANCH_OFFSET)) ++ (const_int LONG_CBRANCH_LENGTH) ++ (const_int SHORT_CBRANCH_LENGTH))) ++ ] (const_int DEFAULT_INSN_LENGTH))) ++ ++ ++;; ++;; The default attributes for 'asm' statements. ++;; The default length is the longest possible single 6809 instruction, ++;; which is 5 bytes. GCC will automatically multiply this by the ++;; number of real insns contained in an asm statement. ++;; ++(define_asm_attributes ++ [(set_attr "length" "5") ++ (set_attr "type" "unknown")]) ++ ++;; ++;; An attribute for the number of cycles that it takes an instruction ++;; to execute. ++;; ++(define_attr "cycles" "" (const_int DEFAULT_INSN_CYCLES)) ++ ++ ++;;-------------------------------------------------------------------- ++;;- Instruction patterns. When multiple patterns apply, ++;;- the first one in the file is chosen. ++;;- ++;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. ++;;- ++;;- Note: NOTICE_UPDATE_CC in m6809.h handles condition code updates ++;;- for most instructions. ++;;-------------------------------------------------------------------- ++ ++;;-------------------------------------------------------------------- ++;;- Test ++;;-------------------------------------------------------------------- ++ ++;; cmpx is 3 bytes, not 4 ++(define_insn "*tsthi_x" ++ [(set (cc0) (match_operand:HI 0 "register_operand_x" "v"))] ++ "" ++ "cmpx\t#0" ++ [(set_attr "length" "3")]) ++ ++;; subd #0 is 3 bytes, better than cmpd #0 which is 4 bytes ++(define_insn "*tsthi_d" ++ [(set (cc0) (match_operand:HI 0 "register_operand_d" "d"))] ++ "" ++ "subd\t#0" ++ [(set_attr "length" "3")]) ++ ++(define_insn "*tsthi" ++ [(set (cc0) (match_operand:HI 0 "register_operand" "a"))] ++ "" ++ "cmp%0\t#0" ++ [(set_attr "length" "4")]) ++ ++(define_insn "*bitqi3" ++ [(set (cc0) ++ (and:QI (match_operand:QI 0 "register_operand" "%q") ++ (match_operand:QI 1 "general_operand" "mi")))] ++ "" ++ "bit%0\t%1" ++ [(set_attr "length" "3")]) ++ ++ ++(define_insn "tstqi" ++ [(set (cc0) (match_operand:QI 0 "nonimmediate_operand" "q,mt"))] ++ "" ++ "@ ++ tst%0 ++ tst\t%0" ++ [(set_attr "length" "1,3")]) ++ ++;;-------------------------------------------------------------------- ++;;- Compare instructions ++;;-------------------------------------------------------------------- ++ ++;; - cmphi for register to memory or register compares ++(define_insn "cmphi" ++ [(set (cc0) ++ (compare ++ (match_operand:HI 0 "general_operand" "da, mi, ??Ud") ++ (match_operand:HI 1 "general_operand" "mi, da, dU")))] ++ "" ++{ ++ if ((REG_P (operands[0])) && (REG_P (operands[1]))) { ++ output_asm_insn ("pshs\t%1\t;cmphi: R:%1 with R:%0", operands); ++ return "cmp%0\t,s++\t;cmphi:"; ++ } ++ if (GET_CODE (operands[0]) == REG) ++ return "cmp%0\t%1\t;cmphi:"; ++ else { ++ cc_status.flags |= CC_REVERSED; ++ return "cmp%1\t%0\t;cmphi:(R)"; ++ } ++} ++ [(set_attr "length" "5,5,7")]) ++ ++ ++(define_insn "cmpqi" ++ [(set (cc0) ++ (compare (match_operand:QI 0 "whole_general_operand" "q,q, q,O,mt,K") ++ (match_operand:QI 1 "whole_general_operand" "O,mt,K,q,q, q")))] ++ "" ++{ ++ if (REG_P (operands[0]) && !M_REG_P (operands[0])) ++ { ++ if (operands[1] == const0_rtx) ++ return "tst%0\t;cmpqi:(ZERO)"; ++ else ++ return "cmp%0\t%1\t;cmpqi:"; ++ } ++ else ++ { ++ cc_status.flags |= CC_REVERSED; ++ ++ if (operands[0] == const0_rtx) ++ return "tst%1\t;cmpqi:(RZERO)"; ++ else ++ return "cmp%1\t%0\t;cmpqi:(R)"; ++ } ++} ++ [(set_attr "length" "1,3,2,1,3,2")]) ++ ++ ++;;-------------------------------------------------------------------- ++;;- Compare/branch pattern ++;;-------------------------------------------------------------------- ++ ++(define_expand "cbranchhi4" ++ [(set (cc0) ++ (compare ++ (match_operand:HI 1 "general_operand" "da, mi, ??Ud") ++ (match_operand:HI 2 "general_operand" "mi, da, dU"))) ++ (set (pc) ++ (if_then_else ++ (match_operator 0 "ordered_comparison_operator" [(cc0) (const_int 0)]) ++ (label_ref (match_operand 3 "" "")) ++ (pc)))] ++ "" ++ "" ++) ++ ++(define_expand "cbranchqi4" ++ [(set (cc0) ++ (compare ++ (match_operand:QI 1 "whole_general_operand" "q,q, q,O,mt,K") ++ (match_operand:QI 2 "whole_general_operand" "O,mt,K,q,q, q"))) ++ (set (pc) ++ (if_then_else ++ (match_operator 0 "ordered_comparison_operator" [(cc0) (const_int 0)]) ++ (label_ref (match_operand 3 "" "")) ++ (pc)))] ++ "" ++ "" ++) ++ ++;;-------------------------------------------------------------------- ++;;- Move ++;;-------------------------------------------------------------------- ++ ++; this looks good (obviously not finished) but I still see 'movsi' ++; places in udivsi3 where it's broken ++; (define_insn "pushsi1" ++; [(set (mem:SI (pre_dec (reg:HI HARD_S_REGNUM))) ++; (match_operand:SI 0 "general_operand" "o")) ++; (set (reg:HI HARD_S_REGNUM) ++; (plus:HI (reg:HI HARD_S_REGNUM) (const_int -4))) ] ++; "" ++; "; pushsi %0" ++; [(set_attr "length" "12")]) ++; ++; (define_insn "popsi1" ++; [(set (match_operand:SI 0 "general_operand" "=o") ++; (mem:SI (post_inc (reg:HI HARD_S_REGNUM)))) ++; (set (reg:HI HARD_S_REGNUM) ++; (plus:HI (reg:HI HARD_S_REGNUM) (const_int 4))) ] ++; "" ++; "; popsi %0" ++; [(set_attr "length" "12")]) ++ ++; (define_insn "movsi" ++; [(set (match_operand:SI 0 "nonimmediate_operand" "=o") ++; (match_operand:SI 1 "general_operand" " oi"))] ++; "" ++; "; movsi %0 <- %1" ++; [(set_attr "length" "1")]) ++ ++; this doesn't work ++; (define_expand "movsi" ++; [(parallel [ ++; (set (match_operand:SI 0 "nonimmediate_operand" "") ++; (match_operand:SI 1 "general_operand" "")) ++; (clobber (match_scratch:HI 2 ""))])] ++; "" ++; { ++; rtx insn; ++; if (STACK_PUSH_P (operands[0]) || STACK_POP_P (operands[1])) ++; { ++; REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, stack_pointer_rtx, REG_NOTES (insn)); ++; } ++; insn = emit_move_multi_word (SImode, operands[0], operands[1]); ++; DONE; ++; }) ++ ++ ++(define_expand "movhi" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (match_operand:HI 1 "general_operand" ""))] ++ "" ++{ ++ /* One of the ops has to be in a register prior to reload */ ++ if (!register_operand (operand0, HImode) && ++ !register_operand (operand1, HImode)) ++ operands[1] = copy_to_mode_reg (HImode, operand1); ++}) ++ ++;;; Try a splitter to handle failure cases where we try to move ++;;; an immediate constant (zero usually) directly to memory. ++;;; This absolutely requires an intermediate register. ++(define_split ++ [(set (match_operand:HI 0 "memory_operand" "") ++ (match_operand:HI 1 "immediate_operand" "")) ++ (clobber (match_operand:HI 2 "register_operand" ""))] ++ "" ++ [(set (match_dup 2) (match_dup 1)) ++ (set (match_dup 0) (match_dup 2))] ++ "") ++ ++ ++;;; This would be a nice method for loading from a word array, ++;;; but it is never generated because the combiner cannot merge ++;;; more than 3 instructions (there are four here). This is ++;;; perhaps better done via a peephole. ++(define_insn "*movhi_array_load" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=da") ++ (mem:HI (plus:HI (ashift:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%B")) (const_int 1)) ++ (match_operand:HI 2 "immediate_operand" "i")))) ++ (clobber (match_scratch:HI 3 "=X"))] ++ "" ++ "ldx\t%2\;abx\;abx\;ld%0\t,x" ++ [(set_attr "length" "7")]) ++ ++ ++;;; Optimize the move of a byte to the stack using the pshs instruction ++;;; instead of a store with pre-increment. ++(define_insn "movhi_push" ++ [(set (match_operand:HI 0 "push_operand" "=m") ++ (match_operand:HI 1 "register_operand" "U"))] ++ "" ++ "pshs\t%1" ++ [(set_attr "length" "2")]) ++ ++ ++(define_insn "*movhi_pic_symbolref" ++ [(set (match_operand:HI 0 "register_operand" "=a") ++ (match_operand:HI 1 "symbolic_operand" ""))] ++ "flag_pic" ++ "lea%0\t%c1,pcr" ++ [(set_attr "length" "4")]) ++ ++ ++(define_insn "*movhi_1" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=a,d,a,ad,mu") ++ (match_operand:HI 1 "general_operand" " a,a,d,miu,ad"))] ++ "" ++ "@ ++ lea%0\t,%1 ++ tfr\t%1,%0 ++ tfr\t%1,%0 ++ ld%0\t%1 ++ st%1\t%0" ++ [(set_attr "length" "2,2,2,*,*")]) ++ ++ ++;;; Generated by the combiner to merge an address calculation with ++;;; a byte load. We can use the 'abx' instruction here. ++(define_insn "*movqi_array_load" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=q") ++ (mem:QI (plus:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%B")) ++ (match_operand:HI 2 "immediate_operand" "i")))) ++ (clobber (match_scratch:HI 3 "=X"))] ++ "" ++ "ldx\t%2\;abx\;ld%0\t,x" ++ [(set_attr "length" "6")]) ++ ++ ++;;; Optimize the move of a byte to the stack using the pshs instruction ++;;; instead of a store with pre-increment. ++(define_insn "movqi_push" ++ [(set (match_operand:QI 0 "push_operand" "=m") ++ (match_operand:QI 1 "register_operand" " q"))] ++ "" ++ "pshs\t%1" ++ [(set_attr "length" "2")]) ++ ++ ++;;; Optimize the move of a byte from the stack using the puls instruction ++;;; instead of a store with post-decrement. ++(define_insn "movqi_pop" ++ [(set (match_operand:QI 0 "register_operand" "=q") ++ (match_operand:QI 1 "pop_operand" "m"))] ++ "" ++ "puls\t%0" ++ [(set_attr "length" "2")]) ++ ++ ++;;- load low byte of 16-bit data into 8-bit register/memory ++(define_insn "*mov_lsb" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q,q,m,!q") ++ (subreg:QI (match_operand:HI 1 "general_operand" "d,m,a,d, U") 1))] ++ "" ++ "@ ++ \t;movlsbqihi: D->B ++ ld%0\t%L1\t;movlsbqihi: msb:%1 -> R:%0 ++ tfr\t%1,d\t;movlsbqihi: R:%1 -> R:%0 ++ stb\t%0\t;movlsbqihi: R:%1 -> %0 ++ pshs\t%1\t;movlsbqihi: R:%1 -> R:%0\;leas\t1,s\;puls\t%0" ++ [(set_attr "length" "0,*,2,*,6")]) ++ ++ ++;;- load high byte of 16-bit data into 8-bit register/memory ++(define_insn "*mov_msb" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q,q,q,m,!q") ++ (subreg:QI (match_operand:HI 1 "general_operand" "d,O,a,m,d, U") 0))] ++ "" ++ "@ ++ tfr\ta,b\t;movmsbqihi: D->B ++ clr%0\t\t;movmsbqihi: ZERO -> R:%0 ++ tfr\t%1,d\t;movmsbqihi: R:%1 -> R:%0\;tfr\ta,b ++ ld%0\t%L1\t;movmsbqihi: lsb:%1 -> R:%0 ++ sta\t%0\t;movmsbqihi: R:%1 -> %0 ++ pshs\t%1\t;movmsbqihi: R:%1 -> R:%0\;puls\t%0\;leas\t1,s" ++ [(set_attr "length" "2,1,4,*,*,6")]) ++ ++ ++(define_insn "*movqi_boolean" ++ [(set (reg:QI HARD_Z_REGNUM) ++ (match_operand:QI 0 "general_operand" "q,O,i,m"))] ++ "" ++ "@ ++ tst%0 ++ andcc\t#~4 ++ orcc\t#4 ++ tst\t%0") ++ ++ ++(define_insn "movqi" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q,m,q,m,q,z") ++ (match_operand:QI 1 "general_operand" " q,O,O,mi,q,z,q"))] ++ "" ++ "@ ++ tfr\t%1,%0 ++ clr%0 ++ clr\t%0 ++ ld%0\t%1 ++ st%1\t%0 ++ tfr\tcc,%0\;and%0\t#4 ++ tst%0" ++ [(set_attr "length" "2,1,3,*,*,4,1")]) ++ ++ ++;;-------------------------------------------------------------------- ++;;- Swap registers ++;;-------------------------------------------------------------------- ++ ++; Note: 8-bit swap is never needed so it is not defined. ++ ++(define_insn "swaphi" ++ [(set (match_operand:HI 0 "register_operand" "+r") ++ (match_operand:HI 1 "register_operand" "+r")) ++ (set (match_dup 1) (match_dup 0))] ++ "" ++ "exg\t%1,%0" ++ [(set_attr "length" "2") ++ (set (attr "cycles") (const_int EXG_CYCLES))]) ++ ++ ++(define_insn "bswaphi2" ++ [(set (match_operand:HI 0 "register_operand" "=d") ++ (bswap:HI (match_operand:HI 1 "register_operand" "0")))] ++ "" ++ "exg\ta,b" ++ [(set_attr "length" "2")]) ++ ++ ++;;-------------------------------------------------------------------- ++;;- Extension and truncation insns. ++;;-------------------------------------------------------------------- ++ ++(define_insn "extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "=d") ++ (sign_extend:HI (match_operand:QI 1 "general_operand" "B")))] ++ "" ++ "sex\t\t;extendqihi2: R:%1 -> R:%0" ++ [(set_attr "length" "1")]) ++ ++ ++(define_insn "zero_extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "=d") ++ (zero_extend:HI (match_operand:QI 1 "general_operand" "B")))] ++ "" ++ "clra\t\t;zero_extendqihi: R:%1 -> R:%0" ++ [(set_attr "length" "1")]) ++ ++ ++;;-------------------------------------------------------------------- ++;;- All kinds of add instructions. ++;;-------------------------------------------------------------------- ++ ++ ++;; ++;; gcc's automatic version of addsi3 doesn't know about adcb,adca ++;; so it is MUCH less efficient. Define this one ourselves. ++;; ++;; TODO - can't always get 'd' for the clobber... allow other registers ++;; as well and use exg d,R ... exg R,d around the code sequence to ++;; use others, at a price. Also consider libcall for this when ++;; optimizing for size. ++;; ++(define_insn "addsi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=o") ++ (plus:SI (match_operand:SI 1 "general_operand" "%o") ++ (match_operand:SI 2 "general_operand" " oi"))) ++ (clobber (match_scratch:HI 3 "=d"))] ++ "" ++{ ++ m6809_output_addsi3 (PLUS, operands); ++ return ""; ++} ++ [(set_attr "length" "21")]) ++ ++ ++; Increment of a 16-bit MEM by 1 can be done without a register. ++(define_insn "*addhi_mem_1" ++ [(set (match_operand:HI 0 "memory_operand" "=m") ++ (plus:HI (match_dup 0) (const_int 1)))] ++ "GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF" ++{ ++ rtx xoperands[2]; ++ ++ xoperands[0] = operands[0]; ++ xoperands[1] = adjust_address (operands[0], QImode, 1); ++ ++ output_asm_insn ("inc\t%1", xoperands); ++ output_asm_insn ("bne\t__IL%=", xoperands); ++ output_asm_insn ("inc\t%0\;__IL%=:", xoperands); ++ return ""; ++} ++ [(set_attr "length" "7")]) ++ ++ ++; Decrement of a 16-bit MEM by 1 can be done without a register. ++(define_insn "*addhi_mem_minus1" ++ [(set (match_operand:HI 0 "memory_operand" "=m") ++ (plus:HI (match_dup 0) (const_int -1)))] ++ "GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF" ++{ ++ rtx xoperands[2]; ++ ++ xoperands[0] = operands[0]; ++ xoperands[1] = adjust_address (operands[0], QImode, 1); ++ ++ output_asm_insn ("tst\t%1", xoperands); ++ output_asm_insn ("bne\t__IL%=", xoperands); ++ output_asm_insn ("dec\t%0", xoperands); ++ output_asm_insn ("__IL%=:", xoperands); ++ output_asm_insn ("dec\t%1", xoperands); ++ return ""; ++} ++ [(set_attr "length" "7")]) ++ ++ ++; Allow the addition of an 8-bit quantity to a 16-bit quantity ++; using the LEAX B,Y addressing mode, where X and Y are both ++; index registers. This will only get generated via the peephole ++; which removes a sign extension. ++(define_insn "*addhi_b" ++ [(set (match_operand:HI 0 "index_register_operand" "=a") ++ (plus:HI(match_operand:HI 1 "index_register_operand" "%a") ++ (match_operand:QI 2 "register_operand" "q") ++ ))] ++ "" ++ "lea%0\t%2,%1\t;addhi_b: R:%0 = R:%2 + R:%1" ++ [(set_attr "length" "*")]) ++ ++ ++; Splitter for addhi pattern #5 below ++(define_split ++ [(set (match_operand:HI 0 "index_register_operand" "") ++ (plus:HI (match_dup 0) (match_operand:HI 1 "memory_operand" "")))] ++ "reload_completed" ++ [ ++ (parallel [(set (match_dup 0) (reg:HI HARD_D_REGNUM)) ++ (set (reg:HI HARD_D_REGNUM) (match_dup 0))]) ++ (set (reg:HI HARD_D_REGNUM) ++ (plus:HI (reg:HI HARD_D_REGNUM) (match_dup 1))) ++ (parallel [(set (match_dup 0) (reg:HI HARD_D_REGNUM)) ++ (set (reg:HI HARD_D_REGNUM) (match_dup 0))]) ++ ] ++{ ++}) ++ ++ ++; Splitter for addhi pattern #7 below ++(define_split ++ [(set (match_operand:HI 0 "index_register_operand" "") ++ (plus:HI (match_dup 0) (match_operand:HI 1 "index_register_operand" "")))] ++ "reload_completed" ++ [ ++ (parallel [(set (match_dup 1) (reg:HI HARD_D_REGNUM)) ++ (set (reg:HI HARD_D_REGNUM) (match_dup 1))]) ++ (set (match_dup 0) ++ (plus:HI (reg:HI HARD_D_REGNUM) (match_dup 0))) ++ (parallel [(set (match_dup 1) (reg:HI HARD_D_REGNUM)) ++ (set (reg:HI HARD_D_REGNUM) (match_dup 1))]) ++ ] ++{ ++}) ++ ++ ++; TODO - this is ugly. During RTL generation, we don't know what registers ++; are available, so the multiple-insn sequences can only be solved ++; via 'define_split's during matching. See andhi3 for an example. ++; Keep the constraints with ? modifiers to help reload pick the right ++; registers. ++; ++; The forms are: ++; 1. D += D, expand this into a shift instead. (rtx costs should be corrected ++; to avoid this even happening...) ++; 2. D += U, require U to be pushed to memory. (Lots of patterns do this ++; now, is this a better way?) ++; 3. Best choice: 'addd' ++; 4. Next best choice: 'lea' ++; 5. Hybrid of 3 and 4 ++; 6. Same as 4, not bad ++; 7. BAD, no D register at all ++; 8. 'lea', as good as 4. ++(define_insn "addhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=d, d, d, a,?a, a,???T,a") ++ (plus:HI(match_operand:HI 1 "add_general_operand" "%0, 0, 0, d, 0, a, 0, a") ++ (match_operand:HI 2 "general_operand" " 0, !U, mi, a, m, d, T, i") ++ ))] ++ "" ++ "@ ++ lslb\t\t;addhi: R:%0 += R:%2\;rola\t\t;also R:%0 *= 2 ++ pshs\t%2\t;addhi: R:%0 += R:%2\;add%0\t,s++ ++ add%0\t%2 ++ lea%0\t%1,%2 ++ # ++ lea%0\t%2,%1 ++ # ++ lea%0\t%a2,%1" ++ [(set_attr "length" "2,6,*,*,7,*,7,*")]) ++ ++ ++(define_insn "addqi3_carry" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=q") ++ (unspec:QI [ ++ (match_operand:QI 1 "whole_general_operand" "%0") ++ (match_operand:QI 2 "whole_general_operand" "tmi")] UNSPEC_ADD_CARRY))] ++ "" ++ "adc%0\t%2\t;addqi_carry: R:%0 += %2" ++ [(set_attr "length" "*")]) ++ ++ ++; TODO: specifying 'A' for the first constraint, to force into the A register ++; is not working because of the way registers are currently set up. This will ++; take some work to get right. Thus the second alternative as a backup. ++(define_insn "addqi3_decimal" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=A,?q") ++ (unspec:QI [ ++ (match_operand:QI 1 "general_operand" "%0,0") ++ (match_operand:QI 2 "general_operand" "mi,mi")] UNSPEC_ADD_DECIMAL))] ++ "" ++ "@ ++ adda\t%2\;daa ++ tfr\t%0,a\;adda\t%2\;daa\;tfr\ta,%0" ++ [(set_attr "length" "5,9")]) ++ ++ ++(define_insn "addqi3" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q,q,m,m,q") ++ (plus:QI (match_operand:QI 1 "whole_general_operand" "%0,0,0,0,0,0") ++ (match_operand:QI 2 "whole_general_operand" " 0,I,N,I,N,mi")))] ++ "" ++ "@ ++ asl%0\t\t;addqi: R:%0 = R:%0 + R:%0 ++ inc%0 ++ dec%0 ++ inc\t%0 ++ dec\t%0 ++ add%0\t%2" ++ [(set_attr "length" "1,1,1,3,3,*")]) ++ ++ ++;;-------------------------------------------------------------------- ++;;- Subtract instructions. ++;;-------------------------------------------------------------------- ++ ++(define_insn "subsi3" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=o") ++ (minus:SI (match_operand:SI 1 "general_operand" " o") ++ (match_operand:SI 2 "general_operand" " oi"))) ++ (clobber (match_scratch:HI 3 "=d"))] ++ "" ++{ ++ m6809_output_addsi3 (MINUS, operands); ++ return ""; ++} ++ [(set_attr "length" "21")]) ++ ++ ++(define_insn "subhi3" ++ [(set (match_operand:HI 0 "register_operand" "=d, d, a") ++ (minus:HI (match_operand:HI 1 "register_operand" "0, 0, 0") ++ (match_operand:HI 2 "general_operand" "mi, ?U,n")))] ++ "" ++ "@ ++ sub%0\t%2\t;subhi: R:%0 -= %2 ++ pshs\t%2\t;subhi: R:%0 -= R:%2\;sub%0\t,s++ ++ lea%0\t%n2,%1\t;subhi: R:%0 = R:%1 + %n2" ++ [(set_attr "length" "*,5,3")]) ++ ++ ++(define_insn "subqi3_carry" ++ [(set (match_operand:QI 0 "register_operand" "=q") ++ (unspec:QI [ ++ (match_operand:QI 1 "whole_general_operand" "%0") ++ (match_operand:QI 2 "whole_general_operand" "tmi")] UNSPEC_SUB_CARRY))] ++ "" ++ "sbc%0\t%2\t;subqi_carry: R:%0 += %2" ++ [(set_attr "length" "*")]) ++ ++ ++(define_insn "subqi3" ++ [(set (match_operand:QI 0 "register_operand" "=q, q, !q, q") ++ (minus:QI (match_operand:QI 1 "whole_register_operand" "0, 0, I, 0") ++ (match_operand:QI 2 "whole_general_operand" "I, mi, 0, t")))] ++ "" ++ "@ ++ dec%0 ++ sub%0\t%2 ++ dec%0\;neg%0 ++ sub%0\t%2" ++ [(set_attr "length" "1,3,2,3")]) ++ ++ ++;;-------------------------------------------------------------------- ++;;- Multiply instructions. ++;;-------------------------------------------------------------------- ++ ++; TODO - merge these two instructions, using 'extend_operator' to match ++; either signed or zero extension. Everything else is the same. ++(define_insn "mulqihi3" ++ [(set (match_operand:HI 0 "register_operand" "=d") ++ (mult:HI (sign_extend:HI (match_operand:QI 1 "general_operand" "%q")) ++ (match_operand:QI 2 "general_operand" "tmK")))] ++ "" ++ "lda\t%2\t;mulqihi3\;mul" ++ [(set_attr "length" "3")]) ++ ++ ++(define_insn "umulqihi3" ++ [(set (match_operand:HI 0 "register_operand" "=d") ++ (mult:HI (zero_extend:HI (match_operand:QI 1 "general_operand" "%q")) ++ (match_operand:QI 2 "general_operand" "tmK")))] ++ "" ++ "lda\t%2\t;umulqihi3\;mul" ++ [(set_attr "length" "3")]) ++ ++ ++; Expand a 16x16 multiplication into either a libcall or a shift. ++; If the second operand is a small constant, use the above form. ++; Otherwise, do a libcall. ++(define_expand "mulhi3" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (mult:HI (match_operand:HI 1 "general_operand" "") ++ (match_operand:HI 2 "nonmemory_operand" "")))] ++ "" ++{ ++ emit_libcall_insns (HImode, "mulhi3", operands, 2); ++ DONE; ++}) ++ ++ ++;;-------------------------------------------------------------------- ++;;- Divide instructions. ++;;-------------------------------------------------------------------- ++ ++(define_expand "divhi3" ++ [(set (match_operand:HI 0 "register_operand" "") ++ (div:HI (match_operand:HI 1 "register_operand" "") ++ (match_operand:HI 2 "register_operand" "")))] ++ "" ++{ ++ emit_libcall_insns (HImode, "divhi3", operands, 2); ++ DONE; ++}) ++ ++ ++(define_expand "divqi3" ++ [(set (match_operand:QI 0 "register_operand" "") ++ (div:QI (match_operand:QI 1 "register_operand" "") ++ (match_operand:QI 2 "register_operand" "")))] ++ "" ++{ ++ emit_libcall_insns (QImode, "divqi3", operands, 2); ++ DONE; ++}) ++ ++ ++(define_expand "udivhi3" ++ [(set (match_operand:HI 0 "register_operand" "") ++ (udiv:HI (match_operand:HI 1 "register_operand" "") ++ (match_operand:HI 2 "register_operand" "")))] ++ "" ++{ ++ emit_libcall_insns (HImode, "udivhi3", operands, 2); ++ DONE; ++}) ++ ++ ++;;-------------------------------------------------------------------- ++;;- mod ++;;-------------------------------------------------------------------- ++ ++(define_expand "modhi3" ++ [(set (match_operand:HI 0 "register_operand" "") ++ (mod:HI (match_operand:HI 1 "register_operand" "") ++ (match_operand:HI 2 "register_operand" "")))] ++ "" ++{ ++ emit_libcall_insns (HImode, "modhi3", operands, 2); ++ DONE; ++}) ++ ++ ++(define_expand "modqi3" ++ [(set (match_operand:QI 0 "register_operand" "") ++ (mod:QI (match_operand:QI 1 "register_operand" "") ++ (match_operand:QI 2 "register_operand" "")))] ++ "" ++{ ++ emit_libcall_insns (QImode, "modqi3", operands, 2); ++ DONE; ++}) ++ ++ ++(define_expand "umodhi3" ++ [(set (match_operand:HI 0 "register_operand" "") ++ (umod:HI (match_operand:HI 1 "register_operand" "") ++ (match_operand:HI 2 "register_operand" "")))] ++ "" ++{ ++ emit_libcall_insns (HImode, "umodhi3", operands, 2); ++ DONE; ++}) ++ ++ ++ ++;;-------------------------------------------------------------------- ++;;- and, or, xor common patterns ++;;-------------------------------------------------------------------- ++ ++; Split a bitwise HImode into two QImode instructions, with one of ++; the sources in a pushable register. The register is pushed onto ++; the stack and memory pop operands (,s+) are used in the QI forms. ++(define_split ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operator:HI 3 "logical_bit_operator" ++ [(match_operand:HI 1 "register_operand" "") ++ (match_operand:HI 2 "register_operand" "")]))] ++ "reload_completed" ++ [(set (mem:HI (pre_dec:HI (reg:HI HARD_S_REGNUM))) (match_dup 2)) ++ (set (reg:QI HARD_A_REGNUM) (match_op_dup:QI 3 ++ [(reg:QI HARD_A_REGNUM) ++ (mem:QI (post_inc:QI (reg:HI HARD_S_REGNUM)))])) ++ (set (reg:QI HARD_D_REGNUM) (match_op_dup:QI 3 ++ [(reg:QI HARD_D_REGNUM) ++ (mem:QI (post_inc:QI (reg:HI HARD_S_REGNUM)))])) ++ (use (reg:QI HARD_A_REGNUM))] ++{ ++}) ++ ++; Split a bitwise HImode into two QImode instructions, with one ++; of the sources being a (MEM (MEM (...)); i.e. an indirect memory ++; reference. This requires dereferencing the pointer into a ++; temporary register (X), which must be saved/restored around the ++; compute instructions. ++(define_split ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operator:HI 3 "logical_bit_operator" ++ [(match_operand:HI 1 "register_operand" "") ++ (mem:HI (match_operand:HI 2 "memory_operand" ""))]))] ++ "reload_completed" ++ [ ++ (set (mem:HI (pre_dec:HI (reg:HI HARD_S_REGNUM))) (match_dup 4)) ++ (set (match_dup 4) (match_dup 2)) ++ (set (match_dup 4) (mem:HI (match_dup 4))) ++ (set (reg:QI HARD_A_REGNUM) (match_op_dup:QI 3 ++ [(reg:QI HARD_A_REGNUM) ++ (mem:QI (post_inc:QI (match_dup 4)))])) ++ (set (reg:QI HARD_D_REGNUM) (match_op_dup:QI 3 ++ [(reg:QI HARD_D_REGNUM) ++ (mem:QI (post_inc:QI (match_dup 4)))])) ++ (use (reg:QI HARD_A_REGNUM)) ++ (set (match_dup 4) (mem:HI (post_inc:HI (reg:HI HARD_S_REGNUM)))) ++ ] ++{ ++ /* Use X for a temporary index register */ ++ operands[4] = gen_rtx_REG (HImode, HARD_X_REGNUM); ++}) ++ ++ ++; Split a bitwise HImode into two QImode instructions. This is ++; the common case. This handles splitting when neither of the ++; above two cases applies. ++(define_split ++ [(set (match_operand:HI 0 "register_operand" "") ++ (match_operator:HI 3 "logical_bit_operator" ++ [(match_operand:HI 1 "register_operand" "") ++ (match_operand:HI 2 "general_operand" "")]))] ++ "reload_completed" ++ [(set (reg:QI HARD_A_REGNUM) (match_op_dup:QI 3 ++ [(reg:QI HARD_A_REGNUM) (match_dup 4)])) ++ (set (reg:QI HARD_D_REGNUM) (match_op_dup:QI 3 ++ [(reg:QI HARD_D_REGNUM) (match_dup 5)])) ++ (use (reg:QI HARD_A_REGNUM))] ++{ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ operands[4] = gen_rtx_const_high (operands[2]); ++ operands[5] = gen_rtx_const_low (operands[2]); ++ } ++ else if ((GET_CODE (operands[2]) == MEM) ++ && (GET_CODE (XEXP (operands[2], 0)) == MEM)) ++ { ++ FAIL; ++ } ++ else ++ { ++ operands[4] = gen_highpart (QImode, operands[2]); ++ operands[5] = gen_lowpart (QImode, operands[2]); ++ } ++}) ++ ++; Below are the specific cases for each of the operators. ++; The QImode versions are the simplest and can be implemented ++; directly on the hardware. The HImode cases are all output ++; using one of the above splitting techniques. ++ ++;;-------------------------------------------------------------------- ++;;- and ++;;-------------------------------------------------------------------- ++ ++(define_insn "andhi3" ++ [(set (match_operand:HI 0 "register_operand" "=d") ++ (and:HI (match_operand:HI 1 "register_operand" "%0") ++ (match_operand:HI 2 "general_operand" "mnU")))] ++ "" ++ "#") ++ ++;; it is not clear that this is correct ++(define_insn "*andqi_2" ++ [(set ++ (match_operand:QI 0 "register_operand" "=q") ++ (and:QI (match_operand:QI 1 "register_operand" "q") ++ (match_operand 2 "const_int_operand" "i")))] ++ "" ++{ ++ if (GET_CODE (operands[2]) == CONST_INT) ++ { ++ operands[3] = GEN_INT(INTVAL(operands[2]) & 0xff); ++ return "and%0 %3"; ++ } ++ ++ return "and%0 %2"; ++} ++ [(set_attr "length" "2")]) ++ ++(define_insn "andqi3" ++ [(set (match_operand:QI 0 "register_operand" "=q,q,q,qc") ++ (and:QI (match_operand:QI 1 "whole_register_operand" "%0,0,0,0") ++ (match_operand:QI 2 "whole_general_operand" " O,N,m,i")))] ++ "" ++ "@ ++ clr%0\t;andqi(ZERO) ++ \t;andqi(-1) ++ and%0\t%2 ++ and%0\t%2" ++ [(set_attr "length" "1,0,3,2")]) ++ ++ ++;;-------------------------------------------------------------------- ++;;- or ++;;-------------------------------------------------------------------- ++ ++(define_insn "iorhi3" ++ [(set (match_operand:HI 0 "register_operand" "=d") ++ (ior:HI (match_operand:HI 1 "register_operand" "%0") ++ (match_operand:HI 2 "general_operand" "mnU")))] ++ "" ++ "#") ++ ++ ++(define_insn "iorqi3" ++ [(set (match_operand:QI 0 "register_operand" "=q,q, qc") ++ (ior:QI (match_operand:QI 1 "whole_register_operand" "%0,0, 0") ++ (match_operand:QI 2 "whole_general_operand" " O,m,i")))] ++ "" ++ "@ ++ \t;iorqi(ZERO) ++ or%0\t%2 ++ or%0\t%2" ++ [(set_attr "length" "0,3,2")]) ++ ++;;-------------------------------------------------------------------- ++;;- xor ++;;-------------------------------------------------------------------- ++ ++(define_insn "xorhi3" ++ [(set (match_operand:HI 0 "register_operand" "=d") ++ (xor:HI (match_operand:HI 1 "register_operand" "%0") ++ (match_operand:HI 2 "general_operand" "mnU")))] ++ "" ++ "#") ++ ++ ++(define_insn "xorqi3" ++ [(set (match_operand:QI 0 "register_operand" "=q,q,q,q") ++ (xor:QI (match_operand:QI 1 "whole_register_operand" "%0,0,0,0") ++ (match_operand:QI 2 "whole_general_operand" " O,N,m,i")))] ++ "" ++ "@ ++ \t;xorqi(ZERO) ++ com%0\t;xorqi(-1) ++ eor%0\t%2 ++ eor%0\t%2" ++ [(set_attr "length" "0,1,3,2")]) ++ ++;;-------------------------------------------------------------------- ++;;- Two's Complements ++;;-------------------------------------------------------------------- ++ ++(define_insn "neghi2" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,!a") ++ (neg:HI (match_operand:HI 1 "general_operand" "0, 0")))] ++ "" ++ "@ ++ nega\;negb\;sbca\t#0 ++ exg\td,%0\;nega\;negb\;sbca\t#0\;exg\td,%0" ++ [(set_attr "length" "5,9")]) ++ ++ ++(define_insn "negqi2" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m") ++ (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")))] ++ "" ++ "@ ++ neg%0 ++ neg\t%0" ++ [(set_attr "length" "1,3")]) ++ ++ ++;;-------------------------------------------------------------------- ++;;- One's Complements ++;;-------------------------------------------------------------------- ++ ++(define_insn "one_cmplhi2" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,?tm,???a") ++ (not:HI (match_operand:HI 1 "general_operand" "0, 0, 0")))] ++ "" ++ "@ ++ coma\;comb ++ com\t%0\;com\t%L0 ++ exg\td,%0\;coma\;comb\;exg\td,%0" ++ [(set_attr "length" "2,6,6")]) ++ ++ ++(define_insn "one_cmplqi2" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m") ++ (not:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")))] ++ "" ++ "@ ++ com%0 ++ com\t%0" ++ [(set_attr "length" "1,3")]) ++ ++;;-------------------------------------------------------------------- ++;;- Shifts/rotates ++;;-------------------------------------------------------------------- ++ ++(define_code_iterator bit_code [ashift ashiftrt lshiftrt]) ++(define_code_attr bit_code_name [(ashift "ashl") (ashiftrt "ashr") (lshiftrt "lshr")]) ++ ++(define_mode_iterator bit_mode [QI HI]) ++(define_mode_attr bit_mode_name [(QI "qi3") (HI "hi3")]) ++ ++;; Emit RTL for any shift (handles all 3 opcodes and 2 mode sizes) ++ ++(define_expand "<bit_code:bit_code_name><bit_mode:bit_mode_name>" ++ [(set (match_operand:bit_mode 0 "nonimmediate_operand" "") ++ (bit_code:bit_mode (match_operand:bit_mode 1 "general_operand" "") ++ (match_operand:bit_mode 2 "nonmemory_operand" "")))] ++ "" ++{ ++}) ++ ++; Individual instructions implemented in the CPU. ++ ++ ++(define_insn "*ashift1" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=m,q") ++ (ashift:QI (match_operand:QI 1 "general_operand" "0,0") (const_int 1)))] ++ "" ++ "@ ++ asl\t%0 ++ asl%0" ++ [(set_attr "length" "3,1")]) ++ ++(define_insn "*lshiftrt1" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=m,q") ++ (lshiftrt:QI (match_operand:QI 1 "general_operand" "0,0") (const_int 1)))] ++ "" ++ "@ ++ lsr\t%0 ++ lsr%0" ++ [(set_attr "length" "3,1")]) ++ ++(define_insn "*ashiftrt1" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=m,q") ++ (ashiftrt:QI (match_operand:QI 1 "general_operand" "0,0") (const_int 1)))] ++ "" ++ "@ ++ asr\t%0 ++ asr%0" ++ [(set_attr "length" "3,1")]) ++ ++(define_insn "*rotate1" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=m,q") ++ (rotate:QI (match_operand:QI 1 "general_operand" "0,0") (const_int 1)))] ++ "" ++ "@ ++ rol\t%0 ++ rol%0" ++ [(set_attr "length" "3,1")]) ++ ++ ++(define_insn "*rotatert1" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=m,q") ++ (rotatert:QI (match_operand:QI 1 "general_operand" "0,0") (const_int 1)))] ++ "" ++ "@ ++ ror\t%0 ++ ror%0" ++ [(set_attr "length" "3,1")]) ++ ++ ++; A shift by 8 for D reg can be optimized by just moving ++; between the A/B halves, and then zero/sign extending or ++; filling in zeroes. ++; Because GCC does not understand that 'A' and 'D' refer to ++; the same storage location, we must use 'USE' throughout ++; to prevent deletion of 'unnecessary' instructions. ++; Similar optimization for MEM would require a scratch register ++; so is not done here. ++ ++(define_split ++ [(set (reg:HI HARD_D_REGNUM) (ashift:HI (reg:HI HARD_D_REGNUM) (const_int 8)))] ++ "reload_completed" ++ [ ++ (use (reg:HI HARD_D_REGNUM)) ++ (set (reg:QI HARD_A_REGNUM) (reg:QI HARD_D_REGNUM)) ++ (use (reg:QI HARD_A_REGNUM)) ++ (set (reg:QI HARD_D_REGNUM) (const_int 0)) ++ ] ++ "") ++ ++(define_split ++ [(set (reg:HI HARD_D_REGNUM) (lshiftrt:HI (reg:HI HARD_D_REGNUM) (const_int 8)))] ++ "reload_completed" ++ [ ++ (use (reg:HI HARD_D_REGNUM)) ++ (set (reg:QI HARD_D_REGNUM) (reg:QI HARD_A_REGNUM)) ++ (use (reg:QI HARD_D_REGNUM)) ++ (set (reg:HI HARD_D_REGNUM) (zero_extend:HI (reg:QI HARD_D_REGNUM))) ++ ] ++ "") ++ ++(define_split ++ [(set (reg:HI HARD_D_REGNUM) (ashiftrt:HI (reg:HI HARD_D_REGNUM) (const_int 8)))] ++ "reload_completed" ++ [ ++ (use (reg:HI HARD_D_REGNUM)) ++ (set (reg:QI HARD_D_REGNUM) (reg:QI HARD_A_REGNUM)) ++ (use (reg:QI HARD_D_REGNUM)) ++ (set (reg:HI HARD_D_REGNUM) (sign_extend:HI (reg:QI HARD_D_REGNUM))) ++ ] ++ "") ++ ++ ++; On the WPC hardware, there is a shift register that can be used ++; to compute (1<<n) efficiently in two instructions. Note that this ++; form only works when using -mint8 though, because C will promote ++; to 'int' when doing this operation. TODO : we need a 16-bit form too. ++(define_insn "ashlqi3_wpc" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=q") ++ (ashift:QI (match_operand:QI 1 "immediate_operand" "I") ++ (match_operand:QI 2 "general_operand" "q")))] ++ "TARGET_WPC" ++ "st%2\t0x3FF7\;ld%0\t0x3FF7" ++ [(set_attr "length" "6")]) ++ ++ ++; Internal instructions for shifting by a constant. ++; Two forms are provided, one for QImode, one for HImode. ++; These are always split into the above instructions ++; (except for QImode forms that directly match one of the ++; above instructions, in which the condition will not ++; allow the splitter to match). ++ ++(define_insn_and_split "<bit_code:bit_code_name>hi3_const" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=dm") ++ (bit_code:HI (match_operand:HI 1 "general_operand" "0") ++ (match_operand:HI 2 "immediate_operand" "n")))] ++ "" ++ "#" ++ "reload_completed" ++ [(const_int 0)] ++{ ++ m6809_split_shift (<bit_code:CODE>, operands); ++ DONE; ++}) ++ ++ ++(define_insn_and_split "<bit_code:bit_code_name>qi3_const" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") ++ (bit_code:QI (match_operand:QI 1 "general_operand" "0") ++ (match_operand:QI 2 "immediate_operand" "n")))] ++ "INTVAL (operands[2]) > 1" ++ "#" ++ "&& reload_completed" ++ [(const_int 0)] ++{ ++ m6809_split_shift (<bit_code:CODE>, operands); ++ DONE; ++}) ++ ++; Internal instructions for shifting by a nonconstant. ++; These expand into complex assembly. ++ ++(define_insn "<bit_code:bit_code_name>hi3_reg" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=d") ++ (bit_code:HI (match_operand:HI 1 "general_operand" "0") ++ (match_operand:HI 2 "nonimmediate_operand" "v")))] ++ "" ++{ ++ m6809_output_shift_insn (<bit_code:CODE>, operands); ++ return ""; ++} ++ [(set_attr "length" "20")]) ++ ++ ++(define_insn "<bit_code:bit_code_name>qi3_reg" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=q") ++ (bit_code:QI (match_operand:QI 1 "general_operand" "0") ++ (match_operand:QI 2 "nonimmediate_operand" "v")))] ++ "" ++{ ++ m6809_output_shift_insn (<bit_code:CODE>, operands); ++ return ""; ++} ++ [(set_attr "length" "16")]) ++ ++ ++ ++;;-------------------------------------------------------------------- ++;;- Jumps and transfers ++;;-------------------------------------------------------------------- ++ ++;;; The casesi pattern is normally *not* defined; see 'tablejump' instead. ++(define_expand "casesi" ++ [(match_operand:HI 0 "register_operand" "") ; index to jump on ++ (match_operand:HI 1 "immediate_operand" "") ; lower bound ++ (match_operand:HI 2 "immediate_operand" "") ; total range ++ (match_operand 3 "" "") ; table label ++ (match_operand 4 "" "")] ; out of range label ++ "TARGET_BYTE_INT && TARGET_CASESI" ++{ ++ m6809_do_casesi (operands[0], operands[1], operands[2], ++ operands[3], operands[4]); ++ DONE; ++}) ++ ++(define_insn "tablejump_short_offset" ++ [(set (pc) ++ (mem:HI (plus:HI (match_operand:HI 1 "register_operand" "U") ++ (zero_extend:HI (match_operand:QI 0 "register_operand" "q")))))] ++ "" ++ "jmp\t[b,x]\t;tablejump_short_offset" ++ [(set_attr "length" "3")]) ++ ++(define_insn "tablejump_long_offset" ++ [(set (pc) ++ (mem:HI (plus:HI (match_operand:HI 1 "register_operand" "U") ++ (match_operand:HI 0 "register_operand" "d"))))] ++ "" ++ "jmp\t[d,x]\t;tablejump_long_offset" ++ [(set_attr "length" "3")]) ++ ++ ++ ;; A tablejump operation gives the address in operand 0, with the ++ ;; CODE_LABEL for the table in operand 1. The 'define_expand' ++ ;; shows the arguments as GCC presents them. For a register ++ ;; operand, the assembly code is straightforward. For a MEM, ++ ;; assumed to be a SYMBOL_REF, two forms are given, one normal ++ ;; and one for PIC mode. ++ (define_expand "tablejump" ++ [(parallel [ ++ (set (pc) (match_operand:HI 0 "" "")) ++ (use (label_ref (match_operand 1 "" ""))) ++ (clobber (match_scratch:HI 2 "")) ++ ])] ++ "" ++ { ++ }) ++ ++ ++(define_insn "*tablejump_reg" ++ [(parallel [ ++ (set (pc) ++ (match_operand:HI 0 "register_operand" "a")) ++ (use (label_ref (match_operand 1 "" ""))) ++ (clobber (match_scratch:HI 2 "")) ++ ])] ++ "" ++ "jmp\t,%0" ++ [(set_attr "length" "3")]) ++ ++ ++(define_insn "*tablejump_symbol" ++ [(parallel [ ++ (set (pc) ++ (mem:HI ++ (plus:HI (match_operand:HI 0 "register_operand" "a") ++ (label_ref (match_operand 1 "" ""))))) ++ (use (label_ref (match_dup 1))) ++ (clobber (match_scratch:HI 2 "")) ++ ])] ++ "!flag_pic" ++{ ++ output_asm_insn ("jmp\t[%a1,%0]", operands); ++ return ""; ++} ++ [(set_attr "length" "4")]) ++ ++ ++(define_insn "*tablejump_symbol_pic" ++ [(parallel [ ++ (set (pc) ++ (mem:HI ++ (plus:HI (match_operand:HI 0 "register_operand" "d") ++ (label_ref (match_operand 1 "" ""))))) ++ (use (label_ref (match_dup 1))) ++ (clobber (match_scratch:HI 2 "=&a")) ++ ])] ++ "flag_pic" ++{ ++ output_asm_insn ("lea%2\t%a1,pcr", operands); ++ output_asm_insn ("ld%0\t%0,%2", operands); ++ output_asm_insn ("jmp\t%0,%2", operands); ++ return ""; ++} ++ [(set_attr "length" "8")]) ++ ++ ++(define_insn "indirect_jump" ++ [(set (pc) ++ (match_operand:HI 0 "register_operand" "a"))] ++ "" ++ "jmp\t,%0" ++ [(set_attr "length" "3")]) ++ ++ ++(define_insn "jump" ++ [(set (pc) (label_ref (match_operand 0 "" "")))] ++ "" ++{ ++ return output_branch_insn ( LABEL_REF, operands, get_attr_length (insn)); ++} ++ [(set (attr "type") (const_string "branch"))]) ++ ++; Output assembly for a condition branch instruction. ++(define_insn "*cond_branch" ++ [(set (pc) ++ (if_then_else ++ (match_operator 1 "comparison_operator" [(cc0) (const_int 0)]) ++ (label_ref (match_operand 0 "" "")) (pc)))] ++ "" ++{ ++ return output_branch_insn ( GET_CODE(operands[1]), ++ operands, get_attr_length (insn)); ++} ++ [(set (attr "type") (const_string "cbranch"))]) ++ ++ ++; Similar to above, but for a condition branch instruction that ++; had its operands reversed at some point. ++(define_insn "*cond_branch_reverse" ++ [(set (pc) ++ (if_then_else ++ (match_operator 1 "comparison_operator" [(cc0) (const_int 0)]) ++ (pc) (label_ref (match_operand 0 "" ""))))] ++ "" ++{ ++ return output_branch_insn ( reverse_condition (GET_CODE(operands[1])), ++ operands, get_attr_length (insn)); ++} ++ [(set (attr "type") (const_string "cbranch"))]) ++ ++ ++ ++;;-------------------------------------------------------------------- ++;;- Calls ++;;-------------------------------------------------------------------- ++ ++;; Generate a call instruction for a function that does not ++;; return a value. The expander is used during RTL generation. ++;; The instructions below are used during matching; only one ++;; of them will be used, depending on the type of function ++;; being called. The different conditions are: ++;; ++;; 1) far_functionp - is this a far function? Those need ++;; to be output as indirect calls through a far-function ++;; handler. ++;; ++;; 2) noreturn_functionp - if the function does not return, ++;; we can use a 'jmp' instead of a 'jsr' to call it. ++;; ++;; 3) is PIC mode enabled? If so, we'll always use ++;; relative calls (lbsr or lbra). ++;; ++;; Note: not all combinations are fully supported, especially ++;; relating to PIC. ++;; ++;; The 'bsr' instruction is never generated. ++ ++(define_expand "call" ++ [(call (match_operand:HI 0 "memory_operand" "") ++ (match_operand:HI 1 "general_operand" ""))] ++ "" ++ "") ++ ++(define_insn "*call_nopic_far" ++ [(call (match_operand:HI 0 "memory_operand" "m") ++ (match_operand:HI 1 "general_operand" "g"))] ++ "far_functionp (operands[0])" ++{ ++ output_far_call_insn (operands, 0); ++ return ""; ++} ++ [(set_attr "length" "6")]) ++ ++ ++; PIC forms come first, and should only match ++; (MEM (SYMBOL_REF)). Other MEM forms are treated as usual. ++(define_insn "*call_pic" ++ [(call (mem:HI (match_operand:HI 0 "symbolic_operand" "")) ++ (match_operand:HI 1 "general_operand" "g"))] ++ "flag_pic && !noreturn_functionp (operands[0])" ++ "lbsr\t%C0" ++ [(set_attr "length" "4")]) ++ ++ ++(define_insn "*call_nopic" ++ [(call (match_operand:HI 0 "memory_operand" "m") ++ (match_operand:HI 1 "general_operand" "g"))] ++ "!noreturn_functionp (operands[0])" ++ "jsr\t%0" ++ [(set_attr "length" "3") ++ (set (attr "cycles") (const_int JSR_EXTENDED_CYCLES))]) ++ ++ ++(define_insn "*call_noreturn_pic" ++ [(call (mem:HI (match_operand:HI 0 "symbolic_operand" "")) ++ (match_operand:HI 1 "general_operand" "g"))] ++ "flag_pic && noreturn_functionp (operands[0])" ++ "lbra\t%C0" ++ [(set_attr "length" "4")]) ++ ++ ++(define_insn "*call_noreturn_nopic" ++ [(call (match_operand:HI 0 "memory_operand" "m") ++ (match_operand:HI 1 "general_operand" "g"))] ++ "noreturn_functionp (operands[0])" ++ "jmp\t%0" ++ [(set_attr "length" "3")]) ++ ++ ++;; ++;; Same as above, but for functions that do return a value. ++;; ++(define_expand "call_value" ++ [(set (match_operand 0 "" "") ++ (call (match_operand:HI 1 "memory_operand" "") ++ (match_operand:HI 2 "general_operand" "")))] ++ "" ++ "") ++ ++ ++(define_insn "*call_value_far" ++ [(set (match_operand 0 "" "=gz") ++ (call (match_operand:HI 1 "memory_operand" "m") ++ (match_operand:HI 2 "general_operand" "g")))] ++ "far_functionp (operands[1])" ++{ ++ output_far_call_insn (operands, 1); ++ return ""; ++} ++ [(set_attr "length" "6")]) ++ ++ ++(define_insn "*call_value_pic" ++ [(set (match_operand 0 "" "=gz") ++ (call (mem:HI (match_operand:HI 1 "symbolic_operand" "")) ++ (match_operand:HI 2 "general_operand" "g")))] ++ "flag_pic" ++ "lbsr\t%C1" ++ [(set_attr "length" "4")]) ++ ++ ++(define_insn "*call_value_nopic" ++ [(set (match_operand 0 "" "=gz") ++ (call (match_operand:HI 1 "memory_operand" "m") ++ (match_operand:HI 2 "general_operand" "g")))] ++ "" ++ "jsr\t%1" ++ [(set_attr "length" "3") ++ (set (attr "cycles") (const_int JSR_EXTENDED_CYCLES))]) ++ ++ ++ ++;; ++;; How to generate an untyped call. ++;; ++(define_expand "untyped_call" ++ [(parallel [(call (match_operand 0 "" "") ++ (const_int 0)) ++ (match_operand 1 "" "") ++ (match_operand 2 "" "")])] ++ "" ++{ ++ int i; ++ ++ emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx)); ++ for (i=0; i < XVECLEN (operands[2], 0); i++) ++ { ++ rtx set = XVECEXP (operands[2], 0, i); ++ emit_move_insn (SET_DEST (set), SET_SRC (set)); ++ } ++ emit_insn (gen_blockage ()); ++ DONE; ++}) ++ ++ ++(define_expand "sibcall" ++ [(parallel ++ [(call (match_operand:HI 0 "memory_operand" "") ++ (match_operand:HI 1 "immediate_operand" "")) ++ (use (reg:HI HARD_PC_REGNUM))])] ++ "" ++ "") ++ ++(define_insn "*sibcall_1" ++ [(parallel ++ [(call (match_operand:HI 0 "memory_operand" "m") ++ (match_operand:HI 1 "immediate_operand" "i")) ++ (use (reg:HI HARD_PC_REGNUM))])] ++ "SIBLING_CALL_P(insn)" ++ "jmp\t%0" ++ [(set_attr "length" "4")]) ++ ++ ++(define_expand "sibcall_value" ++ [(parallel ++ [(set (match_operand 0 "" "") ++ (call (match_operand:HI 1 "memory_operand" "") ++ (match_operand:HI 2 "immediate_operand" ""))) ++ (use (reg:HI HARD_PC_REGNUM))])] ++ "" ++ "") ++ ++(define_insn "*sibcall_value_1" ++ [(parallel ++ [(set (match_operand 0 "" "=gz") ++ (call (match_operand:HI 1 "memory_operand" "m") ++ (match_operand:HI 2 "immediate_operand" "i"))) ++ (use (reg:HI HARD_PC_REGNUM))])] ++ "SIBLING_CALL_P(insn)" ++ "jmp\t%1" ++ [(set_attr "length" "4")]) ++ ++ ++;;-------------------------------------------------------------------- ++;;- Function Entry and Exit ++;;-------------------------------------------------------------------- ++ ++;; On entry to a function, the stack frame looks as follows: ++;; - return address (pushed by the caller) ++;; - saved registers ++;; - local variable storage ++;; ++;; If the function does not modify the stack after that, then ++;; any of these can be accessed directly as an offset from ++;; STACK_POINTER_REGNUM. Otherwise, a frame pointer is required. ++;; In that case, the prologue must also initialize HARD_FRAME_POINTER_REGNUM ++;; and all references to the stack frame will use that as a base instead. ++;; ++(define_expand "prologue" ++ [(const_int 0)] ++ "prologue_epilogue_required ()" ++{ ++ emit_prologue_insns (); ++ DONE; ++}) ++ ++ ++;; The function epilogue does exactly the reverse of the prologue, ++;; deallocating local variable space, restoring saved registers, ++;; and returning. ++;; ++;; For the 6809, the return may be 'rti' if the function was ++;; declared as an interrupt function, but is normally 'rts'. ++;; ++;; Also, as an optimization, the register restore and the 'rts' ++;; can be combined into a single instruction, by adding 'PC' to the ++;; list of registers to be restored. This is only done if there are ++;; any saved registers, as 'rts' is more efficient by itself. ++;; ++(define_expand "epilogue" ++ [(const_int 0)] ++ "prologue_epilogue_required ()" ++{ ++ emit_epilogue_insns (false); ++ DONE; ++}) ++ ++ ++(define_expand "sibcall_epilogue" ++ [(const_int 0)] ++ "prologue_epilogue_required ()" ++{ ++ emit_epilogue_insns (true); ++ DONE; ++}) ++ ++ ++;; The RTS instruction ++(define_insn "return_rts" ++ [(return) ++ (use (reg:HI HARD_PC_REGNUM))] ++ "!m6809_current_function_has_type_attr_p (\"interrupt\") ++ && m6809_get_live_regs () == 0" ++ "rts" ++ [(set_attr "length" "1") ++ (set (attr "cycles") (const_int RTS_CYCLES))]) ++ ++(define_insn "return_puls_pc" ++ [(return) ++ (use (reg:HI HARD_PC_REGNUM))] ++ "!m6809_current_function_has_type_attr_p (\"interrupt\") ++ && m6809_get_live_regs () != 0" ++ "" ++ [(set_attr "length" "1") ++ (set (attr "cycles") (const_int RTS_CYCLES))]) ++ ++;; The RTI instruction ++(define_insn "return_rti" ++ [(return) ++ (use (reg:HI HARD_PC_REGNUM))] ++ "m6809_current_function_has_type_attr_p (\"interrupt\")" ++ "rti" ++ [(set_attr "length" "1") ++ (set (attr "cycles") (const_int RTI_CYCLES))]) ++ ++ ++;;-------------------------------------------------------------------- ++;;- Unspecified instructions ++;;-------------------------------------------------------------------- ++ ++;; An instruction that has the effect of an unspec_volatile, but ++;; which doesn't require emitting any assembly code. ++(define_insn "blockage" ++ [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] ++ "" ++ "" ++ [(set_attr "length" "0") ++ (set (attr "cycles") (const_int 0))]) ++ ++ ++;; Say how to push multiple registers onto the stack, using ++;; the 6809 'pshs' instruction. The operand is a regset ++;; specifying which registers to push. ++;; ++;; The operand mode is not given intentionally, so as to allow ++;; any possible integer mode for the regset. ++;; ++;; See below for a peephole that can combine consecutive push ++;; instructions that qualify for merging. ++(define_insn "register_push" ++ [(use (reg:HI HARD_S_REGNUM)) ++ (unspec_volatile ++ [(match_operand 0 "immediate_operand" "")] UNSPEC_PUSH_RS) ++ (clobber (reg:HI HARD_S_REGNUM))] ++ "" ++ "pshs\t%R0" ++ [(set_attr "length" "2") ++ (set (attr "cycles") (const_int PSH_PUL_CYCLES))]) ++ ++ ++;; Say how to pop multiple registers from the stack, using ++;; the 6809 'puls' instruction. The operand is the register ++;; bitset value. ++(define_insn "register_pop" ++ [(use (reg:HI HARD_S_REGNUM)) ++ (unspec_volatile ++ [(match_operand 0 "immediate_operand" "")] UNSPEC_POP_RS) ++ (clobber (reg:HI HARD_S_REGNUM))] ++ "" ++ "puls\t%R0" ++ [(set_attr "length" "2") ++ (set (attr "cycles") (const_int PSH_PUL_CYCLES))]) ++ ++ ++(define_insn "m6809_swi" ++ [(unspec_volatile ++ [(match_operand:QI 0 "immediate_operand" "I,n")] UNSPEC_SWI)] ++ "" ++ "@ ++ swi ++ swi%c0" ++ [(set_attr "length" "1,2") ++ (set (attr "cycles") (const_int SWI_CYCLES))]) ++ ++ ++;; Generate the CWAI instruction ++(define_insn "m6809_cwai" ++ [(unspec_volatile ++ [(match_operand:QI 0 "immediate_operand" "")] UNSPEC_CWAI)] ++ "" ++ "cwai\t%0" ++ [(set_attr "length" "2") ++ (set (attr "cycles") (const_int CWAI_CYCLES))]) ++ ++ ++;; Generate the SYNC instruction ++(define_insn "m6809_sync" ++ [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)] ++ "" ++ "sync" ++ [(set_attr "length" "1") ++ (set (attr "cycles") (const_int SYNC_CYCLES))]) ++ ++ ++;; Generate the NOP instruction ++(define_insn "nop" ++ [(const_int 0)] ++ "" ++ "nop" ++ [(set_attr "length" "1") ++ (set (attr "cycles") (const_int NOP_CYCLES))]) ++ ++ ++;;-------------------------------------------------------------------- ++;;- Peepholes ++;;-------------------------------------------------------------------- ++ ++;;; Each peephole has an ID that is used for debugging. ++;;; Each peephole condition is bracketed by calls to ++;;; m6809_match_peephole2() also for debugging. ++(define_constants [ ++ (PEEP_END 0) ++ (PEEP_COND 1) ++ ++ (PEEP_STACK_STORE_INC 0) ++ (PEEP_STACK_CLEAR_INC 1) ++ (PEEP_LSRB_ADCB 2) ++ (PEEP_ABX 3) ++ (PEEP_ABX2 4) ++ (PEEP_INDEXED_INC 5) ++ (PEEP_MEM_DEC 6) ++ (PEEP_MEM_INC 7) ++ (PEEP_MEM_DEC_CMP 8) ++ (PEEP_PUSH2 9) ++ (PEEP_STORE_IMPLIES_CC 10) ++ (PEEP_DEC_IMPLIES_CC 11) ++ (PEEP_LEAB 12) ++ (PEEP_LDX_INDIRECT 13) ++ (PEEP_POP_JUNK 14) ++]) ++ ++ ++;;; Optimize 'leas -1,s' followed by 'stb ,s'. This can happen if the ++;;; function prologue needs to allocate stack space and 'b' is placed ++;;; into that local right away. Combine the stack allocation with the ++;;; store using preincrement mode. ++(define_peephole2 ++ [(set (reg:HI HARD_S_REGNUM) ++ (plus:HI (reg:HI HARD_S_REGNUM) (const_int -1))) ++ (set (mem:QI (reg:HI HARD_S_REGNUM)) ++ (match_operand:QI 0 "register_operand" ""))] ++ "m6809_match_peephole2 (PEEP_STACK_STORE_INC, PEEP_END)" ++ [(set (mem:QI (pre_dec:HI (reg:HI HARD_S_REGNUM))) (match_dup 0))] ++ "") ++ ++ ++;;; Same as above, but for a 'clr ,s' that follows the prologue. ++(define_peephole2 ++ [(set (reg:HI HARD_S_REGNUM) (plus:HI (reg:HI HARD_S_REGNUM) (const_int -1))) ++ (set (mem:QI (reg:HI HARD_S_REGNUM)) (const_int 0))] ++ "m6809_match_peephole2 (PEEP_STACK_CLEAR_INC, PEEP_END)" ++ [(set (mem:QI (pre_dec:HI (reg:HI HARD_S_REGNUM))) (const_int 0))] ++ "") ++ ++ ++;;; Merge two consecutive push instructions into a single register_push. ++(define_peephole2 ++ [(set (match_operand 0 "push_operand" "") ++ (match_operand 1 "register_operand" "")) ++ (set (match_operand 2 "push_operand" "") ++ (match_operand 3 "register_operand" ""))] ++ "m6809_match_peephole2 (PEEP_PUSH2, PEEP_COND) ++ && reload_completed ++ && GET_MODE (operands[1]) == GET_MODE (operands[3]) ++ && m6809_can_merge_pushpop_p (UNSPEC_PUSH_RS, 1 << REGNO (operands[1]), 1 << REGNO (operands[3])) ++ && m6809_match_peephole2 (PEEP_PUSH2, PEEP_END)" ++ [(parallel [ ++ (use (reg:HI HARD_S_REGNUM)) ++ (unspec_volatile [(match_dup 4)] UNSPEC_PUSH_RS) ++ (clobber (reg:HI HARD_S_REGNUM))]) ++ (use (match_dup 1)) ++ (use (match_dup 3))] ++{ ++ operands[4] = gen_rtx_CONST_INT (QImode, ++ (1 << REGNO (operands[1])) | (1 << REGNO (operands[3]))); ++}) ++ ++ ++;;; Convert 'stX ,--s' into a push instruction. Use the regset ++;;; notation, so that it may be combined with an adjacent regset. ++;;; TBD - this doesn't compile some code cleanly. ++;(define_peephole2 ++; [(set (mem:HI (pre_dec:HI (reg:HI HARD_S_REGNUM))) ++; (reg:HI HARD_X_REGNUM))] ++; "reload_completed" ++; [(parallel [ ++; (use (reg:HI HARD_S_REGNUM)) ++; (unspec_volatile [(match_dup 0)] UNSPEC_PUSH_RS) ++; (clobber (reg:HI HARD_S_REGNUM))])] ++;{ ++; operands[0] = gen_rtx_CONST_INT (HImode, X_REGBIT); ++;}) ++ ++ ++;;; ++;;; q = (q+1)/2 can be optimized as "lsrb; adcb". This also ++;;; won't overflow when q=0xFF. ++;;; TODO : this form isn't accounting for promotion when ++;;; using 16-bit ints. ++;;; ++(define_peephole ++ [(set (reg:QI HARD_D_REGNUM) ++ (lshiftrt:QI (plus:HI (match_dup 0) (const_int 1)) (const_int 1)))] ++ "m6809_match_peephole2 (PEEP_LSRB_ADCB, PEEP_END)" ++ "lsrb\;adcb\t#0; peephole" ++ [(set_attr "length" "2")]) ++ ++ ++;; ++;; Optimize the case of following a register store with a test ++;; of reg or mem just moved. ++;; ++(define_peephole ++ [(set (match_operand:HI 0 "memory_operand" "=m") ++ (match_operand:HI 1 "register_operand" "r")) ++ (set (cc0) (match_operand:HI 2 "general_operand" "g"))] ++ "m6809_match_peephole2 (PEEP_STORE_IMPLIES_CC, PEEP_COND) ++ && (operands[2] == operands[0] || operands[2] == operands[1]) ++ && m6809_match_peephole2 (PEEP_STORE_IMPLIES_CC, PEEP_END)" ++ "st%1\t%0\t;movhi: R:%1 -> %0 w/ implied test of %2" ++ [(set_attr "length" "4")]) ++ ++ ++;; Optimize a pair of SET instructions in which the second insn ++;; is the reverse of the first one. I.e. ++;; ++;; A = B ++;; ----> A = B ++;; B = A ++;; ++;; The second insn is redundant. Define two patterns, one for QI, one for HI. ++;; But don't do this if either is a VOLATILE MEM. ++(define_peephole2 ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (match_operand:HI 1 "nonimmediate_operand" "")) ++ (set (match_dup 1) (match_dup 0))] ++ "!MEM_P (operands[0]) || !MEM_P (operands[1]) || (!MEM_VOLATILE_P (operands[0]) && !MEM_VOLATILE_P (operands[1]))" ++ [(set (match_dup 0) (match_dup 1))] ++ "") ++ ++(define_peephole2 ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (match_operand:QI 1 "nonimmediate_operand" "")) ++ (set (match_dup 1) (match_dup 0))] ++ "!MEM_P (operands[0]) || !MEM_P (operands[1]) || (!MEM_VOLATILE_P (operands[0]) && !MEM_VOLATILE_P (operands[1]))" ++ [(set (match_dup 0) (match_dup 1))] ++ "") ++ ++ ++;; ++;; Optimize the sum of an 8-bit and 16-bit using the 'abx' instruction ++;; if B and X can be used. Two patterns are provided to catch both ++;; X=X+D and X=D+X. ++;; ++(define_peephole ++ [(set (reg:HI HARD_D_REGNUM) ++ (zero_extend:HI (match_operand:QI 0 "general_operand" "q"))) ++ (set (reg:HI HARD_X_REGNUM) ++ (plus:HI (reg:HI HARD_D_REGNUM) (reg:HI HARD_X_REGNUM)))] ++ "m6809_match_peephole2 (PEEP_ABX, PEEP_END)" ++ "abx" ++ [(set_attr "length" "1")]) ++ ++(define_peephole ++ [(set (reg:HI HARD_D_REGNUM) ++ (zero_extend:HI (match_operand:QI 0 "general_operand" "q"))) ++ (set (reg:HI HARD_X_REGNUM) ++ (plus:HI (reg:HI HARD_X_REGNUM) (reg:HI HARD_D_REGNUM)))] ++ "m6809_match_peephole2 (PEEP_ABX, PEEP_END)" ++ "abx" ++ [(set_attr "length" "1")]) ++ ++;;; Likewise, handle when B is scaled by 2 prior to the add. ++;;; Instead of shifting B in 4 cycles, just do the ABX a second ++;;; time, in only 3 cycles. ++ ++(define_peephole ++ [(set (reg:HI HARD_D_REGNUM) ++ (zero_extend:HI (match_operand:QI 0 "general_operand" "q"))) ++ (set (reg:HI HARD_D_REGNUM) ++ (ashift:HI (reg:HI HARD_D_REGNUM) (const_int 1))) ++ (set (reg:HI HARD_X_REGNUM) ++ (plus:HI (reg:HI HARD_D_REGNUM) (reg:HI HARD_X_REGNUM)))] ++ "m6809_match_peephole2 (PEEP_ABX2, PEEP_END)" ++ "abx\;abx" ++ [(set_attr "length" "2")]) ++ ++(define_peephole ++ [(set (reg:HI HARD_D_REGNUM) ++ (zero_extend:HI (match_operand:QI 0 "general_operand" "q"))) ++ (set (reg:HI HARD_D_REGNUM) ++ (ashift:HI (reg:HI HARD_D_REGNUM) (const_int 1))) ++ (set (reg:HI HARD_X_REGNUM) ++ (plus:HI (reg:HI HARD_X_REGNUM) (reg:HI HARD_D_REGNUM)))] ++ "m6809_match_peephole2 (PEEP_ABX2, PEEP_END)" ++ "abx\;abx" ++ [(set_attr "length" "2")]) ++ ++ ++;; ++;; Work around a compiler bug that generates bad code when copying ++;; between 32-bit memory addresses after a libcall. The problem seen is ++;; that the source is MEM (REG X), but X is used as the reload register. ++;; The second half of the copy therefore fails. ++;; ++;; The solution is to switch the reload register to D, since that is guaranteed ++;; not to be in use right after a libcall. ++;; ++(define_peephole2 ++ [(set (reg:HI HARD_X_REGNUM) (mem:HI (reg:HI HARD_X_REGNUM))) ++ (set (match_operand:HI 0 "nonimmediate_operand" "") (reg:HI HARD_X_REGNUM)) ++ (set (reg:HI HARD_X_REGNUM) ++ (mem:HI (plus:HI (reg:HI HARD_X_REGNUM) (const_int 2)))) ++ (set (match_operand:HI 1 "nonimmediate_operand" "") (reg:HI HARD_X_REGNUM))] ++ "reload_completed" ++ [(set (reg:HI HARD_D_REGNUM) (mem:HI (reg:HI HARD_X_REGNUM))) ++ (set (match_dup 0) (reg:HI HARD_D_REGNUM)) ++ (set (reg:HI HARD_X_REGNUM) ++ (mem:HI (plus:HI (reg:HI HARD_X_REGNUM) (const_int 2)))) ++ (set (match_dup 1) (reg:HI HARD_X_REGNUM))] ++ "") ++ ++ ++;; Turn "and then test" into a "bit test" operation. ++;; Provide variants for immediate and memory sources ++;; This is the most used peephople. ++; (define_peephole ++; [(set (match_operand:QI 0 "register_operand" "=q") ++; (and:QI (match_operand:QI 1 "register_operand" "0") ++; (match_operand:QI 2 "immediate_operand" "i"))) ++; (set (cc0) (match_dup 0))] ++; "" ++; "bit%0\t%2" ++; [(set_attr "length" "3")]) ++; ++; (define_peephole ++; [(set (match_operand:QI 0 "register_operand" "=q") ++; (and:QI (match_operand:QI 1 "register_operand" "0") ++; (match_operand:QI 2 "memory_operand" "m"))) ++; (set (cc0) (match_dup 0))] ++; "" ++; "bit%0\t%2" ++; [(set_attr "length" "4")]) ++ ++ ++;; Turn a "decrement, then test" sequence into just a "decrement". ++;; The test can be omitted, since it is implicitly done. ++(define_peephole2 ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (plus:QI (match_operand:QI 1 "whole_general_operand" "") ++ (match_operand:QI 2 "immediate_operand" ""))) ++ (set (cc0) (match_dup 0))] ++ "m6809_match_peephole2 (PEEP_DEC_IMPLIES_CC, PEEP_END)" ++ [(set (match_dup 0) (plus:QI (match_dup 1) (match_dup 2)))] ++ "") ++ ++ ++;; Merge an indexed register increment with a previous usage. ++;; This is usually done automatically, but not always ++;; The 'use' should be optional; in all cases where this has been ++;; seen, it is required though. ++(define_peephole2 ++ [(set (match_operand:QI 0 "register_operand" "") ++ (mem:QI (match_operand:HI 1 "index_register_operand" ""))) ++ (use (match_dup 0)) ++ (set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))] ++ "m6809_match_peephole2 (PEEP_INDEXED_INC, PEEP_END)" ++ [(set (match_dup 0) (mem:QI (post_inc:HI (match_dup 1)))) ++ (use (match_dup 0))] ++ "") ++ ++ ++;;; Merge "ldX MEM; ldX ,X" into a single instruction using ++;;; the indirect mode. ++(define_peephole2 ++ [(set (reg:HI HARD_X_REGNUM) ++ (mem:HI (match_operand:HI 0 "general_operand" ""))) ++ (set (reg:HI HARD_X_REGNUM) (mem:HI (reg:HI HARD_X_REGNUM)))] ++ "reload_completed && m6809_match_peephole2 (PEEP_LDX_INDIRECT, PEEP_END)" ++ [(set (reg:HI HARD_X_REGNUM) ++ (mem:HI (mem:HI (match_dup 0))))] ++ "") ++ ++ ++;;; Reorder a store followed by a unary operation on that memory ++;;; so that the unary is performed and then the store. Consider ++;;; a binary shift operation, which will be decomposed into ++;;; identical single shifts, also. ++;;; TODO - recognize more than just 'ashift' here. ++(define_peephole2 ++ [(set (match_operand:QI 0 "memory_operand" "") ++ (match_operand:QI 1 "register_operand" "")) ++ (set (match_dup 0) ++ (ashift:QI (match_dup 0) (match_operand:QI 2 "immediate_operand")))] ++ "reload_completed" ++ [(set (match_dup 1) ++ (ashift:QI (match_dup 1) (match_operand:QI 2 "immediate_operand"))) ++ (set (match_dup 0) (match_dup 1))] ++ "") ++ ++;;; Likewise, reorder a unary MEM followed by a load, so that the load ++;;; is done first, then use the REG instead of the MEM. ++;;;(define_peephole2 ++;;; [(set (match_dup 0) ++;;; (ashift:QI (match_dup 0) (match_operand:QI 2 "immediate_operand"))) ++;;; (set (match_operand:QI 0 "register_operand" "") ++;;; (match_operand:QI 1 "memory_operand" ""))] ++;;; "reload_completed" ++;;; [(set (match_dup 0) (match_dup 1)) ++;;; (set (match_dup 0) ++;;; (ashift:QI (match_dup 0) (match_operand:QI 2 "immediate_operand")))] ++;;; "") ++ ++ ++;;; Replace sex; leaX d,Y with leaX b,Y. ++;;; ++(define_peephole2 ++ [(set (reg:HI HARD_D_REGNUM) (sign_extend:HI (reg:QI HARD_D_REGNUM))) ++ (set (match_operand:HI 0 "index_register_operand" "") ++ (plus:HI (match_operand:HI 1 "index_register_operand" "") ++ (reg:HI HARD_D_REGNUM)))] ++ "reload_completed && m6809_match_peephole2 (PEEP_LEAB, PEEP_END)" ++ [(set (match_dup 0) ++ (plus:HI (match_dup 1) (reg:QI HARD_D_REGNUM)))] ++ "") ++ ++(define_peephole2 ++ [(set (reg:HI HARD_D_REGNUM) (sign_extend:HI (reg:QI HARD_D_REGNUM))) ++ (set (match_operand:HI 0 "index_register_operand" "") ++ (plus:HI (reg:HI HARD_D_REGNUM) ++ (match_operand:HI 1 "index_register_operand" "")))] ++ "reload_completed && m6809_match_peephole2 (PEEP_LEAB, PEEP_END)" ++ [(set (match_dup 0) ++ (plus:HI (match_dup 1) (reg:QI HARD_D_REGNUM)))] ++ "") ++ ++ ++;;; Replace ldb; decb; stb; tstb with dec(mem). If the ++;;; register is not needed, then the load will get deleted ++;;; automatically, but it may be needed for comparisons. ++;;; Same for incb/inc. ++(define_peephole2 ++ [(set (match_operand:QI 0 "register_operand" "") ++ (match_operand:QI 1 "nonimmediate_operand" "")) ++ (set (match_dup 0) (plus:QI (match_dup 0) (const_int -1))) ++ (set (match_dup 1) (match_dup 0)) ++ (set (cc0) (match_dup 0))] ++ "m6809_match_peephole2 (PEEP_MEM_DEC_CMP, PEEP_END)" ++ [(set (match_dup 1) (plus:QI (match_dup 1) (const_int -1)))] ++ "") ++ ++ ++;;; Replace ldb; decb; stb with dec(mem); ldb. If the ++;;; register is not needed, then the load will get deleted ++;;; automatically, but it may be needed for comparisons. ++;;; Same for incb/inc. ++(define_peephole2 ++ [(set (match_operand:QI 0 "register_operand" "") ++ (match_operand:QI 1 "nonimmediate_operand" "")) ++ (set (match_dup 0) (plus:QI (match_dup 0) (const_int -1))) ++ (set (match_dup 1) (match_dup 0))] ++ "m6809_match_peephole2 (PEEP_MEM_DEC, PEEP_END)" ++ [(set (match_dup 1) (plus:QI (match_dup 1) (const_int -1))) ++ (set (match_dup 0) (match_dup 1))] ++ "") ++ ++(define_peephole2 ++ [(set (match_operand:QI 0 "register_operand" "") ++ (match_operand:QI 1 "nonimmediate_operand" "")) ++ (set (match_dup 0) (plus:QI (match_dup 0) (const_int 1))) ++ (set (match_dup 1) (match_dup 0))] ++ "m6809_match_peephole2 (PEEP_MEM_INC, PEEP_END)" ++ [(set (match_dup 1) (plus:QI (match_dup 1) (const_int 1))) ++ (set (match_dup 0) (match_dup 1))] ++ "") ++ ++ ++;;; Replace "andb #N; cmpb #N; bhi" with "andb #N", if it can be proven ++;;; that the branch can never occur because of the limited range of B. ++;;; N must be a power of two for this to make sense. This helps with ++;;; the default cases of switch statements on a value (x & N). ++(define_peephole2 ++ [(set (match_operand:QI 0 "register_operand" "") ++ (and:QI (match_dup 0) (match_operand:QI 1 "immediate_operand" ""))) ++ (set (cc0) ++ (compare (match_dup 0) (match_dup 1))) ++ (set (pc) (if_then_else (gtu (cc0) (const_int 0)) (match_operand 2 "" "") (match_operand 3 "" ""))) ++ ] ++ "reload_completed && power_of_two_p (INTVAL (operands[1]) + 1)" ++ [(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))] ++ "") ++ ++;;; Replace ldd <mem>; addd #1; std <mem> with 16-bit increment ++;;; of the mem, but only if D is dead. Same for 16-bit decrement. ++;;; <mem> must be offsettable for the instruction to match. ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") (match_operand:HI 1 "memory_operand" "")) ++ (set (match_dup 0) (plus:HI (match_dup 0) (const_int 1))) ++ (set (match_dup 1) (match_dup 0))] ++ "reload_completed ++ && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF ++ && peep2_reg_dead_p (3, operands[0])" ++ [(set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))] ++ "") ++ ++(define_peephole2 ++ [(set (match_operand:HI 0 "register_operand" "") (match_operand:HI 1 "memory_operand" "")) ++ (set (match_dup 0) (plus:HI (match_dup 0) (const_int -1))) ++ (set (match_dup 1) (match_dup 0))] ++ "reload_completed ++ && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF ++ && peep2_reg_dead_p (3, operands[0])" ++ [(set (match_dup 1) (plus:HI (match_dup 1) (const_int -1)))] ++ "") ++ ++ ++;;; Replace a load or store using an indexed register, followed by an increment of that ++;;; register, with the combined form using autoincrement. ++(define_peephole2 ++ [(set (match_operand:QI 0 "register_operand" "") ++ (mem:QI (match_operand:HI 1 "index_register_operand" ""))) ++ (set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))] ++ "reload_completed" ++ [(set (match_dup 0) (mem:QI (post_inc (match_dup 1))))] ++ "") ++ ++ ++;;- mode:emacs-lisp ++;;- comment-start: ";;- " ++;;- eval: (set-syntax-table (copy-sequence (syntax-table))) ++;;- eval: (modify-syntax-entry ?[ "(]") ++;;- eval: (modify-syntax-entry ?] ")[") ++;;- eval: (modify-syntax-entry ?{ "(}") ++;;- eval: (modify-syntax-entry ?} "){") ++;-; vim: set ts=2: ++;-; vim: set expandtab: ++;-; vim: set filetype=lisp: ++;;- End: +diff -urN gcc-4.6.4-clean/gcc/config/m6809/m6809.opt gcc-4.6.4/gcc/config/m6809/m6809.opt +--- gcc-4.6.4-clean/gcc/config/m6809/m6809.opt 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-4.6.4/gcc/config/m6809/m6809.opt 2015-07-20 19:44:52.770843181 -0600 +@@ -0,0 +1,98 @@ ++; Options for the M6809 port of the compiler ++; ++; Copyright (C) 2005 Free Software Foundation, 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 2, or (at your option) any later ++; version. ++; ++; GCC is distributed in the hope that it will be useful, but WITHOUT ++; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public ++; License for more details. ++; ++; You should have received a copy of the GNU General Public License ++; along with GCC; see the file COPYING. If not, write to the Free ++; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA ++; 02110-1301, USA. ++ ++margcount ++Target Mask(ARGCOUNT) ++Push argument count ++ ++mint8 ++Target RejectNegative Mask(BYTE_INT) ++Use 8-bit integers ++ ++mint16 ++Target RejectNegative ++Use 16-bit integers InverseMask(BYTE_INT) ++ ++mreg-args ++Target Mask(REG_ARGS) ++Use registers for function arguments ++ ++mshort_size ++Target RejectNegative Mask(SMALL_SIZE_T) ++Use 8-bit size_t ++ ++mlong_size ++Target RejectNegative InverseMask(SMALL_SIZE_T) ++Use 16-bit size_t ++ ++mdirect ++Target Mask(DIRECT) ++Enable direct addressing ++ ++mwpc ++Target RejectNegative Mask(WPC) ++Enable WPC platform extensions ++ ++mexperiment ++Target RejectNegative Mask(EXPERIMENT) ++Enable current experimental feature ++ ++m6309 ++Target RejectNegative Mask(6309) ++Enable Hitachi 6309 extensions ++ ++mcasesi ++Target RejectNegative Mask(CASESI) ++Enable the casesi pattern ++ ++mfar-code-page= ++Target RejectNegative Joined Var(far_code_page_option) ++Sets the far code page value for this compilation unit ++ ++mcode-section= ++Target RejectNegative Joined Var(code_section_ptr) ++Sets the name of the section for code ++ ++mdata-section= ++Target RejectNegative Joined Var(data_section_ptr) ++Sets the name of the section for initialized data ++ ++mbss-section= ++Target RejectNegative Joined Var(bss_section_ptr) ++Sets the name of the section for uninitialized data ++ ++mabi_version= ++Target RejectNegative Joined Var(m6809_abi_version_ptr) ++Sets the calling convention ++ ++msoft-reg-count= ++Target RejectNegative Joined Var(m6809_soft_reg_count) ++Sets the number of soft registers that can be used ++ ++mdret ++Target RejectNegative Mask(DRET) ++Put function call results in D, not X ++ ++mfar-stack-param ++Target Mask(FAR_STACK_PARAM) ++Enable stack parameters to a farcall ++ ++ +diff -urN gcc-4.6.4-clean/gcc/config/m6809/m6809-protos.h gcc-4.6.4/gcc/config/m6809/m6809-protos.h +--- gcc-4.6.4-clean/gcc/config/m6809/m6809-protos.h 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-4.6.4/gcc/config/m6809/m6809-protos.h 2015-07-20 19:44:52.770843181 -0600 +@@ -0,0 +1,94 @@ ++/* GCC for 6809 : machine-specific function prototypes ++ ++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 ++<http://www.gnu.org/licenses/>. */ ++ ++#ifndef __M6809_PROTOS_H__ ++#define __M6809_PROTOS_H__ ++ ++void print_options (FILE *file); ++void m6809_cpu_cpp_builtins (void); ++void m6809_override_options (void); ++void m6809_init_builtins (void); ++unsigned int m6809_get_live_regs (void); ++const char * m6809_get_regs_printable (unsigned int regs); ++unsigned int m6809_get_regs_size (unsigned int regs); ++int m6809_function_has_type_attr_p (tree decl, const char *); ++int m6809_current_function_has_type_attr_p (const char *); ++int prologue_epilogue_required (void); ++int noreturn_functionp (rtx x); ++void output_function_prologue (FILE *file, int size); ++void output_function_epilogue (FILE *file, int size); ++int check_float_value (enum machine_mode mode, double *d, int overflow); ++void m6809_asm_named_section (const char *name, unsigned int flags, tree decl); ++void m6809_asm_file_start (void); ++void m6809_output_ascii (FILE *fp, const char *str, unsigned long size); ++void m6809_declare_function_name (FILE *asm_out_file, const char *name, tree decl); ++void m6809_reorg (void); ++int m6809_current_function_is_void (void); ++int m6809_can_merge_pushpop_p (int op, int regs1, int regs2); ++int m6809_function_value_regno_p (unsigned int regno); ++void emit_prologue_insns (void); ++void emit_epilogue_insns (bool); ++void m6809_conditional_register_usage (void); ++void m6809_output_quoted_string (FILE *asm_file, const char *string); ++int m6809_match_peephole2 (unsigned int peephole_id, unsigned int stage); ++int m6809_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode); ++int power_of_two_p (unsigned int n); ++void m6809_do_casesi (rtx index, rtx lower_bound, rtx range, rtx table_label, rtx default_label); ++void m6809_output_addsi3 (int rtx_code, rtx *operands); ++rtx m6809_function_arg_on_stack (CUMULATIVE_ARGS *cump); ++void expand_constant_shift (int code, rtx dst, rtx src, rtx count); ++int m6809_single_operand_operator (rtx exp); ++ ++#ifdef TREE_CODE ++int m6809_init_cumulative_args (CUMULATIVE_ARGS cum, tree fntype, rtx libname); ++#endif /* TREE_CODE */ ++ ++#ifdef RTX_CODE ++void print_direct_prefix (FILE *file, rtx addr); ++void print_operand (FILE *file, rtx x, int code); ++void print_operand_address (FILE *file, rtx addr); ++void notice_update_cc (rtx exp, rtx insn); ++enum reg_class m6809_preferred_reload_class (rtx x, enum reg_class regclass); ++rtx gen_rtx_const_high (rtx r); ++rtx gen_rtx_const_low (rtx r); ++rtx gen_rtx_register_pushpop (int pop_flag, int regs); ++void emit_libcall_insns (enum machine_mode mode, const char *name, rtx *operands, int count); ++const char * output_branch_insn (enum rtx_code code, rtx *operands, int length); ++void output_far_call_insn (rtx *operands, int has_return); ++void m6809_initialize_trampoline (rtx tramp, tree fndecl, rtx cxt); ++rtx m6809_expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, int ignore); ++const char * far_functionp (rtx x); ++rtx m6809_function_value (const tree valtype, const tree func); ++void m6809_output_shift_insn (int rtx_code, rtx *operands); ++ ++const char * m6809_get_decl_bank (tree decl); ++void output_branch_insn1 (const char *opcode, rtx *operands, int long_p); ++rtx m6809_builtin_operand (tree arglist, enum machine_mode mode, int opnum); ++const char * far_function_type_p (tree type); ++void m6809_asm_trampoline_template(FILE *f); ++bool m6809_frame_pointer_required (void); ++int m6809_can_eliminate (int from, int to); ++int m6809_initial_elimination_offset (int from, int to); ++void m6809_emit_move_insn (rtx dst, rtx src); ++void m6809_split_shift (enum rtx_code code, rtx *operands); ++bool m6809_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED); ++ ++ ++#endif /* RTX_CODE */ ++ ++#endif /* __M6809_PROTOS_H__ */ +diff -urN gcc-4.6.4-clean/gcc/config/m6809/predicates.md gcc-4.6.4/gcc/config/m6809/predicates.md +--- gcc-4.6.4-clean/gcc/config/m6809/predicates.md 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-4.6.4/gcc/config/m6809/predicates.md 2015-07-20 19:44:52.770843181 -0600 +@@ -0,0 +1,78 @@ ++;; Predicate definitions for Motorola 6809 ++;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, 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 ++;; <http://www.gnu.org/licenses/>. ++ ++;; whole_register_operand is like register_operand, but it ++;; does not allow SUBREGs. ++(define_predicate "whole_register_operand" ++ (and (match_code "reg") ++ (match_operand 0 "register_operand"))) ++ ++ ++;; A predicate that matches any index register. This can be used in nameless ++;; patterns and peepholes which need a 16-bit reg, but not D. ++(define_predicate "index_register_operand" ++ (and (match_code "reg") ++ (match_test "REGNO (op) == HARD_X_REGNUM || REGNO (op) == HARD_Y_REGNUM || REGNO (op) == HARD_U_REGNUM"))) ++ ++ ++;; match only X ++(define_predicate "register_operand_x" ++ (and (match_code "reg") ++ (match_test "REGNO (op) == HARD_X_REGNUM"))) ++ ++;; match only D ++(define_predicate "register_operand_d" ++ (and (match_code "reg") ++ (match_test "REGNO (op) == HARD_D_REGNUM"))) ++ ++ ++;; Likwise, a replacement for general_operand which excludes ++;; SUBREGs. ++(define_predicate "whole_general_operand" ++ (and (match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem") ++ (match_operand 0 "general_operand"))) ++ ++ ++(define_predicate "add_general_operand" ++ (and (match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem") ++ (match_operand 0 "general_operand") ++ (match_test "REGNO (op) != SOFT_AP_REGNUM"))) ++ ++ ++(define_predicate "shift_count_operand" ++ (and (match_code "const_int") ++ (and (match_operand 0 "const_int_operand") ++ (match_test "INTVAL (op) == 1 || INTVAL (op) == 8")))) ++ ++ ++;; A predicate that matches any bitwise logical operator. This ++;; allows for a single RTL pattern to be used for multiple operations. ++(define_predicate "logical_bit_operator" ++ (ior (match_code "and") (match_code "ior") (match_code "xor"))) ++ ++ ++;; A predicate that matches any shift or rotate operator. This ++;; allows for a single RTL pattern to be used for multiple operations. ++(define_predicate "shift_rotate_operator" ++ (ior (match_code "ashift") (match_code "ashiftrt") (match_code "lshiftrt") ++ (match_code "rotate") (match_code "rotatert"))) ++ ++ ++(define_predicate "symbolic_operand" (match_code "symbol_ref")) ++ +diff -urN gcc-4.6.4-clean/gcc/config/m6809/t-coco gcc-4.6.4/gcc/config/m6809/t-coco +--- gcc-4.6.4-clean/gcc/config/m6809/t-coco 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-4.6.4/gcc/config/m6809/t-coco 2015-07-20 19:44:52.770843181 -0600 +@@ -0,0 +1,6 @@ ++# For a few minor differences in code generation on the CoCo... ++T_CFLAGS = -DTARGET_COCO ++ ++# For doing the startup differently on the CoCo... ++CRT0STUFF_T_CFLAGS += -Wa,--globalize-symbols -DTARGET_COCO ++# vim: set filetype=make: +diff -urN gcc-4.6.4-clean/gcc/config/m6809/t-m6809 gcc-4.6.4/gcc/config/m6809/t-m6809 +--- gcc-4.6.4-clean/gcc/config/m6809/t-m6809 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-4.6.4/gcc/config/m6809/t-m6809 2015-07-20 19:44:52.770843181 -0600 +@@ -0,0 +1,64 @@ ++ ++# ranlib doesn't exist, so define it to 'true' to make it a no-op ++RANLIB_FOR_TARGET = true ++ ++# Stubs for libgcc defined by m6809 are here ++LIB1ASMSRC = m6809/libgcc1.s ++ ++# Here are the functions that are implemented within libgcc1.s ++LIB1ASMFUNCS = _mulhi3 _divhi3 _modhi3 _udivhi3 _umodhi3 \ ++ _euclid _seuclid _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _softregs \ ++ _ashlhi3 _ashrhi3 _lshrhi3 ++ ++# Flags to use when building libgcc. IN_GCC does not seem necessary, ++# although the compile breaks without it. -DDF=SF is required to set ++# the size of "double" to the same as the size of a "float". ++TARGET_LIBGCC2_CFLAGS =-DIN_GCC -Dinhibit_libc -DDF=SF -DLIBGCC2_HAS_SF_MODE=0 -DLIBGCC2_HAS_DF_MODE=0 ++ ++LIB2ADDEH = ++LIB2ADDEHSTATIC = ++LIB2ADDEHSHARED = ++ ++LIBGCC2_DEBUG_CFLAGS = ++LIBGCC2_CFLAGS = -Os $(LIBGCC2_INCLUDES) $(TARGET_LIBGCC2_CFLAGS) $(LIBGCC2_DEBUG_CFLAGS) $(GTHREAD_FLAGS) -DIN_LIBGCC2 ++ ++# Multilib information ++# This creates multiple versions of libgcc.a for each set of incompatible ++# -mxxx options. ++MULTILIB_OPTIONS = fpic mdret ++MULTILIB_DIRNAMES = ++MULTILIB_MATCHES = ++MULTILIB_EXCEPTIONS = ++EXTRA_MULTILIB_PARTS = crt0.o ++ ++LIBGCC = stmp-multilib ++INSTALL_LIBGCC = install-multilib ++ ++# We want fine grained libraries, so use the new code to build the ++# floating point emulation libraries. ++FPBIT = fp-bit.c ++ ++fp-bit.c: $(srcdir)/config/fp-bit.c ++ echo '#define FLOAT' > fp-bit.c ++ echo '#define FLOAT_ONLY' >> fp-bit.c ++ echo '#define CMPtype HItype' >> fp-bit.c ++ echo '#define SMALL_MACHINE' >> fp-bit.c ++ echo '#ifdef __LITTLE_ENDIAN__' >> fp-bit.c ++ echo '#define FLOAT_BIT_ORDER_MISMATCH' >>fp-bit.c ++ echo '#endif' >> fp-bit.c ++ echo '#define DI SI' >> fp-bit.c ++ cat $(srcdir)/config/fp-bit.c >> fp-bit.c ++ ++# crt0.o is built from the following source file ++CRT0_S = $(srcdir)/config/m6809/crt0.S ++MCRT0_S = $(srcdir)/config/m6809/crt0.S ++ ++# Flags to use when building crt0.o ++CRT0STUFF_T_CFLAGS += -fno-builtin -nostartfiles -nostdlib ++ ++# Assemble startup files. ++$(T)crt0.o: $(CRT0_S) $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(CRT0STUFF_T_CFLAGS) $(MULTILIB_CFLAGS) -c -o $(T)crt0.o -x assembler-with-cpp $(CRT0_S) ++ ++$(T)mcrt0.o: $(MCRT0_S) $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(CRT0STUFF_T_CFLAGS) $(MULTILIB_CFLAGS) -c -o $(T)mcrt0.o -x assembler-with-cpp $(MCRT0_S) +diff -urN gcc-4.6.4-clean/gcc/config/m6809/t-sim gcc-4.6.4/gcc/config/m6809/t-sim +--- gcc-4.6.4-clean/gcc/config/m6809/t-sim 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-4.6.4/gcc/config/m6809/t-sim 2015-07-20 19:44:52.770843181 -0600 +@@ -0,0 +1 @@ ++CRT0STUFF_T_CFLAGS += -DTARGET_SIM +diff -urN gcc-4.6.4-clean/gcc/config.gcc gcc-4.6.4/gcc/config.gcc +--- gcc-4.6.4-clean/gcc/config.gcc 2013-03-06 10:40:07.000000000 -0700 ++++ gcc-4.6.4/gcc/config.gcc 2015-07-20 19:44:52.770843181 -0600 +@@ -375,6 +375,9 @@ + cpu_type=m32r + extra_options="${extra_options} g.opt" + ;; ++m6809-*-*) ++ cpu_type=m6809 ++ ;; + m68k-*-*) + extra_headers=math-68881.h + ;; +@@ -1706,6 +1709,12 @@ + thread_file='posix' + fi + ;; ++m6809-coco-*) ++ tmake_file="${tmake_file} m6809/t-m6809 m6809/t-coco" ++ ;; ++m6809-*-*) ++ tmake_file="${tmake_file} m6809/t-m6809 m6809/t-sim" ++ ;; + # m68hc11 and m68hc12 share the same machine description. + m68hc11-*-*|m6811-*-*) + tm_file="dbxelf.h elfos.h usegas.h newlib-stdint.h m68hc11/m68hc11.h" +diff -urN gcc-4.6.4-clean/gcc/gcse.c gcc-4.6.4/gcc/gcse.c +--- gcc-4.6.4-clean/gcc/gcse.c 2011-02-02 23:04:04.000000000 -0700 ++++ gcc-4.6.4/gcc/gcse.c 2015-07-20 19:44:52.770843181 -0600 +@@ -833,7 +833,6 @@ + max_distance = (GCSE_COST_DISTANCE_RATIO * cost) / 10; + if (max_distance == 0) + return 0; +- + gcc_assert (max_distance > 0); + } + else +diff -urN gcc-4.6.4-clean/gcc/libgcc2.c gcc-4.6.4/gcc/libgcc2.c +--- gcc-4.6.4-clean/gcc/libgcc2.c 2011-01-03 13:52:22.000000000 -0700 ++++ gcc-4.6.4/gcc/libgcc2.c 2015-07-20 19:44:52.770843181 -0600 +@@ -485,6 +485,7 @@ + #endif + + #ifdef L_bswapsi2 ++#if MIN_UNITS_PER_WORD > 1 + SItype + __bswapsi2 (SItype u) + { +@@ -494,7 +495,9 @@ + | (((u) & 0x000000ff) << 24)); + } + #endif ++#endif + #ifdef L_bswapdi2 ++#if LONG_LONG_TYPE_SIZE > 32 + DItype + __bswapdi2 (DItype u) + { +@@ -508,6 +511,7 @@ + | (((u) & 0x00000000000000ffull) << 56)); + } + #endif ++#endif + #ifdef L_ffssi2 + #undef int + int +@@ -1280,7 +1284,7 @@ + UDWtype + __fixunssfDI (SFtype a) + { +-#if LIBGCC2_HAS_DF_MODE ++#if LIBGCC2_HAS_DF_MODE || (FLT_MANT_DIG >= W_TYPE_SIZE) + /* Convert the SFtype to a DFtype, because that is surely not going + to lose any bits. Some day someone else can write a faster version + that avoids converting to DFtype, and verify it really works right. */ +@@ -1298,7 +1302,7 @@ + + /* Assemble result from the two parts. */ + return ((UDWtype) hi << W_TYPE_SIZE) | lo; +-#elif FLT_MANT_DIG < W_TYPE_SIZE ++#else + if (a < 1) + return 0; + if (a < Wtype_MAXp1_F) +@@ -1334,8 +1338,6 @@ + return (DWtype)counter << shift; + } + return -1; +-#else +-# error + #endif + } + #endif +diff -urN gcc-4.6.4-clean/gcc/longlong.h gcc-4.6.4/gcc/longlong.h +--- gcc-4.6.4-clean/gcc/longlong.h 2011-10-04 01:28:50.000000000 -0600 ++++ gcc-4.6.4/gcc/longlong.h 2015-07-20 19:44:52.770843181 -0600 +@@ -528,6 +528,11 @@ + : "cbit") + #endif /* __M32R__ */ + ++#if defined (__m6309__) || defined (__m6809__) ++#define count_leading_zeros(COUNT,X) ((COUNT) = __builtin_clz (X)) ++#define count_trailing_zeros(COUNT,X) ((COUNT) = __builtin_ctz (X)) ++#endif ++ + #if defined (__mc68000__) && W_TYPE_SIZE == 32 + #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add%.l %5,%1\n\taddx%.l %3,%0" \ +diff -urN gcc-4.6.4-clean/gcc/Makefile.in gcc-4.6.4/gcc/Makefile.in +--- gcc-4.6.4-clean/gcc/Makefile.in 2013-04-01 02:32:34.000000000 -0600 ++++ gcc-4.6.4/gcc/Makefile.in 2015-07-20 19:44:52.770843181 -0600 +@@ -2003,14 +2003,14 @@ + + # Compile the start modules crt0.o and mcrt0.o that are linked with + # every program +-$(T)crt0.o: s-crt0 ; @true +-$(T)mcrt0.o: s-crt0; @true ++crt0.o: s-crt0 ; @true ++mcrt0.o: s-crt0; @true + + s-crt0: $(CRT0_S) $(MCRT0_S) $(GCC_PASSES) $(CONFIG_H) + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(CRT0STUFF_T_CFLAGS) \ +- -o $(T)crt0.o -c $(CRT0_S) ++ -o crt0.o -c $(CRT0_S) + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(CRT0STUFF_T_CFLAGS) \ +- -o $(T)mcrt0.o -c $(MCRT0_S) ++ -o mcrt0.o -c $(MCRT0_S) + $(STAMP) s-crt0 + # + # Compiling object files from source files. +diff -urN gcc-4.6.4-clean/gcc/opth-gen.awk gcc-4.6.4/gcc/opth-gen.awk +--- gcc-4.6.4-clean/gcc/opth-gen.awk 2011-02-08 10:41:00.000000000 -0700 ++++ gcc-4.6.4/gcc/opth-gen.awk 2015-07-20 19:44:52.774843181 -0600 +@@ -121,7 +121,7 @@ + END { + print "/* This file is auto-generated by opth-gen.awk. */" + print "" +-print "#ifndef OPTIONS_H" ++print "#if !defined(OPTIONS_H) && !defined(IN_LIBGCC2)" + print "#define OPTIONS_H" + print "" + print "#include \"flag-types.h\"" +@@ -432,18 +432,9 @@ + + for (i = 0; i < n_opts; i++) { + opt = opt_args("InverseMask", flags[i]) +- if (opt ~ ",") { +- vname = var_name(flags[i]) +- macro = "OPTION_" +- mask = "OPTION_MASK_" +- if (vname == "") { +- vname = "target_flags" +- macro = "TARGET_" +- mask = "MASK_" +- } +- print "#define " macro nth_arg(1, opt) \ +- " ((" vname " & " mask nth_arg(0, opt) ") == 0)" +- } ++ if (opt ~ ",") ++ print "#define TARGET_" nth_arg(1, opt) \ ++ " ((target_flags & MASK_" nth_arg(0, opt) ") == 0)" + } + print "" + +diff -urN gcc-4.6.4-clean/gcc/tree.h gcc-4.6.4/gcc/tree.h +--- gcc-4.6.4-clean/gcc/tree.h 2011-10-06 13:57:52.000000000 -0600 ++++ gcc-4.6.4/gcc/tree.h 2015-07-20 19:44:52.774843181 -0600 +@@ -3563,6 +3563,8 @@ + TI_UINTDI_TYPE, + TI_UINTTI_TYPE, + ++ TI_UINT8_TYPE, ++ TI_UINT16_TYPE, + TI_UINT32_TYPE, + TI_UINT64_TYPE, + +diff -urN gcc-4.6.4-clean/gcc/version.c gcc-4.6.4/gcc/version.c +--- gcc-4.6.4-clean/gcc/version.c 2009-04-21 13:03:23.000000000 -0600 ++++ gcc-4.6.4/gcc/version.c 2015-07-20 19:44:52.774843181 -0600 +@@ -21,16 +21,16 @@ + + /* This is the location of the online document giving instructions for + reporting bugs. If you distribute a modified version of GCC, +- please configure with --with-bugurl pointing to a document giving +- instructions for reporting bugs to you, not us. (You are of course +- welcome to forward us bugs reported to you, if you determine that +- they are not bugs in your modifications.) */ ++ please change this to refer to a document giving instructions for ++ reporting bugs to you, not us. (You are of course welcome to ++ forward us bugs reported to you, if you determine that they are ++ not bugs in your modifications.) */ + +-const char bug_report_url[] = BUGURL; ++const char bug_report_url[] = "<URL:http://lost.l-w.ca/coco/lwtools/>"; + + /* The complete version string, assembled from several pieces. + BASEVER, DATESTAMP, DEVPHASE, and REVISION are defined by the + Makefile. */ + +-const char version_string[] = BASEVER DATESTAMP DEVPHASE REVISION; ++const char version_string[] = BASEVER DATESTAMP DEVPHASE REVISION " (gcc6809lw pl6)"; + const char pkgversion_string[] = PKGVERSION; +diff -urN gcc-4.6.4-clean/libgcc/config.host gcc-4.6.4/libgcc/config.host +--- gcc-4.6.4-clean/libgcc/config.host 2011-11-23 15:15:54.000000000 -0700 ++++ gcc-4.6.4/libgcc/config.host 2015-07-20 19:44:52.774843181 -0600 +@@ -371,6 +371,8 @@ + ;; + m32rle-*-linux*) + ;; ++m6809*) ++ ;; + m68hc11-*-*|m6811-*-*) + ;; + m68hc12-*-*|m6812-*-*) +diff -urN gcc-4.6.4-clean/libgcc/fixed-obj.mk gcc-4.6.4/libgcc/fixed-obj.mk +--- gcc-4.6.4-clean/libgcc/fixed-obj.mk 2007-09-17 16:18:13.000000000 -0600 ++++ gcc-4.6.4/libgcc/fixed-obj.mk 2015-07-20 19:44:52.774843181 -0600 +@@ -23,7 +23,7 @@ + #$(info $o$(objext): -DL$($o-label) $($o-opt)) + + $o$(objext): %$(objext): $(gcc_srcdir)/config/fixed-bit.c +- $(gcc_compile) -DL$($*-label) $($*-opt) -c $(gcc_srcdir)/config/fixed-bit.c $(vis_hide) ++ $(gcc_compile) -DL$($*-label) $($*-opt) -c $(gcc_srcdir)/config/fixed-bit.c $(vis_hide) -save-temps + + ifeq ($(enable_shared),yes) + $(o)_s$(objext): %_s$(objext): $(gcc_srcdir)/config/fixed-bit.c +diff -urN gcc-4.6.4-clean/libgcc/Makefile.in gcc-4.6.4/libgcc/Makefile.in +--- gcc-4.6.4-clean/libgcc/Makefile.in 2012-12-04 12:11:33.000000000 -0700 ++++ gcc-4.6.4/libgcc/Makefile.in 2015-07-20 19:44:52.774843181 -0600 +@@ -374,8 +374,8 @@ + # Build lib2funcs. For the static library also include LIB2FUNCS_ST. + lib2funcs-o = $(patsubst %,%$(objext),$(lib2funcs) $(LIB2FUNCS_ST)) + $(lib2funcs-o): %$(objext): $(gcc_srcdir)/libgcc2.c +- $(gcc_compile) -DL$* -c $(gcc_srcdir)/libgcc2.c \ +- $(vis_hide) ++ ln -sf $(gcc_srcdir)/libgcc2.c $*.c && \ ++ $(gcc_compile) -DL$* -c $*.c $(vis_hide) -save-temps + libgcc-objects += $(lib2funcs-o) + + ifeq ($(enable_shared),yes) +@@ -410,8 +410,9 @@ + # Build LIB2_DIVMOD_FUNCS. + lib2-divmod-o = $(patsubst %,%$(objext),$(LIB2_DIVMOD_FUNCS)) + $(lib2-divmod-o): %$(objext): $(gcc_srcdir)/libgcc2.c +- $(gcc_compile) -DL$* -c $(gcc_srcdir)/libgcc2.c \ +- -fexceptions -fnon-call-exceptions $(vis_hide) ++ ln -sf $(gcc_srcdir)/libgcc2.c $*.c && \ ++ $(gcc_compile) -DL$* -c $*.c \ ++ -fexceptions -fnon-call-exceptions $(vis_hide) -save-temps + libgcc-objects += $(lib2-divmod-o) + + ifeq ($(enable_shared),yes) +@@ -443,7 +444,8 @@ + ifneq ($(FPBIT),) + fpbit-o = $(patsubst %,%$(objext),$(FPBIT_FUNCS)) + $(fpbit-o): %$(objext): $(FPBIT) +- $(gcc_compile) -DFINE_GRAINED_LIBRARIES -DL$* -c $(FPBIT) $(vis_hide) ++ ln -sf $(FPBIT) $*.c && \ ++ $(gcc_compile) -DFINE_GRAINED_LIBRARIES -DL$* -c $*.c $(vis_hide) -save-temps + libgcc-objects += $(fpbit-o) + + ifeq ($(enable_shared),yes) +@@ -458,7 +460,8 @@ + ifneq ($(DPBIT),) + dpbit-o = $(patsubst %,%$(objext),$(DPBIT_FUNCS)) + $(dpbit-o): %$(objext): $(DPBIT) +- $(gcc_compile) -DFINE_GRAINED_LIBRARIES -DL$* -c $(DPBIT) $(vis_hide) ++ ln -sf $(DPBIT) $*.c && \ ++ $(gcc_compile) -DFINE_GRAINED_LIBRARIES -DL$* -c $*.c $(vis_hide) -save-temps + libgcc-objects += $(dpbit-o) + + ifeq ($(enable_shared),yes) +diff -urN gcc-4.6.4-clean/README.LW gcc-4.6.4/README.LW +--- gcc-4.6.4-clean/README.LW 1969-12-31 17:00:00.000000000 -0700 ++++ gcc-4.6.4/README.LW 2015-07-20 19:44:52.774843181 -0600 +@@ -0,0 +1,14 @@ ++This is a port of gcc6809 which is designed to work with the lwtools ++cross-assembler and linker package. You will need several scripts from that ++package, available at http://lost.l-w.ca/coco/lwtools/, in order to use ++this. Instructions for building are present in the lwtools package. ++ ++This work is based extensively on the gcc6809 4.3.4-3 release by Brian ++Dominy (brian@oddchange.com) with some significant renovations to make it ++work with gcc 4.6.1. ++ ++There is no guarantee that it will work for any particular purpose you ++choose to put it to. ++ ++If you run into any problems, contact William Astle (lost@l-w.ca). DO NOT ++contact the main GCC developers!