diff options
Diffstat (limited to 'gcc')
-rwxr-xr-x | gcc/config/arm/lib1thumb.asm | 745 | ||||
-rwxr-xr-x | gcc/config/arm/lib1thumb_981111.asm | 747 | ||||
-rwxr-xr-x | gcc/config/arm/telf_020422.h | 443 | ||||
-rwxr-xr-x | gcc/config/arm/thumb.c.orig | 2132 | ||||
-rwxr-xr-x | gcc/config/arm/thumb.c.rej | 168 | ||||
-rwxr-xr-x | gcc/config/arm/thumb.h.orig | 1195 | ||||
-rwxr-xr-x | gcc/config/arm/thumb.md.orig | 1174 | ||||
-rwxr-xr-x | gcc/config/arm/thumb.md.rej | 168 | ||||
-rwxr-xr-x | gcc/config/arm/thumb_000513.h | 1187 | ||||
-rwxr-xr-x | gcc/config/arm/thumb_010110a.c | 2124 | ||||
-rwxr-xr-x | gcc/config/arm/thumb_010110a.md | 1166 | ||||
-rwxr-xr-x | gcc/config/arm/thumb_010309a.c | 2132 | ||||
-rwxr-xr-x | gcc/config/arm/thumb_020422.c | 2291 | ||||
-rwxr-xr-x | gcc/config/arm/thumb_020422.h | 1295 | ||||
-rwxr-xr-x | gcc/config/arm/thumb_020422.md | 1194 | ||||
-rwxr-xr-x | gcc/config/arm/thumb_020428.h | 1297 | ||||
-rwxr-xr-x | gcc/config/arm/thumb_020428.md | 1194 | ||||
-rwxr-xr-x | gcc/config/arm/thumb_981111.md | 1166 |
18 files changed, 460 insertions, 21358 deletions
diff --git a/gcc/config/arm/lib1thumb.asm b/gcc/config/arm/lib1thumb.asm index 1789356..dcabcf4 100755 --- a/gcc/config/arm/lib1thumb.asm +++ b/gcc/config/arm/lib1thumb.asm @@ -39,6 +39,18 @@ Boston, MA 02111-1307, USA. */ #error __USER_LABEL_PREFIX__ not defined #endif +#ifdef __elf__ +#define __PLT__ (PLT) +#define TYPE(x) .type SYM(x),function +#define SIZE(x) .size SYM(x), . - SYM(x) +#else +#define __PLT__ +#define TYPE(x) +#define SIZE(x) +#endif + +#define RET mov pc, lr + /* ANSI concatenation macros. */ #define CONCAT1(a, b) CONCAT2(a, b) @@ -48,298 +60,290 @@ Boston, MA 02111-1307, USA. */ #define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) -#define __PLT__ +work .req r4 @ XXXX is this safe ? -#ifdef __ELF__ -#define TYPE(x) .type SYM(x),function -#define SIZE(x) .size SYM(x), . - SYM(x) -#else -#define TYPE(x) -#define SIZE(x) -#endif +#ifdef L_udivsi3 -/* Function end macros. Variants for interworking. */ +dividend .req r0 +divisor .req r1 +result .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + + .text + .globl SYM (__udivsi3) + TYPE (__udivsi3) + .align 0 + .thumb_func +SYM (__udivsi3): + cmp divisor, #0 + beq Ldiv0 + mov curbit, #1 + mov result, #0 + + push { work } + cmp dividend, divisor + bcc Lgot_result -# define __THUMB_INTERWORK__ -# ifdef __THUMB_INTERWORK__ -# define RET bx lr -# define RETc(x) bx##x lr -.macro THUMB_LDIV0 -.Ldiv0: - push { lr } - bl SYM (__div0) - mov r0, #0 @ About as wrong as it could be. - pop { r1 } - bx r1 -.endm -# else -# define RET mov pc, lr -# define RETc(x) mov##x pc, lr -.macro THUMB_LDIV0 -.Ldiv0: - push { lr } - bl SYM (__div0) - mov r0, #0 @ About as wrong as it could be. - pop { pc } -.endm -# endif -# define RETCOND + @ Load the constant 0x10000000 into our work register + mov work, #1 + lsl work, #28 +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + bcs Lbignum + cmp divisor, dividend + bcs Lbignum + lsl divisor, #4 + lsl curbit, #4 + b Loop1 -.macro FUNC_END name -.Ldiv0: - THUMB_LDIV0 - SIZE (__\name) -.endm +Lbignum: + @ Set work to 0x80000000 + lsl work, #3 +Loop2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, work + bcs Loop3 + cmp divisor, dividend + bcs Loop3 + lsl divisor, #1 + lsl curbit, #1 + b Loop2 -.macro THUMB_FUNC_START name - .globl SYM (\name) - TYPE (\name) - .thumb_func -SYM (\name): -.endm +Loop3: + @ Test for possible subtractions, and note which bits + @ are done in the result. On the final pass, this may subtract + @ too much from the dividend, but the result will be ok, since the + @ "bit" will have been shifted out at the bottom. + cmp dividend, divisor + bcc Over1 + sub dividend, dividend, divisor + orr result, result, curbit +Over1: + lsr work, divisor, #1 + cmp dividend, work + bcc Over2 + sub dividend, dividend, work + lsr work, curbit, #1 + orr result, work +Over2: + lsr work, divisor, #2 + cmp dividend, work + bcc Over3 + sub dividend, dividend, work + lsr work, curbit, #2 + orr result, work +Over3: + lsr work, divisor, #3 + cmp dividend, work + bcc Over4 + sub dividend, dividend, work + lsr work, curbit, #3 + orr result, work +Over4: + cmp dividend, #0 @ Early termination? + beq Lgot_result + lsr curbit, #4 @ No, any more bits to do? + beq Lgot_result + lsr divisor, #4 + b Loop3 +Lgot_result: + mov r0, result + pop { work } + RET -/* Function start macros. */ +Ldiv0: + push { lr } + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + pop { pc } -#define THUMB_FUNC .thumb_func -#define THUMB_CODE .force_thumb + SIZE (__udivsi3) -.macro FUNC_START name - .text - .globl SYM (__\name) - TYPE (__\name) - .align 0 - THUMB_CODE - THUMB_FUNC -SYM (__\name): -.endm - -/* Register aliases. */ +#endif /* L_udivsi3 */ + +#ifdef L_umodsi3 -work .req r4 @ XXXX is this safe ? dividend .req r0 divisor .req r1 overdone .req r2 -result .req r2 curbit .req r3 ip .req r12 sp .req r13 lr .req r14 pc .req r15 + + .text + .globl SYM (__umodsi3) + TYPE (__umodsi3) + .align 0 + .thumb_func +SYM (__umodsi3): + cmp divisor, #0 + beq Ldiv0 + mov curbit, #1 + cmp dividend, divisor + bcs Over1 + RET -/* ------------------------------------------------------------------------ */ -/* Bodies of the divsion and modulo routines. */ -/* ------------------------------------------------------------------------ */ -.macro THUMB_DIV_MOD_BODY modulo - @ Load the constant 0x10000000 into our work register. +Over1: + @ Load the constant 0x10000000 into our work register + push { work } mov work, #1 lsl work, #28 -.Loop1: +Loop1: @ Unless the divisor is very big, shift it up in multiples of @ four bits, since this is the amount of unwinding in the main @ division loop. Continue shifting until the divisor is @ larger than the dividend. cmp divisor, work - bhs .Lbignum + bcs Lbignum cmp divisor, dividend - bhs .Lbignum + bcs Lbignum lsl divisor, #4 - lsl curbit, #4 - b .Loop1 -.Lbignum: + lsl curbit, #4 + b Loop1 + +Lbignum: @ Set work to 0x80000000 lsl work, #3 -.Loop2: +Loop2: @ For very big divisors, we must shift it a bit at a time, or @ we will be in danger of overflowing. cmp divisor, work - bhs .Loop3 + bcs Loop3 cmp divisor, dividend - bhs .Loop3 + bcs Loop3 lsl divisor, #1 - lsl curbit, #1 - b .Loop2 -.Loop3: - @ Test for possible subtractions ... - .if \modulo - @ ... On the final pass, this may subtract too much from the dividend, - @ so keep track of which subtractions are done, we can fix them up - @ afterwards. + lsl curbit, #1 + b Loop2 + +Loop3: + @ Test for possible subtractions. On the final pass, this may + @ subtract too much from the dividend, so keep track of which + @ subtractions are done, we can fix them up afterwards... mov overdone, #0 cmp dividend, divisor - blo .Lover1 + bcc Over2 sub dividend, dividend, divisor -.Lover1: +Over2: lsr work, divisor, #1 cmp dividend, work - blo .Lover2 + bcc Over3 sub dividend, dividend, work mov ip, curbit mov work, #1 ror curbit, work orr overdone, curbit mov curbit, ip -.Lover2: +Over3: lsr work, divisor, #2 cmp dividend, work - blo .Lover3 + bcc Over4 sub dividend, dividend, work mov ip, curbit mov work, #2 ror curbit, work orr overdone, curbit mov curbit, ip -.Lover3: +Over4: lsr work, divisor, #3 cmp dividend, work - blo .Lover4 + bcc Over5 sub dividend, dividend, work mov ip, curbit mov work, #3 ror curbit, work orr overdone, curbit mov curbit, ip -.Lover4: +Over5: mov ip, curbit - .else - @ ... and note which bits are done in the result. On the final pass, - @ this may subtract too much from the dividend, but the result will be ok, - @ since the "bit" will have been shifted out at the bottom. - cmp dividend, divisor - blo .Lover1 - sub dividend, dividend, divisor - orr result, result, curbit -.Lover1: - lsr work, divisor, #1 - cmp dividend, work - blo .Lover2 - sub dividend, dividend, work - lsr work, curbit, #1 - orr result, work -.Lover2: - lsr work, divisor, #2 - cmp dividend, work - blo .Lover3 - sub dividend, dividend, work - lsr work, curbit, #2 - orr result, work -.Lover3: - lsr work, divisor, #3 - cmp dividend, work - blo .Lover4 - sub dividend, dividend, work - lsr work, curbit, #3 - orr result, work -.Lover4: - .endif - cmp dividend, #0 @ Early termination? - beq .Lover5 - lsr curbit, #4 @ No, any more bits to do? - beq .Lover5 + beq Over6 + lsr curbit, #4 @ No, any more bits to do? + beq Over6 lsr divisor, #4 - b .Loop3 -.Lover5: - .if \modulo + b Loop3 + +Over6: @ Any subtractions that we should not have done will be recorded in @ the top three bits of "overdone". Exactly which were not needed @ are governed by the position of the bit, stored in ip. + @ If we terminated early, because dividend became zero, + @ then none of the below will match, since the bit in ip will not be + @ in the bottom nibble. + mov work, #0xe - lsl work, #28 + lsl work, #28 and overdone, work - beq .Lgot_result - - @ If we terminated early, because dividend became zero, then the - @ bit in ip will not be in the bottom nibble, and we should not - @ perform the additions below. We must test for this though - @ (rather relying upon the TSTs to prevent the additions) since - @ the bit in ip could be in the top two bits which might then match - @ with one of the smaller RORs. - mov curbit, ip - mov work, #0x7 - tst curbit, work - beq .Lgot_result - + bne Over7 + pop { work } + RET @ No fixups needed +Over7: mov curbit, ip mov work, #3 ror curbit, work tst overdone, curbit - beq .Lover6 + beq Over8 lsr work, divisor, #3 - add dividend, work -.Lover6: + add dividend, dividend, work +Over8: mov curbit, ip mov work, #2 ror curbit, work tst overdone, curbit - beq .Lover7 + beq Over9 lsr work, divisor, #2 - add dividend, work -.Lover7: + add dividend, dividend, work +Over9: mov curbit, ip mov work, #1 ror curbit, work tst overdone, curbit - beq .Lgot_result + beq Over10 lsr work, divisor, #1 - add dividend, work - .endif -.Lgot_result: -.endm -/* ------------------------------------------------------------------------ */ -/* Start of the Real Functions */ -/* ------------------------------------------------------------------------ */ -#ifdef L_udivsi3 - - FUNC_START udivsi3 - - cmp divisor, #0 - beq .Ldiv0 - mov curbit, #1 - mov result, #0 - - push { work } - cmp dividend, divisor - blo .Lgot_result - - THUMB_DIV_MOD_BODY 0 - - mov r0, result + add dividend, dividend, work +Over10: pop { work } - RET - - FUNC_END udivsi3 - -#endif /* L_udivsi3 */ -/* ------------------------------------------------------------------------ */ -#ifdef L_umodsi3 - - FUNC_START umodsi3 - - cmp divisor, #0 - beq .Ldiv0 - mov curbit, #1 - cmp dividend, divisor - bhs ..Lover10 RET -..Lover10: - push { work } +Ldiv0: + push { lr } + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + pop { pc } - THUMB_DIV_MOD_BODY 1 + SIZE (__umodsi3) - pop { work } - RET - - FUNC_END umodsi3 - #endif /* L_umodsi3 */ -/* ------------------------------------------------------------------------ */ -#ifdef L_divsi3 - FUNC_START divsi3 +#ifdef L_divsi3 +dividend .req r0 +divisor .req r1 +result .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + + .text + .globl SYM (__divsi3) + TYPE (__divsi3) + .align 0 + .thumb_func +SYM (__divsi3): cmp divisor, #0 - beq .Ldiv0 + beq Ldiv0 push { work } mov work, dividend @@ -348,111 +352,281 @@ pc .req r15 mov curbit, #1 mov result, #0 cmp divisor, #0 - bpl .Lover10 + bpl Over1 neg divisor, divisor @ Loops below use unsigned. -.Lover10: +Over1: cmp dividend, #0 - bpl .Lover11 + bpl Over2 neg dividend, dividend -.Lover11: +Over2: cmp dividend, divisor - blo .Lgot_result + bcc Lgot_result + + mov work, #1 + lsl work, #28 +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + Bcs Lbignum + cmp divisor, dividend + Bcs Lbignum + lsl divisor, #4 + lsl curbit, #4 + b Loop1 - THUMB_DIV_MOD_BODY 0 +Lbignum: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + lsl work, #3 +Loop2: + cmp divisor, work + Bcs Loop3 + cmp divisor, dividend + Bcs Loop3 + lsl divisor, #1 + lsl curbit, #1 + b Loop2 + +Loop3: + @ Test for possible subtractions, and note which bits + @ are done in the result. On the final pass, this may subtract + @ too much from the dividend, but the result will be ok, since the + @ "bit" will have been shifted out at the bottom. + cmp dividend, divisor + Bcc Over3 + sub dividend, dividend, divisor + orr result, result, curbit +Over3: + lsr work, divisor, #1 + cmp dividend, work + Bcc Over4 + sub dividend, dividend, work + lsr work, curbit, #1 + orr result, work +Over4: + lsr work, divisor, #2 + cmp dividend, work + Bcc Over5 + sub dividend, dividend, work + lsr work, curbit, #2 + orr result, result, work +Over5: + lsr work, divisor, #3 + cmp dividend, work + Bcc Over6 + sub dividend, dividend, work + lsr work, curbit, #3 + orr result, result, work +Over6: + cmp dividend, #0 @ Early termination? + Beq Lgot_result + lsr curbit, #4 @ No, any more bits to do? + Beq Lgot_result + lsr divisor, #4 + b Loop3 +Lgot_result: mov r0, result mov work, ip cmp work, #0 - bpl .Lover12 + Bpl Over7 neg r0, r0 -.Lover12: +Over7: pop { work } - RET - - FUNC_END divsi3 + RET + +Ldiv0: + push { lr } + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + pop { pc } + SIZE (__divsi3) + #endif /* L_divsi3 */ -/* ------------------------------------------------------------------------ */ -#ifdef L_modsi3 - FUNC_START modsi3 +#ifdef L_modsi3 +dividend .req r0 +divisor .req r1 +overdone .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + + .text + .globl SYM (__modsi3) + TYPE (__modsi3) + .align 0 + .thumb_func +SYM (__modsi3): mov curbit, #1 cmp divisor, #0 - beq .Ldiv0 - bpl .Lover10 + beq Ldiv0 + Bpl Over1 neg divisor, divisor @ Loops below use unsigned. - -.Lover10: +Over1: push { work } @ Need to save the sign of the dividend, unfortunately, we need - @ work later on. Must do this after saving the original value of + @ ip later on. Must do this after saving the original value of @ the work register, because we will pop this value off first. push { dividend } cmp dividend, #0 - bpl .Lover11 + Bpl Over2 neg dividend, dividend -.Lover11: +Over2: cmp dividend, divisor - blo .Lgot_result + bcc Lgot_result + mov work, #1 + lsl work, #28 +Loop1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + bcs Lbignum + cmp divisor, dividend + bcs Lbignum + lsl divisor, #4 + lsl curbit, #4 + b Loop1 - THUMB_DIV_MOD_BODY 1 - +Lbignum: + @ Set work to 0x80000000 + lsl work, #3 +Loop2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, work + bcs Loop3 + cmp divisor, dividend + bcs Loop3 + lsl divisor, #1 + lsl curbit, #1 + b Loop2 + +Loop3: + @ Test for possible subtractions. On the final pass, this may + @ subtract too much from the dividend, so keep track of which + @ subtractions are done, we can fix them up afterwards... + mov overdone, #0 + cmp dividend, divisor + bcc Over3 + sub dividend, dividend, divisor +Over3: + lsr work, divisor, #1 + cmp dividend, work + bcc Over4 + sub dividend, dividend, work + mov ip, curbit + mov work, #1 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over4: + lsr work, divisor, #2 + cmp dividend, work + bcc Over5 + sub dividend, dividend, work + mov ip, curbit + mov work, #2 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over5: + lsr work, divisor, #3 + cmp dividend, work + bcc Over6 + sub dividend, dividend, work + mov ip, curbit + mov work, #3 + ror curbit, work + orr overdone, curbit + mov curbit, ip +Over6: + mov ip, curbit + cmp dividend, #0 @ Early termination? + beq Over7 + lsr curbit, #4 @ No, any more bits to do? + beq Over7 + lsr divisor, #4 + b Loop3 + +Over7: + @ Any subtractions that we should not have done will be recorded in + @ the top three bits of "overdone". Exactly which were not needed + @ are governed by the position of the bit, stored in ip. + @ If we terminated early, because dividend became zero, + @ then none of the below will match, since the bit in ip will not be + @ in the bottom nibble. + mov work, #0xe + lsl work, #28 + and overdone, work + beq Lgot_result + + mov curbit, ip + mov work, #3 + ror curbit, work + tst overdone, curbit + beq Over8 + lsr work, divisor, #3 + add dividend, dividend, work +Over8: + mov curbit, ip + mov work, #2 + ror curbit, work + tst overdone, curbit + beq Over9 + lsr work, divisor, #2 + add dividend, dividend, work +Over9: + mov curbit, ip + mov work, #1 + ror curbit, work + tst overdone, curbit + beq Lgot_result + lsr work, divisor, #1 + add dividend, dividend, work +Lgot_result: pop { work } cmp work, #0 - bpl .Lover12 + bpl Over10 neg dividend, dividend -.Lover12: +Over10: pop { work } RET - - FUNC_END modsi3 +Ldiv0: + push { lr } + bl SYM (__div0) __PLT__ + mov r0, #0 @ about as wrong as it could be + pop { pc } + + SIZE (__modsi3) + #endif /* L_modsi3 */ -/* ------------------------------------------------------------------------ */ -#ifdef L_dvmd_tls - FUNC_START div0 +#ifdef L_dvmd_tls - RET + .globl SYM (__div0) + TYPE (__div0) + .align 0 + .thumb_func +SYM (__div0): + RET SIZE (__div0) #endif /* L_divmodsi_tools */ -/* ------------------------------------------------------------------------ */ -#ifdef L_dvmd_lnx -@ GNU/Linux division-by zero handler. Used in place of L_dvmd_tls -#include <asm/unistd.h> -#define SIGFPE 8 @ cant use <asm/signal.h> as it - @ contains too much C rubbish - FUNC_START div0 - - stmfd sp!, {r1, lr} - swi __NR_getpid - cmn r0, #1000 - ldmhsfd sp!, {r1, pc}RETCOND @ not much we can do - mov r1, #SIGFPE - swi __NR_kill -#ifdef __THUMB_INTERWORK__ - ldmfd sp!, {r1, lr} - bx lr -#else - ldmfd sp!, {r1, pc}RETCOND -#endif - - SIZE (__div0) - -#endif /* L_dvmd_lnx */ -/* ------------------------------------------------------------------------ */ -/* These next two sections are here despite the fact that they contain Thumb - assembler because their presence allows interworked code to be linked even - when the GCC library is this one. */ - -/* Do not build the interworking functions when the target architecture does - not support Thumb instructions. (This can be a multilib option). */ -#if defined L_call_via_rX +#ifdef L_call_via_rX /* These labels & instructions are used by the Arm/Thumb interworking code. The address of function to be called is loaded into a register and then @@ -462,14 +636,15 @@ pc .req r15 .text .align 0 - .force_thumb .macro call_via register - THUMB_FUNC_START _call_via_\register - + .globl SYM (_call_via_\register) + TYPE (_call_via_\register) + .thumb_func +SYM (_call_via_\register): bx \register nop - + SIZE (_call_via_\register) .endm @@ -490,10 +665,8 @@ pc .req r15 call_via lr #endif /* L_call_via_rX */ -/* ------------------------------------------------------------------------ */ -/* Do not build the interworking functions when the target architecture does - not support Thumb instructions. (This can be a multilib option). */ -#if defined L_interwork_call_via_rX + +#ifdef L_interwork_call_via_rX /* These labels & instructions are used by the Arm/Thumb interworking code, when the target address is in an unknown instruction set. The address @@ -509,22 +682,23 @@ pc .req r15 .text .align 0 - .code 32 + .code 32 .globl _arm_return _arm_return: ldmia r13!, {r12} bx r12 - .code 16 - + .macro interwork register - .code 16 - - THUMB_FUNC_START _interwork_call_via_\register - + .code 16 + + .globl SYM (_interwork_call_via_\register) + TYPE (_interwork_call_via_\register) + .thumb_func +SYM (_interwork_call_via_\register): bx pc nop - .code 32 + .code 32 .globl .Lchange_\register .Lchange_\register: tst \register, #1 @@ -549,12 +723,13 @@ _arm_return: interwork fp interwork ip interwork sp - - /* The LR case has to be handled a little differently... */ - .code 16 - - THUMB_FUNC_START _interwork_call_via_lr + /* The lr case has to be handled a little differently...*/ + .code 16 + .globl SYM (_interwork_call_via_lr) + TYPE (_interwork_call_via_lr) + .thumb_func +SYM (_interwork_call_via_lr): bx pc nop @@ -566,7 +741,7 @@ _arm_return: mov ip, lr adreq lr, _arm_return bx ip - + SIZE (_interwork_call_via_lr) #endif /* L_interwork_call_via_rX */ diff --git a/gcc/config/arm/lib1thumb_981111.asm b/gcc/config/arm/lib1thumb_981111.asm deleted file mode 100755 index dcabcf4..0000000 --- a/gcc/config/arm/lib1thumb_981111.asm +++ /dev/null @@ -1,747 +0,0 @@ -@ libgcc1 routines for ARM cpu. -@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) - -/* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. - -This file is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -In addition to the permissions in the GNU General Public License, the -Free Software Foundation gives you unlimited permission to link the -compiled version of this file with other programs, and to distribute -those programs without any restriction coming from the use of this -file. (The General Public License restrictions do apply in other -respects; for example, they cover modification of the file, and -distribution when not linked into another program.) - -This file is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* 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. */ - - .code 16 - -#ifndef __USER_LABEL_PREFIX__ -#error __USER_LABEL_PREFIX__ not defined -#endif - -#ifdef __elf__ -#define __PLT__ (PLT) -#define TYPE(x) .type SYM(x),function -#define SIZE(x) .size SYM(x), . - SYM(x) -#else -#define __PLT__ -#define TYPE(x) -#define SIZE(x) -#endif - -#define RET mov pc, lr - -/* ANSI concatenation macros. */ - -#define CONCAT1(a, b) CONCAT2(a, b) -#define CONCAT2(a, b) a ## b - -/* Use the right prefix for global labels. */ - -#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) - -work .req r4 @ XXXX is this safe ? - -#ifdef L_udivsi3 - -dividend .req r0 -divisor .req r1 -result .req r2 -curbit .req r3 -ip .req r12 -sp .req r13 -lr .req r14 -pc .req r15 - - .text - .globl SYM (__udivsi3) - TYPE (__udivsi3) - .align 0 - .thumb_func -SYM (__udivsi3): - cmp divisor, #0 - beq Ldiv0 - mov curbit, #1 - mov result, #0 - - push { work } - cmp dividend, divisor - bcc Lgot_result - - @ Load the constant 0x10000000 into our work register - mov work, #1 - lsl work, #28 -Loop1: - @ Unless the divisor is very big, shift it up in multiples of - @ four bits, since this is the amount of unwinding in the main - @ division loop. Continue shifting until the divisor is - @ larger than the dividend. - cmp divisor, work - bcs Lbignum - cmp divisor, dividend - bcs Lbignum - lsl divisor, #4 - lsl curbit, #4 - b Loop1 - -Lbignum: - @ Set work to 0x80000000 - lsl work, #3 -Loop2: - @ For very big divisors, we must shift it a bit at a time, or - @ we will be in danger of overflowing. - cmp divisor, work - bcs Loop3 - cmp divisor, dividend - bcs Loop3 - lsl divisor, #1 - lsl curbit, #1 - b Loop2 - -Loop3: - @ Test for possible subtractions, and note which bits - @ are done in the result. On the final pass, this may subtract - @ too much from the dividend, but the result will be ok, since the - @ "bit" will have been shifted out at the bottom. - cmp dividend, divisor - bcc Over1 - sub dividend, dividend, divisor - orr result, result, curbit -Over1: - lsr work, divisor, #1 - cmp dividend, work - bcc Over2 - sub dividend, dividend, work - lsr work, curbit, #1 - orr result, work -Over2: - lsr work, divisor, #2 - cmp dividend, work - bcc Over3 - sub dividend, dividend, work - lsr work, curbit, #2 - orr result, work -Over3: - lsr work, divisor, #3 - cmp dividend, work - bcc Over4 - sub dividend, dividend, work - lsr work, curbit, #3 - orr result, work -Over4: - cmp dividend, #0 @ Early termination? - beq Lgot_result - lsr curbit, #4 @ No, any more bits to do? - beq Lgot_result - lsr divisor, #4 - b Loop3 -Lgot_result: - mov r0, result - pop { work } - RET - -Ldiv0: - push { lr } - bl SYM (__div0) __PLT__ - mov r0, #0 @ about as wrong as it could be - pop { pc } - - SIZE (__udivsi3) - -#endif /* L_udivsi3 */ - -#ifdef L_umodsi3 - -dividend .req r0 -divisor .req r1 -overdone .req r2 -curbit .req r3 -ip .req r12 -sp .req r13 -lr .req r14 -pc .req r15 - - .text - .globl SYM (__umodsi3) - TYPE (__umodsi3) - .align 0 - .thumb_func -SYM (__umodsi3): - cmp divisor, #0 - beq Ldiv0 - mov curbit, #1 - cmp dividend, divisor - bcs Over1 - RET - -Over1: - @ Load the constant 0x10000000 into our work register - push { work } - mov work, #1 - lsl work, #28 -Loop1: - @ Unless the divisor is very big, shift it up in multiples of - @ four bits, since this is the amount of unwinding in the main - @ division loop. Continue shifting until the divisor is - @ larger than the dividend. - cmp divisor, work - bcs Lbignum - cmp divisor, dividend - bcs Lbignum - lsl divisor, #4 - lsl curbit, #4 - b Loop1 - -Lbignum: - @ Set work to 0x80000000 - lsl work, #3 -Loop2: - @ For very big divisors, we must shift it a bit at a time, or - @ we will be in danger of overflowing. - cmp divisor, work - bcs Loop3 - cmp divisor, dividend - bcs Loop3 - lsl divisor, #1 - lsl curbit, #1 - b Loop2 - -Loop3: - @ Test for possible subtractions. On the final pass, this may - @ subtract too much from the dividend, so keep track of which - @ subtractions are done, we can fix them up afterwards... - mov overdone, #0 - cmp dividend, divisor - bcc Over2 - sub dividend, dividend, divisor -Over2: - lsr work, divisor, #1 - cmp dividend, work - bcc Over3 - sub dividend, dividend, work - mov ip, curbit - mov work, #1 - ror curbit, work - orr overdone, curbit - mov curbit, ip -Over3: - lsr work, divisor, #2 - cmp dividend, work - bcc Over4 - sub dividend, dividend, work - mov ip, curbit - mov work, #2 - ror curbit, work - orr overdone, curbit - mov curbit, ip -Over4: - lsr work, divisor, #3 - cmp dividend, work - bcc Over5 - sub dividend, dividend, work - mov ip, curbit - mov work, #3 - ror curbit, work - orr overdone, curbit - mov curbit, ip -Over5: - mov ip, curbit - cmp dividend, #0 @ Early termination? - beq Over6 - lsr curbit, #4 @ No, any more bits to do? - beq Over6 - lsr divisor, #4 - b Loop3 - -Over6: - @ Any subtractions that we should not have done will be recorded in - @ the top three bits of "overdone". Exactly which were not needed - @ are governed by the position of the bit, stored in ip. - @ If we terminated early, because dividend became zero, - @ then none of the below will match, since the bit in ip will not be - @ in the bottom nibble. - - mov work, #0xe - lsl work, #28 - and overdone, work - bne Over7 - pop { work } - RET @ No fixups needed -Over7: - mov curbit, ip - mov work, #3 - ror curbit, work - tst overdone, curbit - beq Over8 - lsr work, divisor, #3 - add dividend, dividend, work -Over8: - mov curbit, ip - mov work, #2 - ror curbit, work - tst overdone, curbit - beq Over9 - lsr work, divisor, #2 - add dividend, dividend, work -Over9: - mov curbit, ip - mov work, #1 - ror curbit, work - tst overdone, curbit - beq Over10 - lsr work, divisor, #1 - add dividend, dividend, work -Over10: - pop { work } - RET - -Ldiv0: - push { lr } - bl SYM (__div0) __PLT__ - mov r0, #0 @ about as wrong as it could be - pop { pc } - - SIZE (__umodsi3) - -#endif /* L_umodsi3 */ - -#ifdef L_divsi3 - -dividend .req r0 -divisor .req r1 -result .req r2 -curbit .req r3 -ip .req r12 -sp .req r13 -lr .req r14 -pc .req r15 - - .text - .globl SYM (__divsi3) - TYPE (__divsi3) - .align 0 - .thumb_func -SYM (__divsi3): - cmp divisor, #0 - beq Ldiv0 - - push { work } - mov work, dividend - eor work, divisor @ Save the sign of the result. - mov ip, work - mov curbit, #1 - mov result, #0 - cmp divisor, #0 - bpl Over1 - neg divisor, divisor @ Loops below use unsigned. -Over1: - cmp dividend, #0 - bpl Over2 - neg dividend, dividend -Over2: - cmp dividend, divisor - bcc Lgot_result - - mov work, #1 - lsl work, #28 -Loop1: - @ Unless the divisor is very big, shift it up in multiples of - @ four bits, since this is the amount of unwinding in the main - @ division loop. Continue shifting until the divisor is - @ larger than the dividend. - cmp divisor, work - Bcs Lbignum - cmp divisor, dividend - Bcs Lbignum - lsl divisor, #4 - lsl curbit, #4 - b Loop1 - -Lbignum: - @ For very big divisors, we must shift it a bit at a time, or - @ we will be in danger of overflowing. - lsl work, #3 -Loop2: - cmp divisor, work - Bcs Loop3 - cmp divisor, dividend - Bcs Loop3 - lsl divisor, #1 - lsl curbit, #1 - b Loop2 - -Loop3: - @ Test for possible subtractions, and note which bits - @ are done in the result. On the final pass, this may subtract - @ too much from the dividend, but the result will be ok, since the - @ "bit" will have been shifted out at the bottom. - cmp dividend, divisor - Bcc Over3 - sub dividend, dividend, divisor - orr result, result, curbit -Over3: - lsr work, divisor, #1 - cmp dividend, work - Bcc Over4 - sub dividend, dividend, work - lsr work, curbit, #1 - orr result, work -Over4: - lsr work, divisor, #2 - cmp dividend, work - Bcc Over5 - sub dividend, dividend, work - lsr work, curbit, #2 - orr result, result, work -Over5: - lsr work, divisor, #3 - cmp dividend, work - Bcc Over6 - sub dividend, dividend, work - lsr work, curbit, #3 - orr result, result, work -Over6: - cmp dividend, #0 @ Early termination? - Beq Lgot_result - lsr curbit, #4 @ No, any more bits to do? - Beq Lgot_result - lsr divisor, #4 - b Loop3 - -Lgot_result: - mov r0, result - mov work, ip - cmp work, #0 - Bpl Over7 - neg r0, r0 -Over7: - pop { work } - RET - -Ldiv0: - push { lr } - bl SYM (__div0) __PLT__ - mov r0, #0 @ about as wrong as it could be - pop { pc } - - SIZE (__divsi3) - -#endif /* L_divsi3 */ - -#ifdef L_modsi3 - -dividend .req r0 -divisor .req r1 -overdone .req r2 -curbit .req r3 -ip .req r12 -sp .req r13 -lr .req r14 -pc .req r15 - - .text - .globl SYM (__modsi3) - TYPE (__modsi3) - .align 0 - .thumb_func -SYM (__modsi3): - mov curbit, #1 - cmp divisor, #0 - beq Ldiv0 - Bpl Over1 - neg divisor, divisor @ Loops below use unsigned. -Over1: - push { work } - @ Need to save the sign of the dividend, unfortunately, we need - @ ip later on. Must do this after saving the original value of - @ the work register, because we will pop this value off first. - push { dividend } - cmp dividend, #0 - Bpl Over2 - neg dividend, dividend -Over2: - cmp dividend, divisor - bcc Lgot_result - mov work, #1 - lsl work, #28 -Loop1: - @ Unless the divisor is very big, shift it up in multiples of - @ four bits, since this is the amount of unwinding in the main - @ division loop. Continue shifting until the divisor is - @ larger than the dividend. - cmp divisor, work - bcs Lbignum - cmp divisor, dividend - bcs Lbignum - lsl divisor, #4 - lsl curbit, #4 - b Loop1 - -Lbignum: - @ Set work to 0x80000000 - lsl work, #3 -Loop2: - @ For very big divisors, we must shift it a bit at a time, or - @ we will be in danger of overflowing. - cmp divisor, work - bcs Loop3 - cmp divisor, dividend - bcs Loop3 - lsl divisor, #1 - lsl curbit, #1 - b Loop2 - -Loop3: - @ Test for possible subtractions. On the final pass, this may - @ subtract too much from the dividend, so keep track of which - @ subtractions are done, we can fix them up afterwards... - mov overdone, #0 - cmp dividend, divisor - bcc Over3 - sub dividend, dividend, divisor -Over3: - lsr work, divisor, #1 - cmp dividend, work - bcc Over4 - sub dividend, dividend, work - mov ip, curbit - mov work, #1 - ror curbit, work - orr overdone, curbit - mov curbit, ip -Over4: - lsr work, divisor, #2 - cmp dividend, work - bcc Over5 - sub dividend, dividend, work - mov ip, curbit - mov work, #2 - ror curbit, work - orr overdone, curbit - mov curbit, ip -Over5: - lsr work, divisor, #3 - cmp dividend, work - bcc Over6 - sub dividend, dividend, work - mov ip, curbit - mov work, #3 - ror curbit, work - orr overdone, curbit - mov curbit, ip -Over6: - mov ip, curbit - cmp dividend, #0 @ Early termination? - beq Over7 - lsr curbit, #4 @ No, any more bits to do? - beq Over7 - lsr divisor, #4 - b Loop3 - -Over7: - @ Any subtractions that we should not have done will be recorded in - @ the top three bits of "overdone". Exactly which were not needed - @ are governed by the position of the bit, stored in ip. - @ If we terminated early, because dividend became zero, - @ then none of the below will match, since the bit in ip will not be - @ in the bottom nibble. - mov work, #0xe - lsl work, #28 - and overdone, work - beq Lgot_result - - mov curbit, ip - mov work, #3 - ror curbit, work - tst overdone, curbit - beq Over8 - lsr work, divisor, #3 - add dividend, dividend, work -Over8: - mov curbit, ip - mov work, #2 - ror curbit, work - tst overdone, curbit - beq Over9 - lsr work, divisor, #2 - add dividend, dividend, work -Over9: - mov curbit, ip - mov work, #1 - ror curbit, work - tst overdone, curbit - beq Lgot_result - lsr work, divisor, #1 - add dividend, dividend, work -Lgot_result: - pop { work } - cmp work, #0 - bpl Over10 - neg dividend, dividend -Over10: - pop { work } - RET - -Ldiv0: - push { lr } - bl SYM (__div0) __PLT__ - mov r0, #0 @ about as wrong as it could be - pop { pc } - - SIZE (__modsi3) - -#endif /* L_modsi3 */ - -#ifdef L_dvmd_tls - - .globl SYM (__div0) - TYPE (__div0) - .align 0 - .thumb_func -SYM (__div0): - RET - - SIZE (__div0) - -#endif /* L_divmodsi_tools */ - - -#ifdef L_call_via_rX - -/* These labels & instructions are used by the Arm/Thumb interworking code. - The address of function to be called is loaded into a register and then - one of these labels is called via a BL instruction. This puts the - return address into the link register with the bottom bit set, and the - code here switches to the correct mode before executing the function. */ - - .text - .align 0 - -.macro call_via register - .globl SYM (_call_via_\register) - TYPE (_call_via_\register) - .thumb_func -SYM (_call_via_\register): - bx \register - nop - - SIZE (_call_via_\register) -.endm - - call_via r0 - call_via r1 - call_via r2 - call_via r3 - call_via r4 - call_via r5 - call_via r6 - call_via r7 - call_via r8 - call_via r9 - call_via sl - call_via fp - call_via ip - call_via sp - call_via lr - -#endif /* L_call_via_rX */ - -#ifdef L_interwork_call_via_rX - -/* These labels & instructions are used by the Arm/Thumb interworking code, - when the target address is in an unknown instruction set. The address - of function to be called is loaded into a register and then one of these - labels is called via a BL instruction. This puts the return address - into the link register with the bottom bit set, and the code here - switches to the correct mode before executing the function. Unfortunately - the target code cannot be relied upon to return via a BX instruction, so - instead we have to store the resturn address on the stack and allow the - called function to return here instead. Upon return we recover the real - return address and use a BX to get back to Thumb mode. */ - - .text - .align 0 - - .code 32 - .globl _arm_return -_arm_return: - ldmia r13!, {r12} - bx r12 - -.macro interwork register - .code 16 - - .globl SYM (_interwork_call_via_\register) - TYPE (_interwork_call_via_\register) - .thumb_func -SYM (_interwork_call_via_\register): - bx pc - nop - - .code 32 - .globl .Lchange_\register -.Lchange_\register: - tst \register, #1 - stmeqdb r13!, {lr} - adreq lr, _arm_return - bx \register - - SIZE (_interwork_call_via_\register) -.endm - - interwork r0 - interwork r1 - interwork r2 - interwork r3 - interwork r4 - interwork r5 - interwork r6 - interwork r7 - interwork r8 - interwork r9 - interwork sl - interwork fp - interwork ip - interwork sp - - /* The lr case has to be handled a little differently...*/ - .code 16 - .globl SYM (_interwork_call_via_lr) - TYPE (_interwork_call_via_lr) - .thumb_func -SYM (_interwork_call_via_lr): - bx pc - nop - - .code 32 - .globl .Lchange_lr -.Lchange_lr: - tst lr, #1 - stmeqdb r13!, {lr} - mov ip, lr - adreq lr, _arm_return - bx ip - - SIZE (_interwork_call_via_lr) - -#endif /* L_interwork_call_via_rX */ diff --git a/gcc/config/arm/telf_020422.h b/gcc/config/arm/telf_020422.h deleted file mode 100755 index 6e59404..0000000 --- a/gcc/config/arm/telf_020422.h +++ /dev/null @@ -1,443 +0,0 @@ -/* CYGNUS LOCAL (entire file) clm/arm-elf */ -/* Definitions of target machine for GNU compiler, - for Thumb with ELF obj format. - Copyright (C) 1995, 1996, 2001 Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#define OBJECT_FORMAT_ELF - -#define CPP_PREDEFINES "-Dthumb -Dthumbelf -D__thumb -Acpu(arm) -Amachine(arm)" - -#include "arm/thumb.h" - -/* Run-time Target Specification. */ -#undef TARGET_VERSION -#define TARGET_VERSION fputs (" (Thumb/elf)", stderr) - -#define MULTILIB_DEFAULTS { "mlittle-endian" } - -/* Setting this to 32 produces more efficient code, but the value set in previous - versions of this toolchain was 8, which produces more compact structures. The - command line option -mstructure_size_boundary=<n> can be used to change this - value. */ -#undef STRUCTURE_SIZE_BOUNDARY -#define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary - -extern int arm_structure_size_boundary; - -/* Debug */ -#define DWARF_DEBUGGING_INFO -#define DWARF2_DEBUGGING_INFO -#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG - - -/* Note - it is important that these definitions match those in semi.h for the ARM port. */ -#undef LOCAL_LABEL_PREFIX -#define LOCAL_LABEL_PREFIX "." - - -/* A C statement to output assembler commands which will identify the - object file as having been compiled with GNU CC (or another GNU - compiler). */ -#define ASM_IDENTIFY_GCC(STREAM) \ - fprintf (STREAM, "%sgcc2_compiled.:\n", LOCAL_LABEL_PREFIX ) - -#undef ASM_FILE_START -#define ASM_FILE_START(STREAM) \ -do { \ - extern char *version_string; \ - fprintf ((STREAM), "%s Generated by gcc %s for Thumb/elf\n", \ - ASM_COMMENT_START, version_string); \ - fprintf ((STREAM), ASM_APP_OFF); \ -} while (0) - -/* A C statement to output something to the assembler file to switch to section - NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or - NULL_TREE. Some target formats do not support arbitrary sections. Do not - define this macro in such cases. */ -#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC) \ -do { \ - if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \ - fprintf (STREAM, "\t.section %s,\"ax\",%%progbits\n", (NAME)); \ - else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \ - fprintf (STREAM, "\t.section %s,\"a\"\n", (NAME)); \ - else if (0 == strncmp((NAME), ".bss", sizeof(".bss") - 1)) \ - fprintf (STREAM, "\t.section %s,\"aw\",%%nobits\n", (NAME)); \ - else \ - fprintf (STREAM, "\t.section %s,\"aw\"\n", (NAME)); \ -} while (0) - -/* Support the ctors/dtors and other sections. */ - -#undef INIT_SECTION_ASM_OP - -/* Define this macro if jump tables (for `tablejump' insns) should be - output in the text section, along with the assembler instructions. - Otherwise, the readonly data section is used. */ -#define JUMP_TABLES_IN_TEXT_SECTION 1 - -#undef READONLY_DATA_SECTION -#define READONLY_DATA_SECTION rdata_section -#undef RDATA_SECTION_ASM_OP -#define RDATA_SECTION_ASM_OP "\t.section .rodata" - -#undef CTORS_SECTION_ASM_OP -#define CTORS_SECTION_ASM_OP "\t.section .ctors,\"aw\"" -#undef DTORS_SECTION_ASM_OP -#define DTORS_SECTION_ASM_OP "\t.section .dtors,\"aw\"" - -#define USER_LABEL_PREFIX "" - -/* If defined, a C expression whose value is a string containing the - assembler operation to identify the following data as - uninitialized global data. If not defined, and neither - `ASM_OUTPUT_BSS' nor `ASM_OUTPUT_ALIGNED_BSS' are defined, - uninitialized global data will be output in the data section if - `-fno-common' is passed, otherwise `ASM_OUTPUT_COMMON' will be - used. */ -#ifndef BSS_SECTION_ASM_OP -#define BSS_SECTION_ASM_OP ".section\t.bss" -#endif - -/* Like `ASM_OUTPUT_BSS' except takes the required alignment as a - separate, explicit argument. If you define this macro, it is used - in place of `ASM_OUTPUT_BSS', and gives you more flexibility in - handling the required alignment of the variable. The alignment is - specified as the number of bits. - - Try to use function `asm_output_aligned_bss' defined in file - `varasm.c' when defining this macro. */ -#ifndef ASM_OUTPUT_ALIGNED_BSS -#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ - asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN) -#endif - -/* Don't know how to order these. UNALIGNED_WORD_ASM_OP is in - dwarf2.out. */ -#define UNALIGNED_WORD_ASM_OP ".4byte" - -#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) \ -do { \ - fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ - output_addr_const ((FILE), (RTX)); \ - fputc ('\n', (FILE)); \ -} while (0) - -/* This is how to equate one symbol to another symbol. The syntax used is - `SYM1=SYM2'. Note that this is different from the way equates are done - with most svr4 assemblers, where the syntax is `.set SYM1,SYM2'. */ - -#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \ - do { fprintf ((FILE), "\t"); \ - assemble_name (FILE, LABEL1); \ - fprintf (FILE, " = "); \ - assemble_name (FILE, LABEL2); \ - fprintf (FILE, "\n"); \ - } while (0) - -/* For aliases of functions we use .thumb_set instead. */ -#define ASM_OUTPUT_DEF_FROM_DECLS(FILE,DECL1,DECL2) \ - do \ - { \ - char * LABEL1 = XSTR (XEXP (DECL_RTL (decl), 0), 0); \ - char * LABEL2 = IDENTIFIER_POINTER (DECL2); \ - \ - if (TREE_CODE (DECL1) == FUNCTION_DECL) \ - { \ - fprintf (FILE, "\t.thumb_set "); \ - assemble_name (FILE, LABEL1); \ - fprintf (FILE, ","); \ - assemble_name (FILE, LABEL2); \ - fprintf (FILE, "\n"); \ - } \ - else \ - ASM_OUTPUT_DEF (FILE, LABEL1, LABEL2); \ - } \ - while (0) - -/* A list of other sections which the compiler might be "in" at any - given time. */ -#undef EXTRA_SECTIONS -#define EXTRA_SECTIONS SUBTARGET_EXTRA_SECTIONS in_rdata, in_ctors, in_dtors - -#define SUBTARGET_EXTRA_SECTIONS - -/* A list of extra section function definitions. */ - -#undef EXTRA_SECTION_FUNCTIONS -#define EXTRA_SECTION_FUNCTIONS \ - RDATA_SECTION_FUNCTION \ - CTORS_SECTION_FUNCTION \ - DTORS_SECTION_FUNCTION \ - SUBTARGET_EXTRA_SECTION_FUNCTIONS - -#define SUBTARGET_EXTRA_SECTION_FUNCTIONS - -#define RDATA_SECTION_FUNCTION \ -void \ -rdata_section () \ -{ \ - if (in_section != in_rdata) \ - { \ - fprintf (asm_out_file, "%s\n", RDATA_SECTION_ASM_OP); \ - in_section = in_rdata; \ - } \ -} - -#define CTOR_LIST_BEGIN \ -asm (CTORS_SECTION_ASM_OP); \ -func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) } - -#define CTOR_LIST_END \ -asm (CTORS_SECTION_ASM_OP); \ -func_ptr __CTOR_END__[1] = { (func_ptr) 0 }; - -#define DTOR_LIST_BEGIN \ -asm (DTORS_SECTION_ASM_OP); \ -func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) } - -#define DTOR_LIST_END \ -asm (DTORS_SECTION_ASM_OP); \ -func_ptr __DTOR_END__[1] = { (func_ptr) 0 }; - -#define CTORS_SECTION_FUNCTION \ -void \ -ctors_section () \ -{ \ - if (in_section != in_ctors) \ - { \ - fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \ - in_section = in_ctors; \ - } \ -} - -#define DTORS_SECTION_FUNCTION \ -void \ -dtors_section () \ -{ \ - if (in_section != in_dtors) \ - { \ - fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \ - in_section = in_dtors; \ - } \ -} - -/* Support the ctors/dtors sections for g++. */ - -#define INT_ASM_OP ".word" - -#define INVOKE__main - -#undef STARTFILE_SPEC -#define STARTFILE_SPEC "crtbegin%O%s crt0%O%s" - -#undef ENDFILE_SPEC -#define ENDFILE_SPEC "crtend%O%s" - -/* A C statement (sans semicolon) to output an element in the table of - global constructors. */ -#undef ASM_OUTPUT_CONSTRUCTOR -#define ASM_OUTPUT_CONSTRUCTOR(STREAM,NAME) \ -do { \ - ctors_section (); \ - fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ - assemble_name (STREAM, NAME); \ - fprintf (STREAM, "\n"); \ -} while (0) - -/* A C statement (sans semicolon) to output an element in the table of - global destructors. */ -#undef ASM_OUTPUT_DESTRUCTOR -#define ASM_OUTPUT_DESTRUCTOR(STREAM,NAME) \ -do { \ - dtors_section (); \ - fprintf (STREAM, "\t%s\t ", INT_ASM_OP); \ - assemble_name (STREAM, NAME); \ - fprintf (STREAM, "\n"); \ -} while (0) - -/* The ARM development system has atexit and doesn't have _exit, - so define this for now. */ -#define HAVE_ATEXIT - -/* The ARM development system defines __main. */ -#define NAME__MAIN "__gccmain" -#define SYMBOL__MAIN __gccmain - -#define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1) -#define UNIQUE_SECTION_P(DECL) (DECL_ONE_ONLY (DECL)) -#define UNIQUE_SECTION(DECL,RELOC) \ -do { \ - int len; \ - char * name, * string, * prefix; \ - \ - name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \ - \ - if (! DECL_ONE_ONLY (DECL)) \ - { \ - prefix = "."; \ - if (TREE_CODE (DECL) == FUNCTION_DECL) \ - prefix = ".text."; \ - else if (DECL_READONLY_SECTION (DECL, RELOC)) \ - prefix = ".rodata."; \ - else \ - prefix = ".data."; \ - } \ - else if (TREE_CODE (DECL) == FUNCTION_DECL) \ - prefix = ".gnu.linkonce.t."; \ - else if (DECL_READONLY_SECTION (DECL, RELOC)) \ - prefix = ".gnu.linkonce.r."; \ - else \ - prefix = ".gnu.linkonce.d."; \ - \ - len = strlen (name) + strlen (prefix); \ - string = alloca (len + 1); \ - sprintf (string, "%s%s", prefix, name); \ - \ - DECL_SECTION_NAME (DECL) = build_string (len, string); \ -} while (0) - -/* This is how we tell the assembler that a symbol is weak. */ -#ifndef ASM_WEAKEN_LABEL -#define ASM_WEAKEN_LABEL(FILE, NAME) \ - do \ - { \ - fputs ("\t.weak\t", FILE); \ - assemble_name (FILE, NAME); \ - fputc ('\n', FILE); \ - } \ - while (0) -#endif - -#ifndef TYPE_ASM_OP - -/* These macros generate the special .type and .size directives which - are used to set the corresponding fields of the linker symbol table - entries in an ELF object file under SVR4. These macros also output - the starting labels for the relevant functions/objects. */ -#define TYPE_ASM_OP ".type" -#define SIZE_ASM_OP ".size" - -/* The following macro defines the format used to output the second - operand of the .type assembler directive. Different svr4 assemblers - expect various different forms for this operand. The one given here - is just a default. You may need to override it in your machine- - specific tm.h file (depending upon the particulars of your assembler). */ -#define TYPE_OPERAND_FMT "%s" - -/* Write the extra assembler code needed to declare a function's result. - Most svr4 assemblers don't require any special declaration of the - result value, but there are exceptions. */ -#ifndef ASM_DECLARE_RESULT -#define ASM_DECLARE_RESULT(FILE, RESULT) -#endif - -/* Write the extra assembler code needed to declare a function properly. - Some svr4 assemblers need to also have something extra said about the - function's return value. We allow for that here. */ -#undef ASM_DECLARE_FUNCTION_NAME -#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ - do \ - { \ - fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ - assemble_name (FILE, NAME); \ - putc (',', FILE); \ - fprintf (FILE, TYPE_OPERAND_FMT, "function"); \ - putc ('\n', FILE); \ - ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \ - if (! is_called_in_ARM_mode (decl)) \ - fprintf (FILE, "\t.thumb_func\n") ; \ - else \ - fprintf (FILE, "\t.code\t32\n") ; \ - ASM_OUTPUT_LABEL(FILE, NAME); \ - } \ - while (0) - -/* Write the extra assembler code needed to declare an object properly. */ -#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ - do \ - { \ - fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ - assemble_name (FILE, NAME); \ - putc (',', FILE); \ - fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ - putc ('\n', FILE); \ - size_directive_output = 0; \ - if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ - { \ - size_directive_output = 1; \ - fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ - assemble_name (FILE, NAME); \ - putc (',', FILE); \ - fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \ - int_size_in_bytes (TREE_TYPE (DECL))); \ - fputc ('\n', FILE); \ - } \ - ASM_OUTPUT_LABEL(FILE, NAME); \ - } \ - while (0) - -/* Output the size directive for a decl in rest_of_decl_compilation - in the case where we did not do so before the initializer. - Once we find the error_mark_node, we know that the value of - size_directive_output was set - by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */ -#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ - do \ - { \ - char * name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ - if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \ - && ! AT_END && TOP_LEVEL \ - && DECL_INITIAL (DECL) == error_mark_node \ - && !size_directive_output) \ - { \ - size_directive_output = 1; \ - fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ - assemble_name (FILE, name); \ - putc (',', FILE); \ - fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \ - int_size_in_bytes (TREE_TYPE (DECL))); \ - fputc ('\n', FILE); \ - } \ - } \ - while (0) - -/* This is how to declare the size of a function. */ -#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ - do \ - { \ - if (!flag_inhibit_size_directive) \ - { \ - char label[256]; \ - static int labelno; \ - labelno ++; \ - ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ - ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \ - fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ - assemble_name (FILE, (FNAME)); \ - fprintf (FILE, ","); \ - assemble_name (FILE, label); \ - fprintf (FILE, "-"); \ - assemble_name (FILE, (FNAME)); \ - putc ('\n', FILE); \ - } \ - } \ - while (0) - -#endif /* TYPE_ASM_OP */ diff --git a/gcc/config/arm/thumb.c.orig b/gcc/config/arm/thumb.c.orig deleted file mode 100755 index 778cda9..0000000 --- a/gcc/config/arm/thumb.c.orig +++ /dev/null @@ -1,2132 +0,0 @@ -/* Output routines for GCC for ARM/Thumb - Copyright (C) 1996 Cygnus Software Technologies Ltd - The basis of this contribution was generated by - Richard Earnshaw, Advanced RISC Machines Ltd - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#include <stdio.h> -#include <string.h> -#include "config.h" -#include "rtl.h" -#include "hard-reg-set.h" -#include "regs.h" -#include "output.h" -#include "insn-flags.h" -#include "insn-attr.h" -#include "flags.h" -#include "tree.h" -#include "expr.h" - - -int current_function_anonymous_args = 0; -static int current_function_has_far_jump = 0; - -/* Used to parse -mstructure_size_boundary command line option. */ -char * structure_size_string = NULL; -int arm_structure_size_boundary = 32; /* Used to be 8 */ - - -/* Predicates */ -int -reload_memory_operand (op, mode) - rtx op; - enum machine_mode mode; -{ - int regno = true_regnum (op); - - return (! CONSTANT_P (op) - && (regno == -1 - || (GET_CODE (op) == REG - && REGNO (op) >= FIRST_PSEUDO_REGISTER))); -} - -/* Return nonzero if op is suitable for the RHS of a cmp instruction. */ -int -thumb_cmp_operand (op, mode) - rtx op; - enum machine_mode mode; -{ - return ((GET_CODE (op) == CONST_INT - && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256) - || register_operand (op, mode)); -} - -int -thumb_shiftable_const (val) - HOST_WIDE_INT val; -{ - unsigned HOST_WIDE_INT x = val; - unsigned HOST_WIDE_INT mask = 0xff; - int i; - - for (i = 0; i < 25; i++) - if ((val & (mask << i)) == val) - return 1; - - return 0; -} - -int -thumb_trivial_epilogue () -{ - int regno; - - /* ??? If this function ever returns 1, we get a function without any - epilogue at all. It appears that the intent was to cause a "return" - insn to be emitted, but that does not happen. */ - return 0; - -#if 0 - if (get_frame_size () - || current_function_outgoing_args_size - || current_function_pretend_args_size) - return 0; - - for (regno = 8; regno < 13; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - return 0; - - return 1; -#endif -} - - -/* Routines for handling the constant pool */ -/* This is unashamedly hacked from the version in sh.c, since the problem is - extremely similar. */ - -/* Thumb instructions cannot load a large constant into a register, - constants have to come from a pc relative load. The reference of a pc - relative load instruction must be less than 1k infront of the instruction. - This means that we often have to dump a constant inside a function, and - generate code to branch around it. - - It is important to minimize this, since the branches will slow things - down and make things bigger. - - Worst case code looks like: - - ldr rn, L1 - b L2 - align - L1: .long value - L2: - .. - - ldr rn, L3 - b L4 - align - L3: .long value - L4: - .. - - We fix this by performing a scan before scheduling, which notices which - instructions need to have their operands fetched from the constant table - and builds the table. - - - The algorithm is: - - scan, find an instruction which needs a pcrel move. Look forward, find the - last barrier which is within MAX_COUNT bytes of the requirement. - If there isn't one, make one. Process all the instructions between - the find and the barrier. - - In the above example, we can tell that L3 is within 1k of L1, so - the first move can be shrunk from the 2 insn+constant sequence into - just 1 insn, and the constant moved to L3 to make: - - ldr rn, L1 - .. - ldr rn, L3 - b L4 - align - L1: .long value - L3: .long value - L4: - - Then the second move becomes the target for the shortening process. - - */ - -typedef struct -{ - rtx value; /* Value in table */ - HOST_WIDE_INT next_offset; - enum machine_mode mode; /* Mode of value */ -} pool_node; - -/* The maximum number of constants that can fit into one pool, since - the pc relative range is 0...1020 bytes and constants are at least 4 - bytes long */ - -#define MAX_POOL_SIZE (1020/4) -static pool_node pool_vector[MAX_POOL_SIZE]; -static int pool_size; -static rtx pool_vector_label; - -/* Add a constant to the pool and return its label. */ - -static HOST_WIDE_INT -add_constant (x, mode) - rtx x; - enum machine_mode mode; -{ - int i; - rtx lab; - HOST_WIDE_INT offset; - - if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0)) - && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) - x = get_pool_constant (XEXP (x, 0)); - - /* First see if we've already got it */ - - for (i = 0; i < pool_size; i++) - { - if (x->code == pool_vector[i].value->code - && mode == pool_vector[i].mode) - { - if (x->code == CODE_LABEL) - { - if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) - continue; - } - if (rtx_equal_p (x, pool_vector[i].value)) - return pool_vector[i].next_offset - GET_MODE_SIZE (mode); - } - } - - /* Need a new one */ - - pool_vector[pool_size].next_offset = GET_MODE_SIZE (mode); - offset = 0; - if (pool_size == 0) - pool_vector_label = gen_label_rtx (); - else - pool_vector[pool_size].next_offset - += (offset = pool_vector[pool_size - 1].next_offset); - - pool_vector[pool_size].value = x; - pool_vector[pool_size].mode = mode; - pool_size++; - return offset; -} - -/* Output the literal table */ - -static void -dump_table (scan) - rtx scan; -{ - int i; - - scan = emit_label_after (gen_label_rtx (), scan); - scan = emit_insn_after (gen_align_4 (), scan); - scan = emit_label_after (pool_vector_label, scan); - - for (i = 0; i < pool_size; i++) - { - pool_node *p = pool_vector + i; - - switch (GET_MODE_SIZE (p->mode)) - { - case 4: - scan = emit_insn_after (gen_consttable_4 (p->value), scan); - break; - - case 8: - scan = emit_insn_after (gen_consttable_8 (p->value), scan); - break; - - default: - abort (); - break; - } - } - - scan = emit_insn_after (gen_consttable_end (), scan); - scan = emit_barrier_after (scan); - pool_size = 0; -} - -/* Non zero if the src operand needs to be fixed up */ -static -int -fixit (src, mode) - rtx src; - enum machine_mode mode; -{ - return ((CONSTANT_P (src) - && (GET_CODE (src) != CONST_INT - || ! (CONST_OK_FOR_LETTER_P (INTVAL (src), 'I') - || CONST_OK_FOR_LETTER_P (INTVAL (src), 'J') - || (mode != DImode - && CONST_OK_FOR_LETTER_P (INTVAL (src), 'K'))))) - || (mode == SImode && GET_CODE (src) == MEM - && GET_CODE (XEXP (src, 0)) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (XEXP (src, 0)))); -} - -/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one. */ - -#define MAX_COUNT_SI 1000 - -static rtx -find_barrier (from) - rtx from; -{ - int count = 0; - rtx found_barrier = 0; - rtx label; - - while (from && count < MAX_COUNT_SI) - { - if (GET_CODE (from) == BARRIER) - return from; - - /* Count the length of this insn */ - if (GET_CODE (from) == INSN - && GET_CODE (PATTERN (from)) == SET - && CONSTANT_P (SET_SRC (PATTERN (from))) - && CONSTANT_POOL_ADDRESS_P (SET_SRC (PATTERN (from)))) - { - rtx src = SET_SRC (PATTERN (from)); - count += 2; - } - else - count += get_attr_length (from); - - from = NEXT_INSN (from); - } - - /* We didn't find a barrier in time to - dump our stuff, so we'll make one */ - label = gen_label_rtx (); - - if (from) - from = PREV_INSN (from); - else - from = get_last_insn (); - - /* Walk back to be just before any jump */ - while (GET_CODE (from) == JUMP_INSN - || GET_CODE (from) == NOTE - || GET_CODE (from) == CODE_LABEL) - from = PREV_INSN (from); - - from = emit_jump_insn_after (gen_jump (label), from); - JUMP_LABEL (from) = label; - found_barrier = emit_barrier_after (from); - emit_label_after (label, found_barrier); - return found_barrier; -} - -/* Non zero if the insn is a move instruction which needs to be fixed. */ - -static int -broken_move (insn) - rtx insn; -{ - if (!INSN_DELETED_P (insn) - && GET_CODE (insn) == INSN - && GET_CODE (PATTERN (insn)) == SET) - { - rtx pat = PATTERN (insn); - rtx src = SET_SRC (pat); - rtx dst = SET_DEST (pat); - enum machine_mode mode = GET_MODE (dst); - if (dst == pc_rtx) - return 0; - return fixit (src, mode); - } - return 0; -} - -/* Recursively search through all of the blocks in a function - checking to see if any of the variables created in that - function match the RTX called 'orig'. If they do then - replace them with the RTX called 'new'. */ - -static void -replace_symbols_in_block (tree block, rtx orig, rtx new) -{ - for (; block; block = BLOCK_CHAIN (block)) - { - tree sym; - - if (! TREE_USED (block)) - continue; - - for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym)) - { - if ( (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL) - || DECL_IGNORED_P (sym) - || TREE_CODE (sym) != VAR_DECL - || DECL_EXTERNAL (sym) - || ! rtx_equal_p (DECL_RTL (sym), orig) - ) - continue; - - DECL_RTL (sym) = new; - } - - replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new); - } -} - -void -thumb_reorg (first) - rtx first; -{ - rtx insn; - for (insn = first; insn; insn = NEXT_INSN (insn)) - { - if (broken_move (insn)) - { - /* This is a broken move instruction, scan ahead looking for - a barrier to stick the constant table behind */ - rtx scan; - rtx barrier = find_barrier (insn); - - /* Now find all the moves between the points and modify them */ - for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) - { - if (broken_move (scan)) - { - /* This is a broken move instruction, add it to the pool */ - rtx pat = PATTERN (scan); - rtx src = SET_SRC (pat); - rtx dst = SET_DEST (pat); - enum machine_mode mode = GET_MODE (dst); - HOST_WIDE_INT offset; - rtx newinsn; - rtx newsrc; - - /* If this is an HImode constant load, convert it into - an SImode constant load. Since the register is always - 32 bits this is safe. We have to do this, since the - load pc-relative instruction only does a 32-bit load. */ - if (mode == HImode) - { - mode = SImode; - if (GET_CODE (dst) != REG) - abort (); - PUT_MODE (dst, SImode); - } - - offset = add_constant (src, mode); - newsrc = gen_rtx (MEM, mode, - plus_constant (gen_rtx (LABEL_REF, - VOIDmode, - pool_vector_label), - offset)); - - /* Build a jump insn wrapper around the move instead - of an ordinary insn, because we want to have room for - the target label rtx in fld[7], which an ordinary - insn doesn't have. */ - newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode, - dst, newsrc), scan); - JUMP_LABEL (newinsn) = pool_vector_label; - - /* But it's still an ordinary insn */ - PUT_CODE (newinsn, INSN); - - /* If debugging information is going to be emitted - then we must make sure that any refences to - symbols which are removed by the above code are - also removed in the descriptions of the - function's variables. Failure to do this means - that the debugging information emitted could - refer to symbols which are not emited by - output_constant_pool() because - mark_constant_pool() never sees them as being - used. */ - - - /* These are the tests used in - output_constant_pool() to decide if the constant - pool will be marked. Only necessary if debugging - info is being emitted. Only necessary for - references to memory whose address is given by a - symbol. */ - - if (optimize > 0 - && flag_expensive_optimizations - && write_symbols != NO_DEBUG - && GET_CODE (src) == MEM - && GET_CODE (XEXP (src, 0)) == SYMBOL_REF) - replace_symbols_in_block - (DECL_INITIAL (current_function_decl), src, newsrc); - - /* Kill old insn */ - delete_insn (scan); - scan = newinsn; - } - } - dump_table (barrier); - } - } -} - - -/* Routines for generating rtl */ - -void -thumb_expand_movstrqi (operands) - rtx *operands; -{ - rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); - rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); - HOST_WIDE_INT len = INTVAL (operands[2]); - HOST_WIDE_INT offset = 0; - - while (len >= 12) - { - emit_insn (gen_movmem12b (out, in)); - len -= 12; - } - if (len >= 8) - { - emit_insn (gen_movmem8b (out, in)); - len -= 8; - } - if (len >= 4) - { - rtx reg = gen_reg_rtx (SImode); - emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in))); - emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg)); - len -= 4; - offset += 4; - } - if (len >= 2) - { - rtx reg = gen_reg_rtx (HImode); - emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode, - plus_constant (in, offset)))); - emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)), - reg)); - len -= 2; - offset += 2; - } - if (len) - { - rtx reg = gen_reg_rtx (QImode); - emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode, - plus_constant (in, offset)))); - emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)), - reg)); - } -} - - -/* Routines for reloading */ - -void -thumb_reload_out_si (operands) - rtx operands; -{ - abort (); -} - -/* CYGNUS LOCAL nickc/thumb-pe */ - -#ifdef THUMB_PE -/* Return non-zero if FUNC is a naked function. */ - -static int -arm_naked_function_p (func) - tree func; -{ - tree a; - - if (TREE_CODE (func) != FUNCTION_DECL) - abort (); - - a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); - return a != NULL_TREE; -} -#endif -/* END CYGNUS LOCAL nickc/thumb-pe */ - -/* Return non-zero if FUNC must be entered in ARM mode. */ -int -is_called_in_ARM_mode (func) - tree func; -{ - if (TREE_CODE (func) != FUNCTION_DECL) - abort (); - - /* Ignore the problem about functions whoes address is taken. */ - if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func)) - return TRUE; - -/* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; -#else - return FALSE; -#endif -/* END CYGNUS LOCAL */ -} - - -/* Routines for emitting code */ - -void -final_prescan_insn(insn) - rtx insn; -{ - extern int *insn_addresses; - - if (flag_print_asm_name) - fprintf (asm_out_file, "%s 0x%04x\n", ASM_COMMENT_START, - insn_addresses[INSN_UID (insn)]); -} - - -static void thumb_pushpop ( FILE *, int, int ); /* Forward declaration. */ - -#ifdef __GNUC__ -inline -#endif -static int -number_of_first_bit_set (mask) - int mask; -{ - int bit; - - for (bit = 0; - (mask & (1 << bit)) == 0; - ++ bit) - continue; - - return bit; -} - -#define ARG_1_REGISTER 0 -#define ARG_2_REGISTER 1 -#define ARG_3_REGISTER 2 -#define ARG_4_REGISTER 3 -#define WORK_REGISTER 7 -#define FRAME_POINTER 11 -#define IP_REGISTER 12 -#define STACK_POINTER STACK_POINTER_REGNUM -#define LINK_REGISTER 14 -#define PROGRAM_COUNTER 15 - -/* Generate code to return from a thumb function. If - 'reg_containing_return_addr' is -1, then the return address is - actually on the stack, at the stack pointer. */ -static void -thumb_exit (f, reg_containing_return_addr) - FILE * f; - int reg_containing_return_addr; -{ - int regs_available_for_popping; - int regs_to_pop; - int pops_needed; - int reg; - int available; - int required; - int mode; - int size; - int restore_a4 = FALSE; - - /* Compute the registers we need to pop. */ - regs_to_pop = 0; - pops_needed = 0; - - if (reg_containing_return_addr == -1) - { - regs_to_pop |= 1 << LINK_REGISTER; - ++ pops_needed; - } - - if (TARGET_BACKTRACE) - { - /* Restore frame pointer and stack pointer. */ - regs_to_pop |= (1 << FRAME_POINTER) | (1 << STACK_POINTER); - pops_needed += 2; - } - - /* If there is nothing to pop then just emit the BX instruction and return.*/ - if (pops_needed == 0) - { - asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); - - return; - } - - /* Otherwise if we are not supporting interworking and we have not created - a backtrace structure and the function was not entered in ARM mode then - just pop the return address straight into the PC. */ - else if ( ! TARGET_THUMB_INTERWORK - && ! TARGET_BACKTRACE - && ! is_called_in_ARM_mode (current_function_decl)) - { - asm_fprintf (f, "\tpop\t{pc}\n" ); - - return; - } - - /* Find out how many of the (return) argument registers we can corrupt. */ - regs_available_for_popping = 0; - -#ifdef RTX_CODE - /* If we can deduce the registers used from the function's return value. - This is more reliable that examining regs_ever_live[] because that - will be set if the register is ever used in the function, not just if - the register is used to hold a return value. */ - - if (current_function_return_rtx != 0) - mode = GET_MODE (current_function_return_rtx); - else -#endif - mode = DECL_MODE (DECL_RESULT (current_function_decl)); - - size = GET_MODE_SIZE (mode); - - if (size == 0) - { - /* In a void function we can use any argument register. - In a function that returns a structure on the stack - we can use the second and third argument registers. */ - if (mode == VOIDmode) - regs_available_for_popping = - (1 << ARG_1_REGISTER) - | (1 << ARG_2_REGISTER) - | (1 << ARG_3_REGISTER); - else - regs_available_for_popping = - (1 << ARG_2_REGISTER) - | (1 << ARG_3_REGISTER); - } - else if (size <= 4) regs_available_for_popping = - (1 << ARG_2_REGISTER) - | (1 << ARG_3_REGISTER); - else if (size <= 8) regs_available_for_popping = - (1 << ARG_3_REGISTER); - - /* Match registers to be popped with registers into which we pop them. */ - for (available = regs_available_for_popping, - required = regs_to_pop; - required != 0 && available != 0; - available &= ~(available & - available), - required &= ~(required & - required)) - -- pops_needed; - - /* If we have any popping registers left over, remove them. */ - if (available > 0) - regs_available_for_popping &= ~ available; - - /* Otherwise if we need another popping register we can use - the fourth argument register. */ - else if (pops_needed) - { - /* If we have not found any free argument registers and - reg a4 contains the return address, we must move it. */ - if (regs_available_for_popping == 0 - && reg_containing_return_addr == ARG_4_REGISTER) - { - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); - reg_containing_return_addr = LINK_REGISTER; - } - else if (size > 12) - { - /* Register a4 is being used to hold part of the return value, - but we have dire need of a free, low register. */ - restore_a4 = TRUE; - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [IP_REGISTER], reg_names [ARG_4_REGISTER]); - } - - if (reg_containing_return_addr != ARG_4_REGISTER) - { - /* The fourth argument register is available. */ - regs_available_for_popping |= 1 << ARG_4_REGISTER; - - -- pops_needed; - } - } - - /* Pop as many registers as we can. */ - thumb_pushpop (f, regs_available_for_popping, FALSE); - - /* Process the registers we popped. */ - if (reg_containing_return_addr == -1) - { - /* The return address was popped into the lowest numbered register. */ - regs_to_pop &= ~ (1 << LINK_REGISTER); - - reg_containing_return_addr = - number_of_first_bit_set (regs_available_for_popping); - - /* Remove this register for the mask of available registers, so that - the return address will not be corrupted by futher pops. */ - regs_available_for_popping &= ~ (1 << reg_containing_return_addr); - } - - /* If we popped other registers then handle them here. */ - if (regs_available_for_popping) - { - int frame_pointer; - - /* Work out which register currently contains the frame pointer. */ - frame_pointer = number_of_first_bit_set (regs_available_for_popping); - - /* Move it into the correct place. */ - asm_fprintf (f, "\tmov\tfp, %s\n", reg_names [frame_pointer]); - - /* (Temporarily) remove it from the mask of popped registers. */ - regs_available_for_popping &= ~ (1 << frame_pointer); - regs_to_pop &= ~ (1 << FRAME_POINTER); - - if (regs_available_for_popping) - { - int stack_pointer; - - /* We popped the stack pointer as well, find the register that - contains it.*/ - stack_pointer = number_of_first_bit_set (regs_available_for_popping); - - /* Move it into the stack register. */ - asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [stack_pointer]); - - /* At this point we have popped all necessary registers, so - do not worry about restoring regs_available_for_popping - to its correct value: - - assert (pops_needed == 0) - assert (regs_available_for_popping == (1 << frame_pointer)) - assert (regs_to_pop == (1 << STACK_POINTER)) */ - } - else - { - /* Since we have just move the popped value into the frame - pointer, the popping register is available for reuse, and - we know that we still have the stack pointer left to pop. */ - regs_available_for_popping |= (1 << frame_pointer); - } - } - - /* If we still have registers left on the stack, but we no longer have - any registers into which we can pop them, then we must move the return - address into the link register and make available the register that - contained it. */ - if (regs_available_for_popping == 0 && pops_needed > 0) - { - regs_available_for_popping |= 1 << reg_containing_return_addr; - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [LINK_REGISTER], - reg_names [reg_containing_return_addr]); - - reg_containing_return_addr = LINK_REGISTER; - } - - /* If we have registers left on the stack then pop some more. - We know that at most we will want to pop FP and SP. */ - if (pops_needed > 0) - { - int popped_into; - int move_to; - - thumb_pushpop (f, regs_available_for_popping, FALSE); - - /* We have popped either FP or SP. - Move whichever one it is into the correct register. */ - popped_into = number_of_first_bit_set (regs_available_for_popping); - move_to = number_of_first_bit_set (regs_to_pop); - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [move_to], reg_names [popped_into]); - - regs_to_pop &= ~ (1 << move_to); - - -- pops_needed; - } - - /* If we still have not popped everything then we must have only - had one register available to us and we are now popping the SP. */ - if (pops_needed > 0) - { - int popped_into; - - thumb_pushpop (f, regs_available_for_popping, FALSE); - - popped_into = number_of_first_bit_set (regs_available_for_popping); - - asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [popped_into]); - - /* - assert (regs_to_pop == (1 << STACK_POINTER)) - assert (pops_needed == 1) - */ - } - - /* If necessary restore the a4 register. */ - if (restore_a4) - { - if (reg_containing_return_addr != LINK_REGISTER) - { - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); - reg_containing_return_addr = LINK_REGISTER; - } - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [ARG_4_REGISTER], reg_names [IP_REGISTER]); - } - - /* Return to caller. */ - asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); -} - -/* Emit code to push or pop registers to or from the stack. */ -static void -thumb_pushpop (f, mask, push) - FILE * f; - int mask; - int push; -{ - int regno; - int lo_mask = mask & 0xFF; - - if (lo_mask == 0 && ! push && (mask & (1 << 15))) - { - /* Special case. Do not generate a POP PC statement here, do it in - thumb_exit() */ - - thumb_exit (f, -1); - return; - } - - asm_fprintf (f, "\t%s\t{", push ? "push" : "pop"); - - /* Look at the low registers first. */ - - for (regno = 0; regno < 8; regno ++, lo_mask >>= 1) - { - if (lo_mask & 1) - { - asm_fprintf (f, reg_names[regno]); - - if ((lo_mask & ~1) != 0) - asm_fprintf (f, ", "); - } - } - - if (push && (mask & (1 << 14))) - { - /* Catch pushing the LR. */ - - if (mask & 0xFF) - asm_fprintf (f, ", "); - - asm_fprintf (f, reg_names[14]); - } - else if (!push && (mask & (1 << 15))) - { - /* Catch popping the PC. */ - - if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) - { - /* The PC is never poped directly, instead - it is popped into r3 and then BX is used. */ - - asm_fprintf (f, "}\n"); - - thumb_exit (f, -1); - - return; - } - else - { - if (mask & 0xFF) - asm_fprintf (f, ", "); - - asm_fprintf (f, reg_names[15]); - } - } - - asm_fprintf (f, "}\n"); -} - -/* Returns non-zero if the current function contains a far jump */ - -int -far_jump_used_p (void) -{ - rtx insn; - - if (current_function_has_far_jump) - return 1; - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (GET_CODE (insn) == JUMP_INSN - /* Ignore tablejump patterns. */ - && GET_CODE (PATTERN (insn)) != ADDR_VEC - && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC - && get_attr_far_jump (insn) == FAR_JUMP_YES) - { - current_function_has_far_jump = 1; - return 1; - } - } - - return 0; -} - -static int return_used_this_function = 0; - -char * -output_return () -{ - int regno; - int live_regs_mask = 0; - - /* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - /* If a function is naked, don't use the "return" insn. */ - if (arm_naked_function_p (current_function_decl)) - return ""; -#endif - /* END CYGNUS LOCAL nickc/thumb-pe */ - - return_used_this_function = 1; - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - if (live_regs_mask == 0) - { - if (leaf_function_p () && ! far_jump_used_p()) - { - thumb_exit (asm_out_file, 14); - } - else if ( TARGET_THUMB_INTERWORK - || TARGET_BACKTRACE - || is_called_in_ARM_mode (current_function_decl)) - { - thumb_exit (asm_out_file, -1); - } - else - asm_fprintf (asm_out_file, "\tpop\t{pc}\n"); - } - else - { - asm_fprintf (asm_out_file, "\tpop\t{"); - - for (regno = 0; live_regs_mask; regno ++, live_regs_mask >>= 1) - if (live_regs_mask & 1) - { - asm_fprintf (asm_out_file, reg_names[regno]); - if (live_regs_mask & ~1) - asm_fprintf (asm_out_file, ", "); - } - - if ( TARGET_THUMB_INTERWORK - || TARGET_BACKTRACE - || is_called_in_ARM_mode (current_function_decl)) - { - asm_fprintf (asm_out_file, "}\n"); - thumb_exit (asm_out_file, -1); - } - else - asm_fprintf (asm_out_file, ", pc}\n"); - } - - return ""; -} - -void -thumb_function_prologue (f, frame_size) - FILE *f; - int frame_size; -{ - int amount = frame_size + current_function_outgoing_args_size; - int live_regs_mask = 0; - int high_regs_pushed = 0; - int store_arg_regs = 0; - int regno; - -/* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - if (arm_naked_function_p (current_function_decl)) - return; -#endif -/* CYGNUS LOCAL nickc/thumb-pe */ - - if (is_called_in_ARM_mode (current_function_decl)) - { - char * name; - if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) - abort(); - if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) - abort(); - name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); - - /* Generate code sequence to switch us into Thumb mode. */ - /* The .code 32 directive has already been emitted by - ASM_DECLARE_FUNCITON_NAME */ - asm_fprintf (f, "\torr\tr12, pc, #1\n"); - asm_fprintf (f, "\tbx\tr12\n"); - - /* Generate a label, so that the debugger will notice the - change in instruction sets. This label is also used by - the assembler to bypass the ARM code when this function - is called from a Thumb encoded function elsewhere in the - same file. Hence the definition of STUB_NAME here must - agree with the definition in gas/config/tc-arm.c */ - -#define STUB_NAME ".real_start_of" - - asm_fprintf (f, "\t.code\t16\n"); - asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); - asm_fprintf (f, "\t.thumb_func\n"); - asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); - } - - if (current_function_anonymous_args && current_function_pretend_args_size) - store_arg_regs = 1; - - if (current_function_pretend_args_size) - { - if (store_arg_regs) - { - asm_fprintf (f, "\tpush\t{"); - for (regno = 4 - current_function_pretend_args_size / 4 ; regno < 4; - regno++) - asm_fprintf (f, "%s%s", reg_names[regno], regno == 3 ? "" : ", "); - asm_fprintf (f, "}\n"); - } - else - asm_fprintf (f, "\tsub\t%Rsp, %Rsp, #%d\n", - current_function_pretend_args_size); - } - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - if (live_regs_mask || ! leaf_function_p () || far_jump_used_p()) - live_regs_mask |= 1 << 14; - - if (TARGET_BACKTRACE) - { - char * name; - int offset; - int work_register = 0; - - - /* We have been asked to create a stack backtrace structure. - The code looks like this: - - 0 .align 2 - 0 func: - 0 sub SP, #16 Reserve space for 4 registers. - 2 push {R7} Get a work register. - 4 add R7, SP, #20 Get the stack pointer before the push. - 6 str R7, [SP, #8] Store the stack pointer (before reserving the space). - 8 mov R7, PC Get hold of the start of this code plus 12. - 10 str R7, [SP, #16] Store it. - 12 mov R7, FP Get hold of the current frame pointer. - 14 str R7, [SP, #4] Store it. - 16 mov R7, LR Get hold of the current return address. - 18 str R7, [SP, #12] Store it. - 20 add R7, SP, #16 Point at the start of the backtrace structure. - 22 mov FP, R7 Put this value into the frame pointer. */ - - if ((live_regs_mask & 0xFF) == 0) - { - /* See if the a4 register is free. */ - - if (regs_ever_live[ 3 ] == 0) - work_register = 3; - else /* We must push a register of our own */ - live_regs_mask |= (1 << 7); - } - - if (work_register == 0) - { - /* Select a register from the list that will be pushed to use as our work register. */ - - for (work_register = 8; work_register--;) - if ((1 << work_register) & live_regs_mask) - break; - } - - name = reg_names[ work_register ]; - - asm_fprintf (f, "\tsub\tsp, sp, #16\t@ Create stack backtrace structure\n"); - - if (live_regs_mask) - thumb_pushpop (f, live_regs_mask, 1); - - for (offset = 0, work_register = 1 << 15; work_register; work_register >>= 1) - if (work_register & live_regs_mask) - offset += 4; - - asm_fprintf (f, "\tadd\t%s, sp, #%d\n", - name, offset + 16 + current_function_pretend_args_size); - - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 4); - - /* Make sure that the instruction fetching the PC is in the right place - to calculate "start of backtrace creation code + 12". */ - - if (live_regs_mask) - { - asm_fprintf (f, "\tmov\t%s, pc\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); - asm_fprintf (f, "\tmov\t%s, fp\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); - } - else - { - asm_fprintf (f, "\tmov\t%s, fp\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); - asm_fprintf (f, "\tmov\t%s, pc\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); - } - - asm_fprintf (f, "\tmov\t%s, lr\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 8); - asm_fprintf (f, "\tadd\t%s, sp, #%d\n", name, offset + 12); - asm_fprintf (f, "\tmov\tfp, %s\t\t@ Backtrace structure created\n", name); - } - else if (live_regs_mask) - thumb_pushpop (f, live_regs_mask, 1); - - for (regno = 8; regno < 13; regno++) - { - if (regs_ever_live[regno] && ! call_used_regs[regno]) - high_regs_pushed++; - } - - if (high_regs_pushed) - { - int pushable_regs = 0; - int mask = live_regs_mask & 0xff; - int next_hi_reg; - - for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--) - { - if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) - break; - } - - pushable_regs = mask; - - if (pushable_regs == 0) - { - /* desperation time -- this probably will never happen */ - if (regs_ever_live[3] || ! call_used_regs[3]) - asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[12], reg_names[3]); - mask = 1 << 3; - } - - while (high_regs_pushed > 0) - { - for (regno = 7; regno >= 0; regno--) - { - if (mask & (1 << regno)) - { - asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[regno], - reg_names[next_hi_reg]); - high_regs_pushed--; - if (high_regs_pushed) - for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--) - { - if (regs_ever_live[next_hi_reg] - && ! call_used_regs[next_hi_reg]) - break; - } - else - { - mask &= ~ ((1 << regno) - 1); - break; - } - } - } - thumb_pushpop (f, mask, 1); - } - - if (pushable_regs == 0 && (regs_ever_live[3] || ! call_used_regs[3])) - asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[3], reg_names[12]); - } -} - -void -thumb_expand_prologue () -{ - HOST_WIDE_INT amount = (get_frame_size () - + current_function_outgoing_args_size); - int regno; - int live_regs_mask; - - /* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - /* Naked functions don't have prologues. */ - if (arm_naked_function_p (current_function_decl)) - return; -#endif - /* END CYGNUS LOCAL nickc/thumb-pe */ - - if (amount) - { - live_regs_mask = 0; - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - if (amount < 512) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (-amount))); - else - { - rtx reg, spare; - - if ((live_regs_mask & 0xff) == 0) /* Very unlikely */ - emit_insn (gen_movsi (spare = gen_rtx (REG, SImode, 12), - reg = gen_rtx (REG, SImode, 4))); - else - { - for (regno = 0; regno < 8; regno++) - if (live_regs_mask & (1 << regno)) - break; - reg = gen_rtx (REG, SImode, regno); - } - - emit_insn (gen_movsi (reg, GEN_INT (-amount))); - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); - if ((live_regs_mask & 0xff) == 0) - emit_insn (gen_movsi (reg, spare)); - } - } - - if (frame_pointer_needed) - { - if (current_function_outgoing_args_size) - { - rtx offset = GEN_INT (current_function_outgoing_args_size); - - if (current_function_outgoing_args_size < 1024) - emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, - offset)); - else - { - emit_insn (gen_movsi (frame_pointer_rtx, offset)); - emit_insn (gen_addsi3 (frame_pointer_rtx, frame_pointer_rtx, - stack_pointer_rtx)); - } - } - else - emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); - } - - /* if (profile_flag || profile_block_flag) */ - emit_insn (gen_blockage ()); -} - -void -thumb_expand_epilogue () -{ - HOST_WIDE_INT amount = (get_frame_size () - + current_function_outgoing_args_size); - int regno; - - /* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - /* Naked functions don't have epilogues. */ - if (arm_naked_function_p (current_function_decl)) - return; -#endif - /* END CYGNUS LOCAL nickc/thumb-pe */ - - if (amount) - { - if (amount < 512) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (amount))); - else - { - rtx reg = gen_rtx (REG, SImode, 3); /* Always free in the epilogue */ - - emit_insn (gen_movsi (reg, GEN_INT (amount))); - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); - } - /* if (profile_flag || profile_block_flag) */ - emit_insn (gen_blockage ()); - } -} - -void -thumb_function_epilogue (f, frame_size) - FILE *f; - int frame_size; -{ - /* ??? Probably not safe to set this here, since it assumes that a - function will be emitted as assembly immediately after we generate - RTL for it. This does not happen for inline functions. */ - return_used_this_function = 0; - current_function_has_far_jump = 0; -#if 0 /* TODO : comment not really needed */ - fprintf (f, "%s THUMB Epilogue\n", ASM_COMMENT_START); -#endif -} - -/* The bits which aren't usefully expanded as rtl. */ -char * -thumb_unexpanded_epilogue () -{ - int regno; - int live_regs_mask = 0; - int high_regs_pushed = 0; - int leaf_function = leaf_function_p (); - int had_to_push_lr; - - if (return_used_this_function) - return ""; - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - for (regno = 8; regno < 13; regno++) - { - if (regs_ever_live[regno] && ! call_used_regs[regno]) - high_regs_pushed ++; - } - - /* The prolog may have pushed some high registers to use as - work registers. eg the testuite file: - gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c - compiles to produce: - push {r4, r5, r6, r7, lr} - mov r7, r9 - mov r6, r8 - push {r6, r7} - as part of the prolog. We have to undo that pushing here. */ - - if (high_regs_pushed) - { - int mask = live_regs_mask; - int next_hi_reg; - int size; - int mode; - -#ifdef RTX_CODE - /* If we can deduce the registers used from the function's return value. - This is more reliable that examining regs_ever_live[] because that - will be set if the register is ever used in the function, not just if - the register is used to hold a return value. */ - - if (current_function_return_rtx != 0) - { - mode = GET_MODE (current_function_return_rtx); - } - else -#endif - { - mode = DECL_MODE (DECL_RESULT (current_function_decl)); - } - - size = GET_MODE_SIZE (mode); - - /* Unless we are returning a type of size > 12 register r3 is available. */ - if (size < 13) - mask |= 1 << 3; - - if (mask == 0) - { - /* Oh dear! We have no low registers into which we can pop high registers! */ - - fatal ("No low registers available for popping high registers"); - } - - for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++) - if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) - break; - - while (high_regs_pushed) - { - /* Find low register(s) into which the high register(s) can be popped. */ - for (regno = 0; regno < 8; regno++) - { - if (mask & (1 << regno)) - high_regs_pushed--; - if (high_regs_pushed == 0) - break; - } - - mask &= (2 << regno) - 1; /* A noop if regno == 8 */ - - /* Pop the values into the low register(s). */ - thumb_pushpop (asm_out_file, mask, 0); - - /* Move the value(s) into the high registers. */ - for (regno = 0; regno < 8; regno++) - { - if (mask & (1 << regno)) - { - asm_fprintf (asm_out_file, "\tmov\t%s, %s\n", - reg_names[next_hi_reg], reg_names[regno]); - for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++) - if (regs_ever_live[next_hi_reg] && - ! call_used_regs[next_hi_reg]) - break; - } - } - } - } - - had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); - - if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) - { - /* The stack backtrace structure creation code had to - push R7 in order to get a work register, so we pop - it now. */ - - live_regs_mask |= (1 << WORK_REGISTER); - } - - if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) - { - if (had_to_push_lr - && ! is_called_in_ARM_mode (current_function_decl)) - live_regs_mask |= 1 << PROGRAM_COUNTER; - - /* Either no argument registers were pushed or a backtrace - structure was created which includes an adjusted stack - pointer, so just pop everything. */ - - if (live_regs_mask) - thumb_pushpop (asm_out_file, live_regs_mask, FALSE); - - /* We have either just popped the return address into the - PC or it is was kept in LR for the entire function or - it is still on the stack because we do not want to - return by doing a pop {pc}. */ - - if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0) - thumb_exit (asm_out_file, - (had_to_push_lr - && is_called_in_ARM_mode (current_function_decl)) ? - -1 : LINK_REGISTER); - } - else - { - /* Pop everything but the return address. */ - live_regs_mask &= ~ (1 << PROGRAM_COUNTER); - - if (live_regs_mask) - thumb_pushpop (asm_out_file, live_regs_mask, FALSE); - - if (had_to_push_lr) - { - /* Get the return address into a temporary register. */ - thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0); - } - - /* Remove the argument registers that were pushed onto the stack. */ - asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n", - reg_names [STACK_POINTER], - reg_names [STACK_POINTER], - current_function_pretend_args_size); - - thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER); - } - - return ""; -} - -/* Handle the case of a double word load into a low register from - a computed memory address. The computed address may involve a - register which is overwritten by the load. */ - -char * -thumb_load_double_from_address (operands) - rtx * operands; -{ - rtx addr; - rtx base; - rtx offset; - rtx arg1; - rtx arg2; - - if (GET_CODE (operands[0]) != REG) - fatal ("thumb_load_double_from_address: destination is not a register"); - - if (GET_CODE (operands[1]) != MEM) - fatal ("thumb_load_double_from_address: source is not a computed memory address"); - - /* Get the memory address. */ - - addr = XEXP (operands[1], 0); - - /* Work out how the memory address is computed. */ - - switch (GET_CODE (addr)) - { - case REG: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - if (REGNO (operands[0]) == REGNO (addr)) - { - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - } - else - { - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - } - break; - - case CONST: - /* Compute <address> + 4 for the high order load. */ - - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - break; - - case PLUS: - arg1 = XEXP (addr, 0); - arg2 = XEXP (addr, 1); - - if (CONSTANT_P (arg1)) - base = arg2, offset = arg1; - else - base = arg1, offset = arg2; - - if (GET_CODE (base) != REG) - fatal ("thumb_load_double_from_address: base is not a register"); - - /* Catch the case of <address> = <reg> + <reg> */ - - if (GET_CODE (offset) == REG) - { - int reg_offset = REGNO (offset); - int reg_base = REGNO (base); - int reg_dest = REGNO (operands[0]); - - /* Add the base and offset registers together into the higher destination register. */ - - fprintf (asm_out_file, "\tadd\t%s, %s, %s\t\t%s created by thumb_load_double_from_address", - reg_names[ reg_dest + 1 ], - reg_names[ reg_base ], - reg_names[ reg_offset ], - ASM_COMMENT_START); - - /* Load the lower destination register from the address in the higher destination register. */ - - fprintf (asm_out_file, "\tldr\t%s, [%s, #0]\t\t%s created by thumb_load_double_from_address", - reg_names[ reg_dest ], - reg_names[ reg_dest + 1], - ASM_COMMENT_START); - - /* Load the higher destination register from its own address plus 4. */ - - fprintf (asm_out_file, "\tldr\t%s, [%s, #4]\t\t%s created by thumb_load_double_from_address", - reg_names[ reg_dest + 1 ], - reg_names[ reg_dest + 1 ], - ASM_COMMENT_START); - } - else - { - /* Compute <address> + 4 for the high order load. */ - - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - /* If the computed address is held in the low order register - then load the high order register first, otherwise always - load the low order register first. */ - - if (REGNO (operands[0]) == REGNO (base)) - { - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - } - else - { - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - } - } - break; - - case LABEL_REF: - /* With no registers to worry about we can just load the value directly. */ - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - break; - - default: - debug_rtx (operands[1]); - fatal ("thumb_load_double_from_address: Unhandled address calculation"); - break; - } - - return ""; -} - -char * -output_move_mem_multiple (n, operands) - int n; - rtx *operands; -{ - rtx tmp; - - switch (n) - { - case 2: - if (REGNO (operands[2]) > REGNO (operands[3])) - { - tmp = operands[2]; - operands[2] = operands[3]; - operands[3] = tmp; - } - output_asm_insn ("ldmia\t%1!, {%2, %3}", operands); - output_asm_insn ("stmia\t%0!, {%2, %3}", operands); - break; - - case 3: - if (REGNO (operands[2]) > REGNO (operands[3])) - { - tmp = operands[2]; - operands[2] = operands[3]; - operands[3] = tmp; - } - if (REGNO (operands[3]) > REGNO (operands[4])) - { - tmp = operands[3]; - operands[3] = operands[4]; - operands[4] = tmp; - } - if (REGNO (operands[2]) > REGNO (operands[3])) - { - tmp = operands[2]; - operands[2] = operands[3]; - operands[3] = tmp; - } - output_asm_insn ("ldmia\t%1!, {%2, %3, %4}", operands); - output_asm_insn ("stmia\t%0!, {%2, %3, %4}", operands); - break; - - default: - abort (); - } - - return ""; -} - - -int -thumb_epilogue_size () -{ - return 42; /* The answer to .... */ -} - -static char *conds[] = -{ - "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", "gt", "le" -}; - -static char * -thumb_condition_code (x, invert) - rtx x; - int invert; -{ - int val; - - switch (GET_CODE (x)) - { - case EQ: val = 0; break; - case NE: val = 1; break; - case GEU: val = 2; break; - case LTU: val = 3; break; - case GTU: val = 8; break; - case LEU: val = 9; break; - case GE: val = 10; break; - case LT: val = 11; break; - case GT: val = 12; break; - case LE: val = 13; break; - default: - abort (); - } - - return conds[val ^ invert]; -} - -void -thumb_print_operand (f, x, code) - FILE *f; - rtx x; - int code; -{ - if (code) - { - switch (code) - { - case '@': - fputs (ASM_COMMENT_START, f); - return; - - case '_': - fputs (user_label_prefix, f); - return; - - case 'D': - if (x) - fputs (thumb_condition_code (x, 1), f); - return; - - case 'd': - if (x) - fputs (thumb_condition_code (x, 0), f); - return; - - /* An explanation of the 'Q', 'R' and 'H' register operands: - - In a pair of registers containing a DI or DF value the 'Q' - operand returns the register number of the register containing - the least signficant part of the value. The 'R' operand returns - the register number of the register containing the most - significant part of the value. - - The 'H' operand returns the higher of the two register numbers. - On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the - same as the 'Q' operand, since the most signficant part of the - value is held in the lower number register. The reverse is true - on systems where WORDS_BIG_ENDIAN is false. - - The purpose of these operands is to distinguish between cases - where the endian-ness of the values is important (for example - when they are added together), and cases where the endian-ness - is irrelevant, but the order of register operations is important. - For example when loading a value from memory into a register - pair, the endian-ness does not matter. Provided that the value - from the lower memory address is put into the lower numbered - register, and the value from the higher address is put into the - higher numbered register, the load will work regardless of whether - the value being loaded is big-wordian or little-wordian. The - order of the two register loads can matter however, if the address - of the memory location is actually held in one of the registers - being overwritten by the load. */ - case 'Q': - if (REGNO (x) > 15) - abort (); - fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], f); - return; - - case 'R': - if (REGNO (x) > 15) - abort (); - fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], f); - return; - - case 'H': - if (REGNO (x) > 15) - abort (); - fputs (reg_names[REGNO (x) + 1], f); - return; - - case 'c': - /* We use 'c' operands with symbols for .vtinherit */ - if (GET_CODE (x) == SYMBOL_REF) - output_addr_const(f, x); - return; - - default: - abort (); - } - } - if (GET_CODE (x) == REG) - fputs (reg_names[REGNO (x)], f); - else if (GET_CODE (x) == MEM) - output_address (XEXP (x, 0)); - else if (GET_CODE (x) == CONST_INT) - { - fputc ('#', f); - output_addr_const (f, x); - } - else - abort (); -} - -#ifdef AOF_ASSEMBLER -int arm_text_section_count = 1; - -char * -aof_text_section (in_readonly) - int in_readonly; -{ - static char buf[100]; - if (in_readonly) - return ""; - sprintf (buf, "\tCODE16\n\tAREA |C$$code%d|, CODE, READONLY", - arm_text_section_count++); - return buf; -} - -static int arm_data_section_count = 1; - -char * -aof_data_section () -{ - static char buf[100]; - sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++); - return buf; -} - -/* The AOF thumb assembler is religiously strict about declarations of - imported and exported symbols, so that it is impossible to declare a - function as imported near the begining of the file, and then to export - it later on. It is, however, possible to delay the decision until all - the functions in the file have been compiled. To get around this, we - maintain a list of the imports and exports, and delete from it any that - are subsequently defined. At the end of compilation we spit the - remainder of the list out before the END directive. */ - -struct import -{ - struct import *next; - char *name; -}; - -static struct import *imports_list = NULL; - -void -thumb_aof_add_import (name) - char *name; -{ - struct import *new; - - for (new = imports_list; new; new = new->next) - if (new->name == name) - return; - - new = (struct import *) xmalloc (sizeof (struct import)); - new->next = imports_list; - imports_list = new; - new->name = name; -} - -void -thumb_aof_delete_import (name) - char *name; -{ - struct import **old; - - for (old = &imports_list; *old; old = & (*old)->next) - { - if ((*old)->name == name) - { - *old = (*old)->next; - return; - } - } -} - -void -thumb_aof_dump_imports (f) - FILE *f; -{ - while (imports_list) - { - fprintf (f, "\tIMPORT\t"); - assemble_name (f, imports_list->name); - fputc ('\n', f); - imports_list = imports_list->next; - } -} -#endif - -/* Decide whether a type should be returned in memory (true) - or in a register (false). This is called by the macro - RETURN_IN_MEMORY. */ - -int -thumb_return_in_memory (type) - tree type; -{ - if (! AGGREGATE_TYPE_P (type)) - { - /* All simple types are returned in registers. */ - - return 0; - } - else if (int_size_in_bytes (type) > 4) - { - /* All structures/unions bigger than one word are returned in memory. */ - - return 1; - } - else if (TREE_CODE (type) == RECORD_TYPE) - { - tree field; - - /* For a struct the APCS says that we must return in a register if - every addressable element has an offset of zero. For practical - purposes this means that the structure can have at most one non- - bit-field element and that this element must be the first one in - the structure. */ - - /* Find the first field, ignoring non FIELD_DECL things which will - have been created by C++. */ - for (field = TYPE_FIELDS (type); - field && TREE_CODE (field) != FIELD_DECL; - field = TREE_CHAIN (field)) - continue; - - if (field == NULL) - return 0; /* An empty structure. Allowed by an extension to ANSI C. */ - - /* Now check the remaining fields, if any. */ - for (field = TREE_CHAIN (field); field; field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) != FIELD_DECL) - continue; - - if (! DECL_BIT_FIELD_TYPE (field)) - return 1; - } - - return 0; - } - else if (TREE_CODE (type) == UNION_TYPE) - { - tree field; - - /* Unions can be returned in registers if every element is - integral, or can be returned in an integer register. */ - - for (field = TYPE_FIELDS (type); - field; - field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) != FIELD_DECL) - continue; - - if (RETURN_IN_MEMORY (TREE_TYPE (field))) - return 1; - } - - return 0; - } - /* XXX Not sure what should be done for other aggregates, so put them in - memory. */ - return 1; -} - -void -thumb_override_options () -{ - if (structure_size_string != NULL) - { - int size = strtol (structure_size_string, NULL, 0); - - if (size == 8 || size == 32) - arm_structure_size_boundary = size; - else - warning ("Structure size boundary can only be set to 8 or 32"); - } - - if (flag_pic) - { - warning ("Position independent code not supported. Ignored"); - flag_pic = 0; - } -} - -/* CYGNUS LOCAL nickc/thumb-pe */ - -#ifdef THUMB_PE -/* Return nonzero if ATTR is a valid attribute for DECL. - ATTRIBUTES are any existing attributes and ARGS are the arguments - supplied with ATTR. - - Supported attributes: - - naked: don't output any prologue or epilogue code, the user is assumed - to do the right thing. - - interfacearm: Always assume that this function will be entered in ARM - mode, not Thumb mode, and that the caller wishes to be returned to in - ARM mode. */ -int -arm_valid_machine_decl_attribute (decl, attributes, attr, args) - tree decl; - tree attributes; - tree attr; - tree args; -{ - if (args != NULL_TREE) - return 0; - - if (is_attribute_p ("naked", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; - - if (is_attribute_p ("interfacearm", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; - - return 0; -} -#endif /* THUMB_PE */ -/* END CYGNUS LOCAL nickc/thumb-pe */ - -/* s_register_operand is the same as register_operand, but it doesn't accept - (SUBREG (MEM)...). - - This function exists because at the time it was put in it led to better - code. SUBREG(MEM) always needs a reload in the places where - s_register_operand is used, and this seemed to lead to excessive - reloading. */ - -int -s_register_operand (op, mode) - register rtx op; - enum machine_mode mode; -{ - if (GET_MODE (op) != mode && mode != VOIDmode) - return 0; - - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - - /* We don't consider registers whose class is NO_REGS - to be a register operand. */ - /* XXX might have to check for lo regs only for thumb ??? */ - return (GET_CODE (op) == REG - && (REGNO (op) >= FIRST_PSEUDO_REGISTER - || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); -} diff --git a/gcc/config/arm/thumb.c.rej b/gcc/config/arm/thumb.c.rej deleted file mode 100755 index 0233312..0000000 --- a/gcc/config/arm/thumb.c.rej +++ /dev/null @@ -1,168 +0,0 @@ -***************
-*** 2103,2105 ****
- }
- #endif /* THUMB_PE */
- /* END CYGNUS LOCAL nickc/thumb-pe */
---- 2103,2264 ----
- }
- #endif /* THUMB_PE */
- /* END CYGNUS LOCAL nickc/thumb-pe */
-+
-+ /* Return nonzero if ATTR is a valid attribute for TYPE.
-+ ATTRIBUTES are any existing attributes and ARGS are the arguments
-+ supplied with ATTR.
-+
-+ Supported attributes:
-+
-+ short_call: assume the offset from the caller to the callee is small.
-+
-+ long_call: don't assume the offset is small. */
-+
-+ int
-+ arm_valid_machine_type_attribute (type, attributes, attr, args)
-+ tree type;
-+ tree attributes;
-+ tree attr;
-+ tree args;
-+ {
-+ if (args != NULL_TREE)
-+ return 0;
-+
-+ if (is_attribute_p ("long_call", attr))
-+ return 1;
-+
-+ if (is_attribute_p ("short_call", attr))
-+ return 1;
-+
-+ return 0;
-+ }
-+
-+ /* Encode long_call or short_call attribute by prefixing
-+ symbol name in DECL with a special character FLAG. */
-+
-+ void
-+ arm_encode_call_attribute (decl, flag)
-+ tree decl;
-+ int flag;
-+ {
-+ const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
-+ int len = strlen (str);
-+ char * newstr;
-+
-+ /* Do not allow weak functions to be treated as short call. */
-+ if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR)
-+ return;
-+
-+ if (ENCODED_SHORT_CALL_ATTR_P (str)
-+ || ENCODED_LONG_CALL_ATTR_P (str))
-+ return;
-+
-+ newstr = malloc (len + 2);
-+ newstr[0] = flag;
-+ strcpy (newstr + 1, str);
-+
-+ XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
-+ }
-+
-+ /* Return the length of a function name prefix
-+ that starts with the character 'c'. */
-+
-+ static int
-+ arm_get_strip_length (char c)
-+ {
-+ switch (c)
-+ {
-+ ARM_NAME_ENCODING_LENGTHS
-+ default: return 0;
-+ }
-+ }
-+
-+ /* Return a pointer to a function's name with any
-+ and all prefix encodings stripped from it. */
-+
-+ char *
-+ arm_strip_name_encoding (char * name)
-+ {
-+ int skip;
-+
-+ while ((skip = arm_get_strip_length (* name)))
-+ name += skip;
-+
-+ return name;
-+ }
-+
-+ /* Return 1 if the operand is a SYMBOL_REF for a function known to be
-+ defined within the current compilation unit. If this caanot be
-+ determined, then 0 is returned. */
-+
-+ static int
-+ current_file_function_operand (sym_ref)
-+ rtx sym_ref;
-+ {
-+ /* This is a bit of a fib. A function will have a short call flag
-+ applied to its name if it has the short call attribute, or it has
-+ already been defined within the current compilation unit. */
-+ if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0)))
-+ return 1;
-+
-+ /* The current function is always defined within the current compilation
-+ unit. if it s a weak definition however, then this may not be the real
-+ definition of the function, and so we have to say no. */
-+ if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0)
-+ && !DECL_WEAK (current_function_decl))
-+ return 1;
-+
-+ /* We cannot make the determination - default to returning 0. */
-+ return 0;
-+ }
-+
-+ /* Return non-zero if a 32 bit "long_call" should be generated for
-+ this call. We generate a long_call if the function:
-+
-+ a. has an __attribute__((long call))
-+ or b. the -mlong-calls command line switch has been specified
-+
-+ However we do not generate a long call if the function:
-+
-+ c. has an __attribute__ ((short_call))
-+ or d. has an __attribute__ ((section))
-+ or e. is defined within the current compilation unit.
-+
-+ This function will be called by C fragments contained in the machine
-+ description file. CALL_REF and CALL_COOKIE correspond to the matched
-+ rtl operands. CALL_SYMBOL is used to distinguish between
-+ two different callers of the function. It is set to 1 in the
-+ "call_symbol" and "call_symbol_value" patterns and to 0 in the "call"
-+ and "call_value" patterns. This is because of the difference in the
-+ SYM_REFs passed by these patterns. */
-+
-+ int
-+ arm_is_longcall_p (sym_ref, call_cookie, call_symbol)
-+ rtx sym_ref;
-+ int call_cookie;
-+ int call_symbol;
-+ {
-+ if (!call_symbol)
-+ {
-+ if (GET_CODE (sym_ref) != MEM)
-+ return 0;
-+
-+ sym_ref = XEXP (sym_ref, 0);
-+ }
-+
-+ if (GET_CODE (sym_ref) != SYMBOL_REF)
-+ return 0;
-+
-+ if (call_cookie & CALL_SHORT)
-+ return 0;
-+
-+ if (TARGET_LONG_CALLS && flag_function_sections)
-+ return 1;
-+
-+ if (current_file_function_operand (sym_ref))
-+ return 0;
-+
-+ return (call_cookie & CALL_LONG)
-+ || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
-+ || TARGET_LONG_CALLS;
-+ }
diff --git a/gcc/config/arm/thumb.h.orig b/gcc/config/arm/thumb.h.orig deleted file mode 100755 index 9cd719a..0000000 --- a/gcc/config/arm/thumb.h.orig +++ /dev/null @@ -1,1195 +0,0 @@ -/* Definitions of target machine for GNU compiler, for ARM/Thumb. - Copyright (C) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. - The basis of this contribution was generated by - Richard Earnshaw, Advanced RISC Machines Ltd - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* ??? The files thumb.{c,h,md} are all seriously lacking comments. */ - -/* ??? The files thumb.{c,h,md} need to be reviewed by an experienced - gcc hacker in their entirety. */ - -/* ??? The files thumb.{c,h,md} and tcoff.h are all separate from the arm - files, which will lead to many maintenance problems. These files are - likely missing all bug fixes made to the arm port since they diverged. */ - -/* ??? Many patterns in the md file accept operands that will require a - reload. These should be eliminated if possible by tightening the - predicates and/or constraints. This will give faster/smaller code. */ - -/* ??? There is no pattern for the TST instuction. Check for other unsupported - instructions. */ - -/* Run Time Target Specifications */ -#ifndef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dthumb -D__thumb -Acpu(arm) -Amachine(arm)" -#endif - -#ifndef CPP_SPEC -#define CPP_SPEC "\ -%{mbig-endian:-D__ARMEB__ -D__THUMBEB__} \ -%{mbe:-D__ARMEB__ -D__THUMBEB__} \ -%{!mbe: %{!mbig-endian:-D__ARMEL__ -D__THUMBEL__}} \ -" -#endif - -#ifndef ASM_SPEC -#define ASM_SPEC "-marm7tdmi %{mthumb-interwork:-mthumb-interwork} %{mbig-endian:-EB}" -#endif -#define LINK_SPEC "%{mbig-endian:-EB} -X" - -#define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr); - -/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ -#define THUMB_FLAG_BIG_END 0x0001 -#define THUMB_FLAG_BACKTRACE 0x0002 -#define THUMB_FLAG_LEAF_BACKTRACE 0x0004 -#define ARM_FLAG_THUMB 0x1000 /* same as in arm.h */ -#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING 0x40000 -#define THUMB_FLAG_CALLER_SUPER_INTERWORKING 0x80000 - -/* Nonzero if all call instructions should be indirect. */ -#define ARM_FLAG_LONG_CALLS (0x10000) /* same as in arm.h */ - - -/* Run-time compilation parameters selecting different hardware/software subsets. */ -extern int target_flags; -#define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */ -#define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END) -#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) -#define TARGET_BACKTRACE (leaf_function_p() \ - ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ - : (target_flags & THUMB_FLAG_BACKTRACE)) - -/* Set if externally visable functions should assume that they - might be called in ARM mode, from a non-thumb aware code. */ -#define TARGET_CALLEE_INTERWORKING \ - (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING) - -/* Set if calls via function pointers should assume that their - destination is non-Thumb aware. */ -#define TARGET_CALLER_INTERWORKING \ - (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING) - -#define TARGET_LONG_CALLS (target_flags & ARM_FLAG_LONG_CALLS) - -/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */ -#ifndef SUBTARGET_SWITCHES -#define SUBTARGET_SWITCHES -#endif - -#define TARGET_SWITCHES \ -{ \ - {"big-endian", THUMB_FLAG_BIG_END}, \ - {"little-endian", -THUMB_FLAG_BIG_END}, \ - {"thumb-interwork", ARM_FLAG_THUMB}, \ - {"no-thumb-interwork", -ARM_FLAG_THUMB}, \ - {"tpcs-frame", THUMB_FLAG_BACKTRACE}, \ - {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \ - {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \ - {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \ - {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ - {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ - {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ - {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ - {"long-calls", ARM_FLAG_LONG_CALLS, \ - "Generate all call instructions as indirect calls"}, \ - {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ - SUBTARGET_SWITCHES \ - {"", TARGET_DEFAULT} \ -} - -#define TARGET_OPTIONS \ -{ \ - { "structure-size-boundary=", & structure_size_string }, \ -} - -#define REGISTER_PREFIX "" - -#define CAN_DEBUG_WITHOUT_FP 1 - -#define ASM_APP_ON "" -#define ASM_APP_OFF "\t.code\t16\n" - -/* Output a gap. In fact we fill it with nulls. */ -#define ASM_OUTPUT_SKIP(STREAM, NBYTES) \ - fprintf ((STREAM), "\t.space\t%u\n", (NBYTES)) - -/* 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(STREAM,LOG) \ -{ \ - if ((LOG) > 0) \ - fprintf (STREAM, "\t.align\t%d\n", (LOG)); \ -} - -/* Output a common block */ -#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ - (fprintf ((STREAM), "\t.comm\t"), \ - assemble_name ((STREAM), (NAME)), \ - fprintf((STREAM), ", %d\t%s %d\n", (ROUNDED), (ASM_COMMENT_START), (SIZE))) - -#define ASM_GENERATE_INTERNAL_LABEL(STRING,PREFIX,NUM) \ - sprintf ((STRING), "*%s%s%d", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) - -/* This is how to output an internal numbered label where - PREFIX is the class of label and NUM is the number within the class. */ -#define ASM_OUTPUT_INTERNAL_LABEL(STREAM,PREFIX,NUM) \ - fprintf ((STREAM), "%s%s%d:\n", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) - -/* This is how to output a label which precedes a jumptable. Since - instructions are 2 bytes, we need explicit alignment here. */ - -#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ - do { \ - ASM_OUTPUT_ALIGN (FILE, 2); \ - ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \ - } while (0) - -/* This says how to define a local common symbol (ie, not visible to - linker). */ -#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ - (fprintf((STREAM),"\n\t.lcomm\t"), \ - assemble_name((STREAM),(NAME)), \ - fprintf((STREAM),",%u\n",(SIZE))) - -/* Output a reference to a label. */ -#define ASM_OUTPUT_LABELREF(STREAM,NAME) \ - fprintf ((STREAM), "%s%s", user_label_prefix, (NAME)) - -/* This is how to output an assembler line for a numeric constant byte. */ -#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ - fprintf ((STREAM), "\t.byte\t0x%x\n", (VALUE)) - -#define ASM_OUTPUT_INT(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.word\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.short\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.byte\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ -do { char dstr[30]; \ - long l[3]; \ - REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ - fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n", \ - l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ - } while (0) - -#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ -do { char dstr[30]; \ - long l[2]; \ - REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ - fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ - l[1], ASM_COMMENT_START, dstr); \ - } while (0) - -#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ -do { char dstr[30]; \ - long l; \ - REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ - fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ - ASM_COMMENT_START, dstr); \ - } while (0); - -/* Define results of standard character escape sequences. */ -#define TARGET_BELL 007 -#define TARGET_BS 010 -#define TARGET_TAB 011 -#define TARGET_NEWLINE 012 -#define TARGET_VT 013 -#define TARGET_FF 014 -#define TARGET_CR 015 - -/* This is how to output a string. */ -#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ -do { \ - register int i, c, len = (LEN), cur_pos = 17; \ - register unsigned char *string = (unsigned char *)(STRING); \ - fprintf ((STREAM), "\t.ascii\t\""); \ - for (i = 0; i < len; i++) \ - { \ - register int c = string[i]; \ - \ - switch (c) \ - { \ - case '\"': \ - case '\\': \ - putc ('\\', (STREAM)); \ - putc (c, (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_NEWLINE: \ - fputs ("\\n", (STREAM)); \ - if (i+1 < len \ - && (((c = string[i+1]) >= '\040' && c <= '~') \ - || c == TARGET_TAB)) \ - cur_pos = 32767; /* break right here */ \ - else \ - cur_pos += 2; \ - break; \ - \ - case TARGET_TAB: \ - fputs ("\\t", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_FF: \ - fputs ("\\f", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_BS: \ - fputs ("\\b", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_CR: \ - fputs ("\\r", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - default: \ - if (c >= ' ' && c < 0177) \ - { \ - putc (c, (STREAM)); \ - cur_pos++; \ - } \ - else \ - { \ - fprintf ((STREAM), "\\%03o", c); \ - cur_pos += 4; \ - } \ - } \ - \ - if (cur_pos > 72 && i+1 < len) \ - { \ - cur_pos = 17; \ - fprintf ((STREAM), "\"\n\t.ascii\t\""); \ - } \ - } \ - fprintf ((STREAM), "\"\n"); \ -} while (0) - -/* Output and Generation of Labels */ -#define ASM_OUTPUT_LABEL(STREAM,NAME) \ - (assemble_name ((STREAM), (NAME)), \ - fprintf ((STREAM), ":\n")) - -#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ - (fprintf ((STREAM), "\t.globl\t"), \ - assemble_name ((STREAM), (NAME)), \ - fputc ('\n', (STREAM))) - -/* Construct a private name. */ -#define ASM_FORMAT_PRIVATE_NAME(OUTVAR,NAME,NUMBER) \ - ((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \ - sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) - -/* Switch to the text or data segment. */ -#define TEXT_SECTION_ASM_OP ".text" -#define DATA_SECTION_ASM_OP ".data" -#define BSS_SECTION_ASM_OP ".bss" - -/* The assembler's names for the registers. */ -#ifndef REGISTER_NAMES -#define REGISTER_NAMES \ -{ \ - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ - "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", "ap" \ -} -#endif - -#ifndef ADDITIONAL_REGISTER_NAMES -#define ADDITIONAL_REGISTER_NAMES \ -{ \ - {"a1", 0}, \ - {"a2", 1}, \ - {"a3", 2}, \ - {"a4", 3}, \ - {"v1", 4}, \ - {"v2", 5}, \ - {"v3", 6}, \ - {"v4", 7}, \ - {"v5", 8}, \ - {"v6", 9}, \ - {"sb", 9}, \ - {"v7", 10}, \ - {"r10", 10}, /* sl */ \ - {"r11", 11}, /* fp */ \ - {"r12", 12}, /* ip */ \ - {"r13", 13}, /* sp */ \ - {"r14", 14}, /* lr */ \ - {"r15", 15} /* pc */ \ -} -#endif - -/* The assembler's parentheses characters. */ -#define ASM_OPEN_PAREN "(" -#define ASM_CLOSE_PAREN ")" - -#ifndef ASM_COMMENT_START -#define ASM_COMMENT_START "@" -#endif - -/* Output an element of a dispatch table. */ -#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ - fprintf (STREAM, "\t.word\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) - -#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ - fprintf (STREAM, "\tb\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) - -/* Storage Layout */ - -/* Define this is most significant bit is lowest numbered in - instructions that operate on numbered bit-fields. */ -#define BITS_BIG_ENDIAN 0 - -/* Define this if most significant byte of a word is the lowest - numbered. */ -#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) - -#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN) - -/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based - on processor pre-defineds when compiling libgcc2.c. */ -#if defined(__THUMBEB__) && !defined(__THUMBEL__) -#define LIBGCC2_WORDS_BIG_ENDIAN 1 -#else -#define LIBGCC2_WORDS_BIG_ENDIAN 0 -#endif - -#define FLOAT_WORDS_BIG_ENDIAN 1 - -#define BITS_PER_UNIT 8 -#define BITS_PER_WORD 32 - -#define UNITS_PER_WORD 4 - -#define POINTER_SIZE 32 - -#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ -{ \ - if (GET_MODE_CLASS (MODE) == MODE_INT \ - && GET_MODE_SIZE (MODE) < 4) \ - { \ - (UNSIGNEDP) = 1; \ - (MODE) = SImode; \ - } \ -} - -#define PARM_BOUNDARY 32 -#define STACK_BOUNDARY 32 - -#define FUNCTION_BOUNDARY 32 -#define BIGGEST_ALIGNMENT 32 - -/* Make strings word-aligned so strcpy from constants will be faster. */ -#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ - (TREE_CODE (EXP) == STRING_CST \ - && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) - -#define EMPTY_FIELD_BOUNDARY 32 - -#define STRUCTURE_SIZE_BOUNDARY 32 - -/* Used when parsing command line option -mstructure_size_boundary. */ -extern char * structure_size_string; - -#define STRICT_ALIGNMENT 1 - -#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT - - -/* Layout of Source Language Data Types */ - -#define DEFAULT_SIGNED_CHAR 0 - -#define TARGET_BELL 007 -#define TARGET_BS 010 -#define TARGET_TAB 011 -#define TARGET_NEWLINE 012 -#define TARGET_VT 013 -#define TARGET_FF 014 -#define TARGET_CR 015 - - -/* Register Usage */ - -/* Note there are 16 hard registers on the Thumb. We invent a 17th register - which is assigned to ARG_POINTER_REGNUM, but this is later removed by - elimination passes in the compiler. */ -#define FIRST_PSEUDO_REGISTER 17 - -/* ??? This is questionable. */ -#define FIXED_REGISTERS \ -{ \ - 0,0,0,0, \ - 0,0,0,0, \ - 0,0,0,1, \ - 0,1,1,1,1 \ -} - -/* ??? This is questionable. */ -#define CALL_USED_REGISTERS \ -{ \ - 1,1,1,1, \ - 0,0,0,0, \ - 0,0,0,1, \ - 1,1,1,1,1 \ -} - -#define HARD_REGNO_NREGS(REGNO,MODE) \ - ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ - / UNITS_PER_WORD) - -/* ??? Probably should only allow DImode/DFmode in even numbered registers. */ -#define HARD_REGNO_MODE_OK(REGNO,MODE) ((GET_MODE_SIZE (MODE) > UNITS_PER_WORD) ? (REGNO < 7) : 1) - -#define MODES_TIEABLE_P(MODE1,MODE2) 1 - -/* The NOARG_LO_REGS class is the set of LO_REGS that are not used for passing - arguments to functions. These are the registers that are available for - spilling during reload. The code in reload1.c:init_reload() will detect this - class and place it into 'reload_address_base_reg_class'. */ - -enum reg_class -{ - NO_REGS, - NONARG_LO_REGS, - LO_REGS, - STACK_REG, - BASE_REGS, - HI_REGS, - ALL_REGS, - LIM_REG_CLASSES -}; - -#define GENERAL_REGS ALL_REGS - -#define N_REG_CLASSES (int) LIM_REG_CLASSES - -#define REG_CLASS_NAMES \ -{ \ - "NO_REGS", \ - "NONARG_LO_REGS", \ - "LO_REGS", \ - "STACK_REG", \ - "BASE_REGS", \ - "HI_REGS", \ - "ALL_REGS" \ -} - -#define REG_CLASS_CONTENTS \ -{ \ - 0x00000, \ - 0x000f0, \ - 0x000ff, \ - 0x02000, \ - 0x020ff, \ - 0x0ff00, \ - 0x1ffff, \ -} - -#define REGNO_REG_CLASS(REGNO) \ - ((REGNO) == STACK_POINTER_REGNUM ? STACK_REG \ - : (REGNO) < 8 ? ((REGNO) < 4 ? LO_REGS \ - : NONARG_LO_REGS) \ - : HI_REGS) - -#define BASE_REG_CLASS BASE_REGS - -#define MODE_BASE_REG_CLASS(MODE) \ - ((MODE) != QImode && (MODE) != HImode \ - ? BASE_REGS : LO_REGS) - -#define INDEX_REG_CLASS LO_REGS - -/* When SMALL_REGISTER_CLASSES is nonzero, the compiler allows - registers explicitly used in the rtl to be used as spill registers - but prevents the compiler from extending the lifetime of these - registers. */ - -#define SMALL_REGISTER_CLASSES 1 - -#define REG_CLASS_FROM_LETTER(C) \ - ((C) == 'l' ? LO_REGS \ - : (C) == 'h' ? HI_REGS \ - : (C) == 'b' ? BASE_REGS \ - : (C) == 'k' ? STACK_REG \ - : NO_REGS) - -#define REGNO_OK_FOR_BASE_P(REGNO) \ - ((REGNO) < 8 \ - || (REGNO) == STACK_POINTER_REGNUM \ - || (unsigned) reg_renumber[REGNO] < 8 \ - || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM) - -#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ - ((REGNO) < 8 \ - || (unsigned) reg_renumber[REGNO] < 8 \ - || (GET_MODE_SIZE (MODE) >= 4 \ - && ((REGNO) == STACK_POINTER_REGNUM \ - || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM))) - -#define REGNO_OK_FOR_INDEX_P(REGNO) \ - ((REGNO) < 8 \ - || (unsigned) reg_renumber[REGNO] < 8) - -/* ??? This looks suspiciously wrong. */ -/* We need to leave BASE_REGS reloads alone, in order to avoid caller_save - lossage. Caller_saves requests a BASE_REGS reload (caller_save_spill_class) - and then later we verify that one was allocated. If PREFERRED_RELOAD_CLASS - says to allocate a LO_REGS spill instead, then this mismatch gives an - abort. Alternatively, this could be fixed by modifying BASE_REG_CLASS - to be LO_REGS instead of BASE_REGS. It is not clear what affect this - change would have. */ -/* ??? This looks even more suspiciously wrong. PREFERRED_RELOAD_CLASS - must always return a strict subset of the input class. Just blindly - returning LO_REGS is safe only if the input class is a superset of LO_REGS, - but there is no check for this. Added another exception for NONARG_LO_REGS - because it is not a superset of LO_REGS. */ -/* ??? We now use NONARG_LO_REGS for caller_save_spill_class, so the - comments about BASE_REGS are now obsolete. */ -#define PREFERRED_RELOAD_CLASS(X,CLASS) \ - ((CLASS) == BASE_REGS || (CLASS) == NONARG_LO_REGS ? (CLASS) \ - : LO_REGS) -/* - ((CONSTANT_P ((X)) && GET_CODE ((X)) != CONST_INT \ - && ! CONSTANT_POOL_ADDRESS_P((X))) ? NO_REGS \ - : (GET_CODE ((X)) == CONST_INT \ - && (unsigned HOST_WIDE_INT) INTVAL ((X)) > 255) ? NO_REGS \ - : LO_REGS) */ - -/* Must leave BASE_REGS and NONARG_LO_REGS reloads alone, see comment - above. */ -#define SECONDARY_RELOAD_CLASS(CLASS,MODE,X) \ - ((CLASS) != LO_REGS && (CLASS) != BASE_REGS && (CLASS) != NONARG_LO_REGS \ - ? ((true_regnum (X) == -1 ? LO_REGS \ - : (true_regnum (X) + HARD_REGNO_NREGS (0, MODE) > 8) ? LO_REGS \ - : NO_REGS)) \ - : NO_REGS) - -#define CLASS_MAX_NREGS(CLASS,MODE) HARD_REGNO_NREGS(0,(MODE)) - -int thumb_shiftable_const (); - -#define CONST_OK_FOR_LETTER_P(VAL,C) \ - ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VAL) < 256 \ - : (C) == 'J' ? (VAL) > -256 && (VAL) <= 0 \ - : (C) == 'K' ? thumb_shiftable_const (VAL) \ - : (C) == 'L' ? (VAL) > -8 && (VAL) < 8 \ - : (C) == 'M' ? ((unsigned HOST_WIDE_INT) (VAL) < 1024 \ - && ((VAL) & 3) == 0) \ - : (C) == 'N' ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ - : (C) == 'O' ? ((VAL) >= -508 && (VAL) <= 508) \ - : 0) - -#define CONST_DOUBLE_OK_FOR_LETTER_P(VAL,C) 0 - -#define EXTRA_CONSTRAINT(X,C) \ - ((C) == 'Q' ? (GET_CODE (X) == MEM \ - && GET_CODE (XEXP (X, 0)) == LABEL_REF) : 0) - -/* Stack Layout and Calling Conventions */ - -#define STACK_GROWS_DOWNWARD 1 - -/* #define FRAME_GROWS_DOWNWARD 1 */ - -/* #define ARGS_GROW_DOWNWARD 1 */ - -#define STARTING_FRAME_OFFSET 0 - -#define FIRST_PARM_OFFSET(FNDECL) 0 - -/* Registers that address the stack frame */ - -#define STACK_POINTER_REGNUM 13 /* Defined by the TPCS. */ - -#define FRAME_POINTER_REGNUM 7 /* TPCS defines this as 11 but it does not really mean it. */ - -#define ARG_POINTER_REGNUM 16 /* A fake hard register that is eliminated later on. */ - -#define STATIC_CHAIN_REGNUM 9 - -#define FRAME_POINTER_REQUIRED 0 - -#define ELIMINABLE_REGS \ -{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ - {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ - {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} - -/* On the Thumb we always want to perform the eliminations as we - actually only have one real register pointing to the stashed - variables: the stack pointer, and we never use the frame pointer. */ -#define CAN_ELIMINATE(FROM,TO) 1 - -/* Note: This macro must match the code in thumb_function_prologue() in thumb.c. */ -#define INITIAL_ELIMINATION_OFFSET(FROM,TO,OFFSET) \ -{ \ - (OFFSET) = 0; \ - if ((FROM) == ARG_POINTER_REGNUM) \ - { \ - int count_regs = 0; \ - int regno; \ - (OFFSET) += get_frame_size (); \ - for (regno = 8; regno < 13; regno++) \ - if (regs_ever_live[regno] && ! call_used_regs[regno]) \ - count_regs++; \ - if (count_regs) \ - (OFFSET) += 4 * count_regs; \ - count_regs = 0; \ - for (regno = 0; regno < 8; regno++) \ - if (regs_ever_live[regno] && ! call_used_regs[regno]) \ - count_regs++; \ - if (count_regs || ! leaf_function_p () || far_jump_used_p()) \ - (OFFSET) += 4 * (count_regs + 1); \ - if (TARGET_BACKTRACE) { \ - if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0)) \ - (OFFSET) += 20; \ - else \ - (OFFSET) += 16; } \ - } \ - if ((TO) == STACK_POINTER_REGNUM) \ - (OFFSET) += current_function_outgoing_args_size; \ -} - -/* Passing Arguments on the stack */ - -#define PROMOTE_PROTOTYPES 1 - -#define ACCUMULATE_OUTGOING_ARGS 1 - -#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 - -#define FUNCTION_ARG(CUM,MODE,TYPE,NAMED) \ - ((NAMED) ? ((CUM) >= 16 ? 0 : gen_rtx (REG, (MODE), (CUM) / 4)) \ - : 0) - -#define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) \ - (((CUM) < 16 && (CUM) + (((MODE) == BLKmode) \ - ? int_size_in_bytes (TYPE) \ - : HARD_REGNO_NREGS (0, (MODE)) * 4) > 16) \ - ? 4 - (CUM) / 4 : 0) - -#define CUMULATIVE_ARGS int - -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ - ((CUM) = ((FNTYPE) && aggregate_value_p (TREE_TYPE (FNTYPE))) ? 4 : 0) - -#define FUNCTION_ARG_ADVANCE(CUM,MODE,TYPE,NAMED) \ - (CUM) += ((((MODE) == BLKmode) \ - ? int_size_in_bytes (TYPE) \ - : GET_MODE_SIZE (MODE)) + 3) & ~3 - -#define FUNCTION_ARG_REGNO_P(REGNO) \ - ((REGNO) >=0 && (REGNO) <= 3) - -#define FUNCTION_VALUE(VALTYPE,FUNC) gen_rtx (REG, TYPE_MODE (VALTYPE), 0) - -#define LIBCALL_VALUE(MODE) gen_rtx (REG, (MODE), 0) - -#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == 0) - - /* How large values are returned */ -/* A C expression which can inhibit the returning of certain function values - in registers, based on the type of value. */ -#define RETURN_IN_MEMORY(TYPE) thumb_return_in_memory (TYPE) - -/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return - values must be in memory. On the ARM, they need only do so if larger - than a word, or if they contain elements offset from zero in the struct. */ -#define DEFAULT_PCC_STRUCT_RETURN 0 - - -#define STRUCT_VALUE_REGNUM 0 - -#define FUNCTION_PROLOGUE(FILE,SIZE) thumb_function_prologue((FILE),(SIZE)) - -#define FUNCTION_EPILOGUE(FILE,SIZE) thumb_function_epilogue((FILE),(SIZE)) - -/* Implementing the Varargs Macros */ - -#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ -{ \ - extern int current_function_anonymous_args; \ - current_function_anonymous_args = 1; \ - if ((CUM) < 16) \ - (PRETEND_SIZE) = 16 - (CUM); \ -} - -/* Trampolines for nested functions */ - -/* Output assembler code for a block containing the constant parts of - a trampoline, leaving space for the variable parts. - - On the Thumb we always switch into ARM mode to execute the trampoline. - Why - because it is easier. This code will always be branched to via - a BX instruction and since the compiler magically generates the address - of the function the linker has no opportunity to ensure that the - bottom bit is set. Thus the processor will be in ARM mode when it - reaches this code. So we duplicate the ARM trampoline code and add - a switch into Thumb mode as well. - - On the ARM, (if r8 is the static chain regnum, and remembering that - referencing pc adds an offset of 8) the trampoline looks like: - ldr r8, [pc, #0] - ldr pc, [pc] - .word static chain value - .word function's address - ??? FIXME: When the trampoline returns, r8 will be clobbered. */ -#define TRAMPOLINE_TEMPLATE(FILE) \ -{ \ - fprintf ((FILE), "\t.code 32\n"); \ - fprintf ((FILE), ".Ltrampoline_start:\n"); \ - fprintf ((FILE), "\tldr\t%s, [%spc, #8]\n", \ - reg_names[STATIC_CHAIN_REGNUM], REGISTER_PREFIX); \ - fprintf ((FILE), "\tldr\t%sip, [%spc, #8]\n", \ - REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf ((FILE), "\torr\t%sip, %sip, #1\n", \ - REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf ((FILE), "\tbx\t%sip\n", REGISTER_PREFIX); \ - fprintf ((FILE), "\t.word\t0\n"); \ - fprintf ((FILE), "\t.word\t0\n"); \ - fprintf ((FILE), "\t.code 16\n"); \ -} - -/* Length in units of the trampoline for entering a nested function. */ -#define TRAMPOLINE_SIZE 24 - -/* Alignment required for a trampoline in units. */ -#define TRAMPOLINE_ALIGN 4 - -#define INITIALIZE_TRAMPOLINE(ADDR,FNADDR,CHAIN) \ -{ \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 16)), \ - (CHAIN)); \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 20)), \ - (FNADDR)); \ -} - - -/* Implicit Calls to Library Routines */ - -#define TARGET_MEM_FUNCTIONS 1 - -#define OVERRIDE_OPTIONS thumb_override_options () - - -/* Addressing Modes */ - -#define HAVE_POST_INCREMENT 1 - -#define CONSTANT_ADDRESS_P(X) \ - (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X)) - -#define MAX_REGS_PER_ADDRESS 2 - -#ifdef REG_OK_STRICT - -#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) -#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) - -#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ - REGNO_MODE_OK_FOR_BASE_P (REGNO (X), MODE) - -#else /* REG_OK_STRICT */ - -#define REG_OK_FOR_BASE_P(X) \ - (REGNO (X) < 8 || REGNO (X) == STACK_POINTER_REGNUM \ - || (X) == arg_pointer_rtx \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER) - -#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ - (REGNO (X) < 8 \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER \ - || (GET_MODE_SIZE (MODE) >= 4 \ - && (REGNO (X) == STACK_POINTER_REGNUM \ - || (X) == arg_pointer_rtx))) - -#define REG_OK_FOR_INDEX_P(X) \ - (REGNO (X) < 8 \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER) - -#endif /* REG_OK_STRICT */ - -/* In a REG+REG address, both must be INDEX registers. */ -#define REG_OK_FOR_INDEXED_BASE_P(X) REG_OK_FOR_INDEX_P(X) - -#define LEGITIMATE_OFFSET(MODE,VAL) \ -(GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ - : GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \ - && ((VAL) & 1) == 0) \ - : ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \ - && ((VAL) & 3) == 0)) - -/* The AP may be eliminated to either the SP or the FP, so we use the - least common denominator, e.g. SImode, and offsets from 0 to 64. */ - -/* ??? Verify whether the above is the right approach. */ - -/* ??? Also, the FP may be eliminated to the SP, so perhaps that - needs special handling also. */ - -/* ??? Look at how the mips16 port solves this problem. It probably uses - better ways to solve some of these problems. */ - -/* Although it is not incorrect, we don't accept QImode and HImode - addresses based on the frame pointer or arg pointer until the reload pass starts. - This is so that eliminating such addresses into stack based ones - won't produce impossible code. */ -#define GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \ -{ \ - /* ??? Not clear if this is right. Experiment. */ \ - if (GET_MODE_SIZE (MODE) < 4 \ - && ! (reload_in_progress || reload_completed) \ - && (reg_mentioned_p (frame_pointer_rtx, X) \ - || reg_mentioned_p (arg_pointer_rtx, X) \ - || reg_mentioned_p (virtual_incoming_args_rtx, X) \ - || reg_mentioned_p (virtual_outgoing_args_rtx, X) \ - || reg_mentioned_p (virtual_stack_dynamic_rtx, X) \ - || reg_mentioned_p (virtual_stack_vars_rtx, X))) \ - ; \ - /* Accept any base register. SP only in SImode or larger. */ \ - else if (GET_CODE (X) == REG && REG_MODE_OK_FOR_BASE_P(X, MODE)) \ - goto WIN; \ - /* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \ - else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \ - && CONSTANT_POOL_ADDRESS_P (X)) \ - goto WIN; \ - /* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \ - else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ - && (GET_CODE (X) == LABEL_REF \ - || (GET_CODE (X) == CONST \ - && GET_CODE (XEXP (X, 0)) == PLUS \ - && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \ - && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \ - goto WIN; \ - /* Post-inc indexing only supported for SImode and larger. */ \ - else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \ - && GET_CODE (XEXP (X, 0)) == REG \ - && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ - goto WIN; \ - else if (GET_CODE (X) == PLUS) \ - { \ - /* REG+REG address can be any two index registers. */ \ - /* ??? REG+REG addresses have been completely disabled before \ - reload completes, because we do not have enough available \ - reload registers. We only have 3 guaranteed reload registers \ - (NONARG_LO_REGS - the frame pointer), but we need at least 4 \ - to support REG+REG addresses. We have left them enabled after \ - reload completes, in the hope that reload_cse_regs and related \ - routines will be able to create them after the fact. It is \ - probably possible to support REG+REG addresses with additional \ - reload work, but I do not not have enough time to attempt such \ - a change at this time. */ \ - /* ??? Normally checking the mode here is wrong, since it isn't \ - impossible to use REG+REG with DFmode. However, the movdf \ - pattern requires offsettable addresses, and REG+REG is not \ - offsettable, so it must be rejected somehow. Trying to use \ - 'o' fails, because offsettable_address_p does a QImode check. \ - QImode is not valid for stack addresses, and has a smaller \ - range for non-stack bases, and this causes valid addresses \ - to be rejected. So we just eliminate REG+REG here by checking \ - the mode. */ \ - /* We also disallow FRAME+REG addressing since we know that FRAME \ - will be replaced with STACK, and SP relative addressing only \ - permits SP+OFFSET. */ \ - if (GET_MODE_SIZE (MODE) <= 4 \ - /* ??? See comment above. */ \ - && reload_completed \ - && GET_CODE (XEXP (X, 0)) == REG \ - && GET_CODE (XEXP (X, 1)) == REG \ - && XEXP (X, 0) != frame_pointer_rtx \ - && XEXP (X, 1) != frame_pointer_rtx \ - && XEXP (X, 0) != virtual_stack_vars_rtx \ - && XEXP (X, 1) != virtual_stack_vars_rtx \ - && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ - && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ - goto WIN; \ - /* REG+const has 5-7 bit offset for non-SP registers. */ \ - else if (GET_CODE (XEXP (X, 0)) == REG \ - && (REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ - || XEXP (X, 0) == arg_pointer_rtx) \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ - goto WIN; \ - /* REG+const has 10 bit offset for SP, but only SImode and \ - larger is supported. */ \ - /* ??? Should probably check for DI/DFmode overflow here \ - just like GO_IF_LEGITIMATE_OFFSET does. */ \ - else if (GET_CODE (XEXP (X, 0)) == REG \ - && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \ - && GET_MODE_SIZE (MODE) >= 4 \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && (unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) < 1024 \ - && (INTVAL (XEXP (X, 1)) & 3) == 0) \ - goto WIN; \ - } \ -} - -/* ??? If an HImode FP+large_offset address is converted to an HImode - SP+large_offset address, then reload won't know how to fix it. It sees - only that SP isn't valid for HImode, and so reloads the SP into an index - register, but the resulting address is still invalid because the offset - is too big. We fix it here instead by reloading the entire address. */ -/* We could probably achieve better results by defining PROMOTE_MODE to help - cope with the variances between the Thumb's signed and unsigned byte and - halfword load instructions. */ -#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ -{ \ - if (GET_CODE (X) == PLUS \ - && GET_MODE_SIZE (MODE) < 4 \ - && GET_CODE (XEXP (X, 0)) == REG \ - && XEXP (X, 0) == stack_pointer_rtx \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && ! LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ - { \ - rtx orig_X = X; \ - X = copy_rtx (X); \ - push_reload (orig_X, NULL_RTX, &X, NULL_PTR, \ - BASE_REG_CLASS, \ - Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \ - goto WIN; \ - } \ -} - -#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) - -#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) - -#define LEGITIMATE_CONSTANT_P(X) \ - (GET_CODE (X) == CONST_INT \ - || GET_CODE (X) == CONST_DOUBLE \ - || CONSTANT_ADDRESS_P (X)) - - -/* Condition Code Status */ - -#define NOTICE_UPDATE_CC(EXP,INSN) \ -{ \ - if (get_attr_conds ((INSN)) != CONDS_UNCHANGED) \ - CC_STATUS_INIT; \ -} - - -/* Describing Relative Costs of Operations */ - -#define SLOW_BYTE_ACCESS 0 - -#define SLOW_UNALIGNED_ACCESS 1 - -#define NO_FUNCTION_CSE 1 - -#define NO_RECURSIVE_FUNCTION_CSE 1 - -#define REGISTER_MOVE_COST(FROM,TO) \ - (((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2) - -#define MEMORY_MOVE_COST(M,CLASS,IN) \ - ((GET_MODE_SIZE(M) < 4 ? 8 : 2 * GET_MODE_SIZE(M)) * (CLASS == LO_REGS ? 1 : 2)) - -/* This will allow better space optimization when compiling with -O */ -#define BRANCH_COST (optimize > 1 ? 1 : 0) - -#define RTX_COSTS(X,CODE,OUTER) \ - case MULT: \ - if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ - { \ - int cycles = 0; \ - unsigned HOST_WIDE_INT i = INTVAL (XEXP (X, 1)); \ - while (i) \ - { \ - i >>= 2; \ - cycles++; \ - } \ - return COSTS_N_INSNS (2) + cycles; \ - } \ - return COSTS_N_INSNS (1) + 16; \ - case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATERT: \ - case PLUS: case MINUS: case COMPARE: case NEG: case NOT: \ - return COSTS_N_INSNS (1); \ - case SET: \ - return (COSTS_N_INSNS (1) \ - + 4 * ((GET_CODE (SET_SRC (X)) == MEM) \ - + GET_CODE (SET_DEST (X)) == MEM)) - -#define CONST_COSTS(X,CODE,OUTER) \ - case CONST_INT: \ - if ((OUTER) == SET) \ - { \ - if ((unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ - return 0; \ - if (thumb_shiftable_const (INTVAL (X))) \ - return COSTS_N_INSNS (2); \ - return COSTS_N_INSNS (3); \ - } \ - else if (OUTER == PLUS \ - && INTVAL (X) < 256 && INTVAL (X) > -256) \ - return 0; \ - else if (OUTER == COMPARE \ - && (unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ - return 0; \ - else if (OUTER == ASHIFT || OUTER == ASHIFTRT \ - || OUTER == LSHIFTRT) \ - return 0; \ - return COSTS_N_INSNS (2); \ - case CONST: \ - case CONST_DOUBLE: \ - case LABEL_REF: \ - case SYMBOL_REF: \ - return COSTS_N_INSNS(3); - -#define ADDRESS_COST(X) \ - ((GET_CODE (X) == REG \ - || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \ - && GET_CODE (XEXP (X, 1)) == CONST_INT)) \ - ? 1 : 2) - - -/* Position Independent Code */ - -#define PRINT_OPERAND(STREAM,X,CODE) \ - thumb_print_operand((STREAM), (X), (CODE)) - -#define PRINT_OPERAND_ADDRESS(STREAM,X) \ -{ \ - if (GET_CODE ((X)) == REG) \ - fprintf ((STREAM), "[%s]", reg_names[REGNO ((X))]); \ - else if (GET_CODE ((X)) == POST_INC) \ - fprintf ((STREAM), "%s!", reg_names[REGNO (XEXP (X, 0))]); \ - else if (GET_CODE ((X)) == PLUS) \ - { \ - if (GET_CODE (XEXP ((X), 1)) == CONST_INT) \ - fprintf ((STREAM), "[%s, #%d]", \ - reg_names[REGNO (XEXP ((X), 0))], \ - (int) INTVAL (XEXP ((X), 1))); \ - else \ - fprintf ((STREAM), "[%s, %s]", \ - reg_names[REGNO (XEXP ((X), 0))], \ - reg_names[REGNO (XEXP ((X), 1))]); \ - } \ - else \ - output_addr_const ((STREAM), (X)); \ -} - -#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_')) - -/* Emit a special directive when defining a function name. - This is used by the assembler to assit with interworking. */ -#define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ - if (! is_called_in_ARM_mode (decl)) \ - fprintf (file, "\t.thumb_func\n") ; \ - else \ - fprintf (file, "\t.code\t32\n") ; \ - ASM_OUTPUT_LABEL (file, name) - -#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ - asm_fprintf ((STREAM), "\tpush {%R%s}\n", reg_names[(REGNO)]) - -#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ - fprintf ((STREAM), "\tpop {%R%s}\n", reg_names[(REGNO)]) - -#define FINAL_PRESCAN_INSN(INSN,OPVEC,NOPERANDS) \ - final_prescan_insn((INSN)) - -/* Controlling Debugging Information Format */ -#define DBX_REGISTER_NUMBER(REGNO) (REGNO) - -/* Specific options for DBX Output */ - -#define DBX_DEBUGGING_INFO 1 - -#define DEFAULT_GDB_EXTENSIONS 1 - - -/* Cross Compilation and Floating Point */ - -#define REAL_ARITHMETIC - - -/* Miscellaneous Parameters */ - -#define PREDICATE_CODES \ - {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, - -#define CASE_VECTOR_MODE Pmode - -#define WORD_REGISTER_OPERATIONS - -#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND - -#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR - -#define EASY_DIV_EXPR TRUNC_DIV_EXPR - -#define MOVE_MAX 4 - -#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 - -#define STORE_FLAG_VALUE 1 - -#define Pmode SImode - -#define FUNCTION_MODE SImode - -#define DOLLARS_IN_IDENTIFIERS 0 - -#define NO_DOLLAR_IN_LABEL 1 - -#define HAVE_ATEXIT - -/* The literal pool needs to reside in the text area due to the - limited PC addressing range: */ -#define MACHINE_DEPENDENT_REORG(INSN) thumb_reorg ((INSN)) - - -/* Options specific to Thumb */ - -/* True if a return instruction can be used in this function. */ -int thumb_trivial_epilogue (); -#define USE_RETURN (reload_completed && thumb_trivial_epilogue ()) - -extern char * thumb_unexpanded_epilogue (); -extern char * output_move_mem_multiple (); -extern char * thumb_load_double_from_address (); -extern char * output_return (); -extern int far_jump_used_p(); -extern int is_called_in_ARM_mode (); - diff --git a/gcc/config/arm/thumb.md.orig b/gcc/config/arm/thumb.md.orig deleted file mode 100755 index dd86008..0000000 --- a/gcc/config/arm/thumb.md.orig +++ /dev/null @@ -1,1174 +0,0 @@ -;; thumb.md Machine description for ARM/Thumb processors -;; Copyright (C) 1996, 1997, 1998, 2002 Free Software Foundation, Inc. -;; The basis of this contribution was generated by -;; Richard Earnshaw, Advanced RISC Machines Ltd - -;; This file is part of GNU CC. - -;; GNU CC is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. - -;; GNU CC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU CC; see the file COPYING. If not, write to -;; the Free Software Foundation, 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;; LENGTH of an instruction is 2 bytes -(define_attr "length" "" (const_int 2)) - -;; CONDS is set to UNCHANGED when an insn does not affect the condition codes -;; Most insns change the condition codes -(define_attr "conds" "changed,unchanged" (const_string "changed")) - -;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a -;; distant label. -(define_attr "far_jump" "yes,no" (const_string "no")) - -;; Start with move insns - -(define_expand "movsi" - [(set (match_operand:SI 0 "general_operand" "") - (match_operand:SI 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (SImode, operands[1]); - } -") - -(define_insn "*movsi_insn" - [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h") - (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))] - "register_operand (operands[0], SImode) - || register_operand (operands[1], SImode)" - "@ - add\\t%0, %1, #0 - mov\\t%0, %1 - # - # - ldmia\\t%1, {%0} - stmia\\t%0, {%1} - ldr\\t%0, %1 - str\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1" -[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")]) - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] - "thumb_shiftable_const (INTVAL (operands[1]))" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] - " -{ - unsigned HOST_WIDE_INT val = INTVAL (operands[1]); - unsigned HOST_WIDE_INT mask = 0xff; - int i; - for (i = 0; i < 25; i++) - if ((val & (mask << i)) == val) - break; - - if (i == 0) - FAIL; - - operands[1] = GEN_INT (val >> i); - operands[2] = GEN_INT (i); -}") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] - "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (neg:SI (match_dup 0)))] - " - operands[1] = GEN_INT (- INTVAL (operands[1])); -") - -;;(define_expand "reload_outsi" -;; [(set (match_operand:SI 2 "register_operand" "=&l") -;; (match_operand:SI 1 "register_operand" "h")) -;; (set (match_operand:SI 0 "reload_memory_operand" "=o") -;; (match_dup 2))] -;; "" -;; " -;;/* thumb_reload_out_si (operands); -;; DONE; */ -;;") - -(define_expand "movhi" - [(set (match_operand:HI 0 "general_operand" "") - (match_operand:HI 1 "general_operand" ""))] - "" - " -{ - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (HImode, operands[1]); - - /* ??? We shouldn't really get invalid addresses here, but this can - happen if we are passed a SP (never OK for HImode/QImode) or virtual - register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) - relative address. */ - /* ??? This should perhaps be fixed elsewhere, for instance, in - fixup_stack_1, by checking for other kinds of invalid addresses, - e.g. a bare reference to a virtual register. This may confuse the - alpha though, which must handle this case differently. */ - if (GET_CODE (operands[0]) == MEM - && ! memory_address_p (GET_MODE (operands[0]), - XEXP (operands[0], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[0], 0)); - operands[0] = change_address (operands[0], VOIDmode, temp); - } - if (GET_CODE (operands[1]) == MEM - && ! memory_address_p (GET_MODE (operands[1]), - XEXP (operands[1], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[1], 0)); - operands[1] = change_address (operands[1], VOIDmode, temp); - } - } - /* Handle loading a large integer during reload */ - else if (GET_CODE (operands[1]) == CONST_INT - && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) - { - /* Writing a constant to memory needs a scratch, which should - be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); - - operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } -}") - -(define_insn "*movhi_insn" - [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") - (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] - "register_operand (operands[0], HImode) - || register_operand (operands[1], HImode)" - "@ - add\\t%0, %1, #0 - ldrh\\t%0, %1 - strh\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1 - mov\\t%0, %1") - -(define_expand "movqi" - [(set (match_operand:QI 0 "general_operand" "") - (match_operand:QI 1 "general_operand" ""))] - "" - " -{ - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (QImode, operands[1]); - - /* ??? We shouldn't really get invalid addresses here, but this can - happen if we are passed a SP (never OK for HImode/QImode) or virtual - register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) - relative address. */ - /* ??? This should perhaps be fixed elsewhere, for instance, in - fixup_stack_1, by checking for other kinds of invalid addresses, - e.g. a bare reference to a virtual register. This may confuse the - alpha though, which must handle this case differently. */ - if (GET_CODE (operands[0]) == MEM - && ! memory_address_p (GET_MODE (operands[0]), - XEXP (operands[0], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[0], 0)); - operands[0] = change_address (operands[0], VOIDmode, temp); - } - if (GET_CODE (operands[1]) == MEM - && ! memory_address_p (GET_MODE (operands[1]), - XEXP (operands[1], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[1], 0)); - operands[1] = change_address (operands[1], VOIDmode, temp); - } - } - /* Handle loading a large integer during reload */ - else if (GET_CODE (operands[1]) == CONST_INT - && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) - { - /* Writing a constant to memory needs a scratch, which should - be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); - - operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } -}") - -(define_insn "*movqi_insn" - [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") - (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] - "register_operand (operands[0], QImode) - || register_operand (operands[1], QImode)" - "@ - add\\t%0, %1, #0 - ldrb\\t%0, %1 - strb\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1 - mov\\t%0, %1") - -(define_expand "movdi" - [(set (match_operand:DI 0 "general_operand" "") - (match_operand:DI 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (DImode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -;;; ??? This was originally identical to the movdf_insn pattern. -;;; ??? The 'i' constraint looks funny, but it should always be replaced by -;;; thumb_reorg with a memory reference. -(define_insn "*movdi_insn" - [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r") - (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] - "register_operand (operands[0], DImode) - || register_operand (operands[1], DImode)" - "* -{ - switch (which_alternative) - { - case 0: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; - return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; - case 1: - return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; - case 2: - operands[1] = GEN_INT (- INTVAL (operands[1])); - return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; - case 3: - return \"ldmia\\t%1, {%0, %H0}\"; - case 4: - return \"stmia\\t%0, {%1, %H1}\"; - case 5: - return thumb_load_double_from_address (operands); - case 6: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); - output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); - return \"\"; - case 7: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; - return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; - } -}"[(set_attr "length" "4,4,6,2,2,6,4,4")]) - -(define_expand "movdf" - [(set (match_operand:DF 0 "general_operand" "") - (match_operand:DF 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (DFmode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -;;; ??? This was originally identical to the movdi_insn pattern. -;;; ??? The 'F' constraint looks funny, but it should always be replaced by -;;; thumb_reorg with a memory reference. -(define_insn "*movdf_insn" - [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r") - (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] - "register_operand (operands[0], DFmode) - || register_operand (operands[1], DFmode)" - "* - switch (which_alternative) - { - case 0: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; - return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; - case 1: - return \"ldmia\\t%1, {%0, %H0}\"; - case 2: - return \"stmia\\t%0, {%1, %H1}\"; - case 3: - return thumb_load_double_from_address (operands); - case 4: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); - output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); - return \"\"; - case 5: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; - return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; - } -"[(set_attr "length" "4,2,2,6,4,4")]) - -(define_expand "movsf" - [(set (match_operand:SF 0 "general_operand" "") - (match_operand:SF 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (SFmode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -(define_insn "*movsf_insn" - [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") - (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] - "register_operand (operands[0], SFmode) - || register_operand (operands[1], SFmode)" - "@ - add\\t%0, %1, #0 - ldmia\\t%1, {%0} - stmia\\t%0, {%1} - ldr\\t%0, %1 - str\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1") - -;; Widening move insns - -(define_expand "zero_extendhisi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); - emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16))); - DONE; - } -") - -(define_insn "*zero_extendhisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] - "" - "ldrh\\t%0, %1") - -(define_expand "zero_extendqisi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); - emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24))); - DONE; - } -") - -(define_insn "*zero_extendqisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] - "" - "ldrb\\t%0, %1") - -(define_expand "extendhisi2" - [(parallel [(set (match_operand:SI 0 "s_register_operand" "") - (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:SI 2 ""))])] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); - emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16))); - DONE; - } -") - -(define_insn "*extendhisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) - (clobber (match_scratch:SI 2 "=&l"))] - "" - "* -{ - rtx ops[4]; - /* This code used to try to use 'V', and fix the address only if it was - offsettable, but this fails for e.g. REG+48 because 48 is outside the - range of QImode offsets, and offsettable_address_p does a QImode - address check. */ - - if (GET_CODE (XEXP (operands[1], 0)) == PLUS) - { - ops[1] = XEXP (XEXP (operands[1], 0), 0); - ops[2] = XEXP (XEXP (operands[1], 0), 1); - } - else - { - ops[1] = XEXP (operands[1], 0); - ops[2] = const0_rtx; - } - if (GET_CODE (ops[2]) == REG) - return \"ldrsh\\t%0, %1\"; - - ops[0] = operands[0]; - ops[3] = operands[2]; - output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); - return \"\"; -}" -[(set_attr "length" "4")]) - -(define_expand "extendqisi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); - emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24))); - DONE; - } -") - -(define_insn "*extendqisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] - "" - "* -{ - rtx ops[3]; - - if (which_alternative == 0) - return \"ldrsb\\t%0, %1\"; - ops[0] = operands[0]; - if (GET_CODE (XEXP (operands[1], 0)) == PLUS) - { - ops[1] = XEXP (XEXP (operands[1], 0), 0); - ops[2] = XEXP (XEXP (operands[1], 0), 1); - - if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG) - output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); - else if (GET_CODE (ops[1]) == REG) - { - if (REGNO (ops[1]) == REGNO (operands[0])) - output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - else - { - if (REGNO (ops[2]) == REGNO (operands[0])) - output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - } - else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0))) - { - output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - } - else - { - ops[1] = XEXP (operands[1], 0); - ops[2] = const0_rtx; - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - return \"\"; -}" -[(set_attr "length" "2,6")]) - -;; We don't really have extzv, but defining this using shifts helps -;; to reduce register pressure later on. - -(define_expand "extzv" - [(set (match_dup 4) - (ashift:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "const_int_operand" ""))) - (set (match_operand:SI 0 "register_operand" "") - (lshiftrt:SI (match_dup 4) - (match_operand:SI 3 "const_int_operand" "")))] - "" - " -{ - HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); - HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); - operands[3] = GEN_INT (rshift); - if (lshift == 0) - { - emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); - DONE; - } - operands[2] = GEN_INT (lshift); - operands[4] = gen_reg_rtx (SImode); -} -") - -;; Block-move insns - -(define_expand "movstrqi" - [(match_operand:BLK 0 "general_operand" "") - (match_operand:BLK 1 "general_operand" "") - (match_operand:SI 2 "" "") - (match_operand:SI 3 "const_int_operand" "")] - "" - " - if (INTVAL (operands[3]) != 4 - || GET_CODE (operands[2]) != CONST_INT - || INTVAL (operands[2]) > 48) - FAIL; - - thumb_expand_movstrqi (operands); - DONE; -") - -(define_insn "movmem12b" - [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) - (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) - (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) - (mem:SI (plus:SI (match_dup 1) (const_int 8)))) - (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) - (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) - (clobber (match_scratch:SI 2 "=&l")) - (clobber (match_scratch:SI 3 "=&l")) - (clobber (match_scratch:SI 4 "=&l"))] - "" - "* return output_move_mem_multiple (3, operands);" -[(set_attr "length" "4")]) - -(define_insn "movmem8b" - [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) - (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) - (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) - (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) - (clobber (match_scratch:SI 2 "=&l")) - (clobber (match_scratch:SI 3 "=&l"))] - "" - "* return output_move_mem_multiple (2, operands);" -[(set_attr "length" "4")]) - -;; Arithmetic insns - -(define_insn "adddi3" - [(set (match_operand:DI 0 "s_register_operand" "=l") - (plus:DI (match_operand:DI 1 "s_register_operand" "%0") - (match_operand:DI 2 "s_register_operand" "l")))] - "" - "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" -[(set_attr "conds" "changed") - (set_attr "length" "8")]) - -;; register group 'k' is a single register group containing only the stack -;; register. Trying to reload it will always fail catastrophically, -;; so never allow those alternatives to match if reloading is needed. -(define_insn "addsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l,l,*r,*h,l,!k") - (plus:SI (match_operand:SI 1 "s_register_operand" "%0,0,l,*0,*0,!k,!k") - (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] - "" - "* - static char *asms[] = -{ - \"add\\t%0, %0, %2\", - \"sub\\t%0, %0, #%n2\", - \"add\\t%0, %1, %2\", - \"add\\t%0, %0, %2\", - \"add\\t%0, %0, %2\", - \"add\\t%0, %1, %2\", - \"add\\t%0, %1, %2\" -}; - if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) < 0) - return \"sub\\t%0, %1, #%n2\"; - return asms[which_alternative]; -") - -; reloading and elimination of the frame pointer can sometimes cause this -; optimization to be missed. -(define_peephole - [(set (match_operand:SI 0 "register_operand" "=l") - (match_operand:SI 1 "const_int_operand" "M")) - (set (match_dup 0) - (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] - "REGNO (operands[2]) == STACK_POINTER_REGNUM - && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 - && (INTVAL (operands[1]) & 3) == 0" - "add\\t%0, %2, %1") - -(define_insn "subdi3" - [(set (match_operand:DI 0 "s_register_operand" "=l") - (minus:DI (match_operand:DI 1 "s_register_operand" "0") - (match_operand:DI 2 "s_register_operand" "l")))] - "" - "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" -[(set_attr "conds" "changed") - (set_attr "length" "8")]) - -(define_insn "subsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (minus:SI (match_operand:SI 1 "s_register_operand" "l") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "sub\\t%0, %1, %2") - -;; We must ensure that one input matches the output, and that the other input -;; does not match the output. Using 0 satisfies the first, and using & -;; satisfies the second. Unfortunately, this fails when operands 1 and 2 -;; are the same, because reload will make operand 0 match operand 1 without -;; realizing that this conflicts with operand 2. We fix this by adding another -;; alternative to match this case, and then `reload' it ourselves. This -;; alternative must come first. -(define_insn "mulsi3" - [(set (match_operand:SI 0 "s_register_operand" "=&l,&l,&l") - (mult:SI (match_operand:SI 1 "s_register_operand" "%l,*h,0") - (match_operand:SI 2 "s_register_operand" "l,l,l")))] - "" - "* -{ - if (which_alternative < 2) - return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; - else - return \"mul\\t%0, %0, %2\"; -}" - [(set_attr "length" "4,4,2")]) - -(define_insn "negsi2" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (neg:SI (match_operand:SI 1 "s_register_operand" "l")))] - "" - "neg\\t%0, %1") - -;; Logical insns - -(define_expand "andsi3" - [(set (match_operand:SI 0 "s_register_operand" "") - (and:SI (match_operand:SI 1 "s_register_operand" "") - (match_operand:SI 2 "nonmemory_operand" "")))] - "" - " - if (GET_CODE (operands[2]) != CONST_INT) - operands[2] = force_reg (SImode, operands[2]); - else - { - int i; - if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) - { - operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); - emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); - DONE; - } - - for (i = 9; i <= 31; i++) - if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) - { - emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), - const0_rtx)); - DONE; - } - else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) - { - rtx shift = GEN_INT (i); - rtx reg = gen_reg_rtx (SImode); - emit_insn (gen_lshrsi3 (reg, operands[1], shift)); - emit_insn (gen_ashlsi3 (operands[0], reg, shift)); - DONE; - } - - operands[2] = force_reg (SImode, operands[2]); - } -") - -(define_insn "*andsi3_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (and:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "and\\t%0, %0, %2") - -(define_insn "bicsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "l")) - (match_operand:SI 2 "s_register_operand" "0")))] - "" - "bic\\t%0, %0, %1") - -(define_insn "iorsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (ior:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "orr\\t%0, %0, %2") - -(define_insn "xorsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (xor:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "eor\\t%0, %0, %2") - -(define_insn "one_cmplsi2" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (not:SI (match_operand:SI 1 "s_register_operand" "l")))] - "" - "mvn\\t%0, %1") - -;; Shift and rotation insns - -(define_insn "ashlsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (ashift:SI (match_operand:SI 1 "s_register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - lsl\\t%0, %1, %2 - lsl\\t%0, %0, %2") - -(define_insn "ashrsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - asr\\t%0, %1, %2 - asr\\t%0, %0, %2") - -(define_insn "lshrsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - lsr\\t%0, %1, %2 - lsr\\t%0, %0, %2") - -(define_insn "rotrsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (rotatert:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "ror\\t%0, %0, %2") - -;; Comparison insns - -(define_expand "cmpsi" - [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "") - (match_operand:SI 1 "nonmemory_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG) - { - if (GET_CODE (operands[1]) != CONST_INT - || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256) - { - if (GET_CODE (operands[1]) != CONST_INT - || INTVAL (operands[1]) < -255 - || INTVAL (operands[1]) > 0) - operands[1] = force_reg (SImode, operands[1]); - else - { - operands[1] = force_reg (SImode, - GEN_INT (- INTVAL (operands[1]))); - emit_insn (gen_cmnsi (operands[0], operands[1])); - DONE; - } - } - } -") - -(define_insn "*cmpsi_insn" - [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l,*r,*h") - (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))] - "" - "@ - cmp\\t%0, %1 - cmp\\t%0, %1 - cmp\\t%0, %1") - -(define_insn "tstsi" - [(set (cc0) (match_operand:SI 0 "s_register_operand" "l"))] - "" - "cmp\\t%0, #0") - -(define_insn "cmnsi" - [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l") - (neg:SI (match_operand:SI 1 "s_register_operand" "l"))))] - "" - "cmn\\t%0, %1") - -;; Jump insns - -(define_insn "jump" - [(set (pc) (label_ref (match_operand 0 "" "")))] - "" - "* - if (get_attr_length (insn) == 2) - return \"b\\t%l0\"; - return \"bl\\t%l0\\t%@ far jump\"; -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "4") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 2) - (const_int 4)))]) - - -(define_expand "beq" - [(set (pc) (if_then_else (eq (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bne" - [(set (pc) (if_then_else (ne (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bge" - [(set (pc) (if_then_else (ge (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "ble" - [(set (pc) (if_then_else (le (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgt" - [(set (pc) (if_then_else (gt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "blt" - [(set (pc) (if_then_else (lt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgeu" - [(set (pc) (if_then_else (geu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bleu" - [(set (pc) (if_then_else (leu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgtu" - [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bltu" - [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_insn "*cond_branch" - [(set (pc) (if_then_else (match_operator 1 "comparison_operator" - [(cc0) (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "* - switch (get_attr_length (insn)) - { - case 2: return \"b%d1\\t%l0\\t%@cond_branch\"; - case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\"; - default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\"; - } -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "6") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int -252)) - (le (minus (match_dup 0) (pc)) (const_int 254))) - (const_int 2) - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 4) - (const_int 6))))]) - -(define_insn "*cond_branch_reversed" - [(set (pc) (if_then_else (match_operator 1 "comparison_operator" - [(cc0) (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "* - switch (get_attr_length (insn)) - { - case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\"; - case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\"; - default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\"; - } - return \"\"; -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "6") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int -252)) - (le (minus (match_dup 0) (pc)) (const_int 254))) - (const_int 2) - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 4) - (const_int 6))))]) - -(define_insn "indirect_jump" - [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r"))] - "" - "mov\\tpc, %0") - -(define_insn "tablejump" - [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r")) - (use (label_ref (match_operand 1 "" "")))] - "" - "mov\\tpc, %0") - -(define_insn "return" - [(return)] - "USE_RETURN" - "* return output_return ();" -[(set_attr "length" "18")]) - -;; Call insns - -(define_expand "call" - [(call (match_operand:SI 0 "memory_operand" "") - (match_operand 1 "" ""))] - "" - " -{ - if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[0], 0)) != REG) - XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); -}") - -(define_insn "*call_indirect" - [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) - (match_operand 1 "" ""))] - "! TARGET_CALLER_INTERWORKING" - "bl\\t%__call_via_%0" -[(set_attr "length" "4")]) -;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version -;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set -;; the bottom bit of lr so that a function return (using bx) -;; would switch back into ARM mode... - -(define_insn "*call_indirect_interwork" - [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) - (match_operand 1 "" ""))] - "TARGET_CALLER_INTERWORKING" - "bl\\t%__interwork_call_via_%0" -[(set_attr "length" "4")]) - -(define_expand "call_value" - [(set (match_operand 0 "" "") - (call (match_operand 1 "memory_operand" "") - (match_operand 2 "" "")))] - "" - " -{ - if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[1], 0)) != REG) - XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); -}") - -(define_insn "*call_value_indirect" - [(set (match_operand 0 "" "=l") - (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) - (match_operand 2 "" "")))] - "! TARGET_CALLER_INTERWORKING" - "bl\\t%__call_via_%1" -[(set_attr "length" "4")]) -;; See comment for call_indirect pattern - -(define_insn "*call_value_indirect_interwork" - [(set (match_operand 0 "" "=l") - (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) - (match_operand 2 "" "")))] - "TARGET_CALLER_INTERWORKING" - "bl\\t%__interwork_call_via_%1" -[(set_attr "length" "4")]) - - -(define_insn "*call_insn" - [(call (mem:SI (match_operand:SI 0 "" "i")) - (match_operand:SI 1 "" ""))] - "! TARGET_LONG_CALLS && GET_CODE (operands[0]) == SYMBOL_REF" - "bl\\t%a0" -[(set_attr "length" "4")]) - -(define_insn "*call_value_insn" - [(set (match_operand 0 "s_register_operand" "=l") - (call (mem:SI (match_operand 1 "" "i")) - (match_operand 2 "" "")))] - "! TARGET_LONG_CALLS && GET_CODE (operands[1]) == SYMBOL_REF" - "bl\\t%a1" -[(set_attr "length" "4")]) - -;; Untyped call not required, since all funcs return in r0 - -;; Miscellaneous patterns - -(define_insn "nop" - [(clobber (const_int 0))] - "" - "mov\\tr8, r8") - -(define_insn "blockage" - [(unspec_volatile [(const_int 0)] 0)] - "" - "" - [(set_attr "length" "0")]) - -(define_expand "prologue" - [(const_int 0)] - "" - " - thumb_expand_prologue (); - DONE; -") - -(define_expand "epilogue" - [(unspec_volatile [(const_int 0)] 1)] - "! thumb_trivial_epilogue ()" - " - thumb_expand_epilogue (); -") - -(define_insn "*epilogue_insns" - [(unspec_volatile [(const_int 0)] 1)] - "" - "* - return thumb_unexpanded_epilogue (); -" -[(set_attr "length" "42")]) - -;; Special patterns for dealing with the constant pool - -(define_insn "consttable_4" - [(unspec_volatile [(match_operand 0 "" "")] 2)] - "" - "* -{ - switch (GET_MODE_CLASS (GET_MODE (operands[0]))) - { - case MODE_FLOAT: - { - union real_extract u; - bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); - assemble_real (u.d, GET_MODE (operands[0])); - break; - } - default: - assemble_integer (operands[0], 4, 1); - break; - } - return \"\"; -}" -[(set_attr "length" "4")]) - -(define_insn "consttable_8" - [(unspec_volatile [(match_operand 0 "" "")] 3)] - "" - "* -{ - switch (GET_MODE_CLASS (GET_MODE (operands[0]))) - { - case MODE_FLOAT: - { - union real_extract u; - bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); - assemble_real (u.d, GET_MODE (operands[0])); - break; - } - default: - assemble_integer (operands[0], 8, 1); - break; - } - return \"\"; -}" -[(set_attr "length" "8")]) - -(define_insn "consttable_end" - [(unspec_volatile [(const_int 0)] 4)] - "" - "* - /* Nothing to do (currently). */ - return \"\"; -") - -(define_insn "align_4" - [(unspec_volatile [(const_int 0)] 5)] - "" - "* - assemble_align (32); - return \"\"; -") diff --git a/gcc/config/arm/thumb.md.rej b/gcc/config/arm/thumb.md.rej deleted file mode 100755 index 2a1ba64..0000000 --- a/gcc/config/arm/thumb.md.rej +++ /dev/null @@ -1,168 +0,0 @@ -***************
-*** 1002,1019 ****
- ;; Call insns
-
- (define_expand "call"
-- [(call (match_operand:SI 0 "memory_operand" "")
-- (match_operand 1 "" ""))]
- ""
- "
- {
-- if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[0], 0)) != REG)
- XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0));
- }")
-
- (define_insn "*call_indirect"
-- [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
-- (match_operand 1 "" ""))]
- "! TARGET_CALLER_INTERWORKING"
- "bl\\t%__call_via_%0"
- [(set_attr "length" "4")])
---- 1002,1024 ----
- ;; Call insns
-
- (define_expand "call"
-+ [(parallel
-+ [(call (match_operand:SI 0 "memory_operand" "")
-+ (match_operand 1 "" ""))
-+ (use (match_operand 2 "" ""))])]
- ""
- "
- {
-+ if (GET_CODE (XEXP (operands[0], 0)) != REG
-+ && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0))
- XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0));
- }")
-
- (define_insn "*call_indirect"
-+ [(parallel
-+ [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
-+ (match_operand 1 "" ""))
-+ (use (match_operand 2 "" ""))])]
- "! TARGET_CALLER_INTERWORKING"
- "bl\\t%__call_via_%0"
- [(set_attr "length" "4")])
-***************
-*** 1023,1075 ****
- ;; would switch back into ARM mode...
-
- (define_insn "*call_indirect_interwork"
-- [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
-- (match_operand 1 "" ""))]
- "TARGET_CALLER_INTERWORKING"
- "bl\\t%__interwork_call_via_%0"
- [(set_attr "length" "4")])
-
- (define_expand "call_value"
-- [(set (match_operand 0 "" "")
-- (call (match_operand 1 "memory_operand" "")
-- (match_operand 2 "" "")))]
- ""
- "
- {
-- if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[1], 0)) != REG)
- XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0));
- }")
-
- (define_insn "*call_value_indirect"
-- [(set (match_operand 0 "" "=l")
-- (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
-- (match_operand 2 "" "")))]
- "! TARGET_CALLER_INTERWORKING"
- "bl\\t%__call_via_%1"
- [(set_attr "length" "4")])
- ;; See comment for call_indirect pattern
-
- (define_insn "*call_value_indirect_interwork"
-- [(set (match_operand 0 "" "=l")
-- (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
-- (match_operand 2 "" "")))]
- "TARGET_CALLER_INTERWORKING"
- "bl\\t%__interwork_call_via_%1"
- [(set_attr "length" "4")])
-
-
- (define_insn "*call_insn"
-- [(call (mem:SI (match_operand:SI 0 "" "i"))
-- (match_operand:SI 1 "" ""))]
-- "! TARGET_LONG_CALLS && GET_CODE (operands[0]) == SYMBOL_REF"
- "bl\\t%a0"
- [(set_attr "length" "4")])
-
- (define_insn "*call_value_insn"
-- [(set (match_operand 0 "register_operand" "=l")
- (call (mem:SI (match_operand 1 "" "i"))
-- (match_operand 2 "" "")))]
-- "! TARGET_LONG_CALLS && GET_CODE (operands[1]) == SYMBOL_REF"
- "bl\\t%a1"
- [(set_attr "length" "4")])
-
---- 1028,1095 ----
- ;; would switch back into ARM mode...
-
- (define_insn "*call_indirect_interwork"
-+ [(parallel
-+ [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
-+ (match_operand 1 "" ""))
-+ (use (match_operand 2 "" ""))])]
- "TARGET_CALLER_INTERWORKING"
- "bl\\t%__interwork_call_via_%0"
- [(set_attr "length" "4")])
-
- (define_expand "call_value"
-+ [(parallel
-+ [(set (match_operand 0 "" "")
-+ (call (match_operand 1 "memory_operand" "")
-+ (match_operand 2 "" "")))
-+ (use (match_operand 3 "" ""))])]
- ""
- "
- {
-+ if (GET_CODE (XEXP (operands[1], 0)) != REG
-+ && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0))
- XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0));
- }")
-
- (define_insn "*call_value_indirect"
-+ [(parallel
-+ [(set (match_operand 0 "" "=l")
-+ (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
-+ (match_operand 2 "" "")))
-+ (use (match_operand 3 "" ""))])]
- "! TARGET_CALLER_INTERWORKING"
- "bl\\t%__call_via_%1"
- [(set_attr "length" "4")])
- ;; See comment for call_indirect pattern
-
- (define_insn "*call_value_indirect_interwork"
-+ [(parallel
-+ [(set (match_operand 0 "" "=l")
-+ (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
-+ (match_operand 2 "" "")))
-+ (use (match_operand 3 "" ""))])]
- "TARGET_CALLER_INTERWORKING"
- "bl\\t%__interwork_call_via_%1"
- [(set_attr "length" "4")])
-
-
- (define_insn "*call_insn"
-+ [(parallel
-+ [(call (mem:SI (match_operand:SI 0 "" "i"))
-+ (match_operand:SI 1 "" ""))
-+ (use (match_operand 2 "" ""))])]
-+ "GET_CODE (operands[0]) == SYMBOL_REF
-+ && ! arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)"
- "bl\\t%a0"
- [(set_attr "length" "4")])
-
- (define_insn "*call_value_insn"
-+ [(parallel
-+ [(set (match_operand 0 "register_operand" "=l")
- (call (mem:SI (match_operand 1 "" "i"))
-+ (match_operand 2 "" "")))
-+ (use (match_operand 3 "" ""))])]
-+ "GET_CODE(operands[1]) == SYMBOL_REF
-+ && ! arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)"
- "bl\\t%a1"
- [(set_attr "length" "4")])
-
diff --git a/gcc/config/arm/thumb_000513.h b/gcc/config/arm/thumb_000513.h deleted file mode 100755 index a5c25b9..0000000 --- a/gcc/config/arm/thumb_000513.h +++ /dev/null @@ -1,1187 +0,0 @@ -/* Definitions of target machine for GNU compiler, for ARM/Thumb. - Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. - The basis of this contribution was generated by - Richard Earnshaw, Advanced RISC Machines Ltd - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* ??? The files thumb.{c,h,md} are all seriously lacking comments. */ - -/* ??? The files thumb.{c,h,md} need to be reviewed by an experienced - gcc hacker in their entirety. */ - -/* ??? The files thumb.{c,h,md} and tcoff.h are all separate from the arm - files, which will lead to many maintenance problems. These files are - likely missing all bug fixes made to the arm port since they diverged. */ - -/* ??? Many patterns in the md file accept operands that will require a - reload. These should be eliminated if possible by tightening the - predicates and/or constraints. This will give faster/smaller code. */ - -/* ??? There is no pattern for the TST instuction. Check for other unsupported - instructions. */ - -/* Run Time Target Specifications */ -#ifndef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dthumb -D__thumb -Acpu(arm) -Amachine(arm)" -#endif - -#ifndef CPP_SPEC -#define CPP_SPEC "\ -%{mbig-endian:-D__ARMEB__ -D__THUMBEB__} \ -%{mbe:-D__ARMEB__ -D__THUMBEB__} \ -%{!mbe: %{!mbig-endian:-D__ARMEL__ -D__THUMBEL__}} \ -" -#endif - -#ifndef ASM_SPEC -#define ASM_SPEC "-marm7tdmi %{mthumb-interwork:-mthumb-interwork} %{mbig-endian:-EB}" -#endif -#define LINK_SPEC "%{mbig-endian:-EB} -X" - -#define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr); - -/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ -#define THUMB_FLAG_BIG_END 0x0001 -#define THUMB_FLAG_BACKTRACE 0x0002 -#define THUMB_FLAG_LEAF_BACKTRACE 0x0004 -#define ARM_FLAG_THUMB 0x1000 /* same as in arm.h */ -#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING 0x40000 -#define THUMB_FLAG_CALLER_SUPER_INTERWORKING 0x80000 - - -/* Run-time compilation parameters selecting different hardware/software subsets. */ -extern int target_flags; -#define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */ -#define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END) -#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) -#define TARGET_BACKTRACE (leaf_function_p() \ - ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ - : (target_flags & THUMB_FLAG_BACKTRACE)) - -/* Set if externally visable functions should assume that they - might be called in ARM mode, from a non-thumb aware code. */ -#define TARGET_CALLEE_INTERWORKING \ - (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING) - -/* Set if calls via function pointers should assume that their - destination is non-Thumb aware. */ -#define TARGET_CALLER_INTERWORKING \ - (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING) - -/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */ -#ifndef SUBTARGET_SWITCHES -#define SUBTARGET_SWITCHES -#endif - -#define TARGET_SWITCHES \ -{ \ - {"big-endian", THUMB_FLAG_BIG_END}, \ - {"little-endian", -THUMB_FLAG_BIG_END}, \ - {"thumb-interwork", ARM_FLAG_THUMB}, \ - {"no-thumb-interwork", -ARM_FLAG_THUMB}, \ - {"tpcs-frame", THUMB_FLAG_BACKTRACE}, \ - {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \ - {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \ - {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \ - {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ - {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ - {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ - {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ - SUBTARGET_SWITCHES \ - {"", TARGET_DEFAULT} \ -} - -#define TARGET_OPTIONS \ -{ \ - { "structure-size-boundary=", & structure_size_string }, \ -} - -#define REGISTER_PREFIX "" - -#define CAN_DEBUG_WITHOUT_FP 1 - -#define ASM_APP_ON "" -#define ASM_APP_OFF "\t.code\t16\n" - -/* Output a gap. In fact we fill it with nulls. */ -#define ASM_OUTPUT_SKIP(STREAM, NBYTES) \ - fprintf ((STREAM), "\t.space\t%u\n", (NBYTES)) - -/* 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(STREAM,LOG) \ -{ \ - if ((LOG) > 0) \ - fprintf (STREAM, "\t.align\t%d\n", (LOG)); \ -} - -/* Output a common block */ -#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ - (fprintf ((STREAM), "\t.comm\t"), \ - assemble_name ((STREAM), (NAME)), \ - fprintf((STREAM), ", %d\t%s %d\n", (ROUNDED), (ASM_COMMENT_START), (SIZE))) - -#define ASM_GENERATE_INTERNAL_LABEL(STRING,PREFIX,NUM) \ - sprintf ((STRING), "*%s%s%d", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) - -/* This is how to output an internal numbered label where - PREFIX is the class of label and NUM is the number within the class. */ -#define ASM_OUTPUT_INTERNAL_LABEL(STREAM,PREFIX,NUM) \ - fprintf ((STREAM), "%s%s%d:\n", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) - -/* This is how to output a label which precedes a jumptable. Since - instructions are 2 bytes, we need explicit alignment here. */ - -#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ - do { \ - ASM_OUTPUT_ALIGN (FILE, 2); \ - ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \ - } while (0) - -/* This says how to define a local common symbol (ie, not visible to - linker). */ -#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ - (fprintf((STREAM),"\n\t.lcomm\t"), \ - assemble_name((STREAM),(NAME)), \ - fprintf((STREAM),",%u\n",(SIZE))) - -/* Output a reference to a label. */ -#define ASM_OUTPUT_LABELREF(STREAM,NAME) \ - fprintf ((STREAM), "%s%s", user_label_prefix, (NAME)) - -/* This is how to output an assembler line for a numeric constant byte. */ -#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ - fprintf ((STREAM), "\t.byte\t0x%x\n", (VALUE)) - -#define ASM_OUTPUT_INT(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.word\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.short\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.byte\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ -do { char dstr[30]; \ - long l[3]; \ - REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ - fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n", \ - l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ - } while (0) - -#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ -do { char dstr[30]; \ - long l[2]; \ - REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ - fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ - l[1], ASM_COMMENT_START, dstr); \ - } while (0) - -#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ -do { char dstr[30]; \ - long l; \ - REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ - fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ - ASM_COMMENT_START, dstr); \ - } while (0); - -/* Define results of standard character escape sequences. */ -#define TARGET_BELL 007 -#define TARGET_BS 010 -#define TARGET_TAB 011 -#define TARGET_NEWLINE 012 -#define TARGET_VT 013 -#define TARGET_FF 014 -#define TARGET_CR 015 - -/* This is how to output a string. */ -#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ -do { \ - register int i, c, len = (LEN), cur_pos = 17; \ - register unsigned char *string = (unsigned char *)(STRING); \ - fprintf ((STREAM), "\t.ascii\t\""); \ - for (i = 0; i < len; i++) \ - { \ - register int c = string[i]; \ - \ - switch (c) \ - { \ - case '\"': \ - case '\\': \ - putc ('\\', (STREAM)); \ - putc (c, (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_NEWLINE: \ - fputs ("\\n", (STREAM)); \ - if (i+1 < len \ - && (((c = string[i+1]) >= '\040' && c <= '~') \ - || c == TARGET_TAB)) \ - cur_pos = 32767; /* break right here */ \ - else \ - cur_pos += 2; \ - break; \ - \ - case TARGET_TAB: \ - fputs ("\\t", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_FF: \ - fputs ("\\f", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_BS: \ - fputs ("\\b", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_CR: \ - fputs ("\\r", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - default: \ - if (c >= ' ' && c < 0177) \ - { \ - putc (c, (STREAM)); \ - cur_pos++; \ - } \ - else \ - { \ - fprintf ((STREAM), "\\%03o", c); \ - cur_pos += 4; \ - } \ - } \ - \ - if (cur_pos > 72 && i+1 < len) \ - { \ - cur_pos = 17; \ - fprintf ((STREAM), "\"\n\t.ascii\t\""); \ - } \ - } \ - fprintf ((STREAM), "\"\n"); \ -} while (0) - -/* Output and Generation of Labels */ -#define ASM_OUTPUT_LABEL(STREAM,NAME) \ - (assemble_name ((STREAM), (NAME)), \ - fprintf ((STREAM), ":\n")) - -#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ - (fprintf ((STREAM), "\t.globl\t"), \ - assemble_name ((STREAM), (NAME)), \ - fputc ('\n', (STREAM))) - -/* Construct a private name. */ -#define ASM_FORMAT_PRIVATE_NAME(OUTVAR,NAME,NUMBER) \ - ((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \ - sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) - -/* Switch to the text or data segment. */ -#define TEXT_SECTION_ASM_OP ".text" -#define DATA_SECTION_ASM_OP ".data" -#define BSS_SECTION_ASM_OP ".bss" - -/* The assembler's names for the registers. */ -#ifndef REGISTER_NAMES -#define REGISTER_NAMES \ -{ \ - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ - "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", "ap" \ -} -#endif - -#ifndef ADDITIONAL_REGISTER_NAMES -#define ADDITIONAL_REGISTER_NAMES \ -{ \ - {"a1", 0}, \ - {"a2", 1}, \ - {"a3", 2}, \ - {"a4", 3}, \ - {"v1", 4}, \ - {"v2", 5}, \ - {"v3", 6}, \ - {"v4", 7}, \ - {"v5", 8}, \ - {"v6", 9}, \ - {"sb", 9}, \ - {"v7", 10}, \ - {"r10", 10}, /* sl */ \ - {"r11", 11}, /* fp */ \ - {"r12", 12}, /* ip */ \ - {"r13", 13}, /* sp */ \ - {"r14", 14}, /* lr */ \ - {"r15", 15} /* pc */ \ -} -#endif - -/* The assembler's parentheses characters. */ -#define ASM_OPEN_PAREN "(" -#define ASM_CLOSE_PAREN ")" - -#ifndef ASM_COMMENT_START -#define ASM_COMMENT_START "@" -#endif - -/* Output an element of a dispatch table. */ -#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ - fprintf (STREAM, "\t.word\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) - -#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ - fprintf (STREAM, "\tb\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) - -/* Storage Layout */ - -/* Define this is most significant bit is lowest numbered in - instructions that operate on numbered bit-fields. */ -#define BITS_BIG_ENDIAN 0 - -/* Define this if most significant byte of a word is the lowest - numbered. */ -#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) - -#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN) - -/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based - on processor pre-defineds when compiling libgcc2.c. */ -#if defined(__THUMBEB__) && !defined(__THUMBEL__) -#define LIBGCC2_WORDS_BIG_ENDIAN 1 -#else -#define LIBGCC2_WORDS_BIG_ENDIAN 0 -#endif - -#define FLOAT_WORDS_BIG_ENDIAN 1 - -#define BITS_PER_UNIT 8 -#define BITS_PER_WORD 32 - -#define UNITS_PER_WORD 4 - -#define POINTER_SIZE 32 - -#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ -{ \ - if (GET_MODE_CLASS (MODE) == MODE_INT \ - && GET_MODE_SIZE (MODE) < 4) \ - { \ - (UNSIGNEDP) = 1; \ - (MODE) = SImode; \ - } \ -} - -#define PARM_BOUNDARY 32 -#define STACK_BOUNDARY 32 - -#define FUNCTION_BOUNDARY 32 -#define BIGGEST_ALIGNMENT 32 - -/* Make strings word-aligned so strcpy from constants will be faster. */ -#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ - (TREE_CODE (EXP) == STRING_CST \ - && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) - -#define EMPTY_FIELD_BOUNDARY 32 - -#define STRUCTURE_SIZE_BOUNDARY 32 - -/* Used when parsing command line option -mstructure_size_boundary. */ -extern char * structure_size_string; - -#define STRICT_ALIGNMENT 1 - -#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT - - -/* Layout of Source Language Data Types */ - -#define DEFAULT_SIGNED_CHAR 0 - -#define TARGET_BELL 007 -#define TARGET_BS 010 -#define TARGET_TAB 011 -#define TARGET_NEWLINE 012 -#define TARGET_VT 013 -#define TARGET_FF 014 -#define TARGET_CR 015 - - -/* Register Usage */ - -/* Note there are 16 hard registers on the Thumb. We invent a 17th register - which is assigned to ARG_POINTER_REGNUM, but this is later removed by - elimination passes in the compiler. */ -#define FIRST_PSEUDO_REGISTER 17 - -/* ??? This is questionable. */ -#define FIXED_REGISTERS \ -{ \ - 0,0,0,0, \ - 0,0,0,0, \ - 0,0,0,1, \ - 0,1,1,1,1 \ -} - -/* ??? This is questionable. */ -#define CALL_USED_REGISTERS \ -{ \ - 1,1,1,1, \ - 0,0,0,0, \ - 0,0,0,1, \ - 1,1,1,1,1 \ -} - -#define HARD_REGNO_NREGS(REGNO,MODE) \ - ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ - / UNITS_PER_WORD) - -/* ??? Probably should only allow DImode/DFmode in even numbered registers. */ -#define HARD_REGNO_MODE_OK(REGNO,MODE) ((GET_MODE_SIZE (MODE) > UNITS_PER_WORD) ? (REGNO < 7) : 1) - -#define MODES_TIEABLE_P(MODE1,MODE2) 1 - -/* The NOARG_LO_REGS class is the set of LO_REGS that are not used for passing - arguments to functions. These are the registers that are available for - spilling during reload. The code in reload1.c:init_reload() will detect this - class and place it into 'reload_address_base_reg_class'. */ - -enum reg_class -{ - NO_REGS, - NONARG_LO_REGS, - LO_REGS, - STACK_REG, - BASE_REGS, - HI_REGS, - ALL_REGS, - LIM_REG_CLASSES -}; - -#define GENERAL_REGS ALL_REGS - -#define N_REG_CLASSES (int) LIM_REG_CLASSES - -#define REG_CLASS_NAMES \ -{ \ - "NO_REGS", \ - "NONARG_LO_REGS", \ - "LO_REGS", \ - "STACK_REG", \ - "BASE_REGS", \ - "HI_REGS", \ - "ALL_REGS" \ -} - -#define REG_CLASS_CONTENTS \ -{ \ - 0x00000, \ - 0x000f0, \ - 0x000ff, \ - 0x02000, \ - 0x020ff, \ - 0x0ff00, \ - 0x1ffff, \ -} - -#define REGNO_REG_CLASS(REGNO) \ - ((REGNO) == STACK_POINTER_REGNUM ? STACK_REG \ - : (REGNO) < 8 ? ((REGNO) < 4 ? LO_REGS \ - : NONARG_LO_REGS) \ - : HI_REGS) - -#define BASE_REG_CLASS BASE_REGS - -#define MODE_BASE_REG_CLASS(MODE) \ - ((MODE) != QImode && (MODE) != HImode \ - ? BASE_REGS : LO_REGS) - -#define INDEX_REG_CLASS LO_REGS - -/* When SMALL_REGISTER_CLASSES is nonzero, the compiler allows - registers explicitly used in the rtl to be used as spill registers - but prevents the compiler from extending the lifetime of these - registers. */ - -#define SMALL_REGISTER_CLASSES 1 - -#define REG_CLASS_FROM_LETTER(C) \ - ((C) == 'l' ? LO_REGS \ - : (C) == 'h' ? HI_REGS \ - : (C) == 'b' ? BASE_REGS \ - : (C) == 'k' ? STACK_REG \ - : NO_REGS) - -#define REGNO_OK_FOR_BASE_P(REGNO) \ - ((REGNO) < 8 \ - || (REGNO) == STACK_POINTER_REGNUM \ - || (unsigned) reg_renumber[REGNO] < 8 \ - || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM) - -#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ - ((REGNO) < 8 \ - || (unsigned) reg_renumber[REGNO] < 8 \ - || (GET_MODE_SIZE (MODE) >= 4 \ - && ((REGNO) == STACK_POINTER_REGNUM \ - || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM))) - -#define REGNO_OK_FOR_INDEX_P(REGNO) \ - ((REGNO) < 8 \ - || (unsigned) reg_renumber[REGNO] < 8) - -/* ??? This looks suspiciously wrong. */ -/* We need to leave BASE_REGS reloads alone, in order to avoid caller_save - lossage. Caller_saves requests a BASE_REGS reload (caller_save_spill_class) - and then later we verify that one was allocated. If PREFERRED_RELOAD_CLASS - says to allocate a LO_REGS spill instead, then this mismatch gives an - abort. Alternatively, this could be fixed by modifying BASE_REG_CLASS - to be LO_REGS instead of BASE_REGS. It is not clear what affect this - change would have. */ -/* ??? This looks even more suspiciously wrong. PREFERRED_RELOAD_CLASS - must always return a strict subset of the input class. Just blindly - returning LO_REGS is safe only if the input class is a superset of LO_REGS, - but there is no check for this. Added another exception for NONARG_LO_REGS - because it is not a superset of LO_REGS. */ -/* ??? We now use NONARG_LO_REGS for caller_save_spill_class, so the - comments about BASE_REGS are now obsolete. */ -#define PREFERRED_RELOAD_CLASS(X,CLASS) \ - ((CLASS) == BASE_REGS || (CLASS) == NONARG_LO_REGS ? (CLASS) \ - : LO_REGS) -/* - ((CONSTANT_P ((X)) && GET_CODE ((X)) != CONST_INT \ - && ! CONSTANT_POOL_ADDRESS_P((X))) ? NO_REGS \ - : (GET_CODE ((X)) == CONST_INT \ - && (unsigned HOST_WIDE_INT) INTVAL ((X)) > 255) ? NO_REGS \ - : LO_REGS) */ - -/* Must leave BASE_REGS and NONARG_LO_REGS reloads alone, see comment - above. */ -#define SECONDARY_RELOAD_CLASS(CLASS,MODE,X) \ - ((CLASS) != LO_REGS && (CLASS) != BASE_REGS && (CLASS) != NONARG_LO_REGS \ - ? ((true_regnum (X) == -1 ? LO_REGS \ - : (true_regnum (X) + HARD_REGNO_NREGS (0, MODE) > 8) ? LO_REGS \ - : NO_REGS)) \ - : NO_REGS) - -#define CLASS_MAX_NREGS(CLASS,MODE) HARD_REGNO_NREGS(0,(MODE)) - -int thumb_shiftable_const (); - -#define CONST_OK_FOR_LETTER_P(VAL,C) \ - ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VAL) < 256 \ - : (C) == 'J' ? (VAL) > -256 && (VAL) <= 0 \ - : (C) == 'K' ? thumb_shiftable_const (VAL) \ - : (C) == 'L' ? (VAL) > -8 && (VAL) < 8 \ - : (C) == 'M' ? ((unsigned HOST_WIDE_INT) (VAL) < 1024 \ - && ((VAL) & 3) == 0) \ - : (C) == 'N' ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ - : (C) == 'O' ? ((VAL) >= -508 && (VAL) <= 508) \ - : 0) - -#define CONST_DOUBLE_OK_FOR_LETTER_P(VAL,C) 0 - -#define EXTRA_CONSTRAINT(X,C) \ - ((C) == 'Q' ? (GET_CODE (X) == MEM \ - && GET_CODE (XEXP (X, 0)) == LABEL_REF) : 0) - -/* Stack Layout and Calling Conventions */ - -#define STACK_GROWS_DOWNWARD 1 - -/* #define FRAME_GROWS_DOWNWARD 1 */ - -/* #define ARGS_GROW_DOWNWARD 1 */ - -#define STARTING_FRAME_OFFSET 0 - -#define FIRST_PARM_OFFSET(FNDECL) 0 - -/* Registers that address the stack frame */ - -#define STACK_POINTER_REGNUM 13 /* Defined by the TPCS. */ - -#define FRAME_POINTER_REGNUM 7 /* TPCS defines this as 11 but it does not really mean it. */ - -#define ARG_POINTER_REGNUM 16 /* A fake hard register that is eliminated later on. */ - -#define STATIC_CHAIN_REGNUM 9 - -#define FRAME_POINTER_REQUIRED 0 - -#define ELIMINABLE_REGS \ -{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ - {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ - {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} - -/* On the Thumb we always want to perform the eliminations as we - actually only have one real register pointing to the stashed - variables: the stack pointer, and we never use the frame pointer. */ -#define CAN_ELIMINATE(FROM,TO) 1 - -/* Note: This macro must match the code in thumb_function_prologue() in thumb.c. */ -#define INITIAL_ELIMINATION_OFFSET(FROM,TO,OFFSET) \ -{ \ - (OFFSET) = 0; \ - if ((FROM) == ARG_POINTER_REGNUM) \ - { \ - int count_regs = 0; \ - int regno; \ - (OFFSET) += get_frame_size (); \ - for (regno = 8; regno < 13; regno++) \ - if (regs_ever_live[regno] && ! call_used_regs[regno]) \ - count_regs++; \ - if (count_regs) \ - (OFFSET) += 4 * count_regs; \ - count_regs = 0; \ - for (regno = 0; regno < 8; regno++) \ - if (regs_ever_live[regno] && ! call_used_regs[regno]) \ - count_regs++; \ - if (count_regs || ! leaf_function_p () || far_jump_used_p()) \ - (OFFSET) += 4 * (count_regs + 1); \ - if (TARGET_BACKTRACE) { \ - if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0)) \ - (OFFSET) += 20; \ - else \ - (OFFSET) += 16; } \ - } \ - if ((TO) == STACK_POINTER_REGNUM) \ - (OFFSET) += current_function_outgoing_args_size; \ -} - -/* Passing Arguments on the stack */ - -#define PROMOTE_PROTOTYPES 1 - -#define ACCUMULATE_OUTGOING_ARGS 1 - -#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 - -#define FUNCTION_ARG(CUM,MODE,TYPE,NAMED) \ - ((NAMED) ? ((CUM) >= 16 ? 0 : gen_rtx (REG, (MODE), (CUM) / 4)) \ - : 0) - -#define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) \ - (((CUM) < 16 && (CUM) + (((MODE) == BLKmode) \ - ? int_size_in_bytes (TYPE) \ - : HARD_REGNO_NREGS (0, (MODE)) * 4) > 16) \ - ? 4 - (CUM) / 4 : 0) - -#define CUMULATIVE_ARGS int - -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ - ((CUM) = ((FNTYPE) && aggregate_value_p (TREE_TYPE (FNTYPE))) ? 4 : 0) - -#define FUNCTION_ARG_ADVANCE(CUM,MODE,TYPE,NAMED) \ - (CUM) += ((((MODE) == BLKmode) \ - ? int_size_in_bytes (TYPE) \ - : GET_MODE_SIZE (MODE)) + 3) & ~3 - -#define FUNCTION_ARG_REGNO_P(REGNO) \ - ((REGNO) >=0 && (REGNO) <= 3) - -#define FUNCTION_VALUE(VALTYPE,FUNC) gen_rtx (REG, TYPE_MODE (VALTYPE), 0) - -#define LIBCALL_VALUE(MODE) gen_rtx (REG, (MODE), 0) - -#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == 0) - - /* How large values are returned */ -/* A C expression which can inhibit the returning of certain function values - in registers, based on the type of value. */ -#define RETURN_IN_MEMORY(TYPE) thumb_return_in_memory (TYPE) - -/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return - values must be in memory. On the ARM, they need only do so if larger - than a word, or if they contain elements offset from zero in the struct. */ -#define DEFAULT_PCC_STRUCT_RETURN 0 - - -#define STRUCT_VALUE_REGNUM 0 - -#define FUNCTION_PROLOGUE(FILE,SIZE) thumb_function_prologue((FILE),(SIZE)) - -#define FUNCTION_EPILOGUE(FILE,SIZE) thumb_function_epilogue((FILE),(SIZE)) - -/* Implementing the Varargs Macros */ - -#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ -{ \ - extern int current_function_anonymous_args; \ - current_function_anonymous_args = 1; \ - if ((CUM) < 16) \ - (PRETEND_SIZE) = 16 - (CUM); \ -} - -/* Trampolines for nested functions */ - -/* Output assembler code for a block containing the constant parts of - a trampoline, leaving space for the variable parts. - - On the Thumb we always switch into ARM mode to execute the trampoline. - Why - because it is easier. This code will always be branched to via - a BX instruction and since the compiler magically generates the address - of the function the linker has no opportunity to ensure that the - bottom bit is set. Thus the processor will be in ARM mode when it - reaches this code. So we duplicate the ARM trampoline code and add - a switch into Thumb mode as well. - - On the ARM, (if r8 is the static chain regnum, and remembering that - referencing pc adds an offset of 8) the trampoline looks like: - ldr r8, [pc, #0] - ldr pc, [pc] - .word static chain value - .word function's address - ??? FIXME: When the trampoline returns, r8 will be clobbered. */ -#define TRAMPOLINE_TEMPLATE(FILE) \ -{ \ - fprintf ((FILE), "\t.code 32\n"); \ - fprintf ((FILE), ".Ltrampoline_start:\n"); \ - fprintf ((FILE), "\tldr\t%s, [%spc, #8]\n", \ - reg_names[STATIC_CHAIN_REGNUM], REGISTER_PREFIX); \ - fprintf ((FILE), "\tldr\t%sip, [%spc, #8]\n", \ - REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf ((FILE), "\torr\t%sip, %sip, #1\n", \ - REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf ((FILE), "\tbx\t%sip\n", REGISTER_PREFIX); \ - fprintf ((FILE), "\t.word\t0\n"); \ - fprintf ((FILE), "\t.word\t0\n"); \ - fprintf ((FILE), "\t.code 16\n"); \ -} - -/* Length in units of the trampoline for entering a nested function. */ -#define TRAMPOLINE_SIZE 24 - -/* Alignment required for a trampoline in units. */ -#define TRAMPOLINE_ALIGN 4 - -#define INITIALIZE_TRAMPOLINE(ADDR,FNADDR,CHAIN) \ -{ \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 16)), \ - (CHAIN)); \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 20)), \ - (FNADDR)); \ -} - - -/* Implicit Calls to Library Routines */ - -#define TARGET_MEM_FUNCTIONS 1 - -#define OVERRIDE_OPTIONS thumb_override_options () - - -/* Addressing Modes */ - -#define HAVE_POST_INCREMENT 1 - -#define CONSTANT_ADDRESS_P(X) \ - (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X)) - -#define MAX_REGS_PER_ADDRESS 2 - -#ifdef REG_OK_STRICT - -#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) -#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) - -#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ - REGNO_MODE_OK_FOR_BASE_P (REGNO (X), MODE) - -#else /* REG_OK_STRICT */ - -#define REG_OK_FOR_BASE_P(X) \ - (REGNO (X) < 8 || REGNO (X) == STACK_POINTER_REGNUM \ - || (X) == arg_pointer_rtx \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER) - -#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ - (REGNO (X) < 8 \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER \ - || (GET_MODE_SIZE (MODE) >= 4 \ - && (REGNO (X) == STACK_POINTER_REGNUM \ - || (X) == arg_pointer_rtx))) - -#define REG_OK_FOR_INDEX_P(X) \ - (REGNO (X) < 8 \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER) - -#endif /* REG_OK_STRICT */ - -/* In a REG+REG address, both must be INDEX registers. */ -#define REG_OK_FOR_INDEXED_BASE_P(X) REG_OK_FOR_INDEX_P(X) - -#define LEGITIMATE_OFFSET(MODE,VAL) \ -(GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ - : GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \ - && ((VAL) & 1) == 0) \ - : ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \ - && ((VAL) & 3) == 0)) - -/* The AP may be eliminated to either the SP or the FP, so we use the - least common denominator, e.g. SImode, and offsets from 0 to 64. */ - -/* ??? Verify whether the above is the right approach. */ - -/* ??? Also, the FP may be eliminated to the SP, so perhaps that - needs special handling also. */ - -/* ??? Look at how the mips16 port solves this problem. It probably uses - better ways to solve some of these problems. */ - -/* Although it is not incorrect, we don't accept QImode and HImode - addresses based on the frame pointer or arg pointer until the reload pass starts. - This is so that eliminating such addresses into stack based ones - won't produce impossible code. */ -#define GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \ -{ \ - /* ??? Not clear if this is right. Experiment. */ \ - if (GET_MODE_SIZE (MODE) < 4 \ - && ! (reload_in_progress || reload_completed) \ - && (reg_mentioned_p (frame_pointer_rtx, X) \ - || reg_mentioned_p (arg_pointer_rtx, X) \ - || reg_mentioned_p (virtual_incoming_args_rtx, X) \ - || reg_mentioned_p (virtual_outgoing_args_rtx, X) \ - || reg_mentioned_p (virtual_stack_dynamic_rtx, X) \ - || reg_mentioned_p (virtual_stack_vars_rtx, X))) \ - ; \ - /* Accept any base register. SP only in SImode or larger. */ \ - else if (GET_CODE (X) == REG && REG_MODE_OK_FOR_BASE_P(X, MODE)) \ - goto WIN; \ - /* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \ - else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \ - && CONSTANT_POOL_ADDRESS_P (X)) \ - goto WIN; \ - /* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \ - else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ - && (GET_CODE (X) == LABEL_REF \ - || (GET_CODE (X) == CONST \ - && GET_CODE (XEXP (X, 0)) == PLUS \ - && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \ - && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \ - goto WIN; \ - /* Post-inc indexing only supported for SImode and larger. */ \ - else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \ - && GET_CODE (XEXP (X, 0)) == REG \ - && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ - goto WIN; \ - else if (GET_CODE (X) == PLUS) \ - { \ - /* REG+REG address can be any two index registers. */ \ - /* ??? REG+REG addresses have been completely disabled before \ - reload completes, because we do not have enough available \ - reload registers. We only have 3 guaranteed reload registers \ - (NONARG_LO_REGS - the frame pointer), but we need at least 4 \ - to support REG+REG addresses. We have left them enabled after \ - reload completes, in the hope that reload_cse_regs and related \ - routines will be able to create them after the fact. It is \ - probably possible to support REG+REG addresses with additional \ - reload work, but I do not not have enough time to attempt such \ - a change at this time. */ \ - /* ??? Normally checking the mode here is wrong, since it isn't \ - impossible to use REG+REG with DFmode. However, the movdf \ - pattern requires offsettable addresses, and REG+REG is not \ - offsettable, so it must be rejected somehow. Trying to use \ - 'o' fails, because offsettable_address_p does a QImode check. \ - QImode is not valid for stack addresses, and has a smaller \ - range for non-stack bases, and this causes valid addresses \ - to be rejected. So we just eliminate REG+REG here by checking \ - the mode. */ \ - /* We also disallow FRAME+REG addressing since we know that FRAME \ - will be replaced with STACK, and SP relative addressing only \ - permits SP+OFFSET. */ \ - if (GET_MODE_SIZE (MODE) <= 4 \ - /* ??? See comment above. */ \ - && reload_completed \ - && GET_CODE (XEXP (X, 0)) == REG \ - && GET_CODE (XEXP (X, 1)) == REG \ - && XEXP (X, 0) != frame_pointer_rtx \ - && XEXP (X, 1) != frame_pointer_rtx \ - && XEXP (X, 0) != virtual_stack_vars_rtx \ - && XEXP (X, 1) != virtual_stack_vars_rtx \ - && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ - && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ - goto WIN; \ - /* REG+const has 5-7 bit offset for non-SP registers. */ \ - else if (GET_CODE (XEXP (X, 0)) == REG \ - && (REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ - || XEXP (X, 0) == arg_pointer_rtx) \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ - goto WIN; \ - /* REG+const has 10 bit offset for SP, but only SImode and \ - larger is supported. */ \ - /* ??? Should probably check for DI/DFmode overflow here \ - just like GO_IF_LEGITIMATE_OFFSET does. */ \ - else if (GET_CODE (XEXP (X, 0)) == REG \ - && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \ - && GET_MODE_SIZE (MODE) >= 4 \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && (unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) < 1024 \ - && (INTVAL (XEXP (X, 1)) & 3) == 0) \ - goto WIN; \ - } \ -} - -/* ??? If an HImode FP+large_offset address is converted to an HImode - SP+large_offset address, then reload won't know how to fix it. It sees - only that SP isn't valid for HImode, and so reloads the SP into an index - register, but the resulting address is still invalid because the offset - is too big. We fix it here instead by reloading the entire address. */ -/* We could probably achieve better results by defining PROMOTE_MODE to help - cope with the variances between the Thumb's signed and unsigned byte and - halfword load instructions. */ -#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ -{ \ - if (GET_CODE (X) == PLUS \ - && GET_MODE_SIZE (MODE) < 4 \ - && GET_CODE (XEXP (X, 0)) == REG \ - && XEXP (X, 0) == stack_pointer_rtx \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && ! LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ - { \ - rtx orig_X = X; \ - X = copy_rtx (X); \ - push_reload (orig_X, NULL_RTX, &X, NULL_PTR, \ - BASE_REG_CLASS, \ - Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \ - goto WIN; \ - } \ -} - -#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) - -#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) - -#define LEGITIMATE_CONSTANT_P(X) \ - (GET_CODE (X) == CONST_INT \ - || GET_CODE (X) == CONST_DOUBLE \ - || CONSTANT_ADDRESS_P (X)) - - -/* Condition Code Status */ - -#define NOTICE_UPDATE_CC(EXP,INSN) \ -{ \ - if (get_attr_conds ((INSN)) != CONDS_UNCHANGED) \ - CC_STATUS_INIT; \ -} - - -/* Describing Relative Costs of Operations */ - -#define SLOW_BYTE_ACCESS 0 - -#define SLOW_UNALIGNED_ACCESS 1 - -#define NO_FUNCTION_CSE 1 - -#define NO_RECURSIVE_FUNCTION_CSE 1 - -#define REGISTER_MOVE_COST(FROM,TO) \ - (((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2) - -#define MEMORY_MOVE_COST(M,CLASS,IN) \ - ((GET_MODE_SIZE(M) < 4 ? 8 : 2 * GET_MODE_SIZE(M)) * (CLASS == LO_REGS ? 1 : 2)) - -/* This will allow better space optimization when compiling with -O */ -#define BRANCH_COST (optimize > 1 ? 1 : 0) - -#define RTX_COSTS(X,CODE,OUTER) \ - case MULT: \ - if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ - { \ - int cycles = 0; \ - unsigned HOST_WIDE_INT i = INTVAL (XEXP (X, 1)); \ - while (i) \ - { \ - i >>= 2; \ - cycles++; \ - } \ - return COSTS_N_INSNS (2) + cycles; \ - } \ - return COSTS_N_INSNS (1) + 16; \ - case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATERT: \ - case PLUS: case MINUS: case COMPARE: case NEG: case NOT: \ - return COSTS_N_INSNS (1); \ - case SET: \ - return (COSTS_N_INSNS (1) \ - + 4 * ((GET_CODE (SET_SRC (X)) == MEM) \ - + GET_CODE (SET_DEST (X)) == MEM)) - -#define CONST_COSTS(X,CODE,OUTER) \ - case CONST_INT: \ - if ((OUTER) == SET) \ - { \ - if ((unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ - return 0; \ - if (thumb_shiftable_const (INTVAL (X))) \ - return COSTS_N_INSNS (2); \ - return COSTS_N_INSNS (3); \ - } \ - else if (OUTER == PLUS \ - && INTVAL (X) < 256 && INTVAL (X) > -256) \ - return 0; \ - else if (OUTER == COMPARE \ - && (unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ - return 0; \ - else if (OUTER == ASHIFT || OUTER == ASHIFTRT \ - || OUTER == LSHIFTRT) \ - return 0; \ - return COSTS_N_INSNS (2); \ - case CONST: \ - case CONST_DOUBLE: \ - case LABEL_REF: \ - case SYMBOL_REF: \ - return COSTS_N_INSNS(3); - -#define ADDRESS_COST(X) \ - ((GET_CODE (X) == REG \ - || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \ - && GET_CODE (XEXP (X, 1)) == CONST_INT)) \ - ? 1 : 2) - - -/* Position Independent Code */ - -#define PRINT_OPERAND(STREAM,X,CODE) \ - thumb_print_operand((STREAM), (X), (CODE)) - -#define PRINT_OPERAND_ADDRESS(STREAM,X) \ -{ \ - if (GET_CODE ((X)) == REG) \ - fprintf ((STREAM), "[%s]", reg_names[REGNO ((X))]); \ - else if (GET_CODE ((X)) == POST_INC) \ - fprintf ((STREAM), "%s!", reg_names[REGNO (XEXP (X, 0))]); \ - else if (GET_CODE ((X)) == PLUS) \ - { \ - if (GET_CODE (XEXP ((X), 1)) == CONST_INT) \ - fprintf ((STREAM), "[%s, #%d]", \ - reg_names[REGNO (XEXP ((X), 0))], \ - (int) INTVAL (XEXP ((X), 1))); \ - else \ - fprintf ((STREAM), "[%s, %s]", \ - reg_names[REGNO (XEXP ((X), 0))], \ - reg_names[REGNO (XEXP ((X), 1))]); \ - } \ - else \ - output_addr_const ((STREAM), (X)); \ -} - -#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_')) - -/* Emit a special directive when defining a function name. - This is used by the assembler to assit with interworking. */ -#define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ - if (! is_called_in_ARM_mode (decl)) \ - fprintf (file, "\t.thumb_func\n") ; \ - else \ - fprintf (file, "\t.code\t32\n") ; \ - ASM_OUTPUT_LABEL (file, name) - -#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ - asm_fprintf ((STREAM), "\tpush {%R%s}\n", reg_names[(REGNO)]) - -#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ - fprintf ((STREAM), "\tpop {%R%s}\n", reg_names[(REGNO)]) - -#define FINAL_PRESCAN_INSN(INSN,OPVEC,NOPERANDS) \ - final_prescan_insn((INSN)) - -/* Controlling Debugging Information Format */ -#define DBX_REGISTER_NUMBER(REGNO) (REGNO) - -/* Specific options for DBX Output */ - -#define DBX_DEBUGGING_INFO 1 - -#define DEFAULT_GDB_EXTENSIONS 1 - - -/* Cross Compilation and Floating Point */ - -#define REAL_ARITHMETIC - - -/* Miscellaneous Parameters */ - -#define PREDICATE_CODES \ - {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, - -#define CASE_VECTOR_MODE Pmode - -#define WORD_REGISTER_OPERATIONS - -#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND - -#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR - -#define EASY_DIV_EXPR TRUNC_DIV_EXPR - -#define MOVE_MAX 4 - -#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 - -#define STORE_FLAG_VALUE 1 - -#define Pmode SImode - -#define FUNCTION_MODE SImode - -#define DOLLARS_IN_IDENTIFIERS 0 - -#define NO_DOLLAR_IN_LABEL 1 - -#define HAVE_ATEXIT - -/* The literal pool needs to reside in the text area due to the - limited PC addressing range: */ -#define MACHINE_DEPENDENT_REORG(INSN) thumb_reorg ((INSN)) - - -/* Options specific to Thumb */ - -/* True if a return instruction can be used in this function. */ -int thumb_trivial_epilogue (); -#define USE_RETURN (reload_completed && thumb_trivial_epilogue ()) - -extern char * thumb_unexpanded_epilogue (); -extern char * output_move_mem_multiple (); -extern char * thumb_load_double_from_address (); -extern char * output_return (); -extern int far_jump_used_p(); -extern int is_called_in_ARM_mode (); - diff --git a/gcc/config/arm/thumb_010110a.c b/gcc/config/arm/thumb_010110a.c deleted file mode 100755 index ef7ebff..0000000 --- a/gcc/config/arm/thumb_010110a.c +++ /dev/null @@ -1,2124 +0,0 @@ -/* Output routines for GCC for ARM/Thumb - Copyright (C) 1996 Cygnus Software Technologies Ltd - The basis of this contribution was generated by - Richard Earnshaw, Advanced RISC Machines Ltd - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#include <stdio.h> -#include <string.h> -#include "config.h" -#include "rtl.h" -#include "hard-reg-set.h" -#include "regs.h" -#include "output.h" -#include "insn-flags.h" -#include "insn-attr.h" -#include "flags.h" -#include "tree.h" -#include "expr.h" - - -int current_function_anonymous_args = 0; - -/* Used to parse -mstructure_size_boundary command line option. */ -char * structure_size_string = NULL; -int arm_structure_size_boundary = 32; /* Used to be 8 */ - - -/* Predicates */ -int -reload_memory_operand (op, mode) - rtx op; - enum machine_mode mode; -{ - int regno = true_regnum (op); - - return (! CONSTANT_P (op) - && (regno == -1 - || (GET_CODE (op) == REG - && REGNO (op) >= FIRST_PSEUDO_REGISTER))); -} - -/* Return nonzero if op is suitable for the RHS of a cmp instruction. */ -int -thumb_cmp_operand (op, mode) - rtx op; - enum machine_mode mode; -{ - return ((GET_CODE (op) == CONST_INT - && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256) - || register_operand (op, mode)); -} - -int -thumb_shiftable_const (val) - HOST_WIDE_INT val; -{ - unsigned HOST_WIDE_INT x = val; - unsigned HOST_WIDE_INT mask = 0xff; - int i; - - for (i = 0; i < 25; i++) - if ((val & (mask << i)) == val) - return 1; - - return 0; -} - -int -thumb_trivial_epilogue () -{ - int regno; - - /* ??? If this function ever returns 1, we get a function without any - epilogue at all. It appears that the intent was to cause a "return" - insn to be emitted, but that does not happen. */ - return 0; - -#if 0 - if (get_frame_size () - || current_function_outgoing_args_size - || current_function_pretend_args_size) - return 0; - - for (regno = 8; regno < 13; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - return 0; - - return 1; -#endif -} - - -/* Routines for handling the constant pool */ -/* This is unashamedly hacked from the version in sh.c, since the problem is - extremely similar. */ - -/* Thumb instructions cannot load a large constant into a register, - constants have to come from a pc relative load. The reference of a pc - relative load instruction must be less than 1k infront of the instruction. - This means that we often have to dump a constant inside a function, and - generate code to branch around it. - - It is important to minimize this, since the branches will slow things - down and make things bigger. - - Worst case code looks like: - - ldr rn, L1 - b L2 - align - L1: .long value - L2: - .. - - ldr rn, L3 - b L4 - align - L3: .long value - L4: - .. - - We fix this by performing a scan before scheduling, which notices which - instructions need to have their operands fetched from the constant table - and builds the table. - - - The algorithm is: - - scan, find an instruction which needs a pcrel move. Look forward, find the - last barrier which is within MAX_COUNT bytes of the requirement. - If there isn't one, make one. Process all the instructions between - the find and the barrier. - - In the above example, we can tell that L3 is within 1k of L1, so - the first move can be shrunk from the 2 insn+constant sequence into - just 1 insn, and the constant moved to L3 to make: - - ldr rn, L1 - .. - ldr rn, L3 - b L4 - align - L1: .long value - L3: .long value - L4: - - Then the second move becomes the target for the shortening process. - - */ - -typedef struct -{ - rtx value; /* Value in table */ - HOST_WIDE_INT next_offset; - enum machine_mode mode; /* Mode of value */ -} pool_node; - -/* The maximum number of constants that can fit into one pool, since - the pc relative range is 0...1020 bytes and constants are at least 4 - bytes long */ - -#define MAX_POOL_SIZE (1020/4) -static pool_node pool_vector[MAX_POOL_SIZE]; -static int pool_size; -static rtx pool_vector_label; - -/* Add a constant to the pool and return its label. */ - -static HOST_WIDE_INT -add_constant (x, mode) - rtx x; - enum machine_mode mode; -{ - int i; - rtx lab; - HOST_WIDE_INT offset; - - if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0)) - && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) - x = get_pool_constant (XEXP (x, 0)); - - /* First see if we've already got it */ - - for (i = 0; i < pool_size; i++) - { - if (x->code == pool_vector[i].value->code - && mode == pool_vector[i].mode) - { - if (x->code == CODE_LABEL) - { - if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) - continue; - } - if (rtx_equal_p (x, pool_vector[i].value)) - return pool_vector[i].next_offset - GET_MODE_SIZE (mode); - } - } - - /* Need a new one */ - - pool_vector[pool_size].next_offset = GET_MODE_SIZE (mode); - offset = 0; - if (pool_size == 0) - pool_vector_label = gen_label_rtx (); - else - pool_vector[pool_size].next_offset - += (offset = pool_vector[pool_size - 1].next_offset); - - pool_vector[pool_size].value = x; - pool_vector[pool_size].mode = mode; - pool_size++; - return offset; -} - -/* Output the literal table */ - -static void -dump_table (scan) - rtx scan; -{ - int i; - - scan = emit_label_after (gen_label_rtx (), scan); - scan = emit_insn_after (gen_align_4 (), scan); - scan = emit_label_after (pool_vector_label, scan); - - for (i = 0; i < pool_size; i++) - { - pool_node *p = pool_vector + i; - - switch (GET_MODE_SIZE (p->mode)) - { - case 4: - scan = emit_insn_after (gen_consttable_4 (p->value), scan); - break; - - case 8: - scan = emit_insn_after (gen_consttable_8 (p->value), scan); - break; - - default: - abort (); - break; - } - } - - scan = emit_insn_after (gen_consttable_end (), scan); - scan = emit_barrier_after (scan); - pool_size = 0; -} - -/* Non zero if the src operand needs to be fixed up */ -static -int -fixit (src, mode) - rtx src; - enum machine_mode mode; -{ - return ((CONSTANT_P (src) - && (GET_CODE (src) != CONST_INT - || ! (CONST_OK_FOR_LETTER_P (INTVAL (src), 'I') - || CONST_OK_FOR_LETTER_P (INTVAL (src), 'J') - || (mode != DImode - && CONST_OK_FOR_LETTER_P (INTVAL (src), 'K'))))) - || (mode == SImode && GET_CODE (src) == MEM - && GET_CODE (XEXP (src, 0)) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (XEXP (src, 0)))); -} - -/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one. */ - -#define MAX_COUNT_SI 1000 - -static rtx -find_barrier (from) - rtx from; -{ - int count = 0; - rtx found_barrier = 0; - rtx label; - - while (from && count < MAX_COUNT_SI) - { - if (GET_CODE (from) == BARRIER) - return from; - - /* Count the length of this insn */ - if (GET_CODE (from) == INSN - && GET_CODE (PATTERN (from)) == SET - && CONSTANT_P (SET_SRC (PATTERN (from))) - && CONSTANT_POOL_ADDRESS_P (SET_SRC (PATTERN (from)))) - { - rtx src = SET_SRC (PATTERN (from)); - count += 2; - } - else - count += get_attr_length (from); - - from = NEXT_INSN (from); - } - - /* We didn't find a barrier in time to - dump our stuff, so we'll make one */ - label = gen_label_rtx (); - - if (from) - from = PREV_INSN (from); - else - from = get_last_insn (); - - /* Walk back to be just before any jump */ - while (GET_CODE (from) == JUMP_INSN - || GET_CODE (from) == NOTE - || GET_CODE (from) == CODE_LABEL) - from = PREV_INSN (from); - - from = emit_jump_insn_after (gen_jump (label), from); - JUMP_LABEL (from) = label; - found_barrier = emit_barrier_after (from); - emit_label_after (label, found_barrier); - return found_barrier; -} - -/* Non zero if the insn is a move instruction which needs to be fixed. */ - -static int -broken_move (insn) - rtx insn; -{ - if (!INSN_DELETED_P (insn) - && GET_CODE (insn) == INSN - && GET_CODE (PATTERN (insn)) == SET) - { - rtx pat = PATTERN (insn); - rtx src = SET_SRC (pat); - rtx dst = SET_DEST (pat); - enum machine_mode mode = GET_MODE (dst); - if (dst == pc_rtx) - return 0; - return fixit (src, mode); - } - return 0; -} - -/* Recursively search through all of the blocks in a function - checking to see if any of the variables created in that - function match the RTX called 'orig'. If they do then - replace them with the RTX called 'new'. */ - -static void -replace_symbols_in_block (tree block, rtx orig, rtx new) -{ - for (; block; block = BLOCK_CHAIN (block)) - { - tree sym; - - if (! TREE_USED (block)) - continue; - - for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym)) - { - if ( (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL) - || DECL_IGNORED_P (sym) - || TREE_CODE (sym) != VAR_DECL - || DECL_EXTERNAL (sym) - || ! rtx_equal_p (DECL_RTL (sym), orig) - ) - continue; - - DECL_RTL (sym) = new; - } - - replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new); - } -} - -void -thumb_reorg (first) - rtx first; -{ - rtx insn; - for (insn = first; insn; insn = NEXT_INSN (insn)) - { - if (broken_move (insn)) - { - /* This is a broken move instruction, scan ahead looking for - a barrier to stick the constant table behind */ - rtx scan; - rtx barrier = find_barrier (insn); - - /* Now find all the moves between the points and modify them */ - for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) - { - if (broken_move (scan)) - { - /* This is a broken move instruction, add it to the pool */ - rtx pat = PATTERN (scan); - rtx src = SET_SRC (pat); - rtx dst = SET_DEST (pat); - enum machine_mode mode = GET_MODE (dst); - HOST_WIDE_INT offset; - rtx newinsn; - rtx newsrc; - - /* If this is an HImode constant load, convert it into - an SImode constant load. Since the register is always - 32 bits this is safe. We have to do this, since the - load pc-relative instruction only does a 32-bit load. */ - if (mode == HImode) - { - mode = SImode; - if (GET_CODE (dst) != REG) - abort (); - PUT_MODE (dst, SImode); - } - - offset = add_constant (src, mode); - newsrc = gen_rtx (MEM, mode, - plus_constant (gen_rtx (LABEL_REF, - VOIDmode, - pool_vector_label), - offset)); - - /* Build a jump insn wrapper around the move instead - of an ordinary insn, because we want to have room for - the target label rtx in fld[7], which an ordinary - insn doesn't have. */ - newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode, - dst, newsrc), scan); - JUMP_LABEL (newinsn) = pool_vector_label; - - /* But it's still an ordinary insn */ - PUT_CODE (newinsn, INSN); - - /* If debugging information is going to be emitted - then we must make sure that any refences to - symbols which are removed by the above code are - also removed in the descriptions of the - function's variables. Failure to do this means - that the debugging information emitted could - refer to symbols which are not emited by - output_constant_pool() because - mark_constant_pool() never sees them as being - used. */ - - - /* These are the tests used in - output_constant_pool() to decide if the constant - pool will be marked. Only necessary if debugging - info is being emitted. Only necessary for - references to memory whose address is given by a - symbol. */ - - if (optimize > 0 - && flag_expensive_optimizations - && write_symbols != NO_DEBUG - && GET_CODE (src) == MEM - && GET_CODE (XEXP (src, 0)) == SYMBOL_REF) - replace_symbols_in_block - (DECL_INITIAL (current_function_decl), src, newsrc); - - /* Kill old insn */ - delete_insn (scan); - scan = newinsn; - } - } - dump_table (barrier); - } - } -} - - -/* Routines for generating rtl */ - -void -thumb_expand_movstrqi (operands) - rtx *operands; -{ - rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); - rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); - HOST_WIDE_INT len = INTVAL (operands[2]); - HOST_WIDE_INT offset = 0; - - while (len >= 12) - { - emit_insn (gen_movmem12b (out, in)); - len -= 12; - } - if (len >= 8) - { - emit_insn (gen_movmem8b (out, in)); - len -= 8; - } - if (len >= 4) - { - rtx reg = gen_reg_rtx (SImode); - emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in))); - emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg)); - len -= 4; - offset += 4; - } - if (len >= 2) - { - rtx reg = gen_reg_rtx (HImode); - emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode, - plus_constant (in, offset)))); - emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)), - reg)); - len -= 2; - offset += 2; - } - if (len) - { - rtx reg = gen_reg_rtx (QImode); - emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode, - plus_constant (in, offset)))); - emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)), - reg)); - } -} - - -/* Routines for reloading */ - -void -thumb_reload_out_si (operands) - rtx operands; -{ - abort (); -} - -/* CYGNUS LOCAL nickc/thumb-pe */ - -#ifdef THUMB_PE -/* Return non-zero if FUNC is a naked function. */ - -static int -arm_naked_function_p (func) - tree func; -{ - tree a; - - if (TREE_CODE (func) != FUNCTION_DECL) - abort (); - - a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); - return a != NULL_TREE; -} -#endif -/* END CYGNUS LOCAL nickc/thumb-pe */ - -/* Return non-zero if FUNC must be entered in ARM mode. */ -int -is_called_in_ARM_mode (func) - tree func; -{ - if (TREE_CODE (func) != FUNCTION_DECL) - abort (); - - /* Ignore the problem about functions whoes address is taken. */ - if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func)) - return TRUE; - -/* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; -#else - return FALSE; -#endif -/* END CYGNUS LOCAL */ -} - - -/* Routines for emitting code */ - -void -final_prescan_insn(insn) - rtx insn; -{ - extern int *insn_addresses; - - if (flag_print_asm_name) - fprintf (asm_out_file, "%s 0x%04x\n", ASM_COMMENT_START, - insn_addresses[INSN_UID (insn)]); -} - - -static void thumb_pushpop ( FILE *, int, int ); /* Forward declaration. */ - -#ifdef __GNUC__ -inline -#endif -static int -number_of_first_bit_set (mask) - int mask; -{ - int bit; - - for (bit = 0; - (mask & (1 << bit)) == 0; - ++ bit) - continue; - - return bit; -} - -#define ARG_1_REGISTER 0 -#define ARG_2_REGISTER 1 -#define ARG_3_REGISTER 2 -#define ARG_4_REGISTER 3 -#define WORK_REGISTER 7 -#define FRAME_POINTER 11 -#define IP_REGISTER 12 -#define STACK_POINTER STACK_POINTER_REGNUM -#define LINK_REGISTER 14 -#define PROGRAM_COUNTER 15 - -/* Generate code to return from a thumb function. If - 'reg_containing_return_addr' is -1, then the return address is - actually on the stack, at the stack pointer. */ -static void -thumb_exit (f, reg_containing_return_addr) - FILE * f; - int reg_containing_return_addr; -{ - int regs_available_for_popping; - int regs_to_pop; - int pops_needed; - int reg; - int available; - int required; - int mode; - int size; - int restore_a4 = FALSE; - - /* Compute the registers we need to pop. */ - regs_to_pop = 0; - pops_needed = 0; - - if (reg_containing_return_addr == -1) - { - regs_to_pop |= 1 << LINK_REGISTER; - ++ pops_needed; - } - - if (TARGET_BACKTRACE) - { - /* Restore frame pointer and stack pointer. */ - regs_to_pop |= (1 << FRAME_POINTER) | (1 << STACK_POINTER); - pops_needed += 2; - } - - /* If there is nothing to pop then just emit the BX instruction and return.*/ - if (pops_needed == 0) - { - asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); - - return; - } - - /* Otherwise if we are not supporting interworking and we have not created - a backtrace structure and the function was not entered in ARM mode then - just pop the return address straight into the PC. */ - else if ( ! TARGET_THUMB_INTERWORK - && ! TARGET_BACKTRACE - && ! is_called_in_ARM_mode (current_function_decl)) - { - asm_fprintf (f, "\tpop\t{pc}\n" ); - - return; - } - - /* Find out how many of the (return) argument registers we can corrupt. */ - regs_available_for_popping = 0; - -#ifdef RTX_CODE - /* If we can deduce the registers used from the function's return value. - This is more reliable that examining regs_ever_live[] because that - will be set if the register is ever used in the function, not just if - the register is used to hold a return value. */ - - if (current_function_return_rtx != 0) - mode = GET_MODE (current_function_return_rtx); - else -#endif - mode = DECL_MODE (DECL_RESULT (current_function_decl)); - - size = GET_MODE_SIZE (mode); - - if (size == 0) - { - /* In a void function we can use any argument register. - In a function that returns a structure on the stack - we can use the second and third argument registers. */ - if (mode == VOIDmode) - regs_available_for_popping = - (1 << ARG_1_REGISTER) - | (1 << ARG_2_REGISTER) - | (1 << ARG_3_REGISTER); - else - regs_available_for_popping = - (1 << ARG_2_REGISTER) - | (1 << ARG_3_REGISTER); - } - else if (size <= 4) regs_available_for_popping = - (1 << ARG_2_REGISTER) - | (1 << ARG_3_REGISTER); - else if (size <= 8) regs_available_for_popping = - (1 << ARG_3_REGISTER); - - /* Match registers to be popped with registers into which we pop them. */ - for (available = regs_available_for_popping, - required = regs_to_pop; - required != 0 && available != 0; - available &= ~(available & - available), - required &= ~(required & - required)) - -- pops_needed; - - /* If we have any popping registers left over, remove them. */ - if (available > 0) - regs_available_for_popping &= ~ available; - - /* Otherwise if we need another popping register we can use - the fourth argument register. */ - else if (pops_needed) - { - /* If we have not found any free argument registers and - reg a4 contains the return address, we must move it. */ - if (regs_available_for_popping == 0 - && reg_containing_return_addr == ARG_4_REGISTER) - { - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); - reg_containing_return_addr = LINK_REGISTER; - } - else if (size > 12) - { - /* Register a4 is being used to hold part of the return value, - but we have dire need of a free, low register. */ - restore_a4 = TRUE; - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [IP_REGISTER], reg_names [ARG_4_REGISTER]); - } - - if (reg_containing_return_addr != ARG_4_REGISTER) - { - /* The fourth argument register is available. */ - regs_available_for_popping |= 1 << ARG_4_REGISTER; - - -- pops_needed; - } - } - - /* Pop as many registers as we can. */ - thumb_pushpop (f, regs_available_for_popping, FALSE); - - /* Process the registers we popped. */ - if (reg_containing_return_addr == -1) - { - /* The return address was popped into the lowest numbered register. */ - regs_to_pop &= ~ (1 << LINK_REGISTER); - - reg_containing_return_addr = - number_of_first_bit_set (regs_available_for_popping); - - /* Remove this register for the mask of available registers, so that - the return address will not be corrupted by futher pops. */ - regs_available_for_popping &= ~ (1 << reg_containing_return_addr); - } - - /* If we popped other registers then handle them here. */ - if (regs_available_for_popping) - { - int frame_pointer; - - /* Work out which register currently contains the frame pointer. */ - frame_pointer = number_of_first_bit_set (regs_available_for_popping); - - /* Move it into the correct place. */ - asm_fprintf (f, "\tmov\tfp, %s\n", reg_names [frame_pointer]); - - /* (Temporarily) remove it from the mask of popped registers. */ - regs_available_for_popping &= ~ (1 << frame_pointer); - regs_to_pop &= ~ (1 << FRAME_POINTER); - - if (regs_available_for_popping) - { - int stack_pointer; - - /* We popped the stack pointer as well, find the register that - contains it.*/ - stack_pointer = number_of_first_bit_set (regs_available_for_popping); - - /* Move it into the stack register. */ - asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [stack_pointer]); - - /* At this point we have popped all necessary registers, so - do not worry about restoring regs_available_for_popping - to its correct value: - - assert (pops_needed == 0) - assert (regs_available_for_popping == (1 << frame_pointer)) - assert (regs_to_pop == (1 << STACK_POINTER)) */ - } - else - { - /* Since we have just move the popped value into the frame - pointer, the popping register is available for reuse, and - we know that we still have the stack pointer left to pop. */ - regs_available_for_popping |= (1 << frame_pointer); - } - } - - /* If we still have registers left on the stack, but we no longer have - any registers into which we can pop them, then we must move the return - address into the link register and make available the register that - contained it. */ - if (regs_available_for_popping == 0 && pops_needed > 0) - { - regs_available_for_popping |= 1 << reg_containing_return_addr; - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [LINK_REGISTER], - reg_names [reg_containing_return_addr]); - - reg_containing_return_addr = LINK_REGISTER; - } - - /* If we have registers left on the stack then pop some more. - We know that at most we will want to pop FP and SP. */ - if (pops_needed > 0) - { - int popped_into; - int move_to; - - thumb_pushpop (f, regs_available_for_popping, FALSE); - - /* We have popped either FP or SP. - Move whichever one it is into the correct register. */ - popped_into = number_of_first_bit_set (regs_available_for_popping); - move_to = number_of_first_bit_set (regs_to_pop); - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [move_to], reg_names [popped_into]); - - regs_to_pop &= ~ (1 << move_to); - - -- pops_needed; - } - - /* If we still have not popped everything then we must have only - had one register available to us and we are now popping the SP. */ - if (pops_needed > 0) - { - int popped_into; - - thumb_pushpop (f, regs_available_for_popping, FALSE); - - popped_into = number_of_first_bit_set (regs_available_for_popping); - - asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [popped_into]); - - /* - assert (regs_to_pop == (1 << STACK_POINTER)) - assert (pops_needed == 1) - */ - } - - /* If necessary restore the a4 register. */ - if (restore_a4) - { - if (reg_containing_return_addr != LINK_REGISTER) - { - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); - reg_containing_return_addr = LINK_REGISTER; - } - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [ARG_4_REGISTER], reg_names [IP_REGISTER]); - } - - /* Return to caller. */ - asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); -} - -/* Emit code to push or pop registers to or from the stack. */ -static void -thumb_pushpop (f, mask, push) - FILE * f; - int mask; - int push; -{ - int regno; - int lo_mask = mask & 0xFF; - - if (lo_mask == 0 && ! push && (mask & (1 << 15))) - { - /* Special case. Do not generate a POP PC statement here, do it in - thumb_exit() */ - - thumb_exit (f, -1); - return; - } - - asm_fprintf (f, "\t%s\t{", push ? "push" : "pop"); - - /* Look at the low registers first. */ - - for (regno = 0; regno < 8; regno ++, lo_mask >>= 1) - { - if (lo_mask & 1) - { - asm_fprintf (f, reg_names[regno]); - - if ((lo_mask & ~1) != 0) - asm_fprintf (f, ", "); - } - } - - if (push && (mask & (1 << 14))) - { - /* Catch pushing the LR. */ - - if (mask & 0xFF) - asm_fprintf (f, ", "); - - asm_fprintf (f, reg_names[14]); - } - else if (!push && (mask & (1 << 15))) - { - /* Catch popping the PC. */ - - if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) - { - /* The PC is never poped directly, instead - it is popped into r3 and then BX is used. */ - - asm_fprintf (f, "}\n"); - - thumb_exit (f, -1); - - return; - } - else - { - if (mask & 0xFF) - asm_fprintf (f, ", "); - - asm_fprintf (f, reg_names[15]); - } - } - - asm_fprintf (f, "}\n"); -} - -/* Returns non-zero if the current function contains a far jump */ - -int -far_jump_used_p (void) -{ - rtx insn; - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (GET_CODE (insn) == JUMP_INSN - /* Ignore tablejump patterns. */ - && GET_CODE (PATTERN (insn)) != ADDR_VEC - && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC - && get_attr_far_jump (insn) == FAR_JUMP_YES) - return 1; - } - - return 0; -} - -static int return_used_this_function = 0; - -char * -output_return () -{ - int regno; - int live_regs_mask = 0; - - /* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - /* If a function is naked, don't use the "return" insn. */ - if (arm_naked_function_p (current_function_decl)) - return ""; -#endif - /* END CYGNUS LOCAL nickc/thumb-pe */ - - return_used_this_function = 1; - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - if (live_regs_mask == 0) - { - if (leaf_function_p () && ! far_jump_used_p()) - { - thumb_exit (asm_out_file, 14); - } - else if ( TARGET_THUMB_INTERWORK - || TARGET_BACKTRACE - || is_called_in_ARM_mode (current_function_decl)) - { - thumb_exit (asm_out_file, -1); - } - else - asm_fprintf (asm_out_file, "\tpop\t{pc}\n"); - } - else - { - asm_fprintf (asm_out_file, "\tpop\t{"); - - for (regno = 0; live_regs_mask; regno ++, live_regs_mask >>= 1) - if (live_regs_mask & 1) - { - asm_fprintf (asm_out_file, reg_names[regno]); - if (live_regs_mask & ~1) - asm_fprintf (asm_out_file, ", "); - } - - if ( TARGET_THUMB_INTERWORK - || TARGET_BACKTRACE - || is_called_in_ARM_mode (current_function_decl)) - { - asm_fprintf (asm_out_file, "}\n"); - thumb_exit (asm_out_file, -1); - } - else - asm_fprintf (asm_out_file, ", pc}\n"); - } - - return ""; -} - -void -thumb_function_prologue (f, frame_size) - FILE *f; - int frame_size; -{ - int amount = frame_size + current_function_outgoing_args_size; - int live_regs_mask = 0; - int high_regs_pushed = 0; - int store_arg_regs = 0; - int regno; - -/* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - if (arm_naked_function_p (current_function_decl)) - return; -#endif -/* CYGNUS LOCAL nickc/thumb-pe */ - - if (is_called_in_ARM_mode (current_function_decl)) - { - char * name; - if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) - abort(); - if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) - abort(); - name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); - - /* Generate code sequence to switch us into Thumb mode. */ - /* The .code 32 directive has already been emitted by - ASM_DECLARE_FUNCITON_NAME */ - asm_fprintf (f, "\torr\tr12, pc, #1\n"); - asm_fprintf (f, "\tbx\tr12\n"); - - /* Generate a label, so that the debugger will notice the - change in instruction sets. This label is also used by - the assembler to bypass the ARM code when this function - is called from a Thumb encoded function elsewhere in the - same file. Hence the definition of STUB_NAME here must - agree with the definition in gas/config/tc-arm.c */ - -#define STUB_NAME ".real_start_of" - - asm_fprintf (f, "\t.code\t16\n"); - asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); - asm_fprintf (f, "\t.thumb_func\n"); - asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); - } - - if (current_function_anonymous_args && current_function_pretend_args_size) - store_arg_regs = 1; - - if (current_function_pretend_args_size) - { - if (store_arg_regs) - { - asm_fprintf (f, "\tpush\t{"); - for (regno = 4 - current_function_pretend_args_size / 4 ; regno < 4; - regno++) - asm_fprintf (f, "%s%s", reg_names[regno], regno == 3 ? "" : ", "); - asm_fprintf (f, "}\n"); - } - else - asm_fprintf (f, "\tsub\t%Rsp, %Rsp, #%d\n", - current_function_pretend_args_size); - } - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - if (live_regs_mask || ! leaf_function_p () || far_jump_used_p()) - live_regs_mask |= 1 << 14; - - if (TARGET_BACKTRACE) - { - char * name; - int offset; - int work_register = 0; - - - /* We have been asked to create a stack backtrace structure. - The code looks like this: - - 0 .align 2 - 0 func: - 0 sub SP, #16 Reserve space for 4 registers. - 2 push {R7} Get a work register. - 4 add R7, SP, #20 Get the stack pointer before the push. - 6 str R7, [SP, #8] Store the stack pointer (before reserving the space). - 8 mov R7, PC Get hold of the start of this code plus 12. - 10 str R7, [SP, #16] Store it. - 12 mov R7, FP Get hold of the current frame pointer. - 14 str R7, [SP, #4] Store it. - 16 mov R7, LR Get hold of the current return address. - 18 str R7, [SP, #12] Store it. - 20 add R7, SP, #16 Point at the start of the backtrace structure. - 22 mov FP, R7 Put this value into the frame pointer. */ - - if ((live_regs_mask & 0xFF) == 0) - { - /* See if the a4 register is free. */ - - if (regs_ever_live[ 3 ] == 0) - work_register = 3; - else /* We must push a register of our own */ - live_regs_mask |= (1 << 7); - } - - if (work_register == 0) - { - /* Select a register from the list that will be pushed to use as our work register. */ - - for (work_register = 8; work_register--;) - if ((1 << work_register) & live_regs_mask) - break; - } - - name = reg_names[ work_register ]; - - asm_fprintf (f, "\tsub\tsp, sp, #16\t@ Create stack backtrace structure\n"); - - if (live_regs_mask) - thumb_pushpop (f, live_regs_mask, 1); - - for (offset = 0, work_register = 1 << 15; work_register; work_register >>= 1) - if (work_register & live_regs_mask) - offset += 4; - - asm_fprintf (f, "\tadd\t%s, sp, #%d\n", - name, offset + 16 + current_function_pretend_args_size); - - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 4); - - /* Make sure that the instruction fetching the PC is in the right place - to calculate "start of backtrace creation code + 12". */ - - if (live_regs_mask) - { - asm_fprintf (f, "\tmov\t%s, pc\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); - asm_fprintf (f, "\tmov\t%s, fp\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); - } - else - { - asm_fprintf (f, "\tmov\t%s, fp\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); - asm_fprintf (f, "\tmov\t%s, pc\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); - } - - asm_fprintf (f, "\tmov\t%s, lr\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 8); - asm_fprintf (f, "\tadd\t%s, sp, #%d\n", name, offset + 12); - asm_fprintf (f, "\tmov\tfp, %s\t\t@ Backtrace structure created\n", name); - } - else if (live_regs_mask) - thumb_pushpop (f, live_regs_mask, 1); - - for (regno = 8; regno < 13; regno++) - { - if (regs_ever_live[regno] && ! call_used_regs[regno]) - high_regs_pushed++; - } - - if (high_regs_pushed) - { - int pushable_regs = 0; - int mask = live_regs_mask & 0xff; - int next_hi_reg; - - for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--) - { - if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) - break; - } - - pushable_regs = mask; - - if (pushable_regs == 0) - { - /* desperation time -- this probably will never happen */ - if (regs_ever_live[3] || ! call_used_regs[3]) - asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[12], reg_names[3]); - mask = 1 << 3; - } - - while (high_regs_pushed > 0) - { - for (regno = 7; regno >= 0; regno--) - { - if (mask & (1 << regno)) - { - asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[regno], - reg_names[next_hi_reg]); - high_regs_pushed--; - if (high_regs_pushed) - for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--) - { - if (regs_ever_live[next_hi_reg] - && ! call_used_regs[next_hi_reg]) - break; - } - else - { - mask &= ~ ((1 << regno) - 1); - break; - } - } - } - thumb_pushpop (f, mask, 1); - } - - if (pushable_regs == 0 && (regs_ever_live[3] || ! call_used_regs[3])) - asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[3], reg_names[12]); - } -} - -void -thumb_expand_prologue () -{ - HOST_WIDE_INT amount = (get_frame_size () - + current_function_outgoing_args_size); - int regno; - int live_regs_mask; - - /* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - /* Naked functions don't have prologues. */ - if (arm_naked_function_p (current_function_decl)) - return; -#endif - /* END CYGNUS LOCAL nickc/thumb-pe */ - - if (amount) - { - live_regs_mask = 0; - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - if (amount < 512) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (-amount))); - else - { - rtx reg, spare; - - if ((live_regs_mask & 0xff) == 0) /* Very unlikely */ - emit_insn (gen_movsi (spare = gen_rtx (REG, SImode, 12), - reg = gen_rtx (REG, SImode, 4))); - else - { - for (regno = 0; regno < 8; regno++) - if (live_regs_mask & (1 << regno)) - break; - reg = gen_rtx (REG, SImode, regno); - } - - emit_insn (gen_movsi (reg, GEN_INT (-amount))); - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); - if ((live_regs_mask & 0xff) == 0) - emit_insn (gen_movsi (reg, spare)); - } - } - - if (frame_pointer_needed) - { - if (current_function_outgoing_args_size) - { - rtx offset = GEN_INT (current_function_outgoing_args_size); - - if (current_function_outgoing_args_size < 1024) - emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, - offset)); - else - { - emit_insn (gen_movsi (frame_pointer_rtx, offset)); - emit_insn (gen_addsi3 (frame_pointer_rtx, frame_pointer_rtx, - stack_pointer_rtx)); - } - } - else - emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); - } - - /* if (profile_flag || profile_block_flag) */ - emit_insn (gen_blockage ()); -} - -void -thumb_expand_epilogue () -{ - HOST_WIDE_INT amount = (get_frame_size () - + current_function_outgoing_args_size); - int regno; - - /* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - /* Naked functions don't have epilogues. */ - if (arm_naked_function_p (current_function_decl)) - return; -#endif - /* END CYGNUS LOCAL nickc/thumb-pe */ - - if (amount) - { - if (amount < 512) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (amount))); - else - { - rtx reg = gen_rtx (REG, SImode, 3); /* Always free in the epilogue */ - - emit_insn (gen_movsi (reg, GEN_INT (amount))); - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); - } - /* if (profile_flag || profile_block_flag) */ - emit_insn (gen_blockage ()); - } -} - -void -thumb_function_epilogue (f, frame_size) - FILE *f; - int frame_size; -{ - /* ??? Probably not safe to set this here, since it assumes that a - function will be emitted as assembly immediately after we generate - RTL for it. This does not happen for inline functions. */ - return_used_this_function = 0; -#if 0 /* TODO : comment not really needed */ - fprintf (f, "%s THUMB Epilogue\n", ASM_COMMENT_START); -#endif -} - -/* The bits which aren't usefully expanded as rtl. */ -char * -thumb_unexpanded_epilogue () -{ - int regno; - int live_regs_mask = 0; - int high_regs_pushed = 0; - int leaf_function = leaf_function_p (); - int had_to_push_lr; - - if (return_used_this_function) - return ""; - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - for (regno = 8; regno < 13; regno++) - { - if (regs_ever_live[regno] && ! call_used_regs[regno]) - high_regs_pushed ++; - } - - /* The prolog may have pushed some high registers to use as - work registers. eg the testuite file: - gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c - compiles to produce: - push {r4, r5, r6, r7, lr} - mov r7, r9 - mov r6, r8 - push {r6, r7} - as part of the prolog. We have to undo that pushing here. */ - - if (high_regs_pushed) - { - int mask = live_regs_mask; - int next_hi_reg; - int size; - int mode; - -#ifdef RTX_CODE - /* If we can deduce the registers used from the function's return value. - This is more reliable that examining regs_ever_live[] because that - will be set if the register is ever used in the function, not just if - the register is used to hold a return value. */ - - if (current_function_return_rtx != 0) - { - mode = GET_MODE (current_function_return_rtx); - } - else -#endif - { - mode = DECL_MODE (DECL_RESULT (current_function_decl)); - } - - size = GET_MODE_SIZE (mode); - - /* Unless we are returning a type of size > 12 register r3 is available. */ - if (size < 13) - mask |= 1 << 3; - - if (mask == 0) - { - /* Oh dear! We have no low registers into which we can pop high registers! */ - - fatal ("No low registers available for popping high registers"); - } - - for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++) - if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) - break; - - while (high_regs_pushed) - { - /* Find low register(s) into which the high register(s) can be popped. */ - for (regno = 0; regno < 8; regno++) - { - if (mask & (1 << regno)) - high_regs_pushed--; - if (high_regs_pushed == 0) - break; - } - - mask &= (2 << regno) - 1; /* A noop if regno == 8 */ - - /* Pop the values into the low register(s). */ - thumb_pushpop (asm_out_file, mask, 0); - - /* Move the value(s) into the high registers. */ - for (regno = 0; regno < 8; regno++) - { - if (mask & (1 << regno)) - { - asm_fprintf (asm_out_file, "\tmov\t%s, %s\n", - reg_names[next_hi_reg], reg_names[regno]); - for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++) - if (regs_ever_live[next_hi_reg] && - ! call_used_regs[next_hi_reg]) - break; - } - } - } - } - - had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); - - if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) - { - /* The stack backtrace structure creation code had to - push R7 in order to get a work register, so we pop - it now. */ - - live_regs_mask |= (1 << WORK_REGISTER); - } - - if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) - { - if (had_to_push_lr - && ! is_called_in_ARM_mode (current_function_decl)) - live_regs_mask |= 1 << PROGRAM_COUNTER; - - /* Either no argument registers were pushed or a backtrace - structure was created which includes an adjusted stack - pointer, so just pop everything. */ - - if (live_regs_mask) - thumb_pushpop (asm_out_file, live_regs_mask, FALSE); - - /* We have either just popped the return address into the - PC or it is was kept in LR for the entire function or - it is still on the stack because we do not want to - return by doing a pop {pc}. */ - - if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0) - thumb_exit (asm_out_file, - (had_to_push_lr - && is_called_in_ARM_mode (current_function_decl)) ? - -1 : LINK_REGISTER); - } - else - { - /* Pop everything but the return address. */ - live_regs_mask &= ~ (1 << PROGRAM_COUNTER); - - if (live_regs_mask) - thumb_pushpop (asm_out_file, live_regs_mask, FALSE); - - if (had_to_push_lr) - { - /* Get the return address into a temporary register. */ - thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0); - } - - /* Remove the argument registers that were pushed onto the stack. */ - asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n", - reg_names [STACK_POINTER], - reg_names [STACK_POINTER], - current_function_pretend_args_size); - - thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER); - } - - return ""; -} - -/* Handle the case of a double word load into a low register from - a computed memory address. The computed address may involve a - register which is overwritten by the load. */ - -char * -thumb_load_double_from_address (operands) - rtx * operands; -{ - rtx addr; - rtx base; - rtx offset; - rtx arg1; - rtx arg2; - - if (GET_CODE (operands[0]) != REG) - fatal ("thumb_load_double_from_address: destination is not a register"); - - if (GET_CODE (operands[1]) != MEM) - fatal ("thumb_load_double_from_address: source is not a computed memory address"); - - /* Get the memory address. */ - - addr = XEXP (operands[1], 0); - - /* Work out how the memory address is computed. */ - - switch (GET_CODE (addr)) - { - case REG: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - if (REGNO (operands[0]) == REGNO (addr)) - { - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - } - else - { - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - } - break; - - case CONST: - /* Compute <address> + 4 for the high order load. */ - - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - break; - - case PLUS: - arg1 = XEXP (addr, 0); - arg2 = XEXP (addr, 1); - - if (CONSTANT_P (arg1)) - base = arg2, offset = arg1; - else - base = arg1, offset = arg2; - - if (GET_CODE (base) != REG) - fatal ("thumb_load_double_from_address: base is not a register"); - - /* Catch the case of <address> = <reg> + <reg> */ - - if (GET_CODE (offset) == REG) - { - int reg_offset = REGNO (offset); - int reg_base = REGNO (base); - int reg_dest = REGNO (operands[0]); - - /* Add the base and offset registers together into the higher destination register. */ - - fprintf (asm_out_file, "\tadd\t%s, %s, %s\t\t%s created by thumb_load_double_from_address", - reg_names[ reg_dest + 1 ], - reg_names[ reg_base ], - reg_names[ reg_offset ], - ASM_COMMENT_START); - - /* Load the lower destination register from the address in the higher destination register. */ - - fprintf (asm_out_file, "\tldr\t%s, [%s, #0]\t\t%s created by thumb_load_double_from_address", - reg_names[ reg_dest ], - reg_names[ reg_dest + 1], - ASM_COMMENT_START); - - /* Load the higher destination register from its own address plus 4. */ - - fprintf (asm_out_file, "\tldr\t%s, [%s, #4]\t\t%s created by thumb_load_double_from_address", - reg_names[ reg_dest + 1 ], - reg_names[ reg_dest + 1 ], - ASM_COMMENT_START); - } - else - { - /* Compute <address> + 4 for the high order load. */ - - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - /* If the computed address is held in the low order register - then load the high order register first, otherwise always - load the low order register first. */ - - if (REGNO (operands[0]) == REGNO (base)) - { - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - } - else - { - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - } - } - break; - - case LABEL_REF: - /* With no registers to worry about we can just load the value directly. */ - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - break; - - default: - debug_rtx (operands[1]); - fatal ("thumb_load_double_from_address: Unhandled address calculation"); - break; - } - - return ""; -} - -char * -output_move_mem_multiple (n, operands) - int n; - rtx *operands; -{ - rtx tmp; - - switch (n) - { - case 2: - if (REGNO (operands[2]) > REGNO (operands[3])) - { - tmp = operands[2]; - operands[2] = operands[3]; - operands[3] = tmp; - } - output_asm_insn ("ldmia\t%1!, {%2, %3}", operands); - output_asm_insn ("stmia\t%0!, {%2, %3}", operands); - break; - - case 3: - if (REGNO (operands[2]) > REGNO (operands[3])) - { - tmp = operands[2]; - operands[2] = operands[3]; - operands[3] = tmp; - } - if (REGNO (operands[3]) > REGNO (operands[4])) - { - tmp = operands[3]; - operands[3] = operands[4]; - operands[4] = tmp; - } - if (REGNO (operands[2]) > REGNO (operands[3])) - { - tmp = operands[2]; - operands[2] = operands[3]; - operands[3] = tmp; - } - output_asm_insn ("ldmia\t%1!, {%2, %3, %4}", operands); - output_asm_insn ("stmia\t%0!, {%2, %3, %4}", operands); - break; - - default: - abort (); - } - - return ""; -} - - -int -thumb_epilogue_size () -{ - return 42; /* The answer to .... */ -} - -static char *conds[] = -{ - "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", "gt", "le" -}; - -static char * -thumb_condition_code (x, invert) - rtx x; - int invert; -{ - int val; - - switch (GET_CODE (x)) - { - case EQ: val = 0; break; - case NE: val = 1; break; - case GEU: val = 2; break; - case LTU: val = 3; break; - case GTU: val = 8; break; - case LEU: val = 9; break; - case GE: val = 10; break; - case LT: val = 11; break; - case GT: val = 12; break; - case LE: val = 13; break; - default: - abort (); - } - - return conds[val ^ invert]; -} - -void -thumb_print_operand (f, x, code) - FILE *f; - rtx x; - int code; -{ - if (code) - { - switch (code) - { - case '@': - fputs (ASM_COMMENT_START, f); - return; - - case '_': - fputs (user_label_prefix, f); - return; - - case 'D': - if (x) - fputs (thumb_condition_code (x, 1), f); - return; - - case 'd': - if (x) - fputs (thumb_condition_code (x, 0), f); - return; - - /* An explanation of the 'Q', 'R' and 'H' register operands: - - In a pair of registers containing a DI or DF value the 'Q' - operand returns the register number of the register containing - the least signficant part of the value. The 'R' operand returns - the register number of the register containing the most - significant part of the value. - - The 'H' operand returns the higher of the two register numbers. - On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the - same as the 'Q' operand, since the most signficant part of the - value is held in the lower number register. The reverse is true - on systems where WORDS_BIG_ENDIAN is false. - - The purpose of these operands is to distinguish between cases - where the endian-ness of the values is important (for example - when they are added together), and cases where the endian-ness - is irrelevant, but the order of register operations is important. - For example when loading a value from memory into a register - pair, the endian-ness does not matter. Provided that the value - from the lower memory address is put into the lower numbered - register, and the value from the higher address is put into the - higher numbered register, the load will work regardless of whether - the value being loaded is big-wordian or little-wordian. The - order of the two register loads can matter however, if the address - of the memory location is actually held in one of the registers - being overwritten by the load. */ - case 'Q': - if (REGNO (x) > 15) - abort (); - fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], f); - return; - - case 'R': - if (REGNO (x) > 15) - abort (); - fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], f); - return; - - case 'H': - if (REGNO (x) > 15) - abort (); - fputs (reg_names[REGNO (x) + 1], f); - return; - - case 'c': - /* We use 'c' operands with symbols for .vtinherit */ - if (GET_CODE (x) == SYMBOL_REF) - output_addr_const(f, x); - return; - - default: - abort (); - } - } - if (GET_CODE (x) == REG) - fputs (reg_names[REGNO (x)], f); - else if (GET_CODE (x) == MEM) - output_address (XEXP (x, 0)); - else if (GET_CODE (x) == CONST_INT) - { - fputc ('#', f); - output_addr_const (f, x); - } - else - abort (); -} - -#ifdef AOF_ASSEMBLER -int arm_text_section_count = 1; - -char * -aof_text_section (in_readonly) - int in_readonly; -{ - static char buf[100]; - if (in_readonly) - return ""; - sprintf (buf, "\tCODE16\n\tAREA |C$$code%d|, CODE, READONLY", - arm_text_section_count++); - return buf; -} - -static int arm_data_section_count = 1; - -char * -aof_data_section () -{ - static char buf[100]; - sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++); - return buf; -} - -/* The AOF thumb assembler is religiously strict about declarations of - imported and exported symbols, so that it is impossible to declare a - function as imported near the begining of the file, and then to export - it later on. It is, however, possible to delay the decision until all - the functions in the file have been compiled. To get around this, we - maintain a list of the imports and exports, and delete from it any that - are subsequently defined. At the end of compilation we spit the - remainder of the list out before the END directive. */ - -struct import -{ - struct import *next; - char *name; -}; - -static struct import *imports_list = NULL; - -void -thumb_aof_add_import (name) - char *name; -{ - struct import *new; - - for (new = imports_list; new; new = new->next) - if (new->name == name) - return; - - new = (struct import *) xmalloc (sizeof (struct import)); - new->next = imports_list; - imports_list = new; - new->name = name; -} - -void -thumb_aof_delete_import (name) - char *name; -{ - struct import **old; - - for (old = &imports_list; *old; old = & (*old)->next) - { - if ((*old)->name == name) - { - *old = (*old)->next; - return; - } - } -} - -void -thumb_aof_dump_imports (f) - FILE *f; -{ - while (imports_list) - { - fprintf (f, "\tIMPORT\t"); - assemble_name (f, imports_list->name); - fputc ('\n', f); - imports_list = imports_list->next; - } -} -#endif - -/* Decide whether a type should be returned in memory (true) - or in a register (false). This is called by the macro - RETURN_IN_MEMORY. */ - -int -thumb_return_in_memory (type) - tree type; -{ - if (! AGGREGATE_TYPE_P (type)) - { - /* All simple types are returned in registers. */ - - return 0; - } - else if (int_size_in_bytes (type) > 4) - { - /* All structures/unions bigger than one word are returned in memory. */ - - return 1; - } - else if (TREE_CODE (type) == RECORD_TYPE) - { - tree field; - - /* For a struct the APCS says that we must return in a register if - every addressable element has an offset of zero. For practical - purposes this means that the structure can have at most one non- - bit-field element and that this element must be the first one in - the structure. */ - - /* Find the first field, ignoring non FIELD_DECL things which will - have been created by C++. */ - for (field = TYPE_FIELDS (type); - field && TREE_CODE (field) != FIELD_DECL; - field = TREE_CHAIN (field)) - continue; - - if (field == NULL) - return 0; /* An empty structure. Allowed by an extension to ANSI C. */ - - /* Now check the remaining fields, if any. */ - for (field = TREE_CHAIN (field); field; field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) != FIELD_DECL) - continue; - - if (! DECL_BIT_FIELD_TYPE (field)) - return 1; - } - - return 0; - } - else if (TREE_CODE (type) == UNION_TYPE) - { - tree field; - - /* Unions can be returned in registers if every element is - integral, or can be returned in an integer register. */ - - for (field = TYPE_FIELDS (type); - field; - field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) != FIELD_DECL) - continue; - - if (RETURN_IN_MEMORY (TREE_TYPE (field))) - return 1; - } - - return 0; - } - /* XXX Not sure what should be done for other aggregates, so put them in - memory. */ - return 1; -} - -void -thumb_override_options () -{ - if (structure_size_string != NULL) - { - int size = strtol (structure_size_string, NULL, 0); - - if (size == 8 || size == 32) - arm_structure_size_boundary = size; - else - warning ("Structure size boundary can only be set to 8 or 32"); - } - - if (flag_pic) - { - warning ("Position independent code not supported. Ignored"); - flag_pic = 0; - } -} - -/* CYGNUS LOCAL nickc/thumb-pe */ - -#ifdef THUMB_PE -/* Return nonzero if ATTR is a valid attribute for DECL. - ATTRIBUTES are any existing attributes and ARGS are the arguments - supplied with ATTR. - - Supported attributes: - - naked: don't output any prologue or epilogue code, the user is assumed - to do the right thing. - - interfacearm: Always assume that this function will be entered in ARM - mode, not Thumb mode, and that the caller wishes to be returned to in - ARM mode. */ -int -arm_valid_machine_decl_attribute (decl, attributes, attr, args) - tree decl; - tree attributes; - tree attr; - tree args; -{ - if (args != NULL_TREE) - return 0; - - if (is_attribute_p ("naked", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; - - if (is_attribute_p ("interfacearm", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; - - return 0; -} -#endif /* THUMB_PE */ -/* END CYGNUS LOCAL nickc/thumb-pe */ - -/* s_register_operand is the same as register_operand, but it doesn't accept - (SUBREG (MEM)...). - - This function exists because at the time it was put in it led to better - code. SUBREG(MEM) always needs a reload in the places where - s_register_operand is used, and this seemed to lead to excessive - reloading. */ - -int -s_register_operand (op, mode) - register rtx op; - enum machine_mode mode; -{ - if (GET_MODE (op) != mode && mode != VOIDmode) - return 0; - - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - - /* We don't consider registers whose class is NO_REGS - to be a register operand. */ - /* XXX might have to check for lo regs only for thumb ??? */ - return (GET_CODE (op) == REG - && (REGNO (op) >= FIRST_PSEUDO_REGISTER - || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); -} diff --git a/gcc/config/arm/thumb_010110a.md b/gcc/config/arm/thumb_010110a.md deleted file mode 100755 index 29a75bb..0000000 --- a/gcc/config/arm/thumb_010110a.md +++ /dev/null @@ -1,1166 +0,0 @@ -;; thumb.md Machine description for ARM/Thumb processors -;; Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. -;; The basis of this contribution was generated by -;; Richard Earnshaw, Advanced RISC Machines Ltd - -;; This file is part of GNU CC. - -;; GNU CC is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. - -;; GNU CC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU CC; see the file COPYING. If not, write to -;; the Free Software Foundation, 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;; LENGTH of an instruction is 2 bytes -(define_attr "length" "" (const_int 2)) - -;; CONDS is set to UNCHANGED when an insn does not affect the condition codes -;; Most insns change the condition codes -(define_attr "conds" "changed,unchanged" (const_string "changed")) - -;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a -;; distant label. -(define_attr "far_jump" "yes,no" (const_string "no")) - -;; Start with move insns - -(define_expand "movsi" - [(set (match_operand:SI 0 "general_operand" "") - (match_operand:SI 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (SImode, operands[1]); - } -") - -(define_insn "*movsi_insn" - [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h") - (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))] - "register_operand (operands[0], SImode) - || register_operand (operands[1], SImode)" - "@ - add\\t%0, %1, #0 - mov\\t%0, %1 - # - # - ldmia\\t%1, {%0} - stmia\\t%0, {%1} - ldr\\t%0, %1 - str\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1" -[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")]) - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] - "thumb_shiftable_const (INTVAL (operands[1]))" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] - " -{ - unsigned HOST_WIDE_INT val = INTVAL (operands[1]); - unsigned HOST_WIDE_INT mask = 0xff; - int i; - for (i = 0; i < 25; i++) - if ((val & (mask << i)) == val) - break; - - if (i == 0) - FAIL; - - operands[1] = GEN_INT (val >> i); - operands[2] = GEN_INT (i); -}") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] - "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (neg:SI (match_dup 0)))] - " - operands[1] = GEN_INT (- INTVAL (operands[1])); -") - -;;(define_expand "reload_outsi" -;; [(set (match_operand:SI 2 "register_operand" "=&l") -;; (match_operand:SI 1 "register_operand" "h")) -;; (set (match_operand:SI 0 "reload_memory_operand" "=o") -;; (match_dup 2))] -;; "" -;; " -;;/* thumb_reload_out_si (operands); -;; DONE; */ -;;") - -(define_expand "movhi" - [(set (match_operand:HI 0 "general_operand" "") - (match_operand:HI 1 "general_operand" ""))] - "" - " -{ - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (HImode, operands[1]); - - /* ??? We shouldn't really get invalid addresses here, but this can - happen if we are passed a SP (never OK for HImode/QImode) or virtual - register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) - relative address. */ - /* ??? This should perhaps be fixed elsewhere, for instance, in - fixup_stack_1, by checking for other kinds of invalid addresses, - e.g. a bare reference to a virtual register. This may confuse the - alpha though, which must handle this case differently. */ - if (GET_CODE (operands[0]) == MEM - && ! memory_address_p (GET_MODE (operands[0]), - XEXP (operands[0], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[0], 0)); - operands[0] = change_address (operands[0], VOIDmode, temp); - } - if (GET_CODE (operands[1]) == MEM - && ! memory_address_p (GET_MODE (operands[1]), - XEXP (operands[1], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[1], 0)); - operands[1] = change_address (operands[1], VOIDmode, temp); - } - } - /* Handle loading a large integer during reload */ - else if (GET_CODE (operands[1]) == CONST_INT - && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) - { - /* Writing a constant to memory needs a scratch, which should - be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); - - operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } -}") - -(define_insn "*movhi_insn" - [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") - (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] - "register_operand (operands[0], HImode) - || register_operand (operands[1], HImode)" - "@ - add\\t%0, %1, #0 - ldrh\\t%0, %1 - strh\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1 - mov\\t%0, %1") - -(define_expand "movqi" - [(set (match_operand:QI 0 "general_operand" "") - (match_operand:QI 1 "general_operand" ""))] - "" - " -{ - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (QImode, operands[1]); - - /* ??? We shouldn't really get invalid addresses here, but this can - happen if we are passed a SP (never OK for HImode/QImode) or virtual - register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) - relative address. */ - /* ??? This should perhaps be fixed elsewhere, for instance, in - fixup_stack_1, by checking for other kinds of invalid addresses, - e.g. a bare reference to a virtual register. This may confuse the - alpha though, which must handle this case differently. */ - if (GET_CODE (operands[0]) == MEM - && ! memory_address_p (GET_MODE (operands[0]), - XEXP (operands[0], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[0], 0)); - operands[0] = change_address (operands[0], VOIDmode, temp); - } - if (GET_CODE (operands[1]) == MEM - && ! memory_address_p (GET_MODE (operands[1]), - XEXP (operands[1], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[1], 0)); - operands[1] = change_address (operands[1], VOIDmode, temp); - } - } - /* Handle loading a large integer during reload */ - else if (GET_CODE (operands[1]) == CONST_INT - && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) - { - /* Writing a constant to memory needs a scratch, which should - be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); - - operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } -}") - -(define_insn "*movqi_insn" - [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") - (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] - "register_operand (operands[0], QImode) - || register_operand (operands[1], QImode)" - "@ - add\\t%0, %1, #0 - ldrb\\t%0, %1 - strb\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1 - mov\\t%0, %1") - -(define_expand "movdi" - [(set (match_operand:DI 0 "general_operand" "") - (match_operand:DI 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (DImode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -;;; ??? This was originally identical to the movdf_insn pattern. -;;; ??? The 'i' constraint looks funny, but it should always be replaced by -;;; thumb_reorg with a memory reference. -(define_insn "*movdi_insn" - [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r") - (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] - "register_operand (operands[0], DImode) - || register_operand (operands[1], DImode)" - "* -{ - switch (which_alternative) - { - case 0: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; - return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; - case 1: - return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; - case 2: - operands[1] = GEN_INT (- INTVAL (operands[1])); - return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; - case 3: - return \"ldmia\\t%1, {%0, %H0}\"; - case 4: - return \"stmia\\t%0, {%1, %H1}\"; - case 5: - return thumb_load_double_from_address (operands); - case 6: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); - output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); - return \"\"; - case 7: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; - return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; - } -}"[(set_attr "length" "4,4,6,2,2,6,4,4")]) - -(define_expand "movdf" - [(set (match_operand:DF 0 "general_operand" "") - (match_operand:DF 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (DFmode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -;;; ??? This was originally identical to the movdi_insn pattern. -;;; ??? The 'F' constraint looks funny, but it should always be replaced by -;;; thumb_reorg with a memory reference. -(define_insn "*movdf_insn" - [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r") - (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] - "register_operand (operands[0], DFmode) - || register_operand (operands[1], DFmode)" - "* - switch (which_alternative) - { - case 0: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; - return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; - case 1: - return \"ldmia\\t%1, {%0, %H0}\"; - case 2: - return \"stmia\\t%0, {%1, %H1}\"; - case 3: - return thumb_load_double_from_address (operands); - case 4: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); - output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); - return \"\"; - case 5: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; - return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; - } -"[(set_attr "length" "4,2,2,6,4,4")]) - -(define_expand "movsf" - [(set (match_operand:SF 0 "general_operand" "") - (match_operand:SF 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (SFmode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -(define_insn "*movsf_insn" - [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") - (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] - "register_operand (operands[0], SFmode) - || register_operand (operands[1], SFmode)" - "@ - add\\t%0, %1, #0 - ldmia\\t%1, {%0} - stmia\\t%0, {%1} - ldr\\t%0, %1 - str\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1") - -;; Widening move insns - -(define_expand "zero_extendhisi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); - emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16))); - DONE; - } -") - -(define_insn "*zero_extendhisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] - "" - "ldrh\\t%0, %1") - -(define_expand "zero_extendqisi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); - emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24))); - DONE; - } -") - -(define_insn "*zero_extendqisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] - "" - "ldrb\\t%0, %1") - -(define_expand "extendhisi2" - [(parallel [(set (match_operand:SI 0 "s_register_operand" "") - (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:SI 2 ""))])] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); - emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16))); - DONE; - } -") - -(define_insn "*extendhisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) - (clobber (match_scratch:SI 2 "=&l"))] - "" - "* -{ - rtx ops[4]; - /* This code used to try to use 'V', and fix the address only if it was - offsettable, but this fails for e.g. REG+48 because 48 is outside the - range of QImode offsets, and offsettable_address_p does a QImode - address check. */ - - if (GET_CODE (XEXP (operands[1], 0)) == PLUS) - { - ops[1] = XEXP (XEXP (operands[1], 0), 0); - ops[2] = XEXP (XEXP (operands[1], 0), 1); - } - else - { - ops[1] = XEXP (operands[1], 0); - ops[2] = const0_rtx; - } - if (GET_CODE (ops[2]) == REG) - return \"ldrsh\\t%0, %1\"; - - ops[0] = operands[0]; - ops[3] = operands[2]; - output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); - return \"\"; -}" -[(set_attr "length" "4")]) - -(define_expand "extendqisi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); - emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24))); - DONE; - } -") - -(define_insn "*extendqisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] - "" - "* -{ - rtx ops[3]; - - if (which_alternative == 0) - return \"ldrsb\\t%0, %1\"; - ops[0] = operands[0]; - if (GET_CODE (XEXP (operands[1], 0)) == PLUS) - { - ops[1] = XEXP (XEXP (operands[1], 0), 0); - ops[2] = XEXP (XEXP (operands[1], 0), 1); - - if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG) - output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); - else if (GET_CODE (ops[1]) == REG) - { - if (REGNO (ops[1]) == REGNO (operands[0])) - output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - else - { - if (REGNO (ops[2]) == REGNO (operands[0])) - output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - } - else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0))) - { - output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - } - else - { - ops[1] = XEXP (operands[1], 0); - ops[2] = const0_rtx; - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - return \"\"; -}" -[(set_attr "length" "2,6")]) - -;; We don't really have extzv, but defining this using shifts helps -;; to reduce register pressure later on. - -(define_expand "extzv" - [(set (match_dup 4) - (ashift:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "const_int_operand" ""))) - (set (match_operand:SI 0 "register_operand" "") - (lshiftrt:SI (match_dup 4) - (match_operand:SI 3 "const_int_operand" "")))] - "" - " -{ - HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); - HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); - operands[3] = GEN_INT (rshift); - if (lshift == 0) - { - emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); - DONE; - } - operands[2] = GEN_INT (lshift); - operands[4] = gen_reg_rtx (SImode); -} -") - -;; Block-move insns - -(define_expand "movstrqi" - [(match_operand:BLK 0 "general_operand" "") - (match_operand:BLK 1 "general_operand" "") - (match_operand:SI 2 "" "") - (match_operand:SI 3 "const_int_operand" "")] - "" - " - if (INTVAL (operands[3]) != 4 - || GET_CODE (operands[2]) != CONST_INT - || INTVAL (operands[2]) > 48) - FAIL; - - thumb_expand_movstrqi (operands); - DONE; -") - -(define_insn "movmem12b" - [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) - (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) - (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) - (mem:SI (plus:SI (match_dup 1) (const_int 8)))) - (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) - (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) - (clobber (match_scratch:SI 2 "=&l")) - (clobber (match_scratch:SI 3 "=&l")) - (clobber (match_scratch:SI 4 "=&l"))] - "" - "* return output_move_mem_multiple (3, operands);" -[(set_attr "length" "4")]) - -(define_insn "movmem8b" - [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) - (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) - (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) - (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) - (clobber (match_scratch:SI 2 "=&l")) - (clobber (match_scratch:SI 3 "=&l"))] - "" - "* return output_move_mem_multiple (2, operands);" -[(set_attr "length" "4")]) - -;; Arithmetic insns - -(define_insn "adddi3" - [(set (match_operand:DI 0 "s_register_operand" "=l") - (plus:DI (match_operand:DI 1 "s_register_operand" "%0") - (match_operand:DI 2 "s_register_operand" "l")))] - "" - "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" -[(set_attr "conds" "changed") - (set_attr "length" "8")]) - -;; register group 'k' is a single register group containing only the stack -;; register. Trying to reload it will always fail catastrophically, -;; so never allow those alternatives to match if reloading is needed. -(define_insn "addsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l,l,*r,*h,l,!k") - (plus:SI (match_operand:SI 1 "s_register_operand" "%0,0,l,*0,*0,!k,!k") - (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] - "" - "* - static char *asms[] = -{ - \"add\\t%0, %0, %2\", - \"sub\\t%0, %0, #%n2\", - \"add\\t%0, %1, %2\", - \"add\\t%0, %0, %2\", - \"add\\t%0, %0, %2\", - \"add\\t%0, %1, %2\", - \"add\\t%0, %1, %2\" -}; - if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) < 0) - return \"sub\\t%0, %1, #%n2\"; - return asms[which_alternative]; -") - -; reloading and elimination of the frame pointer can sometimes cause this -; optimization to be missed. -(define_peephole - [(set (match_operand:SI 0 "register_operand" "=l") - (match_operand:SI 1 "const_int_operand" "M")) - (set (match_dup 0) - (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] - "REGNO (operands[2]) == STACK_POINTER_REGNUM - && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 - && (INTVAL (operands[1]) & 3) == 0" - "add\\t%0, %2, %1") - -(define_insn "subdi3" - [(set (match_operand:DI 0 "s_register_operand" "=l") - (minus:DI (match_operand:DI 1 "s_register_operand" "0") - (match_operand:DI 2 "s_register_operand" "l")))] - "" - "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" -[(set_attr "conds" "changed") - (set_attr "length" "8")]) - -(define_insn "subsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (minus:SI (match_operand:SI 1 "s_register_operand" "l") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "sub\\t%0, %1, %2") - -;; We must ensure that one input matches the output, and that the other input -;; does not match the output. Using 0 satisfies the first, and using & -;; satisfies the second. Unfortunately, this fails when operands 1 and 2 -;; are the same, because reload will make operand 0 match operand 1 without -;; realizing that this conflicts with operand 2. We fix this by adding another -;; alternative to match this case, and then `reload' it ourselves. This -;; alternative must come first. -(define_insn "mulsi3" - [(set (match_operand:SI 0 "s_register_operand" "=&l,&l,&l") - (mult:SI (match_operand:SI 1 "s_register_operand" "%l,*h,0") - (match_operand:SI 2 "s_register_operand" "l,l,l")))] - "" - "* -{ - if (which_alternative < 2) - return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; - else - return \"mul\\t%0, %0, %2\"; -}" - [(set_attr "length" "4,4,2")]) - -(define_insn "negsi2" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (neg:SI (match_operand:SI 1 "s_register_operand" "l")))] - "" - "neg\\t%0, %1") - -;; Logical insns - -(define_expand "andsi3" - [(set (match_operand:SI 0 "s_register_operand" "") - (and:SI (match_operand:SI 1 "s_register_operand" "") - (match_operand:SI 2 "nonmemory_operand" "")))] - "" - " - if (GET_CODE (operands[2]) != CONST_INT) - operands[2] = force_reg (SImode, operands[2]); - else - { - int i; - if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) - { - operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); - emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); - DONE; - } - - for (i = 9; i <= 31; i++) - if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) - { - emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), - const0_rtx)); - DONE; - } - else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) - { - rtx shift = GEN_INT (i); - rtx reg = gen_reg_rtx (SImode); - emit_insn (gen_lshrsi3 (reg, operands[1], shift)); - emit_insn (gen_ashlsi3 (operands[0], reg, shift)); - DONE; - } - - operands[2] = force_reg (SImode, operands[2]); - } -") - -(define_insn "*andsi3_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (and:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "and\\t%0, %0, %2") - -(define_insn "bicsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "l")) - (match_operand:SI 2 "s_register_operand" "0")))] - "" - "bic\\t%0, %0, %1") - -(define_insn "iorsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (ior:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "orr\\t%0, %0, %2") - -(define_insn "xorsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (xor:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "eor\\t%0, %0, %2") - -(define_insn "one_cmplsi2" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (not:SI (match_operand:SI 1 "s_register_operand" "l")))] - "" - "mvn\\t%0, %1") - -;; Shift and rotation insns - -(define_insn "ashlsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (ashift:SI (match_operand:SI 1 "s_register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - lsl\\t%0, %1, %2 - lsl\\t%0, %0, %2") - -(define_insn "ashrsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - asr\\t%0, %1, %2 - asr\\t%0, %0, %2") - -(define_insn "lshrsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - lsr\\t%0, %1, %2 - lsr\\t%0, %0, %2") - -(define_insn "rotrsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (rotatert:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "ror\\t%0, %0, %2") - -;; Comparison insns - -(define_expand "cmpsi" - [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "") - (match_operand:SI 1 "nonmemory_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG) - { - if (GET_CODE (operands[1]) != CONST_INT - || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256) - { - if (GET_CODE (operands[1]) != CONST_INT - || INTVAL (operands[1]) < -255 - || INTVAL (operands[1]) > 0) - operands[1] = force_reg (SImode, operands[1]); - else - { - operands[1] = force_reg (SImode, - GEN_INT (- INTVAL (operands[1]))); - emit_insn (gen_cmnsi (operands[0], operands[1])); - DONE; - } - } - } -") - -(define_insn "*cmpsi_insn" - [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l,*r,*h") - (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))] - "" - "@ - cmp\\t%0, %1 - cmp\\t%0, %1 - cmp\\t%0, %1") - -(define_insn "tstsi" - [(set (cc0) (match_operand:SI 0 "s_register_operand" "l"))] - "" - "cmp\\t%0, #0") - -(define_insn "cmnsi" - [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l") - (neg:SI (match_operand:SI 1 "s_register_operand" "l"))))] - "" - "cmn\\t%0, %1") - -;; Jump insns - -(define_insn "jump" - [(set (pc) (label_ref (match_operand 0 "" "")))] - "" - "* - if (get_attr_length (insn) == 2) - return \"b\\t%l0\"; - return \"bl\\t%l0\\t%@ far jump\"; -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "4") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 2) - (const_int 4)))]) - - -(define_expand "beq" - [(set (pc) (if_then_else (eq (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bne" - [(set (pc) (if_then_else (ne (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bge" - [(set (pc) (if_then_else (ge (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "ble" - [(set (pc) (if_then_else (le (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgt" - [(set (pc) (if_then_else (gt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "blt" - [(set (pc) (if_then_else (lt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgeu" - [(set (pc) (if_then_else (geu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bleu" - [(set (pc) (if_then_else (leu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgtu" - [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bltu" - [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_insn "*cond_branch" - [(set (pc) (if_then_else (match_operator 1 "comparison_operator" - [(cc0) (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "* - switch (get_attr_length (insn)) - { - case 2: return \"b%d1\\t%l0\\t%@cond_branch\"; - case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\"; - default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\"; - } -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "6") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int -252)) - (le (minus (match_dup 0) (pc)) (const_int 254))) - (const_int 2) - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 4) - (const_int 6))))]) - -(define_insn "*cond_branch_reversed" - [(set (pc) (if_then_else (match_operator 1 "comparison_operator" - [(cc0) (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "* - switch (get_attr_length (insn)) - { - case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\"; - case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\"; - default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\"; - } - return \"\"; -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "6") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int -252)) - (le (minus (match_dup 0) (pc)) (const_int 254))) - (const_int 2) - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 4) - (const_int 6))))]) - -(define_insn "indirect_jump" - [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r"))] - "" - "mov\\tpc, %0") - -(define_insn "tablejump" - [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r")) - (use (label_ref (match_operand 1 "" "")))] - "" - "mov\\tpc, %0") - -(define_insn "return" - [(return)] - "USE_RETURN" - "* return output_return ();" -[(set_attr "length" "18")]) - -;; Call insns - -(define_expand "call" - [(call (match_operand:SI 0 "memory_operand" "") - (match_operand 1 "" ""))] - "" - "") - -(define_insn "*call_indirect" - [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) - (match_operand 1 "" ""))] - "! TARGET_CALLER_INTERWORKING" - "bl\\t%__call_via_%0" -[(set_attr "length" "4")]) -;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version -;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set -;; the bottom bit of lr so that a function return (using bx) -;; would switch back into ARM mode... - -(define_insn "*call_indirect_interwork" - [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) - (match_operand 1 "" ""))] - "TARGET_CALLER_INTERWORKING" - "bl\\t%__interwork_call_via_%0" -[(set_attr "length" "4")]) - -(define_expand "call_value" - [(set (match_operand 0 "" "") - (call (match_operand 1 "memory_operand" "") - (match_operand 2 "" "")))] - "" - "") - -(define_insn "*call_value_indirect" - [(set (match_operand 0 "" "=l") - (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) - (match_operand 2 "" "")))] - "! TARGET_CALLER_INTERWORKING" - "bl\\t%__call_via_%1" -[(set_attr "length" "4")]) -;; See comment for call_indirect pattern - -(define_insn "*call_value_indirect_interwork" - [(set (match_operand 0 "" "=l") - (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) - (match_operand 2 "" "")))] - "TARGET_CALLER_INTERWORKING" - "bl\\t%__interwork_call_via_%1" -[(set_attr "length" "4")]) - - -(define_insn "*call_insn" - [(call (mem:SI (match_operand:SI 0 "" "i")) - (match_operand:SI 1 "" ""))] - "GET_CODE (operands[0]) == SYMBOL_REF" - "bl\\t%a0" -[(set_attr "length" "4")]) - -(define_insn "*call_value_insn" - [(set (match_operand 0 "s_register_operand" "=l") - (call (mem:SI (match_operand 1 "" "i")) - (match_operand 2 "" "")))] - "GET_CODE (operands[1]) == SYMBOL_REF" - "bl\\t%a1" -[(set_attr "length" "4")]) - -;; Untyped call not required, since all funcs return in r0 - -;; Miscellaneous patterns - -(define_insn "nop" - [(clobber (const_int 0))] - "" - "mov\\tr8, r8") - -(define_insn "blockage" - [(unspec_volatile [(const_int 0)] 0)] - "" - "" - [(set_attr "length" "0")]) - -(define_expand "prologue" - [(const_int 0)] - "" - " - thumb_expand_prologue (); - DONE; -") - -(define_expand "epilogue" - [(unspec_volatile [(const_int 0)] 1)] - "! thumb_trivial_epilogue ()" - " - thumb_expand_epilogue (); -") - -(define_insn "*epilogue_insns" - [(unspec_volatile [(const_int 0)] 1)] - "" - "* - return thumb_unexpanded_epilogue (); -" -[(set_attr "length" "42")]) - -;; Special patterns for dealing with the constant pool - -(define_insn "consttable_4" - [(unspec_volatile [(match_operand 0 "" "")] 2)] - "" - "* -{ - switch (GET_MODE_CLASS (GET_MODE (operands[0]))) - { - case MODE_FLOAT: - { - union real_extract u; - bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); - assemble_real (u.d, GET_MODE (operands[0])); - break; - } - default: - assemble_integer (operands[0], 4, 1); - break; - } - return \"\"; -}" -[(set_attr "length" "4")]) - -(define_insn "consttable_8" - [(unspec_volatile [(match_operand 0 "" "")] 3)] - "" - "* -{ - switch (GET_MODE_CLASS (GET_MODE (operands[0]))) - { - case MODE_FLOAT: - { - union real_extract u; - bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); - assemble_real (u.d, GET_MODE (operands[0])); - break; - } - default: - assemble_integer (operands[0], 8, 1); - break; - } - return \"\"; -}" -[(set_attr "length" "8")]) - -(define_insn "consttable_end" - [(unspec_volatile [(const_int 0)] 4)] - "" - "* - /* Nothing to do (currently). */ - return \"\"; -") - -(define_insn "align_4" - [(unspec_volatile [(const_int 0)] 5)] - "" - "* - assemble_align (32); - return \"\"; -") diff --git a/gcc/config/arm/thumb_010309a.c b/gcc/config/arm/thumb_010309a.c deleted file mode 100755 index 778cda9..0000000 --- a/gcc/config/arm/thumb_010309a.c +++ /dev/null @@ -1,2132 +0,0 @@ -/* Output routines for GCC for ARM/Thumb - Copyright (C) 1996 Cygnus Software Technologies Ltd - The basis of this contribution was generated by - Richard Earnshaw, Advanced RISC Machines Ltd - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#include <stdio.h> -#include <string.h> -#include "config.h" -#include "rtl.h" -#include "hard-reg-set.h" -#include "regs.h" -#include "output.h" -#include "insn-flags.h" -#include "insn-attr.h" -#include "flags.h" -#include "tree.h" -#include "expr.h" - - -int current_function_anonymous_args = 0; -static int current_function_has_far_jump = 0; - -/* Used to parse -mstructure_size_boundary command line option. */ -char * structure_size_string = NULL; -int arm_structure_size_boundary = 32; /* Used to be 8 */ - - -/* Predicates */ -int -reload_memory_operand (op, mode) - rtx op; - enum machine_mode mode; -{ - int regno = true_regnum (op); - - return (! CONSTANT_P (op) - && (regno == -1 - || (GET_CODE (op) == REG - && REGNO (op) >= FIRST_PSEUDO_REGISTER))); -} - -/* Return nonzero if op is suitable for the RHS of a cmp instruction. */ -int -thumb_cmp_operand (op, mode) - rtx op; - enum machine_mode mode; -{ - return ((GET_CODE (op) == CONST_INT - && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256) - || register_operand (op, mode)); -} - -int -thumb_shiftable_const (val) - HOST_WIDE_INT val; -{ - unsigned HOST_WIDE_INT x = val; - unsigned HOST_WIDE_INT mask = 0xff; - int i; - - for (i = 0; i < 25; i++) - if ((val & (mask << i)) == val) - return 1; - - return 0; -} - -int -thumb_trivial_epilogue () -{ - int regno; - - /* ??? If this function ever returns 1, we get a function without any - epilogue at all. It appears that the intent was to cause a "return" - insn to be emitted, but that does not happen. */ - return 0; - -#if 0 - if (get_frame_size () - || current_function_outgoing_args_size - || current_function_pretend_args_size) - return 0; - - for (regno = 8; regno < 13; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - return 0; - - return 1; -#endif -} - - -/* Routines for handling the constant pool */ -/* This is unashamedly hacked from the version in sh.c, since the problem is - extremely similar. */ - -/* Thumb instructions cannot load a large constant into a register, - constants have to come from a pc relative load. The reference of a pc - relative load instruction must be less than 1k infront of the instruction. - This means that we often have to dump a constant inside a function, and - generate code to branch around it. - - It is important to minimize this, since the branches will slow things - down and make things bigger. - - Worst case code looks like: - - ldr rn, L1 - b L2 - align - L1: .long value - L2: - .. - - ldr rn, L3 - b L4 - align - L3: .long value - L4: - .. - - We fix this by performing a scan before scheduling, which notices which - instructions need to have their operands fetched from the constant table - and builds the table. - - - The algorithm is: - - scan, find an instruction which needs a pcrel move. Look forward, find the - last barrier which is within MAX_COUNT bytes of the requirement. - If there isn't one, make one. Process all the instructions between - the find and the barrier. - - In the above example, we can tell that L3 is within 1k of L1, so - the first move can be shrunk from the 2 insn+constant sequence into - just 1 insn, and the constant moved to L3 to make: - - ldr rn, L1 - .. - ldr rn, L3 - b L4 - align - L1: .long value - L3: .long value - L4: - - Then the second move becomes the target for the shortening process. - - */ - -typedef struct -{ - rtx value; /* Value in table */ - HOST_WIDE_INT next_offset; - enum machine_mode mode; /* Mode of value */ -} pool_node; - -/* The maximum number of constants that can fit into one pool, since - the pc relative range is 0...1020 bytes and constants are at least 4 - bytes long */ - -#define MAX_POOL_SIZE (1020/4) -static pool_node pool_vector[MAX_POOL_SIZE]; -static int pool_size; -static rtx pool_vector_label; - -/* Add a constant to the pool and return its label. */ - -static HOST_WIDE_INT -add_constant (x, mode) - rtx x; - enum machine_mode mode; -{ - int i; - rtx lab; - HOST_WIDE_INT offset; - - if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0)) - && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) - x = get_pool_constant (XEXP (x, 0)); - - /* First see if we've already got it */ - - for (i = 0; i < pool_size; i++) - { - if (x->code == pool_vector[i].value->code - && mode == pool_vector[i].mode) - { - if (x->code == CODE_LABEL) - { - if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) - continue; - } - if (rtx_equal_p (x, pool_vector[i].value)) - return pool_vector[i].next_offset - GET_MODE_SIZE (mode); - } - } - - /* Need a new one */ - - pool_vector[pool_size].next_offset = GET_MODE_SIZE (mode); - offset = 0; - if (pool_size == 0) - pool_vector_label = gen_label_rtx (); - else - pool_vector[pool_size].next_offset - += (offset = pool_vector[pool_size - 1].next_offset); - - pool_vector[pool_size].value = x; - pool_vector[pool_size].mode = mode; - pool_size++; - return offset; -} - -/* Output the literal table */ - -static void -dump_table (scan) - rtx scan; -{ - int i; - - scan = emit_label_after (gen_label_rtx (), scan); - scan = emit_insn_after (gen_align_4 (), scan); - scan = emit_label_after (pool_vector_label, scan); - - for (i = 0; i < pool_size; i++) - { - pool_node *p = pool_vector + i; - - switch (GET_MODE_SIZE (p->mode)) - { - case 4: - scan = emit_insn_after (gen_consttable_4 (p->value), scan); - break; - - case 8: - scan = emit_insn_after (gen_consttable_8 (p->value), scan); - break; - - default: - abort (); - break; - } - } - - scan = emit_insn_after (gen_consttable_end (), scan); - scan = emit_barrier_after (scan); - pool_size = 0; -} - -/* Non zero if the src operand needs to be fixed up */ -static -int -fixit (src, mode) - rtx src; - enum machine_mode mode; -{ - return ((CONSTANT_P (src) - && (GET_CODE (src) != CONST_INT - || ! (CONST_OK_FOR_LETTER_P (INTVAL (src), 'I') - || CONST_OK_FOR_LETTER_P (INTVAL (src), 'J') - || (mode != DImode - && CONST_OK_FOR_LETTER_P (INTVAL (src), 'K'))))) - || (mode == SImode && GET_CODE (src) == MEM - && GET_CODE (XEXP (src, 0)) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (XEXP (src, 0)))); -} - -/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one. */ - -#define MAX_COUNT_SI 1000 - -static rtx -find_barrier (from) - rtx from; -{ - int count = 0; - rtx found_barrier = 0; - rtx label; - - while (from && count < MAX_COUNT_SI) - { - if (GET_CODE (from) == BARRIER) - return from; - - /* Count the length of this insn */ - if (GET_CODE (from) == INSN - && GET_CODE (PATTERN (from)) == SET - && CONSTANT_P (SET_SRC (PATTERN (from))) - && CONSTANT_POOL_ADDRESS_P (SET_SRC (PATTERN (from)))) - { - rtx src = SET_SRC (PATTERN (from)); - count += 2; - } - else - count += get_attr_length (from); - - from = NEXT_INSN (from); - } - - /* We didn't find a barrier in time to - dump our stuff, so we'll make one */ - label = gen_label_rtx (); - - if (from) - from = PREV_INSN (from); - else - from = get_last_insn (); - - /* Walk back to be just before any jump */ - while (GET_CODE (from) == JUMP_INSN - || GET_CODE (from) == NOTE - || GET_CODE (from) == CODE_LABEL) - from = PREV_INSN (from); - - from = emit_jump_insn_after (gen_jump (label), from); - JUMP_LABEL (from) = label; - found_barrier = emit_barrier_after (from); - emit_label_after (label, found_barrier); - return found_barrier; -} - -/* Non zero if the insn is a move instruction which needs to be fixed. */ - -static int -broken_move (insn) - rtx insn; -{ - if (!INSN_DELETED_P (insn) - && GET_CODE (insn) == INSN - && GET_CODE (PATTERN (insn)) == SET) - { - rtx pat = PATTERN (insn); - rtx src = SET_SRC (pat); - rtx dst = SET_DEST (pat); - enum machine_mode mode = GET_MODE (dst); - if (dst == pc_rtx) - return 0; - return fixit (src, mode); - } - return 0; -} - -/* Recursively search through all of the blocks in a function - checking to see if any of the variables created in that - function match the RTX called 'orig'. If they do then - replace them with the RTX called 'new'. */ - -static void -replace_symbols_in_block (tree block, rtx orig, rtx new) -{ - for (; block; block = BLOCK_CHAIN (block)) - { - tree sym; - - if (! TREE_USED (block)) - continue; - - for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym)) - { - if ( (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL) - || DECL_IGNORED_P (sym) - || TREE_CODE (sym) != VAR_DECL - || DECL_EXTERNAL (sym) - || ! rtx_equal_p (DECL_RTL (sym), orig) - ) - continue; - - DECL_RTL (sym) = new; - } - - replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new); - } -} - -void -thumb_reorg (first) - rtx first; -{ - rtx insn; - for (insn = first; insn; insn = NEXT_INSN (insn)) - { - if (broken_move (insn)) - { - /* This is a broken move instruction, scan ahead looking for - a barrier to stick the constant table behind */ - rtx scan; - rtx barrier = find_barrier (insn); - - /* Now find all the moves between the points and modify them */ - for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) - { - if (broken_move (scan)) - { - /* This is a broken move instruction, add it to the pool */ - rtx pat = PATTERN (scan); - rtx src = SET_SRC (pat); - rtx dst = SET_DEST (pat); - enum machine_mode mode = GET_MODE (dst); - HOST_WIDE_INT offset; - rtx newinsn; - rtx newsrc; - - /* If this is an HImode constant load, convert it into - an SImode constant load. Since the register is always - 32 bits this is safe. We have to do this, since the - load pc-relative instruction only does a 32-bit load. */ - if (mode == HImode) - { - mode = SImode; - if (GET_CODE (dst) != REG) - abort (); - PUT_MODE (dst, SImode); - } - - offset = add_constant (src, mode); - newsrc = gen_rtx (MEM, mode, - plus_constant (gen_rtx (LABEL_REF, - VOIDmode, - pool_vector_label), - offset)); - - /* Build a jump insn wrapper around the move instead - of an ordinary insn, because we want to have room for - the target label rtx in fld[7], which an ordinary - insn doesn't have. */ - newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode, - dst, newsrc), scan); - JUMP_LABEL (newinsn) = pool_vector_label; - - /* But it's still an ordinary insn */ - PUT_CODE (newinsn, INSN); - - /* If debugging information is going to be emitted - then we must make sure that any refences to - symbols which are removed by the above code are - also removed in the descriptions of the - function's variables. Failure to do this means - that the debugging information emitted could - refer to symbols which are not emited by - output_constant_pool() because - mark_constant_pool() never sees them as being - used. */ - - - /* These are the tests used in - output_constant_pool() to decide if the constant - pool will be marked. Only necessary if debugging - info is being emitted. Only necessary for - references to memory whose address is given by a - symbol. */ - - if (optimize > 0 - && flag_expensive_optimizations - && write_symbols != NO_DEBUG - && GET_CODE (src) == MEM - && GET_CODE (XEXP (src, 0)) == SYMBOL_REF) - replace_symbols_in_block - (DECL_INITIAL (current_function_decl), src, newsrc); - - /* Kill old insn */ - delete_insn (scan); - scan = newinsn; - } - } - dump_table (barrier); - } - } -} - - -/* Routines for generating rtl */ - -void -thumb_expand_movstrqi (operands) - rtx *operands; -{ - rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); - rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); - HOST_WIDE_INT len = INTVAL (operands[2]); - HOST_WIDE_INT offset = 0; - - while (len >= 12) - { - emit_insn (gen_movmem12b (out, in)); - len -= 12; - } - if (len >= 8) - { - emit_insn (gen_movmem8b (out, in)); - len -= 8; - } - if (len >= 4) - { - rtx reg = gen_reg_rtx (SImode); - emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in))); - emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg)); - len -= 4; - offset += 4; - } - if (len >= 2) - { - rtx reg = gen_reg_rtx (HImode); - emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode, - plus_constant (in, offset)))); - emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)), - reg)); - len -= 2; - offset += 2; - } - if (len) - { - rtx reg = gen_reg_rtx (QImode); - emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode, - plus_constant (in, offset)))); - emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)), - reg)); - } -} - - -/* Routines for reloading */ - -void -thumb_reload_out_si (operands) - rtx operands; -{ - abort (); -} - -/* CYGNUS LOCAL nickc/thumb-pe */ - -#ifdef THUMB_PE -/* Return non-zero if FUNC is a naked function. */ - -static int -arm_naked_function_p (func) - tree func; -{ - tree a; - - if (TREE_CODE (func) != FUNCTION_DECL) - abort (); - - a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); - return a != NULL_TREE; -} -#endif -/* END CYGNUS LOCAL nickc/thumb-pe */ - -/* Return non-zero if FUNC must be entered in ARM mode. */ -int -is_called_in_ARM_mode (func) - tree func; -{ - if (TREE_CODE (func) != FUNCTION_DECL) - abort (); - - /* Ignore the problem about functions whoes address is taken. */ - if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func)) - return TRUE; - -/* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; -#else - return FALSE; -#endif -/* END CYGNUS LOCAL */ -} - - -/* Routines for emitting code */ - -void -final_prescan_insn(insn) - rtx insn; -{ - extern int *insn_addresses; - - if (flag_print_asm_name) - fprintf (asm_out_file, "%s 0x%04x\n", ASM_COMMENT_START, - insn_addresses[INSN_UID (insn)]); -} - - -static void thumb_pushpop ( FILE *, int, int ); /* Forward declaration. */ - -#ifdef __GNUC__ -inline -#endif -static int -number_of_first_bit_set (mask) - int mask; -{ - int bit; - - for (bit = 0; - (mask & (1 << bit)) == 0; - ++ bit) - continue; - - return bit; -} - -#define ARG_1_REGISTER 0 -#define ARG_2_REGISTER 1 -#define ARG_3_REGISTER 2 -#define ARG_4_REGISTER 3 -#define WORK_REGISTER 7 -#define FRAME_POINTER 11 -#define IP_REGISTER 12 -#define STACK_POINTER STACK_POINTER_REGNUM -#define LINK_REGISTER 14 -#define PROGRAM_COUNTER 15 - -/* Generate code to return from a thumb function. If - 'reg_containing_return_addr' is -1, then the return address is - actually on the stack, at the stack pointer. */ -static void -thumb_exit (f, reg_containing_return_addr) - FILE * f; - int reg_containing_return_addr; -{ - int regs_available_for_popping; - int regs_to_pop; - int pops_needed; - int reg; - int available; - int required; - int mode; - int size; - int restore_a4 = FALSE; - - /* Compute the registers we need to pop. */ - regs_to_pop = 0; - pops_needed = 0; - - if (reg_containing_return_addr == -1) - { - regs_to_pop |= 1 << LINK_REGISTER; - ++ pops_needed; - } - - if (TARGET_BACKTRACE) - { - /* Restore frame pointer and stack pointer. */ - regs_to_pop |= (1 << FRAME_POINTER) | (1 << STACK_POINTER); - pops_needed += 2; - } - - /* If there is nothing to pop then just emit the BX instruction and return.*/ - if (pops_needed == 0) - { - asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); - - return; - } - - /* Otherwise if we are not supporting interworking and we have not created - a backtrace structure and the function was not entered in ARM mode then - just pop the return address straight into the PC. */ - else if ( ! TARGET_THUMB_INTERWORK - && ! TARGET_BACKTRACE - && ! is_called_in_ARM_mode (current_function_decl)) - { - asm_fprintf (f, "\tpop\t{pc}\n" ); - - return; - } - - /* Find out how many of the (return) argument registers we can corrupt. */ - regs_available_for_popping = 0; - -#ifdef RTX_CODE - /* If we can deduce the registers used from the function's return value. - This is more reliable that examining regs_ever_live[] because that - will be set if the register is ever used in the function, not just if - the register is used to hold a return value. */ - - if (current_function_return_rtx != 0) - mode = GET_MODE (current_function_return_rtx); - else -#endif - mode = DECL_MODE (DECL_RESULT (current_function_decl)); - - size = GET_MODE_SIZE (mode); - - if (size == 0) - { - /* In a void function we can use any argument register. - In a function that returns a structure on the stack - we can use the second and third argument registers. */ - if (mode == VOIDmode) - regs_available_for_popping = - (1 << ARG_1_REGISTER) - | (1 << ARG_2_REGISTER) - | (1 << ARG_3_REGISTER); - else - regs_available_for_popping = - (1 << ARG_2_REGISTER) - | (1 << ARG_3_REGISTER); - } - else if (size <= 4) regs_available_for_popping = - (1 << ARG_2_REGISTER) - | (1 << ARG_3_REGISTER); - else if (size <= 8) regs_available_for_popping = - (1 << ARG_3_REGISTER); - - /* Match registers to be popped with registers into which we pop them. */ - for (available = regs_available_for_popping, - required = regs_to_pop; - required != 0 && available != 0; - available &= ~(available & - available), - required &= ~(required & - required)) - -- pops_needed; - - /* If we have any popping registers left over, remove them. */ - if (available > 0) - regs_available_for_popping &= ~ available; - - /* Otherwise if we need another popping register we can use - the fourth argument register. */ - else if (pops_needed) - { - /* If we have not found any free argument registers and - reg a4 contains the return address, we must move it. */ - if (regs_available_for_popping == 0 - && reg_containing_return_addr == ARG_4_REGISTER) - { - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); - reg_containing_return_addr = LINK_REGISTER; - } - else if (size > 12) - { - /* Register a4 is being used to hold part of the return value, - but we have dire need of a free, low register. */ - restore_a4 = TRUE; - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [IP_REGISTER], reg_names [ARG_4_REGISTER]); - } - - if (reg_containing_return_addr != ARG_4_REGISTER) - { - /* The fourth argument register is available. */ - regs_available_for_popping |= 1 << ARG_4_REGISTER; - - -- pops_needed; - } - } - - /* Pop as many registers as we can. */ - thumb_pushpop (f, regs_available_for_popping, FALSE); - - /* Process the registers we popped. */ - if (reg_containing_return_addr == -1) - { - /* The return address was popped into the lowest numbered register. */ - regs_to_pop &= ~ (1 << LINK_REGISTER); - - reg_containing_return_addr = - number_of_first_bit_set (regs_available_for_popping); - - /* Remove this register for the mask of available registers, so that - the return address will not be corrupted by futher pops. */ - regs_available_for_popping &= ~ (1 << reg_containing_return_addr); - } - - /* If we popped other registers then handle them here. */ - if (regs_available_for_popping) - { - int frame_pointer; - - /* Work out which register currently contains the frame pointer. */ - frame_pointer = number_of_first_bit_set (regs_available_for_popping); - - /* Move it into the correct place. */ - asm_fprintf (f, "\tmov\tfp, %s\n", reg_names [frame_pointer]); - - /* (Temporarily) remove it from the mask of popped registers. */ - regs_available_for_popping &= ~ (1 << frame_pointer); - regs_to_pop &= ~ (1 << FRAME_POINTER); - - if (regs_available_for_popping) - { - int stack_pointer; - - /* We popped the stack pointer as well, find the register that - contains it.*/ - stack_pointer = number_of_first_bit_set (regs_available_for_popping); - - /* Move it into the stack register. */ - asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [stack_pointer]); - - /* At this point we have popped all necessary registers, so - do not worry about restoring regs_available_for_popping - to its correct value: - - assert (pops_needed == 0) - assert (regs_available_for_popping == (1 << frame_pointer)) - assert (regs_to_pop == (1 << STACK_POINTER)) */ - } - else - { - /* Since we have just move the popped value into the frame - pointer, the popping register is available for reuse, and - we know that we still have the stack pointer left to pop. */ - regs_available_for_popping |= (1 << frame_pointer); - } - } - - /* If we still have registers left on the stack, but we no longer have - any registers into which we can pop them, then we must move the return - address into the link register and make available the register that - contained it. */ - if (regs_available_for_popping == 0 && pops_needed > 0) - { - regs_available_for_popping |= 1 << reg_containing_return_addr; - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [LINK_REGISTER], - reg_names [reg_containing_return_addr]); - - reg_containing_return_addr = LINK_REGISTER; - } - - /* If we have registers left on the stack then pop some more. - We know that at most we will want to pop FP and SP. */ - if (pops_needed > 0) - { - int popped_into; - int move_to; - - thumb_pushpop (f, regs_available_for_popping, FALSE); - - /* We have popped either FP or SP. - Move whichever one it is into the correct register. */ - popped_into = number_of_first_bit_set (regs_available_for_popping); - move_to = number_of_first_bit_set (regs_to_pop); - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [move_to], reg_names [popped_into]); - - regs_to_pop &= ~ (1 << move_to); - - -- pops_needed; - } - - /* If we still have not popped everything then we must have only - had one register available to us and we are now popping the SP. */ - if (pops_needed > 0) - { - int popped_into; - - thumb_pushpop (f, regs_available_for_popping, FALSE); - - popped_into = number_of_first_bit_set (regs_available_for_popping); - - asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [popped_into]); - - /* - assert (regs_to_pop == (1 << STACK_POINTER)) - assert (pops_needed == 1) - */ - } - - /* If necessary restore the a4 register. */ - if (restore_a4) - { - if (reg_containing_return_addr != LINK_REGISTER) - { - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); - reg_containing_return_addr = LINK_REGISTER; - } - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [ARG_4_REGISTER], reg_names [IP_REGISTER]); - } - - /* Return to caller. */ - asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); -} - -/* Emit code to push or pop registers to or from the stack. */ -static void -thumb_pushpop (f, mask, push) - FILE * f; - int mask; - int push; -{ - int regno; - int lo_mask = mask & 0xFF; - - if (lo_mask == 0 && ! push && (mask & (1 << 15))) - { - /* Special case. Do not generate a POP PC statement here, do it in - thumb_exit() */ - - thumb_exit (f, -1); - return; - } - - asm_fprintf (f, "\t%s\t{", push ? "push" : "pop"); - - /* Look at the low registers first. */ - - for (regno = 0; regno < 8; regno ++, lo_mask >>= 1) - { - if (lo_mask & 1) - { - asm_fprintf (f, reg_names[regno]); - - if ((lo_mask & ~1) != 0) - asm_fprintf (f, ", "); - } - } - - if (push && (mask & (1 << 14))) - { - /* Catch pushing the LR. */ - - if (mask & 0xFF) - asm_fprintf (f, ", "); - - asm_fprintf (f, reg_names[14]); - } - else if (!push && (mask & (1 << 15))) - { - /* Catch popping the PC. */ - - if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) - { - /* The PC is never poped directly, instead - it is popped into r3 and then BX is used. */ - - asm_fprintf (f, "}\n"); - - thumb_exit (f, -1); - - return; - } - else - { - if (mask & 0xFF) - asm_fprintf (f, ", "); - - asm_fprintf (f, reg_names[15]); - } - } - - asm_fprintf (f, "}\n"); -} - -/* Returns non-zero if the current function contains a far jump */ - -int -far_jump_used_p (void) -{ - rtx insn; - - if (current_function_has_far_jump) - return 1; - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (GET_CODE (insn) == JUMP_INSN - /* Ignore tablejump patterns. */ - && GET_CODE (PATTERN (insn)) != ADDR_VEC - && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC - && get_attr_far_jump (insn) == FAR_JUMP_YES) - { - current_function_has_far_jump = 1; - return 1; - } - } - - return 0; -} - -static int return_used_this_function = 0; - -char * -output_return () -{ - int regno; - int live_regs_mask = 0; - - /* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - /* If a function is naked, don't use the "return" insn. */ - if (arm_naked_function_p (current_function_decl)) - return ""; -#endif - /* END CYGNUS LOCAL nickc/thumb-pe */ - - return_used_this_function = 1; - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - if (live_regs_mask == 0) - { - if (leaf_function_p () && ! far_jump_used_p()) - { - thumb_exit (asm_out_file, 14); - } - else if ( TARGET_THUMB_INTERWORK - || TARGET_BACKTRACE - || is_called_in_ARM_mode (current_function_decl)) - { - thumb_exit (asm_out_file, -1); - } - else - asm_fprintf (asm_out_file, "\tpop\t{pc}\n"); - } - else - { - asm_fprintf (asm_out_file, "\tpop\t{"); - - for (regno = 0; live_regs_mask; regno ++, live_regs_mask >>= 1) - if (live_regs_mask & 1) - { - asm_fprintf (asm_out_file, reg_names[regno]); - if (live_regs_mask & ~1) - asm_fprintf (asm_out_file, ", "); - } - - if ( TARGET_THUMB_INTERWORK - || TARGET_BACKTRACE - || is_called_in_ARM_mode (current_function_decl)) - { - asm_fprintf (asm_out_file, "}\n"); - thumb_exit (asm_out_file, -1); - } - else - asm_fprintf (asm_out_file, ", pc}\n"); - } - - return ""; -} - -void -thumb_function_prologue (f, frame_size) - FILE *f; - int frame_size; -{ - int amount = frame_size + current_function_outgoing_args_size; - int live_regs_mask = 0; - int high_regs_pushed = 0; - int store_arg_regs = 0; - int regno; - -/* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - if (arm_naked_function_p (current_function_decl)) - return; -#endif -/* CYGNUS LOCAL nickc/thumb-pe */ - - if (is_called_in_ARM_mode (current_function_decl)) - { - char * name; - if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) - abort(); - if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) - abort(); - name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); - - /* Generate code sequence to switch us into Thumb mode. */ - /* The .code 32 directive has already been emitted by - ASM_DECLARE_FUNCITON_NAME */ - asm_fprintf (f, "\torr\tr12, pc, #1\n"); - asm_fprintf (f, "\tbx\tr12\n"); - - /* Generate a label, so that the debugger will notice the - change in instruction sets. This label is also used by - the assembler to bypass the ARM code when this function - is called from a Thumb encoded function elsewhere in the - same file. Hence the definition of STUB_NAME here must - agree with the definition in gas/config/tc-arm.c */ - -#define STUB_NAME ".real_start_of" - - asm_fprintf (f, "\t.code\t16\n"); - asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); - asm_fprintf (f, "\t.thumb_func\n"); - asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); - } - - if (current_function_anonymous_args && current_function_pretend_args_size) - store_arg_regs = 1; - - if (current_function_pretend_args_size) - { - if (store_arg_regs) - { - asm_fprintf (f, "\tpush\t{"); - for (regno = 4 - current_function_pretend_args_size / 4 ; regno < 4; - regno++) - asm_fprintf (f, "%s%s", reg_names[regno], regno == 3 ? "" : ", "); - asm_fprintf (f, "}\n"); - } - else - asm_fprintf (f, "\tsub\t%Rsp, %Rsp, #%d\n", - current_function_pretend_args_size); - } - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - if (live_regs_mask || ! leaf_function_p () || far_jump_used_p()) - live_regs_mask |= 1 << 14; - - if (TARGET_BACKTRACE) - { - char * name; - int offset; - int work_register = 0; - - - /* We have been asked to create a stack backtrace structure. - The code looks like this: - - 0 .align 2 - 0 func: - 0 sub SP, #16 Reserve space for 4 registers. - 2 push {R7} Get a work register. - 4 add R7, SP, #20 Get the stack pointer before the push. - 6 str R7, [SP, #8] Store the stack pointer (before reserving the space). - 8 mov R7, PC Get hold of the start of this code plus 12. - 10 str R7, [SP, #16] Store it. - 12 mov R7, FP Get hold of the current frame pointer. - 14 str R7, [SP, #4] Store it. - 16 mov R7, LR Get hold of the current return address. - 18 str R7, [SP, #12] Store it. - 20 add R7, SP, #16 Point at the start of the backtrace structure. - 22 mov FP, R7 Put this value into the frame pointer. */ - - if ((live_regs_mask & 0xFF) == 0) - { - /* See if the a4 register is free. */ - - if (regs_ever_live[ 3 ] == 0) - work_register = 3; - else /* We must push a register of our own */ - live_regs_mask |= (1 << 7); - } - - if (work_register == 0) - { - /* Select a register from the list that will be pushed to use as our work register. */ - - for (work_register = 8; work_register--;) - if ((1 << work_register) & live_regs_mask) - break; - } - - name = reg_names[ work_register ]; - - asm_fprintf (f, "\tsub\tsp, sp, #16\t@ Create stack backtrace structure\n"); - - if (live_regs_mask) - thumb_pushpop (f, live_regs_mask, 1); - - for (offset = 0, work_register = 1 << 15; work_register; work_register >>= 1) - if (work_register & live_regs_mask) - offset += 4; - - asm_fprintf (f, "\tadd\t%s, sp, #%d\n", - name, offset + 16 + current_function_pretend_args_size); - - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 4); - - /* Make sure that the instruction fetching the PC is in the right place - to calculate "start of backtrace creation code + 12". */ - - if (live_regs_mask) - { - asm_fprintf (f, "\tmov\t%s, pc\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); - asm_fprintf (f, "\tmov\t%s, fp\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); - } - else - { - asm_fprintf (f, "\tmov\t%s, fp\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); - asm_fprintf (f, "\tmov\t%s, pc\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); - } - - asm_fprintf (f, "\tmov\t%s, lr\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 8); - asm_fprintf (f, "\tadd\t%s, sp, #%d\n", name, offset + 12); - asm_fprintf (f, "\tmov\tfp, %s\t\t@ Backtrace structure created\n", name); - } - else if (live_regs_mask) - thumb_pushpop (f, live_regs_mask, 1); - - for (regno = 8; regno < 13; regno++) - { - if (regs_ever_live[regno] && ! call_used_regs[regno]) - high_regs_pushed++; - } - - if (high_regs_pushed) - { - int pushable_regs = 0; - int mask = live_regs_mask & 0xff; - int next_hi_reg; - - for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--) - { - if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) - break; - } - - pushable_regs = mask; - - if (pushable_regs == 0) - { - /* desperation time -- this probably will never happen */ - if (regs_ever_live[3] || ! call_used_regs[3]) - asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[12], reg_names[3]); - mask = 1 << 3; - } - - while (high_regs_pushed > 0) - { - for (regno = 7; regno >= 0; regno--) - { - if (mask & (1 << regno)) - { - asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[regno], - reg_names[next_hi_reg]); - high_regs_pushed--; - if (high_regs_pushed) - for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--) - { - if (regs_ever_live[next_hi_reg] - && ! call_used_regs[next_hi_reg]) - break; - } - else - { - mask &= ~ ((1 << regno) - 1); - break; - } - } - } - thumb_pushpop (f, mask, 1); - } - - if (pushable_regs == 0 && (regs_ever_live[3] || ! call_used_regs[3])) - asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[3], reg_names[12]); - } -} - -void -thumb_expand_prologue () -{ - HOST_WIDE_INT amount = (get_frame_size () - + current_function_outgoing_args_size); - int regno; - int live_regs_mask; - - /* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - /* Naked functions don't have prologues. */ - if (arm_naked_function_p (current_function_decl)) - return; -#endif - /* END CYGNUS LOCAL nickc/thumb-pe */ - - if (amount) - { - live_regs_mask = 0; - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - if (amount < 512) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (-amount))); - else - { - rtx reg, spare; - - if ((live_regs_mask & 0xff) == 0) /* Very unlikely */ - emit_insn (gen_movsi (spare = gen_rtx (REG, SImode, 12), - reg = gen_rtx (REG, SImode, 4))); - else - { - for (regno = 0; regno < 8; regno++) - if (live_regs_mask & (1 << regno)) - break; - reg = gen_rtx (REG, SImode, regno); - } - - emit_insn (gen_movsi (reg, GEN_INT (-amount))); - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); - if ((live_regs_mask & 0xff) == 0) - emit_insn (gen_movsi (reg, spare)); - } - } - - if (frame_pointer_needed) - { - if (current_function_outgoing_args_size) - { - rtx offset = GEN_INT (current_function_outgoing_args_size); - - if (current_function_outgoing_args_size < 1024) - emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, - offset)); - else - { - emit_insn (gen_movsi (frame_pointer_rtx, offset)); - emit_insn (gen_addsi3 (frame_pointer_rtx, frame_pointer_rtx, - stack_pointer_rtx)); - } - } - else - emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); - } - - /* if (profile_flag || profile_block_flag) */ - emit_insn (gen_blockage ()); -} - -void -thumb_expand_epilogue () -{ - HOST_WIDE_INT amount = (get_frame_size () - + current_function_outgoing_args_size); - int regno; - - /* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - /* Naked functions don't have epilogues. */ - if (arm_naked_function_p (current_function_decl)) - return; -#endif - /* END CYGNUS LOCAL nickc/thumb-pe */ - - if (amount) - { - if (amount < 512) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (amount))); - else - { - rtx reg = gen_rtx (REG, SImode, 3); /* Always free in the epilogue */ - - emit_insn (gen_movsi (reg, GEN_INT (amount))); - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); - } - /* if (profile_flag || profile_block_flag) */ - emit_insn (gen_blockage ()); - } -} - -void -thumb_function_epilogue (f, frame_size) - FILE *f; - int frame_size; -{ - /* ??? Probably not safe to set this here, since it assumes that a - function will be emitted as assembly immediately after we generate - RTL for it. This does not happen for inline functions. */ - return_used_this_function = 0; - current_function_has_far_jump = 0; -#if 0 /* TODO : comment not really needed */ - fprintf (f, "%s THUMB Epilogue\n", ASM_COMMENT_START); -#endif -} - -/* The bits which aren't usefully expanded as rtl. */ -char * -thumb_unexpanded_epilogue () -{ - int regno; - int live_regs_mask = 0; - int high_regs_pushed = 0; - int leaf_function = leaf_function_p (); - int had_to_push_lr; - - if (return_used_this_function) - return ""; - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - for (regno = 8; regno < 13; regno++) - { - if (regs_ever_live[regno] && ! call_used_regs[regno]) - high_regs_pushed ++; - } - - /* The prolog may have pushed some high registers to use as - work registers. eg the testuite file: - gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c - compiles to produce: - push {r4, r5, r6, r7, lr} - mov r7, r9 - mov r6, r8 - push {r6, r7} - as part of the prolog. We have to undo that pushing here. */ - - if (high_regs_pushed) - { - int mask = live_regs_mask; - int next_hi_reg; - int size; - int mode; - -#ifdef RTX_CODE - /* If we can deduce the registers used from the function's return value. - This is more reliable that examining regs_ever_live[] because that - will be set if the register is ever used in the function, not just if - the register is used to hold a return value. */ - - if (current_function_return_rtx != 0) - { - mode = GET_MODE (current_function_return_rtx); - } - else -#endif - { - mode = DECL_MODE (DECL_RESULT (current_function_decl)); - } - - size = GET_MODE_SIZE (mode); - - /* Unless we are returning a type of size > 12 register r3 is available. */ - if (size < 13) - mask |= 1 << 3; - - if (mask == 0) - { - /* Oh dear! We have no low registers into which we can pop high registers! */ - - fatal ("No low registers available for popping high registers"); - } - - for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++) - if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) - break; - - while (high_regs_pushed) - { - /* Find low register(s) into which the high register(s) can be popped. */ - for (regno = 0; regno < 8; regno++) - { - if (mask & (1 << regno)) - high_regs_pushed--; - if (high_regs_pushed == 0) - break; - } - - mask &= (2 << regno) - 1; /* A noop if regno == 8 */ - - /* Pop the values into the low register(s). */ - thumb_pushpop (asm_out_file, mask, 0); - - /* Move the value(s) into the high registers. */ - for (regno = 0; regno < 8; regno++) - { - if (mask & (1 << regno)) - { - asm_fprintf (asm_out_file, "\tmov\t%s, %s\n", - reg_names[next_hi_reg], reg_names[regno]); - for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++) - if (regs_ever_live[next_hi_reg] && - ! call_used_regs[next_hi_reg]) - break; - } - } - } - } - - had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); - - if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) - { - /* The stack backtrace structure creation code had to - push R7 in order to get a work register, so we pop - it now. */ - - live_regs_mask |= (1 << WORK_REGISTER); - } - - if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) - { - if (had_to_push_lr - && ! is_called_in_ARM_mode (current_function_decl)) - live_regs_mask |= 1 << PROGRAM_COUNTER; - - /* Either no argument registers were pushed or a backtrace - structure was created which includes an adjusted stack - pointer, so just pop everything. */ - - if (live_regs_mask) - thumb_pushpop (asm_out_file, live_regs_mask, FALSE); - - /* We have either just popped the return address into the - PC or it is was kept in LR for the entire function or - it is still on the stack because we do not want to - return by doing a pop {pc}. */ - - if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0) - thumb_exit (asm_out_file, - (had_to_push_lr - && is_called_in_ARM_mode (current_function_decl)) ? - -1 : LINK_REGISTER); - } - else - { - /* Pop everything but the return address. */ - live_regs_mask &= ~ (1 << PROGRAM_COUNTER); - - if (live_regs_mask) - thumb_pushpop (asm_out_file, live_regs_mask, FALSE); - - if (had_to_push_lr) - { - /* Get the return address into a temporary register. */ - thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0); - } - - /* Remove the argument registers that were pushed onto the stack. */ - asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n", - reg_names [STACK_POINTER], - reg_names [STACK_POINTER], - current_function_pretend_args_size); - - thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER); - } - - return ""; -} - -/* Handle the case of a double word load into a low register from - a computed memory address. The computed address may involve a - register which is overwritten by the load. */ - -char * -thumb_load_double_from_address (operands) - rtx * operands; -{ - rtx addr; - rtx base; - rtx offset; - rtx arg1; - rtx arg2; - - if (GET_CODE (operands[0]) != REG) - fatal ("thumb_load_double_from_address: destination is not a register"); - - if (GET_CODE (operands[1]) != MEM) - fatal ("thumb_load_double_from_address: source is not a computed memory address"); - - /* Get the memory address. */ - - addr = XEXP (operands[1], 0); - - /* Work out how the memory address is computed. */ - - switch (GET_CODE (addr)) - { - case REG: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - if (REGNO (operands[0]) == REGNO (addr)) - { - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - } - else - { - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - } - break; - - case CONST: - /* Compute <address> + 4 for the high order load. */ - - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - break; - - case PLUS: - arg1 = XEXP (addr, 0); - arg2 = XEXP (addr, 1); - - if (CONSTANT_P (arg1)) - base = arg2, offset = arg1; - else - base = arg1, offset = arg2; - - if (GET_CODE (base) != REG) - fatal ("thumb_load_double_from_address: base is not a register"); - - /* Catch the case of <address> = <reg> + <reg> */ - - if (GET_CODE (offset) == REG) - { - int reg_offset = REGNO (offset); - int reg_base = REGNO (base); - int reg_dest = REGNO (operands[0]); - - /* Add the base and offset registers together into the higher destination register. */ - - fprintf (asm_out_file, "\tadd\t%s, %s, %s\t\t%s created by thumb_load_double_from_address", - reg_names[ reg_dest + 1 ], - reg_names[ reg_base ], - reg_names[ reg_offset ], - ASM_COMMENT_START); - - /* Load the lower destination register from the address in the higher destination register. */ - - fprintf (asm_out_file, "\tldr\t%s, [%s, #0]\t\t%s created by thumb_load_double_from_address", - reg_names[ reg_dest ], - reg_names[ reg_dest + 1], - ASM_COMMENT_START); - - /* Load the higher destination register from its own address plus 4. */ - - fprintf (asm_out_file, "\tldr\t%s, [%s, #4]\t\t%s created by thumb_load_double_from_address", - reg_names[ reg_dest + 1 ], - reg_names[ reg_dest + 1 ], - ASM_COMMENT_START); - } - else - { - /* Compute <address> + 4 for the high order load. */ - - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - /* If the computed address is held in the low order register - then load the high order register first, otherwise always - load the low order register first. */ - - if (REGNO (operands[0]) == REGNO (base)) - { - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - } - else - { - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - } - } - break; - - case LABEL_REF: - /* With no registers to worry about we can just load the value directly. */ - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - break; - - default: - debug_rtx (operands[1]); - fatal ("thumb_load_double_from_address: Unhandled address calculation"); - break; - } - - return ""; -} - -char * -output_move_mem_multiple (n, operands) - int n; - rtx *operands; -{ - rtx tmp; - - switch (n) - { - case 2: - if (REGNO (operands[2]) > REGNO (operands[3])) - { - tmp = operands[2]; - operands[2] = operands[3]; - operands[3] = tmp; - } - output_asm_insn ("ldmia\t%1!, {%2, %3}", operands); - output_asm_insn ("stmia\t%0!, {%2, %3}", operands); - break; - - case 3: - if (REGNO (operands[2]) > REGNO (operands[3])) - { - tmp = operands[2]; - operands[2] = operands[3]; - operands[3] = tmp; - } - if (REGNO (operands[3]) > REGNO (operands[4])) - { - tmp = operands[3]; - operands[3] = operands[4]; - operands[4] = tmp; - } - if (REGNO (operands[2]) > REGNO (operands[3])) - { - tmp = operands[2]; - operands[2] = operands[3]; - operands[3] = tmp; - } - output_asm_insn ("ldmia\t%1!, {%2, %3, %4}", operands); - output_asm_insn ("stmia\t%0!, {%2, %3, %4}", operands); - break; - - default: - abort (); - } - - return ""; -} - - -int -thumb_epilogue_size () -{ - return 42; /* The answer to .... */ -} - -static char *conds[] = -{ - "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", "gt", "le" -}; - -static char * -thumb_condition_code (x, invert) - rtx x; - int invert; -{ - int val; - - switch (GET_CODE (x)) - { - case EQ: val = 0; break; - case NE: val = 1; break; - case GEU: val = 2; break; - case LTU: val = 3; break; - case GTU: val = 8; break; - case LEU: val = 9; break; - case GE: val = 10; break; - case LT: val = 11; break; - case GT: val = 12; break; - case LE: val = 13; break; - default: - abort (); - } - - return conds[val ^ invert]; -} - -void -thumb_print_operand (f, x, code) - FILE *f; - rtx x; - int code; -{ - if (code) - { - switch (code) - { - case '@': - fputs (ASM_COMMENT_START, f); - return; - - case '_': - fputs (user_label_prefix, f); - return; - - case 'D': - if (x) - fputs (thumb_condition_code (x, 1), f); - return; - - case 'd': - if (x) - fputs (thumb_condition_code (x, 0), f); - return; - - /* An explanation of the 'Q', 'R' and 'H' register operands: - - In a pair of registers containing a DI or DF value the 'Q' - operand returns the register number of the register containing - the least signficant part of the value. The 'R' operand returns - the register number of the register containing the most - significant part of the value. - - The 'H' operand returns the higher of the two register numbers. - On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the - same as the 'Q' operand, since the most signficant part of the - value is held in the lower number register. The reverse is true - on systems where WORDS_BIG_ENDIAN is false. - - The purpose of these operands is to distinguish between cases - where the endian-ness of the values is important (for example - when they are added together), and cases where the endian-ness - is irrelevant, but the order of register operations is important. - For example when loading a value from memory into a register - pair, the endian-ness does not matter. Provided that the value - from the lower memory address is put into the lower numbered - register, and the value from the higher address is put into the - higher numbered register, the load will work regardless of whether - the value being loaded is big-wordian or little-wordian. The - order of the two register loads can matter however, if the address - of the memory location is actually held in one of the registers - being overwritten by the load. */ - case 'Q': - if (REGNO (x) > 15) - abort (); - fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], f); - return; - - case 'R': - if (REGNO (x) > 15) - abort (); - fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], f); - return; - - case 'H': - if (REGNO (x) > 15) - abort (); - fputs (reg_names[REGNO (x) + 1], f); - return; - - case 'c': - /* We use 'c' operands with symbols for .vtinherit */ - if (GET_CODE (x) == SYMBOL_REF) - output_addr_const(f, x); - return; - - default: - abort (); - } - } - if (GET_CODE (x) == REG) - fputs (reg_names[REGNO (x)], f); - else if (GET_CODE (x) == MEM) - output_address (XEXP (x, 0)); - else if (GET_CODE (x) == CONST_INT) - { - fputc ('#', f); - output_addr_const (f, x); - } - else - abort (); -} - -#ifdef AOF_ASSEMBLER -int arm_text_section_count = 1; - -char * -aof_text_section (in_readonly) - int in_readonly; -{ - static char buf[100]; - if (in_readonly) - return ""; - sprintf (buf, "\tCODE16\n\tAREA |C$$code%d|, CODE, READONLY", - arm_text_section_count++); - return buf; -} - -static int arm_data_section_count = 1; - -char * -aof_data_section () -{ - static char buf[100]; - sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++); - return buf; -} - -/* The AOF thumb assembler is religiously strict about declarations of - imported and exported symbols, so that it is impossible to declare a - function as imported near the begining of the file, and then to export - it later on. It is, however, possible to delay the decision until all - the functions in the file have been compiled. To get around this, we - maintain a list of the imports and exports, and delete from it any that - are subsequently defined. At the end of compilation we spit the - remainder of the list out before the END directive. */ - -struct import -{ - struct import *next; - char *name; -}; - -static struct import *imports_list = NULL; - -void -thumb_aof_add_import (name) - char *name; -{ - struct import *new; - - for (new = imports_list; new; new = new->next) - if (new->name == name) - return; - - new = (struct import *) xmalloc (sizeof (struct import)); - new->next = imports_list; - imports_list = new; - new->name = name; -} - -void -thumb_aof_delete_import (name) - char *name; -{ - struct import **old; - - for (old = &imports_list; *old; old = & (*old)->next) - { - if ((*old)->name == name) - { - *old = (*old)->next; - return; - } - } -} - -void -thumb_aof_dump_imports (f) - FILE *f; -{ - while (imports_list) - { - fprintf (f, "\tIMPORT\t"); - assemble_name (f, imports_list->name); - fputc ('\n', f); - imports_list = imports_list->next; - } -} -#endif - -/* Decide whether a type should be returned in memory (true) - or in a register (false). This is called by the macro - RETURN_IN_MEMORY. */ - -int -thumb_return_in_memory (type) - tree type; -{ - if (! AGGREGATE_TYPE_P (type)) - { - /* All simple types are returned in registers. */ - - return 0; - } - else if (int_size_in_bytes (type) > 4) - { - /* All structures/unions bigger than one word are returned in memory. */ - - return 1; - } - else if (TREE_CODE (type) == RECORD_TYPE) - { - tree field; - - /* For a struct the APCS says that we must return in a register if - every addressable element has an offset of zero. For practical - purposes this means that the structure can have at most one non- - bit-field element and that this element must be the first one in - the structure. */ - - /* Find the first field, ignoring non FIELD_DECL things which will - have been created by C++. */ - for (field = TYPE_FIELDS (type); - field && TREE_CODE (field) != FIELD_DECL; - field = TREE_CHAIN (field)) - continue; - - if (field == NULL) - return 0; /* An empty structure. Allowed by an extension to ANSI C. */ - - /* Now check the remaining fields, if any. */ - for (field = TREE_CHAIN (field); field; field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) != FIELD_DECL) - continue; - - if (! DECL_BIT_FIELD_TYPE (field)) - return 1; - } - - return 0; - } - else if (TREE_CODE (type) == UNION_TYPE) - { - tree field; - - /* Unions can be returned in registers if every element is - integral, or can be returned in an integer register. */ - - for (field = TYPE_FIELDS (type); - field; - field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) != FIELD_DECL) - continue; - - if (RETURN_IN_MEMORY (TREE_TYPE (field))) - return 1; - } - - return 0; - } - /* XXX Not sure what should be done for other aggregates, so put them in - memory. */ - return 1; -} - -void -thumb_override_options () -{ - if (structure_size_string != NULL) - { - int size = strtol (structure_size_string, NULL, 0); - - if (size == 8 || size == 32) - arm_structure_size_boundary = size; - else - warning ("Structure size boundary can only be set to 8 or 32"); - } - - if (flag_pic) - { - warning ("Position independent code not supported. Ignored"); - flag_pic = 0; - } -} - -/* CYGNUS LOCAL nickc/thumb-pe */ - -#ifdef THUMB_PE -/* Return nonzero if ATTR is a valid attribute for DECL. - ATTRIBUTES are any existing attributes and ARGS are the arguments - supplied with ATTR. - - Supported attributes: - - naked: don't output any prologue or epilogue code, the user is assumed - to do the right thing. - - interfacearm: Always assume that this function will be entered in ARM - mode, not Thumb mode, and that the caller wishes to be returned to in - ARM mode. */ -int -arm_valid_machine_decl_attribute (decl, attributes, attr, args) - tree decl; - tree attributes; - tree attr; - tree args; -{ - if (args != NULL_TREE) - return 0; - - if (is_attribute_p ("naked", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; - - if (is_attribute_p ("interfacearm", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; - - return 0; -} -#endif /* THUMB_PE */ -/* END CYGNUS LOCAL nickc/thumb-pe */ - -/* s_register_operand is the same as register_operand, but it doesn't accept - (SUBREG (MEM)...). - - This function exists because at the time it was put in it led to better - code. SUBREG(MEM) always needs a reload in the places where - s_register_operand is used, and this seemed to lead to excessive - reloading. */ - -int -s_register_operand (op, mode) - register rtx op; - enum machine_mode mode; -{ - if (GET_MODE (op) != mode && mode != VOIDmode) - return 0; - - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - - /* We don't consider registers whose class is NO_REGS - to be a register operand. */ - /* XXX might have to check for lo regs only for thumb ??? */ - return (GET_CODE (op) == REG - && (REGNO (op) >= FIRST_PSEUDO_REGISTER - || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); -} diff --git a/gcc/config/arm/thumb_020422.c b/gcc/config/arm/thumb_020422.c deleted file mode 100755 index cefc7d4..0000000 --- a/gcc/config/arm/thumb_020422.c +++ /dev/null @@ -1,2291 +0,0 @@ -/* Output routines for GCC for ARM/Thumb - Copyright (C) 1996 Cygnus Software Technologies Ltd - The basis of this contribution was generated by - Richard Earnshaw, Advanced RISC Machines Ltd - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -#include <stdio.h> -#include <string.h> -#include "config.h" -#include "rtl.h" -#include "hard-reg-set.h" -#include "regs.h" -#include "output.h" -#include "insn-flags.h" -#include "insn-attr.h" -#include "flags.h" -#include "tree.h" -#include "expr.h" - - -int current_function_anonymous_args = 0; -static int current_function_has_far_jump = 0; - -/* Used to parse -mstructure_size_boundary command line option. */ -char * structure_size_string = NULL; -int arm_structure_size_boundary = 32; /* Used to be 8 */ - - -/* Predicates */ -int -reload_memory_operand (op, mode) - rtx op; - enum machine_mode mode; -{ - int regno = true_regnum (op); - - return (! CONSTANT_P (op) - && (regno == -1 - || (GET_CODE (op) == REG - && REGNO (op) >= FIRST_PSEUDO_REGISTER))); -} - -/* Return nonzero if op is suitable for the RHS of a cmp instruction. */ -int -thumb_cmp_operand (op, mode) - rtx op; - enum machine_mode mode; -{ - return ((GET_CODE (op) == CONST_INT - && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256) - || register_operand (op, mode)); -} - -int -thumb_shiftable_const (val) - HOST_WIDE_INT val; -{ - unsigned HOST_WIDE_INT x = val; - unsigned HOST_WIDE_INT mask = 0xff; - int i; - - for (i = 0; i < 25; i++) - if ((val & (mask << i)) == val) - return 1; - - return 0; -} - -int -thumb_trivial_epilogue () -{ - int regno; - - /* ??? If this function ever returns 1, we get a function without any - epilogue at all. It appears that the intent was to cause a "return" - insn to be emitted, but that does not happen. */ - return 0; - -#if 0 - if (get_frame_size () - || current_function_outgoing_args_size - || current_function_pretend_args_size) - return 0; - - for (regno = 8; regno < 13; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - return 0; - - return 1; -#endif -} - - -/* Routines for handling the constant pool */ -/* This is unashamedly hacked from the version in sh.c, since the problem is - extremely similar. */ - -/* Thumb instructions cannot load a large constant into a register, - constants have to come from a pc relative load. The reference of a pc - relative load instruction must be less than 1k infront of the instruction. - This means that we often have to dump a constant inside a function, and - generate code to branch around it. - - It is important to minimize this, since the branches will slow things - down and make things bigger. - - Worst case code looks like: - - ldr rn, L1 - b L2 - align - L1: .long value - L2: - .. - - ldr rn, L3 - b L4 - align - L3: .long value - L4: - .. - - We fix this by performing a scan before scheduling, which notices which - instructions need to have their operands fetched from the constant table - and builds the table. - - - The algorithm is: - - scan, find an instruction which needs a pcrel move. Look forward, find the - last barrier which is within MAX_COUNT bytes of the requirement. - If there isn't one, make one. Process all the instructions between - the find and the barrier. - - In the above example, we can tell that L3 is within 1k of L1, so - the first move can be shrunk from the 2 insn+constant sequence into - just 1 insn, and the constant moved to L3 to make: - - ldr rn, L1 - .. - ldr rn, L3 - b L4 - align - L1: .long value - L3: .long value - L4: - - Then the second move becomes the target for the shortening process. - - */ - -typedef struct -{ - rtx value; /* Value in table */ - HOST_WIDE_INT next_offset; - enum machine_mode mode; /* Mode of value */ -} pool_node; - -/* The maximum number of constants that can fit into one pool, since - the pc relative range is 0...1020 bytes and constants are at least 4 - bytes long */ - -#define MAX_POOL_SIZE (1020/4) -static pool_node pool_vector[MAX_POOL_SIZE]; -static int pool_size; -static rtx pool_vector_label; - -/* Add a constant to the pool and return its label. */ - -static HOST_WIDE_INT -add_constant (x, mode) - rtx x; - enum machine_mode mode; -{ - int i; - rtx lab; - HOST_WIDE_INT offset; - - if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0)) - && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) - x = get_pool_constant (XEXP (x, 0)); - - /* First see if we've already got it */ - - for (i = 0; i < pool_size; i++) - { - if (x->code == pool_vector[i].value->code - && mode == pool_vector[i].mode) - { - if (x->code == CODE_LABEL) - { - if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) - continue; - } - if (rtx_equal_p (x, pool_vector[i].value)) - return pool_vector[i].next_offset - GET_MODE_SIZE (mode); - } - } - - /* Need a new one */ - - pool_vector[pool_size].next_offset = GET_MODE_SIZE (mode); - offset = 0; - if (pool_size == 0) - pool_vector_label = gen_label_rtx (); - else - pool_vector[pool_size].next_offset - += (offset = pool_vector[pool_size - 1].next_offset); - - pool_vector[pool_size].value = x; - pool_vector[pool_size].mode = mode; - pool_size++; - return offset; -} - -/* Output the literal table */ - -static void -dump_table (scan) - rtx scan; -{ - int i; - - scan = emit_label_after (gen_label_rtx (), scan); - scan = emit_insn_after (gen_align_4 (), scan); - scan = emit_label_after (pool_vector_label, scan); - - for (i = 0; i < pool_size; i++) - { - pool_node *p = pool_vector + i; - - switch (GET_MODE_SIZE (p->mode)) - { - case 4: - scan = emit_insn_after (gen_consttable_4 (p->value), scan); - break; - - case 8: - scan = emit_insn_after (gen_consttable_8 (p->value), scan); - break; - - default: - abort (); - break; - } - } - - scan = emit_insn_after (gen_consttable_end (), scan); - scan = emit_barrier_after (scan); - pool_size = 0; -} - -/* Non zero if the src operand needs to be fixed up */ -static -int -fixit (src, mode) - rtx src; - enum machine_mode mode; -{ - return ((CONSTANT_P (src) - && (GET_CODE (src) != CONST_INT - || ! (CONST_OK_FOR_LETTER_P (INTVAL (src), 'I') - || CONST_OK_FOR_LETTER_P (INTVAL (src), 'J') - || (mode != DImode - && CONST_OK_FOR_LETTER_P (INTVAL (src), 'K'))))) - || (mode == SImode && GET_CODE (src) == MEM - && GET_CODE (XEXP (src, 0)) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (XEXP (src, 0)))); -} - -/* Find the last barrier less than MAX_COUNT bytes from FROM, or create one. */ - -#define MAX_COUNT_SI 1000 - -static rtx -find_barrier (from) - rtx from; -{ - int count = 0; - rtx found_barrier = 0; - rtx label; - - while (from && count < MAX_COUNT_SI) - { - if (GET_CODE (from) == BARRIER) - return from; - - /* Count the length of this insn */ - if (GET_CODE (from) == INSN - && GET_CODE (PATTERN (from)) == SET - && CONSTANT_P (SET_SRC (PATTERN (from))) - && CONSTANT_POOL_ADDRESS_P (SET_SRC (PATTERN (from)))) - { - rtx src = SET_SRC (PATTERN (from)); - count += 2; - } - else - count += get_attr_length (from); - - from = NEXT_INSN (from); - } - - /* We didn't find a barrier in time to - dump our stuff, so we'll make one */ - label = gen_label_rtx (); - - if (from) - from = PREV_INSN (from); - else - from = get_last_insn (); - - /* Walk back to be just before any jump */ - while (GET_CODE (from) == JUMP_INSN - || GET_CODE (from) == NOTE - || GET_CODE (from) == CODE_LABEL) - from = PREV_INSN (from); - - from = emit_jump_insn_after (gen_jump (label), from); - JUMP_LABEL (from) = label; - found_barrier = emit_barrier_after (from); - emit_label_after (label, found_barrier); - return found_barrier; -} - -/* Non zero if the insn is a move instruction which needs to be fixed. */ - -static int -broken_move (insn) - rtx insn; -{ - if (!INSN_DELETED_P (insn) - && GET_CODE (insn) == INSN - && GET_CODE (PATTERN (insn)) == SET) - { - rtx pat = PATTERN (insn); - rtx src = SET_SRC (pat); - rtx dst = SET_DEST (pat); - enum machine_mode mode = GET_MODE (dst); - if (dst == pc_rtx) - return 0; - return fixit (src, mode); - } - return 0; -} - -/* Recursively search through all of the blocks in a function - checking to see if any of the variables created in that - function match the RTX called 'orig'. If they do then - replace them with the RTX called 'new'. */ - -static void -replace_symbols_in_block (tree block, rtx orig, rtx new) -{ - for (; block; block = BLOCK_CHAIN (block)) - { - tree sym; - - if (! TREE_USED (block)) - continue; - - for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym)) - { - if ( (DECL_NAME (sym) == 0 && TREE_CODE (sym) != TYPE_DECL) - || DECL_IGNORED_P (sym) - || TREE_CODE (sym) != VAR_DECL - || DECL_EXTERNAL (sym) - || ! rtx_equal_p (DECL_RTL (sym), orig) - ) - continue; - - DECL_RTL (sym) = new; - } - - replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new); - } -} - -void -thumb_reorg (first) - rtx first; -{ - rtx insn; - for (insn = first; insn; insn = NEXT_INSN (insn)) - { - if (broken_move (insn)) - { - /* This is a broken move instruction, scan ahead looking for - a barrier to stick the constant table behind */ - rtx scan; - rtx barrier = find_barrier (insn); - - /* Now find all the moves between the points and modify them */ - for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) - { - if (broken_move (scan)) - { - /* This is a broken move instruction, add it to the pool */ - rtx pat = PATTERN (scan); - rtx src = SET_SRC (pat); - rtx dst = SET_DEST (pat); - enum machine_mode mode = GET_MODE (dst); - HOST_WIDE_INT offset; - rtx newinsn; - rtx newsrc; - - /* If this is an HImode constant load, convert it into - an SImode constant load. Since the register is always - 32 bits this is safe. We have to do this, since the - load pc-relative instruction only does a 32-bit load. */ - if (mode == HImode) - { - mode = SImode; - if (GET_CODE (dst) != REG) - abort (); - PUT_MODE (dst, SImode); - } - - offset = add_constant (src, mode); - newsrc = gen_rtx (MEM, mode, - plus_constant (gen_rtx (LABEL_REF, - VOIDmode, - pool_vector_label), - offset)); - - /* Build a jump insn wrapper around the move instead - of an ordinary insn, because we want to have room for - the target label rtx in fld[7], which an ordinary - insn doesn't have. */ - newinsn = emit_jump_insn_after (gen_rtx (SET, VOIDmode, - dst, newsrc), scan); - JUMP_LABEL (newinsn) = pool_vector_label; - - /* But it's still an ordinary insn */ - PUT_CODE (newinsn, INSN); - - /* If debugging information is going to be emitted - then we must make sure that any refences to - symbols which are removed by the above code are - also removed in the descriptions of the - function's variables. Failure to do this means - that the debugging information emitted could - refer to symbols which are not emited by - output_constant_pool() because - mark_constant_pool() never sees them as being - used. */ - - - /* These are the tests used in - output_constant_pool() to decide if the constant - pool will be marked. Only necessary if debugging - info is being emitted. Only necessary for - references to memory whose address is given by a - symbol. */ - - if (optimize > 0 - && flag_expensive_optimizations - && write_symbols != NO_DEBUG - && GET_CODE (src) == MEM - && GET_CODE (XEXP (src, 0)) == SYMBOL_REF) - replace_symbols_in_block - (DECL_INITIAL (current_function_decl), src, newsrc); - - /* Kill old insn */ - delete_insn (scan); - scan = newinsn; - } - } - dump_table (barrier); - } - } -} - - -/* Routines for generating rtl */ - -void -thumb_expand_movstrqi (operands) - rtx *operands; -{ - rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); - rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); - HOST_WIDE_INT len = INTVAL (operands[2]); - HOST_WIDE_INT offset = 0; - - while (len >= 12) - { - emit_insn (gen_movmem12b (out, in)); - len -= 12; - } - if (len >= 8) - { - emit_insn (gen_movmem8b (out, in)); - len -= 8; - } - if (len >= 4) - { - rtx reg = gen_reg_rtx (SImode); - emit_insn (gen_movsi (reg, gen_rtx (MEM, SImode, in))); - emit_insn (gen_movsi (gen_rtx (MEM, SImode, out), reg)); - len -= 4; - offset += 4; - } - if (len >= 2) - { - rtx reg = gen_reg_rtx (HImode); - emit_insn (gen_movhi (reg, gen_rtx (MEM, HImode, - plus_constant (in, offset)))); - emit_insn (gen_movhi (gen_rtx (MEM, HImode, plus_constant (out, offset)), - reg)); - len -= 2; - offset += 2; - } - if (len) - { - rtx reg = gen_reg_rtx (QImode); - emit_insn (gen_movqi (reg, gen_rtx (MEM, QImode, - plus_constant (in, offset)))); - emit_insn (gen_movqi (gen_rtx (MEM, QImode, plus_constant (out, offset)), - reg)); - } -} - - -/* Routines for reloading */ - -void -thumb_reload_out_si (operands) - rtx operands; -{ - abort (); -} - -/* CYGNUS LOCAL nickc/thumb-pe */ - -#ifdef THUMB_PE -/* Return non-zero if FUNC is a naked function. */ - -static int -arm_naked_function_p (func) - tree func; -{ - tree a; - - if (TREE_CODE (func) != FUNCTION_DECL) - abort (); - - a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func)); - return a != NULL_TREE; -} -#endif -/* END CYGNUS LOCAL nickc/thumb-pe */ - -/* Return non-zero if FUNC must be entered in ARM mode. */ -int -is_called_in_ARM_mode (func) - tree func; -{ - if (TREE_CODE (func) != FUNCTION_DECL) - abort (); - - /* Ignore the problem about functions whoes address is taken. */ - if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func)) - return TRUE; - -/* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE; -#else - return FALSE; -#endif -/* END CYGNUS LOCAL */ -} - - -/* Routines for emitting code */ - -void -final_prescan_insn(insn) - rtx insn; -{ - extern int *insn_addresses; - - if (flag_print_asm_name) - fprintf (asm_out_file, "%s 0x%04x\n", ASM_COMMENT_START, - insn_addresses[INSN_UID (insn)]); -} - - -static void thumb_pushpop ( FILE *, int, int ); /* Forward declaration. */ - -#ifdef __GNUC__ -inline -#endif -static int -number_of_first_bit_set (mask) - int mask; -{ - int bit; - - for (bit = 0; - (mask & (1 << bit)) == 0; - ++ bit) - continue; - - return bit; -} - -#define ARG_1_REGISTER 0 -#define ARG_2_REGISTER 1 -#define ARG_3_REGISTER 2 -#define ARG_4_REGISTER 3 -#define WORK_REGISTER 7 -#define FRAME_POINTER 11 -#define IP_REGISTER 12 -#define STACK_POINTER STACK_POINTER_REGNUM -#define LINK_REGISTER 14 -#define PROGRAM_COUNTER 15 - -/* Generate code to return from a thumb function. If - 'reg_containing_return_addr' is -1, then the return address is - actually on the stack, at the stack pointer. */ -static void -thumb_exit (f, reg_containing_return_addr) - FILE * f; - int reg_containing_return_addr; -{ - int regs_available_for_popping; - int regs_to_pop; - int pops_needed; - int reg; - int available; - int required; - int mode; - int size; - int restore_a4 = FALSE; - - /* Compute the registers we need to pop. */ - regs_to_pop = 0; - pops_needed = 0; - - if (reg_containing_return_addr == -1) - { - regs_to_pop |= 1 << LINK_REGISTER; - ++ pops_needed; - } - - if (TARGET_BACKTRACE) - { - /* Restore frame pointer and stack pointer. */ - regs_to_pop |= (1 << FRAME_POINTER) | (1 << STACK_POINTER); - pops_needed += 2; - } - - /* If there is nothing to pop then just emit the BX instruction and return.*/ - if (pops_needed == 0) - { - asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); - - return; - } - - /* Otherwise if we are not supporting interworking and we have not created - a backtrace structure and the function was not entered in ARM mode then - just pop the return address straight into the PC. */ - else if ( ! TARGET_THUMB_INTERWORK - && ! TARGET_BACKTRACE - && ! is_called_in_ARM_mode (current_function_decl)) - { - asm_fprintf (f, "\tpop\t{pc}\n" ); - - return; - } - - /* Find out how many of the (return) argument registers we can corrupt. */ - regs_available_for_popping = 0; - -#ifdef RTX_CODE - /* If we can deduce the registers used from the function's return value. - This is more reliable that examining regs_ever_live[] because that - will be set if the register is ever used in the function, not just if - the register is used to hold a return value. */ - - if (current_function_return_rtx != 0) - mode = GET_MODE (current_function_return_rtx); - else -#endif - mode = DECL_MODE (DECL_RESULT (current_function_decl)); - - size = GET_MODE_SIZE (mode); - - if (size == 0) - { - /* In a void function we can use any argument register. - In a function that returns a structure on the stack - we can use the second and third argument registers. */ - if (mode == VOIDmode) - regs_available_for_popping = - (1 << ARG_1_REGISTER) - | (1 << ARG_2_REGISTER) - | (1 << ARG_3_REGISTER); - else - regs_available_for_popping = - (1 << ARG_2_REGISTER) - | (1 << ARG_3_REGISTER); - } - else if (size <= 4) regs_available_for_popping = - (1 << ARG_2_REGISTER) - | (1 << ARG_3_REGISTER); - else if (size <= 8) regs_available_for_popping = - (1 << ARG_3_REGISTER); - - /* Match registers to be popped with registers into which we pop them. */ - for (available = regs_available_for_popping, - required = regs_to_pop; - required != 0 && available != 0; - available &= ~(available & - available), - required &= ~(required & - required)) - -- pops_needed; - - /* If we have any popping registers left over, remove them. */ - if (available > 0) - regs_available_for_popping &= ~ available; - - /* Otherwise if we need another popping register we can use - the fourth argument register. */ - else if (pops_needed) - { - /* If we have not found any free argument registers and - reg a4 contains the return address, we must move it. */ - if (regs_available_for_popping == 0 - && reg_containing_return_addr == ARG_4_REGISTER) - { - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); - reg_containing_return_addr = LINK_REGISTER; - } - else if (size > 12) - { - /* Register a4 is being used to hold part of the return value, - but we have dire need of a free, low register. */ - restore_a4 = TRUE; - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [IP_REGISTER], reg_names [ARG_4_REGISTER]); - } - - if (reg_containing_return_addr != ARG_4_REGISTER) - { - /* The fourth argument register is available. */ - regs_available_for_popping |= 1 << ARG_4_REGISTER; - - -- pops_needed; - } - } - - /* Pop as many registers as we can. */ - thumb_pushpop (f, regs_available_for_popping, FALSE); - - /* Process the registers we popped. */ - if (reg_containing_return_addr == -1) - { - /* The return address was popped into the lowest numbered register. */ - regs_to_pop &= ~ (1 << LINK_REGISTER); - - reg_containing_return_addr = - number_of_first_bit_set (regs_available_for_popping); - - /* Remove this register for the mask of available registers, so that - the return address will not be corrupted by futher pops. */ - regs_available_for_popping &= ~ (1 << reg_containing_return_addr); - } - - /* If we popped other registers then handle them here. */ - if (regs_available_for_popping) - { - int frame_pointer; - - /* Work out which register currently contains the frame pointer. */ - frame_pointer = number_of_first_bit_set (regs_available_for_popping); - - /* Move it into the correct place. */ - asm_fprintf (f, "\tmov\tfp, %s\n", reg_names [frame_pointer]); - - /* (Temporarily) remove it from the mask of popped registers. */ - regs_available_for_popping &= ~ (1 << frame_pointer); - regs_to_pop &= ~ (1 << FRAME_POINTER); - - if (regs_available_for_popping) - { - int stack_pointer; - - /* We popped the stack pointer as well, find the register that - contains it.*/ - stack_pointer = number_of_first_bit_set (regs_available_for_popping); - - /* Move it into the stack register. */ - asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [stack_pointer]); - - /* At this point we have popped all necessary registers, so - do not worry about restoring regs_available_for_popping - to its correct value: - - assert (pops_needed == 0) - assert (regs_available_for_popping == (1 << frame_pointer)) - assert (regs_to_pop == (1 << STACK_POINTER)) */ - } - else - { - /* Since we have just move the popped value into the frame - pointer, the popping register is available for reuse, and - we know that we still have the stack pointer left to pop. */ - regs_available_for_popping |= (1 << frame_pointer); - } - } - - /* If we still have registers left on the stack, but we no longer have - any registers into which we can pop them, then we must move the return - address into the link register and make available the register that - contained it. */ - if (regs_available_for_popping == 0 && pops_needed > 0) - { - regs_available_for_popping |= 1 << reg_containing_return_addr; - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [LINK_REGISTER], - reg_names [reg_containing_return_addr]); - - reg_containing_return_addr = LINK_REGISTER; - } - - /* If we have registers left on the stack then pop some more. - We know that at most we will want to pop FP and SP. */ - if (pops_needed > 0) - { - int popped_into; - int move_to; - - thumb_pushpop (f, regs_available_for_popping, FALSE); - - /* We have popped either FP or SP. - Move whichever one it is into the correct register. */ - popped_into = number_of_first_bit_set (regs_available_for_popping); - move_to = number_of_first_bit_set (regs_to_pop); - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [move_to], reg_names [popped_into]); - - regs_to_pop &= ~ (1 << move_to); - - -- pops_needed; - } - - /* If we still have not popped everything then we must have only - had one register available to us and we are now popping the SP. */ - if (pops_needed > 0) - { - int popped_into; - - thumb_pushpop (f, regs_available_for_popping, FALSE); - - popped_into = number_of_first_bit_set (regs_available_for_popping); - - asm_fprintf (f, "\tmov\tsp, %s\n", reg_names [popped_into]); - - /* - assert (regs_to_pop == (1 << STACK_POINTER)) - assert (pops_needed == 1) - */ - } - - /* If necessary restore the a4 register. */ - if (restore_a4) - { - if (reg_containing_return_addr != LINK_REGISTER) - { - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [LINK_REGISTER], reg_names [ARG_4_REGISTER]); - reg_containing_return_addr = LINK_REGISTER; - } - - asm_fprintf (f, "\tmov\t%s, %s\n", - reg_names [ARG_4_REGISTER], reg_names [IP_REGISTER]); - } - - /* Return to caller. */ - asm_fprintf (f, "\tbx\t%s\n", reg_names [reg_containing_return_addr]); -} - -/* Emit code to push or pop registers to or from the stack. */ -static void -thumb_pushpop (f, mask, push) - FILE * f; - int mask; - int push; -{ - int regno; - int lo_mask = mask & 0xFF; - - if (lo_mask == 0 && ! push && (mask & (1 << 15))) - { - /* Special case. Do not generate a POP PC statement here, do it in - thumb_exit() */ - - thumb_exit (f, -1); - return; - } - - asm_fprintf (f, "\t%s\t{", push ? "push" : "pop"); - - /* Look at the low registers first. */ - - for (regno = 0; regno < 8; regno ++, lo_mask >>= 1) - { - if (lo_mask & 1) - { - asm_fprintf (f, reg_names[regno]); - - if ((lo_mask & ~1) != 0) - asm_fprintf (f, ", "); - } - } - - if (push && (mask & (1 << 14))) - { - /* Catch pushing the LR. */ - - if (mask & 0xFF) - asm_fprintf (f, ", "); - - asm_fprintf (f, reg_names[14]); - } - else if (!push && (mask & (1 << 15))) - { - /* Catch popping the PC. */ - - if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) - { - /* The PC is never poped directly, instead - it is popped into r3 and then BX is used. */ - - asm_fprintf (f, "}\n"); - - thumb_exit (f, -1); - - return; - } - else - { - if (mask & 0xFF) - asm_fprintf (f, ", "); - - asm_fprintf (f, reg_names[15]); - } - } - - asm_fprintf (f, "}\n"); -} - -/* Returns non-zero if the current function contains a far jump */ - -int -far_jump_used_p (void) -{ - rtx insn; - - if (current_function_has_far_jump) - return 1; - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (GET_CODE (insn) == JUMP_INSN - /* Ignore tablejump patterns. */ - && GET_CODE (PATTERN (insn)) != ADDR_VEC - && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC - && get_attr_far_jump (insn) == FAR_JUMP_YES) - { - current_function_has_far_jump = 1; - return 1; - } - } - - return 0; -} - -static int return_used_this_function = 0; - -char * -output_return () -{ - int regno; - int live_regs_mask = 0; - - /* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - /* If a function is naked, don't use the "return" insn. */ - if (arm_naked_function_p (current_function_decl)) - return ""; -#endif - /* END CYGNUS LOCAL nickc/thumb-pe */ - - return_used_this_function = 1; - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - if (live_regs_mask == 0) - { - if (leaf_function_p () && ! far_jump_used_p()) - { - thumb_exit (asm_out_file, 14); - } - else if ( TARGET_THUMB_INTERWORK - || TARGET_BACKTRACE - || is_called_in_ARM_mode (current_function_decl)) - { - thumb_exit (asm_out_file, -1); - } - else - asm_fprintf (asm_out_file, "\tpop\t{pc}\n"); - } - else - { - asm_fprintf (asm_out_file, "\tpop\t{"); - - for (regno = 0; live_regs_mask; regno ++, live_regs_mask >>= 1) - if (live_regs_mask & 1) - { - asm_fprintf (asm_out_file, reg_names[regno]); - if (live_regs_mask & ~1) - asm_fprintf (asm_out_file, ", "); - } - - if ( TARGET_THUMB_INTERWORK - || TARGET_BACKTRACE - || is_called_in_ARM_mode (current_function_decl)) - { - asm_fprintf (asm_out_file, "}\n"); - thumb_exit (asm_out_file, -1); - } - else - asm_fprintf (asm_out_file, ", pc}\n"); - } - - return ""; -} - -void -thumb_function_prologue (f, frame_size) - FILE *f; - int frame_size; -{ - int amount = frame_size + current_function_outgoing_args_size; - int live_regs_mask = 0; - int high_regs_pushed = 0; - int store_arg_regs = 0; - int regno; - -/* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - if (arm_naked_function_p (current_function_decl)) - return; -#endif -/* CYGNUS LOCAL nickc/thumb-pe */ - - if (is_called_in_ARM_mode (current_function_decl)) - { - char * name; - if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) - abort(); - if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) - abort(); - name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); - - /* Generate code sequence to switch us into Thumb mode. */ - /* The .code 32 directive has already been emitted by - ASM_DECLARE_FUNCITON_NAME */ - asm_fprintf (f, "\torr\tr12, pc, #1\n"); - asm_fprintf (f, "\tbx\tr12\n"); - - /* Generate a label, so that the debugger will notice the - change in instruction sets. This label is also used by - the assembler to bypass the ARM code when this function - is called from a Thumb encoded function elsewhere in the - same file. Hence the definition of STUB_NAME here must - agree with the definition in gas/config/tc-arm.c */ - -#define STUB_NAME ".real_start_of" - - asm_fprintf (f, "\t.code\t16\n"); - asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); - asm_fprintf (f, "\t.thumb_func\n"); - asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); - } - - if (current_function_anonymous_args && current_function_pretend_args_size) - store_arg_regs = 1; - - if (current_function_pretend_args_size) - { - if (store_arg_regs) - { - asm_fprintf (f, "\tpush\t{"); - for (regno = 4 - current_function_pretend_args_size / 4 ; regno < 4; - regno++) - asm_fprintf (f, "%s%s", reg_names[regno], regno == 3 ? "" : ", "); - asm_fprintf (f, "}\n"); - } - else - asm_fprintf (f, "\tsub\t%Rsp, %Rsp, #%d\n", - current_function_pretend_args_size); - } - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - if (live_regs_mask || ! leaf_function_p () || far_jump_used_p()) - live_regs_mask |= 1 << 14; - - if (TARGET_BACKTRACE) - { - char * name; - int offset; - int work_register = 0; - - - /* We have been asked to create a stack backtrace structure. - The code looks like this: - - 0 .align 2 - 0 func: - 0 sub SP, #16 Reserve space for 4 registers. - 2 push {R7} Get a work register. - 4 add R7, SP, #20 Get the stack pointer before the push. - 6 str R7, [SP, #8] Store the stack pointer (before reserving the space). - 8 mov R7, PC Get hold of the start of this code plus 12. - 10 str R7, [SP, #16] Store it. - 12 mov R7, FP Get hold of the current frame pointer. - 14 str R7, [SP, #4] Store it. - 16 mov R7, LR Get hold of the current return address. - 18 str R7, [SP, #12] Store it. - 20 add R7, SP, #16 Point at the start of the backtrace structure. - 22 mov FP, R7 Put this value into the frame pointer. */ - - if ((live_regs_mask & 0xFF) == 0) - { - /* See if the a4 register is free. */ - - if (regs_ever_live[ 3 ] == 0) - work_register = 3; - else /* We must push a register of our own */ - live_regs_mask |= (1 << 7); - } - - if (work_register == 0) - { - /* Select a register from the list that will be pushed to use as our work register. */ - - for (work_register = 8; work_register--;) - if ((1 << work_register) & live_regs_mask) - break; - } - - name = reg_names[ work_register ]; - - asm_fprintf (f, "\tsub\tsp, sp, #16\t@ Create stack backtrace structure\n"); - - if (live_regs_mask) - thumb_pushpop (f, live_regs_mask, 1); - - for (offset = 0, work_register = 1 << 15; work_register; work_register >>= 1) - if (work_register & live_regs_mask) - offset += 4; - - asm_fprintf (f, "\tadd\t%s, sp, #%d\n", - name, offset + 16 + current_function_pretend_args_size); - - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 4); - - /* Make sure that the instruction fetching the PC is in the right place - to calculate "start of backtrace creation code + 12". */ - - if (live_regs_mask) - { - asm_fprintf (f, "\tmov\t%s, pc\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); - asm_fprintf (f, "\tmov\t%s, fp\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); - } - else - { - asm_fprintf (f, "\tmov\t%s, fp\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); - asm_fprintf (f, "\tmov\t%s, pc\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); - } - - asm_fprintf (f, "\tmov\t%s, lr\n", name); - asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 8); - asm_fprintf (f, "\tadd\t%s, sp, #%d\n", name, offset + 12); - asm_fprintf (f, "\tmov\tfp, %s\t\t@ Backtrace structure created\n", name); - } - else if (live_regs_mask) - thumb_pushpop (f, live_regs_mask, 1); - - for (regno = 8; regno < 13; regno++) - { - if (regs_ever_live[regno] && ! call_used_regs[regno]) - high_regs_pushed++; - } - - if (high_regs_pushed) - { - int pushable_regs = 0; - int mask = live_regs_mask & 0xff; - int next_hi_reg; - - for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--) - { - if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) - break; - } - - pushable_regs = mask; - - if (pushable_regs == 0) - { - /* desperation time -- this probably will never happen */ - if (regs_ever_live[3] || ! call_used_regs[3]) - asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[12], reg_names[3]); - mask = 1 << 3; - } - - while (high_regs_pushed > 0) - { - for (regno = 7; regno >= 0; regno--) - { - if (mask & (1 << regno)) - { - asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[regno], - reg_names[next_hi_reg]); - high_regs_pushed--; - if (high_regs_pushed) - for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--) - { - if (regs_ever_live[next_hi_reg] - && ! call_used_regs[next_hi_reg]) - break; - } - else - { - mask &= ~ ((1 << regno) - 1); - break; - } - } - } - thumb_pushpop (f, mask, 1); - } - - if (pushable_regs == 0 && (regs_ever_live[3] || ! call_used_regs[3])) - asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[3], reg_names[12]); - } -} - -void -thumb_expand_prologue () -{ - HOST_WIDE_INT amount = (get_frame_size () - + current_function_outgoing_args_size); - int regno; - int live_regs_mask; - - /* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - /* Naked functions don't have prologues. */ - if (arm_naked_function_p (current_function_decl)) - return; -#endif - /* END CYGNUS LOCAL nickc/thumb-pe */ - - if (amount) - { - live_regs_mask = 0; - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - if (amount < 512) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (-amount))); - else - { - rtx reg, spare; - - if ((live_regs_mask & 0xff) == 0) /* Very unlikely */ - emit_insn (gen_movsi (spare = gen_rtx (REG, SImode, 12), - reg = gen_rtx (REG, SImode, 4))); - else - { - for (regno = 0; regno < 8; regno++) - if (live_regs_mask & (1 << regno)) - break; - reg = gen_rtx (REG, SImode, regno); - } - - emit_insn (gen_movsi (reg, GEN_INT (-amount))); - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); - if ((live_regs_mask & 0xff) == 0) - emit_insn (gen_movsi (reg, spare)); - } - } - - if (frame_pointer_needed) - { - if (current_function_outgoing_args_size) - { - rtx offset = GEN_INT (current_function_outgoing_args_size); - - if (current_function_outgoing_args_size < 1024) - emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, - offset)); - else - { - emit_insn (gen_movsi (frame_pointer_rtx, offset)); - emit_insn (gen_addsi3 (frame_pointer_rtx, frame_pointer_rtx, - stack_pointer_rtx)); - } - } - else - emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); - } - - /* if (profile_flag || profile_block_flag) */ - emit_insn (gen_blockage ()); -} - -void -thumb_expand_epilogue () -{ - HOST_WIDE_INT amount = (get_frame_size () - + current_function_outgoing_args_size); - int regno; - - /* CYGNUS LOCAL nickc/thumb-pe */ -#ifdef THUMB_PE - /* Naked functions don't have epilogues. */ - if (arm_naked_function_p (current_function_decl)) - return; -#endif - /* END CYGNUS LOCAL nickc/thumb-pe */ - - if (amount) - { - if (amount < 512) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (amount))); - else - { - rtx reg = gen_rtx (REG, SImode, 3); /* Always free in the epilogue */ - - emit_insn (gen_movsi (reg, GEN_INT (amount))); - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); - } - /* if (profile_flag || profile_block_flag) */ - emit_insn (gen_blockage ()); - } -} - -void -thumb_function_epilogue (f, frame_size) - FILE *f; - int frame_size; -{ - /* ??? Probably not safe to set this here, since it assumes that a - function will be emitted as assembly immediately after we generate - RTL for it. This does not happen for inline functions. */ - return_used_this_function = 0; - current_function_has_far_jump = 0; -#if 0 /* TODO : comment not really needed */ - fprintf (f, "%s THUMB Epilogue\n", ASM_COMMENT_START); -#endif -} - -/* The bits which aren't usefully expanded as rtl. */ -char * -thumb_unexpanded_epilogue () -{ - int regno; - int live_regs_mask = 0; - int high_regs_pushed = 0; - int leaf_function = leaf_function_p (); - int had_to_push_lr; - - if (return_used_this_function) - return ""; - - for (regno = 0; regno < 8; regno++) - if (regs_ever_live[regno] && ! call_used_regs[regno]) - live_regs_mask |= 1 << regno; - - for (regno = 8; regno < 13; regno++) - { - if (regs_ever_live[regno] && ! call_used_regs[regno]) - high_regs_pushed ++; - } - - /* The prolog may have pushed some high registers to use as - work registers. eg the testuite file: - gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c - compiles to produce: - push {r4, r5, r6, r7, lr} - mov r7, r9 - mov r6, r8 - push {r6, r7} - as part of the prolog. We have to undo that pushing here. */ - - if (high_regs_pushed) - { - int mask = live_regs_mask; - int next_hi_reg; - int size; - int mode; - -#ifdef RTX_CODE - /* If we can deduce the registers used from the function's return value. - This is more reliable that examining regs_ever_live[] because that - will be set if the register is ever used in the function, not just if - the register is used to hold a return value. */ - - if (current_function_return_rtx != 0) - { - mode = GET_MODE (current_function_return_rtx); - } - else -#endif - { - mode = DECL_MODE (DECL_RESULT (current_function_decl)); - } - - size = GET_MODE_SIZE (mode); - - /* Unless we are returning a type of size > 12 register r3 is available. */ - if (size < 13) - mask |= 1 << 3; - - if (mask == 0) - { - /* Oh dear! We have no low registers into which we can pop high registers! */ - - fatal ("No low registers available for popping high registers"); - } - - for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++) - if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) - break; - - while (high_regs_pushed) - { - /* Find low register(s) into which the high register(s) can be popped. */ - for (regno = 0; regno < 8; regno++) - { - if (mask & (1 << regno)) - high_regs_pushed--; - if (high_regs_pushed == 0) - break; - } - - mask &= (2 << regno) - 1; /* A noop if regno == 8 */ - - /* Pop the values into the low register(s). */ - thumb_pushpop (asm_out_file, mask, 0); - - /* Move the value(s) into the high registers. */ - for (regno = 0; regno < 8; regno++) - { - if (mask & (1 << regno)) - { - asm_fprintf (asm_out_file, "\tmov\t%s, %s\n", - reg_names[next_hi_reg], reg_names[regno]); - for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++) - if (regs_ever_live[next_hi_reg] && - ! call_used_regs[next_hi_reg]) - break; - } - } - } - } - - had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); - - if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) - { - /* The stack backtrace structure creation code had to - push R7 in order to get a work register, so we pop - it now. */ - - live_regs_mask |= (1 << WORK_REGISTER); - } - - if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) - { - if (had_to_push_lr - && ! is_called_in_ARM_mode (current_function_decl)) - live_regs_mask |= 1 << PROGRAM_COUNTER; - - /* Either no argument registers were pushed or a backtrace - structure was created which includes an adjusted stack - pointer, so just pop everything. */ - - if (live_regs_mask) - thumb_pushpop (asm_out_file, live_regs_mask, FALSE); - - /* We have either just popped the return address into the - PC or it is was kept in LR for the entire function or - it is still on the stack because we do not want to - return by doing a pop {pc}. */ - - if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0) - thumb_exit (asm_out_file, - (had_to_push_lr - && is_called_in_ARM_mode (current_function_decl)) ? - -1 : LINK_REGISTER); - } - else - { - /* Pop everything but the return address. */ - live_regs_mask &= ~ (1 << PROGRAM_COUNTER); - - if (live_regs_mask) - thumb_pushpop (asm_out_file, live_regs_mask, FALSE); - - if (had_to_push_lr) - { - /* Get the return address into a temporary register. */ - thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0); - } - - /* Remove the argument registers that were pushed onto the stack. */ - asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n", - reg_names [STACK_POINTER], - reg_names [STACK_POINTER], - current_function_pretend_args_size); - - thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER); - } - - return ""; -} - -/* Handle the case of a double word load into a low register from - a computed memory address. The computed address may involve a - register which is overwritten by the load. */ - -char * -thumb_load_double_from_address (operands) - rtx * operands; -{ - rtx addr; - rtx base; - rtx offset; - rtx arg1; - rtx arg2; - - if (GET_CODE (operands[0]) != REG) - fatal ("thumb_load_double_from_address: destination is not a register"); - - if (GET_CODE (operands[1]) != MEM) - fatal ("thumb_load_double_from_address: source is not a computed memory address"); - - /* Get the memory address. */ - - addr = XEXP (operands[1], 0); - - /* Work out how the memory address is computed. */ - - switch (GET_CODE (addr)) - { - case REG: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - if (REGNO (operands[0]) == REGNO (addr)) - { - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - } - else - { - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - } - break; - - case CONST: - /* Compute <address> + 4 for the high order load. */ - - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - break; - - case PLUS: - arg1 = XEXP (addr, 0); - arg2 = XEXP (addr, 1); - - if (CONSTANT_P (arg1)) - base = arg2, offset = arg1; - else - base = arg1, offset = arg2; - - if (GET_CODE (base) != REG) - fatal ("thumb_load_double_from_address: base is not a register"); - - /* Catch the case of <address> = <reg> + <reg> */ - - if (GET_CODE (offset) == REG) - { - int reg_offset = REGNO (offset); - int reg_base = REGNO (base); - int reg_dest = REGNO (operands[0]); - - /* Add the base and offset registers together into the higher destination register. */ - - fprintf (asm_out_file, "\tadd\t%s, %s, %s\t\t%s created by thumb_load_double_from_address", - reg_names[ reg_dest + 1 ], - reg_names[ reg_base ], - reg_names[ reg_offset ], - ASM_COMMENT_START); - - /* Load the lower destination register from the address in the higher destination register. */ - - fprintf (asm_out_file, "\tldr\t%s, [%s, #0]\t\t%s created by thumb_load_double_from_address", - reg_names[ reg_dest ], - reg_names[ reg_dest + 1], - ASM_COMMENT_START); - - /* Load the higher destination register from its own address plus 4. */ - - fprintf (asm_out_file, "\tldr\t%s, [%s, #4]\t\t%s created by thumb_load_double_from_address", - reg_names[ reg_dest + 1 ], - reg_names[ reg_dest + 1 ], - ASM_COMMENT_START); - } - else - { - /* Compute <address> + 4 for the high order load. */ - - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - /* If the computed address is held in the low order register - then load the high order register first, otherwise always - load the low order register first. */ - - if (REGNO (operands[0]) == REGNO (base)) - { - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - } - else - { - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - } - } - break; - - case LABEL_REF: - /* With no registers to worry about we can just load the value directly. */ - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 4)); - - output_asm_insn ("ldr\t%H0, %2\t\t%@ created by thumb_load_double_from_address", operands); - output_asm_insn ("ldr\t%0, %1\t\t%@ created by thumb_load_double_from_address", operands); - break; - - default: - debug_rtx (operands[1]); - fatal ("thumb_load_double_from_address: Unhandled address calculation"); - break; - } - - return ""; -} - -char * -output_move_mem_multiple (n, operands) - int n; - rtx *operands; -{ - rtx tmp; - - switch (n) - { - case 2: - if (REGNO (operands[2]) > REGNO (operands[3])) - { - tmp = operands[2]; - operands[2] = operands[3]; - operands[3] = tmp; - } - output_asm_insn ("ldmia\t%1!, {%2, %3}", operands); - output_asm_insn ("stmia\t%0!, {%2, %3}", operands); - break; - - case 3: - if (REGNO (operands[2]) > REGNO (operands[3])) - { - tmp = operands[2]; - operands[2] = operands[3]; - operands[3] = tmp; - } - if (REGNO (operands[3]) > REGNO (operands[4])) - { - tmp = operands[3]; - operands[3] = operands[4]; - operands[4] = tmp; - } - if (REGNO (operands[2]) > REGNO (operands[3])) - { - tmp = operands[2]; - operands[2] = operands[3]; - operands[3] = tmp; - } - output_asm_insn ("ldmia\t%1!, {%2, %3, %4}", operands); - output_asm_insn ("stmia\t%0!, {%2, %3, %4}", operands); - break; - - default: - abort (); - } - - return ""; -} - - -int -thumb_epilogue_size () -{ - return 42; /* The answer to .... */ -} - -static char *conds[] = -{ - "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", "gt", "le" -}; - -static char * -thumb_condition_code (x, invert) - rtx x; - int invert; -{ - int val; - - switch (GET_CODE (x)) - { - case EQ: val = 0; break; - case NE: val = 1; break; - case GEU: val = 2; break; - case LTU: val = 3; break; - case GTU: val = 8; break; - case LEU: val = 9; break; - case GE: val = 10; break; - case LT: val = 11; break; - case GT: val = 12; break; - case LE: val = 13; break; - default: - abort (); - } - - return conds[val ^ invert]; -} - -void -thumb_print_operand (f, x, code) - FILE *f; - rtx x; - int code; -{ - if (code) - { - switch (code) - { - case '@': - fputs (ASM_COMMENT_START, f); - return; - - case '_': - fputs (user_label_prefix, f); - return; - - case 'D': - if (x) - fputs (thumb_condition_code (x, 1), f); - return; - - case 'd': - if (x) - fputs (thumb_condition_code (x, 0), f); - return; - - /* An explanation of the 'Q', 'R' and 'H' register operands: - - In a pair of registers containing a DI or DF value the 'Q' - operand returns the register number of the register containing - the least signficant part of the value. The 'R' operand returns - the register number of the register containing the most - significant part of the value. - - The 'H' operand returns the higher of the two register numbers. - On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the - same as the 'Q' operand, since the most signficant part of the - value is held in the lower number register. The reverse is true - on systems where WORDS_BIG_ENDIAN is false. - - The purpose of these operands is to distinguish between cases - where the endian-ness of the values is important (for example - when they are added together), and cases where the endian-ness - is irrelevant, but the order of register operations is important. - For example when loading a value from memory into a register - pair, the endian-ness does not matter. Provided that the value - from the lower memory address is put into the lower numbered - register, and the value from the higher address is put into the - higher numbered register, the load will work regardless of whether - the value being loaded is big-wordian or little-wordian. The - order of the two register loads can matter however, if the address - of the memory location is actually held in one of the registers - being overwritten by the load. */ - case 'Q': - if (REGNO (x) > 15) - abort (); - fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0)], f); - return; - - case 'R': - if (REGNO (x) > 15) - abort (); - fputs (reg_names[REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1)], f); - return; - - case 'H': - if (REGNO (x) > 15) - abort (); - fputs (reg_names[REGNO (x) + 1], f); - return; - - case 'c': - /* We use 'c' operands with symbols for .vtinherit */ - if (GET_CODE (x) == SYMBOL_REF) - output_addr_const(f, x); - return; - - default: - abort (); - } - } - if (GET_CODE (x) == REG) - fputs (reg_names[REGNO (x)], f); - else if (GET_CODE (x) == MEM) - output_address (XEXP (x, 0)); - else if (GET_CODE (x) == CONST_INT) - { - fputc ('#', f); - output_addr_const (f, x); - } - else - abort (); -} - -#ifdef AOF_ASSEMBLER -int arm_text_section_count = 1; - -char * -aof_text_section (in_readonly) - int in_readonly; -{ - static char buf[100]; - if (in_readonly) - return ""; - sprintf (buf, "\tCODE16\n\tAREA |C$$code%d|, CODE, READONLY", - arm_text_section_count++); - return buf; -} - -static int arm_data_section_count = 1; - -char * -aof_data_section () -{ - static char buf[100]; - sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++); - return buf; -} - -/* The AOF thumb assembler is religiously strict about declarations of - imported and exported symbols, so that it is impossible to declare a - function as imported near the begining of the file, and then to export - it later on. It is, however, possible to delay the decision until all - the functions in the file have been compiled. To get around this, we - maintain a list of the imports and exports, and delete from it any that - are subsequently defined. At the end of compilation we spit the - remainder of the list out before the END directive. */ - -struct import -{ - struct import *next; - char *name; -}; - -static struct import *imports_list = NULL; - -void -thumb_aof_add_import (name) - char *name; -{ - struct import *new; - - for (new = imports_list; new; new = new->next) - if (new->name == name) - return; - - new = (struct import *) xmalloc (sizeof (struct import)); - new->next = imports_list; - imports_list = new; - new->name = name; -} - -void -thumb_aof_delete_import (name) - char *name; -{ - struct import **old; - - for (old = &imports_list; *old; old = & (*old)->next) - { - if ((*old)->name == name) - { - *old = (*old)->next; - return; - } - } -} - -void -thumb_aof_dump_imports (f) - FILE *f; -{ - while (imports_list) - { - fprintf (f, "\tIMPORT\t"); - assemble_name (f, imports_list->name); - fputc ('\n', f); - imports_list = imports_list->next; - } -} -#endif - -/* Decide whether a type should be returned in memory (true) - or in a register (false). This is called by the macro - RETURN_IN_MEMORY. */ - -int -thumb_return_in_memory (type) - tree type; -{ - if (! AGGREGATE_TYPE_P (type)) - { - /* All simple types are returned in registers. */ - - return 0; - } - else if (int_size_in_bytes (type) > 4) - { - /* All structures/unions bigger than one word are returned in memory. */ - - return 1; - } - else if (TREE_CODE (type) == RECORD_TYPE) - { - tree field; - - /* For a struct the APCS says that we must return in a register if - every addressable element has an offset of zero. For practical - purposes this means that the structure can have at most one non- - bit-field element and that this element must be the first one in - the structure. */ - - /* Find the first field, ignoring non FIELD_DECL things which will - have been created by C++. */ - for (field = TYPE_FIELDS (type); - field && TREE_CODE (field) != FIELD_DECL; - field = TREE_CHAIN (field)) - continue; - - if (field == NULL) - return 0; /* An empty structure. Allowed by an extension to ANSI C. */ - - /* Now check the remaining fields, if any. */ - for (field = TREE_CHAIN (field); field; field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) != FIELD_DECL) - continue; - - if (! DECL_BIT_FIELD_TYPE (field)) - return 1; - } - - return 0; - } - else if (TREE_CODE (type) == UNION_TYPE) - { - tree field; - - /* Unions can be returned in registers if every element is - integral, or can be returned in an integer register. */ - - for (field = TYPE_FIELDS (type); - field; - field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) != FIELD_DECL) - continue; - - if (RETURN_IN_MEMORY (TREE_TYPE (field))) - return 1; - } - - return 0; - } - /* XXX Not sure what should be done for other aggregates, so put them in - memory. */ - return 1; -} - -void -thumb_override_options () -{ - if (structure_size_string != NULL) - { - int size = strtol (structure_size_string, NULL, 0); - - if (size == 8 || size == 32) - arm_structure_size_boundary = size; - else - warning ("Structure size boundary can only be set to 8 or 32"); - } - - if (flag_pic) - { - warning ("Position independent code not supported. Ignored"); - flag_pic = 0; - } -} - -/* CYGNUS LOCAL nickc/thumb-pe */ - -#ifdef THUMB_PE -/* Return nonzero if ATTR is a valid attribute for DECL. - ATTRIBUTES are any existing attributes and ARGS are the arguments - supplied with ATTR. - - Supported attributes: - - naked: don't output any prologue or epilogue code, the user is assumed - to do the right thing. - - interfacearm: Always assume that this function will be entered in ARM - mode, not Thumb mode, and that the caller wishes to be returned to in - ARM mode. */ -int -arm_valid_machine_decl_attribute (decl, attributes, attr, args) - tree decl; - tree attributes; - tree attr; - tree args; -{ - if (args != NULL_TREE) - return 0; - - if (is_attribute_p ("naked", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; - - if (is_attribute_p ("interfacearm", attr)) - return TREE_CODE (decl) == FUNCTION_DECL; - - return 0; -} -#endif /* THUMB_PE */ -/* END CYGNUS LOCAL nickc/thumb-pe */ - -/* Return nonzero if ATTR is a valid attribute for TYPE. - ATTRIBUTES are any existing attributes and ARGS are the arguments - supplied with ATTR. - - Supported attributes: - - short_call: assume the offset from the caller to the callee is small. - - long_call: don't assume the offset is small. */ - -int -arm_valid_machine_type_attribute (type, attributes, attr, args) - tree type; - tree attributes; - tree attr; - tree args; -{ - if (args != NULL_TREE) - return 0; - - if (is_attribute_p ("long_call", attr)) - return 1; - - if (is_attribute_p ("short_call", attr)) - return 1; - - return 0; -} - -/* Encode long_call or short_call attribute by prefixing - symbol name in DECL with a special character FLAG. */ - -void -arm_encode_call_attribute (decl, flag) - tree decl; - int flag; -{ - const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0); - int len = strlen (str); - char * newstr; - - /* Do not allow weak functions to be treated as short call. */ - if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR) - return; - - if (ENCODED_SHORT_CALL_ATTR_P (str) - || ENCODED_LONG_CALL_ATTR_P (str)) - return; - - newstr = malloc (len + 2); - newstr[0] = flag; - strcpy (newstr + 1, str); - - XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr; -} - -/* Return the length of a function name prefix - that starts with the character 'c'. */ - -static int -arm_get_strip_length (char c) -{ - switch (c) - { - ARM_NAME_ENCODING_LENGTHS - default: return 0; - } -} - -/* Return a pointer to a function's name with any - and all prefix encodings stripped from it. */ - -char * -arm_strip_name_encoding (char * name) -{ - int skip; - - while ((skip = arm_get_strip_length (* name))) - name += skip; - - return name; -} - -/* Return 1 if the operand is a SYMBOL_REF for a function known to be - defined within the current compilation unit. If this caanot be - determined, then 0 is returned. */ - -static int -current_file_function_operand (sym_ref) - rtx sym_ref; -{ - /* This is a bit of a fib. A function will have a short call flag - applied to its name if it has the short call attribute, or it has - already been defined within the current compilation unit. */ - if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0))) - return 1; - - /* The current function is always defined within the current compilation - unit. if it s a weak definition however, then this may not be the real - definition of the function, and so we have to say no. */ - if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0) - && !DECL_WEAK (current_function_decl)) - return 1; - - /* We cannot make the determination - default to returning 0. */ - return 0; -} - -/* Return non-zero if a 32 bit "long_call" should be generated for - this call. We generate a long_call if the function: - - a. has an __attribute__((long call)) - or b. the -mlong-calls command line switch has been specified - - However we do not generate a long call if the function: - - c. has an __attribute__ ((short_call)) - or d. has an __attribute__ ((section)) - or e. is defined within the current compilation unit. - - This function will be called by C fragments contained in the machine - description file. CALL_REF and CALL_COOKIE correspond to the matched - rtl operands. CALL_SYMBOL is used to distinguish between - two different callers of the function. It is set to 1 in the - "call_symbol" and "call_symbol_value" patterns and to 0 in the "call" - and "call_value" patterns. This is because of the difference in the - SYM_REFs passed by these patterns. */ - -int -arm_is_longcall_p (sym_ref, call_cookie, call_symbol) - rtx sym_ref; - int call_cookie; - int call_symbol; -{ - if (!call_symbol) - { - if (GET_CODE (sym_ref) != MEM) - return 0; - - sym_ref = XEXP (sym_ref, 0); - } - - if (GET_CODE (sym_ref) != SYMBOL_REF) - return 0; - - if (call_cookie & CALL_SHORT) - return 0; - - if (TARGET_LONG_CALLS && flag_function_sections) - return 1; - - if (current_file_function_operand (sym_ref)) - return 0; - - return (call_cookie & CALL_LONG) - || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0)) - || TARGET_LONG_CALLS; -} - -/* s_register_operand is the same as register_operand, but it doesn't accept - (SUBREG (MEM)...). - - This function exists because at the time it was put in it led to better - code. SUBREG(MEM) always needs a reload in the places where - s_register_operand is used, and this seemed to lead to excessive - reloading. */ - -int -s_register_operand (op, mode) - register rtx op; - enum machine_mode mode; -{ - if (GET_MODE (op) != mode && mode != VOIDmode) - return 0; - - if (GET_CODE (op) == SUBREG) - op = SUBREG_REG (op); - - /* We don't consider registers whose class is NO_REGS - to be a register operand. */ - /* XXX might have to check for lo regs only for thumb ??? */ - return (GET_CODE (op) == REG - && (REGNO (op) >= FIRST_PSEUDO_REGISTER - || REGNO_REG_CLASS (REGNO (op)) != NO_REGS)); -} diff --git a/gcc/config/arm/thumb_020422.h b/gcc/config/arm/thumb_020422.h deleted file mode 100755 index 554ed1d..0000000 --- a/gcc/config/arm/thumb_020422.h +++ /dev/null @@ -1,1295 +0,0 @@ -/* Definitions of target machine for GNU compiler, for ARM/Thumb. - Copyright (C) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. - The basis of this contribution was generated by - Richard Earnshaw, Advanced RISC Machines Ltd - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* ??? The files thumb.{c,h,md} are all seriously lacking comments. */ - -/* ??? The files thumb.{c,h,md} need to be reviewed by an experienced - gcc hacker in their entirety. */ - -/* ??? The files thumb.{c,h,md} and tcoff.h are all separate from the arm - files, which will lead to many maintenance problems. These files are - likely missing all bug fixes made to the arm port since they diverged. */ - -/* ??? Many patterns in the md file accept operands that will require a - reload. These should be eliminated if possible by tightening the - predicates and/or constraints. This will give faster/smaller code. */ - -/* ??? There is no pattern for the TST instuction. Check for other unsupported - instructions. */ - -/* Run Time Target Specifications */ -#ifndef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dthumb -D__thumb -Acpu(arm) -Amachine(arm)" -#endif - -#ifndef CPP_SPEC -#define CPP_SPEC "\ -%{mbig-endian:-D__ARMEB__ -D__THUMBEB__} \ -%{mbe:-D__ARMEB__ -D__THUMBEB__} \ -%{!mbe: %{!mbig-endian:-D__ARMEL__ -D__THUMBEL__}} \ -" -#endif - -#ifndef ASM_SPEC -#define ASM_SPEC "-marm7tdmi %{mthumb-interwork:-mthumb-interwork} %{mbig-endian:-EB}" -#endif -#define LINK_SPEC "%{mbig-endian:-EB} -X" - -#define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr); - -/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ -#define THUMB_FLAG_BIG_END 0x0001 -#define THUMB_FLAG_BACKTRACE 0x0002 -#define THUMB_FLAG_LEAF_BACKTRACE 0x0004 -#define ARM_FLAG_THUMB 0x1000 /* same as in arm.h */ -#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING 0x40000 -#define THUMB_FLAG_CALLER_SUPER_INTERWORKING 0x80000 - -/* Nonzero if all call instructions should be indirect. */ -#define ARM_FLAG_LONG_CALLS (0x10000) /* same as in arm.h */ - - -/* Run-time compilation parameters selecting different hardware/software subsets. */ -extern int target_flags; -#define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */ -#define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END) -#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) -#define TARGET_BACKTRACE (leaf_function_p() \ - ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ - : (target_flags & THUMB_FLAG_BACKTRACE)) - -/* Set if externally visable functions should assume that they - might be called in ARM mode, from a non-thumb aware code. */ -#define TARGET_CALLEE_INTERWORKING \ - (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING) - -/* Set if calls via function pointers should assume that their - destination is non-Thumb aware. */ -#define TARGET_CALLER_INTERWORKING \ - (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING) - -#define TARGET_LONG_CALLS (target_flags & ARM_FLAG_LONG_CALLS) - -/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */ -#ifndef SUBTARGET_SWITCHES -#define SUBTARGET_SWITCHES -#endif - -#define TARGET_SWITCHES \ -{ \ - {"big-endian", THUMB_FLAG_BIG_END}, \ - {"little-endian", -THUMB_FLAG_BIG_END}, \ - {"thumb-interwork", ARM_FLAG_THUMB}, \ - {"no-thumb-interwork", -ARM_FLAG_THUMB}, \ - {"tpcs-frame", THUMB_FLAG_BACKTRACE}, \ - {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \ - {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \ - {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \ - {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ - {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ - {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ - {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ - {"long-calls", ARM_FLAG_LONG_CALLS, \ - "Generate all call instructions as indirect calls"}, \ - {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ - SUBTARGET_SWITCHES \ - {"", TARGET_DEFAULT} \ -} - -#define TARGET_OPTIONS \ -{ \ - { "structure-size-boundary=", & structure_size_string }, \ -} - -#define REGISTER_PREFIX "" - -#define CAN_DEBUG_WITHOUT_FP 1 - -#define ASM_APP_ON "" -#define ASM_APP_OFF "\t.code\t16\n" - -/* Output a gap. In fact we fill it with nulls. */ -#define ASM_OUTPUT_SKIP(STREAM, NBYTES) \ - fprintf ((STREAM), "\t.space\t%u\n", (NBYTES)) - -/* 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(STREAM,LOG) \ -{ \ - if ((LOG) > 0) \ - fprintf (STREAM, "\t.align\t%d\n", (LOG)); \ -} - -/* Output a common block */ -#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ - (fprintf ((STREAM), "\t.comm\t"), \ - assemble_name ((STREAM), (NAME)), \ - fprintf((STREAM), ", %d\t%s %d\n", (ROUNDED), (ASM_COMMENT_START), (SIZE))) - -#define ASM_GENERATE_INTERNAL_LABEL(STRING,PREFIX,NUM) \ - sprintf ((STRING), "*%s%s%d", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) - -/* This is how to output an internal numbered label where - PREFIX is the class of label and NUM is the number within the class. */ -#define ASM_OUTPUT_INTERNAL_LABEL(STREAM,PREFIX,NUM) \ - fprintf ((STREAM), "%s%s%d:\n", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) - -/* This is how to output a label which precedes a jumptable. Since - instructions are 2 bytes, we need explicit alignment here. */ - -#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ - do { \ - ASM_OUTPUT_ALIGN (FILE, 2); \ - ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \ - } while (0) - -/* This says how to define a local common symbol (ie, not visible to - linker). */ -#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ - (fprintf((STREAM),"\n\t.lcomm\t"), \ - assemble_name((STREAM),(NAME)), \ - fprintf((STREAM),",%u\n",(SIZE))) - -/* This is how to output an assembler line for a numeric constant byte. */ -#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ - fprintf ((STREAM), "\t.byte\t0x%x\n", (VALUE)) - -#define ASM_OUTPUT_INT(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.word\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.short\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.byte\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ -do { char dstr[30]; \ - long l[3]; \ - REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ - fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n", \ - l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ - } while (0) - -#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ -do { char dstr[30]; \ - long l[2]; \ - REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ - fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ - l[1], ASM_COMMENT_START, dstr); \ - } while (0) - -#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ -do { char dstr[30]; \ - long l; \ - REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ - fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ - ASM_COMMENT_START, dstr); \ - } while (0); - -/* Define results of standard character escape sequences. */ -#define TARGET_BELL 007 -#define TARGET_BS 010 -#define TARGET_TAB 011 -#define TARGET_NEWLINE 012 -#define TARGET_VT 013 -#define TARGET_FF 014 -#define TARGET_CR 015 - -/* This is how to output a string. */ -#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ -do { \ - register int i, c, len = (LEN), cur_pos = 17; \ - register unsigned char *string = (unsigned char *)(STRING); \ - fprintf ((STREAM), "\t.ascii\t\""); \ - for (i = 0; i < len; i++) \ - { \ - register int c = string[i]; \ - \ - switch (c) \ - { \ - case '\"': \ - case '\\': \ - putc ('\\', (STREAM)); \ - putc (c, (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_NEWLINE: \ - fputs ("\\n", (STREAM)); \ - if (i+1 < len \ - && (((c = string[i+1]) >= '\040' && c <= '~') \ - || c == TARGET_TAB)) \ - cur_pos = 32767; /* break right here */ \ - else \ - cur_pos += 2; \ - break; \ - \ - case TARGET_TAB: \ - fputs ("\\t", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_FF: \ - fputs ("\\f", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_BS: \ - fputs ("\\b", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_CR: \ - fputs ("\\r", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - default: \ - if (c >= ' ' && c < 0177) \ - { \ - putc (c, (STREAM)); \ - cur_pos++; \ - } \ - else \ - { \ - fprintf ((STREAM), "\\%03o", c); \ - cur_pos += 4; \ - } \ - } \ - \ - if (cur_pos > 72 && i+1 < len) \ - { \ - cur_pos = 17; \ - fprintf ((STREAM), "\"\n\t.ascii\t\""); \ - } \ - } \ - fprintf ((STREAM), "\"\n"); \ -} while (0) - -/* Output and Generation of Labels */ -#define ASM_OUTPUT_LABEL(STREAM,NAME) \ - (assemble_name ((STREAM), (NAME)), \ - fprintf ((STREAM), ":\n")) - -#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ - (fprintf ((STREAM), "\t.globl\t"), \ - assemble_name ((STREAM), (NAME)), \ - fputc ('\n', (STREAM))) - -/* Construct a private name. */ -#define ASM_FORMAT_PRIVATE_NAME(OUTVAR,NAME,NUMBER) \ - ((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \ - sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) - -/* Switch to the text or data segment. */ -#define TEXT_SECTION_ASM_OP ".text" -#define DATA_SECTION_ASM_OP ".data" -#define BSS_SECTION_ASM_OP ".bss" - -/* The assembler's names for the registers. */ -#ifndef REGISTER_NAMES -#define REGISTER_NAMES \ -{ \ - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ - "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", "ap" \ -} -#endif - -#ifndef ADDITIONAL_REGISTER_NAMES -#define ADDITIONAL_REGISTER_NAMES \ -{ \ - {"a1", 0}, \ - {"a2", 1}, \ - {"a3", 2}, \ - {"a4", 3}, \ - {"v1", 4}, \ - {"v2", 5}, \ - {"v3", 6}, \ - {"v4", 7}, \ - {"v5", 8}, \ - {"v6", 9}, \ - {"sb", 9}, \ - {"v7", 10}, \ - {"r10", 10}, /* sl */ \ - {"r11", 11}, /* fp */ \ - {"r12", 12}, /* ip */ \ - {"r13", 13}, /* sp */ \ - {"r14", 14}, /* lr */ \ - {"r15", 15} /* pc */ \ -} -#endif - -/* The assembler's parentheses characters. */ -#define ASM_OPEN_PAREN "(" -#define ASM_CLOSE_PAREN ")" - -#ifndef ASM_COMMENT_START -#define ASM_COMMENT_START "@" -#endif - -/* Output an element of a dispatch table. */ -#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ - fprintf (STREAM, "\t.word\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) - -#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ - fprintf (STREAM, "\tb\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) - -/* Storage Layout */ - -/* Define this is most significant bit is lowest numbered in - instructions that operate on numbered bit-fields. */ -#define BITS_BIG_ENDIAN 0 - -/* Define this if most significant byte of a word is the lowest - numbered. */ -#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) - -#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN) - -/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based - on processor pre-defineds when compiling libgcc2.c. */ -#if defined(__THUMBEB__) && !defined(__THUMBEL__) -#define LIBGCC2_WORDS_BIG_ENDIAN 1 -#else -#define LIBGCC2_WORDS_BIG_ENDIAN 0 -#endif - -#define FLOAT_WORDS_BIG_ENDIAN 1 - -#define BITS_PER_UNIT 8 -#define BITS_PER_WORD 32 - -#define UNITS_PER_WORD 4 - -#define POINTER_SIZE 32 - -#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ -{ \ - if (GET_MODE_CLASS (MODE) == MODE_INT \ - && GET_MODE_SIZE (MODE) < 4) \ - { \ - (UNSIGNEDP) = 1; \ - (MODE) = SImode; \ - } \ -} - -#define PARM_BOUNDARY 32 -#define STACK_BOUNDARY 32 - -#define FUNCTION_BOUNDARY 32 -#define BIGGEST_ALIGNMENT 32 - -/* Make strings word-aligned so strcpy from constants will be faster. */ -#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ - (TREE_CODE (EXP) == STRING_CST \ - && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) - -#define EMPTY_FIELD_BOUNDARY 32 - -#define STRUCTURE_SIZE_BOUNDARY 32 - -/* Used when parsing command line option -mstructure_size_boundary. */ -extern char * structure_size_string; - -#define STRICT_ALIGNMENT 1 - -#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT - - -/* Layout of Source Language Data Types */ - -#define DEFAULT_SIGNED_CHAR 0 - -#define TARGET_BELL 007 -#define TARGET_BS 010 -#define TARGET_TAB 011 -#define TARGET_NEWLINE 012 -#define TARGET_VT 013 -#define TARGET_FF 014 -#define TARGET_CR 015 - - -/* Register Usage */ - -/* Note there are 16 hard registers on the Thumb. We invent a 17th register - which is assigned to ARG_POINTER_REGNUM, but this is later removed by - elimination passes in the compiler. */ -#define FIRST_PSEUDO_REGISTER 17 - -/* ??? This is questionable. */ -#define FIXED_REGISTERS \ -{ \ - 0,0,0,0, \ - 0,0,0,0, \ - 0,0,0,1, \ - 0,1,1,1,1 \ -} - -/* ??? This is questionable. */ -#define CALL_USED_REGISTERS \ -{ \ - 1,1,1,1, \ - 0,0,0,0, \ - 0,0,0,1, \ - 1,1,1,1,1 \ -} - -#define HARD_REGNO_NREGS(REGNO,MODE) \ - ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ - / UNITS_PER_WORD) - -/* ??? Probably should only allow DImode/DFmode in even numbered registers. */ -#define HARD_REGNO_MODE_OK(REGNO,MODE) ((GET_MODE_SIZE (MODE) > UNITS_PER_WORD) ? (REGNO < 7) : 1) - -#define MODES_TIEABLE_P(MODE1,MODE2) 1 - -/* The NOARG_LO_REGS class is the set of LO_REGS that are not used for passing - arguments to functions. These are the registers that are available for - spilling during reload. The code in reload1.c:init_reload() will detect this - class and place it into 'reload_address_base_reg_class'. */ - -enum reg_class -{ - NO_REGS, - NONARG_LO_REGS, - LO_REGS, - STACK_REG, - BASE_REGS, - HI_REGS, - ALL_REGS, - LIM_REG_CLASSES -}; - -#define GENERAL_REGS ALL_REGS - -#define N_REG_CLASSES (int) LIM_REG_CLASSES - -#define REG_CLASS_NAMES \ -{ \ - "NO_REGS", \ - "NONARG_LO_REGS", \ - "LO_REGS", \ - "STACK_REG", \ - "BASE_REGS", \ - "HI_REGS", \ - "ALL_REGS" \ -} - -#define REG_CLASS_CONTENTS \ -{ \ - 0x00000, \ - 0x000f0, \ - 0x000ff, \ - 0x02000, \ - 0x020ff, \ - 0x0ff00, \ - 0x1ffff, \ -} - -#define REGNO_REG_CLASS(REGNO) \ - ((REGNO) == STACK_POINTER_REGNUM ? STACK_REG \ - : (REGNO) < 8 ? ((REGNO) < 4 ? LO_REGS \ - : NONARG_LO_REGS) \ - : HI_REGS) - -#define BASE_REG_CLASS BASE_REGS - -#define MODE_BASE_REG_CLASS(MODE) \ - ((MODE) != QImode && (MODE) != HImode \ - ? BASE_REGS : LO_REGS) - -#define INDEX_REG_CLASS LO_REGS - -/* When SMALL_REGISTER_CLASSES is nonzero, the compiler allows - registers explicitly used in the rtl to be used as spill registers - but prevents the compiler from extending the lifetime of these - registers. */ - -#define SMALL_REGISTER_CLASSES 1 - -#define REG_CLASS_FROM_LETTER(C) \ - ((C) == 'l' ? LO_REGS \ - : (C) == 'h' ? HI_REGS \ - : (C) == 'b' ? BASE_REGS \ - : (C) == 'k' ? STACK_REG \ - : NO_REGS) - -#define REGNO_OK_FOR_BASE_P(REGNO) \ - ((REGNO) < 8 \ - || (REGNO) == STACK_POINTER_REGNUM \ - || (unsigned) reg_renumber[REGNO] < 8 \ - || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM) - -#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ - ((REGNO) < 8 \ - || (unsigned) reg_renumber[REGNO] < 8 \ - || (GET_MODE_SIZE (MODE) >= 4 \ - && ((REGNO) == STACK_POINTER_REGNUM \ - || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM))) - -#define REGNO_OK_FOR_INDEX_P(REGNO) \ - ((REGNO) < 8 \ - || (unsigned) reg_renumber[REGNO] < 8) - -/* ??? This looks suspiciously wrong. */ -/* We need to leave BASE_REGS reloads alone, in order to avoid caller_save - lossage. Caller_saves requests a BASE_REGS reload (caller_save_spill_class) - and then later we verify that one was allocated. If PREFERRED_RELOAD_CLASS - says to allocate a LO_REGS spill instead, then this mismatch gives an - abort. Alternatively, this could be fixed by modifying BASE_REG_CLASS - to be LO_REGS instead of BASE_REGS. It is not clear what affect this - change would have. */ -/* ??? This looks even more suspiciously wrong. PREFERRED_RELOAD_CLASS - must always return a strict subset of the input class. Just blindly - returning LO_REGS is safe only if the input class is a superset of LO_REGS, - but there is no check for this. Added another exception for NONARG_LO_REGS - because it is not a superset of LO_REGS. */ -/* ??? We now use NONARG_LO_REGS for caller_save_spill_class, so the - comments about BASE_REGS are now obsolete. */ -#define PREFERRED_RELOAD_CLASS(X,CLASS) \ - ((CLASS) == BASE_REGS || (CLASS) == NONARG_LO_REGS ? (CLASS) \ - : LO_REGS) -/* - ((CONSTANT_P ((X)) && GET_CODE ((X)) != CONST_INT \ - && ! CONSTANT_POOL_ADDRESS_P((X))) ? NO_REGS \ - : (GET_CODE ((X)) == CONST_INT \ - && (unsigned HOST_WIDE_INT) INTVAL ((X)) > 255) ? NO_REGS \ - : LO_REGS) */ - -/* Must leave BASE_REGS and NONARG_LO_REGS reloads alone, see comment - above. */ -#define SECONDARY_RELOAD_CLASS(CLASS,MODE,X) \ - ((CLASS) != LO_REGS && (CLASS) != BASE_REGS && (CLASS) != NONARG_LO_REGS \ - ? ((true_regnum (X) == -1 ? LO_REGS \ - : (true_regnum (X) + HARD_REGNO_NREGS (0, MODE) > 8) ? LO_REGS \ - : NO_REGS)) \ - : NO_REGS) - -#define CLASS_MAX_NREGS(CLASS,MODE) HARD_REGNO_NREGS(0,(MODE)) - -int thumb_shiftable_const (); - -#define CONST_OK_FOR_LETTER_P(VAL,C) \ - ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VAL) < 256 \ - : (C) == 'J' ? (VAL) > -256 && (VAL) <= 0 \ - : (C) == 'K' ? thumb_shiftable_const (VAL) \ - : (C) == 'L' ? (VAL) > -8 && (VAL) < 8 \ - : (C) == 'M' ? ((unsigned HOST_WIDE_INT) (VAL) < 1024 \ - && ((VAL) & 3) == 0) \ - : (C) == 'N' ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ - : (C) == 'O' ? ((VAL) >= -508 && (VAL) <= 508) \ - : 0) - -#define CONST_DOUBLE_OK_FOR_LETTER_P(VAL,C) 0 - -#define EXTRA_CONSTRAINT(X,C) \ - ((C) == 'Q' ? (GET_CODE (X) == MEM \ - && GET_CODE (XEXP (X, 0)) == LABEL_REF) : 0) - -/* Stack Layout and Calling Conventions */ - -#define STACK_GROWS_DOWNWARD 1 - -/* #define FRAME_GROWS_DOWNWARD 1 */ - -/* #define ARGS_GROW_DOWNWARD 1 */ - -#define STARTING_FRAME_OFFSET 0 - -#define FIRST_PARM_OFFSET(FNDECL) 0 - -/* Registers that address the stack frame */ - -#define STACK_POINTER_REGNUM 13 /* Defined by the TPCS. */ - -#define FRAME_POINTER_REGNUM 7 /* TPCS defines this as 11 but it does not really mean it. */ - -#define ARG_POINTER_REGNUM 16 /* A fake hard register that is eliminated later on. */ - -#define STATIC_CHAIN_REGNUM 9 - -#define FRAME_POINTER_REQUIRED 0 - -#define ELIMINABLE_REGS \ -{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ - {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ - {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} - -/* On the Thumb we always want to perform the eliminations as we - actually only have one real register pointing to the stashed - variables: the stack pointer, and we never use the frame pointer. */ -#define CAN_ELIMINATE(FROM,TO) 1 - -/* Note: This macro must match the code in thumb_function_prologue() in thumb.c. */ -#define INITIAL_ELIMINATION_OFFSET(FROM,TO,OFFSET) \ -{ \ - (OFFSET) = 0; \ - if ((FROM) == ARG_POINTER_REGNUM) \ - { \ - int count_regs = 0; \ - int regno; \ - (OFFSET) += get_frame_size (); \ - for (regno = 8; regno < 13; regno++) \ - if (regs_ever_live[regno] && ! call_used_regs[regno]) \ - count_regs++; \ - if (count_regs) \ - (OFFSET) += 4 * count_regs; \ - count_regs = 0; \ - for (regno = 0; regno < 8; regno++) \ - if (regs_ever_live[regno] && ! call_used_regs[regno]) \ - count_regs++; \ - if (count_regs || ! leaf_function_p () || far_jump_used_p()) \ - (OFFSET) += 4 * (count_regs + 1); \ - if (TARGET_BACKTRACE) { \ - if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0)) \ - (OFFSET) += 20; \ - else \ - (OFFSET) += 16; } \ - } \ - if ((TO) == STACK_POINTER_REGNUM) \ - (OFFSET) += current_function_outgoing_args_size; \ -} - -/* Passing Arguments on the stack */ - -#define PROMOTE_PROTOTYPES 1 - -#define ACCUMULATE_OUTGOING_ARGS 1 - -#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 - -#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ - ((MODE) == VOIDmode \ - ? GEN_INT ((CUM).call_cookie) \ - : (NAMED) \ - ? ((CUM).nregs >= 16 ? 0 : gen_rtx (REG, MODE, (CUM).nregs / 4)) \ - : 0) - -#define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) \ - (((CUM).nregs < 16 && (CUM).nregs + (((MODE) == BLKmode) \ - ? int_size_in_bytes (TYPE) \ - : (HARD_REGNO_NREGS (0, (MODE)) \ - * 4)) > 16) \ - ? 4 - (CUM).nregs / 4 : 0) - -/* A C type for declaring a variable that is used as the first argument of - `FUNCTION_ARG' and other related values. For some target machines, the - type `int' suffices and can hold the number of bytes of argument so far. - - On the ARM, this is the number of bytes of arguments scanned so far. */ -typedef struct -{ - /* This is the number of registers of arguments scanned so far. */ - int nregs; - /* One of CALL_NORMAL, CALL_LONG or CALL_SHORT . */ - int call_cookie; -} CUMULATIVE_ARGS; - - -/* 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. - On the ARM, the offset starts at 0. */ -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ - ((CUM).nregs = (((FNTYPE) && aggregate_value_p (TREE_TYPE ((FNTYPE)))) \ - ? 4 : 0), \ - (CUM).call_cookie = \ - (((FNTYPE) && lookup_attribute ("short_call", TYPE_ATTRIBUTES (FNTYPE))) \ - ? CALL_SHORT \ - : (((FNTYPE) && lookup_attribute ("long_call", \ - TYPE_ATTRIBUTES (FNTYPE)))\ - || TARGET_LONG_CALLS) \ - ? CALL_LONG \ - : CALL_NORMAL)) - -/* 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) \ - (CUM).nregs += ((MODE) != BLKmode \ - ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ - : (int_size_in_bytes (TYPE) + 3) & ~3) \ - -#define FUNCTION_ARG_REGNO_P(REGNO) \ - ((REGNO) >=0 && (REGNO) <= 3) - -#define FUNCTION_VALUE(VALTYPE,FUNC) gen_rtx (REG, TYPE_MODE (VALTYPE), 0) - -#define LIBCALL_VALUE(MODE) gen_rtx (REG, (MODE), 0) - -#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == 0) - - /* How large values are returned */ -/* A C expression which can inhibit the returning of certain function values - in registers, based on the type of value. */ -#define RETURN_IN_MEMORY(TYPE) thumb_return_in_memory (TYPE) - -/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return - values must be in memory. On the ARM, they need only do so if larger - than a word, or if they contain elements offset from zero in the struct. */ -#define DEFAULT_PCC_STRUCT_RETURN 0 - - -#define STRUCT_VALUE_REGNUM 0 - -#define FUNCTION_PROLOGUE(FILE,SIZE) thumb_function_prologue((FILE),(SIZE)) - -#define FUNCTION_EPILOGUE(FILE,SIZE) thumb_function_epilogue((FILE),(SIZE)) - -/* Implementing the Varargs Macros */ - -#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ -{ \ - extern int current_function_anonymous_args; \ - current_function_anonymous_args = 1; \ - if ((CUM).nregs < 16) \ - (PRETEND_SIZE) = 16 - (CUM).nregs; \ -} - -/* Trampolines for nested functions */ - -/* Output assembler code for a block containing the constant parts of - a trampoline, leaving space for the variable parts. - - On the Thumb we always switch into ARM mode to execute the trampoline. - Why - because it is easier. This code will always be branched to via - a BX instruction and since the compiler magically generates the address - of the function the linker has no opportunity to ensure that the - bottom bit is set. Thus the processor will be in ARM mode when it - reaches this code. So we duplicate the ARM trampoline code and add - a switch into Thumb mode as well. - - On the ARM, (if r8 is the static chain regnum, and remembering that - referencing pc adds an offset of 8) the trampoline looks like: - ldr r8, [pc, #0] - ldr pc, [pc] - .word static chain value - .word function's address - ??? FIXME: When the trampoline returns, r8 will be clobbered. */ -#define TRAMPOLINE_TEMPLATE(FILE) \ -{ \ - fprintf ((FILE), "\t.code 32\n"); \ - fprintf ((FILE), ".Ltrampoline_start:\n"); \ - fprintf ((FILE), "\tldr\t%s, [%spc, #8]\n", \ - reg_names[STATIC_CHAIN_REGNUM], REGISTER_PREFIX); \ - fprintf ((FILE), "\tldr\t%sip, [%spc, #8]\n", \ - REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf ((FILE), "\torr\t%sip, %sip, #1\n", \ - REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf ((FILE), "\tbx\t%sip\n", REGISTER_PREFIX); \ - fprintf ((FILE), "\t.word\t0\n"); \ - fprintf ((FILE), "\t.word\t0\n"); \ - fprintf ((FILE), "\t.code 16\n"); \ -} - -/* Length in units of the trampoline for entering a nested function. */ -#define TRAMPOLINE_SIZE 24 - -/* Alignment required for a trampoline in units. */ -#define TRAMPOLINE_ALIGN 4 - -#define INITIALIZE_TRAMPOLINE(ADDR,FNADDR,CHAIN) \ -{ \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 16)), \ - (CHAIN)); \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 20)), \ - (FNADDR)); \ -} - - -/* Implicit Calls to Library Routines */ - -#define TARGET_MEM_FUNCTIONS 1 - -#define OVERRIDE_OPTIONS thumb_override_options () - - -/* Addressing Modes */ - -#define HAVE_POST_INCREMENT 1 - -#define CONSTANT_ADDRESS_P(X) \ - (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X)) - -#define MAX_REGS_PER_ADDRESS 2 - -#ifdef REG_OK_STRICT - -#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) -#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) - -#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ - REGNO_MODE_OK_FOR_BASE_P (REGNO (X), MODE) - -#else /* REG_OK_STRICT */ - -#define REG_OK_FOR_BASE_P(X) \ - (REGNO (X) < 8 || REGNO (X) == STACK_POINTER_REGNUM \ - || (X) == arg_pointer_rtx \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER) - -#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ - (REGNO (X) < 8 \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER \ - || (GET_MODE_SIZE (MODE) >= 4 \ - && (REGNO (X) == STACK_POINTER_REGNUM \ - || (X) == arg_pointer_rtx))) - -#define REG_OK_FOR_INDEX_P(X) \ - (REGNO (X) < 8 \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER) - -#endif /* REG_OK_STRICT */ - -/* In a REG+REG address, both must be INDEX registers. */ -#define REG_OK_FOR_INDEXED_BASE_P(X) REG_OK_FOR_INDEX_P(X) - -#define LEGITIMATE_OFFSET(MODE,VAL) \ -(GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ - : GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \ - && ((VAL) & 1) == 0) \ - : ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \ - && ((VAL) & 3) == 0)) - -/* The AP may be eliminated to either the SP or the FP, so we use the - least common denominator, e.g. SImode, and offsets from 0 to 64. */ - -/* ??? Verify whether the above is the right approach. */ - -/* ??? Also, the FP may be eliminated to the SP, so perhaps that - needs special handling also. */ - -/* ??? Look at how the mips16 port solves this problem. It probably uses - better ways to solve some of these problems. */ - -/* Although it is not incorrect, we don't accept QImode and HImode - addresses based on the frame pointer or arg pointer until the reload pass starts. - This is so that eliminating such addresses into stack based ones - won't produce impossible code. */ -#define GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \ -{ \ - /* ??? Not clear if this is right. Experiment. */ \ - if (GET_MODE_SIZE (MODE) < 4 \ - && ! (reload_in_progress || reload_completed) \ - && (reg_mentioned_p (frame_pointer_rtx, X) \ - || reg_mentioned_p (arg_pointer_rtx, X) \ - || reg_mentioned_p (virtual_incoming_args_rtx, X) \ - || reg_mentioned_p (virtual_outgoing_args_rtx, X) \ - || reg_mentioned_p (virtual_stack_dynamic_rtx, X) \ - || reg_mentioned_p (virtual_stack_vars_rtx, X))) \ - ; \ - /* Accept any base register. SP only in SImode or larger. */ \ - else if (GET_CODE (X) == REG && REG_MODE_OK_FOR_BASE_P(X, MODE)) \ - goto WIN; \ - /* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \ - else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \ - && CONSTANT_POOL_ADDRESS_P (X)) \ - goto WIN; \ - /* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \ - else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ - && (GET_CODE (X) == LABEL_REF \ - || (GET_CODE (X) == CONST \ - && GET_CODE (XEXP (X, 0)) == PLUS \ - && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \ - && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \ - goto WIN; \ - /* Post-inc indexing only supported for SImode and larger. */ \ - else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \ - && GET_CODE (XEXP (X, 0)) == REG \ - && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ - goto WIN; \ - else if (GET_CODE (X) == PLUS) \ - { \ - /* REG+REG address can be any two index registers. */ \ - /* ??? REG+REG addresses have been completely disabled before \ - reload completes, because we do not have enough available \ - reload registers. We only have 3 guaranteed reload registers \ - (NONARG_LO_REGS - the frame pointer), but we need at least 4 \ - to support REG+REG addresses. We have left them enabled after \ - reload completes, in the hope that reload_cse_regs and related \ - routines will be able to create them after the fact. It is \ - probably possible to support REG+REG addresses with additional \ - reload work, but I do not not have enough time to attempt such \ - a change at this time. */ \ - /* ??? Normally checking the mode here is wrong, since it isn't \ - impossible to use REG+REG with DFmode. However, the movdf \ - pattern requires offsettable addresses, and REG+REG is not \ - offsettable, so it must be rejected somehow. Trying to use \ - 'o' fails, because offsettable_address_p does a QImode check. \ - QImode is not valid for stack addresses, and has a smaller \ - range for non-stack bases, and this causes valid addresses \ - to be rejected. So we just eliminate REG+REG here by checking \ - the mode. */ \ - /* We also disallow FRAME+REG addressing since we know that FRAME \ - will be replaced with STACK, and SP relative addressing only \ - permits SP+OFFSET. */ \ - if (GET_MODE_SIZE (MODE) <= 4 \ - /* ??? See comment above. */ \ - && reload_completed \ - && GET_CODE (XEXP (X, 0)) == REG \ - && GET_CODE (XEXP (X, 1)) == REG \ - && XEXP (X, 0) != frame_pointer_rtx \ - && XEXP (X, 1) != frame_pointer_rtx \ - && XEXP (X, 0) != virtual_stack_vars_rtx \ - && XEXP (X, 1) != virtual_stack_vars_rtx \ - && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ - && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ - goto WIN; \ - /* REG+const has 5-7 bit offset for non-SP registers. */ \ - else if (GET_CODE (XEXP (X, 0)) == REG \ - && (REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ - || XEXP (X, 0) == arg_pointer_rtx) \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ - goto WIN; \ - /* REG+const has 10 bit offset for SP, but only SImode and \ - larger is supported. */ \ - /* ??? Should probably check for DI/DFmode overflow here \ - just like GO_IF_LEGITIMATE_OFFSET does. */ \ - else if (GET_CODE (XEXP (X, 0)) == REG \ - && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \ - && GET_MODE_SIZE (MODE) >= 4 \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && (unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) < 1024 \ - && (INTVAL (XEXP (X, 1)) & 3) == 0) \ - goto WIN; \ - } \ -} - -/* ??? If an HImode FP+large_offset address is converted to an HImode - SP+large_offset address, then reload won't know how to fix it. It sees - only that SP isn't valid for HImode, and so reloads the SP into an index - register, but the resulting address is still invalid because the offset - is too big. We fix it here instead by reloading the entire address. */ -/* We could probably achieve better results by defining PROMOTE_MODE to help - cope with the variances between the Thumb's signed and unsigned byte and - halfword load instructions. */ -#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ -{ \ - if (GET_CODE (X) == PLUS \ - && GET_MODE_SIZE (MODE) < 4 \ - && GET_CODE (XEXP (X, 0)) == REG \ - && XEXP (X, 0) == stack_pointer_rtx \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && ! LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ - { \ - rtx orig_X = X; \ - X = copy_rtx (X); \ - push_reload (orig_X, NULL_RTX, &X, NULL_PTR, \ - BASE_REG_CLASS, \ - Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \ - goto WIN; \ - } \ -} - -#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) - -#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) - -#define LEGITIMATE_CONSTANT_P(X) \ - (GET_CODE (X) == CONST_INT \ - || GET_CODE (X) == CONST_DOUBLE \ - || CONSTANT_ADDRESS_P (X)) - -/* Flags for the call/call_value rtl operations set up by function_arg. */ -#define CALL_NORMAL 0x00000000 /* No special processing. */ -#define CALL_LONG 0x00000001 /* Always call indirect. */ -#define CALL_SHORT 0x00000002 /* Never call indirect. */ - -#define ENCODE_SECTION_INFO(decl) \ -{ \ - ARM_ENCODE_CALL_TYPE (decl) \ -} - -/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS - is a valid machine specific attribute for DECL. - The attributes in ATTRIBUTES have previously been assigned to DECL. */ -int arm_valid_machine_type_attribute (/* union tree_node *, union tree_node *, - union tree_node *, - union tree_node * */); -#define VALID_MACHINE_TYPE_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ -arm_valid_machine_type_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) - -/* If we are referencing a function that is weak then encode a long call - flag in the function name, otherwise if the function is static or - or known to be defined in this file then encode a short call flag. - This macro is used inside the ENCODE_SECTION macro. */ -#define ARM_ENCODE_CALL_TYPE(decl) \ - if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd') \ - { \ - if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl)) \ - arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR); \ - else if (! TREE_PUBLIC (decl)) \ - arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR); \ - } - -/* Special characters prefixed to function names - in order to encode attribute like information. - Note, '@' and '*' have already been taken. */ -#define SHORT_CALL_FLAG_CHAR '^' -#define LONG_CALL_FLAG_CHAR '#' - -#define ENCODED_SHORT_CALL_ATTR_P(SYMBOL_NAME) \ - (*(SYMBOL_NAME) == SHORT_CALL_FLAG_CHAR) - -#define ENCODED_LONG_CALL_ATTR_P(SYMBOL_NAME) \ - (*(SYMBOL_NAME) == LONG_CALL_FLAG_CHAR) - -#ifndef SUBTARGET_NAME_ENCODING_LENGTHS -#define SUBTARGET_NAME_ENCODING_LENGTHS -#endif - -/* This is a C fragement for the inside of a switch statement. - Each case label should return the number of characters to - be stripped from the start of a function's name, if that - name starts with the indicated character. */ -#define ARM_NAME_ENCODING_LENGTHS \ - case SHORT_CALL_FLAG_CHAR: return 1; \ - case LONG_CALL_FLAG_CHAR: return 1; \ - case '*': return 1; \ - SUBTARGET_NAME_ENCODING_LENGTHS - -/* This has to be handled by a function because more than part of the - ARM backend uses function name prefixes to encode attributes. */ -#undef STRIP_NAME_ENCODING -#define STRIP_NAME_ENCODING(VAR, SYMBOL_NAME) \ - (VAR) = arm_strip_name_encoding (SYMBOL_NAME) - -/* This is how to output a reference to a user-level label named NAME. - `assemble_name' uses this. */ -#undef ASM_OUTPUT_LABELREF -#define ASM_OUTPUT_LABELREF(FILE, NAME) \ - asm_fprintf (FILE, "%U%s", arm_strip_name_encoding (NAME)) - - -/* Condition Code Status */ - -#define NOTICE_UPDATE_CC(EXP,INSN) \ -{ \ - if (get_attr_conds ((INSN)) != CONDS_UNCHANGED) \ - CC_STATUS_INIT; \ -} - - -/* Describing Relative Costs of Operations */ - -#define SLOW_BYTE_ACCESS 0 - -#define SLOW_UNALIGNED_ACCESS 1 - -#define NO_FUNCTION_CSE 1 - -#define NO_RECURSIVE_FUNCTION_CSE 1 - -#define REGISTER_MOVE_COST(FROM,TO) \ - (((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2) - -#define MEMORY_MOVE_COST(M,CLASS,IN) \ - ((GET_MODE_SIZE(M) < 4 ? 8 : 2 * GET_MODE_SIZE(M)) * (CLASS == LO_REGS ? 1 : 2)) - -/* This will allow better space optimization when compiling with -O */ -#define BRANCH_COST (optimize > 1 ? 1 : 0) - -#define RTX_COSTS(X,CODE,OUTER) \ - case MULT: \ - if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ - { \ - int cycles = 0; \ - unsigned HOST_WIDE_INT i = INTVAL (XEXP (X, 1)); \ - while (i) \ - { \ - i >>= 2; \ - cycles++; \ - } \ - return COSTS_N_INSNS (2) + cycles; \ - } \ - return COSTS_N_INSNS (1) + 16; \ - case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATERT: \ - case PLUS: case MINUS: case COMPARE: case NEG: case NOT: \ - return COSTS_N_INSNS (1); \ - case SET: \ - return (COSTS_N_INSNS (1) \ - + 4 * ((GET_CODE (SET_SRC (X)) == MEM) \ - + GET_CODE (SET_DEST (X)) == MEM)) - -#define CONST_COSTS(X,CODE,OUTER) \ - case CONST_INT: \ - if ((OUTER) == SET) \ - { \ - if ((unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ - return 0; \ - if (thumb_shiftable_const (INTVAL (X))) \ - return COSTS_N_INSNS (2); \ - return COSTS_N_INSNS (3); \ - } \ - else if (OUTER == PLUS \ - && INTVAL (X) < 256 && INTVAL (X) > -256) \ - return 0; \ - else if (OUTER == COMPARE \ - && (unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ - return 0; \ - else if (OUTER == ASHIFT || OUTER == ASHIFTRT \ - || OUTER == LSHIFTRT) \ - return 0; \ - return COSTS_N_INSNS (2); \ - case CONST: \ - case CONST_DOUBLE: \ - case LABEL_REF: \ - case SYMBOL_REF: \ - return COSTS_N_INSNS(3); - -#define ADDRESS_COST(X) \ - ((GET_CODE (X) == REG \ - || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \ - && GET_CODE (XEXP (X, 1)) == CONST_INT)) \ - ? 1 : 2) - - -/* Position Independent Code */ - -#define PRINT_OPERAND(STREAM,X,CODE) \ - thumb_print_operand((STREAM), (X), (CODE)) - -#define PRINT_OPERAND_ADDRESS(STREAM,X) \ -{ \ - if (GET_CODE ((X)) == REG) \ - fprintf ((STREAM), "[%s]", reg_names[REGNO ((X))]); \ - else if (GET_CODE ((X)) == POST_INC) \ - fprintf ((STREAM), "%s!", reg_names[REGNO (XEXP (X, 0))]); \ - else if (GET_CODE ((X)) == PLUS) \ - { \ - if (GET_CODE (XEXP ((X), 1)) == CONST_INT) \ - fprintf ((STREAM), "[%s, #%d]", \ - reg_names[REGNO (XEXP ((X), 0))], \ - (int) INTVAL (XEXP ((X), 1))); \ - else \ - fprintf ((STREAM), "[%s, %s]", \ - reg_names[REGNO (XEXP ((X), 0))], \ - reg_names[REGNO (XEXP ((X), 1))]); \ - } \ - else \ - output_addr_const ((STREAM), (X)); \ -} - -#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_')) - -/* Emit a special directive when defining a function name. - This is used by the assembler to assit with interworking. */ -#define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ - if (! is_called_in_ARM_mode (decl)) \ - fprintf (file, "\t.thumb_func\n") ; \ - else \ - fprintf (file, "\t.code\t32\n") ; \ - ASM_OUTPUT_LABEL (file, name) - -#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ - asm_fprintf ((STREAM), "\tpush {%R%s}\n", reg_names[(REGNO)]) - -#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ - fprintf ((STREAM), "\tpop {%R%s}\n", reg_names[(REGNO)]) - -#define FINAL_PRESCAN_INSN(INSN,OPVEC,NOPERANDS) \ - final_prescan_insn((INSN)) - -/* Controlling Debugging Information Format */ -#define DBX_REGISTER_NUMBER(REGNO) (REGNO) - -/* Specific options for DBX Output */ - -#define DBX_DEBUGGING_INFO 1 - -#define DEFAULT_GDB_EXTENSIONS 1 - - -/* Cross Compilation and Floating Point */ - -#define REAL_ARITHMETIC - - -/* Miscellaneous Parameters */ - -#define PREDICATE_CODES \ - {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, - -#define CASE_VECTOR_MODE Pmode - -#define WORD_REGISTER_OPERATIONS - -#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND - -#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR - -#define EASY_DIV_EXPR TRUNC_DIV_EXPR - -#define MOVE_MAX 4 - -#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 - -#define STORE_FLAG_VALUE 1 - -#define Pmode SImode - -#define FUNCTION_MODE SImode - -#define DOLLARS_IN_IDENTIFIERS 0 - -#define NO_DOLLAR_IN_LABEL 1 - -#define HAVE_ATEXIT - -/* The literal pool needs to reside in the text area due to the - limited PC addressing range: */ -#define MACHINE_DEPENDENT_REORG(INSN) thumb_reorg ((INSN)) - - -/* Options specific to Thumb */ - -/* True if a return instruction can be used in this function. */ -int thumb_trivial_epilogue (); -#define USE_RETURN (reload_completed && thumb_trivial_epilogue ()) - -extern char * thumb_unexpanded_epilogue (); -extern char * output_move_mem_multiple (); -extern char * thumb_load_double_from_address (); -extern char * output_return (); -extern int far_jump_used_p(); -extern int is_called_in_ARM_mode (); - -char *arm_strip_name_encoding (/* const char * */); -int arm_is_longcall_p (/* rtx, int, int */); diff --git a/gcc/config/arm/thumb_020422.md b/gcc/config/arm/thumb_020422.md deleted file mode 100755 index 04de07c..0000000 --- a/gcc/config/arm/thumb_020422.md +++ /dev/null @@ -1,1194 +0,0 @@ -;; thumb.md Machine description for ARM/Thumb processors -;; Copyright (C) 1996, 1997, 1998, 2002 Free Software Foundation, Inc. -;; The basis of this contribution was generated by -;; Richard Earnshaw, Advanced RISC Machines Ltd - -;; This file is part of GNU CC. - -;; GNU CC is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. - -;; GNU CC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU CC; see the file COPYING. If not, write to -;; the Free Software Foundation, 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;; LENGTH of an instruction is 2 bytes -(define_attr "length" "" (const_int 2)) - -;; CONDS is set to UNCHANGED when an insn does not affect the condition codes -;; Most insns change the condition codes -(define_attr "conds" "changed,unchanged" (const_string "changed")) - -;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a -;; distant label. -(define_attr "far_jump" "yes,no" (const_string "no")) - -;; Start with move insns - -(define_expand "movsi" - [(set (match_operand:SI 0 "general_operand" "") - (match_operand:SI 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (SImode, operands[1]); - } -") - -(define_insn "*movsi_insn" - [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h") - (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))] - "register_operand (operands[0], SImode) - || register_operand (operands[1], SImode)" - "@ - add\\t%0, %1, #0 - mov\\t%0, %1 - # - # - ldmia\\t%1, {%0} - stmia\\t%0, {%1} - ldr\\t%0, %1 - str\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1" -[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")]) - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] - "thumb_shiftable_const (INTVAL (operands[1]))" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] - " -{ - unsigned HOST_WIDE_INT val = INTVAL (operands[1]); - unsigned HOST_WIDE_INT mask = 0xff; - int i; - for (i = 0; i < 25; i++) - if ((val & (mask << i)) == val) - break; - - if (i == 0) - FAIL; - - operands[1] = GEN_INT (val >> i); - operands[2] = GEN_INT (i); -}") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] - "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (neg:SI (match_dup 0)))] - " - operands[1] = GEN_INT (- INTVAL (operands[1])); -") - -;;(define_expand "reload_outsi" -;; [(set (match_operand:SI 2 "register_operand" "=&l") -;; (match_operand:SI 1 "register_operand" "h")) -;; (set (match_operand:SI 0 "reload_memory_operand" "=o") -;; (match_dup 2))] -;; "" -;; " -;;/* thumb_reload_out_si (operands); -;; DONE; */ -;;") - -(define_expand "movhi" - [(set (match_operand:HI 0 "general_operand" "") - (match_operand:HI 1 "general_operand" ""))] - "" - " -{ - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (HImode, operands[1]); - - /* ??? We shouldn't really get invalid addresses here, but this can - happen if we are passed a SP (never OK for HImode/QImode) or virtual - register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) - relative address. */ - /* ??? This should perhaps be fixed elsewhere, for instance, in - fixup_stack_1, by checking for other kinds of invalid addresses, - e.g. a bare reference to a virtual register. This may confuse the - alpha though, which must handle this case differently. */ - if (GET_CODE (operands[0]) == MEM - && ! memory_address_p (GET_MODE (operands[0]), - XEXP (operands[0], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[0], 0)); - operands[0] = change_address (operands[0], VOIDmode, temp); - } - if (GET_CODE (operands[1]) == MEM - && ! memory_address_p (GET_MODE (operands[1]), - XEXP (operands[1], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[1], 0)); - operands[1] = change_address (operands[1], VOIDmode, temp); - } - } - /* Handle loading a large integer during reload */ - else if (GET_CODE (operands[1]) == CONST_INT - && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) - { - /* Writing a constant to memory needs a scratch, which should - be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); - - operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } -}") - -(define_insn "*movhi_insn" - [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") - (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] - "register_operand (operands[0], HImode) - || register_operand (operands[1], HImode)" - "@ - add\\t%0, %1, #0 - ldrh\\t%0, %1 - strh\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1 - mov\\t%0, %1") - -(define_expand "movqi" - [(set (match_operand:QI 0 "general_operand" "") - (match_operand:QI 1 "general_operand" ""))] - "" - " -{ - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (QImode, operands[1]); - - /* ??? We shouldn't really get invalid addresses here, but this can - happen if we are passed a SP (never OK for HImode/QImode) or virtual - register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) - relative address. */ - /* ??? This should perhaps be fixed elsewhere, for instance, in - fixup_stack_1, by checking for other kinds of invalid addresses, - e.g. a bare reference to a virtual register. This may confuse the - alpha though, which must handle this case differently. */ - if (GET_CODE (operands[0]) == MEM - && ! memory_address_p (GET_MODE (operands[0]), - XEXP (operands[0], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[0], 0)); - operands[0] = change_address (operands[0], VOIDmode, temp); - } - if (GET_CODE (operands[1]) == MEM - && ! memory_address_p (GET_MODE (operands[1]), - XEXP (operands[1], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[1], 0)); - operands[1] = change_address (operands[1], VOIDmode, temp); - } - } - /* Handle loading a large integer during reload */ - else if (GET_CODE (operands[1]) == CONST_INT - && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) - { - /* Writing a constant to memory needs a scratch, which should - be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); - - operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } -}") - -(define_insn "*movqi_insn" - [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") - (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] - "register_operand (operands[0], QImode) - || register_operand (operands[1], QImode)" - "@ - add\\t%0, %1, #0 - ldrb\\t%0, %1 - strb\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1 - mov\\t%0, %1") - -(define_expand "movdi" - [(set (match_operand:DI 0 "general_operand" "") - (match_operand:DI 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (DImode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -;;; ??? This was originally identical to the movdf_insn pattern. -;;; ??? The 'i' constraint looks funny, but it should always be replaced by -;;; thumb_reorg with a memory reference. -(define_insn "*movdi_insn" - [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r") - (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] - "register_operand (operands[0], DImode) - || register_operand (operands[1], DImode)" - "* -{ - switch (which_alternative) - { - case 0: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; - return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; - case 1: - return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; - case 2: - operands[1] = GEN_INT (- INTVAL (operands[1])); - return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; - case 3: - return \"ldmia\\t%1, {%0, %H0}\"; - case 4: - return \"stmia\\t%0, {%1, %H1}\"; - case 5: - return thumb_load_double_from_address (operands); - case 6: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); - output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); - return \"\"; - case 7: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; - return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; - } -}"[(set_attr "length" "4,4,6,2,2,6,4,4")]) - -(define_expand "movdf" - [(set (match_operand:DF 0 "general_operand" "") - (match_operand:DF 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (DFmode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -;;; ??? This was originally identical to the movdi_insn pattern. -;;; ??? The 'F' constraint looks funny, but it should always be replaced by -;;; thumb_reorg with a memory reference. -(define_insn "*movdf_insn" - [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r") - (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] - "register_operand (operands[0], DFmode) - || register_operand (operands[1], DFmode)" - "* - switch (which_alternative) - { - case 0: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; - return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; - case 1: - return \"ldmia\\t%1, {%0, %H0}\"; - case 2: - return \"stmia\\t%0, {%1, %H1}\"; - case 3: - return thumb_load_double_from_address (operands); - case 4: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); - output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); - return \"\"; - case 5: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; - return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; - } -"[(set_attr "length" "4,2,2,6,4,4")]) - -(define_expand "movsf" - [(set (match_operand:SF 0 "general_operand" "") - (match_operand:SF 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (SFmode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -(define_insn "*movsf_insn" - [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") - (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] - "register_operand (operands[0], SFmode) - || register_operand (operands[1], SFmode)" - "@ - add\\t%0, %1, #0 - ldmia\\t%1, {%0} - stmia\\t%0, {%1} - ldr\\t%0, %1 - str\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1") - -;; Widening move insns - -(define_expand "zero_extendhisi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); - emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16))); - DONE; - } -") - -(define_insn "*zero_extendhisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] - "" - "ldrh\\t%0, %1") - -(define_expand "zero_extendqisi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); - emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24))); - DONE; - } -") - -(define_insn "*zero_extendqisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] - "" - "ldrb\\t%0, %1") - -(define_expand "extendhisi2" - [(parallel [(set (match_operand:SI 0 "s_register_operand" "") - (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:SI 2 ""))])] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); - emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16))); - DONE; - } -") - -(define_insn "*extendhisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) - (clobber (match_scratch:SI 2 "=&l"))] - "" - "* -{ - rtx ops[4]; - /* This code used to try to use 'V', and fix the address only if it was - offsettable, but this fails for e.g. REG+48 because 48 is outside the - range of QImode offsets, and offsettable_address_p does a QImode - address check. */ - - if (GET_CODE (XEXP (operands[1], 0)) == PLUS) - { - ops[1] = XEXP (XEXP (operands[1], 0), 0); - ops[2] = XEXP (XEXP (operands[1], 0), 1); - } - else - { - ops[1] = XEXP (operands[1], 0); - ops[2] = const0_rtx; - } - if (GET_CODE (ops[2]) == REG) - return \"ldrsh\\t%0, %1\"; - - ops[0] = operands[0]; - ops[3] = operands[2]; - output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); - return \"\"; -}" -[(set_attr "length" "4")]) - -(define_expand "extendqisi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); - emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24))); - DONE; - } -") - -(define_insn "*extendqisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] - "" - "* -{ - rtx ops[3]; - - if (which_alternative == 0) - return \"ldrsb\\t%0, %1\"; - ops[0] = operands[0]; - if (GET_CODE (XEXP (operands[1], 0)) == PLUS) - { - ops[1] = XEXP (XEXP (operands[1], 0), 0); - ops[2] = XEXP (XEXP (operands[1], 0), 1); - - if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG) - output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); - else if (GET_CODE (ops[1]) == REG) - { - if (REGNO (ops[1]) == REGNO (operands[0])) - output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - else - { - if (REGNO (ops[2]) == REGNO (operands[0])) - output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - } - else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0))) - { - output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - } - else - { - ops[1] = XEXP (operands[1], 0); - ops[2] = const0_rtx; - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - return \"\"; -}" -[(set_attr "length" "2,6")]) - -;; We don't really have extzv, but defining this using shifts helps -;; to reduce register pressure later on. - -(define_expand "extzv" - [(set (match_dup 4) - (ashift:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "const_int_operand" ""))) - (set (match_operand:SI 0 "register_operand" "") - (lshiftrt:SI (match_dup 4) - (match_operand:SI 3 "const_int_operand" "")))] - "" - " -{ - HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); - HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); - operands[3] = GEN_INT (rshift); - if (lshift == 0) - { - emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); - DONE; - } - operands[2] = GEN_INT (lshift); - operands[4] = gen_reg_rtx (SImode); -} -") - -;; Block-move insns - -(define_expand "movstrqi" - [(match_operand:BLK 0 "general_operand" "") - (match_operand:BLK 1 "general_operand" "") - (match_operand:SI 2 "" "") - (match_operand:SI 3 "const_int_operand" "")] - "" - " - if (INTVAL (operands[3]) != 4 - || GET_CODE (operands[2]) != CONST_INT - || INTVAL (operands[2]) > 48) - FAIL; - - thumb_expand_movstrqi (operands); - DONE; -") - -(define_insn "movmem12b" - [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) - (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) - (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) - (mem:SI (plus:SI (match_dup 1) (const_int 8)))) - (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) - (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) - (clobber (match_scratch:SI 2 "=&l")) - (clobber (match_scratch:SI 3 "=&l")) - (clobber (match_scratch:SI 4 "=&l"))] - "" - "* return output_move_mem_multiple (3, operands);" -[(set_attr "length" "4")]) - -(define_insn "movmem8b" - [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) - (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) - (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) - (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) - (clobber (match_scratch:SI 2 "=&l")) - (clobber (match_scratch:SI 3 "=&l"))] - "" - "* return output_move_mem_multiple (2, operands);" -[(set_attr "length" "4")]) - -;; Arithmetic insns - -(define_insn "adddi3" - [(set (match_operand:DI 0 "s_register_operand" "=l") - (plus:DI (match_operand:DI 1 "s_register_operand" "%0") - (match_operand:DI 2 "s_register_operand" "l")))] - "" - "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" -[(set_attr "conds" "changed") - (set_attr "length" "8")]) - -;; register group 'k' is a single register group containing only the stack -;; register. Trying to reload it will always fail catastrophically, -;; so never allow those alternatives to match if reloading is needed. -(define_insn "addsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l,l,*r,*h,l,!k") - (plus:SI (match_operand:SI 1 "s_register_operand" "%0,0,l,*0,*0,!k,!k") - (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] - "" - "* - static char *asms[] = -{ - \"add\\t%0, %0, %2\", - \"sub\\t%0, %0, #%n2\", - \"add\\t%0, %1, %2\", - \"add\\t%0, %0, %2\", - \"add\\t%0, %0, %2\", - \"add\\t%0, %1, %2\", - \"add\\t%0, %1, %2\" -}; - if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) < 0) - return \"sub\\t%0, %1, #%n2\"; - return asms[which_alternative]; -") - -; reloading and elimination of the frame pointer can sometimes cause this -; optimization to be missed. -(define_peephole - [(set (match_operand:SI 0 "register_operand" "=l") - (match_operand:SI 1 "const_int_operand" "M")) - (set (match_dup 0) - (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] - "REGNO (operands[2]) == STACK_POINTER_REGNUM - && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 - && (INTVAL (operands[1]) & 3) == 0" - "add\\t%0, %2, %1") - -(define_insn "subdi3" - [(set (match_operand:DI 0 "s_register_operand" "=l") - (minus:DI (match_operand:DI 1 "s_register_operand" "0") - (match_operand:DI 2 "s_register_operand" "l")))] - "" - "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" -[(set_attr "conds" "changed") - (set_attr "length" "8")]) - -(define_insn "subsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (minus:SI (match_operand:SI 1 "s_register_operand" "l") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "sub\\t%0, %1, %2") - -;; We must ensure that one input matches the output, and that the other input -;; does not match the output. Using 0 satisfies the first, and using & -;; satisfies the second. Unfortunately, this fails when operands 1 and 2 -;; are the same, because reload will make operand 0 match operand 1 without -;; realizing that this conflicts with operand 2. We fix this by adding another -;; alternative to match this case, and then `reload' it ourselves. This -;; alternative must come first. -(define_insn "mulsi3" - [(set (match_operand:SI 0 "s_register_operand" "=&l,&l,&l") - (mult:SI (match_operand:SI 1 "s_register_operand" "%l,*h,0") - (match_operand:SI 2 "s_register_operand" "l,l,l")))] - "" - "* -{ - if (which_alternative < 2) - return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; - else - return \"mul\\t%0, %0, %2\"; -}" - [(set_attr "length" "4,4,2")]) - -(define_insn "negsi2" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (neg:SI (match_operand:SI 1 "s_register_operand" "l")))] - "" - "neg\\t%0, %1") - -;; Logical insns - -(define_expand "andsi3" - [(set (match_operand:SI 0 "s_register_operand" "") - (and:SI (match_operand:SI 1 "s_register_operand" "") - (match_operand:SI 2 "nonmemory_operand" "")))] - "" - " - if (GET_CODE (operands[2]) != CONST_INT) - operands[2] = force_reg (SImode, operands[2]); - else - { - int i; - if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) - { - operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); - emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); - DONE; - } - - for (i = 9; i <= 31; i++) - if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) - { - emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), - const0_rtx)); - DONE; - } - else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) - { - rtx shift = GEN_INT (i); - rtx reg = gen_reg_rtx (SImode); - emit_insn (gen_lshrsi3 (reg, operands[1], shift)); - emit_insn (gen_ashlsi3 (operands[0], reg, shift)); - DONE; - } - - operands[2] = force_reg (SImode, operands[2]); - } -") - -(define_insn "*andsi3_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (and:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "and\\t%0, %0, %2") - -(define_insn "bicsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "l")) - (match_operand:SI 2 "s_register_operand" "0")))] - "" - "bic\\t%0, %0, %1") - -(define_insn "iorsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (ior:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "orr\\t%0, %0, %2") - -(define_insn "xorsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (xor:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "eor\\t%0, %0, %2") - -(define_insn "one_cmplsi2" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (not:SI (match_operand:SI 1 "s_register_operand" "l")))] - "" - "mvn\\t%0, %1") - -;; Shift and rotation insns - -(define_insn "ashlsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (ashift:SI (match_operand:SI 1 "s_register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - lsl\\t%0, %1, %2 - lsl\\t%0, %0, %2") - -(define_insn "ashrsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - asr\\t%0, %1, %2 - asr\\t%0, %0, %2") - -(define_insn "lshrsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - lsr\\t%0, %1, %2 - lsr\\t%0, %0, %2") - -(define_insn "rotrsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (rotatert:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "ror\\t%0, %0, %2") - -;; Comparison insns - -(define_expand "cmpsi" - [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "") - (match_operand:SI 1 "nonmemory_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG) - { - if (GET_CODE (operands[1]) != CONST_INT - || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256) - { - if (GET_CODE (operands[1]) != CONST_INT - || INTVAL (operands[1]) < -255 - || INTVAL (operands[1]) > 0) - operands[1] = force_reg (SImode, operands[1]); - else - { - operands[1] = force_reg (SImode, - GEN_INT (- INTVAL (operands[1]))); - emit_insn (gen_cmnsi (operands[0], operands[1])); - DONE; - } - } - } -") - -(define_insn "*cmpsi_insn" - [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l,*r,*h") - (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))] - "" - "@ - cmp\\t%0, %1 - cmp\\t%0, %1 - cmp\\t%0, %1") - -(define_insn "tstsi" - [(set (cc0) (match_operand:SI 0 "s_register_operand" "l"))] - "" - "cmp\\t%0, #0") - -(define_insn "cmnsi" - [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l") - (neg:SI (match_operand:SI 1 "s_register_operand" "l"))))] - "" - "cmn\\t%0, %1") - -;; Jump insns - -(define_insn "jump" - [(set (pc) (label_ref (match_operand 0 "" "")))] - "" - "* - if (get_attr_length (insn) == 2) - return \"b\\t%l0\"; - return \"bl\\t%l0\\t%@ far jump\"; -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "4") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 2) - (const_int 4)))]) - - -(define_expand "beq" - [(set (pc) (if_then_else (eq (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bne" - [(set (pc) (if_then_else (ne (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bge" - [(set (pc) (if_then_else (ge (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "ble" - [(set (pc) (if_then_else (le (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgt" - [(set (pc) (if_then_else (gt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "blt" - [(set (pc) (if_then_else (lt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgeu" - [(set (pc) (if_then_else (geu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bleu" - [(set (pc) (if_then_else (leu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgtu" - [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bltu" - [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_insn "*cond_branch" - [(set (pc) (if_then_else (match_operator 1 "comparison_operator" - [(cc0) (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "* - switch (get_attr_length (insn)) - { - case 2: return \"b%d1\\t%l0\\t%@cond_branch\"; - case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\"; - default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\"; - } -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "6") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int -252)) - (le (minus (match_dup 0) (pc)) (const_int 254))) - (const_int 2) - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 4) - (const_int 6))))]) - -(define_insn "*cond_branch_reversed" - [(set (pc) (if_then_else (match_operator 1 "comparison_operator" - [(cc0) (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "* - switch (get_attr_length (insn)) - { - case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\"; - case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\"; - default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\"; - } - return \"\"; -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "6") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int -252)) - (le (minus (match_dup 0) (pc)) (const_int 254))) - (const_int 2) - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 4) - (const_int 6))))]) - -(define_insn "indirect_jump" - [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r"))] - "" - "mov\\tpc, %0") - -(define_insn "tablejump" - [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r")) - (use (label_ref (match_operand 1 "" "")))] - "" - "mov\\tpc, %0") - -(define_insn "return" - [(return)] - "USE_RETURN" - "* return output_return ();" -[(set_attr "length" "18")]) - -;; Call insns - -(define_expand "call" - [(parallel - [(call (match_operand:SI 0 "memory_operand" "") - (match_operand 1 "" "")) - (use (match_operand 2 "" ""))])] - "" - " -{ - if (GET_CODE (XEXP (operands[0], 0)) != REG - && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0)) - XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); -}") - -(define_insn "*call_indirect" - [(parallel - [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) - (match_operand 1 "" "")) - (use (match_operand 2 "" ""))])] - "! TARGET_CALLER_INTERWORKING" - "bl\\t%__call_via_%0" -[(set_attr "length" "4")]) -;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version -;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set -;; the bottom bit of lr so that a function return (using bx) -;; would switch back into ARM mode... - -(define_insn "*call_indirect_interwork" - [(parallel - [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) - (match_operand 1 "" "")) - (use (match_operand 2 "" ""))])] - "TARGET_CALLER_INTERWORKING" - "bl\\t%__interwork_call_via_%0" -[(set_attr "length" "4")]) - -(define_expand "call_value" - [(parallel - [(set (match_operand 0 "" "") - (call (match_operand 1 "memory_operand" "") - (match_operand 2 "" ""))) - (use (match_operand 3 "" ""))])] - "" - " -{ - if (GET_CODE (XEXP (operands[1], 0)) != REG - && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0)) - XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); -}") - -(define_insn "*call_value_indirect" - [(parallel - [(set (match_operand 0 "" "=l") - (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) - (match_operand 2 "" ""))) - (use (match_operand 3 "" ""))])] - "! TARGET_CALLER_INTERWORKING" - "bl\\t%__call_via_%1" -[(set_attr "length" "4")]) -;; See comment for call_indirect pattern - -(define_insn "*call_value_indirect_interwork" - [(parallel - [(set (match_operand 0 "" "=l") - (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) - (match_operand 2 "" ""))) - (use (match_operand 3 "" ""))])] - "TARGET_CALLER_INTERWORKING" - "bl\\t%__interwork_call_via_%1" -[(set_attr "length" "4")]) - - -(define_insn "*call_insn" - [(parallel - [(call (mem:SI (match_operand:SI 0 "" "i")) - (match_operand:SI 1 "" "")) - (use (match_operand 2 "" ""))])] - "GET_CODE (operands[0]) == SYMBOL_REF - && ! arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)" - "bl\\t%a0" -[(set_attr "length" "4")]) - -(define_insn "*call_value_insn" - [(parallel - [(set (match_operand 0 "register_operand" "=l") - (call (mem:SI (match_operand 1 "" "i")) - (match_operand 2 "" ""))) - (use (match_operand 3 "" ""))])] - "GET_CODE(operands[1]) == SYMBOL_REF - && ! arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)" - "bl\\t%a1" -[(set_attr "length" "4")]) - -;; Untyped call not required, since all funcs return in r0 - -;; Miscellaneous patterns - -(define_insn "nop" - [(clobber (const_int 0))] - "" - "mov\\tr8, r8") - -(define_insn "blockage" - [(unspec_volatile [(const_int 0)] 0)] - "" - "" - [(set_attr "length" "0")]) - -(define_expand "prologue" - [(const_int 0)] - "" - " - thumb_expand_prologue (); - DONE; -") - -(define_expand "epilogue" - [(unspec_volatile [(const_int 0)] 1)] - "! thumb_trivial_epilogue ()" - " - thumb_expand_epilogue (); -") - -(define_insn "*epilogue_insns" - [(unspec_volatile [(const_int 0)] 1)] - "" - "* - return thumb_unexpanded_epilogue (); -" -[(set_attr "length" "42")]) - -;; Special patterns for dealing with the constant pool - -(define_insn "consttable_4" - [(unspec_volatile [(match_operand 0 "" "")] 2)] - "" - "* -{ - switch (GET_MODE_CLASS (GET_MODE (operands[0]))) - { - case MODE_FLOAT: - { - union real_extract u; - bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); - assemble_real (u.d, GET_MODE (operands[0])); - break; - } - default: - assemble_integer (operands[0], 4, 1); - break; - } - return \"\"; -}" -[(set_attr "length" "4")]) - -(define_insn "consttable_8" - [(unspec_volatile [(match_operand 0 "" "")] 3)] - "" - "* -{ - switch (GET_MODE_CLASS (GET_MODE (operands[0]))) - { - case MODE_FLOAT: - { - union real_extract u; - bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); - assemble_real (u.d, GET_MODE (operands[0])); - break; - } - default: - assemble_integer (operands[0], 8, 1); - break; - } - return \"\"; -}" -[(set_attr "length" "8")]) - -(define_insn "consttable_end" - [(unspec_volatile [(const_int 0)] 4)] - "" - "* - /* Nothing to do (currently). */ - return \"\"; -") - -(define_insn "align_4" - [(unspec_volatile [(const_int 0)] 5)] - "" - "* - assemble_align (32); - return \"\"; -") diff --git a/gcc/config/arm/thumb_020428.h b/gcc/config/arm/thumb_020428.h deleted file mode 100755 index 8bba8d0..0000000 --- a/gcc/config/arm/thumb_020428.h +++ /dev/null @@ -1,1297 +0,0 @@ -/* Definitions of target machine for GNU compiler, for ARM/Thumb. - Copyright (C) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc. - The basis of this contribution was generated by - Richard Earnshaw, Advanced RISC Machines Ltd - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* ??? The files thumb.{c,h,md} are all seriously lacking comments. */ - -/* ??? The files thumb.{c,h,md} need to be reviewed by an experienced - gcc hacker in their entirety. */ - -/* ??? The files thumb.{c,h,md} and tcoff.h are all separate from the arm - files, which will lead to many maintenance problems. These files are - likely missing all bug fixes made to the arm port since they diverged. */ - -/* ??? Many patterns in the md file accept operands that will require a - reload. These should be eliminated if possible by tightening the - predicates and/or constraints. This will give faster/smaller code. */ - -/* ??? There is no pattern for the TST instuction. Check for other unsupported - instructions. */ - -/* Run Time Target Specifications */ -#ifndef CPP_PREDEFINES -#define CPP_PREDEFINES "-Dthumb -D__thumb -Acpu(arm) -Amachine(arm)" -#endif - -#ifndef CPP_SPEC -#define CPP_SPEC "\ -%{mbig-endian:-D__ARMEB__ -D__THUMBEB__} \ -%{mbe:-D__ARMEB__ -D__THUMBEB__} \ -%{!mbe: %{!mbig-endian:-D__ARMEL__ -D__THUMBEL__}} \ -" -#endif - -#ifndef ASM_SPEC -#define ASM_SPEC "-marm7tdmi %{mthumb-interwork:-mthumb-interwork} %{mbig-endian:-EB}" -#endif -#define LINK_SPEC "%{mbig-endian:-EB} -X" - -#define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr); - -/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ -#define THUMB_FLAG_BIG_END 0x0001 -#define THUMB_FLAG_BACKTRACE 0x0002 -#define THUMB_FLAG_LEAF_BACKTRACE 0x0004 -#define ARM_FLAG_THUMB 0x1000 /* same as in arm.h */ -#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING 0x40000 -#define THUMB_FLAG_CALLER_SUPER_INTERWORKING 0x80000 - -/* Nonzero if all call instructions should be indirect. */ -#define ARM_FLAG_LONG_CALLS (0x10000) /* same as in arm.h */ - - -/* Run-time compilation parameters selecting different hardware/software subsets. */ -extern int target_flags; -#define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */ -#define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END) -#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) -#define TARGET_BACKTRACE (leaf_function_p() \ - ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ - : (target_flags & THUMB_FLAG_BACKTRACE)) - -/* Set if externally visable functions should assume that they - might be called in ARM mode, from a non-thumb aware code. */ -#define TARGET_CALLEE_INTERWORKING \ - (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING) - -/* Set if calls via function pointers should assume that their - destination is non-Thumb aware. */ -#define TARGET_CALLER_INTERWORKING \ - (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING) - -#define TARGET_LONG_CALLS (target_flags & ARM_FLAG_LONG_CALLS) - -/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */ -#ifndef SUBTARGET_SWITCHES -#define SUBTARGET_SWITCHES -#endif - -#define TARGET_SWITCHES \ -{ \ - {"big-endian", THUMB_FLAG_BIG_END}, \ - {"little-endian", -THUMB_FLAG_BIG_END}, \ - {"thumb-interwork", ARM_FLAG_THUMB}, \ - {"no-thumb-interwork", -ARM_FLAG_THUMB}, \ - {"tpcs-frame", THUMB_FLAG_BACKTRACE}, \ - {"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \ - {"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \ - {"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \ - {"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ - {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \ - {"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ - {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \ - {"long-calls", ARM_FLAG_LONG_CALLS, \ - "Generate all call instructions as indirect calls"}, \ - {"no-long-calls", -ARM_FLAG_LONG_CALLS, ""}, \ - SUBTARGET_SWITCHES \ - {"", TARGET_DEFAULT} \ -} - -#define TARGET_OPTIONS \ -{ \ - { "structure-size-boundary=", & structure_size_string }, \ -} - -#define REGISTER_PREFIX "" - -#define CAN_DEBUG_WITHOUT_FP 1 - -#define ASM_APP_ON "" -#define ASM_APP_OFF "\t.code\t16\n" - -/* Output a gap. In fact we fill it with nulls. */ -#define ASM_OUTPUT_SKIP(STREAM, NBYTES) \ - fprintf ((STREAM), "\t.space\t%u\n", (NBYTES)) - -/* 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(STREAM,LOG) \ -{ \ - if ((LOG) > 0) \ - fprintf (STREAM, "\t.align\t%d\n", (LOG)); \ -} - -/* Output a common block */ -#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ - (fprintf ((STREAM), "\t.comm\t"), \ - assemble_name ((STREAM), (NAME)), \ - fprintf((STREAM), ", %d\t%s %d\n", (ROUNDED), (ASM_COMMENT_START), (SIZE))) - -#define ASM_GENERATE_INTERNAL_LABEL(STRING,PREFIX,NUM) \ - sprintf ((STRING), "*%s%s%d", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) - -/* This is how to output an internal numbered label where - PREFIX is the class of label and NUM is the number within the class. */ -#define ASM_OUTPUT_INTERNAL_LABEL(STREAM,PREFIX,NUM) \ - fprintf ((STREAM), "%s%s%d:\n", (LOCAL_LABEL_PREFIX), (PREFIX), (NUM)) - -/* This is how to output a label which precedes a jumptable. Since - instructions are 2 bytes, we need explicit alignment here. */ - -#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \ - do { \ - ASM_OUTPUT_ALIGN (FILE, 2); \ - ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \ - } while (0) - -/* This says how to define a local common symbol (ie, not visible to - linker). */ -#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \ - (fprintf((STREAM),"\n\t.lcomm\t"), \ - assemble_name((STREAM),(NAME)), \ - fprintf((STREAM),",%u\n",(SIZE))) - -/* This is how to output an assembler line for a numeric constant byte. */ -#define ASM_OUTPUT_BYTE(STREAM,VALUE) \ - fprintf ((STREAM), "\t.byte\t0x%x\n", (VALUE)) - -#define ASM_OUTPUT_INT(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.word\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_SHORT(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.short\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_CHAR(STREAM,VALUE) \ -{ \ - fprintf (STREAM, "\t.byte\t"); \ - output_addr_const (STREAM, (VALUE)); \ - fprintf (STREAM, "\n"); \ -} - -#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ -do { char dstr[30]; \ - long l[3]; \ - REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ - fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n", \ - l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ - } while (0) - -#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ -do { char dstr[30]; \ - long l[2]; \ - REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ - fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ - l[1], ASM_COMMENT_START, dstr); \ - } while (0) - -#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ -do { char dstr[30]; \ - long l; \ - REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ - REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ - fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ - ASM_COMMENT_START, dstr); \ - } while (0); - -/* Define results of standard character escape sequences. */ -#define TARGET_BELL 007 -#define TARGET_BS 010 -#define TARGET_TAB 011 -#define TARGET_NEWLINE 012 -#define TARGET_VT 013 -#define TARGET_FF 014 -#define TARGET_CR 015 - -/* This is how to output a string. */ -#define ASM_OUTPUT_ASCII(STREAM, STRING, LEN) \ -do { \ - register int i, c, len = (LEN), cur_pos = 17; \ - register unsigned char *string = (unsigned char *)(STRING); \ - fprintf ((STREAM), "\t.ascii\t\""); \ - for (i = 0; i < len; i++) \ - { \ - register int c = string[i]; \ - \ - switch (c) \ - { \ - case '\"': \ - case '\\': \ - putc ('\\', (STREAM)); \ - putc (c, (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_NEWLINE: \ - fputs ("\\n", (STREAM)); \ - if (i+1 < len \ - && (((c = string[i+1]) >= '\040' && c <= '~') \ - || c == TARGET_TAB)) \ - cur_pos = 32767; /* break right here */ \ - else \ - cur_pos += 2; \ - break; \ - \ - case TARGET_TAB: \ - fputs ("\\t", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_FF: \ - fputs ("\\f", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_BS: \ - fputs ("\\b", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - case TARGET_CR: \ - fputs ("\\r", (STREAM)); \ - cur_pos += 2; \ - break; \ - \ - default: \ - if (c >= ' ' && c < 0177) \ - { \ - putc (c, (STREAM)); \ - cur_pos++; \ - } \ - else \ - { \ - fprintf ((STREAM), "\\%03o", c); \ - cur_pos += 4; \ - } \ - } \ - \ - if (cur_pos > 72 && i+1 < len) \ - { \ - cur_pos = 17; \ - fprintf ((STREAM), "\"\n\t.ascii\t\""); \ - } \ - } \ - fprintf ((STREAM), "\"\n"); \ -} while (0) - -/* Output and Generation of Labels */ -#define ASM_OUTPUT_LABEL(STREAM,NAME) \ - (assemble_name ((STREAM), (NAME)), \ - fprintf ((STREAM), ":\n")) - -#define ASM_GLOBALIZE_LABEL(STREAM,NAME) \ - (fprintf ((STREAM), "\t.globl\t"), \ - assemble_name ((STREAM), (NAME)), \ - fputc ('\n', (STREAM))) - -/* Construct a private name. */ -#define ASM_FORMAT_PRIVATE_NAME(OUTVAR,NAME,NUMBER) \ - ((OUTVAR) = (char *) alloca (strlen (NAME) + 10), \ - sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) - -/* Switch to the text or data segment. */ -#define TEXT_SECTION_ASM_OP ".text" -#define DATA_SECTION_ASM_OP ".data" -#define BSS_SECTION_ASM_OP ".bss" - -/* The assembler's names for the registers. */ -#ifndef REGISTER_NAMES -#define REGISTER_NAMES \ -{ \ - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ - "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", "ap" \ -} -#endif - -#ifndef ADDITIONAL_REGISTER_NAMES -#define ADDITIONAL_REGISTER_NAMES \ -{ \ - {"a1", 0}, \ - {"a2", 1}, \ - {"a3", 2}, \ - {"a4", 3}, \ - {"v1", 4}, \ - {"v2", 5}, \ - {"v3", 6}, \ - {"v4", 7}, \ - {"v5", 8}, \ - {"v6", 9}, \ - {"sb", 9}, \ - {"v7", 10}, \ - {"r10", 10}, /* sl */ \ - {"r11", 11}, /* fp */ \ - {"r12", 12}, /* ip */ \ - {"r13", 13}, /* sp */ \ - {"r14", 14}, /* lr */ \ - {"r15", 15} /* pc */ \ -} -#endif - -/* The assembler's parentheses characters. */ -#define ASM_OPEN_PAREN "(" -#define ASM_CLOSE_PAREN ")" - -#ifndef ASM_COMMENT_START -#define ASM_COMMENT_START "@" -#endif - -/* Output an element of a dispatch table. */ -#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ - fprintf (STREAM, "\t.word\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) - -#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM,BODY,VALUE,REL) \ - fprintf (STREAM, "\tb\t%sL%d\n", (LOCAL_LABEL_PREFIX), (VALUE)) - -/* Storage Layout */ - -/* Define this is most significant bit is lowest numbered in - instructions that operate on numbered bit-fields. */ -#define BITS_BIG_ENDIAN 0 - -/* Define this if most significant byte of a word is the lowest - numbered. */ -#define BYTES_BIG_ENDIAN (TARGET_BIG_END != 0) - -#define WORDS_BIG_ENDIAN (BYTES_BIG_ENDIAN) - -/* LIBGCC2_WORDS_BIG_ENDIAN has to be a constant, so we define this based - on processor pre-defineds when compiling libgcc2.c. */ -#if defined(__THUMBEB__) && !defined(__THUMBEL__) -#define LIBGCC2_WORDS_BIG_ENDIAN 1 -#else -#define LIBGCC2_WORDS_BIG_ENDIAN 0 -#endif - -#define FLOAT_WORDS_BIG_ENDIAN 1 - -#define BITS_PER_UNIT 8 -#define BITS_PER_WORD 32 - -#define UNITS_PER_WORD 4 - -#define POINTER_SIZE 32 - -#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ -{ \ - if (GET_MODE_CLASS (MODE) == MODE_INT \ - && GET_MODE_SIZE (MODE) < 4) \ - { \ - (UNSIGNEDP) = 1; \ - (MODE) = SImode; \ - } \ -} - -#define PARM_BOUNDARY 32 -#define STACK_BOUNDARY 32 - -#define FUNCTION_BOUNDARY 32 -#define BIGGEST_ALIGNMENT 32 - -/* Make strings word-aligned so strcpy from constants will be faster. */ -#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ - (TREE_CODE (EXP) == STRING_CST \ - && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) - -#define EMPTY_FIELD_BOUNDARY 32 - -#define STRUCTURE_SIZE_BOUNDARY 32 - -/* Used when parsing command line option -mstructure_size_boundary. */ -extern char * structure_size_string; - -#define STRICT_ALIGNMENT 1 - -#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT - - -/* Layout of Source Language Data Types */ - -#define DEFAULT_SIGNED_CHAR 0 - -#define TARGET_BELL 007 -#define TARGET_BS 010 -#define TARGET_TAB 011 -#define TARGET_NEWLINE 012 -#define TARGET_VT 013 -#define TARGET_FF 014 -#define TARGET_CR 015 - - -/* Register Usage */ - -/* Note there are 16 hard registers on the Thumb. We invent a 17th register - which is assigned to ARG_POINTER_REGNUM, but this is later removed by - elimination passes in the compiler. */ -#define FIRST_PSEUDO_REGISTER 17 - -/* ??? This is questionable. */ -#define FIXED_REGISTERS \ -{ \ - 0,0,0,0, \ - 0,0,0,0, \ - 0,0,0,1, \ - 0,1,1,1,1 \ -} - -/* ??? This is questionable. */ -#define CALL_USED_REGISTERS \ -{ \ - 1,1,1,1, \ - 0,0,0,0, \ - 0,0,0,1, \ - 1,1,1,1,1 \ -} - -#define HARD_REGNO_NREGS(REGNO,MODE) \ - ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ - / UNITS_PER_WORD) - -/* ??? Probably should only allow DImode/DFmode in even numbered registers. */ -#define HARD_REGNO_MODE_OK(REGNO,MODE) ((GET_MODE_SIZE (MODE) > UNITS_PER_WORD) ? (REGNO < 7) : 1) - -#define MODES_TIEABLE_P(MODE1,MODE2) 1 - -/* The NOARG_LO_REGS class is the set of LO_REGS that are not used for passing - arguments to functions. These are the registers that are available for - spilling during reload. The code in reload1.c:init_reload() will detect this - class and place it into 'reload_address_base_reg_class'. */ - -enum reg_class -{ - NO_REGS, - NONARG_LO_REGS, - LO_REGS, - STACK_REG, - BASE_REGS, - HI_REGS, - ALL_REGS, - LIM_REG_CLASSES -}; - -#define GENERAL_REGS ALL_REGS - -#define N_REG_CLASSES (int) LIM_REG_CLASSES - -#define REG_CLASS_NAMES \ -{ \ - "NO_REGS", \ - "NONARG_LO_REGS", \ - "LO_REGS", \ - "STACK_REG", \ - "BASE_REGS", \ - "HI_REGS", \ - "ALL_REGS" \ -} - -#define REG_CLASS_CONTENTS \ -{ \ - 0x00000, \ - 0x000f0, \ - 0x000ff, \ - 0x02000, \ - 0x020ff, \ - 0x0ff00, \ - 0x1ffff, \ -} - -#define REGNO_REG_CLASS(REGNO) \ - ((REGNO) == STACK_POINTER_REGNUM ? STACK_REG \ - : (REGNO) < 8 ? ((REGNO) < 4 ? LO_REGS \ - : NONARG_LO_REGS) \ - : HI_REGS) - -#define BASE_REG_CLASS BASE_REGS - -#define MODE_BASE_REG_CLASS(MODE) \ - ((MODE) != QImode && (MODE) != HImode \ - ? BASE_REGS : LO_REGS) - -#define INDEX_REG_CLASS LO_REGS - -/* When SMALL_REGISTER_CLASSES is nonzero, the compiler allows - registers explicitly used in the rtl to be used as spill registers - but prevents the compiler from extending the lifetime of these - registers. */ - -#define SMALL_REGISTER_CLASSES 1 - -#define REG_CLASS_FROM_LETTER(C) \ - ((C) == 'l' ? LO_REGS \ - : (C) == 'h' ? HI_REGS \ - : (C) == 'b' ? BASE_REGS \ - : (C) == 'k' ? STACK_REG \ - : NO_REGS) - -#define REGNO_OK_FOR_BASE_P(REGNO) \ - ((REGNO) < 8 \ - || (REGNO) == STACK_POINTER_REGNUM \ - || (unsigned) reg_renumber[REGNO] < 8 \ - || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM) - -#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \ - ((REGNO) < 8 \ - || (unsigned) reg_renumber[REGNO] < 8 \ - || (GET_MODE_SIZE (MODE) >= 4 \ - && ((REGNO) == STACK_POINTER_REGNUM \ - || (unsigned) reg_renumber[REGNO] == STACK_POINTER_REGNUM))) - -#define REGNO_OK_FOR_INDEX_P(REGNO) \ - ((REGNO) < 8 \ - || (unsigned) reg_renumber[REGNO] < 8) - -/* ??? This looks suspiciously wrong. */ -/* We need to leave BASE_REGS reloads alone, in order to avoid caller_save - lossage. Caller_saves requests a BASE_REGS reload (caller_save_spill_class) - and then later we verify that one was allocated. If PREFERRED_RELOAD_CLASS - says to allocate a LO_REGS spill instead, then this mismatch gives an - abort. Alternatively, this could be fixed by modifying BASE_REG_CLASS - to be LO_REGS instead of BASE_REGS. It is not clear what affect this - change would have. */ -/* ??? This looks even more suspiciously wrong. PREFERRED_RELOAD_CLASS - must always return a strict subset of the input class. Just blindly - returning LO_REGS is safe only if the input class is a superset of LO_REGS, - but there is no check for this. Added another exception for NONARG_LO_REGS - because it is not a superset of LO_REGS. */ -/* ??? We now use NONARG_LO_REGS for caller_save_spill_class, so the - comments about BASE_REGS are now obsolete. */ -#define PREFERRED_RELOAD_CLASS(X,CLASS) \ - ((CLASS) == BASE_REGS || (CLASS) == NONARG_LO_REGS ? (CLASS) \ - : LO_REGS) -/* - ((CONSTANT_P ((X)) && GET_CODE ((X)) != CONST_INT \ - && ! CONSTANT_POOL_ADDRESS_P((X))) ? NO_REGS \ - : (GET_CODE ((X)) == CONST_INT \ - && (unsigned HOST_WIDE_INT) INTVAL ((X)) > 255) ? NO_REGS \ - : LO_REGS) */ - -/* Must leave BASE_REGS and NONARG_LO_REGS reloads alone, see comment - above. */ -#define SECONDARY_RELOAD_CLASS(CLASS,MODE,X) \ - ((CLASS) != LO_REGS && (CLASS) != BASE_REGS && (CLASS) != NONARG_LO_REGS \ - ? ((true_regnum (X) == -1 ? LO_REGS \ - : (true_regnum (X) + HARD_REGNO_NREGS (0, MODE) > 8) ? LO_REGS \ - : NO_REGS)) \ - : NO_REGS) - -#define CLASS_MAX_NREGS(CLASS,MODE) HARD_REGNO_NREGS(0,(MODE)) - -int thumb_shiftable_const (); - -#define CONST_OK_FOR_LETTER_P(VAL,C) \ - ((C) == 'I' ? (unsigned HOST_WIDE_INT) (VAL) < 256 \ - : (C) == 'J' ? (VAL) > -256 && (VAL) <= 0 \ - : (C) == 'K' ? thumb_shiftable_const (VAL) \ - : (C) == 'L' ? (VAL) > -8 && (VAL) < 8 \ - : (C) == 'M' ? ((unsigned HOST_WIDE_INT) (VAL) < 1024 \ - && ((VAL) & 3) == 0) \ - : (C) == 'N' ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ - : (C) == 'O' ? ((VAL) >= -508 && (VAL) <= 508) \ - : 0) - -#define CONST_DOUBLE_OK_FOR_LETTER_P(VAL,C) 0 - -#define EXTRA_CONSTRAINT(X,C) \ - ((C) == 'Q' ? (GET_CODE (X) == MEM \ - && GET_CODE (XEXP (X, 0)) == LABEL_REF) : 0) - -/* Stack Layout and Calling Conventions */ - -#define STACK_GROWS_DOWNWARD 1 - -/* #define FRAME_GROWS_DOWNWARD 1 */ - -/* #define ARGS_GROW_DOWNWARD 1 */ - -#define STARTING_FRAME_OFFSET 0 - -#define FIRST_PARM_OFFSET(FNDECL) 0 - -/* Registers that address the stack frame */ - -#define STACK_POINTER_REGNUM 13 /* Defined by the TPCS. */ - -#define FRAME_POINTER_REGNUM 7 /* TPCS defines this as 11 but it does not really mean it. */ - -#define ARG_POINTER_REGNUM 16 /* A fake hard register that is eliminated later on. */ - -#define STATIC_CHAIN_REGNUM 9 - -#define FRAME_POINTER_REQUIRED 0 - -#define ELIMINABLE_REGS \ -{{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ - {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ - {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} - -/* On the Thumb we always want to perform the eliminations as we - actually only have one real register pointing to the stashed - variables: the stack pointer, and we never use the frame pointer. */ -#define CAN_ELIMINATE(FROM,TO) 1 - -/* Note: This macro must match the code in thumb_function_prologue() in thumb.c. */ -#define INITIAL_ELIMINATION_OFFSET(FROM,TO,OFFSET) \ -{ \ - (OFFSET) = 0; \ - if ((FROM) == ARG_POINTER_REGNUM) \ - { \ - int count_regs = 0; \ - int regno; \ - (OFFSET) += get_frame_size (); \ - for (regno = 8; regno < 13; regno++) \ - if (regs_ever_live[regno] && ! call_used_regs[regno]) \ - count_regs++; \ - if (count_regs) \ - (OFFSET) += 4 * count_regs; \ - count_regs = 0; \ - for (regno = 0; regno < 8; regno++) \ - if (regs_ever_live[regno] && ! call_used_regs[regno]) \ - count_regs++; \ - if (count_regs || ! leaf_function_p () || far_jump_used_p()) \ - (OFFSET) += 4 * (count_regs + 1); \ - if (TARGET_BACKTRACE) { \ - if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0)) \ - (OFFSET) += 20; \ - else \ - (OFFSET) += 16; } \ - } \ - if ((TO) == STACK_POINTER_REGNUM) \ - (OFFSET) += current_function_outgoing_args_size; \ -} - -/* Passing Arguments on the stack */ - -#define PROMOTE_PROTOTYPES 1 - -#define ACCUMULATE_OUTGOING_ARGS 1 - -#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 - -#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ - ((MODE) == VOIDmode \ - ? GEN_INT ((CUM).call_cookie) \ - : (NAMED) \ - ? ((CUM).nregs >= 16 ? 0 : gen_rtx (REG, MODE, (CUM).nregs / 4)) \ - : 0) - -#define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) \ - (((CUM).nregs < 16 && (CUM).nregs + (((MODE) == BLKmode) \ - ? int_size_in_bytes (TYPE) \ - : (HARD_REGNO_NREGS (0, (MODE)) \ - * 4)) > 16) \ - ? 4 - (CUM).nregs / 4 : 0) - -/* A C type for declaring a variable that is used as the first argument of - `FUNCTION_ARG' and other related values. For some target machines, the - type `int' suffices and can hold the number of bytes of argument so far. - - On the ARM, this is the number of bytes of arguments scanned so far. */ -typedef struct -{ - /* This is the number of registers of arguments scanned so far. */ - int nregs; - /* One of CALL_NORMAL, CALL_LONG or CALL_SHORT . */ - int call_cookie; -} CUMULATIVE_ARGS; - - -/* 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. - On the ARM, the offset starts at 0. */ -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ - ((CUM).nregs = (((FNTYPE) && aggregate_value_p (TREE_TYPE ((FNTYPE)))) \ - ? 4 : 0), \ - (CUM).call_cookie = \ - (((FNTYPE) && lookup_attribute ("short_call", TYPE_ATTRIBUTES (FNTYPE))) \ - ? CALL_SHORT \ - : (((FNTYPE) && lookup_attribute ("long_call", \ - TYPE_ATTRIBUTES (FNTYPE)))\ - || TARGET_LONG_CALLS) \ - ? CALL_LONG \ - : CALL_NORMAL)) - -/* 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) \ - (CUM).nregs += ((MODE) != BLKmode \ - ? (GET_MODE_SIZE (MODE) + 3) & ~3 \ - : (int_size_in_bytes (TYPE) + 3) & ~3) \ - -#define FUNCTION_ARG_REGNO_P(REGNO) \ - ((REGNO) >=0 && (REGNO) <= 3) - -#define FUNCTION_VALUE(VALTYPE,FUNC) gen_rtx (REG, TYPE_MODE (VALTYPE), 0) - -#define LIBCALL_VALUE(MODE) gen_rtx (REG, (MODE), 0) - -#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == 0) - - /* How large values are returned */ -/* A C expression which can inhibit the returning of certain function values - in registers, based on the type of value. */ -#define RETURN_IN_MEMORY(TYPE) thumb_return_in_memory (TYPE) - -/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return - values must be in memory. On the ARM, they need only do so if larger - than a word, or if they contain elements offset from zero in the struct. */ -#define DEFAULT_PCC_STRUCT_RETURN 0 - - -#define STRUCT_VALUE_REGNUM 0 - -#define FUNCTION_PROLOGUE(FILE,SIZE) thumb_function_prologue((FILE),(SIZE)) - -#define FUNCTION_EPILOGUE(FILE,SIZE) thumb_function_epilogue((FILE),(SIZE)) - -/* Implementing the Varargs Macros */ - -#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ -{ \ - extern int current_function_anonymous_args; \ - current_function_anonymous_args = 1; \ - if ((CUM).nregs < 16) \ - (PRETEND_SIZE) = 16 - (CUM).nregs; \ -} - -/* Trampolines for nested functions */ - -/* Output assembler code for a block containing the constant parts of - a trampoline, leaving space for the variable parts. - - On the Thumb we always switch into ARM mode to execute the trampoline. - Why - because it is easier. This code will always be branched to via - a BX instruction and since the compiler magically generates the address - of the function the linker has no opportunity to ensure that the - bottom bit is set. Thus the processor will be in ARM mode when it - reaches this code. So we duplicate the ARM trampoline code and add - a switch into Thumb mode as well. - - On the ARM, (if r8 is the static chain regnum, and remembering that - referencing pc adds an offset of 8) the trampoline looks like: - ldr r8, [pc, #0] - ldr pc, [pc] - .word static chain value - .word function's address - ??? FIXME: When the trampoline returns, r8 will be clobbered. */ -#define TRAMPOLINE_TEMPLATE(FILE) \ -{ \ - fprintf ((FILE), "\t.code 32\n"); \ - fprintf ((FILE), ".Ltrampoline_start:\n"); \ - fprintf ((FILE), "\tldr\t%s, [%spc, #8]\n", \ - reg_names[STATIC_CHAIN_REGNUM], REGISTER_PREFIX); \ - fprintf ((FILE), "\tldr\t%sip, [%spc, #8]\n", \ - REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf ((FILE), "\torr\t%sip, %sip, #1\n", \ - REGISTER_PREFIX, REGISTER_PREFIX); \ - fprintf ((FILE), "\tbx\t%sip\n", REGISTER_PREFIX); \ - fprintf ((FILE), "\t.word\t0\n"); \ - fprintf ((FILE), "\t.word\t0\n"); \ - fprintf ((FILE), "\t.code 16\n"); \ -} - -/* Length in units of the trampoline for entering a nested function. */ -#define TRAMPOLINE_SIZE 24 - -/* Alignment required for a trampoline in units. */ -#define TRAMPOLINE_ALIGN 4 - -#define INITIALIZE_TRAMPOLINE(ADDR,FNADDR,CHAIN) \ -{ \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 16)), \ - (CHAIN)); \ - emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((ADDR), 20)), \ - (FNADDR)); \ -} - - -/* Implicit Calls to Library Routines */ - -#define TARGET_MEM_FUNCTIONS 1 - -#define OVERRIDE_OPTIONS thumb_override_options () - - -/* Addressing Modes */ - -#define HAVE_POST_INCREMENT 1 - -#define CONSTANT_ADDRESS_P(X) \ - (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (X)) - -#define MAX_REGS_PER_ADDRESS 2 - -#ifdef REG_OK_STRICT - -#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) -#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) - -#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ - REGNO_MODE_OK_FOR_BASE_P (REGNO (X), MODE) - -#else /* REG_OK_STRICT */ - -#define REG_OK_FOR_BASE_P(X) \ - (REGNO (X) < 8 || REGNO (X) == STACK_POINTER_REGNUM \ - || (X) == arg_pointer_rtx \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER) - -#define REG_MODE_OK_FOR_BASE_P(X,MODE) \ - (REGNO (X) < 8 \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER \ - || (GET_MODE_SIZE (MODE) >= 4 \ - && (REGNO (X) == STACK_POINTER_REGNUM \ - || (X) == arg_pointer_rtx))) - -#define REG_OK_FOR_INDEX_P(X) \ - (REGNO (X) < 8 \ - || REGNO (X) >= FIRST_PSEUDO_REGISTER) - -#endif /* REG_OK_STRICT */ - -/* In a REG+REG address, both must be INDEX registers. */ -#define REG_OK_FOR_INDEXED_BASE_P(X) REG_OK_FOR_INDEX_P(X) - -#define LEGITIMATE_OFFSET(MODE,VAL) \ -(GET_MODE_SIZE (MODE) == 1 ? ((unsigned HOST_WIDE_INT) (VAL) < 32) \ - : GET_MODE_SIZE (MODE) == 2 ? ((unsigned HOST_WIDE_INT) (VAL) < 64 \ - && ((VAL) & 1) == 0) \ - : ((VAL) >= 0 && ((VAL) + GET_MODE_SIZE (MODE)) <= 128 \ - && ((VAL) & 3) == 0)) - -/* The AP may be eliminated to either the SP or the FP, so we use the - least common denominator, e.g. SImode, and offsets from 0 to 64. */ - -/* ??? Verify whether the above is the right approach. */ - -/* ??? Also, the FP may be eliminated to the SP, so perhaps that - needs special handling also. */ - -/* ??? Look at how the mips16 port solves this problem. It probably uses - better ways to solve some of these problems. */ - -/* Although it is not incorrect, we don't accept QImode and HImode - addresses based on the frame pointer or arg pointer until the reload pass starts. - This is so that eliminating such addresses into stack based ones - won't produce impossible code. */ -#define GO_IF_LEGITIMATE_ADDRESS(MODE,X,WIN) \ -{ \ - /* ??? Not clear if this is right. Experiment. */ \ - if (GET_MODE_SIZE (MODE) < 4 \ - && ! (reload_in_progress || reload_completed) \ - && (reg_mentioned_p (frame_pointer_rtx, X) \ - || reg_mentioned_p (arg_pointer_rtx, X) \ - || reg_mentioned_p (virtual_incoming_args_rtx, X) \ - || reg_mentioned_p (virtual_outgoing_args_rtx, X) \ - || reg_mentioned_p (virtual_stack_dynamic_rtx, X) \ - || reg_mentioned_p (virtual_stack_vars_rtx, X))) \ - ; \ - /* Accept any base register. SP only in SImode or larger. */ \ - else if (GET_CODE (X) == REG && REG_MODE_OK_FOR_BASE_P(X, MODE)) \ - goto WIN; \ - /* This is PC relative data before MACHINE_DEPENDENT_REORG runs. */ \ - else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X) \ - && CONSTANT_POOL_ADDRESS_P (X)) \ - goto WIN; \ - /* This is PC relative data after MACHINE_DEPENDENT_REORG runs. */ \ - else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed \ - && (GET_CODE (X) == LABEL_REF \ - || (GET_CODE (X) == CONST \ - && GET_CODE (XEXP (X, 0)) == PLUS \ - && GET_CODE (XEXP (XEXP (X, 0), 0)) == LABEL_REF \ - && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT))) \ - goto WIN; \ - /* Post-inc indexing only supported for SImode and larger. */ \ - else if (GET_CODE (X) == POST_INC && GET_MODE_SIZE (MODE) >= 4 \ - && GET_CODE (XEXP (X, 0)) == REG \ - && REG_OK_FOR_INDEX_P (XEXP (X, 0))) \ - goto WIN; \ - else if (GET_CODE (X) == PLUS) \ - { \ - /* REG+REG address can be any two index registers. */ \ - /* ??? REG+REG addresses have been completely disabled before \ - reload completes, because we do not have enough available \ - reload registers. We only have 3 guaranteed reload registers \ - (NONARG_LO_REGS - the frame pointer), but we need at least 4 \ - to support REG+REG addresses. We have left them enabled after \ - reload completes, in the hope that reload_cse_regs and related \ - routines will be able to create them after the fact. It is \ - probably possible to support REG+REG addresses with additional \ - reload work, but I do not not have enough time to attempt such \ - a change at this time. */ \ - /* ??? Normally checking the mode here is wrong, since it isn't \ - impossible to use REG+REG with DFmode. However, the movdf \ - pattern requires offsettable addresses, and REG+REG is not \ - offsettable, so it must be rejected somehow. Trying to use \ - 'o' fails, because offsettable_address_p does a QImode check. \ - QImode is not valid for stack addresses, and has a smaller \ - range for non-stack bases, and this causes valid addresses \ - to be rejected. So we just eliminate REG+REG here by checking \ - the mode. */ \ - /* We also disallow FRAME+REG addressing since we know that FRAME \ - will be replaced with STACK, and SP relative addressing only \ - permits SP+OFFSET. */ \ - if (GET_MODE_SIZE (MODE) <= 4 \ - /* ??? See comment above. */ \ - && reload_completed \ - && GET_CODE (XEXP (X, 0)) == REG \ - && GET_CODE (XEXP (X, 1)) == REG \ - && XEXP (X, 0) != frame_pointer_rtx \ - && XEXP (X, 1) != frame_pointer_rtx \ - && XEXP (X, 0) != virtual_stack_vars_rtx \ - && XEXP (X, 1) != virtual_stack_vars_rtx \ - && REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ - && REG_OK_FOR_INDEX_P (XEXP (X, 1))) \ - goto WIN; \ - /* REG+const has 5-7 bit offset for non-SP registers. */ \ - else if (GET_CODE (XEXP (X, 0)) == REG \ - && (REG_OK_FOR_INDEX_P (XEXP (X, 0)) \ - || XEXP (X, 0) == arg_pointer_rtx) \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ - goto WIN; \ - /* REG+const has 10 bit offset for SP, but only SImode and \ - larger is supported. */ \ - /* ??? Should probably check for DI/DFmode overflow here \ - just like GO_IF_LEGITIMATE_OFFSET does. */ \ - else if (GET_CODE (XEXP (X, 0)) == REG \ - && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \ - && GET_MODE_SIZE (MODE) >= 4 \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && (unsigned HOST_WIDE_INT) INTVAL (XEXP (X, 1)) < 1024 \ - && (INTVAL (XEXP (X, 1)) & 3) == 0) \ - goto WIN; \ - } \ -} - -/* ??? If an HImode FP+large_offset address is converted to an HImode - SP+large_offset address, then reload won't know how to fix it. It sees - only that SP isn't valid for HImode, and so reloads the SP into an index - register, but the resulting address is still invalid because the offset - is too big. We fix it here instead by reloading the entire address. */ -/* We could probably achieve better results by defining PROMOTE_MODE to help - cope with the variances between the Thumb's signed and unsigned byte and - halfword load instructions. */ -#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \ -{ \ - if (GET_CODE (X) == PLUS \ - && GET_MODE_SIZE (MODE) < 4 \ - && GET_CODE (XEXP (X, 0)) == REG \ - && XEXP (X, 0) == stack_pointer_rtx \ - && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && ! LEGITIMATE_OFFSET (MODE, INTVAL (XEXP (X, 1)))) \ - { \ - rtx orig_X = X; \ - X = copy_rtx (X); \ - push_reload (orig_X, NULL_RTX, &X, NULL_PTR, \ - BASE_REG_CLASS, \ - Pmode, VOIDmode, 0, 0, OPNUM, TYPE); \ - goto WIN; \ - } \ -} - -#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) - -#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) - -#define LEGITIMATE_CONSTANT_P(X) \ - (GET_CODE (X) == CONST_INT \ - || GET_CODE (X) == CONST_DOUBLE \ - || CONSTANT_ADDRESS_P (X)) - -/* Flags for the call/call_value rtl operations set up by function_arg. */ -#define CALL_NORMAL 0x00000000 /* No special processing. */ -#define CALL_LONG 0x00000001 /* Always call indirect. */ -#define CALL_SHORT 0x00000002 /* Never call indirect. */ - -#define ENCODE_SECTION_INFO(decl) \ -{ \ - ARM_ENCODE_CALL_TYPE (decl) \ -} - -/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS - is a valid machine specific attribute for DECL. - The attributes in ATTRIBUTES have previously been assigned to DECL. */ -int arm_valid_machine_type_attribute (/* union tree_node *, union tree_node *, - union tree_node *, - union tree_node * */); -#define VALID_MACHINE_TYPE_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ -arm_valid_machine_type_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) - -/* If we are referencing a function that is weak then encode a long call - flag in the function name, otherwise if the function is static or - or known to be defined in this file then encode a short call flag. - This macro is used inside the ENCODE_SECTION macro. */ -#define ARM_ENCODE_CALL_TYPE(decl) \ - if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd') \ - { \ - if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl)) \ - arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR); \ - else if (! TREE_PUBLIC (decl)) \ - arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR); \ - } - -/* Special characters prefixed to function names - in order to encode attribute like information. - Note, '@' and '*' have already been taken. */ -#define SHORT_CALL_FLAG_CHAR '^' -#define LONG_CALL_FLAG_CHAR '#' - -#define ENCODED_SHORT_CALL_ATTR_P(SYMBOL_NAME) \ - (*(SYMBOL_NAME) == SHORT_CALL_FLAG_CHAR) - -#define ENCODED_LONG_CALL_ATTR_P(SYMBOL_NAME) \ - (*(SYMBOL_NAME) == LONG_CALL_FLAG_CHAR) - -#ifndef SUBTARGET_NAME_ENCODING_LENGTHS -#define SUBTARGET_NAME_ENCODING_LENGTHS -#endif - -/* This is a C fragement for the inside of a switch statement. - Each case label should return the number of characters to - be stripped from the start of a function's name, if that - name starts with the indicated character. */ -#define ARM_NAME_ENCODING_LENGTHS \ - case SHORT_CALL_FLAG_CHAR: return 1; \ - case LONG_CALL_FLAG_CHAR: return 1; \ - case '*': return 1; \ - SUBTARGET_NAME_ENCODING_LENGTHS - -/* This has to be handled by a function because more than part of the - ARM backend uses function name prefixes to encode attributes. */ -#undef STRIP_NAME_ENCODING -#define STRIP_NAME_ENCODING(VAR, SYMBOL_NAME) \ - (VAR) = arm_strip_name_encoding (SYMBOL_NAME) - -/* This is how to output a reference to a user-level label named NAME. - `assemble_name' uses this. */ -#undef ASM_OUTPUT_LABELREF -#define ASM_OUTPUT_LABELREF(FILE, NAME) \ - asm_fprintf (FILE, "%U%s", arm_strip_name_encoding (NAME)) - - -/* Condition Code Status */ - -#define NOTICE_UPDATE_CC(EXP,INSN) \ -{ \ - if (get_attr_conds ((INSN)) != CONDS_UNCHANGED) \ - CC_STATUS_INIT; \ -} - - -/* Describing Relative Costs of Operations */ - -#define SLOW_BYTE_ACCESS 0 - -#define SLOW_UNALIGNED_ACCESS 1 - -#define NO_FUNCTION_CSE 1 - -#define NO_RECURSIVE_FUNCTION_CSE 1 - -#define REGISTER_MOVE_COST(FROM,TO) \ - (((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2) - -#define MEMORY_MOVE_COST(M,CLASS,IN) \ - ((GET_MODE_SIZE(M) < 4 ? 8 : 2 * GET_MODE_SIZE(M)) * (CLASS == LO_REGS ? 1 : 2)) - -/* This will allow better space optimization when compiling with -O */ -#define BRANCH_COST (optimize > 1 ? 1 : 0) - -#define RTX_COSTS(X,CODE,OUTER) \ - case MULT: \ - if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ - { \ - int cycles = 0; \ - unsigned HOST_WIDE_INT i = INTVAL (XEXP (X, 1)); \ - while (i) \ - { \ - i >>= 2; \ - cycles++; \ - } \ - return COSTS_N_INSNS (2) + cycles; \ - } \ - return COSTS_N_INSNS (1) + 16; \ - case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATERT: \ - case PLUS: case MINUS: case COMPARE: case NEG: case NOT: \ - return COSTS_N_INSNS (1); \ - case SET: \ - return (COSTS_N_INSNS (1) \ - + 4 * ((GET_CODE (SET_SRC (X)) == MEM) \ - + GET_CODE (SET_DEST (X)) == MEM)) - -#define CONST_COSTS(X,CODE,OUTER) \ - case CONST_INT: \ - if ((OUTER) == SET) \ - { \ - if ((unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ - return 0; \ - if (thumb_shiftable_const (INTVAL (X))) \ - return COSTS_N_INSNS (2); \ - return COSTS_N_INSNS (3); \ - } \ - else if (OUTER == PLUS \ - && INTVAL (X) < 256 && INTVAL (X) > -256) \ - return 0; \ - else if (OUTER == COMPARE \ - && (unsigned HOST_WIDE_INT) INTVAL (X) < 256) \ - return 0; \ - else if (OUTER == ASHIFT || OUTER == ASHIFTRT \ - || OUTER == LSHIFTRT) \ - return 0; \ - return COSTS_N_INSNS (2); \ - case CONST: \ - case CONST_DOUBLE: \ - case LABEL_REF: \ - case SYMBOL_REF: \ - return COSTS_N_INSNS(3); - -#define ADDRESS_COST(X) \ - ((GET_CODE (X) == REG \ - || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == REG \ - && GET_CODE (XEXP (X, 1)) == CONST_INT)) \ - ? 1 : 2) - - -/* Position Independent Code */ - -#define PRINT_OPERAND(STREAM,X,CODE) \ - thumb_print_operand((STREAM), (X), (CODE)) - -#define PRINT_OPERAND_ADDRESS(STREAM,X) \ -{ \ - if (GET_CODE ((X)) == REG) \ - fprintf ((STREAM), "[%s]", reg_names[REGNO ((X))]); \ - else if (GET_CODE ((X)) == POST_INC) \ - fprintf ((STREAM), "%s!", reg_names[REGNO (XEXP (X, 0))]); \ - else if (GET_CODE ((X)) == PLUS) \ - { \ - if (GET_CODE (XEXP ((X), 1)) == CONST_INT) \ - fprintf ((STREAM), "[%s, #%d]", \ - reg_names[REGNO (XEXP ((X), 0))], \ - (int) INTVAL (XEXP ((X), 1))); \ - else \ - fprintf ((STREAM), "[%s, %s]", \ - reg_names[REGNO (XEXP ((X), 0))], \ - reg_names[REGNO (XEXP ((X), 1))]); \ - } \ - else \ - output_addr_const ((STREAM), (X)); \ -} - -#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_')) - -/* Emit a special directive when defining a function name. - This is used by the assembler to assit with interworking. */ -#define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ - if (! is_called_in_ARM_mode (decl)) \ - fprintf (file, "\t.thumb_func\n") ; \ - else \ - fprintf (file, "\t.code\t32\n") ; \ - ASM_OUTPUT_LABEL (file, name) - -#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ - asm_fprintf ((STREAM), "\tpush {%R%s}\n", reg_names[(REGNO)]) - -#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ - fprintf ((STREAM), "\tpop {%R%s}\n", reg_names[(REGNO)]) - -#define FINAL_PRESCAN_INSN(INSN,OPVEC,NOPERANDS) \ - final_prescan_insn((INSN)) - -/* Controlling Debugging Information Format */ -#define DBX_REGISTER_NUMBER(REGNO) (REGNO) - -/* Specific options for DBX Output */ - -#define DBX_DEBUGGING_INFO 1 - -#define DEFAULT_GDB_EXTENSIONS 1 - - -/* Cross Compilation and Floating Point */ - -#define REAL_ARITHMETIC - - -/* Miscellaneous Parameters */ - -#define PREDICATE_CODES \ - {"s_register_operand", {SUBREG, REG}}, \ - {"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, - -#define CASE_VECTOR_MODE Pmode - -#define WORD_REGISTER_OPERATIONS - -#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND - -#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR - -#define EASY_DIV_EXPR TRUNC_DIV_EXPR - -#define MOVE_MAX 4 - -#define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) 1 - -#define STORE_FLAG_VALUE 1 - -#define Pmode SImode - -#define FUNCTION_MODE SImode - -#define DOLLARS_IN_IDENTIFIERS 0 - -#define NO_DOLLAR_IN_LABEL 1 - -#define HAVE_ATEXIT - -/* The literal pool needs to reside in the text area due to the - limited PC addressing range: */ -#define MACHINE_DEPENDENT_REORG(INSN) thumb_reorg ((INSN)) - - -/* Options specific to Thumb */ - -/* True if a return instruction can be used in this function. */ -int thumb_trivial_epilogue (); -#define USE_RETURN (reload_completed && thumb_trivial_epilogue ()) - -extern char * thumb_unexpanded_epilogue (); -extern char * output_move_mem_multiple (); -extern char * thumb_load_double_from_address (); -extern char * output_return (); -extern int far_jump_used_p(); -extern int is_called_in_ARM_mode (); - -char *arm_strip_name_encoding (/* const char * */); -int arm_is_longcall_p (/* rtx, int, int */); -int s_register_operand (/* register rtx op, enum machine_mode mode */); diff --git a/gcc/config/arm/thumb_020428.md b/gcc/config/arm/thumb_020428.md deleted file mode 100755 index dedf42e..0000000 --- a/gcc/config/arm/thumb_020428.md +++ /dev/null @@ -1,1194 +0,0 @@ -;; thumb.md Machine description for ARM/Thumb processors -;; Copyright (C) 1996, 1997, 1998, 2002 Free Software Foundation, Inc. -;; The basis of this contribution was generated by -;; Richard Earnshaw, Advanced RISC Machines Ltd - -;; This file is part of GNU CC. - -;; GNU CC is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. - -;; GNU CC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU CC; see the file COPYING. If not, write to -;; the Free Software Foundation, 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;; LENGTH of an instruction is 2 bytes -(define_attr "length" "" (const_int 2)) - -;; CONDS is set to UNCHANGED when an insn does not affect the condition codes -;; Most insns change the condition codes -(define_attr "conds" "changed,unchanged" (const_string "changed")) - -;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a -;; distant label. -(define_attr "far_jump" "yes,no" (const_string "no")) - -;; Start with move insns - -(define_expand "movsi" - [(set (match_operand:SI 0 "general_operand" "") - (match_operand:SI 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (SImode, operands[1]); - } -") - -(define_insn "*movsi_insn" - [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h") - (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))] - "register_operand (operands[0], SImode) - || register_operand (operands[1], SImode)" - "@ - add\\t%0, %1, #0 - mov\\t%0, %1 - # - # - ldmia\\t%1, {%0} - stmia\\t%0, {%1} - ldr\\t%0, %1 - str\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1" -[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")]) - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] - "thumb_shiftable_const (INTVAL (operands[1]))" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] - " -{ - unsigned HOST_WIDE_INT val = INTVAL (operands[1]); - unsigned HOST_WIDE_INT mask = 0xff; - int i; - for (i = 0; i < 25; i++) - if ((val & (mask << i)) == val) - break; - - if (i == 0) - FAIL; - - operands[1] = GEN_INT (val >> i); - operands[2] = GEN_INT (i); -}") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] - "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (neg:SI (match_dup 0)))] - " - operands[1] = GEN_INT (- INTVAL (operands[1])); -") - -;;(define_expand "reload_outsi" -;; [(set (match_operand:SI 2 "register_operand" "=&l") -;; (match_operand:SI 1 "register_operand" "h")) -;; (set (match_operand:SI 0 "reload_memory_operand" "=o") -;; (match_dup 2))] -;; "" -;; " -;;/* thumb_reload_out_si (operands); -;; DONE; */ -;;") - -(define_expand "movhi" - [(set (match_operand:HI 0 "general_operand" "") - (match_operand:HI 1 "general_operand" ""))] - "" - " -{ - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (HImode, operands[1]); - - /* ??? We shouldn't really get invalid addresses here, but this can - happen if we are passed a SP (never OK for HImode/QImode) or virtual - register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) - relative address. */ - /* ??? This should perhaps be fixed elsewhere, for instance, in - fixup_stack_1, by checking for other kinds of invalid addresses, - e.g. a bare reference to a virtual register. This may confuse the - alpha though, which must handle this case differently. */ - if (GET_CODE (operands[0]) == MEM - && ! memory_address_p (GET_MODE (operands[0]), - XEXP (operands[0], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[0], 0)); - operands[0] = change_address (operands[0], VOIDmode, temp); - } - if (GET_CODE (operands[1]) == MEM - && ! memory_address_p (GET_MODE (operands[1]), - XEXP (operands[1], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[1], 0)); - operands[1] = change_address (operands[1], VOIDmode, temp); - } - } - /* Handle loading a large integer during reload */ - else if (GET_CODE (operands[1]) == CONST_INT - && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) - { - /* Writing a constant to memory needs a scratch, which should - be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); - - operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } -}") - -(define_insn "*movhi_insn" - [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") - (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] - "register_operand (operands[0], HImode) - || register_operand (operands[1], HImode)" - "@ - add\\t%0, %1, #0 - ldrh\\t%0, %1 - strh\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1 - mov\\t%0, %1") - -(define_expand "movqi" - [(set (match_operand:QI 0 "general_operand" "") - (match_operand:QI 1 "general_operand" ""))] - "" - " -{ - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (QImode, operands[1]); - - /* ??? We shouldn't really get invalid addresses here, but this can - happen if we are passed a SP (never OK for HImode/QImode) or virtual - register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) - relative address. */ - /* ??? This should perhaps be fixed elsewhere, for instance, in - fixup_stack_1, by checking for other kinds of invalid addresses, - e.g. a bare reference to a virtual register. This may confuse the - alpha though, which must handle this case differently. */ - if (GET_CODE (operands[0]) == MEM - && ! memory_address_p (GET_MODE (operands[0]), - XEXP (operands[0], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[0], 0)); - operands[0] = change_address (operands[0], VOIDmode, temp); - } - if (GET_CODE (operands[1]) == MEM - && ! memory_address_p (GET_MODE (operands[1]), - XEXP (operands[1], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[1], 0)); - operands[1] = change_address (operands[1], VOIDmode, temp); - } - } - /* Handle loading a large integer during reload */ - else if (GET_CODE (operands[1]) == CONST_INT - && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) - { - /* Writing a constant to memory needs a scratch, which should - be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); - - operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } -}") - -(define_insn "*movqi_insn" - [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") - (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] - "register_operand (operands[0], QImode) - || register_operand (operands[1], QImode)" - "@ - add\\t%0, %1, #0 - ldrb\\t%0, %1 - strb\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1 - mov\\t%0, %1") - -(define_expand "movdi" - [(set (match_operand:DI 0 "general_operand" "") - (match_operand:DI 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (DImode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -;;; ??? This was originally identical to the movdf_insn pattern. -;;; ??? The 'i' constraint looks funny, but it should always be replaced by -;;; thumb_reorg with a memory reference. -(define_insn "*movdi_insn" - [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r") - (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] - "register_operand (operands[0], DImode) - || register_operand (operands[1], DImode)" - "* -{ - switch (which_alternative) - { - case 0: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; - return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; - case 1: - return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; - case 2: - operands[1] = GEN_INT (- INTVAL (operands[1])); - return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; - case 3: - return \"ldmia\\t%1, {%0, %H0}\"; - case 4: - return \"stmia\\t%0, {%1, %H1}\"; - case 5: - return thumb_load_double_from_address (operands); - case 6: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); - output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); - return \"\"; - case 7: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; - return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; - } -}"[(set_attr "length" "4,4,6,2,2,6,4,4")]) - -(define_expand "movdf" - [(set (match_operand:DF 0 "general_operand" "") - (match_operand:DF 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (DFmode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -;;; ??? This was originally identical to the movdi_insn pattern. -;;; ??? The 'F' constraint looks funny, but it should always be replaced by -;;; thumb_reorg with a memory reference. -(define_insn "*movdf_insn" - [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r") - (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] - "register_operand (operands[0], DFmode) - || register_operand (operands[1], DFmode)" - "* - switch (which_alternative) - { - case 0: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; - return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; - case 1: - return \"ldmia\\t%1, {%0, %H0}\"; - case 2: - return \"stmia\\t%0, {%1, %H1}\"; - case 3: - return thumb_load_double_from_address (operands); - case 4: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); - output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); - return \"\"; - case 5: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; - return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; - } -"[(set_attr "length" "4,2,2,6,4,4")]) - -(define_expand "movsf" - [(set (match_operand:SF 0 "general_operand" "") - (match_operand:SF 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (SFmode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -(define_insn "*movsf_insn" - [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") - (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] - "register_operand (operands[0], SFmode) - || register_operand (operands[1], SFmode)" - "@ - add\\t%0, %1, #0 - ldmia\\t%1, {%0} - stmia\\t%0, {%1} - ldr\\t%0, %1 - str\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1") - -;; Widening move insns - -(define_expand "zero_extendhisi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); - emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16))); - DONE; - } -") - -(define_insn "*zero_extendhisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] - "" - "ldrh\\t%0, %1") - -(define_expand "zero_extendqisi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); - emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24))); - DONE; - } -") - -(define_insn "*zero_extendqisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] - "" - "ldrb\\t%0, %1") - -(define_expand "extendhisi2" - [(parallel [(set (match_operand:SI 0 "s_register_operand" "") - (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:SI 2 ""))])] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); - emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16))); - DONE; - } -") - -(define_insn "*extendhisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) - (clobber (match_scratch:SI 2 "=&l"))] - "" - "* -{ - rtx ops[4]; - /* This code used to try to use 'V', and fix the address only if it was - offsettable, but this fails for e.g. REG+48 because 48 is outside the - range of QImode offsets, and offsettable_address_p does a QImode - address check. */ - - if (GET_CODE (XEXP (operands[1], 0)) == PLUS) - { - ops[1] = XEXP (XEXP (operands[1], 0), 0); - ops[2] = XEXP (XEXP (operands[1], 0), 1); - } - else - { - ops[1] = XEXP (operands[1], 0); - ops[2] = const0_rtx; - } - if (GET_CODE (ops[2]) == REG) - return \"ldrsh\\t%0, %1\"; - - ops[0] = operands[0]; - ops[3] = operands[2]; - output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); - return \"\"; -}" -[(set_attr "length" "4")]) - -(define_expand "extendqisi2" - [(set (match_operand:SI 0 "s_register_operand" "") - (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); - emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24))); - DONE; - } -") - -(define_insn "*extendqisi2_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] - "" - "* -{ - rtx ops[3]; - - if (which_alternative == 0) - return \"ldrsb\\t%0, %1\"; - ops[0] = operands[0]; - if (GET_CODE (XEXP (operands[1], 0)) == PLUS) - { - ops[1] = XEXP (XEXP (operands[1], 0), 0); - ops[2] = XEXP (XEXP (operands[1], 0), 1); - - if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG) - output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); - else if (GET_CODE (ops[1]) == REG) - { - if (REGNO (ops[1]) == REGNO (operands[0])) - output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - else - { - if (REGNO (ops[2]) == REGNO (operands[0])) - output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - } - else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0))) - { - output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - } - else - { - ops[1] = XEXP (operands[1], 0); - ops[2] = const0_rtx; - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - return \"\"; -}" -[(set_attr "length" "2,6")]) - -;; We don't really have extzv, but defining this using shifts helps -;; to reduce register pressure later on. - -(define_expand "extzv" - [(set (match_dup 4) - (ashift:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "const_int_operand" ""))) - (set (match_operand:SI 0 "register_operand" "") - (lshiftrt:SI (match_dup 4) - (match_operand:SI 3 "const_int_operand" "")))] - "" - " -{ - HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); - HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); - operands[3] = GEN_INT (rshift); - if (lshift == 0) - { - emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); - DONE; - } - operands[2] = GEN_INT (lshift); - operands[4] = gen_reg_rtx (SImode); -} -") - -;; Block-move insns - -(define_expand "movstrqi" - [(match_operand:BLK 0 "general_operand" "") - (match_operand:BLK 1 "general_operand" "") - (match_operand:SI 2 "" "") - (match_operand:SI 3 "const_int_operand" "")] - "" - " - if (INTVAL (operands[3]) != 4 - || GET_CODE (operands[2]) != CONST_INT - || INTVAL (operands[2]) > 48) - FAIL; - - thumb_expand_movstrqi (operands); - DONE; -") - -(define_insn "movmem12b" - [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) - (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) - (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) - (mem:SI (plus:SI (match_dup 1) (const_int 8)))) - (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) - (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) - (clobber (match_scratch:SI 2 "=&l")) - (clobber (match_scratch:SI 3 "=&l")) - (clobber (match_scratch:SI 4 "=&l"))] - "" - "* return output_move_mem_multiple (3, operands);" -[(set_attr "length" "4")]) - -(define_insn "movmem8b" - [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) - (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) - (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) - (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) - (clobber (match_scratch:SI 2 "=&l")) - (clobber (match_scratch:SI 3 "=&l"))] - "" - "* return output_move_mem_multiple (2, operands);" -[(set_attr "length" "4")]) - -;; Arithmetic insns - -(define_insn "adddi3" - [(set (match_operand:DI 0 "s_register_operand" "=l") - (plus:DI (match_operand:DI 1 "s_register_operand" "%0") - (match_operand:DI 2 "s_register_operand" "l")))] - "" - "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" -[(set_attr "conds" "changed") - (set_attr "length" "8")]) - -;; register group 'k' is a single register group containing only the stack -;; register. Trying to reload it will always fail catastrophically, -;; so never allow those alternatives to match if reloading is needed. -(define_insn "addsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l,l,*r,*h,l,!k") - (plus:SI (match_operand:SI 1 "s_register_operand" "%0,0,l,*0,*0,!k,!k") - (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] - "" - "* - static char *asms[] = -{ - \"add\\t%0, %0, %2\", - \"sub\\t%0, %0, #%n2\", - \"add\\t%0, %1, %2\", - \"add\\t%0, %0, %2\", - \"add\\t%0, %0, %2\", - \"add\\t%0, %1, %2\", - \"add\\t%0, %1, %2\" -}; - if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) < 0) - return \"sub\\t%0, %1, #%n2\"; - return asms[which_alternative]; -") - -; reloading and elimination of the frame pointer can sometimes cause this -; optimization to be missed. -(define_peephole - [(set (match_operand:SI 0 "register_operand" "=l") - (match_operand:SI 1 "const_int_operand" "M")) - (set (match_dup 0) - (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] - "REGNO (operands[2]) == STACK_POINTER_REGNUM - && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 - && (INTVAL (operands[1]) & 3) == 0" - "add\\t%0, %2, %1") - -(define_insn "subdi3" - [(set (match_operand:DI 0 "s_register_operand" "=l") - (minus:DI (match_operand:DI 1 "s_register_operand" "0") - (match_operand:DI 2 "s_register_operand" "l")))] - "" - "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" -[(set_attr "conds" "changed") - (set_attr "length" "8")]) - -(define_insn "subsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (minus:SI (match_operand:SI 1 "s_register_operand" "l") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "sub\\t%0, %1, %2") - -;; We must ensure that one input matches the output, and that the other input -;; does not match the output. Using 0 satisfies the first, and using & -;; satisfies the second. Unfortunately, this fails when operands 1 and 2 -;; are the same, because reload will make operand 0 match operand 1 without -;; realizing that this conflicts with operand 2. We fix this by adding another -;; alternative to match this case, and then `reload' it ourselves. This -;; alternative must come first. -(define_insn "mulsi3" - [(set (match_operand:SI 0 "s_register_operand" "=&l,&l,&l") - (mult:SI (match_operand:SI 1 "s_register_operand" "%l,*h,0") - (match_operand:SI 2 "s_register_operand" "l,l,l")))] - "" - "* -{ - if (which_alternative < 2) - return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; - else - return \"mul\\t%0, %0, %2\"; -}" - [(set_attr "length" "4,4,2")]) - -(define_insn "negsi2" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (neg:SI (match_operand:SI 1 "s_register_operand" "l")))] - "" - "neg\\t%0, %1") - -;; Logical insns - -(define_expand "andsi3" - [(set (match_operand:SI 0 "s_register_operand" "") - (and:SI (match_operand:SI 1 "s_register_operand" "") - (match_operand:SI 2 "nonmemory_operand" "")))] - "" - " - if (GET_CODE (operands[2]) != CONST_INT) - operands[2] = force_reg (SImode, operands[2]); - else - { - int i; - if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) - { - operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); - emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); - DONE; - } - - for (i = 9; i <= 31; i++) - if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) - { - emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), - const0_rtx)); - DONE; - } - else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) - { - rtx shift = GEN_INT (i); - rtx reg = gen_reg_rtx (SImode); - emit_insn (gen_lshrsi3 (reg, operands[1], shift)); - emit_insn (gen_ashlsi3 (operands[0], reg, shift)); - DONE; - } - - operands[2] = force_reg (SImode, operands[2]); - } -") - -(define_insn "*andsi3_insn" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (and:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "and\\t%0, %0, %2") - -(define_insn "bicsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "l")) - (match_operand:SI 2 "s_register_operand" "0")))] - "" - "bic\\t%0, %0, %1") - -(define_insn "iorsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (ior:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "orr\\t%0, %0, %2") - -(define_insn "xorsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (xor:SI (match_operand:SI 1 "s_register_operand" "%0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "eor\\t%0, %0, %2") - -(define_insn "one_cmplsi2" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (not:SI (match_operand:SI 1 "s_register_operand" "l")))] - "" - "mvn\\t%0, %1") - -;; Shift and rotation insns - -(define_insn "ashlsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (ashift:SI (match_operand:SI 1 "s_register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - lsl\\t%0, %1, %2 - lsl\\t%0, %0, %2") - -(define_insn "ashrsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - asr\\t%0, %1, %2 - asr\\t%0, %0, %2") - -(define_insn "lshrsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l,l") - (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - lsr\\t%0, %1, %2 - lsr\\t%0, %0, %2") - -(define_insn "rotrsi3" - [(set (match_operand:SI 0 "s_register_operand" "=l") - (rotatert:SI (match_operand:SI 1 "s_register_operand" "0") - (match_operand:SI 2 "s_register_operand" "l")))] - "" - "ror\\t%0, %0, %2") - -;; Comparison insns - -(define_expand "cmpsi" - [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "") - (match_operand:SI 1 "nonmemory_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG) - { - if (GET_CODE (operands[1]) != CONST_INT - || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256) - { - if (GET_CODE (operands[1]) != CONST_INT - || INTVAL (operands[1]) < -255 - || INTVAL (operands[1]) > 0) - operands[1] = force_reg (SImode, operands[1]); - else - { - operands[1] = force_reg (SImode, - GEN_INT (- INTVAL (operands[1]))); - emit_insn (gen_cmnsi (operands[0], operands[1])); - DONE; - } - } - } -") - -(define_insn "*cmpsi_insn" - [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l,*r,*h") - (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))] - "" - "@ - cmp\\t%0, %1 - cmp\\t%0, %1 - cmp\\t%0, %1") - -(define_insn "tstsi" - [(set (cc0) (match_operand:SI 0 "s_register_operand" "l"))] - "" - "cmp\\t%0, #0") - -(define_insn "cmnsi" - [(set (cc0) (compare (match_operand:SI 0 "s_register_operand" "l") - (neg:SI (match_operand:SI 1 "s_register_operand" "l"))))] - "" - "cmn\\t%0, %1") - -;; Jump insns - -(define_insn "jump" - [(set (pc) (label_ref (match_operand 0 "" "")))] - "" - "* - if (get_attr_length (insn) == 2) - return \"b\\t%l0\"; - return \"bl\\t%l0\\t%@ far jump\"; -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "4") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 2) - (const_int 4)))]) - - -(define_expand "beq" - [(set (pc) (if_then_else (eq (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bne" - [(set (pc) (if_then_else (ne (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bge" - [(set (pc) (if_then_else (ge (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "ble" - [(set (pc) (if_then_else (le (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgt" - [(set (pc) (if_then_else (gt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "blt" - [(set (pc) (if_then_else (lt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgeu" - [(set (pc) (if_then_else (geu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bleu" - [(set (pc) (if_then_else (leu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgtu" - [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bltu" - [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_insn "*cond_branch" - [(set (pc) (if_then_else (match_operator 1 "comparison_operator" - [(cc0) (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "* - switch (get_attr_length (insn)) - { - case 2: return \"b%d1\\t%l0\\t%@cond_branch\"; - case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\"; - default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\"; - } -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "6") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int -252)) - (le (minus (match_dup 0) (pc)) (const_int 254))) - (const_int 2) - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 4) - (const_int 6))))]) - -(define_insn "*cond_branch_reversed" - [(set (pc) (if_then_else (match_operator 1 "comparison_operator" - [(cc0) (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "* - switch (get_attr_length (insn)) - { - case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\"; - case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\"; - default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\"; - } - return \"\"; -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "6") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int -252)) - (le (minus (match_dup 0) (pc)) (const_int 254))) - (const_int 2) - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 4) - (const_int 6))))]) - -(define_insn "indirect_jump" - [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r"))] - "" - "mov\\tpc, %0") - -(define_insn "tablejump" - [(set (pc) (match_operand:SI 0 "s_register_operand" "l*r")) - (use (label_ref (match_operand 1 "" "")))] - "" - "mov\\tpc, %0") - -(define_insn "return" - [(return)] - "USE_RETURN" - "* return output_return ();" -[(set_attr "length" "18")]) - -;; Call insns - -(define_expand "call" - [(parallel - [(call (match_operand:SI 0 "memory_operand" "") - (match_operand 1 "" "")) - (use (match_operand 2 "" ""))])] - "" - " -{ - if (GET_CODE (XEXP (operands[0], 0)) != REG - && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0)) - XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); -}") - -(define_insn "*call_indirect" - [(parallel - [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) - (match_operand 1 "" "")) - (use (match_operand 2 "" ""))])] - "! TARGET_CALLER_INTERWORKING" - "bl\\t%__call_via_%0" -[(set_attr "length" "4")]) -;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version -;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set -;; the bottom bit of lr so that a function return (using bx) -;; would switch back into ARM mode... - -(define_insn "*call_indirect_interwork" - [(parallel - [(call (mem:SI (match_operand:SI 0 "s_register_operand" "l*r")) - (match_operand 1 "" "")) - (use (match_operand 2 "" ""))])] - "TARGET_CALLER_INTERWORKING" - "bl\\t%__interwork_call_via_%0" -[(set_attr "length" "4")]) - -(define_expand "call_value" - [(parallel - [(set (match_operand 0 "" "") - (call (match_operand 1 "memory_operand" "") - (match_operand 2 "" ""))) - (use (match_operand 3 "" ""))])] - "" - " -{ - if (GET_CODE (XEXP (operands[1], 0)) != REG - && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0)) - XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); -}") - -(define_insn "*call_value_indirect" - [(parallel - [(set (match_operand 0 "" "=l") - (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) - (match_operand 2 "" ""))) - (use (match_operand 3 "" ""))])] - "! TARGET_CALLER_INTERWORKING" - "bl\\t%__call_via_%1" -[(set_attr "length" "4")]) -;; See comment for call_indirect pattern - -(define_insn "*call_value_indirect_interwork" - [(parallel - [(set (match_operand 0 "" "=l") - (call (mem:SI (match_operand:SI 1 "s_register_operand" "l*r")) - (match_operand 2 "" ""))) - (use (match_operand 3 "" ""))])] - "TARGET_CALLER_INTERWORKING" - "bl\\t%__interwork_call_via_%1" -[(set_attr "length" "4")]) - - -(define_insn "*call_insn" - [(parallel - [(call (mem:SI (match_operand:SI 0 "" "i")) - (match_operand:SI 1 "" "")) - (use (match_operand 2 "" ""))])] - "GET_CODE (operands[0]) == SYMBOL_REF - && ! arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)" - "bl\\t%a0" -[(set_attr "length" "4")]) - -(define_insn "*call_value_insn" - [(parallel - [(set (match_operand 0 "s_register_operand" "=l") - (call (mem:SI (match_operand 1 "" "i")) - (match_operand 2 "" ""))) - (use (match_operand 3 "" ""))])] - "GET_CODE(operands[1]) == SYMBOL_REF - && ! arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)" - "bl\\t%a1" -[(set_attr "length" "4")]) - -;; Untyped call not required, since all funcs return in r0 - -;; Miscellaneous patterns - -(define_insn "nop" - [(clobber (const_int 0))] - "" - "mov\\tr8, r8") - -(define_insn "blockage" - [(unspec_volatile [(const_int 0)] 0)] - "" - "" - [(set_attr "length" "0")]) - -(define_expand "prologue" - [(const_int 0)] - "" - " - thumb_expand_prologue (); - DONE; -") - -(define_expand "epilogue" - [(unspec_volatile [(const_int 0)] 1)] - "! thumb_trivial_epilogue ()" - " - thumb_expand_epilogue (); -") - -(define_insn "*epilogue_insns" - [(unspec_volatile [(const_int 0)] 1)] - "" - "* - return thumb_unexpanded_epilogue (); -" -[(set_attr "length" "42")]) - -;; Special patterns for dealing with the constant pool - -(define_insn "consttable_4" - [(unspec_volatile [(match_operand 0 "" "")] 2)] - "" - "* -{ - switch (GET_MODE_CLASS (GET_MODE (operands[0]))) - { - case MODE_FLOAT: - { - union real_extract u; - bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); - assemble_real (u.d, GET_MODE (operands[0])); - break; - } - default: - assemble_integer (operands[0], 4, 1); - break; - } - return \"\"; -}" -[(set_attr "length" "4")]) - -(define_insn "consttable_8" - [(unspec_volatile [(match_operand 0 "" "")] 3)] - "" - "* -{ - switch (GET_MODE_CLASS (GET_MODE (operands[0]))) - { - case MODE_FLOAT: - { - union real_extract u; - bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); - assemble_real (u.d, GET_MODE (operands[0])); - break; - } - default: - assemble_integer (operands[0], 8, 1); - break; - } - return \"\"; -}" -[(set_attr "length" "8")]) - -(define_insn "consttable_end" - [(unspec_volatile [(const_int 0)] 4)] - "" - "* - /* Nothing to do (currently). */ - return \"\"; -") - -(define_insn "align_4" - [(unspec_volatile [(const_int 0)] 5)] - "" - "* - assemble_align (32); - return \"\"; -") diff --git a/gcc/config/arm/thumb_981111.md b/gcc/config/arm/thumb_981111.md deleted file mode 100755 index 93d0c05..0000000 --- a/gcc/config/arm/thumb_981111.md +++ /dev/null @@ -1,1166 +0,0 @@ -;; thumb.md Machine description for ARM/Thumb processors -;; Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. -;; The basis of this contribution was generated by -;; Richard Earnshaw, Advanced RISC Machines Ltd - -;; This file is part of GNU CC. - -;; GNU CC is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. - -;; GNU CC is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU CC; see the file COPYING. If not, write to -;; the Free Software Foundation, 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;; LENGTH of an instruction is 2 bytes -(define_attr "length" "" (const_int 2)) - -;; CONDS is set to UNCHANGED when an insn does not affect the condition codes -;; Most insns change the condition codes -(define_attr "conds" "changed,unchanged" (const_string "changed")) - -;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a -;; distant label. -(define_attr "far_jump" "yes,no" (const_string "no")) - -;; Start with move insns - -(define_expand "movsi" - [(set (match_operand:SI 0 "general_operand" "") - (match_operand:SI 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (SImode, operands[1]); - } -") - -(define_insn "*movsi_insn" - [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h") - (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))] - "register_operand (operands[0], SImode) - || register_operand (operands[1], SImode)" - "@ - add\\t%0, %1, #0 - mov\\t%0, %1 - # - # - ldmia\\t%1, {%0} - stmia\\t%0, {%1} - ldr\\t%0, %1 - str\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1" -[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")]) - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] - "thumb_shiftable_const (INTVAL (operands[1]))" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))] - " -{ - unsigned HOST_WIDE_INT val = INTVAL (operands[1]); - unsigned HOST_WIDE_INT mask = 0xff; - int i; - for (i = 0; i < 25; i++) - if ((val & (mask << i)) == val) - break; - - if (i == 0) - FAIL; - - operands[1] = GEN_INT (val >> i); - operands[2] = GEN_INT (i); -}") - -(define_split - [(set (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] - "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256" - [(set (match_dup 0) (match_dup 1)) - (set (match_dup 0) (neg:SI (match_dup 0)))] - " - operands[1] = GEN_INT (- INTVAL (operands[1])); -") - -;;(define_expand "reload_outsi" -;; [(set (match_operand:SI 2 "register_operand" "=&l") -;; (match_operand:SI 1 "register_operand" "h")) -;; (set (match_operand:SI 0 "reload_memory_operand" "=o") -;; (match_dup 2))] -;; "" -;; " -;;/* thumb_reload_out_si (operands); -;; DONE; */ -;;") - -(define_expand "movhi" - [(set (match_operand:HI 0 "general_operand" "") - (match_operand:HI 1 "general_operand" ""))] - "" - " -{ - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (HImode, operands[1]); - - /* ??? We shouldn't really get invalid addresses here, but this can - happen if we are passed a SP (never OK for HImode/QImode) or virtual - register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) - relative address. */ - /* ??? This should perhaps be fixed elsewhere, for instance, in - fixup_stack_1, by checking for other kinds of invalid addresses, - e.g. a bare reference to a virtual register. This may confuse the - alpha though, which must handle this case differently. */ - if (GET_CODE (operands[0]) == MEM - && ! memory_address_p (GET_MODE (operands[0]), - XEXP (operands[0], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[0], 0)); - operands[0] = change_address (operands[0], VOIDmode, temp); - } - if (GET_CODE (operands[1]) == MEM - && ! memory_address_p (GET_MODE (operands[1]), - XEXP (operands[1], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[1], 0)); - operands[1] = change_address (operands[1], VOIDmode, temp); - } - } - /* Handle loading a large integer during reload */ - else if (GET_CODE (operands[1]) == CONST_INT - && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) - { - /* Writing a constant to memory needs a scratch, which should - be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); - - operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } -}") - -(define_insn "*movhi_insn" - [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") - (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))] - "register_operand (operands[0], HImode) - || register_operand (operands[1], HImode)" - "@ - add\\t%0, %1, #0 - ldrh\\t%0, %1 - strh\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1 - mov\\t%0, %1") - -(define_expand "movqi" - [(set (match_operand:QI 0 "general_operand" "") - (match_operand:QI 1 "general_operand" ""))] - "" - " -{ - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (QImode, operands[1]); - - /* ??? We shouldn't really get invalid addresses here, but this can - happen if we are passed a SP (never OK for HImode/QImode) or virtual - register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode) - relative address. */ - /* ??? This should perhaps be fixed elsewhere, for instance, in - fixup_stack_1, by checking for other kinds of invalid addresses, - e.g. a bare reference to a virtual register. This may confuse the - alpha though, which must handle this case differently. */ - if (GET_CODE (operands[0]) == MEM - && ! memory_address_p (GET_MODE (operands[0]), - XEXP (operands[0], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[0], 0)); - operands[0] = change_address (operands[0], VOIDmode, temp); - } - if (GET_CODE (operands[1]) == MEM - && ! memory_address_p (GET_MODE (operands[1]), - XEXP (operands[1], 0))) - { - rtx temp = copy_to_reg (XEXP (operands[1], 0)); - operands[1] = change_address (operands[1], VOIDmode, temp); - } - } - /* Handle loading a large integer during reload */ - else if (GET_CODE (operands[1]) == CONST_INT - && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I')) - { - /* Writing a constant to memory needs a scratch, which should - be handled with SECONDARY_RELOADs. */ - if (GET_CODE (operands[0]) != REG) - abort (); - - operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0); - emit_insn (gen_movsi (operands[0], operands[1])); - DONE; - } -}") - -(define_insn "*movqi_insn" - [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l") - (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))] - "register_operand (operands[0], QImode) - || register_operand (operands[1], QImode)" - "@ - add\\t%0, %1, #0 - ldrb\\t%0, %1 - strb\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1 - mov\\t%0, %1") - -(define_expand "movdi" - [(set (match_operand:DI 0 "general_operand" "") - (match_operand:DI 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (DImode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -;;; ??? This was originally identical to the movdf_insn pattern. -;;; ??? The 'i' constraint looks funny, but it should always be replaced by -;;; thumb_reorg with a memory reference. -(define_insn "*movdi_insn" - [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r") - (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))] - "register_operand (operands[0], DImode) - || register_operand (operands[1], DImode)" - "* -{ - switch (which_alternative) - { - case 0: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; - return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; - case 1: - return \"mov\\t%Q0, %1\;mov\\t%R0, #0\"; - case 2: - operands[1] = GEN_INT (- INTVAL (operands[1])); - return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\"; - case 3: - return \"ldmia\\t%1, {%0, %H0}\"; - case 4: - return \"stmia\\t%0, {%1, %H1}\"; - case 5: - return thumb_load_double_from_address (operands); - case 6: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); - output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); - return \"\"; - case 7: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; - return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; - } -}"[(set_attr "length" "4,4,6,2,2,6,4,4")]) - -(define_expand "movdf" - [(set (match_operand:DF 0 "general_operand" "") - (match_operand:DF 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (DFmode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -;;; ??? This was originally identical to the movdi_insn pattern. -;;; ??? The 'F' constraint looks funny, but it should always be replaced by -;;; thumb_reorg with a memory reference. -(define_insn "*movdf_insn" - [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r") - (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))] - "register_operand (operands[0], DFmode) - || register_operand (operands[1], DFmode)" - "* - switch (which_alternative) - { - case 0: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\"; - return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\"; - case 1: - return \"ldmia\\t%1, {%0, %H0}\"; - case 2: - return \"stmia\\t%0, {%1, %H1}\"; - case 3: - return thumb_load_double_from_address (operands); - case 4: - operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4)); - output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands); - return \"\"; - case 5: - if (REGNO (operands[1]) == REGNO (operands[0]) + 1) - return \"mov\\t%0, %1\;mov\\t%H0, %H1\"; - return \"mov\\t%H0, %H1\;mov\\t%0, %1\"; - } -"[(set_attr "length" "4,2,2,6,4,4")]) - -(define_expand "movsf" - [(set (match_operand:SF 0 "general_operand" "") - (match_operand:SF 1 "general_operand" ""))] - "" - " - if (! (reload_in_progress || reload_completed)) - { - if (GET_CODE (operands[0]) != REG) - operands[1] = force_reg (SFmode, operands[1]); - } -") - -;;; ??? This should have alternatives for constants. -(define_insn "*movsf_insn" - [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h") - (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))] - "register_operand (operands[0], SFmode) - || register_operand (operands[1], SFmode)" - "@ - add\\t%0, %1, #0 - ldmia\\t%1, {%0} - stmia\\t%0, {%1} - ldr\\t%0, %1 - str\\t%1, %0 - mov\\t%0, %1 - mov\\t%0, %1") - -;; Widening move insns - -(define_expand "zero_extendhisi2" - [(set (match_operand:SI 0 "register_operand" "") - (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); - emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16))); - DONE; - } -") - -(define_insn "*zero_extendhisi2_insn" - [(set (match_operand:SI 0 "register_operand" "=l") - (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))] - "" - "ldrh\\t%0, %1") - -(define_expand "zero_extendqisi2" - [(set (match_operand:SI 0 "register_operand" "") - (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); - emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24))); - DONE; - } -") - -(define_insn "*zero_extendqisi2_insn" - [(set (match_operand:SI 0 "register_operand" "=l") - (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))] - "" - "ldrb\\t%0, %1") - -(define_expand "extendhisi2" - [(parallel [(set (match_operand:SI 0 "register_operand" "") - (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" ""))) - (clobber (match_scratch:SI 2 ""))])] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (HImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16))); - emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16))); - DONE; - } -") - -(define_insn "*extendhisi2_insn" - [(set (match_operand:SI 0 "register_operand" "=l") - (sign_extend:SI (match_operand:HI 1 "memory_operand" "m"))) - (clobber (match_scratch:SI 2 "=&l"))] - "" - "* -{ - rtx ops[4]; - /* This code used to try to use 'V', and fix the address only if it was - offsettable, but this fails for e.g. REG+48 because 48 is outside the - range of QImode offsets, and offsettable_address_p does a QImode - address check. */ - - if (GET_CODE (XEXP (operands[1], 0)) == PLUS) - { - ops[1] = XEXP (XEXP (operands[1], 0), 0); - ops[2] = XEXP (XEXP (operands[1], 0), 1); - } - else - { - ops[1] = XEXP (operands[1], 0); - ops[2] = const0_rtx; - } - if (GET_CODE (ops[2]) == REG) - return \"ldrsh\\t%0, %1\"; - - ops[0] = operands[0]; - ops[3] = operands[2]; - output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops); - return \"\"; -}" -[(set_attr "length" "4")]) - -(define_expand "extendqisi2" - [(set (match_operand:SI 0 "register_operand" "") - (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != MEM) - { - rtx temp = gen_reg_rtx (SImode); - - operands[1] = force_reg (QImode, operands[1]); - operands[1] = gen_lowpart (SImode, operands[1]); - emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24))); - emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24))); - DONE; - } -") - -(define_insn "*extendqisi2_insn" - [(set (match_operand:SI 0 "register_operand" "=l,l") - (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))] - "" - "* -{ - rtx ops[3]; - - if (which_alternative == 0) - return \"ldrsb\\t%0, %1\"; - ops[0] = operands[0]; - if (GET_CODE (XEXP (operands[1], 0)) == PLUS) - { - ops[1] = XEXP (XEXP (operands[1], 0), 0); - ops[2] = XEXP (XEXP (operands[1], 0), 1); - - if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG) - output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops); - else if (GET_CODE (ops[1]) == REG) - { - if (REGNO (ops[1]) == REGNO (operands[0])) - output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - else - { - if (REGNO (ops[2]) == REGNO (operands[0])) - output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - else - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - } - else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0))) - { - output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops); - } - else - { - ops[1] = XEXP (operands[1], 0); - ops[2] = const0_rtx; - output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops); - } - return \"\"; -}" -[(set_attr "length" "2,6")]) - -;; We don't really have extzv, but defining this using shifts helps -;; to reduce register pressure later on. - -(define_expand "extzv" - [(set (match_dup 4) - (ashift:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "const_int_operand" ""))) - (set (match_operand:SI 0 "register_operand" "") - (lshiftrt:SI (match_dup 4) - (match_operand:SI 3 "const_int_operand" "")))] - "" - " -{ - HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]); - HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]); - operands[3] = GEN_INT (rshift); - if (lshift == 0) - { - emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3])); - DONE; - } - operands[2] = GEN_INT (lshift); - operands[4] = gen_reg_rtx (SImode); -} -") - -;; Block-move insns - -(define_expand "movstrqi" - [(match_operand:BLK 0 "general_operand" "") - (match_operand:BLK 1 "general_operand" "") - (match_operand:SI 2 "" "") - (match_operand:SI 3 "const_int_operand" "")] - "" - " - if (INTVAL (operands[3]) != 4 - || GET_CODE (operands[2]) != CONST_INT - || INTVAL (operands[2]) > 48) - FAIL; - - thumb_expand_movstrqi (operands); - DONE; -") - -(define_insn "movmem12b" - [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) - (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) - (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 8))) - (mem:SI (plus:SI (match_dup 1) (const_int 8)))) - (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12))) - (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12))) - (clobber (match_scratch:SI 2 "=&l")) - (clobber (match_scratch:SI 3 "=&l")) - (clobber (match_scratch:SI 4 "=&l"))] - "" - "* return output_move_mem_multiple (3, operands);" -[(set_attr "length" "4")]) - -(define_insn "movmem8b" - [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l")) - (mem:SI (match_operand:SI 1 "register_operand" "+&l"))) - (set (mem:SI (plus:SI (match_dup 0) (const_int 4))) - (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8))) - (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8))) - (clobber (match_scratch:SI 2 "=&l")) - (clobber (match_scratch:SI 3 "=&l"))] - "" - "* return output_move_mem_multiple (2, operands);" -[(set_attr "length" "4")]) - -;; Arithmetic insns - -(define_insn "adddi3" - [(set (match_operand:DI 0 "register_operand" "=l") - (plus:DI (match_operand:DI 1 "register_operand" "%0") - (match_operand:DI 2 "register_operand" "l")))] - "" - "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2" -[(set_attr "conds" "changed") - (set_attr "length" "8")]) - -;; register group 'k' is a single register group containing only the stack -;; register. Trying to reload it will always fail catastrophically, -;; so never allow those alternatives to match if reloading is needed. -(define_insn "addsi3" - [(set (match_operand:SI 0 "register_operand" "=l,l,l,*r,*h,l,!k") - (plus:SI (match_operand:SI 1 "register_operand" "%0,0,l,*0,*0,!k,!k") - (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))] - "" - "* - static char *asms[] = -{ - \"add\\t%0, %0, %2\", - \"sub\\t%0, %0, #%n2\", - \"add\\t%0, %1, %2\", - \"add\\t%0, %0, %2\", - \"add\\t%0, %0, %2\", - \"add\\t%0, %1, %2\", - \"add\\t%0, %1, %2\" -}; - if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT - && INTVAL (operands[2]) < 0) - return \"sub\\t%0, %1, #%n2\"; - return asms[which_alternative]; -") - -; reloading and elimination of the frame pointer can sometimes cause this -; optimization to be missed. -(define_peephole - [(set (match_operand:SI 0 "register_operand" "=l") - (match_operand:SI 1 "const_int_operand" "M")) - (set (match_dup 0) - (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))] - "REGNO (operands[2]) == STACK_POINTER_REGNUM - && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024 - && (INTVAL (operands[1]) & 3) == 0" - "add\\t%0, %2, %1") - -(define_insn "subdi3" - [(set (match_operand:DI 0 "register_operand" "=l") - (minus:DI (match_operand:DI 1 "register_operand" "0") - (match_operand:DI 2 "register_operand" "l")))] - "" - "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2" -[(set_attr "conds" "changed") - (set_attr "length" "8")]) - -(define_insn "subsi3" - [(set (match_operand:SI 0 "register_operand" "=l") - (minus:SI (match_operand:SI 1 "register_operand" "l") - (match_operand:SI 2 "register_operand" "l")))] - "" - "sub\\t%0, %1, %2") - -;; We must ensure that one input matches the output, and that the other input -;; does not match the output. Using 0 satisfies the first, and using & -;; satisfies the second. Unfortunately, this fails when operands 1 and 2 -;; are the same, because reload will make operand 0 match operand 1 without -;; realizing that this conflicts with operand 2. We fix this by adding another -;; alternative to match this case, and then `reload' it ourselves. This -;; alternative must come first. -(define_insn "mulsi3" - [(set (match_operand:SI 0 "register_operand" "=&l,&l,&l") - (mult:SI (match_operand:SI 1 "register_operand" "%l,*h,0") - (match_operand:SI 2 "register_operand" "l,l,l")))] - "" - "* -{ - if (which_alternative < 2) - return \"mov\\t%0, %1\;mul\\t%0, %0, %2\"; - else - return \"mul\\t%0, %0, %2\"; -}" - [(set_attr "length" "4,4,2")]) - -(define_insn "negsi2" - [(set (match_operand:SI 0 "register_operand" "=l") - (neg:SI (match_operand:SI 1 "register_operand" "l")))] - "" - "neg\\t%0, %1") - -;; Logical insns - -(define_expand "andsi3" - [(set (match_operand:SI 0 "register_operand" "") - (and:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "nonmemory_operand" "")))] - "" - " - if (GET_CODE (operands[2]) != CONST_INT) - operands[2] = force_reg (SImode, operands[2]); - else - { - int i; - if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256) - { - operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2]))); - emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1])); - DONE; - } - - for (i = 9; i <= 31; i++) - if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2])) - { - emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i), - const0_rtx)); - DONE; - } - else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2])) - { - rtx shift = GEN_INT (i); - rtx reg = gen_reg_rtx (SImode); - emit_insn (gen_lshrsi3 (reg, operands[1], shift)); - emit_insn (gen_ashlsi3 (operands[0], reg, shift)); - DONE; - } - - operands[2] = force_reg (SImode, operands[2]); - } -") - -(define_insn "*andsi3_insn" - [(set (match_operand:SI 0 "register_operand" "=l") - (and:SI (match_operand:SI 1 "register_operand" "%0") - (match_operand:SI 2 "register_operand" "l")))] - "" - "and\\t%0, %0, %2") - -(define_insn "bicsi3" - [(set (match_operand:SI 0 "register_operand" "=l") - (and:SI (not:SI (match_operand:SI 1 "register_operand" "l")) - (match_operand:SI 2 "register_operand" "0")))] - "" - "bic\\t%0, %0, %1") - -(define_insn "iorsi3" - [(set (match_operand:SI 0 "register_operand" "=l") - (ior:SI (match_operand:SI 1 "register_operand" "%0") - (match_operand:SI 2 "register_operand" "l")))] - "" - "orr\\t%0, %0, %2") - -(define_insn "xorsi3" - [(set (match_operand:SI 0 "register_operand" "=l") - (xor:SI (match_operand:SI 1 "register_operand" "%0") - (match_operand:SI 2 "register_operand" "l")))] - "" - "eor\\t%0, %0, %2") - -(define_insn "one_cmplsi2" - [(set (match_operand:SI 0 "register_operand" "=l") - (not:SI (match_operand:SI 1 "register_operand" "l")))] - "" - "mvn\\t%0, %1") - -;; Shift and rotation insns - -(define_insn "ashlsi3" - [(set (match_operand:SI 0 "register_operand" "=l,l") - (ashift:SI (match_operand:SI 1 "register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - lsl\\t%0, %1, %2 - lsl\\t%0, %0, %2") - -(define_insn "ashrsi3" - [(set (match_operand:SI 0 "register_operand" "=l,l") - (ashiftrt:SI (match_operand:SI 1 "register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - asr\\t%0, %1, %2 - asr\\t%0, %0, %2") - -(define_insn "lshrsi3" - [(set (match_operand:SI 0 "register_operand" "=l,l") - (lshiftrt:SI (match_operand:SI 1 "register_operand" "l,0") - (match_operand:SI 2 "nonmemory_operand" "N,l")))] - "" - "@ - lsr\\t%0, %1, %2 - lsr\\t%0, %0, %2") - -(define_insn "rotrsi3" - [(set (match_operand:SI 0 "register_operand" "=l") - (rotatert:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "register_operand" "l")))] - "" - "ror\\t%0, %0, %2") - -;; Comparison insns - -(define_expand "cmpsi" - [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "nonmemory_operand" "")))] - "" - " - if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG) - { - if (GET_CODE (operands[1]) != CONST_INT - || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256) - { - if (GET_CODE (operands[1]) != CONST_INT - || INTVAL (operands[1]) < -255 - || INTVAL (operands[1]) > 0) - operands[1] = force_reg (SImode, operands[1]); - else - { - operands[1] = force_reg (SImode, - GEN_INT (- INTVAL (operands[1]))); - emit_insn (gen_cmnsi (operands[0], operands[1])); - DONE; - } - } - } -") - -(define_insn "*cmpsi_insn" - [(set (cc0) (compare (match_operand:SI 0 "register_operand" "l,*r,*h") - (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))] - "" - "@ - cmp\\t%0, %1 - cmp\\t%0, %1 - cmp\\t%0, %1") - -(define_insn "tstsi" - [(set (cc0) (match_operand:SI 0 "register_operand" "l"))] - "" - "cmp\\t%0, #0") - -(define_insn "cmnsi" - [(set (cc0) (compare (match_operand:SI 0 "register_operand" "l") - (neg:SI (match_operand:SI 1 "register_operand" "l"))))] - "" - "cmn\\t%0, %1") - -;; Jump insns - -(define_insn "jump" - [(set (pc) (label_ref (match_operand 0 "" "")))] - "" - "* - if (get_attr_length (insn) == 2) - return \"b\\t%l0\"; - return \"bl\\t%l0\\t%@ far jump\"; -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "4") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 2) - (const_int 4)))]) - - -(define_expand "beq" - [(set (pc) (if_then_else (eq (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bne" - [(set (pc) (if_then_else (ne (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bge" - [(set (pc) (if_then_else (ge (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "ble" - [(set (pc) (if_then_else (le (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgt" - [(set (pc) (if_then_else (gt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "blt" - [(set (pc) (if_then_else (lt (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgeu" - [(set (pc) (if_then_else (geu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bleu" - [(set (pc) (if_then_else (leu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bgtu" - [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_expand "bltu" - [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "") - -(define_insn "*cond_branch" - [(set (pc) (if_then_else (match_operator 1 "comparison_operator" - [(cc0) (const_int 0)]) - (label_ref (match_operand 0 "" "")) - (pc)))] - "" - "* - switch (get_attr_length (insn)) - { - case 2: return \"b%d1\\t%l0\\t%@cond_branch\"; - case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\"; - default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\"; - } -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "6") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int -252)) - (le (minus (match_dup 0) (pc)) (const_int 254))) - (const_int 2) - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 4) - (const_int 6))))]) - -(define_insn "*cond_branch_reversed" - [(set (pc) (if_then_else (match_operator 1 "comparison_operator" - [(cc0) (const_int 0)]) - (pc) - (label_ref (match_operand 0 "" ""))))] - "" - "* - switch (get_attr_length (insn)) - { - case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\"; - case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\"; - default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\"; - } - return \"\"; -"[(set (attr "far_jump") - (if_then_else (eq_attr "length" "6") - (const_string "yes") - (const_string "no"))) - (set (attr "length") - (if_then_else - (and (ge (minus (match_dup 0) (pc)) (const_int -252)) - (le (minus (match_dup 0) (pc)) (const_int 254))) - (const_int 2) - (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) - (le (minus (match_dup 0) (pc)) (const_int 2044))) - (const_int 4) - (const_int 6))))]) - -(define_insn "indirect_jump" - [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))] - "" - "mov\\tpc, %0") - -(define_insn "tablejump" - [(set (pc) (match_operand:SI 0 "register_operand" "l*r")) - (use (label_ref (match_operand 1 "" "")))] - "" - "mov\\tpc, %0") - -(define_insn "return" - [(return)] - "USE_RETURN" - "* return output_return ();" -[(set_attr "length" "18")]) - -;; Call insns - -(define_expand "call" - [(call (match_operand:SI 0 "memory_operand" "") - (match_operand 1 "" ""))] - "" - "") - -(define_insn "*call_indirect" - [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) - (match_operand 1 "" ""))] - "! TARGET_CALLER_INTERWORKING" - "bl\\t%__call_via_%0" -[(set_attr "length" "4")]) -;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version -;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set -;; the bottom bit of lr so that a function return (using bx) -;; would switch back into ARM mode... - -(define_insn "*call_indirect_interwork" - [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) - (match_operand 1 "" ""))] - "TARGET_CALLER_INTERWORKING" - "bl\\t%__interwork_call_via_%0" -[(set_attr "length" "4")]) - -(define_expand "call_value" - [(set (match_operand 0 "" "") - (call (match_operand 1 "memory_operand" "") - (match_operand 2 "" "")))] - "" - "") - -(define_insn "*call_value_indirect" - [(set (match_operand 0 "" "=l") - (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) - (match_operand 2 "" "")))] - "! TARGET_CALLER_INTERWORKING" - "bl\\t%__call_via_%1" -[(set_attr "length" "4")]) -;; See comment for call_indirect pattern - -(define_insn "*call_value_indirect_interwork" - [(set (match_operand 0 "" "=l") - (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) - (match_operand 2 "" "")))] - "TARGET_CALLER_INTERWORKING" - "bl\\t%__interwork_call_via_%1" -[(set_attr "length" "4")]) - - -(define_insn "*call_insn" - [(call (mem:SI (match_operand:SI 0 "" "i")) - (match_operand:SI 1 "" ""))] - "GET_CODE (operands[0]) == SYMBOL_REF" - "bl\\t%a0" -[(set_attr "length" "4")]) - -(define_insn "*call_value_insn" - [(set (match_operand 0 "register_operand" "=l") - (call (mem:SI (match_operand 1 "" "i")) - (match_operand 2 "" "")))] - "GET_CODE (operands[1]) == SYMBOL_REF" - "bl\\t%a1" -[(set_attr "length" "4")]) - -;; Untyped call not required, since all funcs return in r0 - -;; Miscellaneous patterns - -(define_insn "nop" - [(clobber (const_int 0))] - "" - "mov\\tr8, r8") - -(define_insn "blockage" - [(unspec_volatile [(const_int 0)] 0)] - "" - "" - [(set_attr "length" "0")]) - -(define_expand "prologue" - [(const_int 0)] - "" - " - thumb_expand_prologue (); - DONE; -") - -(define_expand "epilogue" - [(unspec_volatile [(const_int 0)] 1)] - "! thumb_trivial_epilogue ()" - " - thumb_expand_epilogue (); -") - -(define_insn "*epilogue_insns" - [(unspec_volatile [(const_int 0)] 1)] - "" - "* - return thumb_unexpanded_epilogue (); -" -[(set_attr "length" "42")]) - -;; Special patterns for dealing with the constant pool - -(define_insn "consttable_4" - [(unspec_volatile [(match_operand 0 "" "")] 2)] - "" - "* -{ - switch (GET_MODE_CLASS (GET_MODE (operands[0]))) - { - case MODE_FLOAT: - { - union real_extract u; - bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); - assemble_real (u.d, GET_MODE (operands[0])); - break; - } - default: - assemble_integer (operands[0], 4, 1); - break; - } - return \"\"; -}" -[(set_attr "length" "4")]) - -(define_insn "consttable_8" - [(unspec_volatile [(match_operand 0 "" "")] 3)] - "" - "* -{ - switch (GET_MODE_CLASS (GET_MODE (operands[0]))) - { - case MODE_FLOAT: - { - union real_extract u; - bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u); - assemble_real (u.d, GET_MODE (operands[0])); - break; - } - default: - assemble_integer (operands[0], 8, 1); - break; - } - return \"\"; -}" -[(set_attr "length" "8")]) - -(define_insn "consttable_end" - [(unspec_volatile [(const_int 0)] 4)] - "" - "* - /* Nothing to do (currently). */ - return \"\"; -") - -(define_insn "align_4" - [(unspec_volatile [(const_int 0)] 5)] - "" - "* - assemble_align (32); - return \"\"; -") |