#! /bin/sh /usr/share/dpatch/dpatch-run ## 001-mspgcc-3.2.3-20080819.dpatch by ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: Patch derived from mspgcc project gcc/3.3 directory, CVS 20080819 @DPATCH@ diff -urN -x CVS gcc-3.2.3.orig/configure.in gcc-3.2.3/configure.in --- gcc-3.2.3.orig/configure.in 2002-07-08 04:00:57.000000000 -0600 +++ gcc-3.2.3/configure.in 2008-08-22 09:17:00.000000000 -0600 @@ -907,6 +907,9 @@ target_configdirs="${target_configdirs} target-bsp target-libstub target-cygmon" fi ;; + msp430-*-*) + noconfigdirs="$noconfigdirs target-libiberty ${libstdcxx_version} ${libgcj}" + ;; powerpc-*-aix*) # copied from rs6000-*-* entry # The configure and build of ld are currently disabled because diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/libgcc.c gcc-3.2.3/gcc/config/msp430/libgcc.c --- gcc-3.2.3.orig/gcc/config/msp430/libgcc.c 1969-12-31 17:00:00.000000000 -0700 +++ gcc-3.2.3/gcc/config/msp430/libgcc.c 2008-08-22 09:17:00.000000000 -0600 @@ -0,0 +1,74 @@ + +/* + Stages of division: + 0. Clear carry flag, et all. + 1. Shift divident into divider. + Shift carry bit into divident. + 2. Check if the remainder >= divider + 3. if yes, remainder -= divider + this MUST set carry flag + 4. if not, clear carry flag + + repeat from 1 sizeof(type) times + */ + + +typedef unsigned long __XX; + +__XX +__udivmodXI3 ( __XX a, __XX b) +{ + __XX al = a; // quotant + __XX ah = 0; // reminder + __XX tmpf; + int i; + + for (i = sizeof(__XX)*8; i > 0; i--) + { + ah = (ah << 1) | (al >> (sizeof(__XX)*8-1) ); + tmpf = (ah >= b) ? 1 : 0; + ah -= ((tmpf) ? b : 0); + al = (al << 1) | tmpf; + } + + return al; // for __udivXi3 + return ah; // for __umodXi3 +} + +/* Signed: */ + +__XX +__divmodXI3 ( __XX a, __XX b) +{ + unsigned at = abs(a); + unsigned bt = abs(b); + unsigned al, ah; + + __udivmodXI3 (at, bt); + + // now we get al, ah + + if (a < 0) + ah = -ah, al = -al; + + if (b < 0) + al = -al; + + return al; + return ah; +} + +#if 1 +int main() +{ + __XX a,b, r; + + a = 100; + b = 0; + r = __udivmodXI3(a,b); + printf("R=%d\n",r); + +} +#endif + + diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/libgcc.S gcc-3.2.3/gcc/config/msp430/libgcc.S --- gcc-3.2.3.orig/gcc/config/msp430/libgcc.S 1969-12-31 17:00:00.000000000 -0700 +++ gcc-3.2.3/gcc/config/msp430/libgcc.S 2008-08-22 09:17:00.000000000 -0600 @@ -0,0 +1,1326 @@ +/* -*- Mode: Asm -*- */ + + + .section .text.libgcc, "ax", @progbits + +#if defined (L_cmpdi2) + + .global __cmpdi2 + .func __cmpdi2 +__cmpdi2: + sub 2(r1), r12 ; a = a-b; + subc 4(r1), r13 + subc 6(r1), r14 + subc 8(r1), r15 + + tst r15 ; c<0 ? return -1; + jge .L2 + + mov #-1, r15 ; yes, return -1 + ret +.L2: + bis r12, r14 ; check if zero + bis r13, r15 + bis r14, r15 + tst r15 + jeq .L4 ; test result or or'ing all nibbles + + mov #1, r15 ; no, positive, return 1 + ret +.L4: + mov #0, r15 ; return 0 + ret +.endfunc +#endif + +#if defined (L_cmpsf2) + .global __cmpsf2 + .func __cmpsf2 +__cmpsf2: +/* prologue: frame size = 0; addenum 0; alloca:0, varargs:0 , fpr:0*/ +.L__FrameSize___cmpsf2=0x0 +.L__FrameOffset___cmpsf2=0x4 +/* prologue end (size=2) */ + cmp r12, r14 ; 11 cmpsi [length = 3] + jne .L2 + cmp r13, r15 + jne .L2 ; 12 bne [length = 1] + mov #llo(0), r15 ; 15 *movhi3/7 [length = 1] + ret +.L2: + tst r15 ; 20 tstsi [length = 1] + jge .L3 ; 21 bge [length = 1] + tst r13 ; 22 tstsi [length = 1] + jge .L3 ; 23 bge [length = 1] + xor #lhi(-2147483648), r15 ; 27 *xorsi3_3 [length = 2] + xor #lhi(-2147483648), r13 ; 29 *xorsi3_3 [length = 2] +.L3: + sub r14, r12 ; 64 *subsi3_3 [length = 2] + subc r15, r13 + jge .L4 ; 33 bge [length = 1] + mov #llo(1), r15 ; 36 *movhi3/7 [length = 1] + ret +.L4: + mov #llo(-1), r15 ; 43 *movhi3/7 [length = 1] +.L1: +/* epilogue: frame size=0 */ + ret +/* epilogue end (size=3) */ +/* function __cmpsf2 size 25 (20) */ + +.endfunc + +#endif + + + +/******************************************************* + Multiplication 8 x 8 +*******************************************************/ +#if defined (L_mulqi3) +/* + a = reg:qi 10 clobber + b = reg:qi 12 clobber + res = reg:qi 14 +*/ + + .global __mulqi3 + .func __mulqi3 +__mulqi3: + clr r14 +.L__mulqiloop: + tst.b r10 + jz .L__mulqiexit + clrc + rrc.b r12 + jnc +2 + add.b r10, r14 + rla.b r10 + tst.b r12 + jne .L__mulqiloop +.L__mulqiexit: + ret + .endfunc +#endif /* defined (L_mulqi3) */ + + +#if defined (L_mulqihi3) + .global __mulqihi3 + .func __mulqihi3 +__mulqihi3: + sxt r10 + sxt r12 + br #__mulhi3 +.endfunc +#endif /* defined (L_mulqihi3) */ + +#if defined (L_umulqihi3) + .global __umulqihi3 + .func __umulqihi3 +__umulqihi3: + and.b #-1, r10 + and.b #-1, r12 + br #__mulhi3 + .endfunc +#endif /* defined (L_umulqihi3) */ + +/******************************************************* + Multiplication 16 x 16 +*******************************************************/ +#if defined (L_mulhi3) +/* + a = reg:hi 10 clobber + b = reg:hi 12 clobber + res = reg:hi 14 +*/ + + .global __mulhi3 + .func __mulhi3 +__mulhi3: + clr r14 +.L__mulhiloop: + tst r10 + jz .L__mulhiexit + clrc + rrc r12 + jnc +2 + add r10, r14 + rla r10 + tst r12 + jne .L__mulhiloop +.L__mulhiexit: + ret + .endfunc +#endif /* defined (L_mulhi3) */ + +#if defined (L_mulhisi3) +/* clobber r11, r13 */ + .global __mulhisi3 + .func __mulhisi3 +__mulhisi3: + br #__mulsi3 + .endfunc +#endif /* defined (L_mulhisi3) */ + +#if defined (L_umulhisi3) + .global __umulhisi3 + .func __umulhisi3 +__umulhisi3: + br #__mulsi3 + .endfunc +#endif /* defined (L_umulhisi3) */ + +#if defined (L_mulsi3) +/******************************************************* + Multiplication 32 x 32 +*******************************************************/ +/* +res = a*b + a - reg:SI 10 clobber + b - reg:SI 12 clobber + res - reg: SI 14 +*/ + .global __mulsi3 + .func __mulsi3 + +__mulsi3: + clr r14 + clr r15 + jmp .L__mulsi3st +.L__mulsi3loop: + clrc + rrc r13 ; b >>= 1 + rrc r12 + jnc +4 ; + add r10, r14 ; res = res + a + addc r11, r15 + rla r10 + rlc r11 ; a <<= 1 +.L__mulsi3st: + tst r12 ; if b ne 0 goto L__mulsi3loop + jne .L__mulsi3loop + tst r13 + jne .L__mulsi3loop + ret + .endfunc + +#endif + +#if defined (L_mulsi3hw) + +__MPY=0x130 +__MPYS=0x132 +__MAC=0x134 +__MACS=0x136 +__OP2=0x138 +__RESLO=0x13a +__RESHI=0x13c +__SUMEXT=0x13e + + .global __umulsi3hw + .func __umulsi3hw +__umulsi3hw: + mov r12, &__MPY + mov r10, &__OP2 + mov r12, &__MAC + mov &__RESLO, r14 + mov &__RESHI, &__RESLO + mov r11, &__OP2 + mov r13, &__MAC + mov r10, &__OP2 + mov &__RESLO, r15 + ret +.endfunc + +#endif + + +/******************************************************* + Division 8 / 8 => (result + remainder) +*******************************************************/ + +#define r_rem r14 /* remainder */ +#define r_arg1 r12 /* dividend, quotient */ +#define r_arg2 r10 /* divisor */ +#define r_cnt r11 /* loop count */ +#define r_tmp r13 /* save carry flag */ + + +#if defined (L_udivmodqi4) + .global __udivmodqi4 + .func __udivmodqi4 +__udivmodqi4: + xor.b r_rem, r_rem ; clear reminder and carry + mov.b #9, r_cnt + jmp .L__udivmodqi4_ep +.L__udivmodqi4_loop: + rrc r_tmp ; restore carry bit + rlc.b r_rem + cmp.b r_arg2, r_rem + jlo .L__udivmodqi4_ep + sub.b r_arg2, r_rem ; FIXME: will this clobber carry ? +.L__udivmodqi4_ep: + rlc.b r_arg1 ; shift divident + rlc r_tmp ; save carry bit + dec.b r_cnt ; this clobbers C bit. + jnz .L__udivmodqi4_loop + ret + .endfunc +#endif /* defined (L_udivmodqi4) */ + + +#if defined (L_divmodqi4) + .global __divmodqi4 + .func __divmodqi4 +__divmodqi4: + clr r_tmp + bit #0x80, r_arg1 ; save divident sign + jnc .L__divmodqi4arg1pos + inv.b r_arg1 ; negate + inc.b r_arg1 + bis #4, r_tmp + +.L__divmodqi4arg1pos: + bit #0x80, r_arg2 ; check divisor sign + jnc .L__divmodqi4arg2pos + inv.b r_arg2 ; negate + inc.b r_arg2 + bis #8, r_tmp + +.L__divmodqi4arg2pos: + + call #__udivmodqi4 ; do unsigned division + rrc r_tmp ; restore carry and sign bits + + bit #4, r_tmp ; is divident < 0 ? + jnc .L__divmodqi4rem ; no. skip + inv.b r_rem ; negate remainder + inc.b r_rem + +;; bit #8, r_tmp +;; jc .L__divmodqi4end + inv.b r_arg1 ; negate quotient + inc.b r_arg1 + +.L__divmodqi4rem: + bit #8, r_tmp + jnc .L__divmodqi4end + inv.b r_arg1 + inc.b r_arg1 + +.L__divmodqi4end: + ret + + .endfunc +#endif /* defined (L_divmodqi4) */ + +#undef r_rem +#undef r_arg1 +#undef r_arg2 +#undef r_cnt +#undef r_tmp + + +/******************************************************* + Division 16 / 16 => (result + remainder) +*******************************************************/ + +#define r_rem r14 /* remainder */ +#define r_arg1 r12 /* dividend, quotient */ +#define r_arg2 r10 /* divisor */ +#define r_cnt r11 /* loop count */ +#define r_tmp r13 + + +#if defined (L_udivmodhi4) + .global __udivmodhi4 + .func __udivmodhi4 +__udivmodhi4: + xor r_rem, r_rem ; clear reminder and carry + mov #17, r_cnt + jmp .L__udivmodhi4_ep +.L__udivmodhi4_loop: + rrc r_tmp ; restore carry bit + rlc r_rem + cmp r_arg2, r_rem + jlo .L__udivmodhi4_ep + sub r_arg2, r_rem +.L__udivmodhi4_ep: + rlc r_arg1 + rlc r_tmp ; save carry bit + dec r_cnt ; this clobbers C bit. + jnz .L__udivmodhi4_loop + ret + .endfunc +#endif /* defined (L_udivmodhi4) */ + + +#if defined (L_divmodhi4) +#define r_rem r14 /* remainder */ +#define r_arg1 r12 /* dividend, quotient */ +#define r_arg2 r10 /* divisor */ +#define r_cnt r11 /* loop count */ +#define r_tmp r13 + + + .global __divmodhi4 + .func __divmodhi4 +__divmodhi4: + clr r_tmp ; clear reg is cheaper than clr 2 bits. + bit #0x8000, r_arg1 ; save divident sign + jnc .L__divmodhi4arg1pos + inv r_arg1 ; negate + inc r_arg1 + bis #4, r_tmp + +.L__divmodhi4arg1pos: + bit #0x8000, r_arg2 ; check divisor sign + jnc .L__divmodhi4arg2pos + inv r_arg2 ; negate + inc r_arg2 + bis #8, r_tmp + +.L__divmodhi4arg2pos: + call #__udivmodhi4 ; do unsigned division + rrc r_tmp ; restore carry and sign bits + + bit #4, r_tmp ; is divident < 0 ? + jnc .L__divmodhi4rem ; no. skip + inv r_rem ; negate remainder + inc r_rem + +;; bit #8, r_tmp +;; jc .L__divmodhi4end + inv r_arg1 ; negate quotient + inc r_arg1 + +.L__divmodhi4rem: + bit #8, r_tmp + jnc .L__divmodhi4end + inv r_arg1 + inc r_arg1 + +.L__divmodhi4end: + ret + .endfunc +#endif /* defined (L_divmodhi4) */ + +#undef r_rem +#undef r_arg1 +#undef r_arg2 +#undef r_cnt +#undef r_tmp + +/******************************************************* + Division 32 / 32 => (result + remainder) +*******************************************************/ + +#if defined (L_udivmodsi4) + +#define r_remh r15 +#define r_reml r14 /* remainder */ +#define r_arg1h r13 +#define r_arg1l r12 /* dividend, quotient */ +#define r_arg2h r11 +#define r_arg2l r10 /* divisor */ +#define r_cnt r9 /* loop count */ +#define r_tmp r8 + + .global __udivmodsi4 + .func __udivmodsi4 +__udivmodsi4: + xor r_remh, r_remh ; clear reminder and carry + xor r_reml, r_reml + mov #33, r_cnt + jmp .L__udivmodsi4_ep +.L__udivmodsi4_loop: + rrc r_tmp ; restore carry bit + rlc r_reml + rlc r_remh + + cmp r_arg2h, r_remh ; is reminder < divisor ? + jlo .L__udivmodsi4_ep ; yes, skip correction + jne +4 + ; they equal. check LSBytes + cmp r_arg2l, r_reml + jlo .L__udivmodsi4_ep ; is reminder still < divisor ? + + sub r_arg2l, r_reml ; adjust reminder + subc r_arg2h, r_remh + +.L__udivmodsi4_ep: + rlc r_arg1l + rlc r_arg1h + rlc r_tmp + dec r_cnt ; this clobbers C bit. + jnz .L__udivmodsi4_loop + ret + .endfunc + +#undef r_remh +#undef r_reml +#undef r_arg1h +#undef r_arg1l +#undef r_arg2h +#undef r_arg2l + +#undef r_cnt +#undef r_tmp + +#endif /* defined (L_udivmodsi4) */ + + +#if defined (L_divmodsi4) +#define r_remh r15 +#define r_reml r14 /* remainder */ +#define r_arg1h r13 +#define r_arg1l r12 /* dividend, quotient */ +#define r_arg2h r11 +#define r_arg2l r10 /* divisor */ +#define r_cnt r9 /* loop count */ +#define r_tmp r8 + + .global __divmodsi4 + .func __divmodsi4 +__divmodsi4: + clr r_tmp ; clear reg is cheaper than clr 2 bits. + bit #0x8000, r_arg1h ; save divident sign + jz .L__divmodsi4arg1pos + inv r_arg1h ; negate + inv r_arg1l + inc r_arg1l + adc r_arg1h + bis #4, r_tmp + +.L__divmodsi4arg1pos: + bit #0x8000, r_arg2h ; check divisor sign + jz .L__divmodsi4arg2pos + inv r_arg2h ; negate + inv r_arg2l + inc r_arg2l + adc r_arg2h + bis #8, r_tmp ; save divisor sign + +.L__divmodsi4arg2pos: + + call #__udivmodsi4 ; do unsigned division + rrc r_tmp ; restore carry and sign bits + + bit #4, r_tmp ; is divident < 0 ? + jz .L__divmodsi4rem ; no. skip + inv r_reml ; negate remainder + inv r_remh + inc r_reml + adc r_remh + +;; bit #8, r_tmp +;; jc .L__divmodsi4end + inv r_arg1l ; negate quotient + inv r_arg1h + inc r_arg1l + adc r_arg1h + +.L__divmodsi4rem: + bit #8, r_tmp + jz .L__divmodsi4end + inv r_arg1l + inv r_arg1h + inc r_arg1l + adc r_arg1h + +.L__divmodsi4end: + ret + .endfunc + +#undef r_remh +#undef r_reml +#undef r_arg1h +#undef r_arg1l +#undef r_arg2h +#undef r_arg2l + +#undef r_cnt +#undef r_tmp + +#endif /* defined (L_divmodsi4) */ + + +/******* CRT support functions *********/ + +#if defined(L_reset_vector__) +/***************************************************************** + * Program starts here. + * overwriting this label in the user program + * causes removing all strtup code except __do_global_ctors + *****************************************************************/ + .section .init0, "ax", @progbits + + .global _reset_vector__ + .weak _reset_vector__ + + .func _reset_vector__ + +_reset_vector__: + + /* link following functions if library _reset_vector__ used */ + +; actualy stack initialized in main() prologue, so don't link __init_stack +; .global __init_stack + + .global __low_level_init + .global __do_copy_data + .global __do_clear_bss + .global __jump_to_main + + .endfunc +#endif /* defined(L_reset_vector__) */ + +#if defined(L__init_stack) +/***************************************************************** + * Set stack pointer + * can be overwriten + *****************************************************************/ + .section .init2, "ax", @progbits + + .global __init_stack + .weak __init_stack + + .func __init_stack + +set_stack_pointer: + mov #__stack, r1 + + .endfunc +#endif + +#if defined(L__low_level_init) +/***************************************************************** + * Initialize peripherial, particularly disable watchdog + * can be overwriten + *****************************************************************/ + .section .init3, "ax", @progbits + + .global __low_level_init + .weak __low_level_init + + .func __low_level_init + +__low_level_init: + mov #0x5a80, &0x120 + + .endfunc +#endif + +#if defined(L_copy_data) +/***************************************************************** + * Initialize data: copy data + * from __data_load_start ( = _etext) to __data_start + * can be overwriten + *****************************************************************/ + .section .init4, "ax", @progbits + + .global __do_copy_data + .weak __do_copy_data + + .func __do_copy_data + +__do_copy_data: + mov #__data_size, r15 + tst r15 + jz .L__copy_data_end +.L__copy_data_loop: + decd r15 + mov.w __data_load_start(r15), __data_start(r15) ; data section is word-aligned, so word transfer is acceptable + jne .L__copy_data_loop +.L__copy_data_end: + + .endfunc +#endif /* defined(L_copy_data) */ + +#if defined(L_clear_bss) +/***************************************************************** + * Initialize data: clear .bss + * can be overwriten + *****************************************************************/ + .section .init4, "ax", @progbits + + .global __do_clear_bss + .weak __do_clear_bss + + .func __do_clear_bss + +__do_clear_bss: + mov #__bss_size, r15 + tst r15 + jz .L__clear_bss_end +.L__clear_bss_loop: + dec r15 + clr.b __bss_start(r15) + jne .L__clear_bss_loop +.L__clear_bss_end: + + .endfunc +#endif /* defined(L_clear_bss) */ + +#if defined(L_ctors) +/***************************************************************** + * Call C++ global and static objects constructors + * can be overwriten + *****************************************************************/ + .section .init6, "ax", @progbits + .global __do_global_ctors + .weak __do_global_ctors + + .func __do_global_ctors + .global __init_stack ; stack has to be set before constructors calling + + +__do_global_ctors: + mov #__ctors_start, r11 + mov #__ctors_end, r10 +.L__ctors_loop: + call @r11+ ; call constructor + cmp r10, r11 + jne .L__ctors_loop + + .endfunc +#endif + +#if defined(L__jump_to_main) +/***************************************************************** + * jump to main. + * can be overwriten + *****************************************************************/ + .section .init9, "ax", @progbits + + .global __jump_to_main + .weak __jump_to_main + + .func __jump_to_main + +__jump_to_main: + br #main + .endfunc +#endif + +#if defined(L__stop_progExec__) +/***************************************************************** + * return from main. + * can be overwriten + *****************************************************************/ + .section .fini9, "ax", @progbits + .global __stop_progExec__ + .weak __stop_progExec__ + + .func __stop_progExec__ + +__stop_progExec__: + + .endfunc +#endif + +#if defined(L_dtors) +/***************************************************************** + * Call C++ global and static objects destructors + * can be overwriten + *****************************************************************/ + .section .fini6,"ax",@progbits + .global __do_global_dtors + .weak __do_global_dtors + + .func _dtors + +__do_global_dtors: + mov #__dtors_start, r11 + mov #__dtors_end, r10 +.L__dtors_loop: + call @r11+ + cmp r10, r11 + jne .L__dtors_loop + + .endfunc +#endif + +#if defined(L__stop_progExec__) +/***************************************************************** + * endless loop + * can be overwriten + *****************************************************************/ + .section .fini0, "ax", @progbits + + .func _endless_loop__ +1: + jmp 1b + + .endfunc +#endif + +/********* PROLOGE / EPILOGUE aux routines ******************/ +#if defined (L__prologue_saver) + .global __prologue_saver + .func __prologue_saver +__prologue_saver: + mov r4, 0(r1) + mov r5, 2(r1) + mov r6, 4(r1) + mov r7, 6(r1) + mov r8, 8(r1) + mov r9, 10(r1) + mov r10, 12(r1) + mov r11, 14(r1) + br r12 ; now jump to the function body +.endfunc + +#endif + + +#if defined (L__epilogue_restorer) + .global __epilogue_restorer + .func __epilogue_restorer +__epilogue_restorer: + pop r4 + pop r5 + pop r6 + pop r7 + pop r8 + pop r9 + pop r10 + pop r11 + ret +.endfunc + +#endif + + +#if defined (L__epilogue_restorer_intr) + .global __epilogue_restorer_intr + .func __epilogue_restorer_intr +__epilogue_restorer_intr: + pop r4 + pop r5 + pop r6 + pop r7 + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + reti +.endfunc + +#endif + +/****************************************** + * quot/rem = 64/64 + ******************************************/ + +#if defined (L_udivmoddi3_parts) || defined (L_udivdi3) || defined (L_umoddi3) || defined (L_divdi3) || defined (L_moddi3) + +#define r_remhh r11 /* remainder */ +#define r_remhl r10 +#define r_remlh r9 +#define r_remll r8 + +#define r_arg1hh r15 /* dividend, quotient */ +#define r_arg1hl r14 +#define r_arg1lh r13 +#define r_arg1ll r12 + +#define r_arg2hh r7 /* divisor */ +#define r_arg2hl r6 +#define r_arg2lh r5 +#define r_arg2ll r4 + +#define r_cnt 2(r1) /* loop count */ +#define r_tmp 0(r1) /* we'll save carry and signs here */ + +#endif + + +#if defined (L_udivmoddi3_parts) + + .global __udivmoddi3_parts + .func __udivmoddi3_parts +__udivmoddi3_parts: + xor r_remhh, r_remhh ; clear reminder and carry + xor r_remhl, r_remhl + xor r_remlh, r_remlh + xor r_remll, r_remll + + mov #65, 2+r_cnt + jmp .L__udivmoddi3_ep + +.L__udivmoddi3_loop: + rrc 2+r_tmp ; restore carry bit + + rlc r_remll ; shift carry in. + rlc r_remlh + rlc r_remhl + rlc r_remhh + + cmp r_arg2hh, r_remhh ; is reminder < divisor ? + jlo .L__udivmoddi3_ep ; yes, skip correction + jne .L_udmdcrt + ; they equal. check LSBytes + cmp r_arg2hl, r_remhl + jlo .L__udivmoddi3_ep ; is reminder still < divisor ? + jne .L_udmdcrt + + cmp r_arg2lh, r_remlh + jlo .L__udivmoddi3_ep + jne .L_udmdcrt + + cmp r_arg2ll, r_remll + jlo .L__udivmoddi3_ep + jne .L_udmdcrt + +.L_udmdcrt: + sub r_arg2ll, r_remll ; adjust reminder + subc r_arg2lh, r_remlh + subc r_arg2hl, r_remhl + subc r_arg2hh, r_remhh + +.L__udivmoddi3_ep: + rlc r_arg1ll ; shift carry into arg1 + rlc r_arg1lh + rlc r_arg1hl + rlc r_arg1hh + + rlc 2+r_tmp ; save carry + dec 2+r_cnt ; this clobbers C bit. + jnz .L__udivmoddi3_loop + + ret + .endfunc + +#endif /* defined (L_udivmoddi3_parts) */ + + +#if defined (L_udivdi3) + +;; First arg will be in r15:r12 +;; next on stack +;; return in r15:r12 +;; rearrange them as: +;; r15:r12 -> r_arg1hh:r_arg1ll +;; stack+8:stack+2 -> r_arg2hh:r_arg2ll + + .global __udivdi3 + .func __udivdi3 +__udivdi3: + push r4 + push r5 + push r6 + push r7 + push r8 + push r9 + push r10 + push r11 + + mov 18+0(r1), r_arg2ll ; 18 is a stack offset + mov 18+2(r1), r_arg2lh ; so move arg 2 in. + mov 18+4(r1), r_arg2hl + mov 18+6(r1), r_arg2hh + + sub #4, r1 + call #__udivmoddi3_parts + add #4, r1 + + pop r11 + pop r10 + pop r9 + pop r8 + pop r7 + pop r6 + pop r5 + pop r4 + ret + .endfunc +#endif + + +#if defined (L_umoddi3) + .global __umoddi3 + .func __umoddi3 +__umoddi3: + push r4 + push r5 + push r6 + push r7 + push r8 + push r9 + push r10 + push r11 + + mov 18+0(r1), r_arg2ll + mov 18+2(r1), r_arg2lh + mov 18+4(r1), r_arg2hl + mov 18+6(r1), r_arg2hh + + sub #4, r1 + call #__udivmoddi3_parts + add #4, r1 + + mov r_remhh, r15 ; move reminder to (reg:DI 12) + mov r_remhl, r14 + mov r_remlh, r13 + mov r_remll, r12 + + pop r11 + pop r10 + pop r9 + pop r8 + pop r7 + pop r6 + pop r5 + pop r4 + ret + .endfunc +#endif + + +#if defined (L_divdi3) + .global __divdi3 + .func __divdi3 +__divdi3: + push r4 + push r5 + push r6 + push r7 + push r8 + push r9 + push r10 + push r11 + + mov 18+0(r1), r_arg2ll + mov 18+2(r1), r_arg2lh + mov 18+4(r1), r_arg2hl + mov 18+6(r1), r_arg2hh + + sub #4, r1 + + clr r_tmp + bit #0x8000, r_arg1hh + jnc .L__divdi3rempos + inv r_arg1hh + inv r_arg1hl + inv r_arg1lh + inv r_arg1ll + inc r_arg1ll + adc r_arg1lh + adc r_arg1hl + adc r_arg1hh + bis #4, r_tmp + +.L__divdi3rempos: + bit #0x8000, r_arg2hh + jnc .L__divdi3arg2pos + inv r_arg2hh + inv r_arg2hl + inv r_arg2lh + inv r_arg2ll + inc r_arg2ll + adc r_arg2lh + adc r_arg2hl + adc r_arg2hh + xor #4, r_tmp ; this is a trick - invert bit 4 => + ; do not perform double negation. +.L__divdi3arg2pos: + call #__udivmoddi3_parts + + rrc r_tmp ; restore sign bits + + bit #4, r_tmp + jz .L__divdi3end + inv r_arg1hh + inv r_arg1hl + inv r_arg1lh + inv r_arg1ll + inc r_arg1ll + adc r_arg1lh + adc r_arg1hl + adc r_arg1hh + +.L__divdi3end: + add #4, r1 + pop r11 + pop r10 + pop r9 + pop r8 + pop r7 + pop r6 + pop r5 + pop r4 + ret + .endfunc +#endif + + +#if defined (L_moddi3) + .global __moddi3 + .func __moddi3 +__moddi3: + push r4 + push r5 + push r6 + push r7 + push r8 + push r9 + push r10 + push r11 + + mov 18+0(r1), r_arg2ll + mov 18+2(r1), r_arg2lh + mov 18+4(r1), r_arg2hl + mov 18+6(r1), r_arg2hh + + sub #4, r1 + + clr r_tmp + bit #0x8000, r_arg1hh + jnc .L__moddi3rempos + inv r_arg1hh + inv r_arg1hl + inv r_arg1lh + inv r_arg1ll + inc r_arg1ll + adc r_arg1lh + adc r_arg1hl + adc r_arg1hh + bis #4, r_tmp + +.L__moddi3rempos: + bit #0x8000, r_arg2hh + jnc .L__moddi3arg2pos + inv r_arg2hh + inv r_arg2hl + inv r_arg2lh + inv r_arg2ll + inc r_arg2ll + adc r_arg2lh + adc r_arg2hl + adc r_arg2hh + +.L__moddi3arg2pos: + call #__udivmoddi3_parts + + rrc r_tmp + + bit #4, r_tmp + jz .L__moddi3rem + + inv r_remhh + inv r_remhl + inv r_remlh + inv r_remll + inc r_remll + adc r_remlh + adc r_remhl + adc r_remhh + +.L__moddi3rem: + mov r_remhh, r15 + mov r_remhl, r14 + mov r_remlh, r13 + mov r_remll, r12 + + add #4, r1 + pop r11 + pop r10 + pop r9 + pop r8 + pop r7 + pop r6 + pop r5 + pop r4 + ret + .endfunc +#endif + + +/************************************************************** + * Multiplication 64 = 64 x 64 + **************************************************************/ +#if defined(L_muldi3) && !defined(MSP430_HAS_HWMUL) + +#define r_reshh r11 /* res = arg1 * arg2 */ +#define r_reshl r10 +#define r_reslh r9 +#define r_resll r8 + +#define r_arg1hh r15 /* arg1 */ +#define r_arg1hl r14 +#define r_arg1lh r13 +#define r_arg1ll r12 + +#define r_arg2hh r7 /* arg2 */ +#define r_arg2hl r6 +#define r_arg2lh r5 +#define r_arg2ll r4 + + .global __muldi3 + .func __muldi3 +__muldi3: + push r4 + push r5 + push r6 + push r7 + push r8 + push r9 + push r10 + push r11 + + mov 18+0(r1), r_arg2ll ; 18 is a stack offset + mov 18+2(r1), r_arg2lh ; so move arg 2 in. + mov 18+4(r1), r_arg2hl + mov 18+6(r1), r_arg2hh + + clr r_reshh + clr r_reshl + clr r_reslh + clr r_resll + +.L_muldi3_loop: + clrc + rrc r_arg2hh ; arg2 >>= 1 (shift LSB into carry) + rrc r_arg2hl + rrc r_arg2lh + rrc r_arg2ll + + jnc +8 ; check if bit is set + ; yes, it is. + add r_arg1ll, r_resll ; res += arg1 + addc r_arg1lh, r_reslh + addc r_arg1hl, r_reshl + addc r_arg1hh, r_reshh + + rla r_arg1ll ; arg1 <<= 1 + rlc r_arg1lh + rlc r_arg1hl + rlc r_arg1hh + + tst r_arg2ll ; arg2 !=0 ? loop again , exit otherwise. + jne .L_muldi3_loop + tst r_arg2lh + jne .L_muldi3_loop + tst r_arg2hl + jne .L_muldi3_loop + tst r_arg2hh + jne .L_muldi3_loop + + ; move result to proper location + mov r_resll, r12 + mov r_reslh, r13 + mov r_reshl, r14 + mov r_reshh, r15 + + pop r11 + pop r10 + pop r9 + pop r8 + pop r7 + pop r6 + pop r5 + pop r4 + ret + .endfunc +#endif + +#if defined(L_muldi3) && defined(MSP430_HAS_HWMUL) + +__MPY=0x130 +__MPYS=0x132 +__MAC=0x134 +__MACS=0x136 +__OP2=0x138 +__RESLO=0x13a +__RESHI=0x13c +__SUMEXT=0x13e + +#define r_reshh r11 /* res = arg1 * arg2 */ +#define r_reshl r10 +#define r_reslh r9 +#define r_resll r8 + +#define r_arg1hh r15 /* arg1 */ +#define r_arg1hl r14 +#define r_arg1lh r13 +#define r_arg1ll r12 + +#define r_arg2hh r7 /* arg2 */ +#define r_arg2hl r6 +#define r_arg2lh r5 +#define r_arg2ll r4 + + .global __muldi3 + .func __muldi3 +__muldi3: + + push r4 + push r5 + push r6 + push r7 + push r8 + push r9 + push r10 + push r11 + + mov 18+0(r1), r_arg2ll ; 18 is a stack offset + mov 18+2(r1), r_arg2lh ; so move arg 2 in. + mov 18+4(r1), r_arg2hl + mov 18+6(r1), r_arg2hh + +;; r15:r14:r13:r12 * r7:r6:r5:r4 -> r11:r10:r9:r8 +;; actual code follows.... + + mov r_arg1ll,&__MPY + mov r_arg2ll,&__OP2 ;; LL1xLL2 + mov &__RESLO,r_resll + mov &__RESHI,&__RESLO + mov &__SUMEXT,&__RESHI + + mov r_arg1ll,&__MAC + mov r_arg2lh,&__OP2 ;; LL1xLH2 + mov r_arg1lh,&__MAC + mov r_arg2ll,&__OP2 ;; LH1xLL2 + mov &__RESLO,r_reslh + mov &__RESHI,&__RESLO + mov &__SUMEXT,&__RESHI + + mov r_arg2lh,&__OP2 ;; LH1xLH2 + mov r_arg1ll,&__MAC + mov r_arg2hl,&__OP2 ;; LL1xHL2 + mov r_arg1hl,&__MAC + mov r_arg2ll,&__OP2 ;; HL1xLL2 + mov &__RESLO,r_reshl + mov &__RESHI,&__RESLO + + mov r_arg2lh,&__OP2 ;; HL1xLH2 + mov r_arg1ll,&__MAC + mov r_arg2hh,&__OP2 ;; LL1xHH2 + mov r_arg1lh,&__MAC + mov r_arg2hl,&__OP2 ;; LH1xHL2 + mov r_arg1hh,&__MAC + mov r_arg2ll,&__OP2 ;; HH1xLL2 + mov &__RESLO,r_reshh + +;; reload result + mov r_resll, r12 + mov r_reslh, r13 + mov r_reshl, r14 + mov r_reshh, r15 + + pop r11 + pop r10 + pop r9 + pop r8 + pop r7 + pop r6 + pop r5 + pop r4 + ret +.endfunc +#endif diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/msp430.c gcc-3.2.3/gcc/config/msp430/msp430.c --- gcc-3.2.3.orig/gcc/config/msp430/msp430.c 1969-12-31 17:00:00.000000000 -0700 +++ gcc-3.2.3/gcc/config/msp430/msp430.c 2008-08-22 09:17:00.000000000 -0600 @@ -0,0 +1,9851 @@ +/* Subroutines for insn-output.c for Texas Instruments MSP430 MCU + Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Contributed by Dmitry Diky + + This file is part of GNU CC. + GNU CC is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU CC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU CC; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "output.h" +#include "insn-attr.h" +#include "flags.h" +#include "reload.h" +#include "tree.h" +#include "expr.h" +#include "toplev.h" +#include "obstack.h" +#include "function.h" +#include "recog.h" +#include "tm_p.h" +#include "target.h" +#include "target-def.h" + + +/* This holds the last insn address. */ +static int last_insn_address = 0; + +/* Commands count in the compiled file */ +static int commands_in_file; + +/* Commands in the functions prologues in the compiled file */ +static int commands_in_prologues; + +/* Commands in the functions epilogues in the compiled file */ +static int commands_in_epilogues; + +/* Prologue/Epilogue size in words */ +static int prologue_size; +static int epilogue_size; + +/* Size of all jump tables in the current function, in words. */ +static int jump_tables_size; + +/* the size of the stack space freed during mdr pass */ + +/* actual frame offset */ +static int msp430_current_frame_offset = 0; + +/* ret/reti issue indicator for _current_ function */ +static int return_issued = 0; + +/* registers used for incoming funct arguments */ +static char arg_register_used[16]; + +/* push helper */ +int self_push PARAMS ((rtx)); + + +/* aux functions */ +static int msp430_cc_source PARAMS ((rtx, enum rtx_code, rtx, rtx)); +static int msp430_func_num_saved_regs PARAMS ((void)); +static int noint_hwmul_function_p PARAMS ((tree func)); +static int interrupt_function_p PARAMS ((tree func)); +static int msp430_naked_function_p PARAMS ((tree func)); +static int msp430_task_function_p PARAMS ((tree func)); +static int signal_function_p PARAMS ((tree func)); +static int wakeup_function_p PARAMS ((tree func)); +static int msp430_num_arg_regs PARAMS ((enum machine_mode mode, tree type)); +static int msp430_critical_function_p PARAMS ((tree func)); +static int msp430_reentrant_function_p PARAMS ((tree func)); +static int msp430_save_prologue_function_p PARAMS ((tree func)); + +const char * msp430_emit_bltnoovfl PARAMS ((rtx *, int)); + + + +const char *msp430_init_stack = "__stack"; +const char *msp430_endup = "__stop_progExec__"; + +int msp430_case_values_threshold = 30000; +int msp430_has_hwmul = 0; + +struct rtx_def *msp430_compare_op0; +struct rtx_def *msp430_compare_op1; + + +const char *msp430_mcu_name = "msp430x110"; + +enum msp430_arch +{ + MSP430_ISA_1 = 1, + MSP430_ISA_2 = 2, + MSP430_ISA_110 = 110, + MSP430_ISA_11 = 11, + MSP430_ISA_12 = 12, + MSP430_ISA_13 = 13, + MSP430_ISA_14 = 14, + MSP430_ISA_15 = 15, + MSP430_ISA_16 = 16, + MSP430_ISA_20 = 20, + MSP430_ISA_21 = 21, + MSP430_ISA_22 = 22, + MSP430_ISA_23 = 23, + MSP430_ISA_24 = 24, + MSP430_ISA_241 = 241, + MSP430_ISA_26 = 26, + MSP430_ISA_31 = 31, + MSP430_ISA_32 = 32, + MSP430_ISA_33 = 33, + MSP430_ISA_41 = 41, + MSP430_ISA_42 = 42, + MSP430_ISA_43 = 43, + MSP430_ISA_44 = 44, + MSP430_ISA_46 = 46 +}; + +struct mcu_type_s +{ + const char *name; + enum msp430_arch arch; + int has_hwmul; +}; + +static struct mcu_type_s msp430_mcu_types[] = { + /* generic types */ + {"msp1", MSP430_ISA_1, 0}, + {"msp2", MSP430_ISA_2, 1}, + + /* F1xx family */ + {"msp430x110", MSP430_ISA_11, 0}, + {"msp430x112", MSP430_ISA_11, 0}, + + {"msp430x1101", MSP430_ISA_110, 0}, + {"msp430x1111", MSP430_ISA_110, 0}, + {"msp430x1121", MSP430_ISA_110, 0}, + {"msp430x1122", MSP430_ISA_110, 0}, + {"msp430x1132", MSP430_ISA_110, 0}, + + {"msp430x122", MSP430_ISA_12, 0}, + {"msp430x123", MSP430_ISA_12, 0}, + {"msp430x1222", MSP430_ISA_12, 0}, + {"msp430x1232", MSP430_ISA_12, 0}, + + {"msp430x133", MSP430_ISA_13, 0}, + {"msp430x135", MSP430_ISA_13, 0}, + {"msp430x1331", MSP430_ISA_13, 0}, + {"msp430x1351", MSP430_ISA_13, 0}, + + {"msp430x147", MSP430_ISA_14, 1}, + {"msp430x148", MSP430_ISA_14, 1}, + {"msp430x149", MSP430_ISA_14, 1}, + {"msp430x1471", MSP430_ISA_14, 1}, + {"msp430x1481", MSP430_ISA_14, 1}, + {"msp430x1491", MSP430_ISA_14, 1}, + + {"msp430x155", MSP430_ISA_15, 0}, + {"msp430x156", MSP430_ISA_15, 0}, + {"msp430x157", MSP430_ISA_15, 0}, + + {"msp430x167", MSP430_ISA_16, 1}, + {"msp430x168", MSP430_ISA_16, 1}, + {"msp430x169", MSP430_ISA_16, 1}, + {"msp430x1610", MSP430_ISA_16, 1}, + {"msp430x1611", MSP430_ISA_16, 1}, + {"msp430x1612", MSP430_ISA_16, 1}, + + /* F2xx family */ + {"msp430x2001", MSP430_ISA_20, 0}, + {"msp430x2011", MSP430_ISA_20, 0}, + + {"msp430x2002", MSP430_ISA_20, 0}, + {"msp430x2012", MSP430_ISA_20, 0}, + + {"msp430x2003", MSP430_ISA_20, 0}, + {"msp430x2013", MSP430_ISA_20, 0}, + + {"msp430x2101", MSP430_ISA_21, 0}, + {"msp430x2111", MSP430_ISA_21, 0}, + {"msp430x2121", MSP430_ISA_21, 0}, + {"msp430x2131", MSP430_ISA_21, 0}, + + {"msp430x2112", MSP430_ISA_22, 0}, + {"msp430x2122", MSP430_ISA_22, 0}, + {"msp430x2132", MSP430_ISA_22, 0}, + + {"msp430x2232", MSP430_ISA_22, 0}, + {"msp430x2252", MSP430_ISA_22, 0}, + {"msp430x2272", MSP430_ISA_22, 0}, + + {"msp430x2234", MSP430_ISA_22, 0}, + {"msp430x2254", MSP430_ISA_22, 0}, + {"msp430x2274", MSP430_ISA_22, 0}, + + {"msp430x233", MSP430_ISA_23, 1}, + {"msp430x235", MSP430_ISA_23, 1}, + + {"msp430x2330", MSP430_ISA_23, 1}, + {"msp430x2350", MSP430_ISA_23, 1}, + {"msp430x2370", MSP430_ISA_23, 1}, + + {"msp430x247", MSP430_ISA_24, 1}, + {"msp430x248", MSP430_ISA_24, 1}, + {"msp430x249", MSP430_ISA_24, 1}, + {"msp430x2410", MSP430_ISA_24, 1}, + {"msp430x2471", MSP430_ISA_24, 1}, + {"msp430x2481", MSP430_ISA_24, 1}, + {"msp430x2491", MSP430_ISA_24, 1}, + + {"msp430x2416", MSP430_ISA_241, 1}, + {"msp430x2417", MSP430_ISA_241, 1}, + {"msp430x2418", MSP430_ISA_241, 1}, + {"msp430x2419", MSP430_ISA_241, 1}, + + {"msp430x2616", MSP430_ISA_26, 1}, + {"msp430x2617", MSP430_ISA_26, 1}, + {"msp430x2618", MSP430_ISA_26, 1}, + {"msp430x2619", MSP430_ISA_26, 1}, + + /* 3xx family (ROM) */ + {"msp430x311", MSP430_ISA_31, 0}, + {"msp430x312", MSP430_ISA_31, 0}, + {"msp430x313", MSP430_ISA_31, 0}, + {"msp430x314", MSP430_ISA_31, 0}, + {"msp430x315", MSP430_ISA_31, 0}, + + {"msp430x323", MSP430_ISA_32, 0}, + {"msp430x325", MSP430_ISA_32, 0}, + + {"msp430x336", MSP430_ISA_33, 1}, + {"msp430x337", MSP430_ISA_33, 1}, + + /* F4xx family */ + {"msp430x412", MSP430_ISA_41, 0}, + {"msp430x413", MSP430_ISA_41, 0}, + {"msp430x415", MSP430_ISA_41, 0}, + {"msp430x417", MSP430_ISA_41, 0}, + + {"msp430x423", MSP430_ISA_42, 1}, + {"msp430x425", MSP430_ISA_42, 1}, + {"msp430x427", MSP430_ISA_42, 1}, + + {"msp430x4250", MSP430_ISA_42, 0}, + {"msp430x4260", MSP430_ISA_42, 0}, + {"msp430x4270", MSP430_ISA_42, 0}, + + {"msp430xE423", MSP430_ISA_42, 1}, + {"msp430xE425", MSP430_ISA_42, 1}, + {"msp430xE427", MSP430_ISA_42, 1}, + + {"msp430xW423", MSP430_ISA_42, 0}, + {"msp430xW425", MSP430_ISA_42, 0}, + {"msp430xW427", MSP430_ISA_42, 0}, + + {"msp430xG437", MSP430_ISA_43, 0}, + {"msp430xG438", MSP430_ISA_43, 0}, + {"msp430xG439", MSP430_ISA_43, 0}, + + {"msp430x435", MSP430_ISA_43, 0}, + {"msp430x436", MSP430_ISA_43, 0}, + {"msp430x437", MSP430_ISA_43, 0}, + + {"msp430x447", MSP430_ISA_44, 1}, + {"msp430x448", MSP430_ISA_44, 1}, + {"msp430x449", MSP430_ISA_44, 1}, + + {"msp430xG4616", MSP430_ISA_46, 1}, + {"msp430xG4617", MSP430_ISA_46, 1}, + {"msp430xG4618", MSP430_ISA_46, 1}, + {"msp430xG4619", MSP430_ISA_46, 1}, + + {NULL, 0, 0} +}; + + + +const struct attribute_spec msp430_attribute_table[]; +static tree msp430_handle_fndecl_attribute +PARAMS ((tree *, tree, tree, int, bool *)); + +#undef TARGET_ASM_FUNCTION_PROLOGUE +#define TARGET_ASM_FUNCTION_PROLOGUE function_prologue +#undef TARGET_ASM_FUNCTION_EPILOGUE +#define TARGET_ASM_FUNCTION_EPILOGUE function_epilogue +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE msp430_attribute_table +#undef TARGET_SECTION_TYPE_FLAGS +#define TARGET_SECTION_TYPE_FLAGS msp430_section_type_flags + + + +struct gcc_target targetm = TARGET_INITIALIZER; + +/****** ATTRIBUTES TO FUNCTION *************************************/ +const struct attribute_spec msp430_attribute_table[] = { + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + {"reserve", 1, 1, false, false, false, msp430_handle_fndecl_attribute}, + {"signal", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, + {"interrupt", 1, 1, true, false, false, msp430_handle_fndecl_attribute}, + {"naked", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, + {"task", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, + {"wakeup", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, + {"critical", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, + {"reentrant", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, + {"saveprologue", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, + {"noint_hwmul", 0, 0, true, false, false, msp430_handle_fndecl_attribute}, + {NULL, 0, 0, false, false, false, NULL} +}; + +unsigned int +msp430_section_type_flags (decl, name, reloc) + tree decl; + const char *name; + int reloc; +{ + unsigned int flags = 0; + + if (!strcmp (name, ".infomemnobits") || !strcmp (name, ".noinit")) + flags = SECTION_BSS; + + flags |= default_section_type_flags (decl, name, reloc); + return flags; +} + +/* Handle an attribute requiring a FUNCTION_DECL; arguments as in + struct attribute_spec.handler. */ +static tree +msp430_handle_fndecl_attribute (node, name, args, flags, no_add_attrs) + tree *node; + tree name; + tree args ATTRIBUTE_UNUSED; + int flags ATTRIBUTE_UNUSED; + bool *no_add_attrs; +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning ("%s' attribute only applies to functions.", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + return NULL_TREE; +} + + +static int +msp430_naked_function_p (func) + tree func; +{ + tree a; + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + a = lookup_attribute ("naked", DECL_ATTRIBUTES (func)); + return a != NULL_TREE; +} + +static int +msp430_task_function_p (func) + tree func; +{ + tree a; + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + a = lookup_attribute ("task", DECL_ATTRIBUTES (func)); + return a != NULL_TREE; +} +static int +msp430_save_prologue_function_p (func) + tree func; +{ + tree a; + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + a = lookup_attribute ("saveprologue", DECL_ATTRIBUTES (func)); + return a != NULL_TREE; +} + +static int +interrupt_function_p (func) + tree func; +{ + tree a; + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func)); + return a != NULL_TREE; +} + +static int +msp430_critical_function_p (func) + tree func; +{ + tree a; + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + a = lookup_attribute ("critical", DECL_ATTRIBUTES (func)); + return a != NULL_TREE; + +} + +static int +msp430_reentrant_function_p (func) + tree func; +{ + tree a; + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + a = lookup_attribute ("reentrant", DECL_ATTRIBUTES (func)); + return a != NULL_TREE; + +} + +static int +noint_hwmul_function_p (func) + tree func; +{ + tree a; + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + a = lookup_attribute ("noint_hwmul", DECL_ATTRIBUTES (func)); + return a != NULL_TREE; +} + +int +msp430_current_function_noint_hwmul_function_p (void) +{ + int rval; + if (!current_function_decl) + return (TARGET_NOINT_HWMUL); + rval = noint_hwmul_function_p (current_function_decl); + + return (TARGET_NOINT_HWMUL || rval); +} + +static int +signal_function_p (func) + tree func; +{ + tree a; + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + a = lookup_attribute ("signal", DECL_ATTRIBUTES (func)); + return a != NULL_TREE; +} + + +static int +wakeup_function_p (func) + tree func; +{ + tree a; + if (TREE_CODE (func) != FUNCTION_DECL) + abort (); + a = lookup_attribute ("wakeup", DECL_ATTRIBUTES (func)); + return a != NULL_TREE; +} + +enum msp430_arch +msp430_get_arch () +{ + const struct mcu_type_s *t; + + for (t = msp430_mcu_types; t->name; t++) + { + if (strcmp (t->name, msp430_mcu_name) == 0) + break; + } + + if (!t->name) + { + error ("MCU %s not supported", msp430_mcu_name); + fprintf (stderr, "Known MCU names:\n"); + for (t = msp430_mcu_types; t->name; t++) + fprintf (stderr, " %s\n", t->name); + abort (); + return -1; + } + return t->arch; +} + +int +msp430_is_xarch () +{ + switch (msp430_get_arch()) + { + case MSP430_ISA_241: + case MSP430_ISA_26: + case MSP430_ISA_46: + return TRUE; + } + return FALSE; +} + +void +msp430_override_options () +{ + const struct mcu_type_s *t; + + for (t = msp430_mcu_types; t->name; t++) + { + if (strcmp (t->name, msp430_mcu_name) == 0) + break; + } + + if (!t->name) + { + error ("MCU %s not supported", msp430_mcu_name); + fprintf (stderr, "Known MCU names:\n"); + for (t = msp430_mcu_types; t->name; t++) + fprintf (stderr, " %s\n", t->name); + abort (); + return; + } + + msp430_has_hwmul = t->has_hwmul || TARGET_HWMUL; + + if (TARGET_NO_HWMUL) + msp430_has_hwmul = 0; + + msp430_case_values_threshold = 8; /* ? or there is a better value ? */ +} + +rtx mpy_rtx, mpys_rtx, mac_rtx, macs_rtx, op2_rtx, reslo_rtx, reshi_rtx, + sumext_rtx, ressi_rtx; + + +static char __dummy[1024]; + +rtx +sym_ref(mode, arg) +enum machine_mode mode; +const char *arg; +{ + rtx rt; + static int i = 0; + rt = (rtx) &__dummy[i]; + i += sizeof(*rt); + memset(rt,0,4); + PUT_CODE(rt,SYMBOL_REF); + PUT_MODE(rt,mode); + XSTR(rt,0) = arg; + + return rt; +} + + +void +msp430_init_once () +{ +/****************************** + + __MPY=0x130 + __MPYS=0x132 + __MAC=0x134 + __MACS=0x136 + __OP2=0x138 + __RESLO=0x13a + __RESHI=0x13c + __SUMEXT=0x13e + __RESSI <- not natural + *****************************/ + + mpy_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__MPY")); + mpys_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__MPYS")); + mac_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__MAC")); + macs_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__MACS")); + op2_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__OP2")); + reslo_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__RESLO")); + reshi_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__RESHI")); + sumext_rtx = gen_rtx_MEM (HImode, sym_ref (HImode, "__SUMEXT")); + ressi_rtx = gen_rtx_MEM (SImode, sym_ref (SImode, "__RESLO")); + return; +} + +static int reg_class_tab[16] = { + PC_REG, STACK_REGS, CG_REGS, CG_REGS, + GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, + GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, + GENERAL_REGS, GENERAL_REGS /* r0 - r15 */ +}; + + +int +msp430_regno_ok_for_base_p (r) + int r; +{ + + if (r == 2) + return 0; + if (r == 3) + return 0; + if (r < FIRST_PSEUDO_REGISTER && r > 0) + return 1; + if (reg_renumber + && reg_renumber[r] < FIRST_PSEUDO_REGISTER + && reg_renumber[r] > 0 && reg_renumber[r] != 2 && reg_renumber[r] != 3) + return 1; + + return 0; + +} + +enum reg_class +msp430_regno_reg_class (r) + int r; +{ + if (r < FIRST_PSEUDO_REGISTER) + return reg_class_tab[r]; + + return NO_REGS; +} + + +enum reg_class +msp430_reg_class_from_letter (c) + int c; +{ + switch (c) + { + case 'd': + return SP_REG; + default: + break; + } + + return NO_REGS; +} + + + +#define NOVECTOR 0xff + +void +asm_declare_function_name (file, name, decl) + FILE *file; + char *name; + tree decl ATTRIBUTE_UNUSED; +{ + int interrupt_func_p; + tree ss = 0; + int vector = -1; + int vectors_start; + int cfp = msp430_critical_function_p (current_function_decl); + int ree = msp430_reentrant_function_p (current_function_decl); + + interrupt_func_p = interrupt_function_p (current_function_decl); + + if (interrupt_func_p) + { + /* + * .global This_func1 + * .set vector11, This_func1 + * .type This_func1,@function + * + */ + if (msp430_is_xarch()) + { + vectors_start = 0xffc0; + } + else + { + vectors_start = 0xffe0; + } + + ss = lookup_attribute ("interrupt", + DECL_ATTRIBUTES (current_function_decl)); + ss = TREE_VALUE (ss); + if (ss) + { + ss = TREE_VALUE (ss); + if (ss) + vector = TREE_INT_CST_LOW (ss); + + if (vector != NOVECTOR) + vector += vectors_start; + } + + if (vector == -1) + { + warning ("No valid interrupt vector assigned to ISR `%s'.", name); + } + + if ((vector < vectors_start || vector > 0xfffe || (vector & 1)) + && (vector != NOVECTOR && vector != -1)) + { + warning + ("Interrupt vector 0x%x assigned to ISR `%s' is invalid.", + vector, name); + } + + if (vector != NOVECTOR) + { + fprintf (file, ".global vector_%04x\n", vector); + } + fprintf (file, "%s", TYPE_ASM_OP); + assemble_name (file, name); + putc (',', file); + fprintf (file, TYPE_OPERAND_FMT, "function"); + putc ('\n', file); + fprintf (file, "/***********************\n"); + fprintf (file, " * Interrupt %sRoutine `", + (vector != NOVECTOR) ? "Service " : "Sub-"); + assemble_name (file, name); + fprintf (file, "' at 0x%04x\n", vector); + fprintf (file, " ***********************/\n"); + + if (vector != NOVECTOR) + { + fprintf (file, "vector_%04x:\n", vector); + } + + ASM_OUTPUT_LABEL (file, name); + } + else + { + fprintf (file, "%s", TYPE_ASM_OP); + assemble_name (file, name); + putc (',', file); + fprintf (file, TYPE_OPERAND_FMT, "function"); + putc ('\n', file); + fprintf (file, "/***********************\n"); + fprintf (file, " * Function `"); + assemble_name (file, name); + fprintf (file, "' %s\n ***********************/\n", + cfp ? "(OS critical)" : ree ? "(reentrant)" : ""); + ASM_OUTPUT_LABEL (file, name); + } +} + + +static int +msp430_saved_regs_frame (void) +{ + int interrupt_func_p = interrupt_function_p (current_function_decl); + int cfp = msp430_critical_function_p (current_function_decl); + int leaf_func_p = leaf_function_p (); + int offset = interrupt_func_p ? 0 : (cfp ? 2 : 0); + int reg; + + for (reg = 4; reg < 16; ++reg) + { + if ((!leaf_func_p && call_used_regs[reg] && (interrupt_func_p)) + || (regs_ever_live[reg] + && (!call_used_regs[reg] || interrupt_func_p))) + { + offset += 2; + } + } + + return offset; +} + +int +msp430_empty_epilogue () +{ + int cfp = msp430_critical_function_p (current_function_decl); + int ree = msp430_reentrant_function_p (current_function_decl); + int nfp = msp430_naked_function_p (current_function_decl); + int ifp = interrupt_function_p (current_function_decl); + int wup = wakeup_function_p (current_function_decl); + int size = msp430_saved_regs_frame (); + int fs = get_frame_size (); + + if (cfp && ree) + ree = 0; + + /* the following combination of attributes forces to issue + some commands in function epilogue */ + if (ree + || nfp || fs || wup || MAIN_NAME_P (DECL_NAME (current_function_decl))) + return 0; + + size += fs; + + /* <= 2 necessary for first call */ + if (size <= 2 && cfp) + return 2; + if (size == 0 && !cfp && !ifp) + return 1; + if (size == 0 && ifp) + return 2; + + return 0; +} + +/* Returns a number of pushed registers */ +static int +msp430_func_num_saved_regs () +{ + int i; + int saves = 0; + int interrupt_func_p = interrupt_function_p (current_function_decl); + int leaf_func_p = leaf_function_p (); + + for (i = 4; i < 16; i++) + { + if ((regs_ever_live[i] + && (!call_used_regs[i] + || interrupt_func_p)) + || (!leaf_func_p && (call_used_regs[i] && interrupt_func_p))) + { + saves += 1; + } + } + + return saves; +} + + +/* Output function prologue */ +void +function_prologue (file, size) + FILE *file; + int size; +{ + int i; + int interrupt_func_p = interrupt_function_p (current_function_decl); + int signal_func_p = signal_function_p (current_function_decl); + int leaf_func_p = leaf_function_p (); + int main_p = MAIN_NAME_P (DECL_NAME (current_function_decl)); + int stack_reserve = 0; + tree ss = 0; + rtx x = DECL_RTL (current_function_decl); + const char *fnname = XSTR (XEXP (x, 0), 0); + int offset; + int cfp = msp430_critical_function_p (current_function_decl); + int tfp = msp430_task_function_p (current_function_decl); + int ree = msp430_reentrant_function_p (current_function_decl); + int save_prologue_p = + msp430_save_prologue_function_p (current_function_decl); + int num_saved_regs; + + return_issued = 0; + last_insn_address = 0; + jump_tables_size = 0; + prologue_size = 0; + + /* check attributes compatibility */ + + if ((cfp && ree) || (ree && interrupt_func_p)) + { + warning ("attribute 'reentrant' ignored"); + ree = 0; + } + + if (cfp && interrupt_func_p) + { + warning ("attribute 'critical' ignored"); + cfp = 0; + } + + if (signal_func_p && !interrupt_func_p) + { + warning ("attribute 'signal' does not make sense."); + signal_func_p = 0; + } + + /* naked function discards everything */ + if (msp430_naked_function_p (current_function_decl)) + { + fprintf (file, "\t/* prologue: naked */\n"); + fprintf (file, ".L__FrameSize_%s=0x%x\n", fnname, size); + return; + } + ss = lookup_attribute ("reserve", DECL_ATTRIBUTES (current_function_decl)); + if (ss) + { + ss = TREE_VALUE (ss); + if (ss) + { + ss = TREE_VALUE (ss); + if (ss) + stack_reserve = TREE_INT_CST_LOW (ss); + stack_reserve++; + stack_reserve &= ~1; + } + } + + fprintf (file, "\t/* prologue: frame size = %d */\n", size); + fprintf (file, ".L__FrameSize_%s=0x%x\n", fnname, size); + + + offset = initial_elimination_offset (0, 0) - 2; + + msp430_current_frame_offset = offset; + + fprintf (file, ".L__FrameOffset_%s=0x%x\n", fnname, offset); + + if (signal_func_p && interrupt_func_p) + { + prologue_size += 1; + fprintf (file, "\teint\t; enable nested interrupt\n"); + } + + if (main_p) + { + if (TARGET_NSI) + { + if (size || stack_reserve) + fprintf (file, "\tsub\t#%d, r1\t", size + stack_reserve); + if (frame_pointer_needed) + { + fprintf (file, "\tmov\tr1,r%d\n", FRAME_POINTER_REGNUM); + prologue_size += 1; + } + + if (size) + prologue_size += 2; + if (size == 1 || size == 2 || size == 4 || size == 8) + prologue_size--; + } + else + { + fprintf (file, "\tmov\t#(%s-%d), r1\n", msp430_init_stack, + size + stack_reserve); + + if (frame_pointer_needed) + { + fprintf (file, "\tmov\tr1,r%d\n", FRAME_POINTER_REGNUM); + prologue_size += 1; + } + prologue_size += 2; + } + } + else + { + /* Here, we've got a chance to jump to prologue saver */ + num_saved_regs = msp430_func_num_saved_regs (); + + if ((TARGET_SAVE_PROLOGUE || save_prologue_p) + && !interrupt_func_p && !arg_register_used[12] && num_saved_regs > 4) + { + fprintf (file, "\tsub\t#16, r1\n"); + fprintf (file, "\tmov\tr0, r12\n"); + fprintf (file, "\tadd\t#8, r12\n"); + fprintf (file, "\tbr\t#__prologue_saver+%d\n", + (8 - num_saved_regs) * 4); + + if (cfp && 8 - num_saved_regs) + { + int n = 16 - num_saved_regs * 2; + fprintf (file, "\tadd\t#%d, r1\n", n); + if (n != 0 && n != 1 && n != 2 && n != 4 && n != 8) + prologue_size += 1; + } + else + size -= 16 - num_saved_regs * 2; + + prologue_size += 7; + } + else if(!tfp) + { + for (i = 15; i >= 4; i--) + { + if ((regs_ever_live[i] + && (!call_used_regs[i] + || interrupt_func_p)) + || (!leaf_func_p && (call_used_regs[i] + && (interrupt_func_p)))) + { + fprintf (file, "\tpush\tr%d\n", i); + prologue_size += 1; + } + } + } + + if (!interrupt_func_p && cfp) + { + prologue_size += 3; + fprintf (file, "\tpush\tr2\n"); + fprintf (file, "\tdint\n"); + if (!size) + fprintf (file, "\tnop\n"); + } + + if (size) + { + /* The next is a hack... I do not undestand why, but if there + ARG_POINTER_REGNUM and FRAME/STACK are different, + the compiler fails to compute corresponding + displacement */ + if (!optimize && !optimize_size + && regs_ever_live[ARG_POINTER_REGNUM]) + { + int o = initial_elimination_offset (0, 0) - size; + fprintf (file, "\tmov\tr1, r%d\n", ARG_POINTER_REGNUM); + fprintf (file, "\tadd\t#%d, r%d\n", o, ARG_POINTER_REGNUM); + prologue_size += 2; + if (o != 0 && o != 1 && o != 2 && o != 4 && o != 8) + prologue_size += 1; + } + + /* adjust frame ptr... */ + if (size > 0) + fprintf (file, "\tsub\t#%d, r1\t; %d, fpn %d\n", (size + 1) & ~1, + size, frame_pointer_needed); + else + { + size = -size; + fprintf (file, "\tadd\t#%d, r1\t; %d, fpn %d\n", + (size + 1) & ~1, size, frame_pointer_needed); + } + + if (frame_pointer_needed) + { + fprintf (file, "\tmov\tr1,r%d\n", FRAME_POINTER_REGNUM); + prologue_size += 1; + } + + if (size == 1 || size == 2 || size == 4 || size == 8) + prologue_size += 1; + else + prologue_size += 2; + } + + /* disable interrupt for reentrant function */ + if (!interrupt_func_p && ree) + { + prologue_size += 1; + fprintf (file, "\tdint\n"); + } + } + + fprintf (file, "\t/* prologue end (size=%d) */\n\n", prologue_size); +} + + +/* Output function epilogue */ + +void +function_epilogue (file, size) + FILE *file; + int size; +{ + int i; + int interrupt_func_p = interrupt_function_p (current_function_decl); + int leaf_func_p = leaf_function_p (); + int main_p = MAIN_NAME_P (DECL_NAME (current_function_decl)); + int wakeup_func_p = wakeup_function_p (current_function_decl); + int cfp = msp430_critical_function_p (current_function_decl); + int ree = msp430_reentrant_function_p (current_function_decl); + int save_prologue_p = + msp430_save_prologue_function_p (current_function_decl); + int still_return = 1; + int function_size; + + + last_insn_address = 0; + jump_tables_size = 0; + epilogue_size = 0; + function_size = (INSN_ADDRESSES (INSN_UID (get_last_insn ())) + - INSN_ADDRESSES (INSN_UID (get_insns ()))); + + if (msp430_task_function_p (current_function_decl)) + { + fprintf (file, "\n\t/* epilogue: empty, task functions never return */\n"); + return; + } + + if (msp430_naked_function_p (current_function_decl)) + { + fprintf (file, "\n\t/* epilogue: naked */\n"); + return; + } + + if (msp430_empty_epilogue ()) + { + if (!return_issued) + { + fprintf (file, "\t%s\n", msp430_emit_return (NULL, NULL, NULL)); + epilogue_size++; + } + fprintf (file, "\n\t/* epilogue: not required */\n"); + goto done_epilogue; + } + + if ((cfp || interrupt_func_p) && ree) + ree = 0; + if (cfp && interrupt_func_p) + cfp = 0; + + fprintf (file, "\n\t/* epilogue: frame size=%d */\n", size); + + if (main_p) + { + if (size) + fprintf (file, "\tadd\t#%d, r1\n", (size + 1) & ~1); + fprintf (file, "\tbr\t#%s\n", msp430_endup); + epilogue_size += 4; + if (size == 1 || size == 2 || size == 4 || size == 8) + epilogue_size--; + } + else + { + if (ree) + { + fprintf (file, "\teint\n"); + epilogue_size += 1; + } + + if (size) + { + fprintf (file, "\tadd\t#%d, r1\n", (size + 1) & ~1); + if (size == 1 || size == 2 || size == 4 || size == 8) + epilogue_size += 1; + else + epilogue_size += 2; + } + + if (!interrupt_func_p && cfp) + { + epilogue_size += 1; + if (msp430_saved_regs_frame () == 2) + { + fprintf (file, "\treti\n"); + still_return = 0; + } + else + fprintf (file, "\tpop\tr2\n"); + } + + if ((TARGET_SAVE_PROLOGUE || save_prologue_p) + && !interrupt_func_p && msp430_func_num_saved_regs () > 2) + { + fprintf (file, "\tbr\t#__epilogue_restorer+%d\n", + (8 - msp430_func_num_saved_regs ()) * 2); + epilogue_size += 2; + } + else if ((TARGET_SAVE_PROLOGUE || save_prologue_p) && interrupt_func_p) + { + fprintf (file, "\tbr\t#__epilogue_restorer_intr+%d\n", + (12 - msp430_func_num_saved_regs ()) * 2); + } + else + { + for (i = 4; i < 16; i++) + { + if ((regs_ever_live[i] + && (!call_used_regs[i] + || interrupt_func_p)) + || (!leaf_func_p && (call_used_regs[i] && interrupt_func_p))) + { + fprintf (file, "\tpop\tr%d\n", i); + epilogue_size += 1; + } + } + + if (interrupt_func_p) + { + if (wakeup_func_p) + { + fprintf (file, "\tbic\t#0xf0,0(r1)\n"); + epilogue_size += 3; + } + + fprintf (file, "\treti\n"); + epilogue_size += 1; + } + else + { + if (still_return) + fprintf (file, "\tret\n"); + epilogue_size += 1; + } + } + } + + fprintf (file, "\t/* epilogue end (size=%d) */\n", epilogue_size); +done_epilogue: + fprintf (file, "\t/* function %s size %d (%d) */\n", current_function_name, + prologue_size + function_size + epilogue_size, function_size); + + commands_in_file += prologue_size + function_size + epilogue_size; + commands_in_prologues += prologue_size; + commands_in_epilogues += epilogue_size; +} + + +/* Attempts to replace X with a valid + memory address for an operand of mode MODE */ +/* FIXME: broken call */ +rtx +legitimize_address (x, oldx, mode) + rtx x; + rtx oldx ATTRIBUTE_UNUSED; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + /* if (GET_CODE (oldx) == MEM + && GET_CODE (XEXP(oldx,0)) == PLUS + && GET_CODE (XEXP(XEXP(oldx,0),0)) == MEM) + { + x = force_operand (oldx,0); + return x; + } + + return oldx; + */ + return x; +} + +int +legitimate_address_p (mode, operand, strict) + enum machine_mode mode ATTRIBUTE_UNUSED; + rtx operand; + int strict; +{ + rtx xfoob, x = operand; + + xfoob = XEXP (operand, 0); + + /* accept @Rn (Rn points to operand address ) */ + if (GET_CODE (operand) == REG + && (strict ? REG_OK_FOR_BASE_STRICT_P (x) + : REG_OK_FOR_BASE_NOSTRICT_P (x))) + goto granted; + + /* accept address */ + if (CONSTANT_P (operand)) + goto granted; + + /* accept X(Rn) Rn + X points to operand address */ + if (GET_CODE (operand) == PLUS + && GET_CODE (XEXP (operand, 0)) == REG + && CONSTANT_P (XEXP (operand, 1)) + && (strict ? (REG_OK_FOR_BASE_STRICT_P (xfoob)) + : (REG_OK_FOR_BASE_NOSTRICT_P (xfoob)))) + goto granted; + + if (TARGET_ALL_DEBUG) + fprintf (stderr, "Address Failed\n"); + return 0; + +granted: + if (TARGET_ALL_DEBUG) + fprintf (stderr, "Address granted\n"); + return 1; +} + + +void +print_operand_address (file, addr) + FILE *file; + rtx addr; +{ + /* hopefully will be never entered. */ + switch (GET_CODE (addr)) + { + case REG: + fprintf (file, "r%d", REGNO (addr)); + return; + case POST_INC: + fprintf (file, "@r%d+", REGNO (XEXP(addr,0))); + return; + case SYMBOL_REF: + case LABEL_REF: + case CONST: + fprintf (file, "#"); + break; + case CODE_LABEL: + break; + default: + abort (); + fprintf (file, "&"); + } + output_addr_const (file, addr); +} + +void print_sub_operand PARAMS ((FILE *, rtx, int)); + +const char *trim_array[] = { "llo", "lhi", "hlo", "hhi" }; + + + +void +print_sub_operand (file, x, code) + FILE *file; + rtx x; + int code; +{ + + if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) + { + output_addr_const (file, x); + return; + } + else if (GET_CODE (x) == CONST) + { + print_sub_operand (file, XEXP (x, 0), code); + return; + } + else if (GET_CODE (x) == PLUS) + { + print_sub_operand (file, XEXP (x, 0), code); + fprintf (file, "+"); + print_sub_operand (file, XEXP (x, 1), code); + return; + } + else if (GET_CODE (x) == CONST_INT) + { + fprintf (file, "%d", INTVAL (x)); + return; + } + else + abort (); +} + +void +print_operand (file, x, code) + FILE *file; + rtx x; + int code; +{ + int shift = 0; + int ml = GET_MODE_SIZE (x->mode); + int source_reg = 0; + + + if (ml > 1) + ml = 2; + + if (code >= 'A' && code <= 'D') + shift = code - 'A'; + + if (code >= 'E' && code <= 'H') + { + shift = code - 'E'; + source_reg = 1; + } + + if (code >= 'I' && code <= 'L') + { + ml = 1; + shift = code - 'I'; + } + + if (GET_CODE (x) == PLUS) + { + fprintf (file, "add%s", shift ? "c" : ""); + } + else if (GET_CODE (x) == MINUS) + { + fprintf (file, "sub%s", shift ? "c" : ""); + } + else if (GET_CODE (x) == AND) + { + fprintf (file, "and"); + } + else if (GET_CODE (x) == IOR) + { + fprintf (file, "bis"); + } + else if (GET_CODE (x) == XOR) + { + fprintf (file, "xor"); + } + else if (REG_P (x)) + { + fprintf (file, reg_names[true_regnum (x) + shift]); + } + else if (GET_CODE (x) == CONST_INT) + { + if (code != 'F') + fprintf (file, "#%s(%d)", trim_array[shift], INTVAL (x)); + else + fprintf (file, "%d", INTVAL (x)); + } + else if (GET_CODE (x) == MEM) + { + rtx addr = XEXP (x, 0); + + if (GET_CODE (addr) == POST_INC) + { + fprintf (file, "@r%d+", REGNO (XEXP(addr,0))); + } + else if (GET_CODE (addr) == REG) + { /* for X(Rn) */ + if (shift || !source_reg) + { + if (shift) + fprintf (file, "%d(r%d)", shift * ml, REGNO (addr)); + else + fprintf (file, "@r%d", REGNO (addr)); + } + else if (source_reg) + { + fprintf (file, "r%d", REGNO (addr) + shift); + } + else + { + fprintf (file, "@r%d", REGNO (addr)); + } + } + else if (GET_CODE (addr) == SYMBOL_REF) + { + fprintf (file, "&"); + output_addr_const (file, addr); + if (shift) + fprintf (file, "+%d", shift * ml); + } + else if (GET_CODE (addr) == CONST || GET_CODE (addr) == CONST_INT) + { + fputc ('&', file); + output_addr_const (file, addr); + if (shift) + fprintf (file, "+%d", shift * ml); + } + else if (GET_CODE (addr) == PLUS) + { + + print_sub_operand (file, XEXP (addr, 1), code); + + /* shift if the indirect pointer register is the stack pointer */ + if ((code >= 'M' && code <= 'N') && (REGNO (XEXP (addr, 0)) == 1)) + shift = code - 'M'; + + if (shift) + fprintf (file, "+%d", shift * ml); + + if (REG_P (XEXP (addr, 0))) + fprintf (file, "(r%d)", REGNO (XEXP (addr, 0))); + else + abort (); + } + else if (GET_CODE (addr) == MEM) + { + fprintf (file, "@(Invalid addressing mode)"); + print_operand (file, addr, code); + } + else + { + fprintf (file, "Unknown operand. Please check."); + } + } + else if (GET_CODE (x) == SYMBOL_REF) + { + fprintf (file, "#"); + output_addr_const (file, x); + if (shift) + fprintf (file, "+%d", shift * ml); + } + else if (GET_CODE (x) == CONST_DOUBLE) + { + if (GET_MODE (x) == VOIDmode) /* FIXME: may be long long?? */ + { + if (shift < 2) + fprintf (file, "#%s(%d)", trim_array[shift], CONST_DOUBLE_LOW (x)); + else + fprintf (file, "#%s(%d)", trim_array[shift - 2], + CONST_DOUBLE_HIGH (x)); + } + else if (GET_MODE (x) == SFmode || GET_MODE (x) == SImode) + { + long val; + REAL_VALUE_TYPE rv; + REAL_VALUE_FROM_CONST_DOUBLE (rv, x); + REAL_VALUE_TO_TARGET_SINGLE (rv, val); + asm_fprintf (file, "#%s(0x%lx)", trim_array[shift], val); + } + else + { + fatal_insn ("Internal compiler bug. Unknown mode:", x); + } + } + else + print_operand_address (file, x); +} + +/* mode for branch instruction */ +int +msp430_jump_dist (x, insn) + rtx x; + rtx insn; +{ + int dest_addr = INSN_ADDRESSES (INSN_UID (GET_CODE (x) == LABEL_REF + ? XEXP (x, 0) : x)); + int cur_addr = INSN_ADDRESSES (INSN_UID (insn)); + int jump_distance = dest_addr - cur_addr; + + return jump_distance; +} + + + +#define FIRST_CUM_REG 16 +static CUMULATIVE_ARGS *cum_incoming = 0; + +/* Initializing the variable cum for the state at the beginning + of the argument list. */ +void +init_cumulative_args (cum, fntype, libname, indirect) + CUMULATIVE_ARGS *cum; + tree fntype; + rtx libname; + int indirect ATTRIBUTE_UNUSED; +{ + cum->nregs = 4; + cum->regno = FIRST_CUM_REG; + if (!libname) + { + int stdarg = (TYPE_ARG_TYPES (fntype) != 0 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) + != void_type_node)); + if (stdarg) + cum->nregs = 0; + } +} + +/* the same in scope of the cum.args., buf usefull for a + function call */ +void +init_cumulative_incoming_args (cum, fntype, libname) + CUMULATIVE_ARGS *cum; + tree fntype; + rtx libname; +{ + int i; + cum->nregs = 4; + cum->regno = FIRST_CUM_REG; + if (!libname) + { + int stdarg = (TYPE_ARG_TYPES (fntype) != 0 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) + != void_type_node)); + if (stdarg) + cum->nregs = 0; + } + + for (i = 0; i < 16; i++) + arg_register_used[i] = 0; + + cum_incoming = cum; +} + +rtx +msp430_libcall_value (mode) + enum machine_mode mode; +{ + int offs = GET_MODE_SIZE (mode); + offs >>= 1; + if (offs < 1) + offs = 1; + return gen_rtx (REG, mode, (RET_REGISTER + 1 - offs)); +} + +rtx +msp430_function_value (type, func) + tree type; + tree func ATTRIBUTE_UNUSED; +{ + int offs; + if (TYPE_MODE (type) != BLKmode) + return msp430_libcall_value (TYPE_MODE (type)); + + offs = int_size_in_bytes (type); + offs >>= 1; + if (offs < 1) + offs = 1; + if (offs > 1 && offs < (GET_MODE_SIZE (SImode) >> 1)) + offs = GET_MODE_SIZE (SImode) >> 1; + else if (offs > (GET_MODE_SIZE (SImode) >> 1) + && offs < (GET_MODE_SIZE (DImode) >> 1)) + offs = GET_MODE_SIZE (DImode) >> 1; + + return gen_rtx (REG, BLKmode, (RET_REGISTER + 1 - offs)); +} + +/* Returns the number of registers to allocate for a function argument. */ +static int +msp430_num_arg_regs (mode, type) + enum machine_mode mode; + tree type; +{ + int size; + + if (mode == BLKmode) + size = int_size_in_bytes (type); + else + size = GET_MODE_SIZE (mode); + + if (size < 2) + size = 2; + + /* we do not care if argument is passed in odd register + so, do not align the size ... + BUT!!! even char argument passed in 16 bit register + so, align the size */ + return ((size + 1) & ~1) >> 1; +} + +/* Controls whether a function argument is passed + in a register, and which register. */ +rtx +function_arg (cum, mode, type, named) + CUMULATIVE_ARGS *cum; + enum machine_mode mode; + tree type; + int named ATTRIBUTE_UNUSED; +{ + int regs = msp430_num_arg_regs (mode, type); + + if (cum->nregs && regs <= cum->nregs) + { + int regnum = cum->regno - regs; + + if (cum == cum_incoming) + { + arg_register_used[regnum] = 1; + if (regs >= 2) + arg_register_used[regnum + 1] = 1; + if (regs >= 3) + arg_register_used[regnum + 2] = 1; + if (regs >= 4) + arg_register_used[regnum + 3] = 1; + } + + return gen_rtx (REG, mode, regnum); + } + return NULL_RTX; +} + + +/* Update the summarizer variable CUM to advance past an argument + in the argument list. */ +void +function_arg_advance (cum, mode, type, named) + CUMULATIVE_ARGS *cum; + enum machine_mode mode; + tree type; + int named ATTRIBUTE_UNUSED; +{ + int regs = msp430_num_arg_regs (mode, type); + + cum->nregs -= regs; + cum->regno -= regs; + + if (cum->nregs <= 0) + { + cum->nregs = 0; + cum->regno = FIRST_CUM_REG; + } +} + +/* Workaround for volatile variables */ +int +nonimmediate_operand_msp430 (op, mode) + rtx op; + enum machine_mode mode; +{ + int save_volatile_ok = volatile_ok; + int niop = 0; + + if (!TARGET_NVWA) + volatile_ok = 1; + niop = nonimmediate_operand (op, mode); + volatile_ok = save_volatile_ok; + + return niop; +} + +int +memory_operand_msp430 (op, mode) + rtx op; + enum machine_mode mode; +{ + int save_volatile_ok = volatile_ok; + int mop = 0; + + if (!TARGET_NVWA) + volatile_ok = 1; + mop = memory_operand (op, mode); + volatile_ok = save_volatile_ok; + return mop; +} + +int +general_operand_msp430 (op, mode) + rtx op; + enum machine_mode mode; +{ + int save_volatile_ok = volatile_ok; + int gop = 0; + + if (!TARGET_NVWA) + volatile_ok = 1; + gop = general_operand (op, mode); + volatile_ok = save_volatile_ok; + return gop; +} + + +int +halfnibble_integer (op, mode) + rtx op; + enum machine_mode mode; +{ + int hi, lo; + int val; + + if (!const_int_operand (op, mode)) + return 0; + + /* this integer is the one of form: + 0xXXXX0000 or 0x0000XXXX, + where XXXX not one of -1,1,2,4,8 + */ + val = INTVAL (op); + hi = ((val & 0xffff0000ul) >> 16) & 0xffff; + lo = (val & 0xffff); + + if (hi && lo) + return 0; + + if (hi && hi != 0xffff && hi != 1 && hi != 2 && hi != 4 && hi != 8) + return 1; + if (lo && lo != 0xffff && lo != 1 && lo != 2 && lo != 4 && lo != 8) + return 1; + + return 0; +} + + +int +halfnibble_constant (op, mode) + rtx op; + enum machine_mode mode; +{ + int hi, lo; + int val; + + if (!const_int_operand (op, mode)) + return 0; + + /* this integer is the one of form: + 0xXXXX0000 or 0x0000XXXX, + where XXXX one of -1,1,2,4,8 + */ + val = INTVAL (op); + hi = ((val & 0xffff0000ul) >> 16) & 0x0000ffff; + lo = (val & 0x0000ffff); + + if ((hi && lo) || (!hi && !lo)) + return 0; + + if (hi == 0xffff || hi == 1 || hi == 2 || hi == 4 || hi == 8) + return 1; + if (lo == 0xffff || lo == 1 || lo == 2 || lo == 4 || lo == 8) + return 1; + + if (!(hi && lo)) + return 1; + + return 0; +} + + +int +halfnibble_integer_shift (op, mode) + rtx op; + enum machine_mode mode; +{ + int hi, lo; + int val; + + if (!immediate_operand (op, mode)) + return 0; + + /* this integer is the one of form: + 0xXXXX0000 or 0x0000XXXX, + where XXXX not one of -1,1,2,4,8 + */ + val = 1 << INTVAL (op); + hi = ((val & 0xffff0000ul) >> 16) & 0x0000ffff; + lo = (val & 0x0000ffff); + + if (hi && lo) + return 0; + + if (hi && hi != 0xffff && hi != 1 && hi != 2 && hi != 4 && hi != 8) + return 1; + if (lo && lo != 0xffff && lo != 1 && lo != 2 && lo != 4 && lo != 8) + return 1; + + return 0; +} + + +int +halfnibble_constant_shift (op, mode) + rtx op; + enum machine_mode mode; +{ + int hi, lo; + int val; + + if (!immediate_operand (op, mode)) + return 0; + + /* this integer is the one of form: + 0xXXXX0000 or 0x0000XXXX, + where XXXX one of -1,1,2,4,8 + */ + val = 1 << INTVAL (op); + hi = ((val & 0xffff0000ul) >> 16) & 0x0000ffff; + lo = (val & 0x0000ffff); + + if (hi && lo) + return 0; + + if (hi && hi == 0xffff && hi == 1 && hi == 2 && hi == 4 && hi == 8) + return 1; + if (lo && lo == 0xffff && lo == 1 && lo == 2 && lo == 4 && lo == 8) + return 1; + + return 0; +} + + +int +which_nibble (val) + int val; +{ + if (val & 0xffff0000ul) + return 1; + return 0; +} + + +int +which_nibble_shift (val) + int val; +{ + if (val & 0xffff0000ul) + return 1; + return 0; +} + + +int +extra_constraint (x, c) + rtx x; + int c; +{ + + if (c == 'R') + { + if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == REG) + { + rtx xx = XEXP (x, 0); + int regno = REGNO (xx); + if (regno >= 4 || regno == 1) + return 1; + } + } + else if (c == 'Q') + { + if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == REG) + { + rtx xx = XEXP (x, 0); + int regno = REGNO (xx); + if (regno >= 4 || regno == 1) + return 1; + } + + if (GET_CODE (x) == MEM + && GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) + { + rtx xx = XEXP (XEXP (x, 0), 0); + int regno = REGNO (xx); + if (regno >= 4 || regno == 1) + return 1; + } + + if (GET_CODE (x) == MEM + && GET_CODE (XEXP (x, 0)) == PLUS && REG_P (XEXP (XEXP (x, 0), 0))) + { + return 1; + } + + } + else if (c == 'S') + { + if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == SYMBOL_REF) + { + return 1; + } + } + + return 0; +} + +int +indexed_location (x) + rtx x; +{ + int r = 0; + + if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == REG) + { + r = 1; + } + + if (TARGET_ALL_DEBUG) + { + fprintf (stderr, "indexed_location %s: %s \n", + r ? "granted" : "failed", + reload_completed ? "reload completed" : "reload in progress"); + debug_rtx (x); + } + + return r; +} + + +int +zero_shifted (x) + rtx x; +{ + int r = 0; + + if (GET_CODE (x) == MEM && + GET_CODE (XEXP (x, 0)) == REG + && REGNO (XEXP (x, 0)) != STACK_POINTER_REGNUM + && REGNO (XEXP (x, 0)) != FRAME_POINTER_REGNUM + /* the following is Ok, cause we do not corrupt r4 within ISR */ + /*&& REGNO(XEXP (x,0)) != ARG_POINTER_REGNUM */ ) + { + r = 1; + } + return r; +} + + +int +default_rtx_costs (X, code, outer_code) + rtx X ATTRIBUTE_UNUSED; + enum rtx_code code; + enum rtx_code outer_code ATTRIBUTE_UNUSED; +{ + int cost = 0; + + switch (code) + { + case SYMBOL_REF: + cost = 1; + break; + case LABEL_REF: + cost = 1; + break; + case MEM: + cost += 1; + break; + case CONST_INT: + cost = 1; + break; + case SIGN_EXTEND: + case ZERO_EXTEND: + cost += 2; + break; + default: + break; + } + return cost; +} + + +void +order_regs_for_local_alloc () +{ + unsigned int i; + + if (TARGET_REORDER) + { + reg_alloc_order[0] = 12; + reg_alloc_order[1] = 13; + reg_alloc_order[2] = 14; + reg_alloc_order[3] = 15; + for (i = 4; i < 16; i++) + reg_alloc_order[i] = 15 - i; + } + else + { + for (i = 0; i < 16; i++) + reg_alloc_order[i] = 15 - i; + } + + return; +} + +/* Output rtx VALUE as .byte to file FILE */ +void +asm_output_char (file, value) + FILE *file; + rtx value; +{ + fprintf (file, "\t.byte\t"); + output_addr_const (file, value); + fprintf (file, "\n"); +} + +/* Output VALUE as .byte to file FILE */ +void +asm_output_byte (file, value) + FILE *file; + int value; +{ + fprintf (file, "\t.byte 0x%x\n", value & 0xff); +} + +/* Output rtx VALUE as .word to file FILE */ +void +asm_output_short (file, value) + FILE *file; + rtx value; +{ + fprintf (file, "\t.word "); + output_addr_const (file, (value)); + fprintf (file, "\n"); +} + +/* Output real N to file FILE */ +void +asm_output_float (file, n) + FILE *file; + REAL_VALUE_TYPE n; +{ + long val; + char dstr[100]; + + REAL_VALUE_TO_TARGET_SINGLE (n, val); + REAL_VALUE_TO_DECIMAL (n, "%g", dstr); + fprintf (file, "\t.long 0x%08lx\t/* %s */\n", val, dstr); +} + +/* Sets section name for declaration DECL */ +void +unique_section (decl, reloc) + tree decl; + int reloc ATTRIBUTE_UNUSED; +{ + int len; + const char *name, *prefix; + char *string; + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + STRIP_NAME_ENCODING (name, name); + + if ((TREE_CODE (decl) == FUNCTION_DECL) || DECL_READONLY_SECTION (decl, 0)) + prefix = ".text."; + else if ((DECL_INITIAL (decl) == 0) || (DECL_INITIAL (decl) == error_mark_node)) + prefix = ".bss."; + else + prefix = ".data."; + + len = strlen (name) + strlen (prefix); + string = alloca (len + 1); + sprintf (string, "%s%s", prefix, name); + DECL_SECTION_NAME (decl) = build_string (len, string); +} + + +/* Output section name to file FILE + We make the section read-only and executable for a function decl, + read-only for a const data decl, and writable for a non-const data decl. */ + +void +asm_output_section_name (file, decl, name, reloc) + FILE *file; + tree decl; + const char *name; + int reloc ATTRIBUTE_UNUSED; +{ + fprintf (file, ".section %s, \"%s\", @progbits\n", name, + decl && TREE_CODE (decl) == FUNCTION_DECL ? "ax" : + decl && TREE_READONLY (decl) ? "a" : "aw"); +} + + +/* The routine used to output NUL terminated strings. We use a special + version of this for most svr4 targets because doing so makes the + generated assembly code more compact (and thus faster to assemble) + as well as more readable, especially for targets like the i386 + (where the only alternative is to output character sequences as + comma separated lists of numbers). */ + +void +gas_output_limited_string (file, str) + FILE *file; + const char *str; +{ + const unsigned char *_limited_str = (unsigned char *) str; + unsigned ch; + fprintf (file, "%s\"", STRING_ASM_OP); + for (; (ch = *_limited_str); _limited_str++) + { + int escape; + switch (escape = ESCAPES[ch]) + { + case 0: + putc (ch, file); + break; + case 1: + fprintf (file, "\\%03o", ch); + break; + default: + putc ('\\', file); + putc (escape, file); + break; + } + } + fprintf (file, "\"\n"); +} + +/* The routine used to output sequences of byte values. We use a special + version of this for most svr4 targets because doing so makes the + generated assembly code more compact (and thus faster to assemble) + as well as more readable. Note that if we find subparts of the + character sequence which end with NUL (and which are shorter than + STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING. */ + +void +gas_output_ascii (file, str, length) + FILE *file; + const char *str; + size_t length; +{ + const unsigned char *_ascii_bytes = (const unsigned char *) str; + const unsigned char *limit = _ascii_bytes + length; + unsigned bytes_in_chunk = 0; + for (; _ascii_bytes < limit; _ascii_bytes++) + { + const unsigned char *p; + if (bytes_in_chunk >= 60) + { + fprintf (file, "\"\n"); + bytes_in_chunk = 0; + } + for (p = _ascii_bytes; p < limit && *p != '\0'; p++) + continue; + if (p < limit && (p - _ascii_bytes) <= (signed) STRING_LIMIT) + { + if (bytes_in_chunk > 0) + { + fprintf (file, "\"\n"); + bytes_in_chunk = 0; + } + gas_output_limited_string (file, (char *) _ascii_bytes); + _ascii_bytes = p; + } + else + { + int escape; + unsigned ch; + if (bytes_in_chunk == 0) + fprintf (file, "\t.ascii\t\""); + switch (escape = ESCAPES[ch = *_ascii_bytes]) + { + case 0: + putc (ch, file); + bytes_in_chunk++; + break; + case 1: + fprintf (file, "\\%03o", ch); + bytes_in_chunk += 4; + break; + default: + putc ('\\', file); + putc (escape, file); + bytes_in_chunk += 2; + break; + } + } + } + if (bytes_in_chunk > 0) + fprintf (file, "\"\n"); +} + + + +/* Outputs to the stdio stream FILE some + appropriate text to go at the start of an assembler file. */ + +void +asm_file_start (file) + FILE *file; +{ + output_file_directive (file, main_input_filename); + fprintf (file, "\t.arch %s\n\n", msp430_mcu_name); + + if (msp430_has_hwmul) + { + fprintf (file, "/* Hardware multiplier registers: */\n" + "__MPY=0x130\n" + "__MPYS=0x132\n" + "__MAC=0x134\n" + "__MACS=0x136\n" + "__OP2=0x138\n" + "__RESLO=0x13a\n" "__RESHI=0x13c\n" "__SUMEXT=0x13e\n" "\n"); + + } + + commands_in_file = 0; + commands_in_prologues = 0; + commands_in_epilogues = 0; +} + +/* Outputs to the stdio stream FILE some + appropriate text to go at the end of an assembler file. */ + +void +asm_file_end (file) + FILE *file; +{ + fprintf (file, + "\n" + "/*********************************************************************\n" + " * File %s: code size: %d words (0x%x)\n * incl. words in prologues: %d, epilogues: %d\n" + " *********************************************************************/\n", + main_input_filename, + commands_in_file, + commands_in_file, commands_in_prologues, commands_in_epilogues); +} + +int +msp430_hard_regno_mode_ok (regno, mode) + int regno ATTRIBUTE_UNUSED; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return 1; +} + +int +frame_pointer_required_p () +{ + return (current_function_calls_alloca + /* || current_function_args_info.nregs == 0 */ + || current_function_varargs); + + /* || get_frame_size () > 0); */ +} + +enum reg_class +preferred_reload_class (x, class) + rtx x ATTRIBUTE_UNUSED; + enum reg_class class; +{ + return class; +} + +/* cfp minds the fact that the function may save r2 */ +int +initial_elimination_offset (from, to) + int from; + int to; +{ + int reg; + if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) + return 0; + else + { + int interrupt_func_p = interrupt_function_p (current_function_decl); + int cfp = msp430_critical_function_p (current_function_decl); + int leaf_func_p = leaf_function_p (); + int offset = interrupt_func_p ? 0 : (cfp ? 2 : 0); + + for (reg = 4; reg < 16; ++reg) + { + if ((!leaf_func_p && call_used_regs[reg] && (interrupt_func_p)) + || (regs_ever_live[reg] + && (!call_used_regs[reg] || interrupt_func_p))) + { + offset += 2; + } + } + return get_frame_size () + offset + 2; + } + return 0; +} + +int +adjust_insn_length (insn, len) + rtx insn; + int len; +{ + + rtx patt = PATTERN (insn); + rtx set; + + set = single_set (insn); + + if (GET_CODE (patt) == SET) + { + rtx op[10]; + op[1] = SET_SRC (patt); + op[0] = SET_DEST (patt); + + if (general_operand (op[1], VOIDmode) + && general_operand (op[0], VOIDmode)) + { + op[2] = SET_SRC (patt); + switch (GET_MODE (op[0])) + { + case QImode: + case HImode: + if (indexed_location (op[1])) + len--; + break; + + case SImode: + case SFmode: + /* get length first */ + msp430_movesi_code (insn, op, &len); + + if (zero_shifted (op[1]) && regsi_ok_safe (op)) + { + rtx reg = XEXP (op[1], 0); + if (dead_or_set_p (insn, reg)) + len -= 1; + } + else if (!zero_shifted (op[1]) && indexed_location (op[1])) + { + len -= 1; + } + break; + case DImode: + msp430_movedi_code (insn, op, &len); + if (zero_shifted (op[1]) && regdi_ok_safe (op)) + { + rtx reg = XEXP (op[1], 0); + if (dead_or_set_p (insn, reg)) + len -= 1; + } + else if (!zero_shifted (op[1]) && indexed_location (op[1])) + { + len -= 1; + } + break; + + default: + break; + } + + if (GET_CODE (op[2]) == CONST_INT) + { + if (GET_MODE (op[0]) == DImode) + { + int x = INTVAL (op[2]); + int y = (x & 0xffff0000ul) >> 16; + x = x & 0xffff; + + len -= 2; + + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 + || x == 0xffff) + len--; + if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 + || y == 0xffff) + len--; + } + else if (GET_MODE (op[0]) == SImode) + { + int x = INTVAL (op[2]); + int y = (x & 0xffff0000ul) >> 16; + x = x & 0xffff; + + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 + || x == 0xffff) + len--; + if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 + || y == 0xffff) + len--; + } + else + { + /* mighr be hi or qi modes */ + int x = INTVAL (op[2]); + x = x & 0xffff; + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 + || x == 0xffff) + len--; + } + } + + if (GET_CODE (op[2]) == CONST_DOUBLE) + { + if (GET_MODE (op[0]) == SFmode) + { + long val; + int y, x; + REAL_VALUE_TYPE rv; + REAL_VALUE_FROM_CONST_DOUBLE (rv, op[2]); + REAL_VALUE_TO_TARGET_SINGLE (rv, val); + + y = (val & 0xffff0000ul) >> 16; + x = val & 0xffff; + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 + || x == 0xffff) + len--; + if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 + || y == 0xffff) + len--; + } + else + { + int hi = CONST_DOUBLE_HIGH (op[2]); + int lo = CONST_DOUBLE_LOW (op[2]); + int x, y, z; + + x = (hi & 0xffff0000ul) >> 16; + y = hi & 0xffff; + z = (lo & 0xffff0000ul) >> 16; + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 + || x == 0xffff) + len--; + if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 + || y == 0xffff) + len--; + if (z == 0 || z == 1 || z == 2 || z == 4 || z == 8 + || z == 0xffff) + len--; + z = lo & 0xffff; + if (z == 0 || z == 1 || z == 2 || z == 4 || z == 8 + || z == 0xffff) + len--; + } + } + + return len; + } + else if (GET_CODE (op[1]) == MULT) + { + rtx ops[10]; + ops[0] = op[0]; + ops[1] = XEXP (op[1], 0); + ops[2] = XEXP (op[1], 1); + + if (GET_MODE (ops[0]) != SImode + && GET_MODE (ops[0]) != SFmode && GET_MODE (ops[0]) != DImode) + { + if (indexed_location (ops[1])) + len--; + if (indexed_location (ops[2])) + len--; + } + } + else if (GET_CODE (op[1]) == ASHIFT + || GET_CODE (op[1]) == ASHIFTRT || GET_CODE (op[1]) == LSHIFTRT) + { + rtx ops[10]; + ops[0] = op[0]; + ops[1] = XEXP (op[1], 0); + ops[2] = XEXP (op[1], 1); + + switch (GET_CODE (op[1])) + { + case ASHIFT: + switch (GET_MODE (op[0])) + { + case QImode: + msp430_emit_ashlqi3 (insn, ops, &len); + break; + case HImode: + msp430_emit_ashlhi3 (insn, ops, &len); + break; + case SImode: + msp430_emit_ashlsi3 (insn, ops, &len); + break; + case DImode: + msp430_emit_ashldi3 (insn, ops, &len); + break; + default: + break; + } + break; + + case ASHIFTRT: + switch (GET_MODE (op[0])) + { + case QImode: + msp430_emit_ashrqi3 (insn, ops, &len); + break; + case HImode: + msp430_emit_ashrhi3 (insn, ops, &len); + break; + case SImode: + msp430_emit_ashrsi3 (insn, ops, &len); + break; + case DImode: + msp430_emit_ashrdi3 (insn, ops, &len); + break; + default: + break; + } + break; + + case LSHIFTRT: + switch (GET_MODE (op[0])) + { + case QImode: + msp430_emit_lshrqi3 (insn, ops, &len); + break; + case HImode: + msp430_emit_lshrhi3 (insn, ops, &len); + break; + case SImode: + msp430_emit_lshrsi3 (insn, ops, &len); + break; + case DImode: + msp430_emit_lshrdi3 (insn, ops, &len); + break; + default: + break; + } + break; + + default: + break; + } + } + else if (GET_CODE (op[1]) == PLUS + || GET_CODE (op[1]) == MINUS + || GET_CODE (op[1]) == AND + || GET_CODE (op[1]) == IOR || GET_CODE (op[1]) == XOR) + { + rtx ops[10]; + ops[0] = op[0]; + ops[1] = XEXP (op[1], 0); + ops[2] = XEXP (op[1], 1); + + if (GET_CODE (op[1]) == AND && !general_operand (ops[1], VOIDmode)) + return len; + + switch (GET_MODE (ops[0])) + { + case QImode: + case HImode: + if (indexed_location (ops[2])) + len--; + break; + case SImode: + case SFmode: + + if (GET_CODE (op[1]) == PLUS) + msp430_addsi_code (insn, ops, &len); + if (GET_CODE (op[1]) == MINUS) + msp430_subsi_code (insn, ops, &len); + if (GET_CODE (op[1]) == AND) + msp430_andsi_code (insn, ops, &len); + if (GET_CODE (op[1]) == IOR) + msp430_iorsi_code (insn, ops, &len); + if (GET_CODE (op[1]) == XOR) + msp430_xorsi_code (insn, ops, &len); + + if (zero_shifted (ops[2]) && regsi_ok_safe (ops)) + { + rtx reg = XEXP (ops[2], 0); + if (dead_or_set_p (insn, reg)) + len -= 1; + } + else if (!zero_shifted (ops[2]) && indexed_location (ops[2])) + { + len -= 1; + } + break; + case DImode: + + if (GET_CODE (op[1]) == PLUS) + msp430_adddi_code (insn, ops, &len); + if (GET_CODE (op[1]) == MINUS) + msp430_subdi_code (insn, ops, &len); + if (GET_CODE (op[1]) == AND) + msp430_anddi_code (insn, ops, &len); + if (GET_CODE (op[1]) == IOR) + msp430_iordi_code (insn, ops, &len); + if (GET_CODE (op[1]) == XOR) + msp430_xordi_code (insn, ops, &len); + + if (zero_shifted (ops[2]) && regdi_ok_safe (ops)) + { + rtx reg = XEXP (ops[2], 0); + if (dead_or_set_p (insn, reg)) + len -= 1; + } + else if (!zero_shifted (ops[2]) && indexed_location (ops[2])) + { + len -= 1; + } + break; + + default: + break; + } + + if (GET_MODE (ops[0]) == SImode) + { + if (GET_CODE (ops[2]) == CONST_INT) + { + if (GET_CODE (op[1]) == AND) + { + msp430_emit_immediate_and2 (insn, ops, &len); + } + else if (GET_CODE (op[1]) == IOR) + { + msp430_emit_immediate_ior2 (insn, ops, &len); + } + else + { + if (GET_MODE (ops[0]) == SImode) + { + int x = INTVAL (ops[2]); + int y = (x & 0xffff0000ul) >> 16; + x = x & 0xffff; + + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 + || x == 0xffff) + len--; + if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 + || y == 0xffff) + len--; + } + } + } + } + + if (GET_MODE (ops[0]) == SFmode || GET_MODE (ops[0]) == DImode) + { + if (GET_CODE (ops[2]) == CONST_DOUBLE) + { + + if (GET_CODE (op[1]) == AND) + { + msp430_emit_immediate_and4 (insn, ops, &len); + } + else if (GET_CODE (op[1]) == IOR) + { + msp430_emit_immediate_ior4 (insn, ops, &len); + } + else if (GET_MODE (ops[0]) == SFmode) + { + long val; + int y, x; + REAL_VALUE_TYPE rv; + REAL_VALUE_FROM_CONST_DOUBLE (rv, ops[2]); + REAL_VALUE_TO_TARGET_SINGLE (rv, val); + + y = (val & 0xffff0000ul) >> 16; + x = val & 0xffff; + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 + || x == 0xffff) + len--; + if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 + || y == 0xffff) + len--; + } + else + { + int hi = CONST_DOUBLE_HIGH (ops[2]); + int lo = CONST_DOUBLE_LOW (ops[2]); + int x, y, z; + + x = (hi & 0xffff0000ul) >> 16; + y = hi & 0xffff; + z = (lo & 0xffff0000ul) >> 16; + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 + || x == 0xffff) + len--; + if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 + || y == 0xffff) + len--; + if (z == 0 || z == 1 || z == 2 || z == 4 || z == 8 + || z == 0xffff) + len--; + } + } + } + + return len; + } + else if (GET_CODE (op[1]) == NOT + || GET_CODE (op[1]) == ABS || GET_CODE (op[1]) == NEG) + { + if (GET_MODE (op[0]) == HImode || GET_MODE (op[0]) == QImode) + if (indexed_location (XEXP (op[1], 0))) + len--; + /* consts handled by cpp */ + /* nothing... */ + } + else if (GET_CODE (op[1]) == ZERO_EXTEND) + { + rtx ops[10]; + ops[0] = op[0]; + ops[1] = XEXP (op[1], 0); + + if (GET_MODE (ops[1]) == QImode) + { + if (GET_MODE (ops[0]) == HImode) + zeroextendqihi (insn, ops, &len); + else if (GET_MODE (ops[0]) == SImode) + zeroextendqisi (insn, ops, &len); + else if (GET_MODE (ops[0]) == DImode) + zeroextendqidi (insn, ops, &len); + } + else if (GET_MODE (ops[1]) == HImode) + { + if (GET_MODE (ops[0]) == SImode) + zeroextendhisi (insn, ops, &len); + else if (GET_MODE (ops[0]) == DImode) + zeroextendhidi (insn, ops, &len); + } + else if (GET_MODE (ops[1]) == SImode) + { + if (GET_MODE (ops[1]) == DImode) + zeroextendsidi (insn, ops, &len); + } + } + else if (GET_CODE (op[1]) == SIGN_EXTEND) + { + rtx ops[10]; + ops[0] = op[0]; /* dest */ + ops[1] = XEXP (op[1], 0); /* src */ + + if (GET_MODE (ops[1]) == QImode) + { + if (GET_MODE (ops[0]) == HImode) + signextendqihi (insn, ops, &len); + else if (GET_MODE (ops[0]) == SImode) + signextendqisi (insn, ops, &len); + else if (GET_MODE (ops[0]) == DImode) + signextendqidi (insn, ops, &len); + } + else if (GET_MODE (ops[1]) == HImode) + { + if (GET_MODE (ops[0]) == SImode) + signextendhisi (insn, ops, &len); + else if (GET_MODE (ops[0]) == DImode) + signextendhidi (insn, ops, &len); + } + else if (GET_MODE (ops[1]) == SImode) + { + if (GET_MODE (ops[0]) == DImode) + signextendsidi (insn, ops, &len); + } + } + else if (GET_CODE (op[1]) == IF_THEN_ELSE) + { + if (GET_CODE (op[0]) == PC) + { + rtx ops[5]; + ops[0] = XEXP (op[1], 1); + ops[1] = XEXP (op[1], 0); + ops[2] = XEXP (ops[1], 0); + ops[3] = XEXP (ops[1], 1); + msp430_cbranch (insn, ops, &len); + } + } + else if (GET_CODE (op[0]) == MEM + && GET_CODE (XEXP (op[0], 0)) == POST_DEC) + { + rtx ops[4]; + ops[0] = op[1]; + if (GET_MODE (op[0]) == QImode) + msp430_pushqi (insn, ops, &len); + if (GET_MODE (op[0]) == HImode) + msp430_pushhi (insn, ops, &len); + if (GET_MODE (op[0]) == SImode) + msp430_pushsisf (insn, ops, &len); + if (GET_MODE (op[0]) == DImode) + msp430_pushdi (insn, ops, &len); + } + } + + if (set) + { + rtx op[10]; + op[1] = SET_SRC (set); + op[0] = SET_DEST (set); + + if (GET_CODE (patt) == PARALLEL) + { + if (GET_CODE (op[0]) == PC && GET_CODE (op[1]) == IF_THEN_ELSE) + { + rtx ops[5]; + ops[0] = XEXP (op[1], 1); + ops[1] = XEXP (op[1], 0); + ops[2] = XEXP (ops[1], 0); + ops[3] = XEXP (ops[1], 1); + msp430_cbranch (insn, ops, &len); + } + + if (GET_CODE (op[1]) == ASHIFT + || GET_CODE (op[1]) == ASHIFTRT || GET_CODE (op[1]) == LSHIFTRT) + { + rtx ops[10]; + ops[0] = op[0]; + ops[1] = XEXP (op[1], 0); + ops[2] = XEXP (op[1], 1); + + switch (GET_CODE (op[1])) + { + case ASHIFT: + switch (GET_MODE (op[0])) + { + case QImode: + msp430_emit_ashlqi3 (insn, ops, &len); + break; + case HImode: + msp430_emit_ashlhi3 (insn, ops, &len); + break; + case SImode: + msp430_emit_ashlsi3 (insn, ops, &len); + break; + case DImode: + msp430_emit_ashldi3 (insn, ops, &len); + break; + default: + break; + } + break; + + case ASHIFTRT: + switch (GET_MODE (op[0])) + { + case QImode: + msp430_emit_ashrqi3 (insn, ops, &len); + break; + case HImode: + msp430_emit_ashrhi3 (insn, ops, &len); + break; + case SImode: + msp430_emit_ashrsi3 (insn, ops, &len); + break; + case DImode: + msp430_emit_ashrdi3 (insn, ops, &len); + break; + default: + break; + } + break; + + case LSHIFTRT: + switch (GET_MODE (op[0])) + { + case QImode: + msp430_emit_lshrqi3 (insn, ops, &len); + break; + case HImode: + msp430_emit_lshrhi3 (insn, ops, &len); + break; + case SImode: + msp430_emit_lshrsi3 (insn, ops, &len); + break; + case DImode: + msp430_emit_lshrdi3 (insn, ops, &len); + break; + default: + break; + } + break; + + default: + break; + } + } + } + } + + return len; +} + + +/* Output all insn addresses and their sizes into the assembly language + output file. This is helpful for debugging whether the length attributes + in the md file are correct. + Output insn cost for next insn. */ + +void +final_prescan_insn (insn, operand, num_operands) + rtx insn, *operand ATTRIBUTE_UNUSED; + int num_operands ATTRIBUTE_UNUSED; +{ + int uid = INSN_UID (insn); + + if (TARGET_ALL_DEBUG) + { + fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n", + INSN_ADDRESSES (uid), + INSN_ADDRESSES (uid) - last_insn_address, + rtx_cost (PATTERN (insn), INSN)); + } + last_insn_address = INSN_ADDRESSES (uid); +} + +void +msp430_output_addr_vec_elt (stream, value) + FILE *stream; + int value; +{ + fprintf (stream, "\t.word .L%d\n", value); + jump_tables_size++; +} + + +void +machine_dependent_reorg (first_insn) + rtx first_insn ATTRIBUTE_UNUSED; +{ + /* nothing to be done here this time */ + return; +} + + +int +test_hard_reg_class (class, x) + enum reg_class class; + rtx x; +{ + int regno = true_regnum (x); + if (regno < 0) + return 0; + return TEST_HARD_REG_CLASS (class, regno); +} + + +/* Returns 1 if SCRATCH are safe to be allocated as a scratch + registers (for a define_peephole2) in the current function. */ +/* UNUSED ... yet... */ +int +msp430_peep2_scratch_safe (scratch) + rtx scratch; +{ + if ((interrupt_function_p (current_function_decl) + || signal_function_p (current_function_decl)) && leaf_function_p ()) + { + int first_reg = true_regnum (scratch); + int last_reg; + int size = GET_MODE_SIZE (GET_MODE (scratch)); + int reg; + + size >>= 1; + if (!size) + size = 1; + + last_reg = first_reg + size - 1; + + for (reg = first_reg; reg <= last_reg; reg++) + { + if (!regs_ever_live[reg]) + return 0; + } + } + + return 1; +} + + +/* Update the condition code in the INSN. + now mostly unused */ + +void +notice_update_cc (body, insn) + rtx body ATTRIBUTE_UNUSED; + rtx insn ATTRIBUTE_UNUSED; +{ + CC_STATUS_INIT; +} + + + +/*********************************************************************/ + +/* + Next two return non zero for rtx as + (set (reg:xx) + (mem:xx (reg:xx)) + +*/ + +int +regsi_ok_safe (operands) + rtx operands[]; +{ + rtx dest = operands[0]; + rtx areg; + int src_reg; + int dst_reg; + + if (operands[2]) + areg = XEXP (operands[2], 0); + else + areg = XEXP (operands[1], 0); + + if (GET_CODE (dest) == MEM) + { + dest = XEXP (operands[0], 0); + if (GET_CODE (dest) == PLUS && GET_CODE (XEXP (dest, 0)) == REG) + { + dest = XEXP (dest, 0); + } + else if (GET_CODE (dest) == REG) + { + ; /* register */ + } + else + return 1; + } + + if (REGNO (dest) >= FIRST_PSEUDO_REGISTER + || REGNO (areg) >= FIRST_PSEUDO_REGISTER) + return 1; + + dst_reg = true_regnum (dest); + src_reg = true_regnum (areg); + if (dst_reg > src_reg || dst_reg + 1 < src_reg) + { + return 1; + } + return 0; +} + +int +regsi_ok_clobber (operands) + rtx operands[]; +{ + rtx dest = operands[0]; + rtx areg = XEXP (operands[2], 0); + int src_reg; + int dst_reg; + int regno = REGNO (dest); + + + if (GET_CODE (dest) == MEM) + { + dest = XEXP (operands[0], 0); + if (GET_CODE (dest) == PLUS && GET_CODE (XEXP (dest, 0)) == REG) + { + dest = XEXP (dest, 0); + } + else if (GET_CODE (dest) == REG) + { + ; /* register */ + } + else + return 1; + } + + if (regno >= FIRST_PSEUDO_REGISTER || REGNO (areg) >= FIRST_PSEUDO_REGISTER) + return 1; + + dst_reg = true_regnum (dest); + src_reg = true_regnum (areg); + if (dst_reg + 1 == src_reg) + return 1; + return 0; +} + +int +regdi_ok_safe (operands) + rtx operands[]; +{ + rtx dest = operands[0]; + rtx areg = XEXP (operands[2], 0); + int src_reg; + int dst_reg; + + + if (GET_CODE (dest) == MEM) + { + dest = XEXP (operands[0], 0); + if (GET_CODE (dest) == PLUS && GET_CODE (XEXP (dest, 0)) == REG) + { + dest = XEXP (dest, 0); + } + else if (GET_CODE (dest) == REG) + { + ; /* register */ + } + else + return 1; + } + + if (REGNO (dest) >= FIRST_PSEUDO_REGISTER + || REGNO (areg) >= FIRST_PSEUDO_REGISTER) + return 1; + + dst_reg = true_regnum (dest); + src_reg = true_regnum (areg); + if (dst_reg > src_reg || dst_reg + 3 < src_reg) + { + return 1; + } + + return 0; +} + +int +regdi_ok_clobber (operands) + rtx operands[]; +{ + rtx dest = operands[0]; + rtx areg = XEXP (operands[2], 0); + int src_reg; + int dst_reg; + int regno = REGNO (dest); + + if (GET_CODE (dest) == MEM) + { + dest = XEXP (operands[0], 0); + if (GET_CODE (dest) == PLUS && GET_CODE (XEXP (dest, 0)) == REG) + { + dest = XEXP (dest, 0); + } + else if (GET_CODE (dest) == REG) + { + ; /* register */ + } + else + return 1; + } + + if (regno >= FIRST_PSEUDO_REGISTER || REGNO (areg) >= FIRST_PSEUDO_REGISTER) + return 1; + + dst_reg = true_regnum (dest); + src_reg = true_regnum (areg); + if (dst_reg + 3 == src_reg) + return 1; + return 0; +} + + +/***************** ARITHMETIC *******************/ + +int +emit_indexed_arith (insn, operands, m, cmd, iscarry) + rtx insn; + rtx operands[]; + int m; + const char *cmd; + int iscarry; +{ + char template[256]; + register int i = 0; + char *p; + rtx reg = NULL; + int len = m * 2; + rtx x = operands[0]; + int havestop = 0; + rtx pattern; + rtx next = next_real_insn (insn); + + + pattern = PATTERN (next); + + if (pattern && GET_CODE (pattern) == PARALLEL) + { + pattern = XVECEXP (pattern, 0, 0); + } + + if (followed_compare_condition (insn) != UNKNOWN + || GET_CODE(insn) == JUMP_INSN + || (pattern + && GET_CODE (pattern) == SET + && SET_DEST (pattern) == cc0_rtx) + || (pattern && GET_CODE (pattern) == SET + && SET_DEST (pattern) == pc_rtx)) + { + /* very exotic case */ + + snprintf (template, 255, "%s\t" "%%A%d, %%A0", cmd, operands[2] ? 2 : 1); + output_asm_insn (template, operands); + snprintf (template, 255, "%s%s\t" "%%B%d, %%B0", cmd, iscarry ? "c" : "", + operands[2] ? 2 : 1); + output_asm_insn (template, operands); + + if (m == 2) + return len; + + snprintf (template, 255, "%s%s\t" "%%C%d, %%C0", cmd, iscarry ? "c" : "", + operands[2] ? 2 : 1); + output_asm_insn (template, operands); + snprintf (template, 255, "%s%s\t" "%%D%d, %%D0", cmd, iscarry ? "c" : "", + operands[2] ? 2 : 1); + output_asm_insn (template, operands); + + return len; + } + + if (operands[2]) + reg = XEXP (operands[2], 0); + else + reg = XEXP (operands[1], 0); + + if (GET_CODE (x) == REG) + { + int src; + int dst = REGNO (x); + + if (!reg) + { + reg = XEXP (operands[1], 0); + } + + src = REGNO (reg); + + /* check if registers overlap */ + if (dst > src || (dst + m - 1) < src) + { + ; /* fine ! */ + } + else if ((dst + m - 1) == src) + { + havestop = 1; /* worse */ + } + else + { + /* cannot do reverse assigment */ + while (i < m) + { + p = (char *) (template + strlen (cmd)); + p += (i && iscarry) ? 3 : 2; + strcpy (template, cmd); + strcat (template, (i && iscarry) ? "c\t%" : "\t%"); + *p = 'A' + i; + p++; + *p = 0; + strcat (template, "0, %"); + p += 2; + *p = 'A' + i; + p++; + *p = 0; + strcat (template, operands[2] ? "2" : "1"); + output_asm_insn (template, operands); + i++; + } + return m * 3; + } + } + + while (i < (m - havestop)) + { + p = template + strlen (cmd); + + strcpy (template, cmd); + + if (i && iscarry) + { + strcat (template, "c\t"); + p += 2; + } + else + { + strcat (template, "\t"); + p += 1; + } + strcat (template, operands[2] ? "@%E2+, %" : "@%E1+, %"); + p += 8; + *p = 'A' + i; + p++; + *p = 0; + strcat (template, "0"); + p++; + output_asm_insn (template, operands); + i++; + } + + if (havestop) + { + len++; + p = template + strlen (cmd); + strcpy (template, cmd); + if (i && iscarry) + { + strcat (template, "c\t"); + p += 2; + } + else + { + strcat (template, "\t"); + p += 1; + } + strcat (template, operands[2] ? "@%E2, %" : "@%E1, %"); + p += 8; + *p = 'A' + i; + p++; + *p = 0; + strcat (template, "0 ; register won't die"); + p += 1; + output_asm_insn (template, operands); + } + + if (!dead_or_set_p (insn, reg) && !havestop) + { + len++; + p = template + 3; + strcpy (template, "sub"); + strcat (template, "\t#"); + p += 2; + *p = '0' + m * 2; + p++; + *p = 0; + + if (operands[2]) + strcat (template, ", %E2 ; restore %E2"); + else + strcat (template, ", %E1 ; restore %E1"); + output_asm_insn (template, operands); + } + + return len; +} + +static int sameoperand_p PARAMS ((rtx, rtx)); + +int +sameoperand (operands, i) + rtx operands[]; + int i; +{ + rtx dst = operands[0]; + rtx src = operands[i]; + + return sameoperand_p (src, dst); +} + +static int +sameoperand_p (src, dst) + rtx src; + rtx dst; +{ + enum rtx_code scode = GET_CODE (src); + enum rtx_code dcode = GET_CODE (dst); + /* cannot use standard functions here + cause operands have different modes: + */ + + if (scode != dcode) + return 0; + + switch (scode) + { + case REG: + return REGNO (src) == REGNO (dst); + break; + case MEM: + return sameoperand_p (XEXP (src, 0), XEXP (dst, 0)); + break; + case PLUS: + return sameoperand_p (XEXP (src, 0), XEXP (dst, 0)) + && sameoperand_p (XEXP (src, 1), XEXP (dst, 1)); + break; + case CONST_INT: + return INTVAL (src) == INTVAL (dst); + break; + case SYMBOL_REF: + return XSTR (src, 0) == XSTR (dst, 0); + break; + default: + break; + } + return 0; + +} + +#define OUT_INSN(x,p,o) \ +do { \ +if(!x) output_asm_insn (p,o); \ +} while(0) + + + +/************** MOV CODE *********************************/ + +const char * +movstrsi_insn (insn, operands, l) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + + /* operands 0 and 1 are registers !!! */ + /* operand 2 is a cnt and not zero */ + output_asm_insn ("\n.Lmsn%=:", operands); + output_asm_insn ("mov.b\t@%1+,0(%0)", operands); + output_asm_insn ("inc\t%0", operands); + output_asm_insn ("dec\t%2", operands); + output_asm_insn ("jnz\t.Lmsn%=", operands); + + return ""; +} + + +const char * +clrstrsi_insn (insn, operands, l) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + + /* operand 0 is a register !!! */ + /* operand 1 is a cnt and not zero */ + output_asm_insn ("\n.Lcsn%=:", operands); + output_asm_insn ("clr.b\t0(%0) ; clr does not support @rn+", + operands); + output_asm_insn ("inc\t%0", operands); + output_asm_insn ("dec\t%1", operands); + output_asm_insn ("jnz\t.Lcsn%=", operands); + return ""; +} + +const char * +movstrhi_insn (insn, operands, l) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + + /* operands 0 and 1 are registers !!! */ + /* operand 2 is a cnt and not zero */ + output_asm_insn ("\n.Lmsn%=:", operands); + output_asm_insn ("mov.b\t@%1+,0(%0)", operands); + output_asm_insn ("inc\t%0", operands); + output_asm_insn ("dec\t%2", operands); + output_asm_insn ("jnz\t.Lmsn%=", operands); + return ""; +} + +const char * +clrstrhi_insn (insn, operands, l) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + + /* operand 0 is a register !!! */ + /* operand 1 is a cnt and not zero */ + output_asm_insn ("\n.Lcsn%=:", operands); + output_asm_insn ("clr.b\t0(%0)", operands); + output_asm_insn ("inc\t%0", operands); + output_asm_insn ("dec\t%1", operands); + output_asm_insn ("jnz\t.Lcsn%=", operands); + return ""; +} + +int +msp430_emit_indexed_mov (insn, operands, m, cmd) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int m; + const char *cmd; +{ + char template[256]; + register int i = 0; + char *p; + rtx reg = XEXP (operands[1], 0); + int len = m * 2; + rtx dst = 0; + int sreg,dreg = 0; + + if(memory_operand(operands[0], VOIDmode)) + { + if( REG_P(XEXP(operands[0],0))) + dreg = REGNO(XEXP(operands[0],0)); + else if(GET_CODE(XEXP(operands[0],0)) == PLUS + && REG_P(XEXP(XEXP(operands[0],0),0)) ) + dreg = REGNO(XEXP(XEXP(operands[0],0),0)); + } + + + sreg = REGNO(XEXP(operands[1],0)); + + while (i < m) + { + p = template + strlen (cmd); + + strcpy (template, cmd); + strcat (template, "\t"); + p += 1; + strcat (template, "@%E1+, "); + p += 7; + + if(dreg==sreg) + { + *p = '-'; p++; + *p = '2'; p++; + *p = '+'; p++; + } + + *p = '%'; p++; + *p = 'A' + ((dreg==sreg)?0:i); + + p++; + *p = 0; + strcat (template, "0"); + p += 1; + output_asm_insn (template, operands); + i++; + } + + if (!dead_or_set_p (insn, reg)) + { + len++; + p = template + 3; + strcpy (template, "sub"); + strcat (template, "\t#"); + p += 2; + *p = '0' + m * 2; + p++; + *p = 0; + strcat (template, ", %E1 ; restore %E1"); + output_asm_insn (template, operands); + } + + return len; +} + +const char * +msp430_emit_indexed_mov2 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + msp430_emit_indexed_mov (insn, operands, 2, "mov"); + return ""; +} + +const char * +msp430_emit_indexed_mov4 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + msp430_emit_indexed_mov (insn, operands, 4, "mov"); + return ""; +} + +const char * +movsisf_regmode (insn, operands, l) + rtx insn; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx areg = XEXP (src, 0); + int src_reg = true_regnum (areg); + int dst_reg = true_regnum (dest); + + + if (dst_reg > src_reg || dst_reg + 1 < src_reg) + { + output_asm_insn ("mov\t@%E1+, %A0", operands); + output_asm_insn ("mov\t@%E1+, %B0", operands); + if (!dead_or_set_p (insn, areg)) + { + output_asm_insn ("sub\t#4, %E1\t;\trestore %E1", operands); + } + return ""; + } + else if (dst_reg + 1 == src_reg) + { + output_asm_insn ("mov\t@%E1+, %A0", operands); + output_asm_insn ("mov\t@%E1, %B0", operands); + return ""; + } + else + { + /* destination overlaps with source. + so, update destination in reverse way */ + output_asm_insn ("mov\t%B1, %B0", operands); + output_asm_insn ("mov\t@%E1, %A0", operands); + } + + return ""; /* make compiler happy */ +} + + +/* From Max Behensky + This function tells you what the index register in an operand is. It + returns the register number, or -1 if it is not an indexed operand */ +static int get_indexed_reg PARAMS ((rtx)); +static int +get_indexed_reg (x) + rtx x; +{ + int code; + + code = GET_CODE (x); + + if (code != MEM) + return (-1); + + x = XEXP (x, 0); + code = GET_CODE (x); + if (code == REG) + return (REGNO (x)); + + if (code != PLUS) + return (-1); + + x = XEXP (x, 0); + code = GET_CODE (x); + if (code != REG) + return (-1); + + return (REGNO (x)); +} + + +const char * +msp430_movesi_code (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx op0 = operands[0]; + rtx op1 = operands[1]; + + + if (memory_operand (op0, VOIDmode) + && memory_operand (op1, VOIDmode) && zero_shifted (op1)) + { + if (!len) + msp430_emit_indexed_mov2 (insn, operands, NULL); + else + *len = 5; + return ""; + } + else if (register_operand (op0, VOIDmode) + && memory_operand (op1, VOIDmode) && zero_shifted (op1)) + { + if (!len) + movsisf_regmode (insn, operands, NULL); + else + *len = 3; + return ""; + } + + if (!len) + { + if ((register_operand (op0, VOIDmode) + && register_operand (op1, VOIDmode) + && REGNO (op1) + 1 == REGNO (op0)) + || (register_operand (op0, VOIDmode) + && memory_operand (op1, VOIDmode) + && get_indexed_reg (op1) == true_regnum (op0))) + { + output_asm_insn ("mov\t%B1, %B0", operands); + output_asm_insn ("mov\t%A1, %A0", operands); + } + else + { + output_asm_insn ("mov\t%A1, %A0", operands); + output_asm_insn ("mov\t%B1, %B0", operands); + } + } + else + { + *len = 2; /* base length */ + + if (register_operand (op0, VOIDmode)) + *len += 0; + else if (memory_operand (op0, VOIDmode)) + *len += 2; + + if (register_operand (op1, VOIDmode)) + *len += 0; + else if (memory_operand (op1, VOIDmode)) + *len += 2; + else if (immediate_operand (op1, VOIDmode)) + *len += 2; + } + + return ""; +} + +const char * +movdidf_regmode (insn, operands, l) + rtx insn; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx areg = XEXP (src, 0); + + int src_reg = true_regnum (areg); + int dst_reg = true_regnum (dest); + + + if (dst_reg > src_reg || dst_reg + 3 < src_reg) + { + output_asm_insn ("mov\t@%E1+, %A0", operands); + output_asm_insn ("mov\t@%E1+, %B0", operands); + output_asm_insn ("mov\t@%E1+, %C0", operands); + output_asm_insn ("mov\t@%E1+, %D0", operands); + if (!dead_or_set_p (insn, areg)) + { + output_asm_insn ("sub\t#8, %E1\t;\trestore %E1", operands); + } + } + else if (dst_reg + 3 == src_reg) + { + output_asm_insn ("mov\t@%E1+, %A0", operands); + output_asm_insn ("mov\t@%E1+, %B0", operands); + output_asm_insn ("mov\t@%E1+, %C0", operands); + output_asm_insn ("mov\t@%E1, %D0 ; %E1 == %D0", operands); + } + else + { + /* destination overlaps source. + so, update destination in reverse way */ + output_asm_insn ("mov\t%D1, %D0 ; %E1 overlaps wit one of %A0 - %D0", + operands); + output_asm_insn ("mov\t%C1, %C0", operands); + output_asm_insn ("mov\t%B1, %B0", operands); + output_asm_insn ("mov\t@%E1, %A0", operands); + } + + return ""; +} + +const char * +msp430_movedi_code (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx op0 = operands[0]; + rtx op1 = operands[1]; + + if (memory_operand (op0, DImode) + && memory_operand (op1, DImode) && zero_shifted (op1)) + { + if (!len) + msp430_emit_indexed_mov4 (insn, operands, NULL); + else + *len = 9; + return ""; + } + else if (register_operand (op0, DImode) + && memory_operand (op1, DImode) && zero_shifted (op1)) + { + if (!len) + movdidf_regmode (insn, operands, NULL); + else + *len = 5; + return ""; + } + + if (!len) + { + if (register_operand (op0, SImode) + && register_operand (op1, SImode) && REGNO (op1) + 3 == REGNO (op0)) + { + output_asm_insn ("mov\t%D1, %D0", operands); + output_asm_insn ("mov\t%C1, %C0", operands); + output_asm_insn ("mov\t%B1, %B0", operands); + output_asm_insn ("mov\t%A1, %A0", operands); + } + else + { + output_asm_insn ("mov\t%A1, %A0", operands); + output_asm_insn ("mov\t%B1, %B0", operands); + output_asm_insn ("mov\t%C1, %C0", operands); + output_asm_insn ("mov\t%D1, %D0", operands); + } + } + else + { + *len = 4; /* base length */ + + if (register_operand (op0, DImode)) + *len += 0; + else if (memory_operand (op0, DImode)) + *len += 4; + + if (register_operand (op1, DImode)) + *len += 0; + else if (memory_operand (op1, DImode)) + *len += 4; + else if (immediate_operand (op1, DImode)) + *len += 4; + } + + return ""; +} + + + + +/************** ADD CODE *********************************/ + + +const char * +msp430_emit_indexed_add2 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + emit_indexed_arith (insn, operands, 2, "add", 1); + return ""; +} + +const char * +msp430_emit_indexed_add4 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + emit_indexed_arith (insn, operands, 4, "add", 1); + return ""; +} + +const char * +msp430_addsi_code (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx op0 = operands[0]; + rtx op2 = operands[2]; + rtx ops[4]; + + if (memory_operand (op2, SImode) + && zero_shifted (operands[2]) && regsi_ok_safe (operands)) + { + if (!len) + msp430_emit_indexed_add2 (insn, operands, NULL); + else + { + if (memory_operand (op0, SImode)) + *len = 5; + else if (register_operand (op0, SImode)) + *len = 3; + } + return ""; + } + else if (memory_operand (op2, SImode) + && zero_shifted (operands[2]) && regsi_ok_clobber (operands)) + { + if (!len) + { + output_asm_insn ("add\t@%E2+, %A0", operands); + output_asm_insn ("addc\t@%E2+, %B0", operands); + } + else + { + if (register_operand (op0, SImode)) + *len = 2; + else if (memory_operand (op0, SImode)) + *len = 4; + else + abort (); + } + return ""; + } + + ops[0] = operands[0]; + ops[2] = operands[2]; + + if (!len) + { + output_asm_insn ("add\t%A2, %A0", ops); + output_asm_insn ("addc\t%B2, %B0", ops); + } + + if (len) + { + *len = 2; /* base length */ + + if (register_operand (ops[0], SImode)) + *len += 0; + else if (memory_operand (ops[0], SImode)) + *len += 2; + + if (register_operand (ops[2], SImode)) + *len += 0; + else if (memory_operand (ops[2], SImode)) + *len += 2; + else if (immediate_operand (ops[2], SImode)) + { + int x = INTVAL (ops[2]); + if (x == -2 || x == -4 || x == -8) + { + *len += 1; + } + else + *len += 2; + } + } + return ""; +} + +const char * +msp430_adddi_code (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx op0 = operands[0]; + rtx op2 = operands[2]; + + if (memory_operand (op2, DImode) + && zero_shifted (operands[2]) && regdi_ok_safe (operands)) + { + if (!len) + msp430_emit_indexed_add4 (insn, operands, NULL); + else + { + if (memory_operand (op0, DImode)) + *len = 9; + else if (register_operand (op0, DImode)) + *len = 5; + } + + return ""; + } + else if (memory_operand (op2, DImode) + && zero_shifted (operands[2]) && regdi_ok_clobber (operands)) + { + if (!len) + { + output_asm_insn ("add\t@%E2+, %A0", operands); + output_asm_insn ("addc\t@%E2+, %B0", operands); + output_asm_insn ("addc\t@%E2+, %C0", operands); + output_asm_insn ("addc\t@%E2+, %D0", operands); + } + else + { + if (register_operand (op0, DImode)) + *len = 4; + else if (memory_operand (op0, DImode)) + *len = 8; + else + abort (); + } + return ""; + } + + if (!len) + { + output_asm_insn ("add\t%A2, %A0", operands); + output_asm_insn ("addc\t%B2, %B0", operands); + output_asm_insn ("addc\t%C2, %C0", operands); + output_asm_insn ("addc\t%D2, %D0", operands); + } + else + { + *len = 4; /* base length */ + + if (register_operand (op0, DImode)) + *len += 0; + else if (memory_operand (op0, DImode)) + *len += 4; + + if (register_operand (op2, DImode)) + *len += 0; + else if (memory_operand (op2, DImode)) + *len += 4; + else if (immediate_operand (op2, DImode)) + { + int x = INTVAL (op2); + + if (x == -2 || x == -4 || x == -8) + *len += 0; + else + *len += 4; + } + else + abort (); + } + + return ""; +} + + +/************** SUB CODE *********************************/ + +const char * +msp430_emit_indexed_sub2 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + emit_indexed_arith (insn, operands, 2, "sub", 1); + return ""; +} + +const char * +msp430_emit_indexed_sub4 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + emit_indexed_arith (insn, operands, 4, "sub", 1); + return ""; +} + +const char * +msp430_subsi_code (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx op0 = operands[0]; + rtx op2 = operands[2]; + + if (memory_operand (op2, SImode) + && zero_shifted (operands[2]) && regsi_ok_safe (operands)) + { + if (!len) + msp430_emit_indexed_sub2 (insn, operands, NULL); + else + { + if (memory_operand (op0, SImode)) + *len = 5; + else if (register_operand (op0, SImode)) + *len = 3; + } + + return ""; + } + else if (memory_operand (op2, SImode) + && zero_shifted (operands[2]) && regsi_ok_clobber (operands)) + { + if (!len) + { + output_asm_insn ("sub\t@%E2+, %A0", operands); + output_asm_insn ("subc\t@%E2+, %B0", operands); + } + else + { + if (register_operand (op0, SImode)) + *len = 2; + else if (memory_operand (op0, SImode)) + *len = 4; + else + abort (); + } + return ""; + } + + if (!len) + { + output_asm_insn ("sub\t%A2, %A0", operands); + output_asm_insn ("subc\t%B2, %B0", operands); + } + else + { + *len = 2; /* base length */ + + if (register_operand (op0, SImode)) + *len += 0; + else if (memory_operand (op0, SImode)) + *len += 2; + + if (register_operand (op2, SImode)) + *len += 0; + else if (memory_operand (op2, SImode)) + *len += 2; + else if (immediate_operand (op2, SImode)) + *len += 2; + } + + return ""; +} + + +const char * +msp430_subdi_code (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx op0 = operands[0]; + rtx op2 = operands[2]; + + if (memory_operand (op2, DImode) + && zero_shifted (operands[2]) && regdi_ok_safe (operands)) + { + if (!len) + msp430_emit_indexed_sub4 (insn, operands, NULL); + else + { + if (memory_operand (op0, DImode)) + *len = 9; + else if (register_operand (op0, DImode)) + *len = 5; + } + + return ""; + } + else if (memory_operand (op2, DImode) + && zero_shifted (operands[2]) && regdi_ok_clobber (operands)) + { + if (!len) + { + output_asm_insn ("sub\t@%E2+, %A0", operands); + output_asm_insn ("subc\t@%E2+, %B0", operands); + output_asm_insn ("subc\t@%E2+, %C0", operands); + output_asm_insn ("subc\t@%E2+, %D0", operands); + } + else + { + if (register_operand (op0, DImode)) + *len = 4; + else if (memory_operand (op0, DImode)) + *len = 8; + else + abort (); + } + return ""; + } + + if (!len) + { + output_asm_insn ("sub\t%A2, %A0", operands); + output_asm_insn ("subc\t%B2, %B0", operands); + output_asm_insn ("subc\t%C2, %C0", operands); + output_asm_insn ("subc\t%D2, %D0", operands); + } + else + { + *len = 4; /* base length */ + + if (register_operand (op0, DImode)) + *len += 0; + else if (memory_operand (op0, DImode)) + *len += 4; + + if (register_operand (op2, DImode)) + *len += 0; + else if (memory_operand (op2, DImode)) + *len += 4; + else if (immediate_operand (op2, DImode)) + *len += 4; + else + abort (); + } + + return ""; +} + + +/************** AND CODE *********************************/ + +const char * +msp430_emit_indexed_and2 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + emit_indexed_arith (insn, operands, 2, "and", 0); + return ""; +} + +const char * +msp430_emit_indexed_and4 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + emit_indexed_arith (insn, operands, 4, "and", 0); + return ""; +} + +const char * +msp430_emit_immediate_and2 (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int v; + int l = INTVAL (operands[2]); + int r = REG_P (operands[0]); + int list1 = ((~1) & 0xffff); + int list2 = ((~2) & 0xffff); + int list4 = ((~4) & 0xffff); + int list8 = ((~8) & 0xffff); + + rtx op[4]; + + op[0] = operands[0]; + op[1] = operands[1]; + op[2] = operands[2]; + + /* check nibbles */ + + v = (l) & 0xffff; + if (v != 0xffff) + { + if (v == list1 || v == list2 || v == list4 || v == list8) + { + op[2] = gen_rtx_CONST_INT (SImode, ~v); + OUT_INSN (len, "bic\t%A2, %A0", op); + dummy++; + if (!r) + dummy++; + } + else + { + op[2] = gen_rtx_CONST_INT (SImode, v); + OUT_INSN (len, "and\t%A2, %A0", op); + dummy++; + dummy++; + if (!r) + dummy++; + if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8) + dummy--; + } + } + + v = (l >> 16) & 0xffff; + if (v != 0xffff) + { + if (v == list1 || v == list2 || v == list4 || v == list8) + { + op[2] = gen_rtx_CONST_INT (SImode, ~v); + OUT_INSN (len, "bic\t%A2, %B0", op); + dummy++; + if (!r) + dummy++; + } + else + { + op[2] = gen_rtx_CONST_INT (SImode, v); + OUT_INSN (len, "and\t%A2, %B0", op); + dummy++; + dummy++; + if (!r) + dummy++; + if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8) + dummy--; + } + } + + if (len) + *len = dummy; + return ""; +} + +const char * +msp430_emit_immediate_and4 (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int v; + int l = CONST_DOUBLE_LOW (operands[2]); + int h = CONST_DOUBLE_HIGH (operands[2]); + int r = REG_P (operands[0]); + int list1 = ((~1) & 0xffff); + int list2 = ((~2) & 0xffff); + int list4 = ((~4) & 0xffff); + int list8 = ((~8) & 0xffff); + rtx op[4]; + + op[0] = operands[0]; + op[1] = operands[1]; + op[2] = operands[2]; + + /* check if operand 2 is really const_double */ + if (GET_CODE (operands[2]) == CONST_INT) + { + l = INTVAL (operands[2]); + h = 0; + } + + /* check nibbles */ + v = (l) & 0xffff; + if (v != 0xffff) + { + if (v == list1 || v == list2 || v == list4 || v == list8) + { + op[2] = gen_rtx_CONST_INT (SImode, ~v); + OUT_INSN (len, "bic\t%A2, %A0", op); + dummy++; + if (!r) + dummy++; + } + else + { + op[2] = gen_rtx_CONST_INT (SImode, v); + OUT_INSN (len, "and\t%A2, %A0", op); + dummy++; + dummy++; + if (!r) + dummy++; + if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8) + dummy--; + } + } + + v = (l >> 16) & 0xffff; + if (v != 0xffff) + { + if (v == list1 || v == list2 || v == list4 || v == list8) + { + op[2] = gen_rtx_CONST_INT (SImode, ~v); + OUT_INSN (len, "bic\t%A2, %B0", op); + dummy++; + if (!r) + dummy++; + } + else + { + op[2] = gen_rtx_CONST_INT (SImode, v); + OUT_INSN (len, "and\t%A2, %B0", op); + dummy++; + dummy++; + if (!r) + dummy++; + if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8) + dummy--; + } + } + + v = (h) & 0xffff; + if (v != 0xffff) + { + if (v == list1 || v == list2 || v == list4 || v == list8) + { + op[2] = gen_rtx_CONST_INT (SImode, ~v); + OUT_INSN (len, "bic\t%A2, %C0", op); + dummy++; + if (!r) + dummy++; + } + else + { + op[2] = gen_rtx_CONST_INT (SImode, v); + OUT_INSN (len, "and\t%A2, %C0", op); + dummy++; + dummy++; + if (!r) + dummy++; + if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8) + dummy--; + } + } + + v = (h >> 16) & 0xffff; + if (v != 0xffff) + { + if (v == list1 || v == list2 || v == list4 || v == list8) + { + op[2] = gen_rtx_CONST_INT (SImode, ~v); + OUT_INSN (len, "bic\t%A2, %D0", op); + dummy++; + if (!r) + dummy++; + } + else + { + op[2] = gen_rtx_CONST_INT (SImode, v); + OUT_INSN (len, "and\t%A2, %D0", op); + dummy++; + dummy++; + if (!r) + dummy++; + if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8) + dummy--; + } + } + + if (len) + *len = dummy; + return ""; +} + +const char * +msp430_andsi_code (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx op0 = operands[0]; + rtx op2 = operands[2]; + + if (nonimmediate_operand (op0, SImode) && immediate_operand (op2, SImode)) + { + if (!len) + msp430_emit_immediate_and2 (insn, operands, NULL); + return ""; + } + + if (memory_operand (op2, SImode) + && zero_shifted (operands[2]) && regsi_ok_safe (operands)) + { + if (!len) + msp430_emit_indexed_and2 (insn, operands, NULL); + else + { + if (memory_operand (op0, SImode)) + *len = 5; + else if (register_operand (op0, SImode)) + *len = 3; + } + + return ""; + } + else if (memory_operand (op2, SImode) + && zero_shifted (operands[2]) && regsi_ok_clobber (operands)) + { + if (!len) + { + output_asm_insn ("and\t@%E2+, %A0", operands); + output_asm_insn ("and\t@%E2+, %B0", operands); + } + else + { + if (register_operand (op0, SImode)) + *len = 2; + else if (memory_operand (op0, SImode)) + *len = 4; + else + abort (); + } + return ""; + } + + if (!len) + { + output_asm_insn ("and\t%A2, %A0", operands); + output_asm_insn ("and\t%B2, %B0", operands); + } + else + { + *len = 2; /* base length */ + + if (register_operand (op0, SImode)) + *len += 0; + else if (memory_operand (op0, SImode)) + *len += 2; + + if (register_operand (op2, SImode)) + *len += 0; + else if (memory_operand (op2, SImode)) + *len += 2; + else if (immediate_operand (op2, SImode)) + *len += 2; + } + + return ""; +} + + +const char * +msp430_anddi_code (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx op0 = operands[0]; + rtx op2 = operands[2]; + + if (nonimmediate_operand (op0, DImode) && immediate_operand (op2, DImode)) + { + if (!len) + msp430_emit_immediate_and4 (insn, operands, NULL); + return ""; + } + + if (memory_operand (op2, DImode) + && zero_shifted (operands[2]) && regdi_ok_safe (operands)) + { + if (!len) + msp430_emit_indexed_and4 (insn, operands, NULL); + else + { + if (memory_operand (op0, DImode)) + *len = 9; + else if (register_operand (op0, DImode)) + *len = 5; + } + + return ""; + } + else if (memory_operand (op2, DImode) + && zero_shifted (operands[2]) && regdi_ok_clobber (operands)) + { + if (!len) + { + output_asm_insn ("and\t@%E2+, %A0", operands); + output_asm_insn ("and\t@%E2+, %B0", operands); + output_asm_insn ("and\t@%E2+, %C0", operands); + output_asm_insn ("and\t@%E2+, %D0", operands); + } + else + { + if (register_operand (op0, DImode)) + *len = 4; + else if (memory_operand (op0, DImode)) + *len = 8; + else + abort (); + } + return ""; + } + + if (!len) + { + output_asm_insn ("and\t%A2, %A0", operands); + output_asm_insn ("and\t%B2, %B0", operands); + output_asm_insn ("and\t%C2, %C0", operands); + output_asm_insn ("and\t%D2, %D0", operands); + } + else + { + *len = 4; /* base length */ + + if (register_operand (op0, DImode)) + *len += 0; + else if (memory_operand (op0, DImode)) + *len += 4; + + if (register_operand (op2, DImode)) + *len += 0; + else if (memory_operand (op2, DImode)) + *len += 4; + else if (immediate_operand (op2, DImode)) + *len += 4; + else + abort (); + } + + return ""; +} + +/************** IOR CODE *********************************/ + +const char * +msp430_emit_indexed_ior2 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + emit_indexed_arith (insn, operands, 2, "bis", 0); + return ""; +} + +const char * +msp430_emit_indexed_ior4 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + emit_indexed_arith (insn, operands, 4, "bis", 0); + return ""; +} + +const char * +msp430_emit_immediate_ior2 (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int l = INTVAL (operands[2]); + int r = REG_P (operands[0]); + int v; + + + v = l & 0xffff; + + if (v) + { + OUT_INSN (len, "bis\t%A2,%A0", operands); + dummy++; + dummy++; + if (v == 0xffff || v == 1 || v == 2 || v == 4 || v == 8) + dummy--; + if (!r) + dummy++; + } + + v = (l >> 16) & 0xffff; + + if (v) + { + OUT_INSN (len, "bis\t%B2,%B0", operands); + dummy++; + dummy++; + if (v == 0xffff || v == 1 || v == 2 || v == 4 || v == 8) + dummy--; + if (!r) + dummy++; + } + + if (len) + *len = dummy; + return ""; +} + +const char * +msp430_emit_immediate_ior4 (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int l = CONST_DOUBLE_LOW (operands[2]); + int h = CONST_DOUBLE_HIGH (operands[2]); + int r = REG_P (operands[0]); + int v; + + if (GET_CODE (operands[2]) == CONST_INT) + { + l = INTVAL (operands[2]); + h = 0; + } + + v = l & 0xffff; + + if (v) + { + OUT_INSN (len, "bis\t%A2,%A0", operands); + dummy++; + dummy++; + if (v == 0xffff || v == 1 || v == 2 || v == 4 || v == 8) + dummy--; + if (!r) + dummy++; + } + + v = (l >> 16) & 0xffff; + + if (v) + { + OUT_INSN (len, "bis\t%B2,%B0", operands); + dummy++; + dummy++; + if (v == 0xffff || v == 1 || v == 2 || v == 4 || v == 8) + dummy--; + if (!r) + dummy++; + } + + l = h; + v = l & 0xffff; + + if (v) + { + OUT_INSN (len, "bis\t%C2,%C0", operands); + dummy++; + dummy++; + if (v == 0xffff || v == 1 || v == 2 || v == 4 || v == 8) + dummy--; + if (!r) + dummy++; + } + + v = (l >> 16) & 0xffff; + + if (v) + { + OUT_INSN (len, "bis\t%D2,%D0", operands); + dummy++; + dummy++; + if (v == 0xffff || v == 1 || v == 2 || v == 4 || v == 8) + dummy--; + if (!r) + dummy++; + } + + if (len) + *len = dummy; + return ""; +} + +const char * +msp430_iorsi_code (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx op0 = operands[0]; + rtx op2 = operands[2]; + + if (nonimmediate_operand (op0, SImode) && immediate_operand (op2, SImode)) + { + if (!len) + msp430_emit_immediate_ior2 (insn, operands, NULL); + return ""; + } + + if (memory_operand (op2, SImode) + && zero_shifted (operands[2]) && regsi_ok_safe (operands)) + { + if (!len) + msp430_emit_indexed_ior2 (insn, operands, NULL); + else + { + if (memory_operand (op0, SImode)) + *len = 5; + else if (register_operand (op0, SImode)) + *len = 3; + } + + return ""; + } + else if (memory_operand (op2, SImode) + && zero_shifted (operands[2]) && regsi_ok_clobber (operands)) + { + if (!len) + { + output_asm_insn ("bis\t@%E2+, %A0", operands); + output_asm_insn ("bis\t@%E2+, %B0", operands); + } + else + { + if (register_operand (op0, SImode)) + *len = 2; + else if (memory_operand (op0, SImode)) + *len = 4; + else + abort (); + } + return ""; + } + + if (!len) + { + output_asm_insn ("bis\t%A2, %A0", operands); + output_asm_insn ("bis\t%B2, %B0", operands); + } + else + { + *len = 2; /* base length */ + + if (register_operand (op0, SImode)) + *len += 0; + else if (memory_operand (op0, SImode)) + *len += 2; + + if (register_operand (op2, SImode)) + *len += 0; + else if (memory_operand (op2, SImode)) + *len += 2; + else if (immediate_operand (op2, SImode)) + *len += 2; + } + + return ""; +} + +const char * +msp430_iordi_code (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx op0 = operands[0]; + rtx op2 = operands[2]; + + if (nonimmediate_operand (op0, DImode) && immediate_operand (op2, DImode)) + { + if (!len) + msp430_emit_immediate_ior4 (insn, operands, NULL); + return ""; + } + + if (memory_operand (op2, DImode) + && zero_shifted (operands[2]) && regdi_ok_safe (operands)) + { + if (!len) + msp430_emit_indexed_ior4 (insn, operands, NULL); + else + { + if (memory_operand (op0, DImode)) + *len = 9; + else if (register_operand (op0, DImode)) + *len = 5; + } + + return ""; + } + else if (memory_operand (op2, DImode) + && zero_shifted (operands[2]) && regdi_ok_clobber (operands)) + { + if (!len) + { + output_asm_insn ("bis\t@%E2+, %A0", operands); + output_asm_insn ("bis\t@%E2+, %B0", operands); + output_asm_insn ("bis\t@%E2+, %C0", operands); + output_asm_insn ("bis\t@%E2+, %D0", operands); + } + else + { + if (register_operand (op0, DImode)) + *len = 4; + else if (memory_operand (op0, DImode)) + *len = 8; + else + abort (); + } + return ""; + } + + if (!len) + { + output_asm_insn ("bis\t%A2, %A0", operands); + output_asm_insn ("bis\t%B2, %B0", operands); + output_asm_insn ("bis\t%C2, %C0", operands); + output_asm_insn ("bis\t%D2, %D0", operands); + } + else + { + *len = 4; /* base length */ + + if (register_operand (op0, DImode)) + *len += 0; + else if (memory_operand (op0, DImode)) + *len += 4; + + if (register_operand (op2, DImode)) + *len += 0; + else if (memory_operand (op2, DImode)) + *len += 4; + else if (immediate_operand (op2, DImode)) + *len += 4; + else + abort (); + } + + return ""; +} + + +/************************* XOR CODE *****************/ + +const char * +msp430_emit_indexed_xor2 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l; +{ + int dummy = emit_indexed_arith (insn, operands, 2, "xor", 0); + if (!l) + l = &dummy; + *l = dummy; + return ""; +} + +const char * +msp430_emit_indexed_xor4 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l; +{ + int dummy = emit_indexed_arith (insn, operands, 4, "xor", 0); + if (!l) + l = &dummy; + *l = dummy; + return ""; +} + + +const char * +msp430_emit_indexed_xor2_3 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l; +{ + int dummy; + rtx x = operands[2]; + if (zero_shifted (x)) + { + dummy = emit_indexed_arith (insn, operands, 2, "xor", 0); + } + else + { + dummy = 6; + output_asm_insn ("xor\t%A2, %A0", operands); + output_asm_insn ("xor\t%B2, %B0", operands); + } + + if (!l) + l = &dummy; + *l = dummy; + return ""; +} + +const char * +msp430_emit_indexed_xor4_3 (insn, operands, l) + rtx insn; + rtx operands[]; + int *l; +{ + + int dummy; + rtx x = operands[2]; + if (zero_shifted (x)) + { + dummy = emit_indexed_arith (insn, operands, 4, "xor", 0); + } + else + { + dummy = 8; + output_asm_insn ("xor\t%A2, %A0", operands); + output_asm_insn ("xor\t%B2, %B0", operands); + output_asm_insn ("xor\t%C2, %C0", operands); + output_asm_insn ("xor\t%D2, %D0", operands); + } + + if (!l) + l = &dummy; + *l = dummy; + return ""; +} + +const char * +msp430_xorsi_code (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx op0 = operands[0]; + rtx op2 = operands[2]; + + if (memory_operand (op2, SImode) + && zero_shifted (operands[2]) && regsi_ok_safe (operands)) + { + if (!len) + msp430_emit_indexed_xor2 (insn, operands, NULL); + else + { + if (memory_operand (op0, SImode)) + *len = 5; + else if (register_operand (op0, SImode)) + *len = 3; + } + + return ""; + } + else if (memory_operand (op2, SImode) + && zero_shifted (operands[2]) && regsi_ok_clobber (operands)) + { + if (!len) + { + output_asm_insn ("xor\t@%E2+, %A0", operands); + output_asm_insn ("xor\t@%E2+, %B0", operands); + } + else + { + if (register_operand (op0, SImode)) + *len = 2; + else if (memory_operand (op0, SImode)) + *len = 4; + else + abort (); + } + return ""; + } + + if (!len) + { + + if (immediate_operand (op2, SImode)) + { + if (INTVAL (op2) & 0xfffful) + output_asm_insn ("xor\t%A2, %A0", operands); + + if (INTVAL (op2) & 0xffff0000ul) + output_asm_insn ("xor\t%B2, %B0", operands); + } + else + { + output_asm_insn ("xor\t%A2, %A0", operands); + output_asm_insn ("xor\t%B2, %B0", operands); + } + + } + else + { + *len = 2; /* base length */ + + if (register_operand (op0, SImode)) + *len += 0; + else if (memory_operand (op0, SImode)) + *len += 2; + + if (register_operand (op2, SImode)) + *len += 0; + else if (memory_operand (op2, SImode)) + *len += 2; + else if (immediate_operand (op2, SImode)) + { + if (INTVAL (op2) & 0xfffful) + *len += 1; + if (INTVAL (op2) & 0xffff0000ul) + *len += 1; + } + } + + return ""; +} + +const char * +msp430_xordi_code (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx op0 = operands[0]; + rtx op2 = operands[2]; + + if (memory_operand (op2, DImode) + && zero_shifted (operands[2]) && regdi_ok_safe (operands)) + { + if (!len) + msp430_emit_indexed_xor4 (insn, operands, NULL); + else + { + if (memory_operand (op0, DImode)) + *len = 9; + else if (register_operand (op0, DImode)) + *len = 5; + } + + return ""; + } + else if (memory_operand (op2, DImode) + && zero_shifted (operands[2]) && regdi_ok_clobber (operands)) + { + if (!len) + { + output_asm_insn ("xor\t@%E2+, %A0", operands); + output_asm_insn ("xor\t@%E2+, %B0", operands); + output_asm_insn ("xor\t@%E2+, %C0", operands); + output_asm_insn ("xor\t@%E2+, %D0", operands); + } + else + { + if (register_operand (op0, DImode)) + *len = 4; + else if (memory_operand (op0, DImode)) + *len = 8; + else + abort (); + } + return ""; + } + + if (!len) + { + output_asm_insn ("xor\t%A2, %A0", operands); + output_asm_insn ("xor\t%B2, %B0", operands); + output_asm_insn ("xor\t%C2, %C0", operands); + output_asm_insn ("xor\t%D2, %D0", operands); + } + else + { + *len = 4; /* base length */ + + if (register_operand (op0, DImode)) + *len += 0; + else if (memory_operand (op0, DImode)) + *len += 4; + + if (register_operand (op2, DImode)) + *len += 0; + else if (memory_operand (op2, DImode)) + *len += 4; + else if (immediate_operand (op2, DImode)) + *len += 4; + else + abort (); + } + + return ""; +} + + +/********* ABS CODE ***************************************/ +const char * +msp430_emit_abssi (insn, operands, l) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + output_asm_insn ("tst\t%B0", operands); + output_asm_insn ("jge\t.Lae%=", operands); + output_asm_insn ("inv\t%A0", operands); + output_asm_insn ("inv\t%B0", operands); + output_asm_insn ("inc\t%A0", operands); + output_asm_insn ("adc\t%B0", operands); + output_asm_insn (".Lae%=:", operands); + return ""; +} + +const char * +msp430_emit_absdi (insn, operands, l) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *l ATTRIBUTE_UNUSED; +{ + output_asm_insn ("tst\t%D0", operands); + output_asm_insn ("jge\t.Lae%=", operands); + output_asm_insn ("inv\t%A0", operands); + output_asm_insn ("inv\t%B0", operands); + output_asm_insn ("inv\t%C0", operands); + output_asm_insn ("inv\t%D0", operands); + output_asm_insn ("inc\t%A0", operands); + output_asm_insn ("adc\t%B0", operands); + output_asm_insn ("adc\t%C0", operands); + output_asm_insn ("adc\t%D0", operands); + output_asm_insn (".Lae%=:", operands); + return ""; +} + + +/***** SIGN EXTEND *********/ +const char * +signextendqihi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + + if (!sameoperand (operands, 1)) + { + OUT_INSN (len, "mov.b\t%A1, %A0", operands); + dummy = 3; + if (indexed_location (operands[1])) + dummy = 2; + if (GET_CODE (operands[0]) == REG) + dummy--; + if (GET_CODE (operands[1]) == REG) + dummy--; + } + + OUT_INSN (len, "sxt\t%A0", operands); + dummy += 2; + + if (zs || GET_CODE (operands[0]) == REG) + dummy -= 1; + + if (len) + *len = dummy; + + return ""; +} + +const char * +signextendqisi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + + if (!sameoperand (operands, 1)) + { + OUT_INSN (len, "mov.b\t%A1, %A0", operands); + dummy = 3; + if (indexed_location (operands[1])) + dummy = 2; + if (GET_CODE (operands[0]) == REG) + dummy--; + if (GET_CODE (operands[1]) == REG) + dummy--; + } + + OUT_INSN (len, "sxt\t%A0", operands); + OUT_INSN (len, "mov\t%A0, %B0", operands); + OUT_INSN (len, "rla\t%B0", operands); + OUT_INSN (len, "subc\t%B0, %B0", operands); + OUT_INSN (len, "inv\t%B0", operands); + + if (GET_CODE (operands[0]) == REG) + dummy += 5; + else if (zs) + dummy += 10; + else + dummy += 12; + + if (len) + *len = dummy; + + return ""; +} + +const char * +signextendqidi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + + if (!sameoperand (operands, 1)) + { + OUT_INSN (len, "mov.b\t%A1, %A0", operands); + dummy = 3; + if (indexed_location (operands[1])) + dummy = 2; + if (GET_CODE (operands[0]) == REG) + dummy--; + if (GET_CODE (operands[1]) == REG) + dummy--; + } + + OUT_INSN (len, "sxt\t%A0", operands); + OUT_INSN (len, "mov\t%A0, %B0", operands); + OUT_INSN (len, "rla\t%B0", operands); + OUT_INSN (len, "subc\t%B0, %B0", operands); + OUT_INSN (len, "inv\t%B0", operands); + OUT_INSN (len, "mov\t%B0, %C0", operands); + OUT_INSN (len, "mov\t%C0, %D0", operands); + + + if (GET_CODE (operands[0]) == REG) + dummy += 7; + else if (zs) + dummy += 16; + else + dummy += 18; + + if (len) + *len = dummy; + + return ""; +} + +const char * +signextendhisi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + + if (!sameoperand (operands, 1)) + { + OUT_INSN (len, "mov\t%A1, %A0", operands); + dummy = 3; + if (indexed_location (operands[1])) + dummy = 2; + if (GET_CODE (operands[0]) == REG) + dummy--; + if (GET_CODE (operands[1]) == REG) + dummy--; + } + + OUT_INSN (len, "mov\t%A0, %B0", operands); + OUT_INSN (len, "rla\t%B0", operands); + OUT_INSN (len, "subc\t%B0, %B0", operands); + OUT_INSN (len, "inv\t%B0", operands); + + if (GET_CODE (operands[0]) == REG) + dummy += 4; + else if (zs) + dummy += 9; + else + dummy += 11; + + if (len) + *len = dummy; + + return ""; +} + +const char * +signextendhidi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + + if (!sameoperand (operands, 1)) + { + OUT_INSN (len, "mov\t%A1, %A0", operands); + dummy = 3; + if (indexed_location (operands[1])) + dummy = 2; + if (GET_CODE (operands[0]) == REG) + dummy--; + if (GET_CODE (operands[1]) == REG) + dummy--; + } + + OUT_INSN (len, "mov\t%A0, %B0", operands); + OUT_INSN (len, "rla\t%B0", operands); + OUT_INSN (len, "subc\t%B0, %B0", operands); + OUT_INSN (len, "inv\t%B0", operands); + OUT_INSN (len, "mov\t%B0, %C0", operands); + OUT_INSN (len, "mov\t%C0, %D0", operands); + + if (GET_CODE (operands[0]) == REG) + dummy += 6; + else if (zs) + dummy += 13; + else + dummy += 14; + + if (len) + *len = dummy; + + return ""; +} + +const char * +signextendsidi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + + if (!sameoperand (operands, 1)) + { + OUT_INSN (len, "mov\t%A1, %A0", operands); + OUT_INSN (len, "mov\t%B1, %B0", operands); + dummy = 6; + if (indexed_location (operands[1])) + dummy = 4; + if (GET_CODE (operands[0]) == REG) + dummy -= 2; + if (GET_CODE (operands[1]) == REG) + dummy -= 2; + } + + OUT_INSN (len, "mov\t%B0, %C0", operands); + OUT_INSN (len, "rla\t%C0", operands); + OUT_INSN (len, "subc\t%C0, %C0", operands); + OUT_INSN (len, "inv\t%C0", operands); + OUT_INSN (len, "mov\t%C0, %D0", operands); + + if (GET_CODE (operands[0]) == REG) + dummy += 5; + else + dummy += 13; + + if (len) + *len = dummy; + + return ""; +} + + +/**** ZERO EXTEND *****/ + +const char * +zeroextendqihi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[1]) || indexed_location (operands[1]); + + if(operands[0] == op2_rtx) + { + OUT_INSN (len, "and #0xff00, %0",operands); + dummy = 3; + return ""; + } + if (!sameoperand (operands, 1)) + { + OUT_INSN (len, "mov.b\t%A1, %A0", operands); + dummy = 3; + if (zs) + dummy = 2; + if (GET_CODE (operands[0]) == REG) + dummy--; + if (GET_CODE (operands[1]) == REG) + dummy--; + } + + if (!REG_P (operands[0])) + { + OUT_INSN (len, "clr.b\t%J0", operands); + dummy += 2; + } + else if (sameoperand (operands, 1)) + { + OUT_INSN (len, "and.b\t#-1,%0", operands); + dummy++; + } + + if (len) + *len = dummy; + + return ""; +} + +const char * +zeroextendqisi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[1]) || indexed_location (operands[1]); + + if (!sameoperand (operands, 1) || REG_P (operands[0])) + { + OUT_INSN (len, "mov.b\t%A1, %A0", operands); + dummy = 3; + if (zs) + dummy = 2; + if (GET_CODE (operands[0]) == REG) + dummy--; + if (GET_CODE (operands[1]) == REG) + dummy--; + } + + + if (!REG_P (operands[0])) + { + OUT_INSN (len, "clr.b\t%J0", operands); + } + else if (sameoperand (operands, 1)) + { + OUT_INSN (len, "and.b\t#-1,%0", operands); + dummy++; + } + OUT_INSN (len, "clr\t%B0", operands); + dummy += 2; + if (GET_CODE (operands[0]) == REG) + dummy--; + + if (len) + *len = dummy; + + return ""; +} + + +const char * +zeroextendqidi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[1]) || indexed_location (operands[1]); + + if (!sameoperand (operands, 1) || REG_P (operands[0])) + { + OUT_INSN (len, "mov.b\t%A1, %A0", operands); + dummy = 3; + if (zs) + dummy = 2; + if (GET_CODE (operands[0]) == REG) + dummy--; + if (GET_CODE (operands[1]) == REG) + dummy--; + } + + if (!REG_P (operands[0])) + { + OUT_INSN (len, "clr.b\t%J0", operands); + dummy += 2; + } + else if (sameoperand (operands, 1)) + { + OUT_INSN (len, "and.b\t#-1,%0", operands); + dummy++; + } + dummy += 6; + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%C0", operands); + OUT_INSN (len, "clr\t%D0", operands); + + if (GET_CODE (operands[0]) == REG && len) + *len -= 3; + + if (len) + *len = dummy; + + return ""; +} + +const char * +zeroextendhisi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[1]) || indexed_location (operands[1]); + + if (!sameoperand (operands, 1)) + { + OUT_INSN (len, "mov\t%A1, %A0", operands); + dummy = 3; + if (zs) + dummy = 2; + if (GET_CODE (operands[0]) == REG) + dummy--; + if (GET_CODE (operands[1]) == REG) + dummy--; + } + + OUT_INSN (len, "clr\t%B0", operands); + dummy += 2; + if (GET_CODE (operands[0]) == REG) + dummy--; + + if (len) + *len = dummy; + + return ""; + +} + +const char * +zeroextendhidi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[1]) || indexed_location (operands[1]); + + if (!sameoperand (operands, 1)) + { + OUT_INSN (len, "mov\t%A1, %A0", operands); + dummy = 3; + if (zs) + dummy = 2; + if (GET_CODE (operands[0]) == REG) + dummy--; + if (GET_CODE (operands[1]) == REG) + dummy--; + } + + dummy += 6; + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%C0", operands); + OUT_INSN (len, "clr\t%D0", operands); + + if (GET_CODE (operands[0]) == REG) + dummy -= 3; + + if (len) + *len = dummy; + + return ""; +} + +const char * +zeroextendsidi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int dummy = 0; + + if (!sameoperand (operands, 1)) + { + if (zero_shifted (operands[1])) + { + rtx reg = XEXP (operands[1], 0); + + OUT_INSN (len, "mov\t@%E1+, %A0", operands); + OUT_INSN (len, "mov\t@%E1+, %B0", operands); + dummy = 4; + if (GET_CODE (operands[0]) == REG) + dummy -= 2; + + if (!dead_or_set_p (insn, reg)) + { + OUT_INSN (len, "sub\t#4, %E1", operands); + dummy += 1; + } + } + else + { + OUT_INSN (len, "mov\t%A1, %A0", operands); + OUT_INSN (len, "mov\t%B1, %B0", operands); + dummy = 6; + if (GET_CODE (operands[0]) == REG) + dummy -= 2; + if (GET_CODE (operands[1]) == REG) + dummy -= 2; + if (indexed_location (operands[1])) + dummy--; + } + } + + dummy += 4; + OUT_INSN (len, "clr\t%C0", operands); + OUT_INSN (len, "clr\t%D0", operands); + + if (GET_CODE (operands[0]) == REG) + dummy -= 2; + + if (len) + *len = dummy; + + return ""; +} + +/******************* TESTS AND JUMPS *********************/ + +RTX_CODE +msp430_canonicalize_comparison (code, op0, op1) + RTX_CODE code; + rtx *op0; + rtx *op1; +{ + RTX_CODE rc = code; + + if ( CONSTANT_P(*op1) ) + { + ; /* nothing to be done */ + } + else + { + switch (code) + { + case GT: + case LE: + case GTU: + case LEU: + { + rtx x; + rc = swap_condition (code); + x = *op0; + *op0 = *op1; + *op1 = x; + } + break; + default: + break; + } + } + return rc; +} + + +void +msp430_emit_cbranch (code, loc) + enum rtx_code code; + rtx loc; +{ + rtx op0 = msp430_compare_op0; + rtx op1 = msp430_compare_op1; + rtx condition_rtx, loc_ref, branch; + enum machine_mode mode; + int mem_volatil=0; + + if (!msp430_compare_op0 && !msp430_compare_op1) + { + /* this is a branch upon previous insn issued */ + loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc); + condition_rtx = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx); + + branch = gen_rtx_SET (VOIDmode, + pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, + condition_rtx, + loc_ref, pc_rtx)); + emit_jump_insn (branch); + return; + } + + mode = GET_MODE (op0); + if (mode != SImode && mode != HImode && mode != QImode) + abort (); + + + /* now convert codes */ + code = msp430_canonicalize_comparison (code, &op0, &op1); + + /* for HI and QI modes everything is simple. + Also, if code is eq or ne in SI mode, no clobbers required. */ + + if (mode == SImode && !(code == EQ || code == NE)) + { + /* check if only high nibbles required */ + if (GET_CODE (op1) == CONST_INT + && INTVAL (op1) == 0 && (code == LT || code == GE)) + { + mem_volatil = MEM_VOLATILE_P(op0); + MEM_VOLATILE_P(op0) = 0; + op0 = gen_highpart (HImode, op0); + MEM_VOLATILE_P(op0) = mem_volatil; + mode = HImode; + PUT_MODE (op1, VOIDmode); /* paranoia ? */ + } + else if (GET_CODE (op1) == CONST_INT + && ((INTVAL (op1) + 1) & 0xffff) == 0 + && (code == GT || code == GTU || code == LE || code == LEU)) + { + /* check if this can be done simple. + we will not clobber const operand. */ + int x = INTVAL (op1); + x++; + x >>= 16; + MEM_VOLATILE_P(op0) = 0; + op0 = gen_highpart (HImode, op0); + MEM_VOLATILE_P(op0) = mem_volatil; + mode = HImode; + op1 = GEN_INT (trunc_int_for_mode (x, HImode)); + + if (code == GT) + code = GE; + else if (code == GTU) + code = GEU; + else if (code == LEU) + code = LTU; + else if (code == LE) + code = LT; + } + else + { + rtvec vec; + /* the redudant move will be deleted */ + op0 = copy_to_mode_reg (SImode, op0); + condition_rtx = gen_rtx (code, mode, op0, op1); + loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc); + branch = gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, + loc_ref, pc_rtx)); + vec = gen_rtvec (2, branch, gen_rtx_CLOBBER (SImode, op0)); + emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec)); + msp430_compare_op0 = 0; + msp430_compare_op1 = 0; + return; + } + } + else if(mode == SImode && code == NE + && GET_CODE(op1)!= CONST_INT && op1 != const0_rtx) + { + rtx op0lo, op0hi, op1lo, op1hi; + + mem_volatil = MEM_VOLATILE_P(op0); + op0lo = gen_lowpart(HImode, op0); + op0hi = gen_highpart(HImode, op0); + MEM_VOLATILE_P(op0) = mem_volatil; + + mem_volatil = MEM_VOLATILE_P(op1); + op1lo = gen_lowpart(HImode, op1); + op1hi = gen_highpart(HImode, op1); + MEM_VOLATILE_P(op1) = mem_volatil; + + condition_rtx = gen_rtx (NE,HImode,op0lo,op1lo); + loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc); + branch = gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, + loc_ref, pc_rtx)); + emit_jump_insn (branch); + condition_rtx = gen_rtx (NE,HImode,op0hi,op1hi); + branch = gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, + loc_ref, pc_rtx)); + emit_jump_insn (branch); + msp430_compare_op0 = 0; + msp430_compare_op1 = 0; + return; + } + else if(mode == SImode && code == EQ && GET_CODE(op1)!= CONST_INT ) + { + rtx tlabel = gen_label_rtx(); + rtx tloc_ref; + rtx op0lo, op0hi, op1lo, op1hi; + + mem_volatil = MEM_VOLATILE_P(op0); + op0lo = gen_lowpart(HImode, op0); + op0hi = gen_highpart(HImode, op0); + MEM_VOLATILE_P(op0) = mem_volatil; + + mem_volatil = MEM_VOLATILE_P(op1); + op1lo = gen_lowpart(HImode, op1); + op1hi = gen_highpart(HImode, op1); + MEM_VOLATILE_P(op1) = mem_volatil; + + condition_rtx = gen_rtx (NE,HImode,op0lo,op1lo); + tloc_ref = gen_rtx_LABEL_REF (VOIDmode, tlabel); + branch = gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, + tloc_ref, pc_rtx)); + emit_jump_insn (branch); + + condition_rtx = gen_rtx (EQ,HImode,op0hi,op1hi); + loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc); + branch = gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, + loc_ref, pc_rtx)); + emit_jump_insn (branch); + emit_label(tlabel); + msp430_compare_op0 = 0; + msp430_compare_op1 = 0; + return ; + } + + condition_rtx = gen_rtx (code, mode, op0, op1); + loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc); + branch = gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx, + loc_ref, pc_rtx)); + + emit_jump_insn (branch); + + msp430_compare_op0 = 0; + msp430_compare_op1 = 0; + return; +} + + +/* x - dst + y - src */ +static int +msp430_cc_source (insn, code, x, y) + rtx insn; + enum rtx_code code ATTRIBUTE_UNUSED; + rtx x; + rtx y; +{ + rtx prev = insn; + enum attr_cc cc; + rtx set; + rtx src, dst; + rtx x1 = 0; + + if(GET_CODE(x) == MEM) + { + x1 = XEXP(x,0); + if(GET_CODE(x1) == PLUS) + { + x1 = XEXP(x1,0); + } + + if(!REG_P(x1)) x1 = 0; + } + + while (0 != (prev = PREV_INSN (prev))) + { + if (GET_CODE (prev) == CODE_LABEL + || GET_CODE (prev) == BARRIER || GET_CODE (prev) == CALL_INSN) + return 0; + + if (GET_CODE (prev) == INSN) + { + set = single_set (prev); + + if(!set) + return 0; + + cc = get_attr_cc (prev); + + if (cc == CC_NONE) /* does not change CC */ + { + /*The one spot by Nick C. */ + dst = SET_DEST (set); + if((dst && rtx_equal_p (x, dst)) || + (x1 && dst && rtx_equal_p (x1, dst))) + return 0; + else + continue; + } + + if (cc == CC_CLOBBER) /* clobber */ + return 0; + + if (cc == CC_OPER) /* post-incremental stuff */ + { + src = SET_SRC (set); + if (GET_CODE (set) == IOR) /* does not change CC */ + { + dst = SET_DEST (set); + if(dst && rtx_equal_p (x, dst)) + return 0; + else + continue; + } + } + + /* all other attributes are bit messy. + So, we'll record destination and check if + this matches 'x' and compare is against zero */ + dst = SET_DEST (set); + if (rtx_equal_p (x, dst) && rtx_equal_p (y, const0_rtx)) + return 1; + else + return 0; + } + else if (GET_CODE (prev) == JUMP_INSN) + { + /* if 2 consequent jump insns were issued, this means + that operands (more likely src) are different. + however, some jumps optimization can equalize these operands + and everything will be bad. Therefore, assume that + any jump insn clobbers condition codes.*/ + return 0; + } + } + return 0; +} + + + +const char * +msp430_cbranch (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + rtx ops[3]; + enum rtx_code code; + rtx locs[3]; + int dummy = 0; + enum machine_mode mode; + int quater = 0; + rtx loc = operands[0]; + int distance = msp430_jump_dist (loc, insn); + int predist = get_attr_length (insn); + int nooverflow = 0; + +#define ECOND(f,x) do{if(!len)msp430_emit_b##f(locs,predist + x);dummy+=(predist + x);}while(0) + locs[0] = operands[0]; + ops[0] = operands[2]; + ops[1] = operands[3]; + + if (ops[1] && ops[0]) + { + mode = GET_MODE (operands[2]); + code = GET_CODE (operands[1]); + quater = (mode == QImode); + } + else + { + mode = HImode; + code = GET_CODE (operands[1]); + } + + /* here check wiered conditions */ + if (ops[1] && GET_CODE (ops[1]) == CONST_INT + && (code == GT || code == LE || code == GTU || code == LEU)) + { + int x = INTVAL (ops[1]); + switch (code) + { + case GT: + ops[1] = GEN_INT (x + 1); + code = GE; + break; + case LE: + ops[1] = GEN_INT (x + 1); + code = LT; + break; + case GTU: + ops[1] = GEN_INT (x + 1); + code = GEU; + break; + case LEU: + ops[1] = GEN_INT (x + 1); + code = LTU; + break; + default: + break; + } + } + else if (ops[1] && CONSTANT_P (ops[1]) && GET_MODE(ops[1]) == HImode + && (code == GT || code == LE || code == GTU || code == LEU)) + { + /* Handle pointers here */ + ops[1] = gen_rtx_CONST(HImode,gen_rtx_PLUS(HImode,ops[1],GEN_INT(1))); + + switch (code) + { + case GT: + code = GE; + break; + case LE: + code = LT; + break; + case GTU: + code = GEU; + break; + case LEU: + code = LTU; + break; + default: + break; + } + } + + if (ops[0] != cc0_rtx && ops[1] && ops[0]) + { + if (code == NE || code == EQ) + { + /* check if op0 is zero shited - win 1 byte */ + if (indexed_location (ops[0]) && !CONSTANT_P (ops[1])) + { + rtx x = ops[0]; + ops[0] = ops[1]; + ops[1] = x; + } + } + + /* check if compares were not issued */ + if ((mode == QImode || mode == HImode) + && msp430_cc_source (insn, code, ops[0], ops[1])) + { + /* check if overflow can be usefull here. */ + if( ops[1] == const0_rtx + || (GET_CODE(ops[1]) == CONST_INT + && INTVAL(ops[1]) == 0 )) + { + if(code == LT || code == GE) + nooverflow = 1; + } + } + else if (mode == QImode || mode == HImode) + { + /* check if previous insns did not set CC correctly */ + if (quater) + OUT_INSN (len, "cmp.b\t%1, %0", ops); + else + OUT_INSN (len, "cmp\t%1, %0", ops); + dummy += 3; + if (REG_P (ops[0])) + dummy--; + if (REG_P (ops[1])) + dummy--; + if (indexed_location (ops[1])) + dummy--; + if (GET_CODE (ops[1]) == CONST_INT) + { + int x = INTVAL (ops[1]) & 0xffff; + if (x == 0 || x == -1 || x == 1 || x == 2 || x == 4 || x == 8) + dummy--; + } + } + + /* adjust distance */ + distance -= dummy; + + if (mode == SImode && (code == EQ || code == NE)) + { + /* compare against zero and can we clobber source register ? */ + if (((GET_CODE (ops[1]) == CONST_INT + && INTVAL (ops[1]) == 0) + || ops[1] == const0_rtx) + && REG_P (ops[0]) && dead_or_set_p (insn, ops[0])) + { + OUT_INSN (len, "bis\t%A0, %B0", ops); + OUT_INSN (len, "tst\t%B0", ops); + dummy += 2; + } + else + { + /* cannot clobber or something... */ + OUT_INSN (len, "cmp\t%A1, %A0", ops); + dummy += 3; + if (REG_P (ops[0])) + dummy--; + if (REG_P (ops[1])) + dummy--; + if (indexed_location (ops[1])) + dummy--; + if (GET_CODE (ops[1]) == CONST_INT) + { + int x = INTVAL (ops[1]) & 0xffff; + if (x == 0 || x == 1 || x == -1 || x == 2 || x == 4 + || x == 8) + dummy--; + } + distance -= dummy; + if (distance > 500 || distance < -500) + predist = 3; + else + predist = 1; + + if (code == EQ) + { + OUT_INSN (len, "jne\t.LcmpSIe%=", ops); + OUT_INSN (len, "cmp\t%B1, %B0", ops); + dummy++; + } + else + { + ECOND (ne, 0); + OUT_INSN (len, "cmp\t%B1, %B0", ops); + } + + dummy += 3; + if (REG_P (ops[0])) + dummy--; + if (REG_P (ops[1])) + dummy--; + if (GET_CODE (ops[1]) == CONST_INT) + { + int x = (INTVAL (ops[1]) >> 16) & 0xffff; + if (x == 0 || x == 0xffff || x == 1 || x == 2 || x == 4 + || x == 8) + dummy--; + } + } + } + else if (mode == SImode) + { + int dl = 0; + rtx oops[3]; + oops[0] = ops[0]; + oops[1] = ops[0]; + oops[2] = ops[1]; + + if (len) + msp430_subsi_code (insn, oops, &dl); + else + msp430_subsi_code (insn, oops, NULL); + + if (len) + { + /* not handeled by adjust_insn_len() */ + dummy += dl; + if (GET_CODE (ops[1]) == CONST_INT) + { + int x = (INTVAL (ops[1]) >> 16) & 0xffff; + if (x == 0 || x == 1 || x == -1 || x == 2 || x == 4 + || x == 8) + dummy--; + x = (INTVAL (ops[1]) >> 0) & 0xffff; + if (x == 0 || x == 1 || x == -1 || x == 2 || x == 4 + || x == 8) + dummy--; + } + } + } + } + + distance -= dummy; + + if (distance > 500 || distance < -500) + predist = 3; + else + predist = 1; + + /* out assembler commands if required */ + switch (code) + { + case EQ: + ECOND (eq, 0); + if (mode == SImode) + { + OUT_INSN (len, ".LcmpSIe%=:", operands); + } + break; + case NE: + ECOND (ne, 0); + break; + case LT: + if(nooverflow) + ECOND (ltnoovfl,0); + else + ECOND (lt, 0); + break; + case GE: + if(nooverflow) + { + if(len) *len += 2; + if(mode == QImode) + OUT_INSN (len, "bit.b\t#0x80, %0",ops); + else + OUT_INSN (len, "bit\t#0x8000, %0",ops); + } + ECOND (ge, 0); + break; + case LTU: + ECOND (ltu, 0); + break; + case GEU: + ECOND (geu, 0); + break; + /* hopfully the following will not occure */ + case LEU: + ECOND (leu, 1); + break; + case GT: + ECOND (gt, 1); + break; + case GTU: + ECOND (gtu, 1); + break; + case LE: + ECOND (le, 1); + break; + + default: + break; + } + + if (len) + *len = dummy; + return ""; +} + +/***************** AUXES FOR TESTS *********************/ + +RTX_CODE +followed_compare_condition (insn) + rtx insn; +{ + rtx next = next_real_insn (insn); + RTX_CODE cond = UNKNOWN; + + if (next && GET_CODE (next) == JUMP_INSN) + { + rtx pat = PATTERN (next); + rtx src, t; + + if (GET_CODE (pat) == RETURN) + return UNKNOWN; + + src = SET_SRC (pat); + t = XEXP (src, 0); + cond = GET_CODE (t); + } + else if (next && GET_CODE (next) == INSN) + { + /* here, two possible : sgeu ans sltu */ + + rtx pat = PATTERN (next); + rtx src; + + if (!pat || GET_CODE (pat) != SET) + return UNKNOWN; + + src = SET_SRC (pat); + cond = GET_CODE (src); /* this must be IF_THEN_ELSE */ + if (cond != IF_THEN_ELSE) + return UNKNOWN; + } + return cond; +} + +/******** jumps ************/ + +const char * +msp430_emit_blt0si (operands, len) + rtx operands[]; + int len; +{ + output_asm_insn ("tst\t%B2", operands); + switch (len) + { + case 2: + output_asm_insn ("jl\t%0", operands); + break; + case 4: + output_asm_insn ("jge\t+4", operands); + output_asm_insn ("br\t#%0", operands); + break; + default: + return "bug!!!"; + } + + return ""; +} + +const char * +msp430_emit_beq (operands, len) + rtx operands[]; + int len; +{ + + switch (len) + { + case 1: + case 2: + output_asm_insn ("jeq\t%0", operands); + break; + case 3: + case 4: + output_asm_insn ("jne\t+4", operands); + output_asm_insn ("br\t#%0", operands); + break; + default: + return "bug!!!"; + } + + return ""; +} + +const char * +msp430_emit_bne (operands, len) + rtx operands[]; + int len; +{ + + switch (len) + { + case 1: + case 2: + output_asm_insn ("jne\t%0", operands); + break; + case 3: + case 4: + output_asm_insn ("jeq\t+4", operands); + output_asm_insn ("br\t#%0", operands); + break; + default: + return "bug!!!"; + } + + return ""; +} + +const char * +msp430_emit_bgt (operands, len) + rtx operands[]; + int len; +{ + switch (len) + { + case 2: + output_asm_insn ("jeq\t+2", operands); + output_asm_insn ("jge\t%0", operands); + + break; + case 4: + output_asm_insn ("jeq\t+6", operands); + output_asm_insn ("jl\t+4", operands); + output_asm_insn ("br\t#%0", operands); + break; + default: + return "bug!!!"; + } + + return ""; +} + +const char * +msp430_emit_bgtu (operands, len) + rtx operands[]; + int len; +{ + switch (len) + { + case 2: + output_asm_insn ("jeq\t+2", operands); + output_asm_insn ("jhs\t%0", operands); + + break; + case 4: + output_asm_insn ("jeq\t+6", operands); + output_asm_insn ("jlo\t+4", operands); + output_asm_insn ("br\t#%0", operands); + break; + default: + return "bug!!!"; + } + + return ""; +} + +const char * +msp430_emit_blt (operands, len) + rtx operands[]; + int len; +{ + switch (len) + { + case 1: + case 2: + output_asm_insn ("jl\t%0", operands); + break; + case 3: + case 4: + output_asm_insn ("jge\t+4", operands); + output_asm_insn ("br\t#%0", operands); + break; + default: + return "bug!!!"; + } + + return ""; +} + + +const char * +msp430_emit_bltnoovfl (operands, len) + rtx operands[]; + int len; +{ + switch (len) + { + case 1: + case 2: + output_asm_insn ("jn\t%0", operands); + break; + case 3: + case 4: + output_asm_insn ("jn\t+2",operands); + output_asm_insn ("jmp\t+4", operands); + output_asm_insn ("br\t#%0", operands); + break; + default: + return "bug!!!"; + } + + return ""; +} + + + +const char * +msp430_emit_bltu (operands, len) + rtx operands[]; + int len; +{ + switch (len) + { + case 1: + case 2: + output_asm_insn ("jlo\t%0", operands); + break; + case 3: + case 4: + output_asm_insn ("jhs\t+4", operands); + output_asm_insn ("br\t#%0", operands); + break; + default: + return "bug!!!"; + } + + return ""; +} + +const char * +msp430_emit_bge (operands, len) + rtx operands[]; + int len; +{ + switch (len) + { + case 1: + case 2: + output_asm_insn ("jge\t%l0", operands); + break; + case 3: + case 4: + output_asm_insn ("jl\t+4", operands); + output_asm_insn ("br\t#%0", operands); + break; + default: + return "bug!!!"; + } + + return ""; +} + +const char * +msp430_emit_bgeu (operands, len) + rtx operands[]; + int len; +{ + switch (len) + { + case 1: + case 2: + output_asm_insn ("jhs\t%l0", operands); + break; + case 3: + case 4: + output_asm_insn ("jlo\t+4", operands); + output_asm_insn ("br\t#%0", operands); + break; + default: + return "bug!!!"; + } + + return ""; +} + +const char * +msp430_emit_ble (operands, len) + rtx operands[]; + int len; +{ + switch (len) + { + case 2: + output_asm_insn ("jeq\t%0", operands); + output_asm_insn ("jl\t%0", operands); + break; + case 4: + output_asm_insn ("jeq\t+2", operands); + output_asm_insn ("jge\t+4", operands); + output_asm_insn ("br\t#%0", operands); + break; + default: + return "bug!!!"; + } + + return ""; +} + +const char * +msp430_emit_bleu (operands, len) + rtx operands[]; + int len; +{ + switch (len) + { + case 2: + output_asm_insn ("jeq\t%0", operands); + output_asm_insn ("jlo\t%0", operands); + break; + case 4: + output_asm_insn ("jeq\t+2", operands); + output_asm_insn ("jhs\t+4", operands); + output_asm_insn ("br\t#%0", operands); + break; + default: + return "bug!!!"; + } + + return ""; +} + + +/* SHIFT GUARDS */ +int +msp430_ashlhi3 (operands) + rtx operands[]; +{ + int x; + rtx set, shift; + rtx dst; + + if (!const_int_operand (operands[2], VOIDmode)) + { + rtx op0, op1; + + op0 = force_reg (HImode, operands[0]); + op1 = force_reg (HImode, operands[1]); + operands[2] = copy_to_mode_reg (HImode, operands[2]); + emit_insn (gen_ashlhi3_cnt (op0, op1, operands[2])); + emit_move_insn (operands[0], op0); + return 1; + } + + x = INTVAL (operands[2]); + + if (x > 15 || x < 0) + { + emit_move_insn (operands[0], const0_rtx); + return 1; + } + + if (x == 0) + { + emit_move_insn (operands[0], operands[1]); + return 1; + } + + if (x < 3) + { + emit_move_insn (operands[0], operands[1]); + dst = operands[0]; + shift = gen_rtx_ASHIFT (HImode, dst, const1_rtx); + set = gen_rtx_SET (HImode, dst, shift); + while (x--) + emit_insn (set); + return 1; + } + + if (x == 15) + { + shift = gen_rtx_ASHIFT (HImode, operands[1], GEN_INT (15)); + set = gen_rtx_SET (HImode, operands[0], shift); + emit_insn (set); + return 1; + } + + if (operands[0] != operands[1]) + dst = copy_to_mode_reg (HImode, operands[1]); + else + dst = operands[1]; + if (x > 7) + { + emit_insn (gen_andhi3 (dst, dst, GEN_INT (0xff))); + emit_insn (gen_swpb (dst, dst)); + x -= 8; + } + + shift = gen_rtx_ASHIFT (HImode, dst, const1_rtx); + set = gen_rtx_SET (HImode, dst, shift); + + while (x--) + emit_insn (set); + if (dst != operands[0]) + emit_move_insn (operands[0], dst); + return 1; +} + +int +msp430_ashlsi3 (operands) + rtx operands[]; +{ + int x; + rtx shift, set, dst; + + if (!const_int_operand (operands[2], VOIDmode)) + { + rtx op0, op1; + + op0 = force_reg (SImode, operands[0]); + op1 = force_reg (SImode, operands[1]); + operands[2] = copy_to_mode_reg (HImode, operands[2]); + emit_insn (gen_ashlsi3_cnt (op0, op1, operands[2])); + emit_move_insn (operands[0], op0); + return 1; + } + + x = INTVAL (operands[2]); + + if (x >= 32 || x < 0) + { + emit_move_insn (operands[0], const0_rtx); + return 1; + } + + if (x == 0) + { + emit_move_insn (operands[0], operands[1]); + return 1; + } + + if (x == 1) + { + emit_move_insn (operands[0], operands[1]); + dst = operands[0]; + shift = gen_rtx_ASHIFT (SImode, dst, operands[2]); + set = gen_rtx_SET (SImode, dst, shift); + emit_insn (set); + return 1; + } + + if (operands[0] != operands[1]) + dst = copy_to_mode_reg (SImode, operands[1]); + else + dst = operands[1]; + + if (x == 31) + { + shift = gen_rtx_ASHIFT (SImode, operands[1], GEN_INT (31)); + set = gen_rtx_SET (SImode, operands[0], shift); + emit_insn (set); + return 1; + } + + if (x >= 16) + { + rtx dhi = gen_highpart (HImode, operands[0]); + rtx dlo = gen_lowpart (HImode, operands[0]); + rtx shi = gen_highpart (HImode, operands[1]); + rtx slo = gen_lowpart (HImode, operands[1]); + + emit_move_insn (dhi, slo); + emit_move_insn (dlo, const0_rtx); + x -= 16; + if (x) + { + rtx ops[3]; + ops[0] = dhi; + ops[1] = dhi; + ops[2] = GEN_INT (x); + msp430_ashlhi3 (ops); + } + return 1; + } + + if (x >= 8) + { + shift = gen_rtx_ASHIFT (SImode, dst, GEN_INT (8)); + set = gen_rtx_SET (SImode, dst, shift); + emit_insn (set); + x -= 8; + } + + shift = gen_rtx_ASHIFT (SImode, dst, GEN_INT (1)); + set = gen_rtx_SET (SImode, dst, shift); + + while (x--) + emit_insn (set); + if (dst != operands[0]) + emit_move_insn (operands[0], dst); + return 1; +} + +/* arithmetic right */ +int +msp430_ashrhi3 (operands) + rtx operands[]; +{ + int x; + rtx shift, set, dst; + + if (!const_int_operand (operands[2], VOIDmode)) + { + rtx op0, op1; + + op0 = force_reg (HImode, operands[0]); + op1 = force_reg (HImode, operands[1]); + operands[2] = copy_to_mode_reg (HImode, operands[2]); + emit_insn (gen_ashrhi3_cnt (op0, op1, operands[2])); + emit_move_insn (operands[0], op0); + return 1; + } + + x = INTVAL (operands[2]); + if (x >= 15 || x < 0) + { + dst = gen_lowpart (QImode, operands[0]); + emit_move_insn (operands[0], operands[1]); + emit_insn (gen_swpb (operands[0], operands[0])); + emit_insn (gen_extendqihi2 (operands[0], dst)); + emit_insn (gen_swpb (operands[0], operands[0])); + emit_insn (gen_extendqihi2 (operands[0], dst)); + return 1; + } + + if (x == 0) + { + emit_move_insn (operands[0], operands[1]); + return 1; + } + + if (x < 3) + { + emit_move_insn (operands[0], operands[1]); + dst = operands[0]; + shift = gen_rtx_ASHIFTRT (HImode, dst, const1_rtx); + set = gen_rtx_SET (HImode, dst, shift); + + while (x--) + emit_insn (set); + return 1; + } + + if (operands[0] != operands[1]) + dst = copy_to_mode_reg (HImode, operands[1]); + else + dst = operands[1]; + + if (x >= 8) + { + rtx dlo = gen_lowpart (QImode, dst); + emit_insn (gen_swpb (dst, dst)); + emit_insn (gen_extendqihi2 (dst, dlo)); + x -= 8; + } + + shift = gen_rtx_ASHIFTRT (HImode, dst, const1_rtx); + set = gen_rtx_SET (HImode, dst, shift); + + while (x--) + emit_insn (set); + + if (dst != operands[0]) + emit_move_insn (operands[0], dst); + + return 1; +} + +int +msp430_ashrsi3 (operands) + rtx operands[]; +{ + int x; + rtx shift, set, dst; + + if (!const_int_operand (operands[2], VOIDmode)) + { + rtx op0, op1; + + op0 = force_reg (SImode, operands[0]); + op1 = force_reg (SImode, operands[1]); + operands[2] = copy_to_mode_reg (HImode, operands[2]); + emit_insn (gen_ashrsi3_cnt (op0, op1, operands[2])); + emit_move_insn (operands[0], op0); + return 1; + } + + x = INTVAL (operands[2]); + + if (x == 0) + { + emit_move_insn (operands[0], operands[1]); + return 1; + } + + if (operands[0] != operands[1]) + dst = copy_to_mode_reg (SImode, operands[1]); + else + dst = operands[1]; + + if (x >= 31 || x < 0) + { + + shift = gen_rtx_ASHIFTRT (SImode, dst, GEN_INT (31)); + set = gen_rtx_SET (SImode, dst, shift); + emit_insn (set); + + if (dst != operands[0]) + emit_move_insn (operands[0], dst); + return 1; + } + + if (x == 1) + { + emit_move_insn (operands[0], operands[1]); + dst = operands[0]; + shift = gen_rtx_ASHIFTRT (SImode, dst, operands[2]); + set = gen_rtx_SET (SImode, dst, shift); + emit_insn (set); + return 1; + } + + if (x >= 16) + { + rtx dlo = gen_lowpart (HImode, operands[0]); + rtx shi = gen_highpart (HImode, dst); + + emit_move_insn (gen_highpart (HImode, operands[0]), const0_rtx); + emit_insn (gen_extendhisi2 (operands[0], shi)); + x -= 16; + if (x) + { + rtx ops[3]; + ops[0] = dlo; + ops[1] = dlo; + ops[2] = GEN_INT (x); + msp430_ashrhi3 (ops); + } + return 1; + } + + if (x >= 8) + { + shift = gen_rtx_ASHIFTRT (SImode, dst, GEN_INT (8)); + set = gen_rtx_SET (SImode, dst, shift); + emit_insn (set); + x -= 8; + } + + shift = gen_rtx_ASHIFTRT (SImode, dst, GEN_INT (1)); + set = gen_rtx_SET (SImode, dst, shift); + + while (x--) + emit_insn (set); + if (dst != operands[0]) + emit_move_insn (operands[0], dst); + return 1; +} + +/* logical right */ +int +msp430_lshrhi3 (operands) + rtx operands[]; +{ + int x; + rtx shift, set, dst; + + if (!const_int_operand (operands[2], VOIDmode)) + { + rtx op0, op1; + + op0 = force_reg (HImode, operands[0]); + op1 = force_reg (HImode, operands[1]); + operands[2] = copy_to_mode_reg (HImode, operands[2]); + emit_insn (gen_lshrhi3_cnt (op0, op1, operands[2])); + emit_move_insn (operands[0], op0); + return 1; + } + + x = INTVAL (operands[2]); + if (x > 15 || x < 0) + { + emit_move_insn (operands[0], const0_rtx); + return 1; + } + + if (x == 0) + { + emit_move_insn (operands[0], operands[1]); + return 1; + } + + if (x < 3) + { + emit_move_insn (operands[0], operands[1]); + dst = operands[0]; + shift = gen_rtx_LSHIFTRT (HImode, dst, const1_rtx); + set = gen_rtx_SET (HImode, dst, shift); + emit_insn (set); + x--; + + if (x) + { + shift = gen_rtx_ASHIFTRT (HImode, dst, const1_rtx); + set = gen_rtx_SET (HImode, dst, shift); + emit_insn (set); + } + return 1; + } + + if (x == 15) + { + emit_move_insn (operands[0], operands[1]); + dst = operands[0]; + shift = gen_rtx_LSHIFTRT (HImode, dst, GEN_INT (15)); + set = gen_rtx_SET (HImode, dst, shift); + emit_insn (set); + return 1; + } + + if (operands[0] != operands[1]) + dst = copy_to_mode_reg (HImode, operands[1]); + else + dst = operands[1]; + + if (x >= 8) + { + rtx dlo = gen_lowpart (QImode, dst); + emit_insn (gen_swpb (dst, dst)); + emit_insn (gen_zero_extendqihi2 (dst, dlo)); + x -= 8; + } + + if (x) + { + shift = gen_rtx_LSHIFTRT (HImode, dst, const1_rtx); + set = gen_rtx_SET (HImode, dst, shift); + x--; + emit_insn (set); + } + shift = gen_rtx_ASHIFTRT (HImode, dst, const1_rtx); + set = gen_rtx_SET (HImode, dst, shift); + + while (x--) + emit_insn (set); + + if (dst != operands[0]) + emit_move_insn (operands[0], dst); + + return 1; +} + +int +msp430_lshrsi3 (operands) + rtx operands[]; +{ + int x; + rtx shift, set, dst; + + if (!const_int_operand (operands[2], VOIDmode)) + { + rtx op0, op1; + + op0 = force_reg (SImode, operands[0]); + op1 = force_reg (SImode, operands[1]); + operands[2] = copy_to_mode_reg (HImode, operands[2]); + emit_insn (gen_lshrsi3_cnt (op0, op1, operands[2])); + emit_move_insn (operands[0], op0); + return 1; + } + + x = INTVAL (operands[2]); + + if (x == 0) + { + emit_move_insn (operands[0], operands[1]); + return 1; + } + + if (x == 1) + { + emit_move_insn (operands[0], operands[1]); + dst = operands[0]; + shift = gen_rtx_LSHIFTRT (SImode, dst, operands[2]); + set = gen_rtx_SET (SImode, dst, shift); + emit_insn (set); + return 1; + } + + if (x > 31 || x < 0) + { + emit_move_insn (operands[0], const0_rtx); + return 1; + } + + if (operands[0] != operands[1]) + dst = copy_to_mode_reg (SImode, operands[1]); + else + dst = operands[1]; + + if (x >= 16) + { + rtx dlo = gen_lowpart (HImode, operands[0]); + rtx shi = gen_highpart (HImode, dst); + + emit_move_insn (gen_highpart (HImode, operands[0]), const0_rtx); + emit_insn (gen_zero_extendhisi2 (operands[0], shi)); + x -= 16; + if (x) + { + rtx ops[3]; + ops[0] = dlo; + ops[1] = dlo; + ops[2] = GEN_INT (x); + msp430_lshrhi3 (ops); + } + return 1; + } + + if (x >= 8) + { + shift = gen_rtx_LSHIFTRT (SImode, dst, GEN_INT (8)); + set = gen_rtx_SET (SImode, dst, shift); + emit_insn (set); + x -= 8; + } + + if (x) + { + shift = gen_rtx_LSHIFTRT (SImode, dst, const1_rtx); + set = gen_rtx_SET (SImode, dst, shift); + emit_insn (set); + x--; + } + + shift = gen_rtx_ASHIFTRT (SImode, dst, GEN_INT (1)); + set = gen_rtx_SET (SImode, dst, shift); + + while (x--) + emit_insn (set); + if (dst != operands[0]) + emit_move_insn (operands[0], dst); + return 1; +} + +/******* COMMON SHIFT CODE ***************/ +int +is_shift_better_in_reg (operands) + rtx operands[]; +{ + rtx x = operands[0]; + rtx cnt = operands[2]; + int size = GET_MODE_SIZE (x->mode); + int icnt = -1; + int r = 0; + + if (!optimize) + return 0; + + if (GET_CODE (cnt) == CONST_INT) + icnt = INTVAL (cnt); + else + return 1; + + switch (size) + { + case 1: + if (icnt != 1 && icnt != 2 && icnt != 7) + r = 1; + break; + case 2: + if (icnt != 1 && icnt != 2 && icnt != 8 && icnt != 15) + r = 2; + break; + case 4: + if (icnt != 1 + && icnt != 2 && icnt != 8 && icnt != 16 && icnt != 24 && icnt != 31) + r = 4; + break; + case 8: + if (icnt != 1 + && icnt != 2 && icnt != 16 && icnt != 32 && icnt != 48 && icnt != 63) + r = 8; + break; + } + + return r; +} + + +static int set_len PARAMS ((rtx, int, int)); +/* for const operand2 and for SI, DI modes.*/ +static int +set_len (x, bl, sc) + rtx x; /* operand0 */ + int bl; /* base length in assumption of memory operand */ + int sc; /* shift count */ +{ + int dummy; + int zs = zero_shifted (x); + int size = GET_MODE_SIZE (x->mode); + int sshi = 0; + + if (size == 4) + sshi = 1; + else if (size == 8) + sshi = 2; + + if (size == 1) + size++; + + if (GET_CODE (x) == REG) + dummy = (bl >> 1) - sshi; /* bl / 2 is not fully correct */ + else if (zs) + dummy = bl - (size >> 1) + 1; + else if (indexed_location (x)) + dummy = bl - 1; + else + dummy = bl; + + return dummy * sc; +} + +static int set_ren PARAMS ((rtx, int, int)); +/* for const operand2 and for SI, DI modes.*/ +static int +set_ren (x, bl, sc) + rtx x; /* operand0 */ + int bl; /* base length in assumption of memory operand */ + int sc; /* shift count */ +{ + int dummy; + + bl *= sc; + if (GET_CODE (x) == REG) + dummy = bl / 2; + else if (indexed_location (x)) + dummy = bl - sc; + else + dummy = bl; + return dummy; +} + +static int set_rel PARAMS ((rtx, int, int)); +/* for const operand2 and for SI, DI modes.*/ +static int +set_rel (x, bl, sc) + rtx x; /* operand0 */ + int bl; /* base length in assumption of memory operand */ + int sc; /* shift count */ +{ + int dummy; + + bl *= sc; + if (GET_CODE (x) == REG) + dummy = bl / 2; + else if (indexed_location (x)) + dummy = bl - sc; + else + dummy = bl; + dummy += sc; + return dummy; +} + + + +#define INST_THRESHOLD 16 + +int +msp430_emit_shift_cnt (set_len_fun, pattern, insn, operands, len, lsc) + int (*set_len_fun) (rtx, int, int); + const char *pattern; + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; + int lsc; +{ + rtx op[10]; + int dummy = 0; + + op[0] = operands[0]; + op[1] = operands[1]; + op[2] = operands[2]; + op[3] = operands[3]; + + + OUT_INSN (len, "tst\t%2", op); + OUT_INSN (len, "jz\t.Lsend%=\n.Lsst%=:", op); + OUT_INSN (len, pattern, op); + OUT_INSN (len, "dec\t%2", op); + OUT_INSN (len, "jnz\t.Lsst%=\n.Lsend%=:", op); + dummy = (set_len_fun) (op[0], lsc, 1) + 4; + if (!REG_P (op[2]) && !indexed_location (op[2])) + dummy += 2; + + + if (len) + *len = dummy; + return 0; +} + + +/* <<<<<<<<<<<<< SHIFT LEFT CODE <<<<<<<<<<<<<<<<< */ + +const char * +msp430_emit_ashlqi3 (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + const char *pattern; + int shiftpos; + + if (zs) + pattern = "rla.b\t@%E0"; + else + pattern = "rla.b\t%A0"; + + if (GET_CODE (operands[2]) == CONST_INT) + { + shiftpos = INTVAL (operands[2]); + + switch (shiftpos) + { + default: + if (zs) + OUT_INSN (len, "clr.b\t@%E0", operands); + else + OUT_INSN (len, "clr.b\t%A0", operands); + dummy = 2; + if (REG_P (operands[0])) + dummy >>= 1; + break; + + case 0: /* paranoia setting */ + dummy = 0; + break; + + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_len (operands[0], 3, 1); + } + break; + + case 7: + if (zs) + { + OUT_INSN (len, "rra.b\t%0", operands); + OUT_INSN (len, "clr.b\t%0", operands); + OUT_INSN (len, "rrc.b\t%0", operands); + dummy = 5; + } + else + { + OUT_INSN (len, "rra.b\t%0", operands); + OUT_INSN (len, "clr.b\t%0", operands); + OUT_INSN (len, "rrc.b\t%0", operands); + dummy = 6; + if (REG_P (operands[0])) + dummy = 3; + } + + break; + } + + if (len) + *len = dummy; + return ""; + + } + else + { + msp430_emit_shift_cnt (set_len, pattern, insn, operands, len, 3); + } + + return ""; +} + + +const char * +msp430_emit_ashlhi3 (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs; + const char *pattern; + int shiftpos; + + zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + + if (zs) + pattern = "rla\t@%E0"; + else + pattern = "rla\t%A0"; + + if (GET_CODE (operands[2]) == CONST_INT) + { + shiftpos = INTVAL (operands[2]); + + switch (shiftpos) + { + case 0: /* paranoia setting */ + dummy = 0; + break; + + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_len (operands[0], 3, 1); + } + break; + + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + if (zs) + { + dummy = 3; + OUT_INSN (len, "and.b\t#0xffff, %A0", operands); + OUT_INSN (len, "swpb\t@%E0", operands); + } + else + { + dummy = 4; + OUT_INSN (len, "and.b\t#0xffff, %A0", operands); + OUT_INSN (len, "swpb\t%A0", operands); + if (REG_P (operands[0])) + dummy = 2; + } + + + shiftpos -= 8; + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_len (operands[0], 3, 1); + } + break; + + case 15: + if (zs) + { + OUT_INSN (len, "rra\t%0", operands); + OUT_INSN (len, "clr\t%0", operands); + OUT_INSN (len, "rrc\t%0", operands); + dummy = 5; + } + else + { + OUT_INSN (len, "rra\t%0", operands); + OUT_INSN (len, "clr\t%0", operands); + OUT_INSN (len, "rrc\t%0", operands); + dummy = 6; + if (REG_P (operands[0])) + dummy = 3; + } + + break; + + + default: + + OUT_INSN (len, "clr\t%A0", operands); + dummy = 2; + if (REG_P (operands[0])) + dummy = 1; + break; + } + + if (len) + *len = dummy; + return ""; + } + else + { + msp430_emit_shift_cnt (set_len, pattern, insn, operands, len, 3); + } + + return ""; +} + + +const char * +msp430_emit_ashlsi3 (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + + int dummy = 0; + int zs; + const char *pattern; + + zs = zero_shifted (operands[0]); + + if (zs) + pattern = "add\t@%E0+, -2(%E0)\n\taddc\t@%E0+, -2(%E0)\n\tsub\t#4, %E0"; + else + pattern = "rla\t%A0\n\trlc\t%B0"; + + + if (GET_CODE (operands[2]) == CONST_INT) + { + int shiftpos = INTVAL (operands[2]); + + switch (shiftpos) + { + + case 0: + dummy = 0; + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_len (operands[0], 6, 1); + } + break; + + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + + if (zs || indexed_location (operands[0])) + { + OUT_INSN (len, "xor.b\t@%E0, %B0", operands); + OUT_INSN (len, "xor\t@%E0, %B0", operands); + OUT_INSN (len, "swpb\t%B0", operands); + OUT_INSN (len, "and.b\t#-1, %A0", operands); + OUT_INSN (len, "swpb\t@%E0", operands); + dummy = 9; + } + else + { + OUT_INSN (len, "xor.b\t%A0, %B0", operands); + OUT_INSN (len, "xor\t%A0, %B0", operands); + OUT_INSN (len, "swpb\t%B0", operands); + OUT_INSN (len, "and.b\t#-1, %A0", operands); + OUT_INSN (len, "swpb\t%A0", operands); + dummy = 12; + if (REG_P (operands[0])) + dummy = 5; + } + + shiftpos -= 8; + + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_len (operands[0], 6, 1); + } + + if (len) + *len = dummy; + return ""; + + break; + + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + + if (zs || indexed_location (operands[0])) + { + OUT_INSN (len, "mov\t@%E0, %B0", operands); + OUT_INSN (len, "clr\t%A0", operands); + dummy = 4; + } + else + { + OUT_INSN (len, "mov\t%A0, %B0", operands); + OUT_INSN (len, "clr\t%A0", operands); + dummy = 5; + if (REG_P (operands[0])) + dummy = 3; + } + + shiftpos -= 16; + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_len (operands[0], 6, 1); + } + + if (len) + *len = dummy; + return ""; + break; + + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + if (zs || indexed_location (operands[0])) + { + OUT_INSN (len, "mov.b\t@%E0,%B0", operands); + OUT_INSN (len, "swpb\t%B0", operands); + OUT_INSN (len, "clr\t@%E0", operands); + dummy = 6; + } + else + { + OUT_INSN (len, "mov.b\t%A0,%B0", operands); + OUT_INSN (len, "swpb\t%B0", operands); + OUT_INSN (len, "clr\t%A0", operands); + dummy = 8; + if (GET_CODE (operands[0]) == REG) + dummy = 3; + } + + shiftpos -= 24; + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_len (operands[0], 6, 1); + } + + if (len) + *len = dummy; + return ""; + + break; + + case 31: + if (zs || indexed_location (operands[0])) + { + OUT_INSN (len, "rra\t@%E0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "rrc\t%B0", operands); + dummy = 9; + + } + else + { + OUT_INSN (len, "rra\t%A0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "rrc\t%B0", operands); + dummy = 10; + if (REG_P (operands[0])) + dummy = 4; + } + + if (len) + *len = dummy; + return ""; + break; + + default: + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + if (len) + *len = set_len (operands[0], 6, 1); + return ""; + break; + + } /* switch */ + + if (len) + *len = dummy; + return ""; + } + else + msp430_emit_shift_cnt (set_len, pattern, insn, operands, len, 6); + + return ""; + +} + +const char * +msp430_emit_ashldi3 (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + + int dummy = 0; + int zs; + const char *pattern; + + zs = zero_shifted (operands[0]); + + if (zs) + pattern = + "add\t@%E0+,-2(%E0)\n\taddc\t@%E0+,-2(%E0)\n\taddc\t@%E0+,-2(%E0)\n\taddc\t@%E0+,-2(%E0)\n\tsub\t#8,%E0"; + else + pattern = "rla\t%A0\n\trlc\t%B0\n\trlc\t%C0\n\trlc\t%D0"; + + if (GET_CODE (operands[2]) == CONST_INT) + { + int shiftpos = INTVAL (operands[2]); + + switch (shiftpos) + { + case 0: + dummy = 0; + if (len) + *len = dummy; + break; + + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_len (operands[0], 12, 1); + } + if (len) + *len = dummy; + break; + + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + if (zs || indexed_location (operands[0])) + { + dummy = 10; + OUT_INSN (len, "mov\t%C0, %D0", operands); + OUT_INSN (len, "mov\t%B0, %C0", operands); + OUT_INSN (len, "mov\t@%E0, %B0", operands); + OUT_INSN (len, "clr\t@%E0", operands); + } + else + { + dummy = 11; + OUT_INSN (len, "mov\t%C0, %D0", operands); + OUT_INSN (len, "mov\t%B0, %C0", operands); + OUT_INSN (len, "mov\t%A0, %B0", operands); + OUT_INSN (len, "clr\t%A0", operands); + + } + if (GET_CODE (operands[0]) == REG) + dummy = 4; + shiftpos -= 16; + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_len (operands[0], 12, 1); + } + if (len) + *len = dummy; + break; + + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + if (zs) + { + dummy = 8; + OUT_INSN (len, "mov\t@%E0, %D0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%C0", operands); + + } + else + { + dummy = 9; + OUT_INSN (len, "mov\t%A0, %D0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%C0", operands); + } + if (GET_CODE (operands[0]) == REG) + dummy = 4; + + shiftpos -= 16; + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_len (operands[0], 12, 1); + } + + if (len) + *len = dummy; + break; + + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + + if (zs) + { + OUT_INSN (len, "mov\t@%E0+, %C0", operands); + OUT_INSN (len, "mov\t@%E0+, %D0", operands); + OUT_INSN (len, "sub\t#4, %E0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + dummy = 9; + } + else + { + dummy = 10; + OUT_INSN (len, "mov\t%A0, %C0", operands); + OUT_INSN (len, "mov\t%B0, %D0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + } + if (GET_CODE (operands[0]) == REG) + dummy = 4; + + shiftpos -= 32; + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_len (operands[0], 12, 1); + } + + if (len) + *len = dummy; + break; + + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 58: + case 59: + case 60: + case 61: + case 62: + if (zs) + { + dummy = 8; + OUT_INSN (len, "mov\t@%E0, %D0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%C0", operands); + } + else + { + dummy = 9; + OUT_INSN (len, "mov\t%A0, %D0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%C0", operands); + } + + shiftpos -= 48; + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_len (operands[0], 12, 1); + } + + if (GET_CODE (operands[0]) == REG) + dummy = 4; + if (len) + *len = dummy; + + break; + + case 63: + if (zs || indexed_location (operands[0])) + { + OUT_INSN (len, "rra\t@%E0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%C0", operands); + OUT_INSN (len, "clr\t%D0", operands); + OUT_INSN (len, "rrc\t%D0", operands); + dummy = 11; + } + else + { + OUT_INSN (len, "rra\t%A0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%C0", operands); + OUT_INSN (len, "clr\t%D0", operands); + OUT_INSN (len, "rrc\t%D0", operands); + dummy = 12; + if (REG_P (operands[0])) + dummy = 6; + } + + if (len) + *len = dummy; + + break; /* make compiler happy */ + + default: + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%C0", operands); + OUT_INSN (len, "clr\t%D0", operands); + dummy = 8; + if (zs) + dummy--; + if (REG_P (operands[0])) + dummy = 4; + + if (len) + *len = dummy; + + } /* switch */ + + return ""; + } + else + msp430_emit_shift_cnt (set_len, pattern, insn, operands, len, 12); + + return ""; /* make compiler happy */ +} + +/********* SHIFT RIGHT CODE ***************************************/ +const char * +msp430_emit_ashrqi3 (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + const char *pattern; + int shiftpos; + + if (zs) + pattern = "rra.b\t@%E0"; + else + pattern = "rra.b\t%A0"; + + if (GET_CODE (operands[2]) == CONST_INT) + { + + shiftpos = INTVAL (operands[2]); + + switch (shiftpos) + { + case 0: /* paranoia setting */ + dummy = 0; + break; + + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += 2; + } + break; + + case 7: + if (zs) + { + OUT_INSN (len, "sxt\t@%E0", operands); + OUT_INSN (len, "swpb\t@%E0", operands); + OUT_INSN (len, "and.b\t#-1, %A0", operands); + dummy = 4; + } + else + { + OUT_INSN (len, "sxt\t%A0", operands); + OUT_INSN (len, "swpb\t%A0", operands); + OUT_INSN (len, "and.b\t#-1, %A0", operands); + dummy = 6; + } + if (REG_P (operands[0])) + dummy = 3; + if (len) + *len = dummy; + return ""; + + break; + + default: + OUT_INSN (len, "clr.b\t%A0", operands); + dummy = 2; + if (REG_P (operands[0])) + dummy = 1; + } + + if (len) + *len = dummy; + return ""; + } + else + { + msp430_emit_shift_cnt (set_ren, pattern, insn, operands, len, 2); + } + + return ""; +} + +const char * +msp430_emit_ashrhi3 (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + const char *pattern; + int shiftpos; + + if (zs) + pattern = "rra\t@%E0"; + else + pattern = "rra\t%A0"; + + if (GET_CODE (operands[2]) == CONST_INT) + { + shiftpos = INTVAL (operands[2]); + + switch (shiftpos) + { + case 0: /* paranoia setting */ + dummy = 0; + break; + + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += 2; + } + if (zs || REG_P (operands[0])) + dummy >>= 1; + break; + + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + if (zs) + { + OUT_INSN (len, "swpb\t@%E0", operands); + OUT_INSN (len, "sxt\t@%E0", operands); + dummy = 2; + } + else + { + OUT_INSN (len, "swpb\t%A0", operands); + OUT_INSN (len, "sxt\t%A0", operands); + dummy = 4; + if (REG_P (operands[0])) + dummy = 2; + } + shiftpos -= 8; + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += (zs || REG_P (operands[0])) ? 1 : 2; + } + break; + + case 15: + if (zs) + { + OUT_INSN (len, "swpb\t@%E0", operands); + OUT_INSN (len, "sxt\t@%E0", operands); + OUT_INSN (len, "swpb\t@%E0", operands); + OUT_INSN (len, "swpb\t@%E0", operands); + dummy = 4; + } + else + { + OUT_INSN (len, "swpb\t%A0", operands); + OUT_INSN (len, "sxt\t%A0", operands); + OUT_INSN (len, "swpb\t%A0", operands); + OUT_INSN (len, "sxt\t%A0", operands); + dummy = 8; + } + if (REG_P (operands[0])) + dummy = 4; + break; + + default: + OUT_INSN (len, "clr\t%A0", operands); + dummy = 2; + if (REG_P (operands[0])) + dummy = 1; + } + + if (len) + *len = dummy; + return ""; + } + else + { + msp430_emit_shift_cnt (set_ren, pattern, insn, operands, len, 2); + } + + return ""; +} + +const char * +msp430_emit_ashrsi3 (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + + int dummy = 0; + const char *pattern; + int zs = zero_shifted (operands[0]); + + pattern = "rra\t%B0\n\trrc\t%A0"; + + if (GET_CODE (operands[2]) == CONST_INT) + { + int shiftpos = INTVAL (operands[2]); + + switch (shiftpos) + { + case 0: + dummy = 0; + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_ren (operands[0], 4, 1); + } + break; + + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + OUT_INSN (len, "swpb\t%A0", operands); + OUT_INSN (len, "swpb\t%B0", operands); + OUT_INSN (len, "xor.b\t%B0, %A0", operands); + OUT_INSN (len, "xor\t%B0, %A0", operands); + OUT_INSN (len, "sxt\t%B0", operands); + dummy = 12; + + if (REG_P (operands[0])) + dummy = 5; + shiftpos -= 8; + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_ren (operands[0], 4, 1); + } + break; + + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + OUT_INSN (len, "mov\t%B0, %A0", operands); + OUT_INSN (len, "bit\t#0x8000, %B0", operands); + OUT_INSN (len, "jz\t.Lsrc%=", operands); + OUT_INSN (len, "bis\t#0xffff, %B0", operands); + OUT_INSN (len, "jmp\t.Lsre%=\n.Lsrc%=:", operands); + OUT_INSN (len, "clr\t%B0\n.Lsre%=:", operands); + dummy = 12; + + if (GET_CODE (operands[0]) == REG) + dummy = 7; + + shiftpos -= 16; + while (shiftpos--) + { + OUT_INSN (len, "rra\t%A0", operands); + dummy += 2; + if (GET_CODE (operands[0]) == REG || zs) + dummy--; + } + + break; + + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + OUT_INSN (len, "swpb\t%B0", operands); + OUT_INSN (len, "sxt\t%B0", operands); + OUT_INSN (len, "mov\t%B0, %A0", operands); + OUT_INSN (len, "swpb\t%B0", operands); + OUT_INSN (len, "sxt\t%B0", operands); + dummy = 11; + + if (GET_CODE (operands[0]) == REG) + dummy = 5; + + shiftpos -= 24; + while (shiftpos--) + { + OUT_INSN (len, "rra\t%A0", operands); + dummy += 2; + if (GET_CODE (operands[0]) == REG || zs) + dummy--; + } + break; + + case 31: + OUT_INSN (len, "tst\t%B0", operands); + OUT_INSN (len, "mov\t#-1,%B0", operands); + OUT_INSN (len, "mov\t#-1,%A0", operands); + if (GET_CODE (operands[0]) == REG) + OUT_INSN (len, "jn\t+4", operands); + else + OUT_INSN (len, "jn\t+8", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + dummy = 11; + if (GET_CODE (operands[0]) == REG) + dummy = 6; + break; + + default: + dummy = 0; /* leave it alone!!! */ + break; + + } /* switch */ + + if (len) + *len = dummy; + return ""; + } + else + msp430_emit_shift_cnt (set_ren, pattern, insn, operands, len, 4); + + return ""; + +} + +const char * +msp430_emit_ashrdi3 (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + + int dummy = 0; + const char *pattern; + + pattern = "rra\t%D0\n\trrc\t%C0\n\trrc\t%B0\n\trrc\t%A0"; + + if (GET_CODE (operands[2]) == CONST_INT) + { + int shiftpos = INTVAL (operands[2]); + + switch (shiftpos) + { + case 0: + dummy = 0; + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + while (shiftpos--) + { + OUT_INSN (len, pattern, operands); + dummy += set_ren (operands[0], 8, 1); + } + break; + + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + + OUT_INSN (len, "mov\t%B0, %A0", operands); + OUT_INSN (len, "mov\t%C0, %B0", operands); + OUT_INSN (len, "mov\t%D0, %C0", operands); + OUT_INSN (len, "swpb\t%D0", operands); + OUT_INSN (len, "sxt\t%D0", operands); + OUT_INSN (len, "swpb\t%D0", operands); + OUT_INSN (len, "sxt\t%D0", operands); + + dummy = 17; + if (GET_CODE (operands[0]) == REG) + dummy = 7; + shiftpos -= 16; + while (shiftpos--) + { + OUT_INSN (len, "rra\t%C0\n\trrc\t%B0\n\trrc\t%A0", operands); + dummy += set_ren (operands[0], 6, 1); + } + + break; + + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + OUT_INSN (len, "mov\t%C0, %A0", operands); + OUT_INSN (len, "mov\t%D0, %B0", operands); + OUT_INSN (len, "swpb\t%D0", operands); + OUT_INSN (len, "sxt\t%D0", operands); + OUT_INSN (len, "swpb\t%D0", operands); + OUT_INSN (len, "sxt\t%D0", operands); + OUT_INSN (len, "mov\t%D0, %C0", operands); + dummy = 17; + if (GET_CODE (operands[0]) == REG) + dummy = 8; + shiftpos -= 32; + while (shiftpos--) + { + OUT_INSN (len, "rra\t%B0\n\trrc\t%A0", operands); + dummy += set_ren (operands[0], 4, 1); + } + break; + + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 58: + case 59: + case 60: + case 61: + case 62: + OUT_INSN (len, "mov\t%D0, %A0", operands); + OUT_INSN (len, "swpb\t%D0", operands); + OUT_INSN (len, "sxt\t%D0", operands); + OUT_INSN (len, "swpb\t%D0", operands); + OUT_INSN (len, "sxt\t%D0", operands); + OUT_INSN (len, "mov\t%D0, %C0", operands); + OUT_INSN (len, "mov\t%D0, %B0", operands); + dummy = 17; + if (GET_CODE (operands[0]) == REG) + dummy = 7; + shiftpos -= 48; + while (shiftpos--) + { + OUT_INSN (len, "rra\t%A0", operands); + dummy += set_ren (operands[0], 2, 1); + } + break; + + case 63: + OUT_INSN (len, "swpb\t%D0", operands); + OUT_INSN (len, "sxt\t%D0", operands); + OUT_INSN (len, "swpb\t%D0", operands); + OUT_INSN (len, "sxt\t%D0", operands); + OUT_INSN (len, "mov\t%D0, %C0", operands); + OUT_INSN (len, "mov\t%D0, %B0", operands); + OUT_INSN (len, "mov\t%D0, %A0", operands); + dummy = 17; + if (GET_CODE (operands[0]) == REG) + dummy = 7; + break; + + default: + dummy = 0; + + } /* case */ + + if (len) + *len = dummy; + return ""; + } + else + msp430_emit_shift_cnt (set_ren, pattern, insn, operands, len, 8); + return ""; +} + +/********* LOGICAL SHIFT RIGHT CODE ***************************************/ +const char * +msp430_emit_lshrqi3 (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + const char *pattern; + const char *second_pat; + int shiftpos; + + if (zs) + { + pattern = "clrc\n\trrc.b\t@%E0"; + second_pat = "rra.b\t@%E0"; + } + else + { + pattern = "clrc\n\trrc.b\t%A0"; + second_pat = "rra.b\t%A0"; + } + + if (GET_CODE (operands[2]) == CONST_INT) + { + + shiftpos = INTVAL (operands[2]); + + if (shiftpos != 7 && shiftpos) + { + OUT_INSN (len, pattern, operands); + dummy += set_rel (operands[0], 2, 1); + shiftpos--; + } + + switch (shiftpos) + { + case 0: + break; + + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + + while (shiftpos--) + { + OUT_INSN (len, second_pat, operands); + dummy += set_rel (operands[0], 2, 1) - 1; + } + + break; + + case 7: + if (zs) + { + OUT_INSN (len, "rla.b\t@%E0", operands); + OUT_INSN (len, "clr.b\t%A0", operands); + OUT_INSN (len, "rlc.b\t@%E0", operands); + dummy = 4; + } + else + { + OUT_INSN (len, "rla.b\t%A0", operands); + OUT_INSN (len, "clr.b\t%A0", operands); + OUT_INSN (len, "rlc.b\t%A0", operands); + dummy = 6; + } + if (REG_P (operands[0])) + dummy = 3; + break; + + default: + OUT_INSN (len, "clr.b\t%A0", operands); + dummy = 2; + if (REG_P (operands[0])) + dummy = 1; + break; + } + + if (len) + *len = dummy; + } + else + { + msp430_emit_shift_cnt (set_rel, pattern, insn, operands, len, 2); + } + + return ""; +} + +const char * +msp430_emit_lshrhi3 (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + int dummy = 0; + int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + const char *pattern; + const char *second_pat; + int shiftpos; + + if (zs) + { + pattern = "clrc\n\trrc\t@%E0"; + second_pat = "rra\t@%E0"; + } + else + { + pattern = "clrc\n\trrc\t%A0"; + second_pat = "rra\t%A0"; + } + + if (GET_CODE (operands[2]) == CONST_INT) + { + shiftpos = INTVAL (operands[2]); + + if (shiftpos < 8 && shiftpos) + { + OUT_INSN (len, pattern, operands); + dummy += set_rel (operands[0], 2, 1); + shiftpos--; + } + + switch (shiftpos) + { + case 0: + break; + + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + + while (shiftpos--) + { + OUT_INSN (len, second_pat, operands); + dummy += set_rel (operands[0], 2, 1) - 1; + } + + break; + + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + + if (zs) + { + OUT_INSN (len, "swpb\t@%E0", operands); + OUT_INSN (len, "and.b\t#-1, %A0", operands); + dummy = 3; + } + else + { + OUT_INSN (len, "swpb\t%A0", operands); + OUT_INSN (len, "and.b\t#-1, %A0", operands); + dummy = 4; + } + if (REG_P (operands[0])) + dummy = 2; + shiftpos -= 8; + while (shiftpos--) + { + OUT_INSN (len, second_pat, operands); + dummy += set_rel (operands[0], 2, 1) - 1; + } + break; + + case 15: + + if (zs) + { + OUT_INSN (len, "rla\t@%E0", operands); + OUT_INSN (len, "clr\t@%E0", operands); + OUT_INSN (len, "rlc\t@%E0", operands); + dummy = 3; + } + else + { + OUT_INSN (len, "rla\t%A0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "rlc\t%A0", operands); + dummy = 6; + } + if (REG_P (operands[0])) + dummy = 3; + break; + + default: + OUT_INSN (len, "clr\t%A0", operands); + dummy = 2; + if (REG_P (operands[0])) + dummy = 1; + break; + } + + if (len) + *len = dummy; + return ""; + } + else + { + msp430_emit_shift_cnt (set_rel, pattern, insn, operands, len, 2); + } + + return ""; + +} + +const char * +msp430_emit_lshrsi3 (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + const char *pattern; + int dummy = 0; + int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + const char *second_pat = "rra\t%B0\n\trrc\t%A0"; + + pattern = "clrc\n\trrc\t%B0\n\trrc\t%A0"; + + if (GET_CODE (operands[2]) == CONST_INT) + { + int shiftpos = INTVAL (operands[2]); + + if (shiftpos < 8 && shiftpos) + { + OUT_INSN (len, pattern, operands); + /* This function was underestimating the length by 1 for shifts from + 1 to 7. I added one here - Max */ + dummy += set_rel (operands[0], 2, 1) + 1; + shiftpos--; + } + + switch (shiftpos) + { + case 0: + break; + + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + while (shiftpos--) + { + OUT_INSN (len, second_pat, operands); + dummy += set_rel (operands[0], 4, 1) - 1; + } + + break; + + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + OUT_INSN (len, "swpb\t%A0", operands); + OUT_INSN (len, "swpb\t%B0", operands); + OUT_INSN (len, "xor.b\t%B0, %A0", operands); + OUT_INSN (len, "xor\t%B0, %A0", operands); + OUT_INSN (len, "and.b\t#-1, %B0", operands); + dummy = 12; + + if (REG_P (operands[0])) + dummy = 5; + shiftpos -= 8; + while (shiftpos--) + { + OUT_INSN (len, second_pat, operands); + dummy += set_rel (operands[0], 4, 1) - 1; + } + break; + + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + OUT_INSN (len, "mov\t%B0, %A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + dummy = 5; + if (REG_P (operands[0])) + dummy = 2; + + shiftpos -= 16; + if (shiftpos) + { + OUT_INSN (len, "clrc\n\trrc\t%A0", operands); + dummy += 2; + if (!zs && !REG_P (operands[0])) + dummy++; + shiftpos--; + } + + while (shiftpos--) + { + OUT_INSN (len, "rra\t%A0", operands); + dummy += 1; + if (!zs && !REG_P (operands[0])) + dummy++; + } + break; + + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + OUT_INSN (len, "mov\t%B0, %A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "swpb\t%A0", operands); + OUT_INSN (len, "and.b\t#-1, %A0", operands); + dummy = 9; + if (REG_P (operands[0])) + dummy = 4; + if (indexed_location (operands[0])) + dummy -= 1; + shiftpos -= 24; + + while (shiftpos--) + { + OUT_INSN (len, "rra\t%A0", operands); + dummy += 1; + if (!zs && !REG_P (operands[0])) + dummy++; + } + break; + + case 31: + OUT_INSN (len, "rla\r%B0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "rlc\t%A0", operands); + dummy = 8; + if (REG_P (operands[0])) + dummy = 4; + if (indexed_location (operands[0])) + dummy -= 1; + break; + + default: + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%A0", operands); + dummy = 4; + if (REG_P (operands[0])) + dummy = 2; + break; + + } /* switch */ + + if (len) + *len = dummy; + return ""; + } + else + msp430_emit_shift_cnt (set_rel, pattern, insn, operands, len, 4); + + return ""; +} + +const char * +msp430_emit_lshrdi3 (insn, operands, len) + rtx insn; + rtx operands[]; + int *len; +{ + int dummy = 0; + const char *pattern; + int zs = zero_shifted (operands[0]) || indexed_location (operands[0]); + const char *secondary_pat = "rra\t%D0\n\trrc\t%C0\n\trrc\t%B0\n\trrc\t%A0"; + + pattern = "clrc\n\trrc\t%D0\n\trrc\t%C0\n\trrc\t%B0\n\trrc\t%A0"; + + if (GET_CODE (operands[2]) == CONST_INT) + { + int shiftpos = INTVAL (operands[2]); + + if (shiftpos < 16 && shiftpos) + { + OUT_INSN (len, pattern, operands); + dummy += set_rel (operands[0], 2, 1); + shiftpos--; + } + + switch (shiftpos) + { + case 0: + break; + + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + while (shiftpos--) + { + OUT_INSN (len, secondary_pat, operands); + dummy += set_rel (operands[0], 8, 1) - 1; + } + + break; + + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + OUT_INSN (len, "mov\t%B0, %A0", operands); + OUT_INSN (len, "mov\t%C0, %B0", operands); + OUT_INSN (len, "mov\t%D0, %C0", operands); + OUT_INSN (len, "clr\t%D0", operands); + dummy = 11; + if (REG_P (operands[0])) + dummy = 4; + shiftpos -= 16; + + if (shiftpos) + { + OUT_INSN (len, secondary_pat, operands); + dummy += set_rel (operands[0], 8, 1) - 1; + shiftpos--; + } + + while (shiftpos--) + { + OUT_INSN (len, "rra\t%C0\n\trrc\t%B0\n\trrc\t%A0", operands); + if (REG_P (operands[0])) + dummy = 3; + else + dummy += 6; + if (zs) + dummy--; + } + + break; + + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + OUT_INSN (len, "mov\t%C0, %A0", operands); + OUT_INSN (len, "mov\t%D0, %B0", operands); + OUT_INSN (len, "clr\t%C0", operands); + OUT_INSN (len, "clr\t%D0", operands); + + dummy = 10; + if (GET_CODE (operands[0]) == REG) + dummy = 4; + + shiftpos -= 32; + + if (shiftpos) + { + OUT_INSN (len, "clrc\n\trrc\t%B0,rrc\t%A0", operands); + if (REG_P (operands[0])) + dummy += 3; + else + dummy += 5; + if (zs) + dummy--; + shiftpos--; + } + + while (shiftpos--) + { + OUT_INSN (len, "rra\t%B0,rrc\t%A0", operands); + if (REG_P (operands[0])) + dummy += 2; + else + dummy += 4; + if (zs) + dummy--; + } + break; + + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 58: + case 59: + case 60: + case 61: + case 62: + OUT_INSN (len, "mov\t%D0, %A0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%C0", operands); + OUT_INSN (len, "clr\t%D0", operands); + dummy = 9; + if (GET_CODE (operands[0]) == REG) + dummy = 4; + shiftpos -= 48; + + if (shiftpos) + { + OUT_INSN (len, "clrc\n\trrc\t%A0", operands); + if (REG_P (operands[0]) || zs) + dummy += 2; + else + dummy += 3; + + shiftpos--; + } + + while (shiftpos--) + { + OUT_INSN (len, "rra\t%A0", operands); + if (REG_P (operands[0]) || zs) + dummy++; + else + dummy += 2; + } + break; + + case 63: + + OUT_INSN (len, "rla\t%D0", operands); + OUT_INSN (len, "clr\t%D0", operands); + OUT_INSN (len, "clr\t%C0", operands); + OUT_INSN (len, "clr\t%B0", operands); + OUT_INSN (len, "clr\t%A0", operands); + OUT_INSN (len, "rlc\t%A0", operands); + if (REG_P (operands[0])) + dummy += 6; + else + dummy += 13; + + if (zs) + dummy--; + break; + + default: + break; + } /* case */ + + if (len) + *len = dummy; + } + else + msp430_emit_shift_cnt (set_rel, pattern, insn, operands, len, 8); + + return ""; +} + +/* + * Multiplication helpers + * 1. As shifts, 2. the rest + */ + +#define SOME_SHIFT_THRESHOLD_VAL 10 + +int +msp430_easy_mul (operands, sext) + rtx operands[]; + int sext; +{ + enum machine_mode op0mode = GET_MODE (operands[0]); + enum machine_mode op1mode = GET_MODE (operands[1]); + rtx op0 = operands[0]; + rtx op1 = operands[1]; + rtx insn; + int m = INTVAL (operands[2]); + int sign = (m < 0); + int val = (m > 0 ? m : -m); + int shift1 = 0, shift0 = 0; + int add1 = 0, sub1 = 0; + int t0, t1; + int ops = 0; + + m = val; + /* + we can do: + const == single bit const +- N that (shift0 + add1/sub1 < 8 instructions) + */ + shift0 = 1; + shift1 = 0; + + for (t0 = 2; + t0 <= val * 2 && shift0 < GET_MODE_SIZE (op0mode) * BITS_PER_UNIT; + t0 <<= 1) + { + if (t0 == val) + goto done; + + for (t1 = 1; t1 < t0 && shift1 < GET_MODE_SIZE (op1mode) * BITS_PER_UNIT; + t1 <<= 1) + { + add1 = 0; + sub1 = 0; + if (t0 + t1 == m) + { + add1 = 1; + goto done; + } + if (t0 - t1 == m) + { + sub1 = 1; + goto done; + } + + if (t0 + t1 * 3 == m) + { + add1 = 3; + goto done; + } + + if (t0 - t1 * 3 == m) + { + sub1 = 3; + goto done; + } + + add1 = 0; + sub1 = 0; + shift1++; + + } + shift1 = 0; + shift0++; + } + + return 0; +done: + + ops = shift0 * (op0mode == SImode ? 2 : 1); + ops += shift1 + add1 + sub1; + if (op0mode != op1mode) + { + ops += (op0mode == SImode ? 2 : 1) * ((add1 || sub1) ? 2 : 1); + } + + if (ops > SOME_SHIFT_THRESHOLD_VAL) + return 0; + + if (op0mode != op1mode) + { + rtx extend; + if (sext) + extend = gen_rtx_SIGN_EXTEND (op0mode, op1); + else + extend = gen_rtx_ZERO_EXTEND (op0mode, op1); + insn = gen_rtx_SET (VOIDmode, op0, extend); + emit_insn (insn); + } + else + { + emit_move_insn (op0, op1); + } + + /* shift0 */ + switch (op0mode) + { + case QImode: + emit_insn (gen_ashlqi3 (op0, op0, GEN_INT (shift0))); + break; + case HImode: + emit_insn (gen_ashlhi3 (op0, op0, GEN_INT (shift0))); + break; + case SImode: + emit_insn (gen_ashlsi3 (op0, op0, GEN_INT (shift0))); + break; + case DImode: + emit_insn (gen_ashldi3 (op0, op0, GEN_INT (shift0))); + break; + default: + abort (); + } + + if (op0mode != op1mode && (add1 || sub1 || shift1)) + { + /* equalize operands modes */ + rtx extend; + rtx treg = gen_reg_rtx (op0mode); + + if (sext) + extend = gen_rtx_SIGN_EXTEND (op0mode, op1); + else + extend = gen_rtx_ZERO_EXTEND (op0mode, op1); + insn = gen_rtx_SET (VOIDmode, treg, extend); + emit_insn (insn); + op1 = treg; + op1mode = GET_MODE (treg); + } + else if (add1 || sub1 || shift1) + { + rtx treg = gen_reg_rtx (op0mode); + emit_move_insn (treg, op1); + op1 = treg; + } + + if (shift1 && (add1 || sub1)) + { + switch (op1mode) + { + case QImode: + emit_insn (gen_ashlqi3 (op1, op1, GEN_INT (shift1))); + break; + case HImode: + emit_insn (gen_ashlhi3 (op1, op1, GEN_INT (shift1))); + break; + case SImode: + emit_insn (gen_ashlsi3 (op1, op1, GEN_INT (shift1))); + break; + case DImode: + emit_insn (gen_ashldi3 (op1, op1, GEN_INT (shift1))); + break; + default: + abort (); + } + } + else if (shift1) + abort (); /* paranoia */ + + while (add1--) + { + insn = + gen_rtx_SET (VOIDmode, op0, gen_rtx_PLUS (GET_MODE (op0), op0, op1)); + emit_insn (insn); + } + + while (sub1--) + { + insn = + gen_rtx_SET (VOIDmode, op0, + gen_rtx_MINUS (GET_MODE (op0), op0, op1)); + emit_insn (insn); + } + + if (sign) + { + switch (op0mode) + { + case QImode: + emit_insn (gen_negqi2 (op0, op0)); + break; + case HImode: + emit_insn (gen_neghi2 (op0, op0)); + break; + case SImode: + emit_insn (gen_negsi2 (op0, op0)); + break; + case DImode: + emit_insn (gen_negdi2 (op0, op0)); + break; + default: + abort (); + } + } + + return 1; +} + +/* multiplication guards */ +#define LOAD_MPY(x) \ +do{ \ + if(GET_MODE(x) == QImode) \ + emit_insn(gen_load_mpyq(x)); \ + else \ + emit_insn(gen_load_mpy(x)); \ +}while(0) + +#define LOAD_MPYS(x) \ +do{ \ + if(GET_MODE(x) == QImode) \ + emit_insn(gen_load_mpysq(x)); \ + else \ + emit_insn(gen_load_mpys(x)); \ +}while(0) + +#define LOAD_OP2(x) \ +do{ \ + if(GET_MODE(x) == QImode) \ + emit_insn(gen_load_op2q(x)); \ + else \ + emit_insn(gen_load_op2(x)); \ +}while(0) + +int +msp430_mul3_guard (operands, sext) + rtx operands[]; + int sext; +{ + rtx m_mpys = mpys_rtx; + rtx m_op2 = op2_rtx; + rtx m_reslo = reslo_rtx; + enum machine_mode op0mode = GET_MODE (operands[0]); + enum machine_mode op1mode = GET_MODE (operands[1]); + rtx r12 = gen_rtx_REG (op1mode, 12); + rtx r10 = gen_rtx_REG (op1mode, 10); + rtx r14 = gen_rtx_REG (op0mode, 14); + + if (const_int_operand (operands[2], VOIDmode) && + msp430_easy_mul (operands, sext)) + return 1; + + if (!msp430_has_hwmul) + { + rtx clob1 = gen_rtx_CLOBBER (VOIDmode, r10); + rtx clob2 = gen_rtx_CLOBBER (VOIDmode, r12); + rtx set; + rtx mult, op1, op2; + rtvec vec; + /* prepare 'call' pattern */ + if (sext==1) + { + op1 = gen_rtx_SIGN_EXTEND (op0mode, r10); + op2 = gen_rtx_SIGN_EXTEND (op0mode, r12); + } + else + { + op1 = r10; + op2 = r12; + } + mult = gen_rtx_MULT (op0mode, op1, op2); + set = gen_rtx_SET (op0mode, r14, mult); + vec = gen_rtvec (3, set, clob1, clob2); + + emit_move_insn (r10, operands[1]); + emit_move_insn (r12, operands[2]); + emit (gen_rtx_PARALLEL (VOIDmode, vec)); + emit_move_insn (operands[0], r14); + return 1; + } + if (op1mode == QImode) + { + m_mpys = gen_lowpart (QImode, mpys_rtx); + m_op2 = gen_lowpart (QImode, op2_rtx); + } + + if (op0mode == QImode) + m_reslo = gen_lowpart (QImode, reslo_rtx); + + if (!MSP430_NOINT_HWMUL) + emit_insn (gen_reent_in ()); + + LOAD_MPYS (operands[1]); + if (sext) + emit_insn (gen_extendqihi2 (mpys_rtx, m_mpys)); + LOAD_OP2 (operands[2]); + if (sext) + emit_insn (gen_extendqihi2 (op2_rtx, m_op2)); + + if (MSP430_NOINT_HWMUL) + { + if (op0mode == HImode) + emit_insn (gen_fetch_result_hi_nint (operands[0])); + else + emit_insn (gen_fetch_result_qi_nint (operands[0])); + } + else + { + if (op0mode == HImode) + emit_insn (gen_fetch_result_hi (operands[0])); + else + emit_insn (gen_fetch_result_qi (operands[0])); + } + + return 1; +} + + +int +msp430_umul3_guard (operands, sext) + rtx operands[]; + int sext ATTRIBUTE_UNUSED; +{ + rtx m_mpy = mpy_rtx; + rtx m_op2 = op2_rtx; + enum machine_mode op0mode = GET_MODE (operands[0]); + enum machine_mode op1mode = GET_MODE (operands[1]); + rtx r12 = gen_rtx_REG (op1mode, 12); + rtx r10 = gen_rtx_REG (op1mode, 10); + rtx r14 = gen_rtx_REG (op0mode, 14); + + if (const_int_operand (operands[2], VOIDmode) && + msp430_easy_mul (operands, 0)) + return 1; + + if (!msp430_has_hwmul) + { + rtx clob1 = gen_rtx_CLOBBER (VOIDmode, r10); + rtx clob2 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (op1mode, 12)); + rtx set; + rtx mult, op1, op2; + rtvec vec; + /* prepare 'call' pattern */ + op1 = gen_rtx_ZERO_EXTEND (op0mode, r10); + op2 = gen_rtx_ZERO_EXTEND (op0mode, r12); + + mult = gen_rtx_MULT (op0mode, op1, op2); + set = gen_rtx_SET (op0mode, r14, mult); + vec = gen_rtvec (3, set, clob1, clob2); + + emit_move_insn (r10, operands[1]); + emit_move_insn (r12, operands[2]); + emit (gen_rtx_PARALLEL (VOIDmode, vec)); + emit_move_insn (operands[0], r14); + return 1; + } + + m_mpy = gen_lowpart (QImode, mpy_rtx); + m_op2 = gen_lowpart (QImode, op2_rtx); + + if (!MSP430_NOINT_HWMUL) + emit_insn (gen_reent_in ()); + + LOAD_MPY (gen_lowpart (QImode,operands[1])); + //emit_insn (gen_zero_extendqihi2 (mpy_rtx, m_mpy)); + //LOAD_OP2 (gen_lowpart (QImode,operands[2])); + //emit_insn (gen_zero_extendqihi2 (op2_rtx, m_op2)); + emit_move_insn(m_op2, gen_lowpart (QImode,operands[2])); + + if (MSP430_NOINT_HWMUL) + emit_insn (gen_fetch_result_hi_nint (operands[0])); + else + emit_insn (gen_fetch_result_hi (operands[0])); + + return 1; +} + + +int +msp430_mulhisi_guard (operands) + rtx operands[]; +{ + enum machine_mode op0mode = GET_MODE (operands[0]); + enum machine_mode op1mode = GET_MODE (operands[1]); + rtx r12 = gen_rtx_REG (op1mode, 12); + rtx r10 = gen_rtx_REG (op1mode, 10); + rtx r14 = gen_rtx_REG (op0mode, 14); + rtx r11 = gen_rtx_REG (op1mode, 11); + rtx r13 = gen_rtx_REG (op1mode, 13); + + if (const_int_operand (operands[2], VOIDmode) && + msp430_easy_mul (operands, 1)) + return 1; + + if (!msp430_has_hwmul) + { + rtx clob1 = gen_rtx_CLOBBER (VOIDmode, r10); + rtx clob2 = gen_rtx_CLOBBER (VOIDmode, r11); + rtx clob3 = gen_rtx_CLOBBER (VOIDmode, r12); + rtx clob4 = gen_rtx_CLOBBER (VOIDmode, r13); + + rtx set; + rtx mult, op1, op2; + rtvec vec; + /* prepare 'call' pattern */ + op1 = gen_rtx_SIGN_EXTEND (op0mode, r10); + op2 = gen_rtx_SIGN_EXTEND (op0mode, r12); + + mult = gen_rtx_MULT (op0mode, op1, op2); + set = gen_rtx_SET (op0mode, r14, mult); + vec = gen_rtvec (5, set, clob1, clob2, clob3, clob4); + + emit_move_insn (r10, operands[1]); + emit_move_insn (r12, operands[2]); + emit (gen_rtx_PARALLEL (VOIDmode, vec)); + emit_move_insn (operands[0], r14); + return 1; + } + if (!MSP430_NOINT_HWMUL) + emit_insn (gen_reent_in ()); + + LOAD_MPYS (operands[1]); + LOAD_OP2 (operands[2]); + + if (MSP430_NOINT_HWMUL) + { + emit_insn (gen_fetch_result_si_nint (operands[0])); + } + else + emit_insn (gen_fetch_result_si (operands[0])); + + return 1; +} + + +int +msp430_umulhisi_guard (operands) + rtx operands[]; +{ + enum machine_mode op0mode = GET_MODE (operands[0]); + enum machine_mode op1mode = GET_MODE (operands[1]); + rtx r12 = gen_rtx_REG (op1mode, 12); + rtx r10 = gen_rtx_REG (op1mode, 10); + rtx r14 = gen_rtx_REG (op0mode, 14); + rtx r11 = gen_rtx_REG (op1mode, 11); + rtx r13 = gen_rtx_REG (op1mode, 13); + + if (const_int_operand (operands[2], VOIDmode) && + msp430_easy_mul (operands, 0)) + return 1; + + if (!msp430_has_hwmul) + { + rtx clob1 = gen_rtx_CLOBBER (VOIDmode, r10); + rtx clob2 = gen_rtx_CLOBBER (VOIDmode, r11); + rtx clob3 = gen_rtx_CLOBBER (VOIDmode, r12); + rtx clob4 = gen_rtx_CLOBBER (VOIDmode, r13); + + rtx set; + rtx mult, op1, op2; + rtvec vec; + /* prepare 'call' pattern */ + op1 = gen_rtx_ZERO_EXTEND (op0mode, r10); + op2 = gen_rtx_ZERO_EXTEND (op0mode, r12); + + mult = gen_rtx_MULT (op0mode, op1, op2); + set = gen_rtx_SET (op0mode, r14, mult); + vec = gen_rtvec (5, set, clob1, clob2, clob3, clob4); + + emit_move_insn (r10, operands[1]); + emit_move_insn (r12, operands[2]); + emit (gen_rtx_PARALLEL (VOIDmode, vec)); + emit_move_insn (operands[0], r14); + return 1; + } + + if (!MSP430_NOINT_HWMUL) + emit_insn (gen_reent_in ()); + + LOAD_MPY (operands[1]); + LOAD_OP2 (operands[2]); + + if (MSP430_NOINT_HWMUL) + { + emit_insn (gen_fetch_result_si_nint (operands[0])); + } + else + emit_insn (gen_fetch_result_si (operands[0])); + + return 1; +} + + +/* something like 'push x(r1)' or 'push @r1' */ +int +self_push (x) + rtx x; +{ + rtx c; + rtx r; + + if (GET_CODE (x) != MEM) + return 0; + + c = XEXP (x, 0); + + if (REG_P (c) && REGNO (c) == 1) + return 1; + + if (GET_CODE (c) == PLUS) + { + r = XEXP (c, 0); + if (REG_P (r) && REGNO (r) == 1) + return 1; + } + return 0; +} + +/* difficult pushes. + if planets are not aligned, the combiner does not allocate + r4 as a frame pointer. Instead, it uses stack pointer for frame. + If there is a va_arg call and non-register local var has to be passed + as a function parameter, the push X(r1) in SI, SF and DI modes will + corrupt passed var. The following minds this fact */ + + +const char * +msp430_pushqi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int sp = self_push (operands[0]); + int dummy = 0; + + if (sp) + { + rtx c; + c = XEXP (operands[0], 0); + if (REG_P (c)) + OUT_INSN (len, "push.b\t2(%E0)", operands); + else + OUT_INSN (len, "push.b\t2+%A0", operands); + dummy = 2; + } + else + { + OUT_INSN (len, "push.b\t%A0", operands); + dummy = 2; + + if (GET_CODE (operands[0]) == CONST_INT) + { + int cval = INTVAL (operands[0]); + int x = (cval) & 0x0fffful; + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 || x == 0xffff) + dummy--; + + } + else if (GET_CODE (operands[0]) == REG) + dummy--; + else if (GET_CODE (operands[0]) == MEM && REG_P (XEXP (operands[0], 0))) + dummy--; + } + + return ""; +} + +const char * +msp430_pushhi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int sp = self_push (operands[0]); + int dummy = 0; + + if (sp) + { + rtx c; + c = XEXP (operands[0], 0); + if (REG_P (c)) + OUT_INSN (len, "push\t2(%E0)", operands); + else + OUT_INSN (len, "push\t2+%A0", operands); + dummy = 2; + } + else + { + OUT_INSN (len, "push\t%A0", operands); + dummy = 2; + + if (GET_CODE (operands[0]) == CONST_INT) + { + int cval = INTVAL (operands[0]); + int x = (cval) & 0x0fffful; + + if (cval == 99999999) + { + if (len) + *len = 3; + return ""; + } + + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 || x == 0xffff) + dummy--; + + } + else if (GET_CODE (operands[0]) == REG) + dummy--; + else if (GET_CODE (operands[0]) == MEM && REG_P (XEXP (operands[0], 0))) + dummy--; + } + if (len) + *len = dummy; + return ""; +} + +const char * +msp430_pushsisf (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int sp = self_push (operands[0]); + int dummy = 0; + + if (!sp) + { + OUT_INSN (len, "push\t%B0", operands); + OUT_INSN (len, "push\t%A0", operands); + dummy = 4; + if (indexed_location (operands[0])) + dummy--; + if (REG_P (operands[0])) + dummy -= 2; + if (GET_CODE (operands[0]) == CONST_INT) + { + int cval = INTVAL (operands[0]); + int x = (cval) & 0x0fffful; + int y = (((unsigned long) (cval)) & 0xffff0000ul >> 16); + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 || x == 0xffff) + dummy--; + if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 || y == 0xffff) + dummy--; + } + else if (GET_CODE (operands[0]) == CONST_DOUBLE + && GET_MODE (operands[0]) == SFmode) + { + long val; + int y, x; + REAL_VALUE_TYPE rv; + REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[0]); + REAL_VALUE_TO_TARGET_SINGLE (rv, val); + + y = (val & 0xffff0000ul) >> 16; + x = val & 0xffff; + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 || x == 0xffff) + dummy--; + if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 || y == 0xffff) + dummy--; + } + } + else + { + OUT_INSN (len, "push\t2+%B0", operands); + OUT_INSN (len, "push\t2+%B0", operands); + dummy = 4; + } + + if (len) + *len = dummy; + + return ""; +} + + +const char * +msp430_pushdi (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[]; + int *len; +{ + int sp = self_push (operands[0]); + int dummy = 0; + + if (!sp) + { + OUT_INSN (len, "push\t%D0", operands); + OUT_INSN (len, "push\t%C0", operands); + OUT_INSN (len, "push\t%B0", operands); + OUT_INSN (len, "push\t%A0", operands); + + dummy = 8; + if (indexed_location (operands[0])) + dummy--; + if (REG_P (operands[0])) + dummy -= 4; + if (GET_CODE (operands[0]) == CONST_DOUBLE) + { + int hi = CONST_DOUBLE_HIGH (operands[0]); + int lo = CONST_DOUBLE_LOW (operands[0]); + int x, y, z; + + x = (hi & 0xffff0000ul) >> 16; + y = hi & 0xffff; + z = (lo & 0xffff0000ul) >> 16; + if (x == 0 || x == 1 || x == 2 || x == 4 || x == 8 || x == 0xffff) + dummy--; + if (y == 0 || y == 1 || y == 2 || y == 4 || y == 8 || y == 0xffff) + dummy--; + if (z == 0 || z == 1 || z == 2 || z == 4 || z == 8 || z == 0xffff) + dummy--; + z = lo & 0xffff; + if (z == 0 || z == 1 || z == 2 || z == 4 || z == 8 || z == 0xffff) + dummy--; + } + } + else + { + OUT_INSN (len, "push\t2+%D0", operands); + OUT_INSN (len, "push\t2+%D0", operands); + OUT_INSN (len, "push\t2+%D0", operands); + OUT_INSN (len, "push\t2+%D0", operands); + dummy = 8; + } + + if (len) + *len = dummy; + + return ""; +} + +int +dead_or_set_in_peep (which, insn, x) + int which; + rtx insn ATTRIBUTE_UNUSED; + rtx x; +{ + rtx r; + rtx next; + + next = peep2_next_insn (which); + if (!next) + return 0; + if (!REG_P (x)) + return 0; + r = find_regno_note (next, REG_DEAD, REGNO (x)); + + if (!r) + return 0; + + r = XEXP (r, 0); + return GET_MODE (r) == GET_MODE (x); +} + +void +msp430_trampoline_template (FILE * fd) +{ + fprintf (fd, "; TRAMPOLINE HERE\n" + "; move context (either r1 or r4) to r6\n" + "; call function (0xf0f0 will be changed)\n"); + fprintf (fd, "\tmov #0xf0f0, r6\n"); + fprintf (fd, "\tbr #0xf0f0\n"); + fprintf (fd, "; END OF TRAMPOLINE\n\n"); +} + +void +msp430_initialize_trampoline (tramp, fn, ctx) + rtx tramp; + rtx fn; + rtx ctx; +{ + emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), ctx); + emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 6)), fn); +} + +const char * +msp430_emit_return (insn, operands, len) + rtx insn ATTRIBUTE_UNUSED; + rtx operands[] ATTRIBUTE_UNUSED; + int *len ATTRIBUTE_UNUSED; +{ + return_issued = 1; + if (msp430_empty_epilogue () == 1) + return "ret"; + + return "reti"; +} + +int +three_operands_msp430 (x, mode) + rtx x; + enum machine_mode mode; +{ + enum rtx_code code = GET_CODE (x); + if (GET_MODE (x) != mode) + return 0; + + return (code == PLUS + || code == MINUS || code == AND || code == IOR || code == XOR); +} + +int +equality_operator (op, mode) + register rtx op; + enum machine_mode mode; +{ + return ((mode == VOIDmode || GET_MODE (op) == mode) + && (GET_CODE (op) == EQ || GET_CODE (op) == NE)); +} + +/* Return 1 if this is a comparison operator but not an EQ or NE operator. */ +int +inequality_operator (op, mode) + register rtx op; + enum machine_mode mode; +{ + return comparison_operator (op, mode) && !equality_operator (op, mode); +} diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/msp430.h gcc-3.2.3/gcc/config/msp430/msp430.h --- gcc-3.2.3.orig/gcc/config/msp430/msp430.h 1969-12-31 17:00:00.000000000 -0700 +++ gcc-3.2.3/gcc/config/msp430/msp430.h 2008-08-22 09:17:00.000000000 -0600 @@ -0,0 +1,3378 @@ + +/* Definitions of target machine for GNU compiler, + for Texas Instruments MSP430 microcontrollers. + Copyright (C) 2001 Free Software Foundation, Inc. + Contributed by Dmitry Diky + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Names to predefine in the preprocessor for this target machine. */ + +#define CPP_PREDEFINES "-DMSP430" +/* Define this to be a string constant containing `-D' options to + define the predefined macros that identify this machine and system. + These macros will be predefined unless the `-ansi' option is + specified. + + In addition, a parallel set of macros are predefined, whose names + are made by appending `__' at the beginning and at the end. These + `__' macros are permitted by the ANSI standard, so they are + predefined regardless of whether `-ansi' is specified. + + For example, on the Sun, one can use the following value: + + "-Dmc68000 -Dsun -Dunix" + + The result is to define the macros `__mc68000__', `__sun__' and + `__unix__' unconditionally, and the macros `mc68000', `sun' and + `unix' provided `-ansi' is not specified. */ + + +/* This declaration should be present. */ +/* +#include +*/ + +extern int target_flags; + +#define MASK_PROF_STD 0x00000001 +#define MASK_PROF_LIB 0x00000002 +#define MASK_PROF_STACK 0x00000004 + +#define MASK_RTL_DUMP 0x00000010 +#define MASK_ALL_DEBUG 0x00000FE0 +#define MASK_FORCE_HWMUL 0x00001000 +#define MASK_STRICT_ALIGN 0x00002000 +#define MASK_IAR 0x00004000 +#define MASK_NO_STACK_INIT 0x00008000 +#define MASK_NO_VOLAT_WRKAR 0x00010000 +#define MASK_REORDER 0x00020000 +#define MASK_INLINESIHWMUL 0x00040000 +#define MASK_NO_HWMUL 0x00100000 +#define MASK_NOINT_HWMUL 0x00200000 +#define MASK_SAVE_PROLOGUE 0x00400000 + + + +#define TARGET_PROF_STD (target_flags & MASK_PROF_STD) +#define TARGET_PROF_LIB (target_flags & MASK_PROF_LIB) +#define TARGET_PROF_STACK (target_flags & MASK_PROF_STACK) +#define TARGET_NO_HWMUL (target_flags & MASK_NO_HWMUL) +#define TARGET_HWMUL (target_flags & MASK_FORCE_HWMUL) +#define TARGET_NOINT_HWMUL (target_flags & MASK_NOINT_HWMUL) +#define TARGET_RTL_DUMP (target_flags & MASK_RTL_DUMP) +#define TARGET_ALL_DEBUG (target_flags & MASK_ALL_DEBUG) +#define TARGET_STRICT_ALIGN (target_flags & MASK_STRICT_ALIGN) +#define TARGET_IAR (target_flags & MASK_IAR) +#define TARGET_NSI (target_flags & MASK_NO_STACK_INIT) +#define TARGET_NVWA (target_flags & MASK_NO_VOLAT_WRKAR) +#define TARGET_REORDER (target_flags & MASK_REORDER) +#define TARGET_INLINESIHWMUL (target_flags & MASK_INLINESIHWMUL) +#define TARGET_SAVE_PROLOGUE (target_flags & MASK_SAVE_PROLOGUE) + + +#define TARGET_SWITCHES { \ + { "pgs", MASK_PROF_STD, N_("Add ordinary profile information")}, \ + { "pgl", MASK_PROF_LIB, N_("Add library profile information")}, \ + { "pgr", MASK_PROF_STACK,N_("Add stack information to profiler") }, \ + { "rtl", MASK_RTL_DUMP, NULL }, \ + { "deb", MASK_ALL_DEBUG, NULL }, \ + { "strict-align", MASK_STRICT_ALIGN,N_("Strict alignment for all structures") }, \ + { "force-hwmul", MASK_FORCE_HWMUL,N_("Force hardware multiplier") },\ + { "disable-hwmul", MASK_NO_HWMUL, N_("Disable hardware multiplier") }, \ + { "inline-hwmul", MASK_INLINESIHWMUL, N_("Issue inline multiplication code for 32-bit integers") }, \ + { "noint-hwmul", MASK_NOINT_HWMUL, ("Assume interrupt routine does not do hardware multiply")}, \ + { "IAR",MASK_IAR,N_("Produce IAR assembler syntax") }, \ + { "no-stack-init",MASK_NO_STACK_INIT,N_("No stack init in main()") }, \ + { "no-volatile-workaround",MASK_NO_STACK_INIT,N_("Do not perform volatile workaround for bitwise operations") }, \ + { "save-prologue",MASK_SAVE_PROLOGUE, ("Use subroutine call for function prologue/epilogue when possible")}, \ + { "", 0, NULL } \ +} + +extern const char *msp430_endup; +extern const char *msp430_init_stack; +extern const char *msp430_mcu_name; +extern int msp430_has_hwmul; + + +#define MSP430_HAS_HWMUL_INTERNAL (msp430_has_hwmul) + +int msp430_current_function_noint_hwmul_function_p(void); +#define MSP430_NOINT_HWMUL (msp430_current_function_noint_hwmul_function_p()) + +#define TARGET_OPTIONS { \ + { "init-stack=", &msp430_init_stack, N_("Specify the initial stack address") }, \ + { "mcu=", &msp430_mcu_name, N_("Specify the MCU name") }, \ + { "endup-at=",&msp430_endup,N_("Jump to specified routine at the end of main()")} \ +} + + +#define TARGET_VERSION fprintf (stderr, " (GNU assembler syntax)"); + +#define OVERRIDE_OPTIONS msp430_override_options() + +#define CAN_DEBUG_WITHOUT_FP +/* Define this macro if debugging can be performed even without a + frame pointer. If this macro is defined, GNU CC will turn on the + `-fomit-frame-pointer' option whenever `-O' is specified. */ + +#define BITS_BIG_ENDIAN 0 +#define BYTES_BIG_ENDIAN 0 +#define WORDS_BIG_ENDIAN 0 +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 16 + +#ifdef IN_LIBGCC2 +/* This is to get correct SI and DI modes in libgcc2.c (32 and 64 bits). */ +#define UNITS_PER_WORD 4 +#else +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 2 +#endif + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 16 + + +/* Maximum sized of reasonable data type + DImode or Dfmode ... */ +#define MAX_FIXED_MODE_SIZE 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 16 + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 16 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 16 + +/* No data type wants to be aligned rounder than this. */ +#define BIGGEST_ALIGNMENT 16 + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT TARGET_STRICT_ALIGN + +/* A C expression for the size in bits of the type `int' on the + target machine. If you don't define this, the default is one word. */ +#define INT_TYPE_SIZE ( 16) + + +/* A C expression for the size in bits of the type `short' on the + target machine. If you don't define this, the default is half a + word. (If this would be less than one storage unit, it is rounded + up to one unit.) */ +#define SHORT_TYPE_SIZE (INT_TYPE_SIZE == 8 ? INT_TYPE_SIZE : 16) + +/* A C expression for the size in bits of the type `long' on the + target machine. If you don't define this, the default is one word. */ +#define LONG_TYPE_SIZE (INT_TYPE_SIZE == 8 ? 16 : 32) + +#define MAX_LONG_TYPE_SIZE 32 +/* Maximum number for the size in bits of the type `long' on the + target machine. If this is undefined, the default is + `LONG_TYPE_SIZE'. Otherwise, it is the constant value that is the + largest value that `LONG_TYPE_SIZE' can have at run-time. This is + used in `cpp'. */ + + +#define LONG_LONG_TYPE_SIZE 64 +/* A C expression for the size in bits of the type `long long' on the + target machine. If you don't define this, the default is two + words. If you want to support GNU Ada on your machine, the value + of macro must be at least 64. */ + + +#define CHAR_TYPE_SIZE 8 +/* A C expression for the size in bits of the type `char' on the + target machine. If you don't define this, the default is one + quarter of a word. (If this would be less than one storage unit, + it is rounded up to one unit.) */ + +#define FLOAT_TYPE_SIZE 32 +/* A C expression for the size in bits of the type `float' on the + target machine. If you don't define this, the default is one word. */ + +#define DOUBLE_TYPE_SIZE 32 +/* A C expression for the size in bits of the type `double' on the + target machine. If you don't define this, the default is two + words. */ + + +#define LONG_DOUBLE_TYPE_SIZE 32 +/* A C expression for the size in bits of the type `long double' on + the target machine. If you don't define this, the default is two + words. */ + +#define DEFAULT_SIGNED_CHAR 1 +/* An expression whose value is 1 or 0, according to whether the type + `char' should be signed or unsigned by default. The user can + always override this default with the options `-fsigned-char' and + `-funsigned-char'. */ + +/* `DEFAULT_SHORT_ENUMS' + A C expression to determine whether to give an `enum' type only as + many bytes as it takes to represent the range of possible values + of that type. A nonzero value means to do that; a zero value + means all `enum' types should be allocated like `int'. + + If you don't define the macro, the default is 0. */ + +#define SIZE_TYPE (INT_TYPE_SIZE == 8 ? "long unsigned int" : "unsigned int") +/* A C expression for a string describing the name of the data type + to use for size values. The typedef name `size_t' is defined + using the contents of the string. + + The string can contain more than one keyword. If so, separate + them with spaces, and write first any length keyword, then + `unsigned' if appropriate, and finally `int'. The string must + exactly match one of the data type names defined in the function + `init_decl_processing' in the file `c-decl.c'. You may not omit + `int' or change the order--that would cause the compiler to crash + on startup. + + If you don't define this macro, the default is `"long unsigned + int"'. */ + +#define PTRDIFF_TYPE (INT_TYPE_SIZE == 8 ? "long int" :"int") +/* A C expression for a string describing the name of the data type + to use for the result of subtracting two pointers. The typedef + name `ptrdiff_t' is defined using the contents of the string. See + `SIZE_TYPE' above for more information. + + If you don't define this macro, the default is `"long int"'. */ + + +#define WCHAR_TYPE_SIZE 16 +/* A C expression for the size in bits of the data type for wide + characters. This is used in `cpp', which cannot make use of + `WCHAR_TYPE'. */ + +#define FIRST_PSEUDO_REGISTER 16 +/* Number of hardware registers known to the compiler. They receive + numbers 0 through `FIRST_PSEUDO_REGISTER-1'; thus, the first + pseudo register's number really is assigned the number + `FIRST_PSEUDO_REGISTER'. */ + +#define FIXED_REGISTERS {\ + 1,1,/* r0 r1 == PC SP */\ + 1,1,/* r2 r3 == CG1(SR) CG2*/\ + 0,0,/* r4 r5 */\ + 0,0,/* r6 r7 */\ + 0,0,/* r8 r9 */\ + 0,0,/* r10 r11 */\ + 0,0,/* r12 r13 */\ + 0,0,/* r14 r15 */\ +} +/* An initializer that says which registers are used for fixed + purposes all throughout the compiled code and are therefore not + available for general allocation. These would include the stack + pointer, the frame pointer (except on machines where that can be + used as a general register when no frame pointer is needed), the + program counter on machines where that is considered one of the + addressable registers, and any other numbered register with a + standard use. + + This information is expressed as a sequence of numbers, separated + by commas and surrounded by braces. The Nth number is 1 if + register N is fixed, 0 otherwise. + + The table initialized from this macro, and the table initialized by + the following one, may be overridden at run time either + automatically, by the actions of the macro + `CONDITIONAL_REGISTER_USAGE', or by the user with the command + options `-ffixed-REG', `-fcall-used-REG' and `-fcall-saved-REG'. */ + +#define CALL_USED_REGISTERS { \ + 1,1,/* r0 r1 */ \ + 1,1,/* r2 r3 */ \ + 0,0,/* r4 r5 */ \ + 0,0,/* r6 r7 */ \ + 0,0,/* r8 r9 */ \ + 0,0,/* r10 r11 */ \ + 1,1,/* r12 r13 */ \ + 1,1,/* r14 r15 */ \ +} +/* Like `FIXED_REGISTERS' but has 1 for each register that is + clobbered (in general) by function calls as well as for fixed + registers. This macro therefore identifies the registers that are + not available for general allocation of values that must live + across function calls. + + If a register has 0 in `CALL_USED_REGISTERS', the compiler + automatically saves it on function entry and restores it on + function exit, if the register is used within the function. */ + +#define NON_SAVING_SETJMP 0 +/* If this macro is defined and has a nonzero value, it means that + `setjmp' and related functions fail to save the registers, or that + `longjmp' fails to restore them. To compensate, the compiler + avoids putting variables in registers in functions that use + `setjmp'. */ + +#define REG_ALLOC_ORDER { 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 } + +/* If defined, an initializer for a vector of integers, containing the + numbers of hard registers in the order in which GNU CC should + prefer to use them (from most preferred to least). + + If this macro is not defined, registers are used lowest numbered + first (all else being equal). + + One use of this macro is on machines where the highest numbered + registers must always be saved and the save-multiple-registers + instruction supports only sequences of consetionve registers. On + such machines, define `REG_ALLOC_ORDER' to be an initializer that + lists the highest numbered allocatable register first. */ + +#define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc () +/* ORDER_REGS_FOR_LOCAL_ALLOC' + A C statement (sans semicolon) to choose the order in which to + allocate hard registers for pseudo-registers local to a basic + block. + + Store the desired register order in the array `reg_alloc_order'. + Element 0 should be the register to allocate first; element 1, the + next register; and so on. + + The macro body should not assume anything about the contents of + `reg_alloc_order' before execution of the macro. + + On most machines, it is not necessary to define this macro. */ + + +#define HARD_REGNO_NREGS(REGNO, MODE) \ +((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* A C expression for the number of consecutive hard registers, + starting at register number REGNO, required to hold a value of mode + MODE. + + On a machine where all registers are exactly one word, a suitable + definition of this macro is + + #define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD)) */ + +#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 +/* +msp430_hard_regno_mode_ok(REGNO, MODE) +*/ +/* A C expression that is nonzero if it is permissible to store a + value of mode MODE in hard register number REGNO (or in several + registers starting with that one). For a machine where all + registers are equivalent, a suitable definition is + + #define HARD_REGNO_MODE_OK(REGNO, MODE) 1 + + It is not necessary for this macro to check for the numbers of + fixed registers, because the allocation mechanism considers them + to be always occupied. + + On some machines, double-precision values must be kept in even/odd + register pairs. The way to implement that is to define this macro + to reject odd register numbers for such modes. + + The minimum requirement for a mode to be OK in a register is that + the `movMODE' instruction pattern support moves between the + register and any other hard register for which the mode is OK; and + that moving a value into the register and back out not alter it. + + Since the same instruction used to move `SImode' will work for all + narrower integer modes, it is not necessary on any machine for + `HARD_REGNO_MODE_OK' to distinguish between these modes, provided + you define patterns `movhi', etc., to take advantage of this. This + is useful because of the interaction between `HARD_REGNO_MODE_OK' + and `MODES_TIEABLE_P'; it is very desirable for all integer modes + to be tieable. + + Many machines have special registers for floating point arithmetic. + Often people assume that floating point machine modes are allowed + only in floating point registers. This is not true. Any + registers that can hold integers can safely *hold* a floating + point machine mode, whether or not floating arithmetic can be done + on it in those registers. Integer move instructions can be used + to move the values. + + On some machines, though, the converse is true: fixed-point machine + modes may not go in floating registers. This is true if the + floating registers normalize any value stored in them, because + storing a non-floating value there would garble it. In this case, + `HARD_REGNO_MODE_OK' should reject fixed-point machine modes in + floating registers. But if the floating registers do not + automatically normalize, if you can store any bit pattern in one + and retrieve it unchanged without a trap, then any machine mode + may go in a floating register, so you can define this macro to say + so. + + The primary significance of special floating registers is rather + that they are the registers acceptable in floating point arithmetic + instructions. However, this is of no concern to + `HARD_REGNO_MODE_OK'. You handle it by writing the proper + constraints for those instructions. + + On some machines, the floating registers are especially slow to + access, so that it is better to store a value in a stack frame + than in such a register if floating point arithmetic is not being + done. As long as the floating registers are not in class + `GENERAL_REGS', they will not be used unless some pattern's + constraint asks for one. */ + +#define MODES_TIEABLE_P(MODE1, MODE2) \ +0 +/* + ((MODE1) == (MODE2) \ + || ((MODE1) == QImode && (MODE2) == HImode) \ + || ((MODE1) == HImode && (MODE2) == QImode)) +*/ +/* A C expression that is nonzero if it is desirable to choose + register allocation so as to avoid move instructions between a + value of mode MODE1 and a value of mode MODE2. + + If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R, + MODE2)' are ever different for any R, then `MODES_TIEABLE_P (MODE1, + MODE2)' must be zero. */ + + + + +enum reg_class { + NO_REGS, + PC_REG, /* r0 - PC */ + SP_REG, /* r1 - SP */ + STACK_REGS, /* r2 - SR */ + CG1_REG, /* r2 - CG1 */ + CG2_REG, /* r3 - CG2 */ + CG_REGS, /* r2, r3 */ + GENERAL_REGS, /* r4 - r15 */ + POINTER_REGS, + FFOUR_REG, + ALL_REGS, LIM_REG_CLASSES +}; + +/* An enumeral type that must be defined with all the register class + names as enumeral values. `NO_REGS' must be first. `ALL_REGS' + must be the last register class, followed by one more enumeral + value, `LIM_REG_CLASSES', which is not a register class but rather + tells how many classes there are. + + Each register class has a number, which is the value of casting + the class name to type `int'. The number serves as an index in + many of the tables described below. */ + + +#define N_REG_CLASSES (int) LIM_REG_CLASSES +/* The number of distinct register classes, defined as follows: + #define N_REG_CLASSES (int) LIM_REG_CLASSES */ + +#define REG_CLASS_NAMES { \ + "NO_REGS", \ + "PC_REG", \ + "SP_REG", \ + "STACK_REGS", \ + "CG1_REG", \ + "CG2_REG", \ + "CG_REGS", \ + "GENERAL_REGS", \ + "POINTER_REGS", \ + "FFOUR_REG", \ + "ALL_REGS" \ +} + +/* An initializer containing the names of the register classes as C + string constants. These names are used in writing some of the + debugging dumps. */ + +#define REG_CLASS_CONTENTS { \ + {0x00000000ul}, /* NO_REGS */ \ + {0x00000001ul}, /* PC_REG */ \ + {0x00000002ul}, /* SP_REG */ \ + {0x00000004ul}, /* r2 */ \ + {0x00000004ul}, /* r2 */ \ + {0x00000008ul}, /* r3 */ \ + {0x0000000cul}, /* r2,r3 */ \ + {0x0000fff2ul}, /* r4 - r15,r1 */ \ + {0x0000fff2ul}, /* r4 - r15,r1 */ \ + {0x0000fff0ul}, /* r4 - r15 */ \ + {0x0000fffful} /* ALL_REGS */ \ +} +/* An initializer containing the contents of the register classes, as + integers which are bit masks. The Nth integer specifies the + contents of class N. The way the integer MASK is interpreted is + that register R is in the class if `MASK & (1 << R)' is 1. + + When the machine has more than 32 registers, an integer does not + suffice. Then the integers are replaced by sub-initializers, + braced groupings containing several integers. Each + sub-initializer must be suitable as an initializer for the type + `HARD_REG_SET' which is defined in `hard-reg-set.h'. */ + + +enum reg_class msp430_regno_reg_class PARAMS ((int)); +#define REGNO_REG_CLASS(R) msp430_regno_reg_class(R) +/* A C expression whose value is a register class containing hard + register REGNO. In general there is more than one such class; + choose a class which is "minimal", meaning that no smaller class + also contains the register. */ + +#define BASE_REG_CLASS POINTER_REGS +/* A macro whose definition is the name of the class to which a valid + base register must belong. A base register is one used in an + address which is the register value plus a displacement. */ + +#define INDEX_REG_CLASS NO_REGS +/* A macro whose definition is the name of the class to which a valid + index register must belong. An index register is one used in an + address where its value is either multiplied by a scale factor or + added to another register (as well as added to a displacement). */ + +#define REG_CLASS_FROM_LETTER(C) msp430_reg_class_from_letter(C) +/* A C expression which defines the machine-dependent operand + constraint letters for register classes. If CHAR is such a + letter, the value should be the register class corresponding to + it. Otherwise, the value should be `NO_REGS'. The register + letter `r', corresponding to class `GENERAL_REGS', will not be + passed to this macro; you do not need to handle it. */ + +#define REGNO_OK_FOR_BASE_P(r) msp430_regno_ok_for_base_p(r) + +/* A C expression which is nonzero if register number NUM is suitable + for use as a base register in operand addresses. It may be either + a suitable hard register or a pseudo register that has been + allocated such a hard register. */ + +/* #define REGNO_MODE_OK_FOR_BASE_P(r, m) + A C expression that is just like `REGNO_OK_FOR_BASE_P', except that + that expression may examine the mode of the memory reference in + MODE. You should define this macro if the mode of the memory + reference affects whether a register may be used as a base + register. If you define this macro, the compiler will use it + instead of `REGNO_OK_FOR_BASE_P'. */ + +#define REGNO_OK_FOR_INDEX_P(NUM) 0 +/* A C expression which is nonzero if register number NUM is suitable + for use as an index register in operand addresses. It may be + either a suitable hard register or a pseudo register that has been + allocated such a hard register. + + The difference between an index register and a base register is + that the index register may be scaled. If an address involves the + sum of two registers, neither one of them scaled, then either one + may be labeled the "base" and the other the "index"; but whichever + labeling is used must fit the machine's constraints of which + registers may serve in each capacity. The compiler will try both + labelings, looking for one that is valid, and will reload one or + both registers only if neither labeling works. */ + +#define PREFERRED_RELOAD_CLASS(X, CLASS) FFOUR_REG + +/* +referred_reload_class(X,CLASS) + A C expression that places additional restrictions on the register + class to use when it is necessary to copy value X into a register + in class CLASS. The value is a register class; perhaps CLASS, or + perhaps another, smaller class. On many machines, the following + definition is safe: + + #define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS + + Sometimes returning a more restrictive class makes better code. + For example, on the 68000, when X is an integer constant that is + in range for a `moveq' instruction, the value of this macro is + always `DATA_REGS' as long as CLASS includes the data registers. + Requiring a data register guarantees that a `moveq' will be used. + + If X is a `const_double', by returning `NO_REGS' you can force X + into a memory constant. This is useful on certain machines where + immediate floating values cannot be loaded into certain kinds of + registers. */ +/* `PREFERRED_OUTPUT_RELOAD_CLASS (X, CLASS)' + Like `PREFERRED_RELOAD_CLASS', but for output reloads instead of + input reloads. If you don't define this macro, the default is to + use CLASS, unchanged. */ + +/* `LIMIT_RELOAD_CLASS (MODE, CLASS)' + A C expression that places additional restrictions on the register + class to use when it is necessary to be able to hold a value of + mode MODE in a reload register for which class CLASS would + ordinarily be used. + + Unlike `PREFERRED_RELOAD_CLASS', this macro should be used when + there are certain modes that simply can't go in certain reload + classes. + + The value is a register class; perhaps CLASS, or perhaps another, + smaller class. + + Don't define this macro unless the target machine has limitations + which require the macro to do something nontrivial. */ + +/* +#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X) GENERAL_REGS + + +#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X) GENERAL_REGS + + + `SECONDARY_RELOAD_CLASS (CLASS, MODE, X)' + `SECONDARY_OUTPUT_RELOAD_CLASS (CLASS, MODE, X)' + Many machines have some registers that cannot be copied directly + to or from memory or even from other types of registers. An + example is the `MQ' register, which on most machines, can only be + copied to or from general registers, but not memory. Some + machines allow copying all registers to and from memory, but + require a scratch register for stores to some memory locations + (e.g., those with symbolic address on the RT, and those with + certain symbolic address on the Sparc when compiling PIC). In + some cases, both an intermediate and a scratch register are + required. + + You should define these macros to indicate to the reload phase + that it may need to allocate at least one register for a reload in + addition to the register to contain the data. Specifically, if + copying X to a register CLASS in MODE requires an intermediate + register, you should define `SECONDARY_INPUT_RELOAD_CLASS' to + return the largest register class all of whose registers can be + used as intermediate registers or scratch registers. + + If copying a register CLASS in MODE to X requires an intermediate + or scratch register, `SECONDARY_OUTPUT_RELOAD_CLASS' should be + defined to return the largest register class required. If the + requirements for input and output reloads are the same, the macro + `SECONDARY_RELOAD_CLASS' should be used instead of defining both + macros identically. + + The values returned by these macros are often `GENERAL_REGS'. + Return `NO_REGS' if no spare register is needed; i.e., if X can be + directly copied to or from a register of CLASS in MODE without + requiring a scratch register. Do not define this macro if it + would always return `NO_REGS'. + + If a scratch register is required (either with or without an + intermediate register), you should define patterns for + `reload_inM' or `reload_outM', as required (*note Standard + Names::.. These patterns, which will normally be implemented with + a `define_expand', should be similar to the `movM' patterns, + except that operand 2 is the scratch register. + + Define constraints for the reload register and scratch register + that contain a single register class. If the original reload + register (whose class is CLASS) can meet the constraint given in + the pattern, the value returned by these macros is used for the + class of the scratch register. Otherwise, two additional reload + registers are required. Their classes are obtained from the + constraints in the insn pattern. + + X might be a pseudo-register or a `subreg' of a pseudo-register, + which could either be in a hard register or in memory. Use + `true_regnum' to find out; it will return -1 if the pseudo is in + memory and the hard register number if it is in a register. + + These macros should not be used in the case where a particular + class of registers can only be copied to memory and not to another + class of registers. In that case, secondary reload registers are + not needed and would not be helpful. Instead, a stack location + must be used to perform the copy and the `movM' pattern should use + memory as a intermediate storage. This case often occurs between + floating-point and general registers. */ + +/* `SECONDARY_MEMORY_NEEDED (CLASS1, CLASS2, M)' + Certain machines have the property that some registers cannot be + copied to some other registers without using memory. Define this + macro on those machines to be a C expression that is non-zero if + objects of mode M in registers of CLASS1 can only be copied to + registers of class CLASS2 by storing a register of CLASS1 into + memory and loading that memory location into a register of CLASS2. + + Do not define this macro if its value would always be zero. + + `SECONDARY_MEMORY_NEEDED_RTX (MODE)' + Normally when `SECONDARY_MEMORY_NEEDED' is defined, the compiler + allocates a stack slot for a memory location needed for register + copies. If this macro is defined, the compiler instead uses the + memory location defined by this macro. + + Do not define this macro if you do not define + `SECONDARY_MEMORY_NEEDED'. */ + +#define SMALL_REGISTER_CLASSES 1 +/* Normally the compiler avoids choosing registers that have been + explicitly mentioned in the rtl as spill registers (these + registers are normally those used to pass parameters and return + values). However, some machines have so few registers of certain + classes that there would not be enough registers to use as spill + registers if this were done. + + Define `SMALL_REGISTER_CLASSES' to be an expression with a non-zero + value on these machines. When this macro has a non-zero value, the + compiler allows registers explicitly used in the rtl to be used as + spill registers but avoids extending the lifetime of these + registers. + + It is always safe to define this macro with a non-zero value, but + if you unnecessarily define it, you will reduce the amount of + optimizations that can be performed in some cases. If you do not + define this macro with a non-zero value when it is required, the + compiler will run out of spill registers and print a fatal error + message. For most machines, you should not define this macro at + all. */ + +/* +#define CLASS_LIKELY_SPILLED_P(CLASS) \ + ( (CLASS) != ALL_REGS && (CLASS) != GENERAL_REGS) + A C expression whose value is nonzero if pseudos that have been + assigned to registers of class CLASS would likely be spilled + because registers of CLASS are needed for spill registers. + + The default value of this macro returns 1 if CLASS has exactly one + register and zero otherwise. On most machines, this default + should be used. Only define this macro to some other expression + if pseudo allocated by `local-alloc.c' end up in memory because + their hard registers were needed for spill registers. If this + macro returns nonzero for those classes, those pseudos will only + be allocated by `global.c', which knows how to reallocate the + pseudo to another register. If there would not be another + register available for reallocation, you should not change the + definition of this macro since the only effect of such a + definition would be to slow down register allocation. */ + +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) +/* A C expression for the maximum number of consecutive registers of + class CLASS needed to hold a value of mode MODE. + + This is closely related to the macro `HARD_REGNO_NREGS'. In fact, + the value of the macro `CLASS_MAX_NREGS (CLASS, MODE)' should be + the maximum value of `HARD_REGNO_NREGS (REGNO, MODE)' for all + REGNO values in the class CLASS. + + This macro helps control the handling of multiple-word values in + the reload pass. */ + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? (VALUE) >= -32767 && (VALUE) <= 32767 : \ + (C) == 'J' ? (VALUE) <= 0 && (VALUE) >= -32767: \ + (C) == 'K' ? (VALUE) >= 0 && (VALUE) <= 32767 : \ + (C) == 'L' ? (VALUE) >= 0 && (VALUE) <= 0xff : \ + (C) == 'M' ? (VALUE) >= 0x10 && (VALUE) <= 0xff : \ + (C) == 'N' ? (VALUE) >= 0x100 && (VALUE) <= 0x1ff : \ + (C) == 'O' ? (VALUE)&1: \ + (C) == 'P' ? ((VALUE)==-1||(VALUE)==1||(VALUE)==2||(VALUE)==4||(VALUE)==8 ||(VALUE)==0) : 0) +/* A C expression that defines the machine-dependent operand + constraint letters (`I', `J', `K', ... `P') that specify + particular ranges of integer values. If C is one of those + letters, the expression should check that VALUE, an integer, is in + the appropriate range and return 1 if so, 0 otherwise. If C is + not one of those letters, the value should be 0 regardless of + VALUE. */ + + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' ? (VALUE) == CONST0_RTX (SFmode) \ + : 0) +/* `CONST_DOUBLE_OK_FOR_LETTER_P (VALUE, C)' + A C expression that defines the machine-dependent operand + constraint letters that specify particular ranges of + `const_double' values (`G' or `H'). + + If C is one of those letters, the expression should check that + VALUE, an RTX of code `const_double', is in the appropriate range + and return 1 if so, 0 otherwise. If C is not one of those + letters, the value should be 0 regardless of VALUE. + + `const_double' is used for all floating-point constants and for + `DImode' fixed-point constants. A given letter can accept either + or both kinds of values. It can use `GET_MODE' to distinguish + between these kinds. */ + +#define EXTRA_CONSTRAINT(x, c) extra_constraint(x, c) +/* A C expression that defines the optional machine-dependent + constraint letters (``Q', `R', `S', `T', `U') that can' + be used to segregate specific types of operands, usually memory + references, for the target machine. Normally this macro will not + be defined. If it is required for a particular target machine, it + should return 1 if VALUE corresponds to the operand type + represented by the constraint letter C. If C is not defined as an + extra constraint, the value returned should be 0 regardless of + VALUE. + + For example, on the ROMP, load instructions cannot have their + output in r0 if the memory reference contains a symbolic address. + Constraint letter `Q' is defined as representing a memory address + that does *not* contain a symbolic address. An alternative is + specified with a `Q' constraint on the input and `r' on the + output. The next alternative specifies `m' on the input and a + register class that does not include r0 on the output. */ + +/* This is an undocumented variable which describes + how GCC will push a data */ +#define STACK_PUSH_CODE POST_DEC + +#define STACK_GROWS_DOWNWARD +/* Define this macro if pushing a word onto the stack moves the stack + pointer to a smaller address. + + When we say, "define this macro if ...," it means that the + compiler checks this macro only with `#ifdef' so the precise + definition used does not matter. */ + +#define STARTING_FRAME_OFFSET 0 +/* Offset from the frame pointer to the first local variable slot to + be allocated. + + If `FRAME_GROWS_DOWNWARD', find the next slot's offset by + subtracting the first slot's length from `STARTING_FRAME_OFFSET'. + Otherwise, it is found by adding the length of the first slot to + the value `STARTING_FRAME_OFFSET'. */ + +#define STACK_POINTER_OFFSET 0 +/* Offset from the stack pointer register to the first location at + which outgoing arguments are placed. If not specified, the + default value of zero is used. This is the proper value for most + machines. + + If `ARGS_GROW_DOWNWARD', this is the offset to the location above + the first location at which outgoing arguments are placed. */ + +#define FIRST_PARM_OFFSET(FUNDECL) 0 +/* Offset from the argument pointer register to the first argument's + address. On some machines it may depend on the data type of the + function. + + If `ARGS_GROW_DOWNWARD', this is the offset to the location above + the first argument's address. */ + +/* `STACK_DYNAMIC_OFFSET (FUNDECL)' + Offset from the stack pointer register to an item dynamically + allocated on the stack, e.g., by `alloca'. + + The default value for this macro is `STACK_POINTER_OFFSET' plus the + length of the outgoing arguments. The default is correct for most + machines. See `function.c' for details. */ + +#define STACK_BOUNDARY 16 +/* Define this macro if there is a guaranteed alignment for the stack + pointer on this machine. The definition is a C expression for the + desired alignment (measured in bits). This value is used as a + default if PREFERRED_STACK_BOUNDARY is not defined. */ + +#define STACK_POINTER_REGNUM 1 +/* The register number of the stack pointer register, which must also + be a fixed register according to `FIXED_REGISTERS'. On most + machines, the hardware determines which register this is. */ + +#define FRAME_POINTER_REGNUM 4 +/* The register number of the frame pointer register, which is used to + access automatic variables in the stack frame. On some machines, + the hardware determines which register this is. On other + machines, you can choose any register you wish for this purpose. */ + +#define ARG_POINTER_REGNUM 5 +/* The register number of the arg pointer register, which is used to + access the function's argument list. On some machines, this is + the same as the frame pointer register. On some machines, the + hardware determines which register this is. On other machines, + you can choose any register you wish for this purpose. If this is + not the same register as the frame pointer register, then you must + mark it as a fixed register according to `FIXED_REGISTERS', or + arrange to be able to eliminate it (*note Elimination::.). */ + +#define STATIC_CHAIN_REGNUM 6 +/* Register numbers used for passing a function's static chain + pointer. If register windows are used, the register number as + seen by the called function is `STATIC_CHAIN_INCOMING_REGNUM', + while the register number as seen by the calling function is + `STATIC_CHAIN_REGNUM'. If these registers are the same, + `STATIC_CHAIN_INCOMING_REGNUM' need not be defined. + + The static chain register need not be a fixed register. + + If the static chain is passed in memory, these macros should not be + defined; instead, the next two macros should be defined. */ + +#define FRAME_POINTER_REQUIRED frame_pointer_required_p() + +/* + A C expression which is nonzero if a function must have and use a + frame pointer. This expression is evaluated in the reload pass. + If its value is nonzero the function will have a frame pointer. + + The expression can in principle examine the current function and + decide according to the facts, but on most machines the constant 0 + or the constant 1 suffices. Use 0 when the machine allows code to + be generated with no frame pointer, and doing so saves some time + or space. Use 1 when there is no possible advantage to avoiding a + frame pointer. + + In certain cases, the compiler does not know how to produce valid + code without a frame pointer. The compiler recognizes those cases + and automatically gives the function a frame pointer regardless of + what `FRAME_POINTER_REQUIRED' says. You don't need to worry about + them. + + In a function that does not require a frame pointer, the frame + pointer register can be allocated for ordinary usage, unless you + mark it as a fixed register. See `FIXED_REGISTERS' for more + information. */ + +#define ELIMINABLE_REGS { \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, STACK_POINTER_REGNUM} \ +} +/* If defined, this macro specifies a table of register pairs used to + eliminate unneeded registers that point into the stack frame. If + it is not defined, the only elimination attempted by the compiler + is to replace references to the frame pointer with references to + the stack pointer. + + The definition of this macro is a list of structure + initializations, each of which specifies an original and + replacement register. + + On some machines, the position of the argument pointer is not + known until the compilation is completed. In such a case, a + separate hard register must be used for the argument pointer. + This register can be eliminated by replacing it with either the + frame pointer or the argument pointer, depending on whether or not + the frame pointer has been eliminated. + + In this case, you might specify: + #define ELIMINABLE_REGS \ + {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}} + + Note that the elimination of the argument pointer with the stack + pointer is specified first since that is the preferred elimination. */ + +#define CAN_ELIMINATE(FROM, TO) 1 +/* A C expression that returns non-zero if the compiler is allowed to + try to replace register number FROM-REG with register number + TO-REG. This macro need only be defined if `ELIMINABLE_REGS' is + defined, and will usually be the constant 1, since most of the + cases preventing register elimination are things that the compiler + already knows about. */ + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + OFFSET = initial_elimination_offset (FROM, TO) +/* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'. It + specifies the initial difference between the specified pair of + registers. This macro must be defined if `ELIMINABLE_REGS' is + defined. */ +/* +#define RETURN_ADDR_RTX(count, x) \ + gen_rtx_MEM (Pmode, memory_address (Pmode, plus_constant (tem, 1))) +*/ +#define PUSH_ROUNDING(NPUSHED) ((NPUSHED+1) & ~1) +/* A C expression that is the number of bytes actually pushed onto the + stack when an instruction attempts to push NPUSHED bytes. + + If the target machine does not have a push instruction, do not + define this macro. That directs GNU CC to use an alternate + strategy: to allocate the entire argument block and then store the + arguments into it. + + On some machines, the definition + + #define PUSH_ROUNDING(BYTES) (BYTES) + + will suffice. But on other machines, instructions that appear to + push one byte actually push two bytes in an attempt to maintain + alignment. Then the definition should be + + #define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1) */ + +#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACK_SIZE) 0 +/* A C expression that should indicate the number of bytes of its own + arguments that a function pops on returning, or 0 if the function + pops no arguments and the caller must therefore pop them all after + the function returns. + + FUNDECL is a C variable whose value is a tree node that describes + the function in question. Normally it is a node of type + `FUNCTION_DECL' that describes the declaration of the function. + From this you can obtain the DECL_MACHINE_ATTRIBUTES of the + function. + + FUNTYPE is a C variable whose value is a tree node that describes + the function in question. Normally it is a node of type + `FUNCTION_TYPE' that describes the data type of the function. + From this it is possible to obtain the data types of the value and + arguments (if known). + + When a call to a library function is being considered, FUNDECL + will contain an identifier node for the library function. Thus, if + you need to distinguish among various library functions, you can + do so by their names. Note that "library function" in this + context means a function used to perform arithmetic, whose name is + known specially in the compiler and was not mentioned in the C + code being compiled. + + STACK-SIZE is the number of bytes of arguments passed on the + stack. If a variable number of bytes is passed, it is zero, and + argument popping will always be the responsibility of the calling + function. + + On the Vax, all functions always pop their arguments, so the + definition of this macro is STACK-SIZE. On the 68000, using the + standard calling convention, no functions pop their arguments, so + the value of the macro is always 0 in this case. But an + alternative calling convention is available in which functions + that take a fixed number of arguments pop them but other functions + (such as `printf') pop nothing (the caller pops all). When this + convention is in use, FUNTYPE is examined to determine whether a + function takes a fixed number of arguments. */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ +(function_arg (&(CUM), MODE, TYPE, NAMED)) + +/* +#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \ +(function_incoming_arg (&(CUM), MODE, TYPE, NAMED)) +*/ +/* A C expression that controls whether a function argument is passed + in a register, and which register. + + The arguments are CUM, which summarizes all the previous + arguments; MODE, the machine mode of the argument; TYPE, the data + type of the argument as a tree node or 0 if that is not known + (which happens for C support library functions); and NAMED, which + is 1 for an ordinary argument and 0 for nameless arguments that + correspond to `...' in the called function's prototype. + + The value of the expression is usually either a `reg' RTX for the + hard register in which to pass the argument, or zero to pass the + argument on the stack. + + For machines like the Vax and 68000, where normally all arguments + are pushed, zero suffices as a definition. + + The value of the expression can also be a `parallel' RTX. This is + used when an argument is passed in multiple locations. The mode + of the of the `parallel' should be the mode of the entire + argument. The `parallel' holds any number of `expr_list' pairs; + each one describes where part of the argument is passed. In each + `expr_list', the first operand can be either a `reg' RTX for the + hard register in which to pass this part of the argument, or zero + to pass the argument on the stack. If this operand is a `reg', + then the mode indicates how large this part of the argument is. + The second operand of the `expr_list' is a `const_int' which gives + the offset in bytes into the entire argument where this part + starts. + + The usual way to make the ANSI library `stdarg.h' work on a machine + where some arguments are usually passed in registers, is to cause + nameless arguments to be passed on the stack instead. This is done + by making `FUNCTION_ARG' return 0 whenever NAMED is 0. + + You may use the macro `MUST_PASS_IN_STACK (MODE, TYPE)' in the + definition of this macro to determine if this argument is of a + type that must be passed in the stack. If `REG_PARM_STACK_SPACE' + is not defined and `FUNCTION_ARG' returns non-zero for such an + argument, the compiler will abort. If `REG_PARM_STACK_SPACE' is + defined, the argument will be computed in the stack and then + loaded into a register. */ + +typedef struct msp430_args { + int nregs; /* # registers available for passing */ + int regno; /* next available register number */ +} CUMULATIVE_ARGS; +/* A C type for declaring a variable that is used as the first + argument of `FUNCTION_ARG' and other related values. For some + target machines, the type `int' suffices and can hold the number + of bytes of argument so far. + + There is no need to record in `CUMULATIVE_ARGS' anything about the + arguments that have been passed on the stack. The compiler has + other variables to keep track of that. For target machines on + which all arguments are passed on the stack, there is no need to + store anything in `CUMULATIVE_ARGS'; however, the data structure + must exist and should not be empty, so use `int'. */ + +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ +init_cumulative_args (&(CUM), FNTYPE, LIBNAME, INDIRECT) + +#define INIT_CUMULATIVE_INCOMING_ARGS(CUM, FNTYPE, LIBNAME) \ +init_cumulative_incoming_args(&(CUM), FNTYPE, LIBNAME) + +/* A C statement (sans semicolon) for initializing the variable CUM + for the state at the beginning of the argument list. The variable + has type `CUMULATIVE_ARGS'. The value of FNTYPE is the tree node + for the data type of the function which will receive the args, or 0 + if the args are to a compiler support library function. The value + of INDIRECT is nonzero when processing an indirect call, for + example a call through a function pointer. The value of INDIRECT + is zero for a call to an explicitly named function, a library + function call, or when `INIT_CUMULATIVE_ARGS' is used to find + arguments for the function being compiled. + + When processing a call to a compiler support library function, + LIBNAME identifies which one. It is a `symbol_ref' rtx which + contains the name of the function, as a string. LIBNAME is 0 when + an ordinary C function call is being processed. Thus, each time + this macro is called, either LIBNAME or FNTYPE is nonzero, but + never both of them at once. */ + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (function_arg_advance (&CUM, MODE, TYPE, NAMED)) + +/* A C statement (sans semicolon) to update the summarizer variable + CUM to advance past an argument in the argument list. The values + MODE, TYPE and NAMED describe that argument. Once this is done, + the variable CUM is suitable for analyzing the *following* + argument with `FUNCTION_ARG', etc. + + This macro need not do anything if the argument in question was + passed on the stack. The compiler knows how to track the amount + of stack space used for arguments without any special help. */ + +#define FUNCTION_ARG_REGNO_P(r) (r >= 12 && r <= 15) +/* A C expression that is nonzero if REGNO is the number of a hard + register in which function arguments are sometimes passed. This + does *not* include implicit arguments such as the static chain and + the structure-value address. On many machines, no registers can be + used for this purpose since all function arguments are pushed on + the stack. */ + +extern int msp430_reg_order[]; + +#define RET_REGISTER 15 /* msp430_ret_register ()*/ + +#define FUNCTION_VALUE(VALTYPE, FUNC) msp430_function_value (VALTYPE, FUNC) +/* A C expression to create an RTX representing the place where a + function returns a value of data type VALTYPE. VALTYPE is a tree + node representing a data type. Write `TYPE_MODE (VALTYPE)' to get + the machine mode used to represent that type. On many machines, + only the mode is relevant. (Actually, on most machines, scalar + values are returned in the same place regardless of mode). + + The value of the expression is usually a `reg' RTX for the hard + register where the return value is stored. The value can also be a + `parallel' RTX, if the return value is in multiple places. See + `FUNCTION_ARG' for an explanation of the `parallel' form. + + If `PROMOTE_FUNCTION_RETURN' is defined, you must apply the same + promotion rules specified in `PROMOTE_MODE' if VALTYPE is a scalar + type. + + If the precise function being called is known, FUNC is a tree node + (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer. This + makes it possible to use a different value-returning convention + for specific functions when all their calls are known. + + `FUNCTION_VALUE' is not used for return vales with aggregate data + types, because these are returned in another way. See + `STRUCT_VALUE_REGNUM' and related macros, below. */ + +#define LIBCALL_VALUE(MODE) msp430_libcall_value (MODE) +/* A C expression to create an RTX representing the place where a + library function returns a value of mode MODE. If the precise + function being called is known, FUNC is a tree node + (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer. This + makes it possible to use a different value-returning convention + for specific functions when all their calls are known. + + Note that "library function" in this context means a compiler + support routine, used to perform arithmetic, whose name is known + specially by the compiler and was not mentioned in the C code being + compiled. + + The definition of `LIBRARY_VALUE' need not be concerned aggregate + data types, because none of the library functions returns such + types. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == RET_REGISTER) +/* A C expression that is nonzero if REGNO is the number of a hard + register in which the values of called function may come back. + + A register whose use for returning values is limited to serving as + the second of a pair (for a value of type `double', say) need not + be recognized by this macro. So for most machines, this definition + suffices: + + #define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + + If the machine has register windows, so that the caller and the + called function use different registers for the return value, this + macro should recognize only the caller's register numbers. */ + +#define RETURN_IN_MEMORY(TYPE) ((TYPE_MODE (TYPE) == BLKmode) \ + ? int_size_in_bytes (TYPE) > 8 \ + : 0) +/* A C expression which can inhibit the returning of certain function + values in registers, based on the type of value. A nonzero value + says to return the function value in memory, just as large + structures are always returned. Here TYPE will be a C expression + of type `tree', representing the data type of the value. + + Note that values of mode `BLKmode' must be explicitly handled by + this macro. Also, the option `-fpcc-struct-return' takes effect + regardless of this macro. On most systems, it is possible to + leave the macro undefined; this causes a default definition to be + used, whose value is the constant 1 for `BLKmode' values, and 0 + otherwise. + + Do not use this macro to indicate that structures and unions + should always be returned in memory. You should instead use + `DEFAULT_PCC_STRUCT_RETURN' to indicate this. */ + +#define DEFAULT_PCC_STRUCT_RETURN 0 +/* Define this macro to be 1 if all structure and union return values + must be in memory. Since this results in slower code, this should + be defined only if needed for compatibility with other compilers + or with an ABI. If you define this macro to be 0, then the + conventions used for structure and union return values are decided + by the `RETURN_IN_MEMORY' macro. + + If not defined, this defaults to the value 1. */ + +#define STRUCT_VALUE 0 +/* If the structure value address is not passed in a register, define + `STRUCT_VALUE' as an expression returning an RTX for the place + where the address is passed. If it returns 0, the address is + passed as an "invisible" first argument. */ + +#define STRUCT_VALUE_INCOMING 0 +/* If the incoming location is not a register, then you should define + `STRUCT_VALUE_INCOMING' as an expression for an RTX for where the + called function should find the value. If it should find the + value on the stack, define this to create a `mem' which refers to + the frame pointer. A definition of 0 means that the address is + passed as an "invisible" first argument. */ + +#define STRICT_ARGUMENT_NAMING 1 +/* Define this macro if the location where a function argument is + passed depends on whether or not it is a named argument. + + This macro controls how the NAMED argument to `FUNCTION_ARG' is + set for varargs and stdarg functions. With this macro defined, + the NAMED argument is always true for named arguments, and false + for unnamed arguments. If this is not defined, but + `SETUP_INCOMING_VARARGS' is defined, then all arguments are + treated as named. Otherwise, all named arguments except the last + are treated as named. */ + + +/* +#define HAVE_PRE_INCREMENT 1 +*/ + +#define HAVE_POST_INCREMENT 1 + +/* +#define HAVE_PRE_DECREMENT 1 +#define HAVE_PRE_INCREMENT 1 +#define HAVE_POST_DECREMENT 1 +*/ +/* Similar for other kinds of addressing. */ + +#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) + +/* +(GET_CODE (X) == LABEL_REF \ +|| GET_CODE (X) == SYMBOL_REF \ +|| GET_CODE (X) == CONST_INT \ +|| GET_CODE (X) == CONST) +*/ + +/* +#define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \ +do{CODE = msp430_canonicalize_comparison(CODE, &OP0, &OP1); }while(0) +*/ + +/* A C expression that is 1 if the RTX X is a constant which is a + valid address. On most machines, this can be defined as + `CONSTANT_P (X)', but a few machines are more restrictive in which + constant addresses are supported. + + `CONSTANT_P' accepts integer-values expressions whose values are + not explicitly known, such as `symbol_ref', `label_ref', and + `high' expressions and `const' arithmetic expressions, in addition + to `const_int' and `const_double' expressions. */ + +#define MAX_REGS_PER_ADDRESS 1 +/* A number, the maximum number of registers that can appear in a + valid memory address. Note that it is up to you to specify a + value equal to the maximum number that `GO_IF_LEGITIMATE_ADDRESS' + would ever accept. */ + +#ifdef REG_OK_STRICT +# define GO_IF_LEGITIMATE_ADDRESS(mode, operand, ADDR) \ +{ \ + if (legitimate_address_p (mode, operand, 1)) \ + goto ADDR; \ +} +# else +# define GO_IF_LEGITIMATE_ADDRESS(mode, operand, ADDR) \ +{ \ + if (legitimate_address_p (mode, operand, 0)) \ + goto ADDR; \ +} +#endif +/* A C compound statement with a conditional `goto LABEL;' executed + if X (an RTX) is a legitimate memory address on the target machine + for a memory operand of mode MODE. + + It usually pays to define several simpler macros to serve as + subroutines for this one. Otherwise it may be too complicated to + understand. + + This macro must exist in two variants: a strict variant and a + non-strict one. The strict variant is used in the reload pass. It + must be defined so that any pseudo-register that has not been + allocated a hard register is considered a memory reference. In + contexts where some kind of register is required, a pseudo-register + with no hard register must be rejected. + + The non-strict variant is used in other passes. It must be + defined to accept all pseudo-registers in every context where some + kind of register is required. + + Compiler source files that want to use the strict variant of this + macro define the macro `REG_OK_STRICT'. You should use an `#ifdef + REG_OK_STRICT' conditional to define the strict variant in that + case and the non-strict variant otherwise. + + Subroutines to check for acceptable registers for various purposes + (one for base registers, one for index registers, and so on) are + typically among the subroutines used to define + `GO_IF_LEGITIMATE_ADDRESS'. Then only these subroutine macros + need have two variants; the higher levels of macros may be the + same whether strict or not. + + Normally, constant addresses which are the sum of a `symbol_ref' + and an integer are stored inside a `const' RTX to mark them as + constant. Therefore, there is no need to recognize such sums + specifically as legitimate addresses. Normally you would simply + recognize any `const' as legitimate. + + Usually `PRINT_OPERAND_ADDRESS' is not prepared to handle constant + sums that are not marked with `const'. It assumes that a naked + `plus' indicates indexing. If so, then you *must* reject such + naked constant sums as illegitimate addresses, so that none of + them will be given to `PRINT_OPERAND_ADDRESS'. + + On some machines, whether a symbolic address is legitimate depends + on the section that the address refers to. On these machines, + define the macro `ENCODE_SECTION_INFO' to store the information + into the `symbol_ref', and then check for it here. When you see a + `const', you will have to look inside it to find the `symbol_ref' + in order to determine the section. *Note Assembler Format::. + + The best way to modify the name string is by adding text to the + beginning, with suitable punctuation to prevent any ambiguity. + Allocate the new name in `saveable_obstack'. You will have to + modify `ASM_OUTPUT_LABELREF' to remove and decode the added text + and output the name accordingly, and define `STRIP_NAME_ENCODING' + to access the original name string. + + You can check the information stored here into the `symbol_ref' in + the definitions of the macros `GO_IF_LEGITIMATE_ADDRESS' and + `PRINT_OPERAND_ADDRESS'. */ + +/* `REG_OK_FOR_BASE_P (X)' + A C expression that is nonzero if X (assumed to be a `reg' RTX) is + valid for use as a base register. For hard registers, it should + always accept those which the hardware permits and reject the + others. Whether the macro accepts or rejects pseudo registers + must be controlled by `REG_OK_STRICT' as described above. This + usually requires two variant definitions, of which `REG_OK_STRICT' + controls the one actually used. */ + +#define REG_OK_FOR_BASE_NOSTRICT_P(X) \ + (REGNO (X) >= FIRST_PSEUDO_REGISTER || REG_OK_FOR_BASE_STRICT_P(X)) + +#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + +#ifdef REG_OK_STRICT +# define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P (X) +#else +# define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NOSTRICT_P (X) +#endif + +/* A C expression that is just like `REG_OK_FOR_BASE_P', except that + that expression may examine the mode of the memory reference in + MODE. You should define this macro if the mode of the memory + reference affects whether a register may be used as a base + register. If you define this macro, the compiler will use it + instead of `REG_OK_FOR_BASE_P'. */ + + +#define REG_OK_FOR_INDEX_P(X) 0 /*( REGNO(X)!=3 && REGNO(X)!=2 &®NO(X)<=15) */ +/* A C expression that is nonzero if X (assumed to be a `reg' RTX) is + valid for use as an index register. + + The difference between an index register and a base register is + that the index register may be scaled. If an address involves the + sum of two registers, neither one of them scaled, then either one + may be labeled the "base" and the other the "index"; but whichever + labeling is used must fit the machine's constraints of which + registers may serve in each capacity. The compiler will try both + labelings, looking for one that is valid, and will reload one or + both registers only if neither labeling works. */ + +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ +GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN) + +/*{ \ + \ + (X) = legitimize_address (X, OLDX, MODE); \ + if (memory_address_p (MODE, X)) \ + goto WIN; \ + \ +} */ + +/* A C compound statement that attempts to replace X with a valid + memory address for an operand of mode MODE. WIN will be a C + statement label elsewhere in the code; the macro definition may use + + GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); + + to avoid further processing if the address has become legitimate. + + X will always be the result of a call to `break_out_memory_refs', + and OLDX will be the operand that was given to that function to + produce X. + + The code generated by this macro should not alter the substructure + of X. If it transforms X into a more legitimate form, it should + assign X (which will always be a C variable) a new value. + + It is not necessary for this macro to come up with a legitimate + address. The compiler has standard ways of doing so in all cases. + In fact, it is safe for this macro to do nothing. But often a + machine-dependent strategy can generate better code. */ + +/* A C compound statement that attempts to replace X, which is an + address that needs reloading, with a valid memory address for an + operand of mode MODE. WIN will be a C statement label elsewhere + in the code. It is not necessary to define this macro, but it + might be useful for performance reasons. + + For example, on the i386, it is sometimes possible to use a single + reload register instead of two by reloading a sum of two pseudo + registers into a register. On the other hand, for number of RISC + processors offsets are limited so that often an intermediate + address needs to be generated in order to address a stack slot. + By defining LEGITIMIZE_RELOAD_ADDRESS appropriately, the + intermediate addresses generated for adjacent some stack slots can + be made identical, and thus be shared. + + *Note*: This macro should be used with caution. It is necessary + to know something of how reload works in order to effectively use + this, and it is quite easy to produce macros that build in too + much knowledge of reload internals. + + *Note*: This macro must be able to reload an address created by a + previous invocation of this macro. If it fails to handle such + addresses then the compiler may generate incorrect code or abort. + + The macro definition should use `push_reload' to indicate parts + that need reloading; OPNUM, TYPE and IND_LEVELS are usually + suitable to be passed unaltered to `push_reload'. + + The code generated by this macro must not alter the substructure of + X. If it transforms X into a more legitimate form, it should + assign X (which will always be a C variable) a new value. This + also applies to parts that you change indirectly by calling + `push_reload'. + + The macro definition may use `strict_memory_address_p' to test if + the address has become legitimate. + + If you want to change only a part of X, one standard way of doing + this is to use `copy_rtx'. Note, however, that is unshares only a + single level of rtl. Thus, if the part to be changed is not at the + top level, you'll need to replace first the top leve It is not + necessary for this macro to come up with a legitimate address; + but often a machine-dependent strategy can generate better code. */ + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ +{} +/* A C statement or compound statement with a conditional `goto + LABEL;' executed if memory address X (an RTX) can have different + meanings depending on the machine mode of the memory reference it + is used for or if the address is valid for some modes but not + others. + + Autoincrement and autodecrement addresses typically have + mode-dependent effects because the amount of the increment or + decrement is the size of the operand being addressed. Some + machines have other mode-dependent addresses. Many RISC machines + have no mode-dependent addresses. + + You may assume that ADDR is a valid address for the machine. */ + +#define LEGITIMATE_CONSTANT_P(X) 1 +/* A C expression that is nonzero if X is a legitimate constant for + an immediate operand on the target machine. You can assume that X + satisfies `CONSTANT_P', so you need not check this. In fact, `1' + is a suitable definition for this macro on machines where anything + `CONSTANT_P' is valid. */ + +#define CONST_COSTS(x,CODE,OUTER_CODE) \ + case CONST_INT: \ + if (OUTER_CODE == PLUS \ + || OUTER_CODE == IOR \ + || OUTER_CODE == AND \ + || OUTER_CODE == MINUS \ + || OUTER_CODE == SET \ + || INTVAL (x) == 0 \ + || INTVAL (x) == 1 \ + || INTVAL (x) == 2 \ + || INTVAL (x) == 4 \ + || INTVAL (x) == 8 \ + || INTVAL (x) == -1) \ + return 0; \ + case CONST: \ + return 0; \ + case LABEL_REF: \ + return 1; \ + case SYMBOL_REF: \ + return 2; \ + case CONST_DOUBLE: \ + return 4; + +/* A part of a C `switch' statement that describes the relative costs + of constant RTL expressions. It must contain `case' labels for + expression codes `const_int', `const', `symbol_ref', `label_ref' + and `const_double'. Each case must ultimately reach a `return' + statement to return the relative cost of the use of that kind of + constant value in an expression. The cost may depend on the + precise value of the constant, which is available for examination + in X, and the rtx code of the expression in which it is contained, + found in OUTER_CODE. + + CODE is the expression code--redundant, since it can be obtained + with `GET_CODE (X)'. */ + +#define DEFAULT_RTX_COSTS(x, code, outer_code) \ +{ \ + int cst = default_rtx_costs (x, code, outer_code); \ + if (cst>0) \ + return cst; \ + else if (cst<0) \ + total += -cst; \ + break; \ +} + +/* Like `CONST_COSTS' but applies to nonconstant RTL expressions. + This can be used, for example, to indicate how costly a multiply + instruction is. In writing this macro, you can use the construct + `COSTS_N_INSNS (N)' to specify a cost equal to N fast + instructions. OUTER_CODE is the code of the expression in which X + is contained. + + This macro is optional; do not define it if the default cost + assumptions are adequate for the target machine. */ + +#define ADDRESS_COST(ADDRESS) 2 + +/* An expression giving the cost of an addressing mode that contains + ADDRESS. If not defined, the cost is computed from the ADDRESS + expression and the `CONST_COSTS' values. + + For most CISC machines, the default cost is a good approximation + of the true cost of the addressing mode. However, on RISC + machines, all instructions normally have the same length and + execution time. Hence all addresses will have equal costs. + + In cases where more than one form of an address is known, the form + with the lowest cost will be used. If multiple forms have the + same, lowest, cost, the one that is the most complex will be used. + + For example, suppose an address that is equal to the sum of a + register and a constant is used twice in the same basic block. + When this macro is not defined, the address will be computed in a + register and memory references will be indirect through that + register. On machines where the cost of the addressing mode + containing the sum is no higher than that of a simple indirect + reference, this will produce an additional instruction and + possibly require an additional register. Proper specification of + this macro eliminates this overhead for such machines. + + Similar use of this macro is made in strength reduction of loops. + + ADDRESS need not be valid as an address. In such a case, the cost + is not relevant and can be any value; invalid addresses need not be + assigned a different cost. + + On machines where an address involving more than one register is as + cheap as an address computation involving only one register, + defining `ADDRESS_COST' to reflect this can cause two registers to + be live over a region of code where only one would have been if + `ADDRESS_COST' were not defined in that manner. This effect should + be considered in the definition of this macro. Equivalent costs + should probably only be given to addresses with different numbers + of registers on machines with lots of registers. + + This macro will normally either not be defined or be defined as a + constant. */ + +#define REGISTER_MOVE_COST(MODE, FROM, TO) ((MODE)==QImode ? 1 : \ + (MODE)==HImode ? 1 : \ + (MODE)==SImode ? 2 : \ + (MODE)==SFmode ? 2 : 4) + +/* A C expression for the cost of moving data from a register in class + FROM to one in class TO. The classes are expressed using the + enumeration values such as `GENERAL_REGS'. A value of 2 is the + default; other values are interpreted relative to that. + + It is not required that the cost always equal 2 when FROM is the + same as TO; on some machines it is expensive to move between + registers if they are not general registers. + + If reload sees an insn consisting of a single `set' between two + hard registers, and if `REGISTER_MOVE_COST' applied to their + classes returns a value of 2, reload does not check to ensure that + the constraints of the insn are met. Setting a cost of other than + 2 will allow reload to verify that the constraints are met. You + should do this if the `movM' pattern's constraints do not allow + such copying. */ + +#define MEMORY_MOVE_COST(MODE,CLASS,IN) ((MODE)==QImode ? 2 : \ + (MODE)==HImode ? 2 : \ + (MODE)==SImode ? 4 : \ + (MODE)==SFmode ? 4 : 8) +/* A C expression for the cost of moving data of mode M between a + register and memory. A value of 4 is the default; this cost is + relative to those in `REGISTER_MOVE_COST'. + + If moving between registers and memory is more expensive than + between two registers, you should define this macro to express the + relative cost. */ + +#define BRANCH_COST 0 +/* A C expression for the cost of a branch instruction. A value of 1 + is the default; other values are interpreted relative to that. + + Here are additional macros which do not specify precise relative + costs, but only that certain actions are more expensive than GCC would + ordinarily expect. */ + +#define SLOW_BYTE_ACCESS 0 +/* Define this macro as a C expression which is nonzero if accessing + less than a word of memory (i.e. a `char' or a `short') is no + faster than accessing a word of memory, i.e., if such access + require more than one instruction or if there is no difference in + cost between byte and (aligned) word loads. + + When this macro is not defined, the compiler will access a field by + finding the smallest containing object; when it is defined, a + fullword load will be used if alignment permits. Unless bytes + accesses are faster than word accesses, using word accesses is + preferable since it may eliminate subsequent memory access if + subsequent accesses occur to other fields in the same word of the + structure, but to different bytes. + + `SLOW_ZERO_EXTEND' + Define this macro if zero-extension (of a `char' or `short' to an + `int') can be done faster if the destination is a register that is + known to be zero. + + If you define this macro, you must have instruction patterns that + recognize RTL structures like this: + + (set (strict_low_part (subreg:QI (reg:SI ...) 0)) ...) + + and likewise for `HImode'. + + `SLOW_UNALIGNED_ACCESS' + Define this macro to be the value 1 if unaligned accesses have a + cost many times greater than aligned accesses, for example if they + are emulated in a trap handler. + + When this macro is non-zero, the compiler will act as if + `STRICT_ALIGNMENT' were non-zero when generating code for block + moves. This can cause significantly more instructions to be + produced. Therefore, do not set this macro non-zero if unaligned + accesses only add a cycle or two to the time for a memory access. + + If the value of this macro is always zero, it need not be defined. + + `DONT_REDUCE_ADDR' + Define this macro to inhibit strength reduction of memory + addresses. (On some machines, such strength reduction seems to do + harm rather than good.) + + `MOVE_RATIO' + The number of scalar move insns which should be generated instead + of a string move insn or a library call. Increasing the value + will always make code faster, but eventually incurs high cost in + increased code size. + + If you don't define this, a reasonable default is used. */ + +#define NO_FUNCTION_CSE +/* Define this macro if it is as good or better to call a constant + function address than to call an address kept in a register. */ + +#define NO_RECURSIVE_FUNCTION_CSE +/* Define this macro if it is as good or better for a function to call + itself with an explicit address than to call an address kept in a + register. + + `ADJUST_COST (INSN, LINK, DEP_INSN, COST)' + A C statement (sans semicolon) to update the integer variable COST + based on the relationship between INSN that is dependent on + DEP_INSN through the dependence LINK. The default is to make no + adjustment to COST. This can be used for example to specify to + the scheduler that an output- or anti-dependence does not incur + the same cost as a data-dependence. + + `ADJUST_PRIORITY (INSN)' + A C statement (sans semicolon) to update the integer scheduling + priority `INSN_PRIORITY(INSN)'. Reduce the priority to execute + the INSN earlier, increase the priority to execute INSN later. + Do not define this macro if you do not need to adjust the + scheduling priorities of insns. */ + + +#define TEXT_SECTION_ASM_OP "\t.text" +/* A C expression whose value is a string containing the assembler + operation that should precede instructions and read-only data. + Normally `"\t.text"' is right. */ + +#define DATA_SECTION_ASM_OP "\t.data" +/* A C expression whose value is a string containing the assembler + operation to identify the following data as writable initialized + data. Normally `"\t.data"' is right. */ + +#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section + +#define EXTRA_SECTIONS in_bootloader, in_infomem +/* A list of names for sections other than the standard two, which are + `in_text' and `in_data'. You need not define this macro on a + system with no other sections (that GCC needs to use). */ + +#define EXTRA_SECTION_FUNCTIONS \ + \ +void \ +bootloader_section (void) \ +{ \ + if (in_section != in_bootloader) \ + { \ + fprintf (asm_out_file, \ + "\t.section .bootloader, \"ax\", @progbits\n"); \ + /* Should already be aligned, this is just to be safe if it isn't. */ \ + fprintf (asm_out_file, "\t.p2align 1\n"); \ + in_section = in_bootloader; \ + } \ +} \ + \ +void \ +infomem_section (void) \ +{ \ + if (in_section != in_infomem) \ + { \ + fprintf (asm_out_file, \ + "\t.section .infomem, \"a\", @progbits\n"); \ + /* Should already be aligned, this is just to be safe if it isn't. */ \ + fprintf (asm_out_file, "\t.p2align 1\n"); \ + in_section = in_infomem; \ + } \ +} + + +/* Define the pseudo-ops used to switch to the .ctors and .dtors sections. + There are no shared libraries on this target, and these sections are + placed in the read-only program memory, so they are not writable. */ + +#undef CTORS_SECTION_ASM_OP +#define CTORS_SECTION_ASM_OP "\t.global\t__do_global_ctors\n\t.section .ctors,\"a\",@progbits" + +#undef DTORS_SECTION_ASM_OP +#define DTORS_SECTION_ASM_OP "\t.global\t__do_global_dtors\n\t.section .dtors,\"a\",@progbits" + +#define TARGET_ASM_CONSTRUCTOR default_ctor_section_asm_out_constructor + +#define TARGET_ASM_DESTRUCTOR default_dtor_section_asm_out_destructor + +/* `EXTRA_SECTION_FUNCTIONS' + One or more functions to be defined in `varasm.c'. These + functions should do jobs analogous to those of `text_section' and + `data_section', for your additional sections. Do not define this + macro if you do not define `EXTRA_SECTIONS'. */ + +/* +#define READONLY_DATA_SECTION data_section + On most machines, read-only variables, constants, and jump tables + are placed in the text section. If this is not the case on your + machine, this macro should be defined to be the name of a function + (either `data_section' or a function defined in `EXTRA_SECTIONS') + that switches to the section to be used for read-only items. + + If these items should be placed in the text section, this macro + should not be defined. */ + +/* `SELECT_SECTION (EXP, RELOC)' + A C statement or statements to switch to the appropriate section + for output of EXP. You can assume that EXP is either a `VAR_DECL' + node or a constant of some sort. RELOC indicates whether the + initial value of EXP requires link-time relocations. Select the + section by calling `text_section' or one of the alternatives for + other sections. + + Do not define this macro if you put all read-only variables and + constants in the read-only data section (usually the text section). */ + +/* `SELECT_RTX_SECTION (MODE, RTX)' + A C statement or statements to switch to the appropriate section + for output of RTX in mode MODE. You can assume that RTX is some + kind of constant in RTL. The argument MODE is redundant except in + the case of a `const_int' rtx. Select the section by calling + `text_section' or one of the alternatives for other sections. + + Do not define this macro if you put all constants in the read-only + data section. */ + +#define JUMP_TABLES_IN_TEXT_SECTION 0 +/* Define this macro if jump tables (for `tablejump' insns) should be + output in the text section, along with the assembler instructions. + Otherwise, the readonly data section is used. + + This macro is irrelevant if there is no separate readonly data + section. */ + +/* ???? +#define ENCODE_SECTION_INFO(DECL) encode_section_info(DECL) + Define this macro if references to a symbol must be treated + differently depending on something about the variable or function + named by the symbol (such as what section it is in). + + The macro definition, if any, is executed immediately after the + rtl for DECL has been created and stored in `DECL_RTL (DECL)'. + The value of the rtl will be a `mem' whose address is a + `symbol_ref'. + + The usual thing for this macro to do is to record a flag in the + `symbol_ref' (such as `SYMBOL_REF_FLAG') or to store a modified + name string in the `symbol_ref' (if one bit is not enough + information). */ + + +#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \ + (VAR) = (SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*' || (SYMBOL_NAME)[0] == '@'); +/* `STRIP_NAME_ENCODING (VAR, SYM_NAME)' + Decode SYM_NAME and store the real name part in VAR, sans the + characters that encode section info. Define this macro if + `ENCODE_SECTION_INFO' alters the symbol's name string. */ +/* `UNIQUE_SECTION_P (DECL)' + A C expression which evaluates to true if DECL should be placed + into a unique section for some target-specific reason. If you do + not define this macro, the default is `0'. Note that the flag + `-ffunction-sections' will also cause functions to be placed into + unique sections. */ + +#define UNIQUE_SECTION(DECL, RELOC) unique_section (DECL, RELOC) +/* `UNIQUE_SECTION (DECL, RELOC)' + A C statement to build up a unique section name, expressed as a + STRING_CST node, and assign it to `DECL_SECTION_NAME (DECL)'. + RELOC indicates whether the initial value of EXP requires + link-time relocations. If you do not define this macro, GNU CC + will use the symbol name prefixed by `.' as the section name. */ + + +#define ASM_FILE_START(STREAM) asm_file_start (STREAM) +/* A C expression which outputs to the stdio stream STREAM some + appropriate text to go at the start of an assembler file. + + Normally this macro is defined to output a line containing + `#NO_APP', which is a comment that has no effect on most + assemblers but tells the GNU assembler that it can save time by not + checking for certain assembler constructs. + + On systems that use SDB, it is necessary to output certain + commands; see `attasm.h'. */ + +#define ASM_FILE_END(STREAM) asm_file_end (STREAM) +/* A C expression which outputs to the stdio stream STREAM some + appropriate text to go at the end of an assembler file. + + If this macro is not defined, the default is to output nothing + special at the end of the file. Most systems don't require any + definition. + + On systems that use SDB, it is necessary to output certain + commands; see `attasm.h'. */ + +#define ASM_COMMENT_START " ; " +/* A C string constant describing how to begin a comment in the target + assembler language. The compiler assumes that the comment will + end at the end of the line. */ + +#define ASM_APP_ON "/* #APP */\n" +/* A C string constant for text to be output before each `asm' + statement or group of consecutive ones. Normally this is + `"#APP"', which is a comment that has no effect on most assemblers + but tells the GNU assembler that it must check the lines that + follow for all valid assembler constructs. */ + +#define ASM_APP_OFF "/* #NOAPP */\n" +/* A C string constant for text to be output after each `asm' + statement or group of consecutive ones. Normally this is + `"#NO_APP"', which tells the GNU assembler to resume making the + time-saving assumptions that are valid for ordinary compiler + output. */ + +#define ASM_OUTPUT_SOURCE_LINE(STREAM, LINE) fprintf (STREAM,"/* line: %d */\n",LINE) +/* A C statement to output DBX or SDB debugging information before + code for line number LINE of the current source file to the stdio + stream STREAM. + + This macro need not be defined if the standard form of debugging + information for the debugger in use is appropriate. */ + +#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \ + asm_output_section_name(FILE, DECL, NAME, RELOC) + +/* `ASM_OUTPUT_SECTION_NAME (STREAM, DECL, NAME, RELOC)' + A C statement to output something to the assembler file to switch + to section NAME for object DECL which is either a `FUNCTION_DECL', + a `VAR_DECL' or `NULL_TREE'. RELOC indicates whether the initial + value of EXP requires link-time relocations. Some target formats + do not support arbitrary sections. Do not define this macro in + such cases. + + At present this macro is only used to support section attributes. + When this macro is undefined, section attributes are disabled. */ + +#define OBJC_PROLOGUE {} +/* A C statement to output any assembler statements which are + required to precede any Objective C object definitions or message + sending. The statement is executed only when compiling an + Objective C program. */ + + + +#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) fprintf (STREAM, "no double float %.20e\n", VALUE) +#define ASM_OUTPUT_FLOAT(STREAM, VALUE) asm_output_float (STREAM, VALUE) +/* `ASM_OUTPUT_LONG_DOUBLE (STREAM, VALUE)' + `ASM_OUTPUT_THREE_QUARTER_FLOAT (STREAM, VALUE)' + `ASM_OUTPUT_SHORT_FLOAT (STREAM, VALUE)' + `ASM_OUTPUT_BYTE_FLOAT (STREAM, VALUE)' + A C statement to output to the stdio stream STREAM an assembler + instruction to assemble a floating-point constant of `TFmode', + `DFmode', `SFmode', `TQFmode', `HFmode', or `QFmode', + respectively, whose value is VALUE. VALUE will be a C expression + of type `REAL_VALUE_TYPE'. Macros such as + `REAL_VALUE_TO_TARGET_DOUBLE' are useful for writing these + definitions. */ + + +#define ASM_OUTPUT_INT(FILE, VALUE) \ + ( fprintf (FILE, "\t.long "), \ + output_addr_const (FILE, (VALUE)), \ + fputs ("\n", FILE)) + + /* Likewise for `short' and `char' constants. */ + +#define ASM_OUTPUT_SHORT(FILE,VALUE) asm_output_short(FILE,VALUE) +#define ASM_OUTPUT_CHAR(FILE,VALUE) asm_output_char(FILE,VALUE) + +/* `ASM_OUTPUT_QUADRUPLE_INT (STREAM, EXP)' + A C statement to output to the stdio stream STREAM an assembler + instruction to assemble an integer of 16, 8, 4, 2 or 1 bytes, + respectively, whose value is VALUE. The argument EXP will be an + RTL expression which represents a constant value. Use + `output_addr_const (STREAM, EXP)' to output this value as an + assembler expression. + + For sizes larger than `UNITS_PER_WORD', if the action of a macro + would be identical to repeatedly calling the macro corresponding to + a size of `UNITS_PER_WORD', once for each word, you need not define + the macro. */ + + +#define ASM_OUTPUT_BYTE(FILE,VALUE) asm_output_byte (FILE,VALUE) +/* A C statement to output to the stdio stream STREAM an assembler + instruction to assemble a single byte containing the number VALUE. */ + +#define ASM_BYTE_OP "\t.byte " +/* A C string constant giving the pseudo-op to use for a sequence of + single-byte constants. If this macro is not defined, the default + is `"\t.byte\t"'. */ + +#define ASM_OUTPUT_ASCII(FILE, P, SIZE) gas_output_ascii (FILE,P,SIZE) +/* `ASM_OUTPUT_ASCII (STREAM, PTR, LEN)' + output_ascii (FILE, P, SIZE) + A C statement to output to the stdio stream STREAM an assembler + instruction to assemble a string constant containing the LEN bytes + at PTR. PTR will be a C expression of type `char *' and LEN a C + expression of type `int'. + + If the assembler has a `.ascii' pseudo-op as found in the Berkeley + Unix assembler, do not define the macro `ASM_OUTPUT_ASCII'. */ + +#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == '\n') +/* Define this macro as a C expression which is nonzero if C is used + as a logical line separator by the assembler. + + If you do not define this macro, the default is that only the + character `;' is treated as a logical line separator. */ + +/* +#define ASM_OPEN_PAREN "(" +#define ASM_CLOSE_PAREN ")" + These macros are defined as C string constant, describing the + syntax in the assembler for grouping arithmetic expressions. The + following definitions are correct for most assemblers: + + #define ASM_OPEN_PAREN "(" + #define ASM_CLOSE_PAREN ")" + + These macros are provided by `real.h' for writing the definitions of + `ASM_OUTPUT_DOUBLE' and the like: */ + +/* Here we much catch r0 - r15 variable names */ + +#define ASM_OUTPUT_LABELREF(FILE,NAME) \ +do{ \ + char *p = NAME; \ + while(*p == '_') p++; \ + if(*p == 'r' || *p == 'R') \ + { \ + int val; \ + char *endptr; \ + p++; \ + val = strtol (p, &endptr, 10); \ + if(val >= 0 && val <= 15 && \ + *endptr == 0 ) \ + { \ + asm_fprintf ((FILE), "_%U%s", (NAME)); \ + } \ + else \ + asm_fprintf ((FILE), "%U%s", (NAME)); \ + } \ + else \ + asm_fprintf ((FILE), "%U%s", (NAME)); \ +} while(0) + +/* macros to output uninitialized variable definitions */ + +/* Return a non-zero value if DECL has a section attribute. */ +#define IN_NAMED_SECTION(DECL) \ + ((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \ + && DECL_SECTION_NAME (DECL) != NULL_TREE) + +/* macro to output uninitialized varible in normal case where -fno-common is not specified */ + +#undef ASM_OUTPUT_ALIGNED_DECL_COMMON +#define ASM_OUTPUT_ALIGNED_DECL_COMMON(FILE, DECL, NAME, SIZE, ALIGN) \ + do \ + { \ + char *p = NAME; \ + if(*p == '*' || *p == '@' ) p++; \ + if(*p >= '0' && *p <= '9' ) break; \ + if (IN_NAMED_SECTION (DECL)) \ + { \ + /* case where -fdata-sections is specified */ \ + named_section (DECL, NULL, 0); \ + ASM_GLOBALIZE_LABEL (FILE, NAME); \ + ASM_OUTPUT_ALIGN (FILE, floor_log2 (ALIGN / BITS_PER_UNIT)); \ + last_assemble_variable_decl = DECL; \ + ASM_DECLARE_OBJECT_NAME (FILE, NAME, DECL); \ + ASM_OUTPUT_SKIP (FILE, SIZE ? SIZE : 1); \ + } \ + else \ + { \ + /* default case */ \ + fputs ("\t.comm ", (FILE)); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ",%d%s", (SIZE), (SIZE)>1?",2\n":"\n"); \ + } \ + } \ + while (0) + + +/* macro to output uninitialized variable when -fno-common _is_ specified */ +#undef ASM_OUTPUT_ALIGNED_BSS +#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \ + do \ + { \ + char *p = NAME; \ + if(*p == '*' || *p == '@' ) p++; \ + if(*p >= '0' && *p <= '9' ) break; \ + if (IN_NAMED_SECTION (DECL)) \ + named_section (DECL, NULL, 0); \ + else \ + bss_section (); \ + \ + ASM_OUTPUT_ALIGN (FILE, floor_log2 (ALIGN / BITS_PER_UNIT)); \ + \ + last_assemble_variable_decl = DECL; \ + ASM_DECLARE_OBJECT_NAME (FILE, NAME, DECL); \ + ASM_OUTPUT_SKIP (FILE, SIZE ? SIZE : 1); \ + } \ + while (0) + + +#undef ASM_OUTPUT_ALIGNED_DECL_LOCAL +#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN) \ + do \ + { \ + char *p = NAME; \ + if(*p == '*' || *p == '@' ) p++; \ + if(*p >= '0' && *p <= '9' ) break; \ + if ((DECL) != NULL && IN_NAMED_SECTION (DECL)) \ + named_section (DECL, NULL, 0); \ + else \ + bss_section (); \ + \ + ASM_OUTPUT_ALIGN (FILE, floor_log2 (ALIGN / BITS_PER_UNIT)); \ + ASM_OUTPUT_LABEL (FILE, NAME); \ + fprintf (FILE, "\t.space\t%d\n", SIZE); \ + } \ + while (0) + +#define BSS_SECTION_ASM_OP "\t.section\t.bss" +/* If defined, a C expression whose value is a string containing the + assembler operation to identify the following data as + uninitialized global data. If not defined, and neither + 'ASM_OUTPUT_BSS' nor 'ASM_OUTPUT_ALIGNED_BSS' are defined, + uninitialized global data will be output in the data section if + -fno-common' is passed, otherwise 'ASM_OUTPUT_COMMON' will be + used. +*/ + + + +#define ASM_OUTPUT_LABEL(STREAM, NAME) \ +{ \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, ":\n"); \ +} +/* A C statement (sans semicolon) to output to the stdio stream + STREAM the assembler definition of a label named NAME. Use the + expression `assemble_name (STREAM, NAME)' to output the name + itself; before and after that, output the additional assembler + syntax for defining the name, and a newline. */ + +#undef TYPE_ASM_OP +#undef SIZE_ASM_OP +#undef WEAK_ASM_OP +#define TYPE_ASM_OP "\t.type\t" +#define SIZE_ASM_OP "\t.size\t" +#define WEAK_ASM_OP "\t.weak\t" +/* Define the strings used for the special svr4 .type and .size directives. + These strings generally do not vary from one system running svr4 to + another, but if a given system (e.g. m88k running svr) needs to use + different pseudo-op names for these, they may be overridden in the + file which includes this one. */ + + +#undef TYPE_OPERAND_FMT +#define TYPE_OPERAND_FMT "@%s" +/* The following macro defines the format used to output the second + operand of the .type assembler directive. Different svr4 assemblers + expect various different forms for this operand. The one given here + is just a default. You may need to override it in your machine- + specific tm.h file (depending upon the particulars of your assembler). */ + + +#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ +asm_declare_function_name (FILE, NAME, DECL) + + +/* A C statement (sans semicolon) to output to the stdio stream + STREAM any text necessary for declaring the name NAME of a + function which is being defined. This macro is responsible for + outputting the label definition (perhaps using + `ASM_OUTPUT_LABEL'). The argument DECL is the `FUNCTION_DECL' + tree node representing the function. + + If this macro is not defined, then the function name is defined in + the usual manner as a label (by means of `ASM_OUTPUT_LABEL'). */ + +#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \ + do { \ + if (!flag_inhibit_size_directive) \ + { \ + char label[256]; \ + static int labelno; \ + labelno++; \ + ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ + assemble_name (FILE, (FNAME)); \ + fprintf (FILE, ","); \ + assemble_name (FILE, label); \ + fprintf (FILE, "-"); \ + assemble_name (FILE, (FNAME)); \ + fprintf (FILE,"\n/********* End of function ******/\n\n"); \ + } \ + } while (0) +/* A C statement (sans semicolon) to output to the stdio stream + STREAM any text necessary for declaring the size of a function + which is being defined. The argument NAME is the name of the + function. The argument DECL is the `FUNCTION_DECL' tree node + representing the function. + + If this macro is not defined, then the function size is not + defined. */ + +#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \ +do { \ + fprintf (FILE, "%s", TYPE_ASM_OP); \ + assemble_name (FILE, NAME); \ + putc (',', FILE); \ + fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ + putc ('\n', FILE); \ + size_directive_output = 0; \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \ + { \ + size_directive_output = 1; \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ + assemble_name (FILE, NAME); \ + fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ + } \ + ASM_OUTPUT_LABEL(FILE, NAME); \ +} while (0) +/* A C statement (sans semicolon) to output to the stdio stream + STREAM any text necessary for declaring the name NAME of an + initialized variable which is being defined. This macro must + output the label definition (perhaps using `ASM_OUTPUT_LABEL'). + The argument DECL is the `VAR_DECL' tree node representing the + variable. + + If this macro is not defined, then the variable name is defined in + the usual manner as a label (by means of `ASM_OUTPUT_LABEL'). */ + +#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \ +do { \ + const char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \ + if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \ + && ! AT_END && TOP_LEVEL \ + && DECL_INITIAL (DECL) == error_mark_node \ + && !size_directive_output) \ + { \ + size_directive_output = 1; \ + fprintf (FILE, "%s", SIZE_ASM_OP); \ + assemble_name (FILE, name); \ + fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \ + } \ + } while (0) +/* A C statement (sans semicolon) to finish up declaring a variable + name once the compiler has processed its initializer fully and + thus has had a chance to determine the size of an array when + controlled by an initializer. This is used on systems where it's + necessary to declare something about the size of the object. + + If you don't define this macro, that is equivalent to defining it + to do nothing. */ + + +#define ESCAPES \ +"\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ +\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0\ +\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\ +\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1" +/* A table of bytes codes used by the ASM_OUTPUT_ASCII and + ASM_OUTPUT_LIMITED_STRING macros. Each byte in the table + corresponds to a particular byte value [0..255]. For any + given byte value, if the value in the corresponding table + position is zero, the given character can be output directly. + If the table value is 1, the byte must be output as a \ooo + octal escape. If the tables value is anything else, then the + byte value should be output as a \ followed by the value + in the table. Note that we can use standard UN*X escape + sequences for many control characters, but we don't use + \a to represent BEL because some svr4 assemblers (e.g. on + the i386) don't know about that. Also, we don't use \v + since some versions of gas, such as 2.2 did not accept it. */ + +#define STRING_LIMIT ((unsigned) 64) +#define STRING_ASM_OP "\t.string\t" +/* Some svr4 assemblers have a limit on the number of characters which + can appear in the operand of a .string directive. If your assembler + has such a limitation, you should define STRING_LIMIT to reflect that + limit. Note that at least some svr4 assemblers have a limit on the + actual number of bytes in the double-quoted string, and that they + count each character in an escape sequence as one byte. Thus, an + escape sequence like \377 would count as four bytes. + + If your target assembler doesn't support the .string directive, you + should define this to zero. */ + +#define ASM_GLOBALIZE_LABEL(STREAM, NAME) \ +do { \ + char *p = NAME; \ + if(*p == '*' || *p == '@' ) p++; \ + if(*p >= '0' && *p <= '9' ) break; \ + fprintf (STREAM, ".global\t"); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, "\n"); \ +} \ +while (0) + +/* A C statement (sans semicolon) to output to the stdio stream + STREAM some commands that will make the label NAME global; that + is, available for reference from other files. Use the expression + `assemble_name (STREAM, NAME)' to output the name itself; before + and after that, output the additional assembler syntax for making + that name global, and a newline. */ + +#define ASM_WEAKEN_LABEL(FILE, NAME) \ + do \ + { \ + fputs ("\t.weak\t", (FILE)); \ + assemble_name ((FILE), (NAME)); \ + fputc ('\n', (FILE)); \ + } \ + while (0) + +/* A C statement (sans semicolon) to output to the stdio stream + STREAM some commands that will make the label NAME weak; that is, + available for reference from other files but only used if no other + definition is available. Use the expression `assemble_name + (STREAM, NAME)' to output the name itself; before and after that, + output the additional assembler syntax for making that name weak, + and a newline. + + If you don't define this macro, GNU CC will not support weak + symbols and you should not define the `SUPPORTS_WEAK' macro. +*/ + +#define SUPPORTS_WEAK 1 +/* A C expression which evaluates to true if the target supports weak + symbols. + + If you don't define this macro, `defaults.h' provides a default + definition. If `ASM_WEAKEN_LABEL' is defined, the default + definition is `1'; otherwise, it is `0'. Define this macro if you + want to control weak symbol support with a compiler flag such as + `-melf'. + + `MAKE_DECL_ONE_ONLY' + A C statement (sans semicolon) to mark DECL to be emitted as a + public symbol such that extra copies in multiple translation units + will be discarded by the linker. Define this macro if your object + file format provides support for this concept, such as the `COMDAT' + section flags in the Microsoft Windows PE/COFF format, and this + support requires changes to DECL, such as putting it in a separate + section. + + `SUPPORTS_WEAK' + A C expression which evaluates to true if the target supports + one-only semantics. + + If you don't define this macro, `varasm.c' provides a default + definition. If `MAKE_DECL_ONE_ONLY' is defined, the default + definition is `1'; otherwise, it is `0'. Define this macro if you + want to control weak symbol support with a compiler flag, or if + setting the `DECL_ONE_ONLY' flag is enough to mark a declaration to + be emitted as one-only. */ + +#define ASM_OUTPUT_INTERNAL_LABEL(STREAM, PREFIX, NUM) \ +fprintf(STREAM, ".%s%d:\n", PREFIX, NUM) +/* A C statement to output to the stdio stream STREAM a label whose + name is made from the string PREFIX and the number NUM. + + It is absolutely essential that these labels be distinct from the + labels used for user-level functions and variables. Otherwise, + certain programs will have name conflicts with internal labels. + + It is desirable to exclude internal labels from the symbol table + of the object file. Most assemblers have a naming convention for + labels that should be excluded; on many systems, the letter `L' at + the beginning of a label has this effect. You should find out what + convention your system uses, and follow it. + + The usual definition of this macro is as follows: + + fprintf (STREAM, "L%s%d:\n", PREFIX, NUM) */ + +#define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM) \ +sprintf (STRING, "*.%s%d", PREFIX, NUM) +/* A C statement to store into the string STRING a label whose name + is made from the string PREFIX and the number NUM. + + This string, when output subsequently by `assemble_name', should + produce the output that `ASM_OUTPUT_INTERNAL_LABEL' would produce + with the same PREFIX and NUM. + + If the string begins with `*', then `assemble_name' will output + the rest of the string unchanged. It is often convenient for + `ASM_GENERATE_INTERNAL_LABEL' to use `*' in this way. If the + string doesn't start with `*', then `ASM_OUTPUT_LABELREF' gets to + output the string, and may change it. (Of course, + `ASM_OUTPUT_LABELREF' is also part of your machine description, so + you should know what it does on your machine.) */ + +#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ +( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \ + sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO))) + +/* A C expression to assign to OUTVAR (which is a variable of type + `char *') a newly allocated string made from the string NAME and + the number NUMBER, with some suitable punctuation added. Use + `alloca' to get space for the string. + + The string will be used as an argument to `ASM_OUTPUT_LABELREF' to + produce an assembler label for an internal static variable whose + name is NAME. Therefore, the string must be such as to result in + valid assembler code. The argument NUMBER is different each time + this macro is executed; it prevents conflicts between + similarly-named internal static variables in different scopes. + + Ideally this string should not be a valid C identifier, to prevent + any conflict with the user's own symbols. Most assemblers allow + periods or percent signs in assembler symbols; putting at least + one of these between the name and the number will suffice. */ + +/* `ASM_OUTPUT_WEAK_ALIAS (STREAM, NAME, VALUE)' + A C statement to output to the stdio stream STREAM assembler code + which defines (equates) the weak symbol NAME to have the value + VALUE. + + Define this macro if the target only supports weak aliases; define + ASM_OUTPUT_DEF instead if possible. */ + +#define HAS_INIT_SECTION 1 +/* If defined, `main' will not call `__main' as described above. + This macro should be defined for systems that control the contents + of the init section on a symbol-by-symbol basis, such as OSF/1, + and should not be defined explicitly for systems that support + `INIT_SECTION_ASM_OP'. */ + +#define REGISTER_NAMES { \ + "r0","r1","r2","r3","r4","r5","r6","r7", \ + "r8","r9","r10","r11","r12","r13","r14","r15" \ +} +/* A C initializer containing the assembler's names for the machine + registers, each one as a C string constant. This is what + translates register numbers in the compiler into assembler + language. */ + +#define FINAL_PRESCAN_INSN(insn, operand, nop) final_prescan_insn (insn, operand,nop) +/* If defined, a C statement to be executed just prior to the output + of assembler code for INSN, to modify the extracted operands so + they will be output differently. + + Here the argument OPVEC is the vector containing the operands + extracted from INSN, and NOPERANDS is the number of elements of + the vector which contain meaningful data for this insn. The + contents of this vector are what will be used to convert the insn + template into assembler code, so you can change the assembler + output by changing the contents of the vector. + + This macro is useful when various assembler syntaxes share a single + file of instruction patterns; by defining this macro differently, + you can cause a large class of instructions to be output + differently (such as with rearranged operands). Naturally, + variations in assembler syntax affecting individual insn patterns + ought to be handled by writing conditional output routines in + those patterns. + + If this macro is not defined, it is equivalent to a null statement. */ + +#define PRINT_OPERAND(STREAM, X, CODE) print_operand (STREAM, X, CODE) +/* A C compound statement to output to stdio stream STREAM the + assembler syntax for an instruction operand X. X is an RTL + expression. + + CODE is a value that can be used to specify one of several ways of + printing the operand. It is used when identical operands must be + printed differently depending on the context. CODE comes from the + `%' specification that was used to request printing of the + operand. If the specification was just `%DIGIT' then CODE is 0; + if the specification was `%LTR DIGIT' then CODE is the ASCII code + for LTR. + + If X is a register, this macro should print the register's name. + The names can be found in an array `reg_names' whose type is `char + *[]'. `reg_names' is initialized from `REGISTER_NAMES'. + + When the machine description has a specification `%PUNCT' (a `%' + followed by a punctuation character), this macro is called with a + null pointer for X and the punctuation character for CODE. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '~') +/* A C expression which evaluates to true if CODE is a valid + punctuation character for use in the `PRINT_OPERAND' macro. If + `PRINT_OPERAND_PUNCT_VALID_P' is not defined, it means that no + punctuation characters (except for the standard one, `%') are used + in this way. */ + +#define PRINT_OPERAND_ADDRESS(STREAM, X) print_operand_address(STREAM, X) +/* A C compound statement to output to stdio stream STREAM the + assembler syntax for an instruction operand that is a memory + reference whose address is X. X is an RTL expression. + + On some machines, the syntax for a symbolic address depends on the + section that the address refers to. On these machines, define the + macro `ENCODE_SECTION_INFO' to store the information into the + `symbol_ref', and then check for it here. *Note Assembler + Format::. */ + +#define USER_LABEL_PREFIX "" +/* `LOCAL_LABEL_PREFIX' + `REGISTER_PREFIX' + `IMMEDIATE_PREFIX' + If defined, C string expressions to be used for the `%R', `%L', + `%U', and `%I' options of `asm_fprintf' (see `final.c'). These + are useful when a single `md' file must support multiple assembler + formats. In that case, the various `tm.h' files can define these + macros differently. */ + +#define ASSEMBLER_DIALECT MSP430_HAS_HWMUL_INTERNAL +/* If your target supports multiple dialects of assembler language + (such as different opcodes), define this macro as a C expression + that gives the numeric index of the assembler language dialect to + use, with zero as the first variant. + + If this macro is defined, you may use constructs of the form + `{option0|option1|option2...}' in the output templates of patterns + (*note Output Template::.) or in the first argument of + `asm_fprintf'. This construct outputs `option0', `option1' or + `option2', etc., if the value of `ASSEMBLER_DIALECT' is zero, one + or two, etc. Any special characters within these strings retain + their usual meaning. + + If you do not define this macro, the characters `{', `|' and `}' + do not have any special meaning when used in templates or operands + to `asm_fprintf'. + + Define the macros `REGISTER_PREFIX', `LOCAL_LABEL_PREFIX', + `USER_LABEL_PREFIX' and `IMMEDIATE_PREFIX' if you can express the + variations in assembler language syntax with that mechanism. + Define `ASSEMBLER_DIALECT' and use the `{option0|option1}' syntax + if the syntax variant are larger and involve such things as + different opcodes or operand order. */ + +#define ASM_OUTPUT_REG_PUSH(STREAM, REGNO) \ +{ \ + if (REGNO > 15) \ + abort (); \ + fprintf (STREAM, "\tpush\tr%d", REGNO); \ +} +/* A C expression to output to STREAM some assembler code which will + push hard register number REGNO onto the stack. The code need not + be optimal, since this macro is used only when profiling. */ + +#define ASM_OUTPUT_REG_POP(STREAM, REGNO) \ +{ \ + if (REGNO > 15) \ + abort (); \ + fprintf (STREAM, "\tpop\tr%d", REGNO); \ +} +/* A C expression to output to STREAM some assembler code which will + pop hard register number REGNO off of the stack. The code need + not be optimal, since this macro is used only when profiling. */ + +#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \ + msp430_output_addr_vec_elt(STREAM, VALUE) +/* This macro should be provided on machines where the addresses in a + dispatch table are absolute. + + The definition should be a C statement to output to the stdio + stream STREAM an assembler pseudo-instruction to generate a + reference to a label. VALUE is the number of an internal label + whose definition is output using `ASM_OUTPUT_INTERNAL_LABEL'. For + example, + + fprintf (STREAM, "\t.word L%d\n", VALUE) */ + +/* +#define ASM_OUTPUT_CASE_LABEL(STREAM, PREFIX, NUM, TABLE) \ + progmem_section (), ASM_OUTPUT_INTERNAL_LABEL (STREAM, PREFIX, NUM) + + `ASM_OUTPUT_CASE_LABEL (STREAM, PREFIX, NUM, TABLE)' + Define this if the label before a jump-table needs to be output + specially. The first three arguments are the same as for + `ASM_OUTPUT_INTERNAL_LABEL'; the fourth argument is the jump-table + which follows (a `jump_insn' containing an `addr_vec' or + `addr_diff_vec'). + + This feature is used on system V to output a `swbeg' statement for + the table. + + If this macro is not defined, these labels are output with + `ASM_OUTPUT_INTERNAL_LABEL'. */ + +/* `ASM_OUTPUT_CASE_END (STREAM, NUM, TABLE)' + Define this if something special must be output at the end of a + jump-table. The definition should be a C statement to be executed + after the assembler code for the table is written. It should write + the appropriate code to stdio stream STREAM. The argument TABLE + is the jump-table insn, and NUM is the label-number of the + preceding label. + + If this macro is not defined, nothing special is output at the end + of the jump-table. */ + +#ifndef SET_ASM_OP +#define SET_ASM_OP "\t.set\t" +#endif + +#define ASM_OUTPUT_SKIP(STREAM, N) \ +fprintf (STREAM, "\t.skip %d,0\n", N) +/* A C statement to output to the stdio stream STREAM an assembler + instruction to advance the location counter by NBYTES bytes. + Those bytes should be zero when loaded. NBYTES will be a C + expression of type `int'. */ + +#define ASM_OUTPUT_ALIGN(STREAM, POWER) \ +fprintf (STREAM, "\t.p2align %d,0\n", POWER) +/* A C statement to output to the stdio stream STREAM an assembler + command to advance the location counter to a multiple of 2 to the + POWER bytes. POWER will be a C expression of type `int'. */ + +#define CASE_VECTOR_MODE HImode +/* An alias for a machine mode name. This is the machine mode that + elements of a jump-table should have. */ + + +#define PREDICATE_CODES \ +{"memory_operand_msp430", {SUBREG, MEM}}, \ +{"nonimmediate_operand_msp430", {SUBREG, REG, MEM}},\ +{"general_operand_msp430", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, LABEL_REF, SUBREG, REG, MEM}},\ +{"three_operands_msp430", {PLUS, MINUS, AND, IOR, XOR}}, \ +{"equality_operator", {EQ, NE }}, \ +{"inequality_operator", {GE, GT, LE, LT, GEU, GTU, LEU, LTU }}, + + + + +extern struct rtx_def *msp430_compare_op0, *msp430_compare_op1; + + +extern int msp430_case_values_threshold; + +#define CASE_VALUES_THRESHOLD msp430_case_values_threshold +/* `CASE_VALUES_THRESHOLD' + Define this to be the smallest number of different values for + which it is best to use a jump-table instead of a tree of + conditional branches. The default is four for machines with a + `casesi' instruction and five otherwise. This is best for most + machines. */ + +#undef WORD_REGISTER_OPERATIONS +/* Define this macro if operations between registers with integral + mode smaller than a word are always performed on the entire + register. Most RISC machines have this property and most CISC + machines do not. */ + +/* +#define EASY_DIV_EXPR TRUNC_DIV_EXPR + An alias for a tree code that is the easiest kind of division to + compile code for in the general case. It may be `TRUNC_DIV_EXPR', + `FLOOR_DIV_EXPR', `CEIL_DIV_EXPR' or `ROUND_DIV_EXPR'. These four + division operators differ in how they round the result to an + integer. `EASY_DIV_EXPR' is used when it is permissible to use + any of those kinds of division and the choice should be made on + the basis of efficiency. */ + +#define MOVE_MAX 2 +/* The maximum number of bytes that a single instruction can move + quickly between memory and registers or between two memory + locations. */ + +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 +/* A C expression which is nonzero if on this machine it is safe to + "convert" an integer of INPREC bits to one of OUTPREC bits (where + OUTPREC is smaller than INPREC) by merely operating on it as if it + had only OUTPREC bits. + + On many machines, this expression can be 1. + + When `TRULY_NOOP_TRUNCATION' returns 1 for a pair of sizes for + modes for which `MODES_TIEABLE_P' is 0, suboptimal code can result. + If this is the case, making `TRULY_NOOP_TRUNCATION' return 0 in + such cases may improve things. */ + +#define Pmode HImode +/* An alias for the machine mode for pointers. On most machines, + define this to be the integer mode corresponding to the width of a + hardware pointer; `SImode' on 32-bit machine or `DImode' on 64-bit + machines. On some machines you must define this to be one of the + partial integer modes, such as `PSImode'. + + The width of `Pmode' must be at least as large as the value of + `POINTER_SIZE'. If it is not equal, you must define the macro + `POINTERS_EXTEND_UNSIGNED' to specify how pointers are extended to + `Pmode'. */ + +#define FUNCTION_MODE HImode +/* An alias for the machine mode used for memory references to + functions being called, in `call' RTL expressions. On most + machines this should be `QImode'. */ + /* 1 3 */ +#define INTEGRATE_THRESHOLD(DECL) (1 + (3 * list_length (DECL_ARGUMENTS (DECL)) / 2)) + +/* A C expression for the maximum number of instructions above which + the function DECL should not be inlined. DECL is a + `FUNCTION_DECL' node. + + The default definition of this macro is 64 plus 8 times the number + of arguments that the function accepts. Some people think a larger + threshold should be used on RISC machines. */ + +/* +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ +valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + `VALID_MACHINE_DECL_ATTRIBUTE (DECL, ATTRIBUTES, IDENTIFIER, ARGS)' + If defined, a C expression whose value is nonzero if IDENTIFIER + with arguments ARGS is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ + +/* +#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, IDENTIFIER, ARGS) \ + valid_machine_type_attribute(TYPE, ATTRIBUTES, IDENTIFIER, ARGS) + `VALID_MACHINE_TYPE_ATTRIBUTE (TYPE, ATTRIBUTES, IDENTIFIER, ARGS)' + If defined, a C expression whose value is nonzero if IDENTIFIER + with arguments ARGS is a valid machine specific attribute for TYPE. + The attributes in ATTRIBUTES have previously been assigned to TYPE. */ + +#define DOLLARS_IN_IDENTIFIERS 0 +/* Define this macro to control use of the character `$' in identifier + names. 0 means `$' is not allowed by default; 1 means it is + allowed. 1 is the default; there is no need to define this macro + in that case. This macro controls the compiler proper; it does + not affect the preprocessor. */ + +#define NO_DOLLAR_IN_LABEL 1 +/* Define this macro if the assembler does not accept the character + `$' in label names. By default constructors and destructors in + G++ have `$' in the identifiers. If this macro is defined, `.' is + used instead. */ + +#define MACHINE_DEPENDENT_REORG(INSN) machine_dependent_reorg (INSN) +/* In rare cases, correct code generation requires extra machine + dependent processing between the second jump optimization pass and + delayed branch scheduling. On those machines, define this macro + as a C statement to act on the code starting at INSN. */ + +#define GIV_SORT_CRITERION(X, Y) \ + if (GET_CODE ((X)->add_val) == CONST_INT \ + && GET_CODE ((Y)->add_val) == CONST_INT) \ + return INTVAL ((X)->add_val) - INTVAL ((Y)->add_val); + +/* `GIV_SORT_CRITERION(GIV1, GIV2)' + In some cases, the strength reduction optimization pass can + produce better code if this is defined. This macro controls the + order that induction variables are combined. This macro is + particularly useful if the target has limited addressing modes. + For instance, the SH target has only positive offsets in + addresses. Thus sorting to put the smallest address first allows + the most combinations to be found. */ + +/* Define results of standard character escape sequences. */ +#define TARGET_BELL 007 +#define TARGET_BS 010 +#define TARGET_TAB 011 +#define TARGET_NEWLINE 012 +#define TARGET_VT 013 +#define TARGET_FF 014 +#define TARGET_CR 015 +#define TARGET_ESC 033 + +#define TRAMPOLINE_TEMPLATE(FILE) msp430_trampoline_template((FILE)) + +#define TRAMPOLINE_SIZE 8 +#define TRAMPOLINE_ALIGNMENT 16 + + +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ + msp430_initialize_trampoline (TRAMP, FNADDR, CXT) + + +/* Store in cc_status the expressions + that the condition codes will describe + after execution of an instruction whose pattern is EXP. + Do not alter them if the instruction would not alter the cc's. */ + +#define NOTICE_UPDATE_CC(EXP, INSN) notice_update_cc(EXP, INSN) + +/* The add insns don't set overflow in a usable way. */ +#define CC_OVERFLOW_UNUSABLE 01000 +/* The mov,and,or,xor insns don't set carry. That's ok though as the + Z bit is all we need when doing unsigned comparisons on the result of + these insns (since they're always with 0). However, conditions.h has + CC_NO_OVERFLOW defined for this purpose. Rename it to something more + understandable. */ +#define CC_NO_CARRY CC_NO_OVERFLOW + + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "/* profiler %d */", (LABELNO)) + +/* `FIRST_INSN_ADDRESS' + When the `length' insn attribute is used, this macro specifies the + value to be assigned to the address of the first insn in a + function. If not specified, 0 is used. */ + +#define ADJUST_INSN_LENGTH(INSN, LENGTH) (LENGTH =\ + adjust_insn_length (INSN, LENGTH)) +/* If defined, modifies the length assigned to instruction INSN as a + function of the context in which it is used. LENGTH is an lvalue + that contains the initially computed length of the insn and should + be updated with the correct length of the insn. If updating is + required, INSN must not be a varying-length insn. + + This macro will normally not be required. A case in which it is + required is the ROMP. On this machine, the size of an `addr_vec' + insn must be increased by two to compensate for the fact that + alignment may be required. */ + +#define TARGET_MEM_FUNCTIONS +/* Define this macro if GNU CC should generate calls to the System V + (and ANSI C) library functions `memcpy' and `memset' rather than + the BSD functions `bcopy' and `bzero'. */ + +#define CPP_SPEC "\ +%{!mmcu*|mmcu=msp1:%(cpp_msp1)} \ +%{mmcu=msp2:%(cpp_msp2) -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x110:%(cpp_msp1) -D__MSP430_110__} \ +%{mmcu=msp430x112:%(cpp_msp1) -D__MSP430_112__} \ +%{mmcu=msp430x1101:%(cpp_msp1) -D__MSP430_1101__} \ +%{mmcu=msp430x1111:%(cpp_msp1) -D__MSP430_1111__} \ +%{mmcu=msp430x1121:%(cpp_msp1) -D__MSP430_1121__} \ +%{mmcu=msp430x1122:%(cpp_msp1) -D__MSP430_1122__} \ +%{mmcu=msp430x1132:%(cpp_msp1) -D__MSP430_1132__} \ +%{mmcu=msp430x122:%(cpp_msp1) -D__MSP430_122__} \ +%{mmcu=msp430x123:%(cpp_msp1) -D__MSP430_123__} \ +%{mmcu=msp430x1222:%(cpp_msp1) -D__MSP430_1222__} \ +%{mmcu=msp430x1232:%(cpp_msp1) -D__MSP430_1232__} \ +%{mmcu=msp430x133:%(cpp_msp1) -D__MSP430_133__} \ +%{mmcu=msp430x135:%(cpp_msp1) -D__MSP430_135__} \ +%{mmcu=msp430x1331:%(cpp_msp1) -D__MSP430_1331__} \ +%{mmcu=msp430x1351:%(cpp_msp1) -D__MSP430_1351__} \ +%{mmcu=msp430x147:%(cpp_msp2) -D__MSP430_147__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x148:%(cpp_msp2) -D__MSP430_148__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x149:%(cpp_msp2) -D__MSP430_149__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x1471:%(cpp_msp2) -D__MSP430_1471__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x1481:%(cpp_msp2) -D__MSP430_1481__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x1491:%(cpp_msp2) -D__MSP430_1491__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x155:%(cpp_msp1) -D__MSP430_155__} \ +%{mmcu=msp430x156:%(cpp_msp1) -D__MSP430_156__} \ +%{mmcu=msp430x157:%(cpp_msp1) -D__MSP430_157__} \ +%{mmcu=msp430x167:%(cpp_msp2) -D__MSP430_167__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x168:%(cpp_msp2) -D__MSP430_168__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x169:%(cpp_msp2) -D__MSP430_169__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x1610:%(cpp_msp2) -D__MSP430_1610__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x1611:%(cpp_msp2) -D__MSP430_1611__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x1612:%(cpp_msp2) -D__MSP430_1612__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2001:%(cpp_msp1) -D__MSP430_2001__} \ +%{mmcu=msp430x2011:%(cpp_msp1) -D__MSP430_2011__} \ +%{mmcu=msp430x2002:%(cpp_msp1) -D__MSP430_2002__} \ +%{mmcu=msp430x2012:%(cpp_msp1) -D__MSP430_2012__} \ +%{mmcu=msp430x2003:%(cpp_msp1) -D__MSP430_2003__} \ +%{mmcu=msp430x2013:%(cpp_msp1) -D__MSP430_2013__} \ +%{mmcu=msp430x2101:%(cpp_msp1) -D__MSP430_2101__} \ +%{mmcu=msp430x2111:%(cpp_msp1) -D__MSP430_2111__} \ +%{mmcu=msp430x2121:%(cpp_msp1) -D__MSP430_2121__} \ +%{mmcu=msp430x2131:%(cpp_msp1) -D__MSP430_2131__} \ +%{mmcu=msp430x2232:%(cpp_msp1) -D__MSP430_2232__} \ +%{mmcu=msp430x2252:%(cpp_msp1) -D__MSP430_2252__} \ +%{mmcu=msp430x2272:%(cpp_msp1) -D__MSP430_2272__} \ +%{mmcu=msp430x2234:%(cpp_msp1) -D__MSP430_2234__} \ +%{mmcu=msp430x2254:%(cpp_msp1) -D__MSP430_2254__} \ +%{mmcu=msp430x2274:%(cpp_msp1) -D__MSP430_2274__} \ +%{mmcu=msp430x233:%(cpp_msp2) -D__MSP430_233__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x235:%(cpp_msp2) -D__MSP430_235__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2330:%(cpp_msp2) -D__MSP430_2330__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2350:%(cpp_msp2) -D__MSP430_2350__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2370:%(cpp_msp2) -D__MSP430_2370__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x247:%(cpp_msp2) -D__MSP430_247__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x248:%(cpp_msp2) -D__MSP430_248__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x249:%(cpp_msp2) -D__MSP430_249__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2410:%(cpp_msp2) -D__MSP430_2410__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2471:%(cpp_msp2) -D__MSP430_2471__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2481:%(cpp_msp2) -D__MSP430_2481__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2491:%(cpp_msp2) -D__MSP430_2491__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2416:%(cpp_msp2) -D__MSP430_2416__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2417:%(cpp_msp2) -D__MSP430_2417__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2418:%(cpp_msp2) -D__MSP430_2418__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2419:%(cpp_msp2) -D__MSP430_2419__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2616:%(cpp_msp2) -D__MSP430_2616__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2617:%(cpp_msp2) -D__MSP430_2617__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2618:%(cpp_msp2) -D__MSP430_2618__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x2619:%(cpp_msp2) -D__MSP430_2619__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x311:%(cpp_msp1) -D__MSP430_311__} \ +%{mmcu=msp430x312:%(cpp_msp1) -D__MSP430_312__} \ +%{mmcu=msp430x313:%(cpp_msp1) -D__MSP430_313__} \ +%{mmcu=msp430x314:%(cpp_msp1) -D__MSP430_314__} \ +%{mmcu=msp430x315:%(cpp_msp1) -D__MSP430_315__} \ +%{mmcu=msp430x323:%(cpp_msp1) -D__MSP430_323__} \ +%{mmcu=msp430x325:%(cpp_msp1) -D__MSP430_325__} \ +%{mmcu=msp430x336:%(cpp_msp2) -D__MSP430_336__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x337:%(cpp_msp2) -D__MSP430_337__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x412:%(cpp_msp1) -D__MSP430_412__} \ +%{mmcu=msp430x413:%(cpp_msp1) -D__MSP430_413__} \ +%{mmcu=msp430x415:%(cpp_msp1) -D__MSP430_415__} \ +%{mmcu=msp430x417:%(cpp_msp1) -D__MSP430_417__} \ +%{mmcu=msp430x423:%(cpp_msp2) -D__MSP430_423__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x425:%(cpp_msp2) -D__MSP430_425__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x427:%(cpp_msp2) -D__MSP430_427__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x4250:%(cpp_msp1) -D__MSP430_4250__} \ +%{mmcu=msp430x4260:%(cpp_msp1) -D__MSP430_4260__} \ +%{mmcu=msp430x4270:%(cpp_msp1) -D__MSP430_4270__} \ +%{mmcu=msp430xE423:%(cpp_msp2) -D__MSP430_E423__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430xE425:%(cpp_msp2) -D__MSP430_E425__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430xE427:%(cpp_msp2) -D__MSP430_E427__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430xW423:%(cpp_msp1) -D__MSP430_W423__} \ +%{mmcu=msp430xW425:%(cpp_msp1) -D__MSP430_W425__} \ +%{mmcu=msp430xW427:%(cpp_msp1) -D__MSP430_W427__} \ +%{mmcu=msp430xG437:%(cpp_msp1) -D__MSP430_G437__} \ +%{mmcu=msp430xG438:%(cpp_msp1) -D__MSP430_G438__} \ +%{mmcu=msp430xG439:%(cpp_msp1) -D__MSP430_G439__} \ +%{mmcu=msp430x435:%(cpp_msp1) -D__MSP430_435__} \ +%{mmcu=msp430x436:%(cpp_msp1) -D__MSP430_436__} \ +%{mmcu=msp430x437:%(cpp_msp1) -D__MSP430_437__} \ +%{mmcu=msp430x447:%(cpp_msp2) -D__MSP430_447__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x448:%(cpp_msp2) -D__MSP430_448__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430x449:%(cpp_msp2) -D__MSP430_449__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430xG4616:%(cpp_msp2) -D__MSP430_G4616__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430xG4617:%(cpp_msp2) -D__MSP430_G4617__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430xG4618:%(cpp_msp2) -D__MSP430_G4618__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ +%{mmcu=msp430xG4619:%(cpp_msp2) -D__MSP430_G4619__ -D__MSP430X__ -DMSP430_HAS_HWMUL} \ +%{mint8:-D__SIZE_TYPE__=long\\ unsigned\\ int -D__PTRDIFF_TYPE__=long -D__INT_MAX__=127} \ +%{!mint*:-D__SIZE_TYPE__=unsigned\\ int -D__PTRDIFF_TYPE__=int -D__INT_MAX__=32767} \ +%{posix:-D_POSIX_SOURCE} %{mIAR:-D_IAR_ASSEMBLER_}" + +/* A C string constant that tells the GNU CC driver program options to + pass to CPP. It can also specify how to translate options you + give to GNU CC into options for GNU CC to pass to the CPP. + + Do not define this macro if it does not need to do anything. */ + +#define NO_BUILTIN_SIZE_TYPE +/* If this macro is defined, the preprocessor will not define the + builtin macro `__SIZE_TYPE__'. The macro `__SIZE_TYPE__' must + then be defined by `CPP_SPEC' instead. + + This should be defined if `SIZE_TYPE' depends on target dependent + flags which are not accessible to the preprocessor. Otherwise, it + should not be defined. */ + +#define NO_BUILTIN_PTRDIFF_TYPE +/* If this macro is defined, the preprocessor will not define the + builtin macro `__PTRDIFF_TYPE__'. The macro `__PTRDIFF_TYPE__' + must then be defined by `CPP_SPEC' instead. + + This should be defined if `PTRDIFF_TYPE' depends on target + dependent flags which are not accessible to the preprocessor. + Otherwise, it should not be defined. + + `SIGNED_CHAR_SPEC' + A C string constant that tells the GNU CC driver program options to + pass to CPP. By default, this macro is defined to pass the option + `-D__CHAR_UNSIGNED__' to CPP if `char' will be treated as + `unsigned char' by `cc1'. + + Do not define this macro unless you need to override the default + definition. */ + +#define CC1_SPEC "%{profile:-p}" +/* A C string constant that tells the GNU CC driver program options to + pass to `cc1'. It can also specify how to translate options you + give to GNU CC into options for GNU CC to pass to the `cc1'. + + Do not define this macro if it does not need to do anything. */ + +#define ASM_SPEC "" +/* A C string constant that tells the GNU CC driver program options to + pass to the assembler. It can also specify how to translate + options you give to GNU CC into options for GNU CC to pass to the + assembler. See the file `sun3.h' for an example of this. + + Do not define this macro if it does not need to do anything. */ + +#define ASM_FINAL_SPEC "" +/* A C string constant that tells the GNU CC driver program how to + run any programs which cleanup after the normal assembler. + Normally, this is not needed. See the file `mips.h' for an + example of this. + + Do not define this macro if it does not need to do anything. */ + +#define LINK_SPEC "\ +%{!mmcu*:-m msp430x110} \ +%{mmcu=msp1:-m msp430x110} \ +%{mmcu=msp2:-m msp430x336} \ +%{mmcu=msp430x110:-m msp430x110 } \ +%{mmcu=msp430x112:-m msp430x112 } \ +%{mmcu=msp430x1101:-m msp430x1101 } \ +%{mmcu=msp430x1111:-m msp430x1111 } \ +%{mmcu=msp430x1121:-m msp430x1121 } \ +%{mmcu=msp430x1122:-m msp430x1122 } \ +%{mmcu=msp430x1132:-m msp430x1132 } \ +%{mmcu=msp430x122:-m msp430x122 } \ +%{mmcu=msp430x123:-m msp430x123 } \ +%{mmcu=msp430x1222:-m msp430x1222 } \ +%{mmcu=msp430x1232:-m msp430x1232 } \ +%{mmcu=msp430x133:-m msp430x133 } \ +%{mmcu=msp430x135:-m msp430x135 } \ +%{mmcu=msp430x1331:-m msp430x1331 } \ +%{mmcu=msp430x1351:-m msp430x1351 } \ +%{mmcu=msp430x147:-m msp430x147 } \ +%{mmcu=msp430x148:-m msp430x148 } \ +%{mmcu=msp430x149:-m msp430x149 } \ +%{mmcu=msp430x1471:-m msp430x1471 } \ +%{mmcu=msp430x1481:-m msp430x1481 } \ +%{mmcu=msp430x1491:-m msp430x1491 } \ +%{mmcu=msp430x155:-m msp430x155 } \ +%{mmcu=msp430x156:-m msp430x156 } \ +%{mmcu=msp430x157:-m msp430x157 } \ +%{mmcu=msp430x167:-m msp430x167 } \ +%{mmcu=msp430x168:-m msp430x168 } \ +%{mmcu=msp430x169:-m msp430x169 } \ +%{mmcu=msp430x1610:-m msp430x1610 } \ +%{mmcu=msp430x1611:-m msp430x1611 } \ +%{mmcu=msp430x1612:-m msp430x1612 } \ +%{mmcu=msp430x2001:-m msp430x2001 } \ +%{mmcu=msp430x2011:-m msp430x2011 } \ +%{mmcu=msp430x2002:-m msp430x2002 } \ +%{mmcu=msp430x2012:-m msp430x2012 } \ +%{mmcu=msp430x2003:-m msp430x2003 } \ +%{mmcu=msp430x2013:-m msp430x2013 } \ +%{mmcu=msp430x2101:-m msp430x2101 } \ +%{mmcu=msp430x2111:-m msp430x2111 } \ +%{mmcu=msp430x2121:-m msp430x2121 } \ +%{mmcu=msp430x2131:-m msp430x2131 } \ +%{mmcu=msp430x2232:-m msp430x2232 } \ +%{mmcu=msp430x2252:-m msp430x2252 } \ +%{mmcu=msp430x2272:-m msp430x2272 } \ +%{mmcu=msp430x2234:-m msp430x2234 } \ +%{mmcu=msp430x2254:-m msp430x2254 } \ +%{mmcu=msp430x2274:-m msp430x2274 } \ +%{mmcu=msp430x233:-m msp430x233 } \ +%{mmcu=msp430x235:-m msp430x235 } \ +%{mmcu=msp430x2330:-m msp430x2330 } \ +%{mmcu=msp430x2350:-m msp430x2350 } \ +%{mmcu=msp430x2370:-m msp430x2370 } \ +%{mmcu=msp430x247:-m msp430x247 } \ +%{mmcu=msp430x248:-m msp430x248 } \ +%{mmcu=msp430x249:-m msp430x249 } \ +%{mmcu=msp430x2410:-m msp430x2410 } \ +%{mmcu=msp430x2471:-m msp430x2471 } \ +%{mmcu=msp430x2481:-m msp430x2481 } \ +%{mmcu=msp430x2491:-m msp430x2491 } \ +%{mmcu=msp430x2416:-m msp430x2416 } \ +%{mmcu=msp430x2417:-m msp430x2417 } \ +%{mmcu=msp430x2418:-m msp430x2418 } \ +%{mmcu=msp430x2419:-m msp430x2419 } \ +%{mmcu=msp430x2616:-m msp430x2616 } \ +%{mmcu=msp430x2617:-m msp430x2617 } \ +%{mmcu=msp430x2618:-m msp430x2618 } \ +%{mmcu=msp430x2619:-m msp430x2619 } \ +%{mmcu=msp430x311:-m msp430x311 } \ +%{mmcu=msp430x312:-m msp430x312 } \ +%{mmcu=msp430x313:-m msp430x313 } \ +%{mmcu=msp430x314:-m msp430x314 } \ +%{mmcu=msp430x315:-m msp430x315 } \ +%{mmcu=msp430x323:-m msp430x323 } \ +%{mmcu=msp430x325:-m msp430x325 } \ +%{mmcu=msp430x336:-m msp430x336 } \ +%{mmcu=msp430x337:-m msp430x337 } \ +%{mmcu=msp430x412:-m msp430x412 } \ +%{mmcu=msp430x413:-m msp430x413 } \ +%{mmcu=msp430x415:-m msp430x415 } \ +%{mmcu=msp430x417:-m msp430x417 } \ +%{mmcu=msp430x423:-m msp430x423 } \ +%{mmcu=msp430x425:-m msp430x425 } \ +%{mmcu=msp430x427:-m msp430x427 } \ +%{mmcu=msp430x4250:-m msp430x4250 } \ +%{mmcu=msp430x4260:-m msp430x4260 } \ +%{mmcu=msp430x4270:-m msp430x4270 } \ +%{mmcu=msp430xE423:-m msp430xE423 } \ +%{mmcu=msp430xE425:-m msp430xE425 } \ +%{mmcu=msp430xE427:-m msp430xE427 } \ +%{mmcu=msp430xW423:-m msp430xW423 } \ +%{mmcu=msp430xW425:-m msp430xW425 } \ +%{mmcu=msp430xW427:-m msp430xW427 } \ +%{mmcu=msp430xG437:-m msp430xG437 } \ +%{mmcu=msp430xG438:-m msp430xG438 } \ +%{mmcu=msp430xG439:-m msp430xG439 } \ +%{mmcu=msp430x435:-m msp430x435 } \ +%{mmcu=msp430x436:-m msp430x436 } \ +%{mmcu=msp430x437:-m msp430x437 } \ +%{mmcu=msp430x447:-m msp430x447 } \ +%{mmcu=msp430x448:-m msp430x448 } \ +%{mmcu=msp430x449:-m msp430x449 } \ +%{mmcu=msp430xG4616:-m msp430xG4616 } \ +%{mmcu=msp430xG4617:-m msp430xG4617 } \ +%{mmcu=msp430xG4618:-m msp430xG4618 } \ +%{mmcu=msp430xG4619:-m msp430xG4619 }" + +/* A C string constant that tells the GNU CC driver program options to + pass to the linker. It can also specify how to translate options + you give to GNU CC into options for GNU CC to pass to the linker. + + Do not define this macro if it does not need to do anything. */ + +#define LIB_SPEC \ + "%{*:-lc }" +/* Another C string constant used much like `LINK_SPEC'. The + difference between the two is that `LIB_SPEC' is used at the end + of the command given to the linker. + + If this macro is not defined, a default is provided that loads the + standard C library from the usual place. See `gcc.c'. */ + +#define LIBGCC_SPEC \ + "%{*: -lgcc }" +/* Another C string constant that tells the GNU CC driver program how + and when to place a reference to `libgcc.a' into the linker + command line. This constant is placed both before and after the + value of `LIB_SPEC'. + + If this macro is not defined, the GNU CC driver provides a default + that passes the string `-lgcc' to the linker unless the `-shared' + option is specified. */ + +#define STARTFILE_SPEC "%(crt_binutils)" +/* Another C string constant used much like `LINK_SPEC'. The + difference between the two is that `STARTFILE_SPEC' is used at the + very beginning of the command given to the linker. + + If this macro is not defined, a default is provided that loads the + standard C startup file from the usual place. See `gcc.c'. */ + +#define ENDFILE_SPEC "" +/* Another C string constant used much like `LINK_SPEC'. The + difference between the two is that `ENDFILE_SPEC' is used at the + very end of the command given to the linker. + + Do not define this macro if it does not need to do anything. */ + +/* recently added: +1222 1232 */ + +#define CRT_BINUTILS_SPECS "\ +%{!mmcu=*|mmcu=msp430x110|mmcu=msp1:crt430x110.o%s} \ +%{mmcu=msp430x112:crt430x112.o%s} \ +%{mmcu=msp430x1101:crt430x1101.o%s} \ +%{mmcu=msp430x1111:crt430x1111.o%s} \ +%{mmcu=msp430x1121:crt430x1121.o%s} \ +%{mmcu=msp430x1122:crt430x1122.o%s} \ +%{mmcu=msp430x1132:crt430x1132.o%s} \ +%{mmcu=msp430x122:crt430x122.o%s} \ +%{mmcu=msp430x123:crt430x123.o%s} \ +%{mmcu=msp430x1222:crt430x1222.o%s} \ +%{mmcu=msp430x1232:crt430x1232.o%s} \ +%{mmcu=msp430x133:crt430x133.o%s} \ +%{mmcu=msp430x135:crt430x135.o%s} \ +%{mmcu=msp430x1331:crt430x1331.o%s} \ +%{mmcu=msp430x1351:crt430x1351.o%s} \ +%{mmcu=msp430x147:crt430x147.o%s} \ +%{mmcu=msp430x148:crt430x148.o%s} \ +%{mmcu=msp430x149:crt430x149.o%s} \ +%{mmcu=msp430x1471:crt430x1471.o%s} \ +%{mmcu=msp430x1481:crt430x1481.o%s} \ +%{mmcu=msp430x1491:crt430x1491.o%s} \ +%{mmcu=msp430x155:crt430x155.o%s} \ +%{mmcu=msp430x156:crt430x156.o%s} \ +%{mmcu=msp430x157:crt430x157.o%s} \ +%{mmcu=msp430x167:crt430x167.o%s} \ +%{mmcu=msp430x168:crt430x168.o%s} \ +%{mmcu=msp430x169:crt430x169.o%s} \ +%{mmcu=msp430x1610:crt430x1610.o%s} \ +%{mmcu=msp430x1611:crt430x1611.o%s} \ +%{mmcu=msp430x1612:crt430x1612.o%s} \ +%{mmcu=msp430x2001:crt430x2001.o%s} \ +%{mmcu=msp430x2011:crt430x2011.o%s} \ +%{mmcu=msp430x2002:crt430x2002.o%s} \ +%{mmcu=msp430x2012:crt430x2012.o%s} \ +%{mmcu=msp430x2003:crt430x2003.o%s} \ +%{mmcu=msp430x2013:crt430x2013.o%s} \ +%{mmcu=msp430x2101:crt430x2101.o%s} \ +%{mmcu=msp430x2111:crt430x2111.o%s} \ +%{mmcu=msp430x2121:crt430x2121.o%s} \ +%{mmcu=msp430x2131:crt430x2131.o%s} \ +%{mmcu=msp430x2232:crt430x2232.o%s} \ +%{mmcu=msp430x2252:crt430x2252.o%s} \ +%{mmcu=msp430x2272:crt430x2272.o%s} \ +%{mmcu=msp430x2234:crt430x2234.o%s} \ +%{mmcu=msp430x2254:crt430x2254.o%s} \ +%{mmcu=msp430x2274:crt430x2274.o%s} \ +%{mmcu=msp430x247:crt430x247.o%s} \ +%{mmcu=msp430x248:crt430x248.o%s} \ +%{mmcu=msp430x249:crt430x249.o%s} \ +%{mmcu=msp430x2410:crt430x2410.o%s} \ +%{mmcu=msp430x2471:crt430x2471.o%s} \ +%{mmcu=msp430x2481:crt430x2481.o%s} \ +%{mmcu=msp430x2491:crt430x2491.o%s} \ +%{mmcu=msp430x2416:crt430x2416.o%s} \ +%{mmcu=msp430x2417:crt430x2417.o%s} \ +%{mmcu=msp430x2418:crt430x2418.o%s} \ +%{mmcu=msp430x2419:crt430x2419.o%s} \ +%{mmcu=msp430x2616:crt430x2616.o%s} \ +%{mmcu=msp430x2617:crt430x2617.o%s} \ +%{mmcu=msp430x2618:crt430x2618.o%s} \ +%{mmcu=msp430x2619:crt430x2619.o%s} \ +%{mmcu=msp430x311:crt430x311.o%s} \ +%{mmcu=msp430x312:crt430x312.o%s} \ +%{mmcu=msp430x313:crt430x313.o%s} \ +%{mmcu=msp430x314:crt430x314.o%s} \ +%{mmcu=msp430x315:crt430x315.o%s} \ +%{mmcu=msp430x323:crt430x323.o%s} \ +%{mmcu=msp430x325:crt430x325.o%s} \ +%{mmcu=msp430x336|mmcu=msp2:crt430x336.o%s} \ +%{mmcu=msp430x337:crt430x337.o%s} \ +%{mmcu=msp430x412:crt430x412.o%s} \ +%{mmcu=msp430x413:crt430x413.o%s} \ +%{mmcu=msp430x415:crt430x415.o%s} \ +%{mmcu=msp430x417:crt430x417.o%s} \ +%{mmcu=msp430x423:crt430x423.o%s} \ +%{mmcu=msp430x425:crt430x425.o%s} \ +%{mmcu=msp430x427:crt430x427.o%s} \ +%{mmcu=msp430x4250:crt430x4250.o%s} \ +%{mmcu=msp430x4260:crt430x4260.o%s} \ +%{mmcu=msp430x4270:crt430x4270.o%s} \ +%{mmcu=msp430xE423:crt430xE423.o%s} \ +%{mmcu=msp430xE425:crt430xE425.o%s} \ +%{mmcu=msp430xE427:crt430xE427.o%s} \ +%{mmcu=msp430xW423:crt430xW423.o%s} \ +%{mmcu=msp430xW425:crt430xW425.o%s} \ +%{mmcu=msp430xW427:crt430xW427.o%s} \ +%{mmcu=msp430xG437:crt430xG437.o%s} \ +%{mmcu=msp430xG438:crt430xG438.o%s} \ +%{mmcu=msp430xG439:crt430xG439.o%s} \ +%{mmcu=msp430x435:crt430x435.o%s} \ +%{mmcu=msp430x436:crt430x436.o%s} \ +%{mmcu=msp430x437:crt430x437.o%s} \ +%{mmcu=msp430x447:crt430x447.o%s} \ +%{mmcu=msp430x448:crt430x448.o%s} \ +%{mmcu=msp430x449:crt430x449.o%s} \ +%{mmcu=msp430xG4616:crt430xG4616.o%s} \ +%{mmcu=msp430xG4617:crt430xG4617.o%s} \ +%{mmcu=msp430xG4618:crt430xG4618.o%s} \ +%{mmcu=msp430xG4619:crt430xG4619.o%s}" + + + +#define CPP_MSP1_SPEC " -DMSP430_NO_HW_MUL " +#define CPP_MSP2_SPEC " -DMSP430_HAS_HW_MUL " + +#define EXTRA_SPECS \ +{"cpp_msp1",CPP_MSP1_SPEC}, \ +{"cpp_msp2",CPP_MSP2_SPEC}, \ +{"crt_binutils", CRT_BINUTILS_SPECS}, + +/* Define this macro to provide additional specifications to put in + the `specs' file that can be used in various specifications like + `CC1_SPEC'. + + The definition should be an initializer for an array of structures, + containing a string constant, that defines the specification name, + and a string constant that provides the specification. + + Do not define this macro if it does not need to do anything. + + `EXTRA_SPECS' is useful when an architecture contains several + related targets, which have various `..._SPECS' which are similar + to each other, and the maintainer would like one central place to + keep these definitions. + + For example, the PowerPC System V.4 targets use `EXTRA_SPECS' to + define either `_CALL_SYSV' when the System V calling sequence is + used or `_CALL_AIX' when the older AIX-based calling sequence is + used. + + The `config/rs6000/rs6000.h' target file defines: + + #define EXTRA_SPECS \ + { "cpp_sysv_default", CPP_SYSV_DEFAULT }, + + #define CPP_SYS_DEFAULT "" + + The `config/rs6000/sysv.h' target file defines: + #undef CPP_SPEC + #define CPP_SPEC \ + "%{posix: -D_POSIX_SOURCE } \ + %{mcall-sysv: -D_CALL_SYSV } %{mcall-aix: -D_CALL_AIX } \ + %{!mcall-sysv: %{!mcall-aix: %(cpp_sysv_default) }} \ + %{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT}" + + #undef CPP_SYSV_DEFAULT + #define CPP_SYSV_DEFAULT "-D_CALL_SYSV" + + while the `config/rs6000/eabiaix.h' target file defines + `CPP_SYSV_DEFAULT' as: + + #undef CPP_SYSV_DEFAULT + #define CPP_SYSV_DEFAULT "-D_CALL_AIX" */ + + +#define MULTILIB_DEFAULTS { "mmcu=msp430x110" } + +/* This is undefined macro for collect2 disabling */ +#define LINKER_NAME "msp430-ld" + +#define TEST_HARD_REG_CLASS(CLASS, REGNO) \ + TEST_HARD_REG_BIT (reg_class_contents[ (int) (CLASS)], REGNO) + +/* Note that the other files fail to use these + in some of the places where they should. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +#define AS2(a,b,c) #a " " #b "," #c +#define AS2C(b,c) " " #b "," #c +#define AS3(a,b,c,d) #a " " #b "," #c "," #d +#define AS1(a,b) #a " " #b +#else +#define AS1(a,b) "a b" +#define AS2(a,b,c) "a b,c" +#define AS2C(b,c) " b,c" +#define AS3(a,b,c,d) "a b,c,d" +#endif +#define OUT_AS1(a,b) output_asm_insn (AS1(a,b), operands) +#define OUT_AS2(a,b,c) output_asm_insn (AS2(a,b,c), operands) +#define CR_TAB "\n\t" + +/* Define this macro as a C statement that declares additional library + routines renames existing ones. `init_optabs' calls this macro + after initializing all the normal library routines. */ + +#define INIT_TARGET_OPTABS \ +{ \ + msp430_init_once (); \ +} + +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + +/* Define to use software floating point emulator for REAL_ARITHMETIC and + decimal <-> binary conversion. */ + +#ifndef REAL_ARITHMETIC +#define REAL_ARITHMETIC +#endif + +#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG +#define DWARF2_DEBUGGING_INFO 1 +#define OBJECT_FORMAT_ELF + +#define DBX_REGISTER_NUMBER(r) (r) + +/* Get the standard ELF stabs definitions. */ +#include "dbxelf.h" + + diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/msp430.md gcc-3.2.3/gcc/config/msp430/msp430.md --- gcc-3.2.3.orig/gcc/config/msp430/msp430.md 1969-12-31 17:00:00.000000000 -0700 +++ gcc-3.2.3/gcc/config/msp430/msp430.md 2008-08-22 09:17:00.000000000 -0600 @@ -0,0 +1,4079 @@ +;; -*- Mode: Scheme -*- +;; Machine description for GNU compiler, +;; for Texas Instruments msp430 MCUs +;; Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +;; Contributed by Dmitry Diky + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; Special characters after '%': +;; A No effect (add 0). +;; B Add 1 to REG number, 2 to MEM address or CONST_INT. +;; C 2 4 +;; D 3 6 +;; E adds nothing to reg but used only with (mem:hi (reg:hi)) +;; F no trim array +;; M Add 0 to address if using stack pointer +;; N Add 2 to address if using stack pointer +;; Extra constarains: +;; P hardware constants: -1,0,+1,+2,+4,+8 +;; Q Indexed destination register as X(Rn) +;; R Indexed source register as @Rn+ +;; S Symbol reference for 'C' like: a = *b; +;; + +;; Unspec usage: +;; 3 - strlen +;; 0 - addc_reg +;; 5 - addc_any +;; 1 - bittest_lo +;; 2 - bittest_hi +;; 6 - bittest +;; 4 - swpb +;; 7 - bittest_b +;; 8 - move SF to SI with no conversion + + +;; Condition code settings. + + +(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber,further,oper,cbranch" + (const_string "none")) + +(define_attr "type" "branch,branch1,arith" + (const_string "arith")) + +(define_attr "msp430_has_hwmul" "yes,no" + (const (if_then_else (symbol_ref "MSP430_HAS_HWMUL_INTERNAL") + (const_string "yes") + (const_string "no")))) + +(define_attr "msp430_noint_hwmul" "" (symbol_ref "MSP430_NOINT_HWMUL")) + +;; The size of instructions in bytes. +;; XXX may depend from "cc" + +;; for confitional branches +(define_attr "length" "" + (cond [(eq_attr "type" "branch") + (if_then_else (and (ge (minus (pc) (match_dup 0)) + (const_int -508)) + (le (minus (pc) (match_dup 0)) + (const_int 508))) + (const_int 1) + (const_int 2))] + (const_int 2) +)) + + +;;======================================================================== +;; PUSH/POP helper functions +;; + + +(define_insn "*pushqi_pre_mod" +[(set (mem:QI (pre_modify:HI (reg:HI 1) + (plus:HI (reg:HI 1) (const_int -2)))) + (match_operand:QI 0 "general_operand" "rim"))] +"" +"* return msp430_pushqi(insn, operands, NULL);" +[(set_attr "length" "2")]) + +(define_insn "*pushqi" + [(set (mem:QI (post_dec (reg:HI 1))) + (match_operand:QI 0 "general_operand" "rim"))] + "" + "* return msp430_pushqi(insn, operands, NULL);" + [(set_attr "length" "2")]) + +(define_insn "*pushhi" + [(set (mem:HI (post_dec (reg:HI 1))) + (match_operand:HI 0 "general_operand" "rim"))] + "" + "* return msp430_pushhi(insn, operands, NULL);" + [(set_attr "length" "2")]) + +(define_insn "*pushsi" + [(set (mem:SI (post_dec (reg:HI 1))) + (match_operand:SI 0 "general_operand" "rmi"))] + "" + "* return msp430_pushsisf(insn, operands, NULL);" + [(set_attr "length" "4")]) + + +(define_insn "*pushdi" + [(set (mem:DI (post_dec (reg:HI 1))) + (match_operand:DI 0 "general_operand" "rmi"))] + "" + "* return msp430_pushdi(insn, operands, NULL);" + [(set_attr "length" "8")]) + + +(define_insn "*pushsf" + [(set (mem:SF (post_dec (reg:HI 1))) + (match_operand:SF 0 "general_operand" "rmi"))] + "" + "* return msp430_pushsisf(insn, operands, NULL);" + [(set_attr "length" "4")]) + + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "general_operand" "")) + (set (mem:HI (post_dec (reg:HI 1))) + (match_dup 0))] +"dead_or_set_in_peep(1, insn, operands[0])" + [(set (mem:HI (post_dec (reg:HI 1))) + (match_dup 1))] +"") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "general_operand" "")) + (set (mem:SI (post_dec (reg:HI 1))) + (match_dup 0))] +"dead_or_set_in_peep(1, insn, operands[0])" + [(set (mem:SI (post_dec (reg:HI 1))) + (match_dup 1))] +"") + +(define_peephole2 + [(set (match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "general_operand" "")) + (set (mem:SF (post_dec (reg:HI 1))) + (match_dup 0))] +"dead_or_set_in_peep(1, insn, operands[0])" + [(set (mem:SF (post_dec (reg:HI 1))) + (match_dup 1))] +"") + + +;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +;; This instructin sets Z flag + +(define_insn "sez" + [(set (cc0) (const_int 0))] +"" +"setz" + [(set_attr "length" "1") + (set_attr "cc" "compare")]) + + + +;;======================================================================== +;; compare + +(define_expand "cmpqi" + [(set (cc0) + (compare:QI (match_operand:QI 0 "nonimmediate_operand_msp430" "rm") + (match_operand:QI 1 "general_operand_msp430" "rmi")))] + "" +" + msp430_compare_op0 = operands[0]; + msp430_compare_op1 = operands[1]; + DONE; +") + + +(define_expand "cmphi" + [(set (cc0) + (compare:HI (match_operand:HI 0 "nonimmediate_operand_msp430" "rm") + (match_operand:HI 1 "general_operand_msp430" "rmi")))] + "" +" + msp430_compare_op0 = operands[0]; + msp430_compare_op1 = operands[1]; + DONE; +") + + +(define_expand "cmpsi" + [(set (cc0) + (compare:SI (match_operand:SI 0 "nonimmediate_operand" "rm") + (match_operand:SI 1 "general_operand" "rmi")))] + "" +" + msp430_compare_op0 = operands[0]; + msp430_compare_op1 = operands[1]; + DONE; +") + + +(define_expand "beq" + [(use (match_operand 0 "" ""))] +"" +"{ msp430_emit_cbranch (EQ, operands[0]); DONE; }") + +(define_expand "bne" + [(use (match_operand 0 "" ""))] +"" +"{ msp430_emit_cbranch (NE, operands[0]); DONE; }") + +(define_expand "bge" + [(use (match_operand 0 "" ""))] +"" +"{ msp430_emit_cbranch (GE, operands[0]); DONE; }") + +(define_expand "bgt" + [(use (match_operand 0 "" ""))] +"" +"{ msp430_emit_cbranch (GT, operands[0]); DONE; }") + +(define_expand "ble" + [(use (match_operand 0 "" ""))] +"" +"{ msp430_emit_cbranch (LE, operands[0]); DONE; }") + +(define_expand "blt" + [(use (match_operand 0 "" ""))] +"" +"{ msp430_emit_cbranch (LT, operands[0]); DONE; }") + +(define_expand "bgeu" + [(use (match_operand 0 "" ""))] +"" +"{ msp430_emit_cbranch (GEU, operands[0]); DONE; }") + +(define_expand "bgtu" + [(use (match_operand 0 "" ""))] +"" +"{ msp430_emit_cbranch (GTU, operands[0]); DONE; }") + +(define_expand "bleu" + [(use (match_operand 0 "" ""))] +"" +"{ msp430_emit_cbranch (LEU, operands[0]); DONE; }") + +(define_expand "bltu" + [(use (match_operand 0 "" ""))] +"" +"{ msp430_emit_cbranch (LTU, operands[0]); DONE; }") + + +(define_insn "*cbranchqi" + [(set (pc) + (if_then_else (match_operator:QI 1 "comparison_operator" + [(match_operand:QI 2 "nonimmediate_operand_msp430" "rm") + (match_operand:QI 3 "general_operand" "rmi")]) + (label_ref (match_operand 0 "" "")) + (pc)))] +"" +"* return msp430_cbranch(insn, operands, NULL);" + [(set_attr "length" "9") + (set_attr "cc" "cbranch")]) + + + +(define_insn "*cbranchhi" + [(set (pc) + (if_then_else (match_operator:HI 1 "comparison_operator" + [(match_operand:HI 2 "nonimmediate_operand_msp430" "rm") + (match_operand:HI 3 "general_operand" "rmi")]) + (label_ref (match_operand 0 "" "")) + (pc)))] +"" +"* return msp430_cbranch(insn, operands, NULL);" + [(set_attr "length" "9") + (set_attr "cc" "cbranch")]) + + +(define_insn "*cbranchsi_eqne" + [(set (pc) + (if_then_else (match_operator:SI 1 "equality_operator" + [(match_operand:SI 2 "nonimmediate_operand" "rm") + (match_operand:SI 3 "general_operand" "rmi")]) + (label_ref (match_operand 0 "" "")) + (pc)))] +"" +"* return msp430_cbranch(insn, operands, NULL);" +[(set_attr "length" "9") + (set_attr "cc" "cbranch")]) + + +(define_insn "*cbranchsi_others" + [(parallel [(set (pc) + (if_then_else (match_operator:SI 1 "inequality_operator" + [(match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "general_operand" "rmi")]) + (label_ref (match_operand 0 "" "")) + (pc))) + (clobber (match_dup 2))])] +"" +"* return msp430_cbranch(insn, operands, NULL);" +[(set_attr "length" "9") + (set_attr "cc" "cbranch")]) + + +(define_insn "*cbranch_uncoded" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(cc0) + (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] +"" +"* return msp430_cbranch(insn, operands, NULL);" +[(set_attr "length" "9") +(set_attr "cc" "cbranch")]) + + +;;======================================================================== +;; noop +(define_insn "nop" + [(const_int 0)] + "" + "nop" + [(set_attr "cc" "none") + (set_attr "length" "1")]) + + +;;============================================================================ +;; call +;; + +(define_expand "call" + [(call (match_operand:HI 0 "general_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + "") + +(define_insn "*call_insn" + [(call (mem:HI (match_operand:HI 0 "general_operand" "r,P,mi")) + (match_operand:HI 1 "general_operand" "X,X,X"))] +"" +"call\\t%0" +[ (set_attr "length" "1,1,2") + (set_attr "cc" "clobber")]) + + +(define_expand "call_value" + [(set (match_operand 0 "register_operand" "") + (call (match_operand:HI 1 "general_operand" "") + (match_operand:HI 2 "general_operand" "")))] + "" + "") + +(define_insn "*call_value_insn" + [( set (match_operand 0 "register_operand" "=r,r,r") + (call (mem:HI (match_operand:HI 1 "general_operand" "r,P,mi")) + (match_operand:HI 2 "general_operand" "X,X,X")))] +"" + "call\\t%N1" +[ (set_attr "length" "1,1,2") + (set_attr "cc" "clobber")]) + + + + + +;;======================================================================== +;;======================================================================== +;; mult helpers + +(define_insn "reent_in" + [(set (mem:HI (post_dec (reg:HI 1))) + (unspec_volatile:HI [(const_int 99999999)] 10))] + "" + "push\\tr2 +\\tdint +\\tnop" + [(set_attr "length" "4") + (set_attr "cc" "clobber")]) + +;; +;; Next three help to make sure, that +;; all instructions are 'in order' + +(define_insn "fetch_result_qi" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") + (unspec_volatile:QI [(const_int 0)] 12)) + (set (mem:HI (post_inc (reg:HI 1))) + (unspec_volatile:HI [(const_int 99999999)] 11))] + "" + "mov.b\\t&__RESLO, %0 +\\tpop\\tr2" + [(set_attr "length" "3,4") + (set_attr "cc" "none")]) + +(define_insn "fetch_result_hi" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") + (unspec_volatile:HI [(const_int 0)] 13)) + (set (mem:HI (post_inc (reg:HI 1))) + (unspec_volatile:HI [(const_int 99999999)] 11))] + "" + "mov\\t&__RESLO, %0 +\\tpop\\tr2" + [(set_attr "length" "3,4") + (set_attr "cc" "none")]) + +(define_insn "fetch_result_si" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,m") + (unspec_volatile:SI [(const_int 0)] 14)) + (set (mem:HI (post_inc (reg:HI 1))) + (unspec_volatile:HI [(const_int 99999999)] 11))] + "" + "mov\\t&__RESLO, %A0 +\\tmov\\t&__RESHI, %B0 +\\tpop\\tr2" + [(set_attr "length" "5,7") + (set_attr "cc" "none")]) + +;; ===the same with no int + +(define_insn "fetch_result_qi_nint" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") + (unspec_volatile:QI [(const_int 0)] 121))] + "" + "mov.b\\t&__RESLO, %0" + [(set_attr "length" "2,3") + (set_attr "cc" "none")]) + +(define_insn "fetch_result_hi_nint" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") + (unspec_volatile:HI [(const_int 0)] 131))] + "" + "mov\\t&__RESLO, %0" + [(set_attr "length" "2,3") + (set_attr "cc" "none")]) + +(define_insn "fetch_result_si_nint" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,m") + (unspec_volatile:SI [(const_int 0)] 141))] + "" + "mov\\t&__RESLO, %A0 +\\tmov\\t&__RESHI, %B0" + [(set_attr "length" "4,6") + (set_attr "cc" "none")]) + +(define_insn "addc_zero" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") + (unspec_volatile:HI [(const_int 0 )] 15))] + "" + "addc\\t#0, %0" +[(set_attr "length" "1,2") + (set_attr "cc" "none")]) + +(define_insn "subc_zero" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") + (unspec:HI [(const_int 0 )] 16))] + "" + "subc\\t#0, %0" +[(set_attr "length" "1,2") + (set_attr "cc" "none")]) + +(define_insn "load_mpy" + [(unspec_volatile:HI [(const_int 0)] 17) + (use (match_operand:HI 0 "general_operand_msp430" "rRP,mi"))] +"" +"mov\\t%0, &__MPY" +[(set_attr "length" "2,3") + (set_attr "cc" "none")]) + + +(define_insn "load_mpys" + [(unspec_volatile:HI [(const_int 0)] 18) + (use (match_operand:HI 0 "general_operand_msp430" "rRP,mi"))] +"" +"mov\\t%0, &__MPYS" +[(set_attr "length" "2,3") + (set_attr "cc" "none")]) + + +(define_insn "load_op2" + [(unspec_volatile:HI [(const_int 0)] 19) + (use (match_operand:HI 0 "general_operand_msp430" "rRP,mi"))] +"" +"mov\\t%0, &__OP2" +[(set_attr "length" "2,3") + (set_attr "cc" "none")]) + + +(define_insn "load_mpyq" + [(unspec_volatile:QI [(const_int 0 )] 20) + (use (match_operand:QI 0 "general_operand_msp430" "rRP,mi"))] +"" +"mov.b\\t%0, &__MPY" +[(set_attr "length" "2,3") + (set_attr "cc" "none")]) + + +(define_insn "load_mpysq" + [(unspec_volatile:QI [(const_int 0 )] 21) + (use (match_operand:QI 0 "general_operand_msp430" "rRP,mi"))] +"" +"mov.b\\t%0, &__MPYS" +[(set_attr "length" "2,3") + (set_attr "cc" "none")]) + +(define_insn "load_op2q" + [(unspec_volatile:QI [(const_int 0 )] 22) + (use (match_operand:QI 0 "general_operand_msp430" "rRP,mi"))] +"" +"mov.b\\t%0, &__OP2" +[(set_attr "length" "2,3") + (set_attr "cc" "none")]) + + + + + + +;;======================================================================== +;;======================================================================== +;;======================================================================== +;; +;; Multiplication + +;;======================================================================== +;; 8 = 8x8 and 16 = 8x8 + +(define_expand "mulqi3" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") + (mult:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") + (match_operand:QI 2 "general_operand_msp430" "")))] + "" +"{ msp430_mul3_guard(operands,0); DONE; }") + +(define_insn "*mulqi3_call" + [(set (reg:QI 14) (mult:QI (reg:QI 10) (reg:QI 12))) + (clobber (reg:QI 10)) + (clobber (reg:QI 12))] + "!MSP430_HAS_HWMUL_INTERNAL" + "call #__mulqi3" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +;; ============= qi -> hi ======================================================= +(define_expand "mulqihi3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") + (mult:HI (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand_msp430" "")) + (sign_extend:HI (match_operand:QI 2 "general_operand_msp430" ""))))] +"" +"{ msp430_mul3_guard(operands,1); DONE; }") + +(define_insn "*mulqihi3_call" + [(set (reg:HI 14) (mult:HI (sign_extend:HI (reg:QI 10)) + (sign_extend:HI (reg:QI 12)))) + (clobber (reg:QI 10)) + (clobber (reg:QI 12))] + "!MSP430_HAS_HWMUL_INTERNAL" + "call #__mulqihi3" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +;; ============ unsigned ones =================================================== +(define_expand "umulqihi3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") + (mult:HI (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand_msp430" "")) + (zero_extend:HI (match_operand:QI 2 "general_operand_msp430" ""))))] + "" + "{ msp430_umul3_guard(operands,0); DONE; }") + +(define_insn "*umulqihi3_call" + [(set (reg:HI 14) (mult:HI (zero_extend:HI (reg:QI 10)) + (zero_extend:HI (reg:QI 12)))) + (clobber (reg:QI 10)) + (clobber (reg:QI 12))] + "!MSP430_HAS_HWMUL_INTERNAL" + "call #__umulqihi3" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +;;======================================================================== +;; 16 = 16x16 and 32 = 16x16 + +(define_expand "mulhi3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") + (mult:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "") + (match_operand:HI 2 "general_operand_msp430" "")))] + "" +"{msp430_mul3_guard(operands,0); DONE; } ") + +(define_insn "*mulhi3_call" + [(set (reg:HI 14) (mult:HI (reg:HI 10) (reg:HI 12))) + (clobber (reg:HI 10)) + (clobber (reg:HI 12))] + "!MSP430_HAS_HWMUL_INTERNAL" + "call #__mulhi3" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +;; ========================== hi -> si ============================= +(define_expand "mulhisi3" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "") + (mult:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand_msp430" "")) + (sign_extend:SI (match_operand:HI 2 "general_operand_msp430" ""))))] +"" + "{msp430_mulhisi_guard(operands); DONE;}" +) + +(define_insn "*mulhisi3_call" + [(set (reg:SI 14) (mult:SI (sign_extend:SI (reg:HI 10)) + (sign_extend:SI (reg:HI 12)))) + (clobber (reg:HI 10)) + (clobber (reg:HI 11)) + (clobber (reg:HI 12)) + (clobber (reg:HI 13))] + "!MSP430_HAS_HWMUL_INTERNAL" + "mov #0, r11 + tst r10 + jge +2 + mov #-1, r11 + mov #0, r13 + tst r12 + jge +2 + mov #-1, r13 + call #__mulhisi3" + [(set_attr "length" "10") + (set_attr "cc" "clobber")]) + +;; ================== unsigned hi -> si ============================= +(define_expand "umulhisi3" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "") + (mult:SI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand_msp430" "")) + (zero_extend:SI (match_operand:HI 2 "general_operand_msp430" ""))))] + "" + "{msp430_umulhisi_guard(operands); DONE;}") + +(define_insn "*umulhisi3_call" + [(set (reg:SI 14) (mult:SI (zero_extend:SI (reg:HI 10)) + (zero_extend:SI (reg:HI 12)))) + (clobber (reg:HI 10)) + (clobber (reg:HI 11)) + (clobber (reg:HI 12)) + (clobber (reg:HI 13))] + "!MSP430_HAS_HWMUL_INTERNAL" + "clr r11 + clr r13 + call #__umulhisi3" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + + +;;======================================================================== +;; 32 = 32x32. 64 = 32x32 <- via library calls only + +(define_expand "mulsi3" + [(set (reg:SI 10) (match_operand:SI 1 "nonimmediate_operand_msp430" "")) + (set (reg:SI 12) (match_operand:SI 2 "general_operand_msp430" "")) + (set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12))) + (set (match_operand:SI 0 "nonimmediate_operand_msp430" "") (reg:SI 14))] +"" +"{ + if (!MSP430_HAS_HWMUL_INTERNAL) + { + emit_insn (gen_mulsi3_call (operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_insn "*mulsi3hw_call_ni" + [(set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12)))] + "(!TARGET_INLINESIHWMUL) && MSP430_NOINT_HWMUL" + "call #__umulsi3hw" +[(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +(define_insn "*mulsi3hw_call_ie" + [(set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12)))] + "(!TARGET_INLINESIHWMUL) && !MSP430_NOINT_HWMUL" + "push r2 + dint + call #__umulsi3hw + pop r2" +[(set_attr "length" "5") + (set_attr "cc" "clobber")]) + +(define_insn "*mulsi3hw_inline_ni" + [(set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12)))] + "TARGET_INLINESIHWMUL && MSP430_HAS_HWMUL_INTERNAL && MSP430_NOINT_HWMUL" + "mov r12, &__MPY + mov r10, &__OP2 + mov r12, &__MAC + mov &__RESLO, r14 + mov &__RESHI, &__RESLO + mov r11, &__OP2 + mov r13, &__MAC + mov r10, &__OP2 + mov &__RESLO, r15" +[(set_attr "length" "19") + (set_attr "cc" "none")]) + +(define_insn "*mulsi3hw_inline_ie" + [(set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12)))] + "TARGET_INLINESIHWMUL && MSP430_HAS_HWMUL_INTERNAL && !MSP430_NOINT_HWMUL" + "push r2 + dint + nop + mov r12, &__MPY + mov r10, &__OP2 + mov r12, &__MAC + mov &__RESLO, r14 + mov &__RESHI, &__RESLO + mov r11, &__OP2 + mov r13, &__MAC + mov r10, &__OP2 + mov &__RESLO, r15 + pop r2" +[(set_attr "length" "23") + (set_attr "cc" "none")]) + +(define_expand "mulsi3_call" + [(set (reg:SI 10) (match_operand:SI 1 "register_operand" "")) + (set (reg:SI 12) (match_operand:SI 2 "register_operand" "")) + (parallel [(set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12))) + (clobber (reg:SI 10)) + (clobber (reg:SI 12))]) + (set (match_operand:SI 0 "register_operand" "") (reg:SI 14))] +"!MSP430_HAS_HWMUL_INTERNAL" +"") + +(define_insn "*mulsi3_call" + [(set (reg:SI 14) (mult:SI (reg:SI 10) (reg:SI 12))) + (clobber (reg:SI 10)) + (clobber (reg:SI 12))] + "!MSP430_HAS_HWMUL_INTERNAL" + "call #__mulsi3" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + + +;; / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / +;; / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / +;; / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / +;; / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / % / + +(define_expand "divmodqi4" + [(set (reg:QI 12) (match_operand:QI 1 "register_operand" "")) + (set (reg:QI 10) (match_operand:QI 2 "register_operand" "")) + (parallel [(set (reg:QI 12) (div:QI (reg:QI 12) (reg:QI 10))) + (set (reg:QI 14) (mod:QI (reg:QI 12) (reg:QI 10))) + (clobber (reg:QI 10)) + (clobber (reg:QI 11)) + (clobber (reg:QI 13))]) + (set (match_operand:QI 0 "register_operand" "") (reg:QI 12)) + (set (match_operand:QI 3 "register_operand" "") (reg:QI 14))] + "" + "") + +(define_insn "*divmodqi4_call" + [(set (reg:QI 12) (div:QI (reg:QI 12) (reg:QI 10))) + (set (reg:QI 14) (mod:QI (reg:QI 12) (reg:QI 10))) + (clobber (reg:QI 10)) + (clobber (reg:QI 11)) + (clobber (reg:QI 13))] + "" + "call #__divmodqi4" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +(define_expand "udivmodqi4" + [(set (reg:QI 12) (match_operand:QI 1 "register_operand" "")) + (set (reg:QI 10) (match_operand:QI 2 "register_operand" "")) + (parallel [(set (reg:QI 12) (udiv:QI (reg:QI 12) (reg:QI 10))) + (set (reg:QI 14) (umod:QI (reg:QI 12) (reg:QI 10))) + (clobber (reg:QI 10)) + (clobber (reg:QI 11)) + (clobber (reg:QI 13))]) + (set (match_operand:QI 0 "register_operand" "") (reg:QI 12)) + (set (match_operand:QI 3 "register_operand" "") (reg:QI 14))] + "" + "") + +(define_insn "*udivmodqi4_call" + [(set (reg:QI 12) (udiv:QI (reg:QI 12) (reg:QI 10))) + (set (reg:QI 14) (umod:QI (reg:QI 12) (reg:QI 10))) + (clobber (reg:QI 10)) + (clobber (reg:QI 11)) + (clobber (reg:QI 13))] + "" + "call #__udivmodqi4" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + + +(define_expand "divmodhi4" + [(set (reg:HI 12) (match_operand:HI 1 "register_operand" "")) + (set (reg:HI 10) (match_operand:HI 2 "register_operand" "")) + (parallel [(set (reg:HI 12) (div:HI (reg:HI 12) (reg:HI 10))) + (set (reg:HI 14) (mod:HI (reg:HI 12) (reg:HI 10))) + (clobber (reg:HI 10)) + (clobber (reg:HI 11)) + (clobber (reg:HI 13))]) + (set (match_operand:HI 0 "register_operand" "") (reg:HI 12)) + (set (match_operand:HI 3 "register_operand" "") (reg:HI 14))] + "" + "") + +(define_insn "*divmodhi4_call" + [(set (reg:HI 12) (div:HI (reg:HI 12) (reg:HI 10))) + (set (reg:HI 14) (mod:HI (reg:HI 12) (reg:HI 10))) + (clobber (reg:HI 10)) + (clobber (reg:HI 11)) + (clobber (reg:HI 13))] + "" + "call #__divmodhi4" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +(define_expand "udivmodhi4" + [(set (reg:HI 12) (match_operand:HI 1 "register_operand" "")) + (set (reg:HI 10) (match_operand:HI 2 "register_operand" "")) + (parallel [(set (reg:HI 12) (udiv:HI (reg:HI 12) (reg:HI 10))) + (set (reg:HI 14) (umod:HI (reg:HI 12) (reg:HI 10))) + (clobber (reg:HI 10)) + (clobber (reg:HI 11)) + (clobber (reg:HI 13))]) + (set (match_operand:HI 0 "register_operand" "") (reg:HI 12)) + (set (match_operand:HI 3 "register_operand" "") (reg:HI 14))] + "" + "") + +(define_insn "*udivmodhi4_call" + [(set (reg:HI 12) (udiv:HI (reg:HI 12) (reg:HI 10))) + (set (reg:HI 14) (umod:HI (reg:HI 12) (reg:HI 10))) + (clobber (reg:HI 10)) + (clobber (reg:HI 11)) + (clobber (reg:HI 13))] + "" + "call #__udivmodhi4" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + + +;; ///////////////// SINGLE INTEGER %%%%%%%%%%%%%%%%% + +(define_expand "divmodsi4" + [(set (reg:SI 12) (match_operand:SI 1 "register_operand" "")) + (set (reg:SI 10) (match_operand:SI 2 "register_operand" "")) + (parallel [(set (reg:SI 12) (div:SI (reg:SI 12) (reg:SI 10))) + (set (reg:SI 14) (mod:SI (reg:SI 12) (reg:SI 10))) + (clobber (reg:SI 10)) + (clobber (reg:HI 9)) + (clobber (reg:HI 8))]) + (set (match_operand:SI 0 "register_operand" "") (reg:SI 12)) + (set (match_operand:SI 3 "register_operand" "") (reg:SI 14))] + "" + "") + +(define_insn "*divmodsi4_call" + [(set (reg:SI 12) (div:SI (reg:SI 12) (reg:SI 10))) + (set (reg:SI 14) (mod:SI (reg:SI 12) (reg:SI 10))) + (clobber (reg:SI 10)) + (clobber (reg:HI 9)) + (clobber (reg:HI 8))] + "" + "call #__divmodsi4" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +(define_expand "udivmodsi4" + [(set (reg:SI 12) (match_operand:SI 1 "register_operand" "")) + (set (reg:SI 10) (match_operand:SI 2 "register_operand" "")) + (parallel [(set (reg:SI 12) (udiv:SI (reg:SI 12) (reg:SI 10))) + (set (reg:SI 14) (umod:SI (reg:SI 12) (reg:SI 10))) + (clobber (reg:SI 10)) + (clobber (reg:HI 9)) + (clobber (reg:HI 8))]) + (set (match_operand:SI 0 "register_operand" "") (reg:SI 12)) + (set (match_operand:SI 3 "register_operand" "") (reg:SI 14))] + "" + "") + +(define_insn "*udivmodsi4_call" + [(set (reg:SI 12) (udiv:SI (reg:SI 12) (reg:SI 10))) + (set (reg:SI 14) (umod:SI (reg:SI 12) (reg:SI 10))) + (clobber (reg:SI 10)) + (clobber (reg:HI 9)) + (clobber (reg:HI 8))] + "" + "call #__udivmodsi4" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + + + + +;;======================================================================== +;; MOV STRING +;; structures and stuff are word aligned. +;; so, QI mode only defined (as HI actually) +;; + +(define_expand "movstrhi" + [(parallel [(set (match_operand:BLK 0 "memory_operand" "") + (match_operand:BLK 1 "memory_operand" "")) + (use (match_operand 2 "const_int_operand" "")) + (use (match_operand 3 "const_int_operand" "")) + (clobber (match_dup 4)) + (clobber (match_dup 5)) + (clobber (match_dup 6))])] + "" + " +{ + rtx addr0, addr1; + rtx a0, a1; + + if (GET_CODE (operands[2]) != CONST_INT) FAIL; + + addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); + addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); + + a0 = operands[0]; + a1 = operands[1]; + + operands[5] = addr0; + operands[6] = addr1; + + operands[0] = gen_rtx (MEM, BLKmode, addr0); + operands[1] = gen_rtx (MEM, BLKmode, addr1); + + if(INTVAL (operands[2]) <= 10 && !(INTVAL(operands[3])&1)) + { + int x = INTVAL (operands[2]); + int y = (x&~1) >> 1; + int i = 0; + + while(y--) + { + rtx dest = gen_rtx (MEM, HImode, gen_rtx_PLUS(HImode, addr0,GEN_INT(i))); + emit_insn(gen_movstrhi5(dest,addr1)); + i+= 2; + } + + if(x & 1) + { + rtx real_dst = gen_rtx (MEM, HImode, gen_rtx_PLUS(HImode, addr0,GEN_INT(x-1))); + emit_insn(gen_movstrqi5(real_dst,addr1)); + } + DONE; + } + else if(INTVAL (operands[2]) <= 6 && (INTVAL(operands[3])&1)) + { + int x = INTVAL (operands[2]); + int i = 0; + + while(x--) + { + rtx dst = gen_rtx (MEM, HImode, gen_rtx_PLUS(HImode, addr0,GEN_INT(i))); + emit_insn(gen_movstrqi5(dst,addr1)); + i++; + } + DONE; + } + else + { + operands[2] = copy_to_mode_reg (HImode, operands[2]); + operands[4] = operands[2]; + } +} +") + +(define_insn "movstrqi5" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m") + (mem:HI (match_operand:HI 1 "register_operand" "+r"))) + (set (match_dup 1) (plus:HI (match_dup 1) (const_int 1)))] + "" + "mov.b @%1+, %0" +[(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +(define_insn "movstrhi5" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m") + (mem:HI (match_operand:HI 1 "register_operand" "+r"))) + (set (match_dup 1) (plus:HI (match_dup 1) (const_int 2)))] + "" + "mov @%1+, %0" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +(define_insn "*movstrhi_insn" + [(set (mem:BLK (match_operand:HI 0 "register_operand" "r")) + (mem:BLK (match_operand:HI 1 "register_operand" "r"))) + (use (match_operand:HI 2 "register_operand" "r")) + (use (match_operand 3 "const_int_operand" "i")) + (clobber (match_dup 2)) + (clobber (match_dup 0)) + (clobber (match_dup 1))] + "" + "* return movstrhi_insn(insn, operands, NULL);" + [(set_attr "length" "6") + (set_attr "cc" "clobber")]) + + +(define_insn "*movstrqi_insn" + [(set (mem:BLK (match_operand:HI 0 "register_operand" "r")) + (mem:BLK (match_operand:HI 1 "register_operand" "r"))) + (use (match_operand:QI 2 "register_operand" "r")) + (use (match_operand 3 "const_int_operand" "i")) + (clobber (match_dup 2)) + (clobber (match_dup 0)) + (clobber (match_dup 1))] + "" + "* return movstrhi_insn(insn, operands, NULL);" + [(set_attr "length" "6") + (set_attr "cc" "clobber")]) + + + +;;======================================================================== +;; CLEAR STRING + +(define_expand "clrstrhi" + [(parallel [(set (match_operand:BLK 0 "memory_operand" "") + (const_int 0)) + (use (match_operand 1 "const_int_operand" "")) + (use (match_operand 2 "const_int_operand" "i")) + (clobber (match_dup 3)) + (clobber (match_dup 4))])] + "" + " +{ + rtx addr0; + + if (GET_CODE (operands[1]) != CONST_INT) FAIL; + operands[1] = copy_to_mode_reg (HImode, operands[1]); + operands[3] = operands[1]; + addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); + operands[4] = addr0; + operands[0] = gen_rtx (MEM, BLKmode, addr0); +}") + + +(define_insn "*clrstrhi_insn" + [(set (mem:BLK (match_operand:HI 0 "register_operand" "r")) + (const_int 0)) + (use (match_operand:HI 1 "register_operand" "r")) + (use (match_operand 2 "const_int_operand" "i")) + (clobber (match_dup 1)) + (clobber (match_dup 0))] + "" + "* return clrstrhi_insn(insn, operands, NULL);" +[(set_attr "length" "6") + (set_attr "cc" "clobber")]) + + +;;======================================================================== +;; %0 = strchr(%1,%2) - %1 + +(define_expand "strlenhi" + [(set (match_dup 4) + (unspec:HI [(match_operand:BLK 1 "memory_operand" "") + (match_operand 2 "const_int_operand" "") + (match_operand:HI 3 "immediate_operand" "")] 3)) + (set (match_operand:HI 0 "register_operand" "") + (minus:HI (match_dup 4) + (match_dup 5)))] + + "" + " +{ + rtx addr; + + if (! (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0)) + FAIL; + addr = copy_to_mode_reg (Pmode, XEXP (operands[1],0)); + operands[1] = gen_rtx (MEM, BLKmode, addr); + operands[5] = addr; + operands[4] = gen_reg_rtx (HImode); + +}") + + +(define_insn "*strlenhi" + [(set (match_operand:HI 0 "register_operand" "=r") + (unspec:HI [(mem:BLK (match_operand:HI 1 "register_operand" "0")) + (const_int 0) + (match_operand:HI 2 "immediate_operand" "i") ] 3))] + "" +"dec %0 +.L__strlenhi__%=: + inc %0 + tst.b 0(%0) + jne .L__strlenhi__%=" +[(set_attr "length" "5") + (set_attr "cc" "clobber")]) + + +;;======================================================================== +;; MOV code +;; +;; + + +;;======================================================================== +;; move byte +;; nothing much special +;; all addressing modes allowed +;; fits perfectly into a single instruction + +(define_expand "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") + (match_operand:QI 1 "general_operand" ""))] + "" + "") + +(define_insn "*movqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "=m,m,m,m,r,r,r,r") + (match_operand:QI 1 "general_operand_msp430" " m,r,P,i,m,r,P,i"))] + "" + "mov.b\\t%1, %0" + [(set_attr "length" "3,2,3,3,2,1,2,2") + (set_attr "cc" "none,none,none,none,none,none,none,none")]) + + +(define_insn "movqipi" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") + (mem:QI (post_inc:QI (match_operand:HI 1 "register_operand" "r,r"))))] + "" + "mov.b @%1+, %0" +[(set_attr "length" "1,2") + (set_attr "cc" "none,none")]) + + + +;;============================================================================ +;; move word (16 bit) +;; the same as above + +(define_expand "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") + (match_operand:HI 1 "general_operand_msp430" ""))] + "" + "") + +(define_insn "*movhi3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m,m,m,m,r,r,r,r") + (match_operand:HI 1 "general_operand_msp430" " r,m,P,i,r,m,P,i"))] + "" + "mov\\t%1, %0 " + [(set_attr "length" "2,3,3,3,1,2,2,2") + (set_attr "cc" "none")]) + +(define_insn "movhipi" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") + (mem:HI (post_inc:HI (match_operand:HI 1 "register_operand" "r,r"))))] + "" + "mov @%1+, %0" +[(set_attr "length" "1,2") + (set_attr "cc" "none,none")]) + +;;============================================================================ +;; move long (32 bit) +;; the same as above + +(define_expand "movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + "") + +(define_insn "*movsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (match_operand:SI 1 "general_operand" " rmi"))] +"" +"* return msp430_movesi_code(insn,operands,NULL);" + [(set_attr "length" "6") + (set_attr "cc" "none")]) + +(define_insn "movsipi" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,m") + (mem:SI (post_inc (match_operand:HI 1 "register_operand" "r,r"))))] + "" + "mov @%1+, %A0 + mov @%1+, %B0" +[(set_attr "length" "2,4") + (set_attr "cc" "none,none")]) + + + +;;============================================================================ +;; floats are the SI + +(define_expand "movsf" + [(set (match_operand:SF 0 "nonimmediate_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + "") + +(define_insn "*movsf3" + [(set (match_operand:SF 0 "nonimmediate_operand" "=rm") + (match_operand:SF 1 "general_operand" "rmi"))] +"" +"* return msp430_movesi_code(insn,operands,NULL);" + [(set_attr "length" "6") + (set_attr "cc" "none")]) + + +(define_insn "movsfpi" + [(set (match_operand:SF 0 "nonimmediate_operand_msp430" "=r,m") + (mem:SF (post_inc (match_operand:HI 1 "register_operand" "r,r"))))] + "" + "mov @%1+, %A0 + mov @%1+, %B0" +[(set_attr "length" "2,4") + (set_attr "cc" "none,none")]) + +;;============================================================================ +;; move long long (64 bit) +;; the same as above +(define_expand "movdi" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + "") + +(define_insn "*movdi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (match_operand:DI 1 "general_operand" "rmi"))] +"" +"* return msp430_movedi_code(insn,operands,NULL);" + [(set_attr "length" "12") + (set_attr "cc" "none")]) + + +(define_insn "movdipi" + [(set (match_operand:DI 0 "nonimmediate_operand_msp430" "=r,m") + (mem:DI (post_inc (match_operand:HI 1 "register_operand" "r,r"))))] + "" + "mov @%1+, %A0 + mov @%1+, %B0 + mov @%1+, %C0 + mov @%1+, %D0" +[(set_attr "length" "4,8") + (set_attr "cc" "none,none")]) + + +;;============================================================================ +;; ARITHMETIC CODE +;; + + +;; random operations: + +(define_insn "*opqi3_pi" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") + (match_operator:QI 3 "three_operands_msp430" + [(match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0") + (mem:QI (post_inc (match_operand:HI 2 "register_operand" "r,r")))]))] +"" +"%3.b @%2+, %0" + [(set_attr "length" "1,2") + (set_attr "cc" "oper,oper")]) + +(define_insn "*ophi3_pi" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") + (match_operator:HI 3 "three_operands_msp430" + [(match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0") + (mem:HI (post_inc (match_operand:HI 2 "register_operand" "r,r")))]))] +"" +"%3 @%2+, %0" + [(set_attr "length" "1,2") + (set_attr "cc" "oper,oper")]) + +(define_insn "*opsi3_pi" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,m") + (match_operator:SI 3 "three_operands_msp430" + [(match_operand:SI 1 "nonimmediate_operand_msp430" "%0,0") + (mem:SI (post_inc (match_operand:HI 2 "register_operand" "r,r")))]))] +"" +"%A3\\t@%2+, %A0 +\\t%B3\\t@%2+, %B0" + [(set_attr "length" "1,2") + (set_attr "cc" "oper,oper")]) + +(define_insn "*opdi3_pi" + [(set (match_operand:DI 0 "nonimmediate_operand_msp430" "=r,m") + (match_operator:DI 3 "three_operands_msp430" + [(match_operand:DI 1 "nonimmediate_operand_msp430" "%0,0") + (mem:DI (post_inc (match_operand:HI 2 "register_operand" "r,r")))]))] +"" +"%A3\\t@%2+, %A0 +\\t%B3\\t@%2+, %B0 +\\t%C3\\t@%2+, %C0 +\\t%D3\\t@%2+, %D0" + [(set_attr "length" "1,2") + (set_attr "cc" "oper,oper")]) + + + + +;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +;; add 1 byte + + +(define_expand "addqi3" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") + (plus:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") + (match_operand:QI 2 "general_operand_msp430" "")))] + "" + "") + +(define_insn "*addqi3_cg" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=m,r") + (plus:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0") + (match_operand 2 "const_int_operand" "i,i")))] +"(INTVAL(operands[2]) == -2 + || INTVAL(operands[2]) == -4 + || INTVAL(operands[2]) == -8 )" +"* { + operands[2] = gen_rtx_CONST_INT(QImode, -INTVAL(operands[2])); + return \"sub.b\\t%2, %0\"; +}" +[(set_attr "length" "2,1") + (set_attr "cc" "set_czn,set_czn")]) + + +(define_insn "*addqi3_3" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=m,m,m,m,r,r,r,r") + (plus:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") + (match_operand:QI 2 "general_operand_msp430" " m,r,P,i,m,r,P,i")))] +"" + "add.b %2, %0" + [(set_attr "length" "3,2,2,3,2,1,1,2") + (set_attr "cc" "set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) + + +;;============================================================================ +;; add 1 word (16 bits) +;; same as above + + +(define_expand "addhi3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") + (plus:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "") + (match_operand:HI 2 "general_operand_msp430" "")))] + "" + "") + +(define_insn "*addhi3_cg" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m,r") + (plus:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0") + (match_operand 2 "const_int_operand" "i,i")))] +"(INTVAL(operands[2]) == -2 + || INTVAL(operands[2]) == -4 + || INTVAL(operands[2]) == -8 )" +"* { + operands[2] = gen_rtx_CONST_INT(HImode, -INTVAL(operands[2])); + return \"sub\\t%2, %0\" ; +}" +[(set_attr "length" "2,1") + (set_attr "cc" "set_czn,set_czn")]) + +(define_insn "*addhi3_3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m,m,m,m,r,r,r,r") + (plus:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") + (match_operand:HI 2 "general_operand_msp430" " m,r,P,i,m,r,P,i")))] +"" + "add %2, %0" + [(set_attr "length" "3,2,2,3,2,1,1,2") + (set_attr "cc" +"set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) + + +;;============================================================================ +;; add 2 words (32 bits) +;; same as above + +(define_expand "addsi3" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "") + (plus:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "") + (match_operand:SI 2 "general_operand_msp430" "")))] + "" + "") + +(define_insn "*addsi3_cg" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=m,r") + (plus:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "%0,0") + (match_operand 2 "const_int_operand" "i,i")))] +"(INTVAL(operands[2]) == -2 + || INTVAL(operands[2]) == -4 + || INTVAL(operands[2]) == -8 )" +"* { + operands[2] = gen_rtx_CONST_INT(SImode, -INTVAL(operands[2])); + return \"sub\\t%A2, %A0\\n\\tsubc\\t%B2, %B0\" ; +}" +[(set_attr "length" "4,2") + (set_attr "cc" "further,further")]) + + +(define_insn "*addsi3_3" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=rm") + (plus:SI (match_operand:SI 1 "general_operand_msp430" "%0") + (match_operand:SI 2 "general_operand_msp430" " rmi")))] +"" +"* return msp430_addsi_code(insn, operands, NULL);" + [(set_attr "length" "6") + (set_attr "cc" "further")]) + + +;;============================================================================ +;; add 4 words (64 bits) +;; same as above + +(define_expand "adddi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (plus:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:DI 2 "general_operand" "")))] + "" + "") + +(define_insn "*adddi3_cg" + [(set (match_operand:DI 0 "nonimmediate_operand_msp430" "=m,r") + (plus:DI (match_operand:DI 1 "nonimmediate_operand_msp430" "%0,0") + (match_operand:DI 2 "const_int_operand" "i,i")))] +"(INTVAL(operands[2]) == -2 + || INTVAL(operands[2]) == -4 + || INTVAL(operands[2]) == -8 )" +"* { + operands[2] = gen_rtx_CONST_INT(DImode, -INTVAL(operands[2])); + return \"sub\\t%A2, %A0\\n\\tsubc\\t%B2, %B0\\n\\tsubc\\t%C2, %C0\\n\\tsubc\\t%D2, %D0\"; +}" +[(set_attr "length" "4,2") +(set_attr "cc" "further,further")]) + +(define_insn "*adddi3_3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0") + (match_operand:DI 2 "general_operand" " rmi")))] +"" +"* return msp430_adddi_code(insn, operands, NULL);" + [(set_attr "length" "12") + (set_attr "cc" "further")]) + + +;;----------------------------------------------------------------------- +;;----------------------------------------------------------------------- +;;----------------------------------------------------------------------- +;;----------------------------------------------------------------------- +;;----------------------------------------------------------------------- +;; sub 1 byte + + +(define_expand "subqi3" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") + (minus:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") + (match_operand:QI 2 "general_operand_msp430" "")))] + "" + "") + +(define_insn "*subqi3_3" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=m,m,m,m,r,r,r,r") + (minus:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "0,0,0,0,0,0,0,0") + (match_operand:QI 2 "general_operand_msp430" " m,r,P,i,m,r,P,i")))] +"" + "sub.b %2, %0" + [(set_attr "length" "3,2,2,3,2,1,1,2") + (set_attr "cc" "set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) + + +;;============================================================================ +;; sub 1 word (16 bits) +;; same as above + + +(define_expand "subhi3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") + (minus:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "") + (match_operand:HI 2 "general_operand_msp430" "")))] + "" + "") + +(define_insn "*subhi3_3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m,m,m,m,r,r,r,r") + (minus:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0,0,0,0,0,0,0") + (match_operand:HI 2 "general_operand_msp430" "m,r,P,i,m,r,P,i")))] +"" + "sub %2, %0" + [(set_attr "length" "3,2,2,3,2,1,1,2") + (set_attr "cc" +"set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) + + +;;============================================================================ +;; sub 2 words (32 bits) +;; same as above + +(define_expand "subsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (minus:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + "") + + +(define_insn "*subsi3_3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (minus:SI (match_operand:SI 1 "general_operand" "0") + (match_operand:SI 2 "general_operand" " rmi")))] +"" +"* return msp430_subsi_code(insn, operands, NULL);" + [(set_attr "length" "6") + (set_attr "cc" "further")]) + + +;;============================================================================ +;; sub 4 words (64 bits) +;; same as above + +(define_expand "subdi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (minus:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:DI 2 "general_operand" "")))] + "" + "") + +(define_insn "*subdi3_3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand:DI 2 "general_operand" " rmi")))] +"" +"* return msp430_subdi_code(insn, operands,NULL);" + [(set_attr "length" "12") + (set_attr "cc" "set_n")]) + + + + + +;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& +;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& +;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& +;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& +;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& +;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& +;;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& +;; and 1 byte + + +(define_expand "andqi3" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") + (and:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") + (match_operand:QI 2 "general_operand_msp430" "")))] + "" + "") + + +(define_insn "*andqi3_inv" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") + (and:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0") + (match_operand:QI 2 "immediate_operand" " i,i")))] +"(INTVAL(operands[2])==~1 + || INTVAL(operands[2])==~2 + || INTVAL(operands[2])==~4 + || INTVAL(operands[2])==~8)" +"* { + operands[2] = gen_rtx_CONST_INT(QImode, ~(INTVAL(operands[2]))); + return \"bic.b %2,%0\"; +}" + [(set_attr "length" "1,2") + (set_attr "cc" "none,none")]) + + +(define_insn "*andqi3_3" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m,r,m,r,m,m,r") + (and:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") + (match_operand:QI 2 "general_operand_msp430" " r,m,P,P,m,r,i,i")))] +"" +"and.b %2, %0" + [(set_attr "length" "1,3,1,2,2,2,3,2") + (set_attr "cc" "set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) + + + + +;;============================================================================ +;; and 1 word (16 bits) +;; same as above + +(define_expand "andhi3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") + (and:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0") + (match_operand:HI 2 "general_operand_msp430" "")))] + "" + "") + + +(define_insn "*andhi3_inv" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") + (and:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0") + (match_operand:HI 2 "immediate_operand" " i,i")))] +"(INTVAL(operands[2])==~1 + || INTVAL(operands[2])==~2 + || INTVAL(operands[2])==~4 + || INTVAL(operands[2])==~8)" +"* { + operands[2] = gen_rtx_CONST_INT(HImode, ~(INTVAL(operands[2]))); + return \"bic %2,%0\"; +}" + [(set_attr "length" "1,2") + (set_attr "cc" "none,none")]) + +(define_insn "*andhi3_clrup" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m") + (and:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0") + (match_operand:HI 2 "immediate_operand" " i,i")))] +"INTVAL(operands[2])==255" +"* { + if(which_alternative == 0) + { + return \"and.b #-1, %0\"; + } + else if(which_alternative == 1) + { + return \"clr.b %J0\"; + } + + return \"bug\"; +}" + [(set_attr "length" "1,2") + (set_attr "cc" "clobber,clobber")]) + +(define_insn "*andhi3_clrlw" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m,r") + (and:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0") + (match_operand:HI 2 "immediate_operand" " i,i")))] +"((0xffff&INTVAL(operands[2]))==0xff00)" +"@ +clr.b %I0 +and\\t#0xff00, %0" + [(set_attr "length" "2") + (set_attr "cc" "clobber")]) + + +(define_insn "*andhi3_3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m,r,m,r,m,m,r") + (and:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") + (match_operand:HI 2 "general_operand_msp430" " r,m,P,P,m,r,i,i")))] +"" +"and %2, %0" + [(set_attr "length" "1,3,1,2,2,2,3,2") + (set_attr "cc" "set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) + + + + + +;;============================================================================ +;; and 2 words (32 bits) +;; same as above + +(define_expand "andsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (and:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + "") + +(define_insn "*andsi3_3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" " rmi")))] +"" +"* return msp430_andsi_code(insn, operands, NULL);" + [(set_attr "length" "6") + (set_attr "cc" "set_n")]) + + +;;============================================================================ +;; and 4 words (64 bits) +;; same as above + +(define_expand "anddi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (and:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:DI 2 "general_operand" "")))] + "" + "") + +(define_insn "*anddi3_3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (and:DI (match_operand:DI 1 "nonimmediate_operand" "%0") + (match_operand:DI 2 "general_operand" " rmi")))] +"" +"* return msp430_anddi_code(insn, operands, NULL);" + [(set_attr "length" "14") + (set_attr "cc" "clobber")]) + + + +;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +;;||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +;; ior 1 byte +;; looks like a 'mov' insn + +(define_expand "iorqi3" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") + (ior:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") + (match_operand:QI 2 "general_operand_msp430" "")))] + "" + "") + +(define_insn "*iorqi3_3" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m,r,m,r,m,m,r") + (ior:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") + (match_operand:QI 2 "general_operand_msp430" " r,m,P,P,m,r,i,i")))] +"" + "bis.b %2, %0" + [(set_attr "length" "1,3,1,2,2,2,3,2") + (set_attr "cc" "none,none,none,none,none,none,none,none")]) + + + +;;============================================================================ +;; ior 1 word (16 bits) +;; same as above + +(define_expand "iorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") + (ior:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "") + (match_operand:HI 2 "general_operand_msp430" "")))] + "" + " + if(const_int_operand(operands[2], VOIDmode)) + { + int x = INTVAL(operands[2]) & 0xffff; + if(!x) DONE; + } + ") + +(define_insn "*iorhi3_3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m,r,m,r,m,m,r") + (ior:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") + (match_operand:HI 2 "general_operand_msp430" " r,m,P,P,m,r,i,i")))] +"" + "bis %2, %0" + [(set_attr "length" "1,3,1,2,2,2,3,2") + (set_attr "cc" "none,none,none,none,none,none,none,none")]) + + + +;;============================================================================ +;; ior 2 words (32 bits) +;; same as above + + +(define_expand "iorsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (ior:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + "") + +(define_insn "*iorsi3_3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" " rmi")))] +"" +"* return msp430_iorsi_code(insn, operands, NULL);" + [(set_attr "length" "6") + (set_attr "cc" "none")]) + +(define_split + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (ior:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "reload_completed + && (halfnibble_integer(operands[2], VOIDmode) + || halfnibble_constant(operands[2], VOIDmode))" + [(set (match_dup 3) (ior:HI (match_dup 4) (match_dup 5)))] + "{ + int lo = trunc_int_for_mode(INTVAL(operands[2]),HImode); + int hi = trunc_int_for_mode(INTVAL(operands[2])>>16,HImode); + + if(lo == -1) + { + rtx op = gen_lowpart(HImode, operands[0]); + emit_insn(gen_rtx_SET(HImode, op, GEN_INT(-1))); + DONE; + } + + if(hi == -1) + { + rtx op = gen_highpart(HImode, operands[0]); + emit_insn(gen_rtx_SET(HImode, op, GEN_INT(-1))); + DONE; + } + + if(lo) + { + operands[3] = gen_lowpart(HImode, operands[0]); + operands[4] = gen_lowpart(HImode, operands[1]); + operands[5] = GEN_INT(lo); + } + else if(hi) + { + operands[3] = gen_highpart(HImode, operands[0]); + operands[4] = gen_highpart(HImode, operands[1]); + operands[5] = GEN_INT(hi); + } + }") + +(define_peephole2 + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") + (const_int 0)) + (set (match_dup 0) (ior:HI (match_dup 0) + (match_operand:HI 1 "const_int_operand" "")))] + "" + [(set (match_dup 0) (match_dup 1))] + "") + + +;;============================================================================ +;; ior 4 words (64 bits) +;; same as above + +(define_expand "iordi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (ior:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:DI 2 "general_operand" "")))] + "" + "") + +(define_insn "*iordi3_3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (ior:DI (match_operand:DI 1 "nonimmediate_operand" "%0") + (match_operand:DI 2 "general_operand" " rmi")))] +"" +"* return msp430_iordi_code(insn, operands, NULL);" + [(set_attr "length" "12") + (set_attr "cc" "none")]) + + + +;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +;; xor 1 byte +;; looks like a 'mov' insn + +(define_expand "xorqi3" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") + (xor:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") + (match_operand:QI 2 "general_operand_msp430" "")))] + "" + "") + +(define_insn "*xorqi3_3" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m,r,m,r,m,m,r") + (xor:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") + (match_operand:QI 2 "general_operand_msp430" " r,m,P,P,m,r,i,i")))] +"" + "xor.b %2, %0" + [(set_attr "length" "1,3,1,2,2,2,3,2") + (set_attr "cc" "set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) + + + +;;============================================================================ +;; xor 1 word (16 bits) +;; same as above + +(define_expand "xorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") + (xor:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "") + (match_operand:HI 2 "general_operand_msp430" "")))] + "" + "") + +(define_insn "*xorhi3_3" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m,r,m,r,m,m,r") + (xor:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0,0,0,0,0,0,0") + (match_operand:HI 2 "general_operand_msp430" " r,m,P,P,m,r,i,i")))] +"" + "xor %2, %0" + [(set_attr "length" "1,3,1,2,2,2,3,2") + (set_attr "cc" "set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn,set_czn")]) + + + +;;============================================================================ +;; xor 2 words (32 bits) +;; same as above + +(define_expand "xorsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (xor:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand" "")))] + "" + "") + + +(define_insn "*xorsi3_3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") + (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" " rmi")))] +"" +"* return msp430_xorsi_code(insn, operands, NULL);" + [(set_attr "length" "6") + (set_attr "cc" "set_n")]) + + +(define_split + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (xor:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:SI 2 "const_int_operand" "")))] + "reload_completed + && (halfnibble_integer(operands[2], VOIDmode) + || halfnibble_constant(operands[2], VOIDmode)) + && INTVAL(operands[2])" + [(set (match_dup 3) (xor:HI (match_dup 4) (match_dup 5)))] + "{ + int lo = trunc_int_for_mode(INTVAL(operands[2]),HImode); + int hi = trunc_int_for_mode(INTVAL(operands[2])>>16,HImode); + + if(lo) + { + operands[3] = gen_lowpart(HImode, operands[0]); + operands[4] = gen_lowpart(HImode, operands[1]); + operands[5] = GEN_INT(lo); + } + else if(hi) + { + operands[3] = gen_highpart(HImode, operands[0]); + operands[4] = gen_highpart(HImode, operands[1]); + operands[5] = GEN_INT(hi); + } + }") + + +(define_peephole2 + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") + (const_int 0)) + (set (match_dup 0) (xor:HI (match_dup 0) + (const_int -1)))] + "" + [(set (match_dup 0) (const_int -1))] + "") + + +;;============================================================================ +;; xor 4 words (64 bits) +;; same as above + +(define_expand "xordi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (xor:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:DI 2 "general_operand" "")))] + "" + "") + +(define_insn "*xordi3_3" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (xor:DI (match_operand:DI 1 "nonimmediate_operand" "%0") + (match_operand:DI 2 "general_operand" " rmi")))] +"" +"* return msp430_xordi_code(insn, operands, NULL);" + [(set_attr "length" "4") + (set_attr "cc" "set_n")]) + + + + + +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;; neg +;; same as above + +(define_expand "negqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (neg:QI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + "{ emit_insn(gen_one_cmplqi2(operands[0],operands[1])); + emit_insn(gen_addqi3(operands[0],operands[0],const1_rtx)); + DONE; }") + +(define_expand "neghi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (neg:HI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" + "{ emit_insn(gen_one_cmplhi2(operands[0],operands[1])); + emit_insn(gen_addhi3(operands[0],operands[0],const1_rtx)); + DONE; }") + +(define_expand "negsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (neg:SI (match_operand:SI 1 "nonimmediate_operand" "")))] + "" + + "{ emit_insn(gen_one_cmplsi2(operands[0],operands[1])); + emit_insn(gen_addsi3(operands[0],operands[0],const1_rtx)); + DONE; }") + +(define_expand "negdi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (neg:DI (match_operand:DI 1 "nonimmediate_operand" "")))] + "" + + "{ emit_insn(gen_one_cmpldi2(operands[0],operands[1])); + emit_insn(gen_adddi3(operands[0],operands[0],const1_rtx)); + DONE; }") + +(define_insn "negsf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,m") + (neg:SF (match_operand:SF 1 "nonimmediate_operand" "0,0")))] + "" + "xor #0x8000, %B0" + [(set_attr "length" "2,3") + (set_attr "cc" "clobber,clobber")]) + +;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +;; not x = !x +;; ones component + +(define_expand "one_cmplqi2" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") + (not:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "")))] + "" + "") + +(define_insn "*one_cmplqi2_2" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") + (not:QI (match_operand:QI 1 "nonimmediate_operand_msp430" " 0, 0")))] + "" + "inv.b %0" + [(set_attr "length" "1,2") + (set_attr "cc" "set_czn,set_czn")]) + + +;;============================================================================ +;; not HI x = !x +;; - ones component + +(define_expand "one_cmplhi2" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "") + (not:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0")))] + "" + "") + +(define_insn "*one_cmplhi2_2" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r, m") + (not:HI (match_operand:HI 1 "nonimmediate_operand_msp430" " 0, 0")))] + "" + "inv %0" + [(set_attr "length" "1,2") + (set_attr "cc" "set_czn,set_czn")]) + + + +;;============================================================================ +;; not SI x = !x +;; - ones component + +(define_expand "one_cmplsi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))] + "" + "") + +(define_insn "*one_cmplsi2_2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r, m") + (not:SI (match_operand:SI 1 "nonimmediate_operand" " 0, 0")))] +"" + "inv %A0 + inv %B0" + [(set_attr "length" "2,4") + (set_attr "cc" "set_n,set_n")]) + + +;;============================================================================ +;; not DI x = !x +;; - ones component + +(define_expand "one_cmpldi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (not:DI (match_operand:DI 1 "nonimmediate_operand" "0")))] + "" + "") + +(define_insn "*one_cmpldi2_2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r, m") + (not:DI (match_operand:DI 1 "nonimmediate_operand" " 0, 0")))] + "" + "inv %A0 + inv %B0 + inv %C0 + inv %D0" + [(set_attr "length" "4,8") + (set_attr "cc" "set_n,set_n")]) + + + +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;;============================================================================ +;; abs +;; x = |x| + +(define_expand "absqi2" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (abs:QI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" + "") + +(define_insn "*absqi2_2" + [(set (match_operand:QI 0 "nonimmediate_operand" "=r,m") + (abs:QI (match_operand:QI 1 "nonimmediate_operand" " 0, 0")))] + "" + "tst.b %0 + jge .Leaq%= + inv.b %0 + inc.b %0 +.Leaq%=:" + [(set_attr "length" "4,7") + (set_attr "cc" "set_czn,set_czn")]) + + +;;============================================================================ +;; abs HI x = |x| +;; + +(define_expand "abshi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (abs:HI (match_operand:HI 1 "nonimmediate_operand" "0")))] + "" + "") + + +(define_insn "*abshi2_2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r, m") + (abs:HI (match_operand:HI 1 "nonimmediate_operand" " 0, 0")))] + "" + "tst %0 + jge .Lae%= + inv %0 + inc %0 +.Lae%=:" + [(set_attr "length" "4,7") + (set_attr "cc" "set_czn,set_czn")]) + + +;;============================================================================ +;; abs SI x = |x| + +(define_expand "abssi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (abs:SI (match_operand:SI 1 "nonimmediate_operand" "0")))] + "" + "") + +(define_insn "*abssi2_2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r, m") + (abs:SI (match_operand:SI 1 "nonimmediate_operand" " 0, 0")))] + "" + "* return msp430_emit_abssi(insn, operands,NULL);" + [(set_attr "length" "7,13") + (set_attr "cc" "clobber,clobber")]) + + +;;============================================================================ +;; abs DI x = |x| + +(define_expand "absdi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (abs:DI (match_operand:DI 1 "nonimmediate_operand" "0")))] + "" + "") + +(define_insn "*absdi2_2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r, m") + (abs:DI (match_operand:DI 1 "nonimmediate_operand" " 0, 0")))] + "" + "* return msp430_emit_absdi(insn, operands,NULL);" + [(set_attr "length" "11,23") + (set_attr "cc" "clobber,clobber")]) + +;;============================================================================ +;; abs SF + +(define_insn "abssf2" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,m") + (abs:SF (match_operand:SF 1 "nonimmediate_operand" "0,0")))] +"" +"and #0x7fff, %B0" + [(set_attr "length" "2,3") + (set_attr "cc" "clobber,clobber")]) + + +;; ========================================================================== +;; there are shift helpers + +(define_insn "trunchiqi" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m") + (truncate:QI (match_operand:HI 1 "register_operand" "r,r")))] +"" +"mov.b %1, %0" + [(set_attr "length" "1,2") + (set_attr "cc" "none,none")]) + +(define_insn "truncsihi" + [(set (match_operand:HI 0 "register_operand" "=r") + (truncate:HI (match_operand:SI 1 "register_operand" "r")))] +"" +"mov %1, %0" + [(set_attr "length" "1") + (set_attr "cc" "none")]) + + +(define_insn "truncsiqi" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:SI 1 "register_operand" "r")))] +"" +"mov.b %1, %0" + [(set_attr "length" "1") + (set_attr "cc" "none")]) + + +(define_insn "truncdiqi" + [(set (match_operand:QI 0 "register_operand" "=r") + (truncate:QI (match_operand:DI 1 "register_operand" "r")))] +"" +"mov.b %1, %0" + [(set_attr "length" "1") + (set_attr "cc" "none")]) + +(define_insn "truncdisi" + [(set (match_operand:SI 0 "register_operand" "=r") + (truncate:SI (match_operand:DI 1 "register_operand" "r")))] +"" +"mov %A1,%A0 + mov %B1,%B0" + [(set_attr "length" "2") + (set_attr "cc" "none")]) + + +(define_expand "rotlhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "const_int_operand" "")))] +"" +" + if(INTVAL(operands[2])!=8) FAIL; +") + +(define_insn "*rotlhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,m") + (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") + (const_int 8)))] +"" +"swpb\\t%0" + [(set_attr "length" "1,2") + (set_attr "cc" "none")]) + + +;;<< << << << << << << << << << << << << << << << << << << << << << << << << +;; << << << << << << << << << << << << << << << << << << << << << << << << +;;<< << << << << << << << << << << << << << << << << << << << << << << << << +;; << << << << << << << << << << << << << << << << << << << << << << << << +;;<< << << << << << << << << << << << << << << << << << << << << << << << << +;; arithmetic shift left + +(define_expand "ashlqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" "")))] +"" +"{ + if(!const_int_operand(operands[2],VOIDmode)) + { + rtx op0,op1; + + op0 = force_reg(QImode,operands[0]); + op1 = force_reg(QImode,operands[1]); + operands[2] = copy_to_mode_reg(QImode,operands[2]); + emit_insn(gen_ashlqi3_cnt (op0, op1, operands[2])); + emit_move_insn(operands[0],op0); + /*emit_move_insn(operands[1],op1);*/ + DONE; + } + else if(!register_operand(operands[1], QImode) + && is_shift_better_in_reg(operands)) + { + operands[1] = copy_to_mode_reg(QImode,operands[1]); + emit_insn (gen_ashlqi3fnl(operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_insn "ashlqi3_cnt" + [(parallel [(set (match_operand:QI 0 "register_operand" "=r") + (ashift:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "register_operand" ""))) + (clobber (match_dup 2))])] +"" +"* return msp430_emit_ashlqi3(insn, operands,NULL);" + [(set_attr "length" "8") + (set_attr "cc" "clobber")]) + +(define_insn "ashlqi3fnl" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=rm") + (ashift:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "0") + (match_operand 2 "const_int_operand" "i")))] + "" + "* return msp430_emit_ashlqi3(insn, operands,NULL);" + [(set_attr "length" "1") + (set_attr "cc" "clobber")]) + +;; HImode ====================================== +(define_expand "ashlhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand 2 "general_operand" "")))] +"" +"{ msp430_ashlhi3(operands); DONE; }") + +(define_insn "ashlhi3_cnt" + [(parallel [(set (match_operand:HI 0 "register_operand" "=r") + (ashift:HI (match_operand:HI 1 "register_operand" "0") + (match_operand:HI 2 "register_operand" "r"))) + (clobber (match_dup 2))])] + "" + "* return msp430_emit_ashlhi3(insn, operands,NULL);" + [(set_attr "length" "5") + (set_attr "cc" "clobber")]) + +(define_insn "*ashlhi3_1" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,R,m") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0,0") + (const_int 1)))] + "" + "rla\\t%0" + [(set_attr "length" "1,2,3") + (set_attr "cc" "clobber")]) + +(define_insn "*ashlhi3_15" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,R,m") + (ashift:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0,0") + (const_int 15)))] + "" + "rra\\t%0 +\\tclr\\t%0 +\\trrc\\t%0" + [(set_attr "length" "3,5,7") + (set_attr "cc" "clobber")]) + + +;; SImode ====================================== + +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" "")))] +"" +"{ msp430_ashlsi3(operands); DONE; }") + +(define_insn "ashlsi3_cnt" + [(parallel [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:HI 2 "register_operand" ""))) + (clobber (match_dup 2))])] +"" +"* return msp430_emit_ashlsi3(insn, operands,NULL);" + [(set_attr "length" "8") + (set_attr "cc" "clobber")]) + +(define_insn "*ashlsi3_31" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") + (const_int 31)))] + "" +"rra\\t%A0 +\\tclr\\t%A0 +\\tclr\\t%B0 +\\trrc\\t%B0" +[(set_attr "length" "4,7,8") + (set_attr "cc" "clobber")]) + + +(define_insn "*ashlsi3_8" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") + (const_int 8)))] + "" +"*{ + if(which_alternative==0) + { + return \"xor.b\\t%A0, %B0\\n\\txor\\t%A0, %B0\\n\\tswpb\\t%B0\\n\\tand.b\\t#-1, %A0\\n\\tswpb\\t%A0 \"; + } + else + { + return \"xor.b\\t%A0, %B0\\n\\tclr.b\\t%L0\\n\\txor\\t%A0, %B0\\n\\tswpb\\t%B0\\n\\tclr.b\\t%J0\\n\\tswpb\\t%A0\"; + } +}" + [(set_attr "length" "5,11,12") + (set_attr "cc" "clobber")]) + +(define_insn "*ashlsi3_16" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,m,r,m") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "rR,rR,m,m") + (const_int 16)))] +"" +"mov %A1, %B0 +\tmov #0, %A0" +[(set_attr "length" "1,2,2,3") + (set_attr "cc" "clobber")]) + +(define_insn "*ashlsi3_1" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=m,R,r") + (ashift:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") + (const_int 1)))] + "" +"rla\\t%A0 +\\trlc\\t%B0" +[(set_attr "length" "6,5,2") + (set_attr "cc" "clobber")]) + +;; DImode ====================================== + +(define_expand "ashldi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" "")))] +"" +"{ + if( !const_int_operand(operands[2],VOIDmode) || + INTVAL(operands[2]) > 1) + { + rtx op0,op1; + + op0 = force_reg(DImode,operands[0]); + op1 = force_reg(DImode,operands[1]); + operands[2] = copy_to_mode_reg(HImode,operands[2]); + emit_insn(gen_ashldi3_cnt (op0, op1, operands[2])); + emit_move_insn(operands[0],op0); + /*emit_move_insn(operands[1],op1);*/ + DONE; + } + else if(!register_operand(operands[1], DImode) + && is_shift_better_in_reg(operands)) + { + operands[1] = copy_to_mode_reg(DImode,operands[1]); + emit_insn (gen_ashldi3fnl(operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_insn "ashldi3_cnt" + [(parallel [(set (match_operand:DI 0 "register_operand" "=r") + (ashift:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:HI 2 "register_operand" ""))) + (clobber (match_dup 2))])] + "" + "* return msp430_emit_ashldi3(insn, operands,NULL);" + [(set_attr "length" "8") + (set_attr "cc" "clobber")]) + + +(define_insn "ashldi3fnl" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand 2 "const_int_operand" "i")))] + "" + "* return msp430_emit_ashldi3(insn, operands,NULL);" + [(set_attr "length" "1") + (set_attr "cc" "clobber")]) + +;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> +;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> +;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> +;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> +;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> +;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> +;; arithmetic shift right + +(define_expand "ashrqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" "")))] +"" +"{ + if(!const_int_operand(operands[2],VOIDmode)) + { + rtx op0,op1; + + op0 = force_reg(QImode,operands[0]); + op1 = force_reg(QImode,operands[1]); + operands[2] = copy_to_mode_reg(QImode,operands[2]); + emit_insn(gen_ashrqi3_cnt (op0, op1, operands[2])); + emit_move_insn(operands[0],op0); + /*emit_move_insn(operands[1],op1);*/ + DONE; + } + else if(!register_operand(operands[1], QImode) + && INTVAL(operands[2])>2 + && INTVAL(operands[2])!=7) + { + operands[1] = copy_to_mode_reg(QImode,operands[1]); + emit_insn (gen_ashrqi3fnl(operands[0], operands[1], operands[2])); + DONE; + } + else if(INTVAL(operands[2]) == 7) + { + /* to do it simple we need a register */ + rtx r1 = gen_reg_rtx(HImode); + emit_insn(gen_extendqihi2(r1,operands[1])); + emit_insn(gen_swpb(r1,r1)); + emit_insn(gen_trunchiqi(operands[0],r1)); + DONE; + } +}") + +(define_insn "ashrqi3_cnt" + [(parallel [(set (match_operand:QI 0 "register_operand" "=r") + (ashiftrt:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "register_operand" ""))) + (clobber (match_dup 2))])] +"" +"* return msp430_emit_ashrqi3(insn, operands,NULL);" + [(set_attr "length" "8") + (set_attr "cc" "clobber")]) + +(define_insn "ashrqi3fnl" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=rm") + (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "0") + (match_operand 2 "const_int_operand" "i")))] + "" + "* return msp430_emit_ashrqi3(insn, operands,NULL);" + [(set_attr "length" "1") + (set_attr "cc" "clobber")]) + +;; HImode ====================================== +(define_expand "ashrhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand 2 "general_operand" "")))] +"" +"{msp430_ashrhi3(operands); DONE; }") + +(define_insn "ashrhi3_cnt" + [(parallel [(set (match_operand:HI 0 "register_operand" "=r") + (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") + (match_operand:HI 2 "register_operand" ""))) + (clobber (match_dup 2))])] +"" +"* return msp430_emit_ashrhi3(insn, operands,NULL);" + [(set_attr "length" "5") + (set_attr "cc" "clobber")]) + + +(define_insn "*ashrhi3_1" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=rR,m") + (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0") + (const_int 1)))] + "" + "rra\\t%0" + [(set_attr "length" "1,2") + (set_attr "cc" "clobber")]) + + +(define_insn "*ashrhi3_15" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=rR,m") + (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0") + (const_int 15)))] + "" + "swpb\\t%0 +\\tsxt\\t%0 +\\tswpb\\t%0 +\\tsxt\\t%0" + [(set_attr "length" "4,8") + (set_attr "cc" "clobber")]) + + + +;; SImode ====================================== + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" "")))] +"" +"{msp430_ashrsi3(operands);DONE; }") + +(define_insn "ashrsi3_cnt" + [(parallel [(set (match_operand:SI 0 "register_operand" "=r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:HI 2 "register_operand" ""))) + (clobber (match_dup 2))])] +"" +"* return msp430_emit_ashrsi3(insn, operands,NULL);" + [(set_attr "length" "8") + (set_attr "cc" "clobber")]) + +(define_insn "*ashrsi3_1" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=rR,m") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0") + (const_int 1)))] + "" + "rra\\t%B0 +\\trrc\\t%A0" + [(set_attr "length" "2,4") + (set_attr "cc" "clobber")]) + +(define_insn "*ashrsi3_31" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") + (const_int 31)))] + "" +"swpb %B0 +\\tsxt %B0 +\\tswpb %B0 +\\tsxt %B0 +\\tmov %B0, %A0" + [(set_attr "length" "5,10,10") + (set_attr "cc" "clobber")]) + +(define_insn "*ashrsi3_8" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") + (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") + (const_int 8)))] + "" +"*{ + if(which_alternative==0) + { + return \" swpb\\t%A0\\n\\tswpb\\t%B0\\n\\txor.b\\t%B0, %A0\\n\\txor\\t%B0, %A0\\n\\tsxt\\t%B0\"; + } + else + { + return \" swpb\\t%A0\\n\\tswpb\\t%B0\\n\\txor.b\\t%B0, %A0\\n\\tclr.b\\t%J0\\n\\txor\\t%B0, %A0\\n\\tsxt\\t%B0\"; + } +}" + [(set_attr "length" "5,11,12") + (set_attr "cc" "clobber")]) + +;; DImode ====================================== + +(define_expand "ashrdi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" "")))] +"" +"{ + if( !const_int_operand(operands[2],VOIDmode)) + { + rtx op0,op1; + + op0 = force_reg(DImode,operands[0]); + op1 = force_reg(DImode,operands[1]); + operands[2] = copy_to_mode_reg(HImode,operands[2]); + emit_insn(gen_ashrdi3_cnt (op0, op1, operands[2])); + emit_move_insn(operands[0],op0); + /*emit_move_insn(operands[1],op1);*/ + DONE; + } + else if(!register_operand(operands[1], DImode) + && is_shift_better_in_reg(operands)) + { + operands[1] = copy_to_mode_reg(DImode,operands[1]); + emit_insn (gen_ashrdi3fnl(operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_insn "ashrdi3_cnt" + [(parallel [(set (match_operand:DI 0 "register_operand" "=r") + (ashiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:HI 2 "register_operand" ""))) + (clobber (match_dup 2))])] + "" + "* return msp430_emit_ashrdi3(insn, operands,NULL);" + [(set_attr "length" "8") + (set_attr "cc" "clobber")]) + + +(define_insn "ashrdi3fnl" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand 2 "const_int_operand" "i")))] + "" + "* return msp430_emit_ashrdi3(insn, operands,NULL);" + [(set_attr "length" "1") + (set_attr "cc" "clobber")]) + + + + + +;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> +;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> +;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> +;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> +;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> +;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> +;; logical shift right + +(define_expand "lshrqi3" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "") + (match_operand:QI 2 "general_operand" "")))] +"" +"{ + if(!const_int_operand(operands[2],VOIDmode)) + { + rtx op0,op1; + + op0 = force_reg(QImode,operands[0]); + op1 = force_reg(QImode,operands[1]); + operands[2] = copy_to_mode_reg(QImode,operands[2]); + emit_insn(gen_lshrqi3_cnt (op0, op1, operands[2])); + emit_move_insn(operands[0],op0); + /*emit_move_insn(operands[1],op1);*/ + DONE; + } + else if(!register_operand(operands[1], QImode) + && is_shift_better_in_reg(operands)) + { + operands[1] = copy_to_mode_reg(QImode,operands[1]); + emit_insn (gen_lshrqi3fnl(operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_expand "lshrqi3_cnt" + [(parallel [(set (match_operand:QI 0 "register_operand" "=r") + (lshiftrt:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "register_operand" ""))) + (clobber (match_dup 2))])] +"" +"") + +(define_insn "*lshrqi3_cnt" + [(parallel [(set (match_operand:QI 0 "register_operand" "=r") + (lshiftrt:QI (match_operand:QI 1 "register_operand" "0") + (match_operand:QI 2 "register_operand" ""))) + (clobber (match_dup 2))])] +"" +"* return msp430_emit_lshrqi3(insn, operands,NULL);" + [(set_attr "length" "8") + (set_attr "cc" "clobber")]) + +(define_insn "lshrqi3fnl" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=rm") + (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "0") + (match_operand 2 "const_int_operand" "i")))] + "" + "* return msp430_emit_lshrqi3(insn, operands,NULL);" + [(set_attr "length" "1") + (set_attr "cc" "clobber")]) + +;; HImode ====================================== + +(define_insn "clrc" + [(unspec:HI [(const_int 123454321)] 30)] +"" + "clrc" +[(set_attr "length" "1") + (set_attr "cc" "clobber")]) + + +(define_expand "lshrhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "") + (match_operand 2 "general_operand" "")))] +"" +"{msp430_lshrhi3(operands); DONE; }") + +(define_insn "lshrhi3_cnt" + [(parallel [(set (match_operand:HI 0 "register_operand" "=r") + (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") + (match_operand:HI 2 "register_operand" ""))) + (clobber (match_dup 2))])] +"" +"* return msp430_emit_lshrhi3(insn, operands,NULL);" + [(set_attr "length" "5") + (set_attr "cc" "clobber")]) + +(define_insn "*lshrhi3_15" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,R,m") + (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0,0") + (const_int 15)))] + "" + "rla\\t%0 +\\tclr\\t%0 +\\trlc\\t%0" + [(set_attr "length" "3,6,8") + (set_attr "cc" "clobber")]) + + +(define_insn "*lshrhi3_1" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=rR,m") + (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand_msp430" "0,0") + (const_int 1)))] + "" +"clrc +\\trrc\\t%0" + [(set_attr "length" "2,3") + (set_attr "cc" "clobber")]) + +;; SImode ====================================== + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" "")))] +"" +"{ msp430_lshrsi3(operands); DONE; }") + +(define_insn "lshrsi3_cnt" + [(parallel [(set (match_operand:SI 0 "register_operand" "=r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:HI 2 "register_operand" ""))) + (clobber (match_dup 2))])] +"" +"* return msp430_emit_lshrsi3(insn, operands,NULL);" + [(set_attr "length" "8") + (set_attr "cc" "clobber")]) + + +(define_insn "*lshrsi3_31" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") + (const_int 31)))] + "" +"rla %B0 +\\tclr %B0 +\\tclr %A0 +\\trlc %A0" + [(set_attr "length" "4,9,10") + (set_attr "cc" "clobber")]) + + +(define_insn "*lshrsi3_8" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") + (const_int 8)))] + "" +"*{ + if(which_alternative==0) + { + return \"swpb\\t%A0\\n\\tswpb\\t%B0\\n\\txor.b\\t%B0, %A0\\n\\txor\\t%B0, %A0\\n\\tand.b\\t#-1, %B0\"; + } + else + { + return \"swpb\\t%A0\\n\\tswpb\\t%B0\\n\\txor.b\\t%B0, %A0\\n\\tclr.b\\t%J0\\n\\txor\\t%B0, %A0\\n\\tclr.b\\t%L0\"; + } +}" + [(set_attr "length" "5,11,12") + (set_attr "cc" "clobber")]) + +(define_insn "*lshrsi3_1" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,R,m") + (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand_msp430" "0,0,0") + (const_int 1)))] + "" +"clrc +\\trrc\\t%B0 +\\trrc\\t%A0" + [(set_attr "length" "3,4,5") + (set_attr "cc" "clobber")]) + +;; DImode ====================================== + +(define_expand "lshrdi3" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "") + (match_operand:HI 2 "general_operand" "")))] +"" +"{ + if( !const_int_operand(operands[2],VOIDmode)) + { + rtx op0,op1; + + op0 = force_reg(DImode,operands[0]); + op1 = force_reg(DImode,operands[1]); + operands[2] = copy_to_mode_reg(HImode,operands[2]); + emit_insn(gen_lshrdi3_cnt (op0, op1, operands[2])); + emit_move_insn(operands[0],op0); + /*emit_move_insn(operands[1],op1);*/ + DONE; + } + else if(!register_operand(operands[1], DImode) + && is_shift_better_in_reg(operands)) + { + operands[1] = copy_to_mode_reg(DImode,operands[1]); + emit_insn (gen_lshrdi3fnl(operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_insn "lshrdi3_cnt" + [(parallel [(set (match_operand:DI 0 "register_operand" "=r") + (lshiftrt:DI (match_operand:DI 1 "register_operand" "0") + (match_operand:HI 2 "register_operand" ""))) + (clobber (match_dup 2))])] + "" + "* return msp430_emit_lshrdi3(insn, operands,NULL);" + [(set_attr "length" "8") + (set_attr "cc" "clobber")]) + + +(define_insn "lshrdi3fnl" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm") + (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand 2 "const_int_operand" "i")))] + "" + "* return msp430_emit_lshrdi3(insn, operands,NULL);" + [(set_attr "length" "1") + (set_attr "cc" "clobber")]) + + + + + + +;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x +;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x +;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x +;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x +;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x +;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x +;; sign extend + +(define_insn "extendqihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") + (sign_extend:HI (match_operand:QI 1 "general_operand" "0,*rmi")))] + "" + "* return signextendqihi(insn, operands,NULL);" + [(set_attr "length" "2,2") + (set_attr "cc" "set_n,set_n")]) + +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") + (sign_extend:SI (match_operand:QI 1 "general_operand" "0,*rmi")))] + "" + "* return signextendqisi(insn, operands,NULL);" + [(set_attr "length" "6,6") + (set_attr "cc" "set_n,set_n")]) + +(define_insn "extendqidi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") + (sign_extend:DI (match_operand:QI 1 "general_operand" "0,*rmi")))] + "" + "* return signextendqidi(insn, operands,NULL);" + [(set_attr "length" "6,6") + (set_attr "cc" "set_n,set_n")]) + +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") + (sign_extend:SI (match_operand:HI 1 "general_operand" "0,*rmi")))] + "" + "* return signextendhisi(insn, operands,NULL);" + [(set_attr "length" "6,6") + (set_attr "cc" "set_n,set_n")]) + +(define_insn "extendhidi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") + (sign_extend:DI (match_operand:HI 1 "general_operand" "0,*rmi")))] + "" + "* return signextendhidi(insn, operands,NULL);" + [(set_attr "length" "6,6") + (set_attr "cc" "set_n,set_n")]) + +(define_insn "extendsidi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") + (sign_extend:DI (match_operand:SI 1 "general_operand" "0,*rmi")))] + "" + "* return signextendsidi(insn, operands,NULL);" + [(set_attr "length" "6,6") + (set_attr "cc" "set_n,set_n")]) + +;; xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 +;; xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 +;; xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 +;; xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 +;; xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 +;; xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 xx<---0 +;; zero extend + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm") + (zero_extend:HI (match_operand:QI 1 "general_operand" "0,*rmi")))] + "" + "* return zeroextendqihi(insn, operands,NULL);" + [(set_attr "length" "2,2") + (set_attr "cc" "clobber,clobber")]) + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") + (zero_extend:SI (match_operand:QI 1 "general_operand" "0,*rmi")))] + "" + "* return zeroextendqisi(insn, operands,NULL);" + [(set_attr "length" "6,6") + (set_attr "cc" "clobber,clobber")]) + +(define_insn "zero_extendqidi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") + (zero_extend:DI (match_operand:QI 1 "general_operand" "0,*rmi")))] + "" + "* return zeroextendqidi(insn, operands,NULL);" + [(set_attr "length" "6,6") + (set_attr "cc" "clobber,clobber")]) + + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm") + (zero_extend:SI (match_operand:HI 1 "general_operand" "0,*rmi")))] + "" + "* return zeroextendhisi(insn, operands,NULL);" + [(set_attr "length" "6,6") + (set_attr "cc" "clobber,clobber")]) + +(define_insn "zero_extendhidi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") + (zero_extend:DI (match_operand:HI 1 "general_operand" "0,*rmi")))] + "" + "* return zeroextendhidi(insn, operands,NULL);" + [(set_attr "length" "6,6") + (set_attr "cc" "clobber,clobber")]) + +(define_insn "zero_extendsidi2" + [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,rm") + (zero_extend:DI (match_operand:SI 1 "general_operand" "0,*rmi")))] + "" + "* return zeroextendsidi(insn, operands,NULL);" + [(set_attr "length" "6,6") + (set_attr "cc" "clobber,clobber")]) + +;; ===================================================================== +;; single bit extract +;; as soon as all operatoins performed on io registers +;; let use only QImode. + +(define_expand "extv" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "") + (sign_extract:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "") + (match_operand 2 "const_int_operand" "") + (match_operand 3 "const_int_operand" "")))] +"" +"{ + if(INTVAL(operands[2]) != 1 || INTVAL(operands[3]) <= 0) + FAIL; +}") + +(define_insn "*extv" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,r,r,r,m,m,m,m") + (sign_extract:QI (match_operand:QI 1 "nonimmediate_operand_msp430" "r,m,r,m,r,m,r,m") + (const_int 1) + (match_operand 2 "const_int_operand" "P,P,i,i,P,P,i,i")))] + "" +"* { + operands[2] = GEN_INT(1<-500) + return \"jmp %0\"; + return \"br #%0\"; +}" + [(set_attr "length" "2") + (set_attr "cc" "none")]) + + +; indirect jump +(define_expand "indirect_jump" + [(set (pc) (match_operand:HI 0 "nonimmediate_operand" ""))] + "" + "") + +(define_insn "*indirect_jump_idx" + [(set (pc) (match_operand:HI 0 "memory_operand" "m"))] + "indexed_location(operands[0])" + "br @%E0" + [(set_attr "length" "1") + (set_attr "cc" "none")]) + +(define_insn "*indirect_jump_mem" + [(set (pc) (match_operand:HI 0 "memory_operand" "m"))] + "!indexed_location(operands[0])" + "br %0" + [(set_attr "length" "2") + (set_attr "cc" "none")]) + + +(define_insn "*indirect_jump_reg" + [(set (pc) (match_operand:HI 0 "register_operand" "r"))] + "" + "br %0" + [(set_attr "length" "1") + (set_attr "cc" "none")]) + + +;;======================================================================= +;;======================================================================= +;;======================================================================= +;;======================================================================= + + +;;======================================================================= +;; +;; CASE +;; + +/* +(define_expand "casesi" + [(set (match_dup 6) + (minus:HI (subreg:HI (match_operand:SI 0 "register_operand" "") 0) + (match_operand:HI 1 "register_operand" ""))) + (parallel [(set (cc0) + (compare (match_dup 6) + (match_operand:HI 2 "register_operand" "")))]) + (set (pc) + (if_then_else (gtu (cc0) + (const_int 0)) + (label_ref (match_operand 4 "" "")) + (pc))) + (set (match_dup 6) + (plus:HI (match_dup 6) (label_ref (match_operand:HI 3 "" "")))) + + (parallel [(set (pc) (unspec:HI [(match_dup 6)] 1)) + (use (label_ref (match_dup 3))) + (clobber (match_dup 6))])] + "" + " +{ + operands[6] = gen_reg_rtx (HImode); +}") + +*/ + +;; Table helper +(define_insn "tablejump" + [(set (pc) (match_operand:HI 0 "general_operand" "rRP,i,m")) + (use (label_ref (match_operand 1 "" "")))] + "" + "br %0 ; %1" + [(set_attr "length" "1,2,2") + (set_attr "cc" "clobber")]) + + +;; ============================================================= +;; match De Morgan's law +(define_insn "nandqi" + [(set (match_operand:QI 0 "nonimmediate_operand_msp430" "=r,m,m,r") + (and:QI (not:QI (match_operand:QI 1 "general_operand_msp430" "rRP,mi,rRP,mi")) + (match_operand:QI 2 "nonimmediate_operand_msp430" "0,0,0,0")))] +"" +"bic.b %1, %0" +[(set_attr "length" "1,3,2,2") + (set_attr "cc" "none")]) + +(define_insn "nandhi" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m,m,r") + (and:HI (not:HI (match_operand:HI 1 "general_operand_msp430" "rRP,mi,rRP,mi")) + (match_operand:HI 2 "nonimmediate_operand_msp430" "0,0,0,0")))] +"" +"bic %1, %0" +[(set_attr "length" "1,3,2,2") + (set_attr "cc" "none")]) + +(define_insn "nandsi" + [(set (match_operand:SI 0 "nonimmediate_operand_msp430" "=r,m,m,r,r,m") + (and:SI (not:SI (match_operand:SI 1 "general_operand_msp430" "rP,mi,rP,mi,R,R")) + (match_operand:SI 2 "nonimmediate_operand_msp430" "0,0,0,0,0,0")))] +"" +"bic %A1, %A0 +\\tbic %B1, %B0" +[(set_attr "length" "2,6,4,4,3,5") + (set_attr "cc" "none")]) + + + +;; ============================================================= +;; PEEPHOLES + +;; a &= ~b; + +(define_insn "*bit_clear" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=r,m,m,r") + (unspec_volatile:HI [(match_operand:HI 1 "general_operand_msp430" "rRP,mi,rRP,mi")] 40))] +"" +"bic %1, %0" + [(set_attr "length" "1,3,2,2") + (set_attr "cc" "none")]) + + +;; these two for: +;; (ulong) x = (ulong) func() << 16; +;; x |= func(); +;; func() is uint +;; + +;; do not check for zeros here, cause this insn already issued. +(define_peephole2 + [(set (match_operand:SI 1 "register_operand" "") + (sign_extend:SI (match_operand:HI 0 "register_operand" ""))) + (set (match_dup 1) (ashift:SI (match_dup 1) (const_int 16)))] +"" + [(set (subreg:HI (match_dup 1) 2) (match_dup 0))] +"") + +(define_peephole2 + [(set (match_operand:SI 1 "register_operand" "") + (zero_extend:SI (match_operand:HI 0 "register_operand" ""))) + (set (match_dup 1) (ashift:SI (match_dup 1) (const_int 16)))] +"" + [(set (subreg:HI (match_dup 1) 2) (match_dup 0))] +"") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "register_operand" ""))) + (set (match_operand:SI 2 "register_operand" "") + (ior:SI (match_dup 2) (match_dup 0)))] +"dead_or_set_in_peep(1,insn, operands[0])" + [(set (subreg:HI (match_dup 2) 0) + (ior:HI (subreg:HI (match_dup 2) 0) (match_dup 1)))] +"") + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "general_operand_msp430" "")) + (set (match_operand:SI 2 "register_operand" "") + (zero_extend:SI (match_dup 0))) + (set (match_operand:SI 3 "register_operand" "") + (ior:SI (match_dup 3) (match_dup 2)))] +"dead_or_set_in_peep(2,insn, operands[0])" + [(set (subreg:HI (match_dup 3) 0) + (ior:HI (subreg:HI (match_dup 3) 0) (match_dup 1)))] +"") + + +;; (ulong) x = (ulong) f >> 16; +;; +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "register_operand" "")) + (set (match_dup 0) + (lshiftrt:SI (match_dup 0) + (const_int 16)))] +"" +[(set (subreg:HI (match_dup 0) 0) (subreg:HI (match_dup 1) 2)) + (set (subreg:HI (match_dup 0) 2) (const_int 0))] +"") + + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "register_operand" "")) + (set (match_operand:SI 2 "register_operand" "") + (ior:SI (match_dup 2) (match_dup 0)))] +"dead_or_set_in_peep(1,insn, operands[0])" + [(set (match_dup 2) (ior:SI (match_dup 2) + (match_dup 1)))] +"") + + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (zero_extend:SI (match_operand:HI 1 "general_operand" ""))) + (set (match_dup 0) + (ashift:SI (match_dup 0) (const_int 16)))] +"" + [(set (subreg:HI (match_dup 0) 2) (match_dup 1))] +"") + + +;; shift right & set +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "register_operand" "")) + (set (match_operand:HI 2 "register_operand" "") + (match_dup 0)) + (set (match_dup 2) + (and:HI (match_dup 2) + (match_operand 3 "const_int_operand" ""))) + (set (match_dup 2) + (lshiftrt:HI (match_dup 2) + (match_operand 4 "const_int_operand" ""))) + (set (match_dup 1) (match_dup 2))] +"dead_or_set_in_peep(4,insn, operands[2])" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 1) + (and:HI (match_dup 1) + (match_dup 3))) + (set (match_dup 1) + (lshiftrt:HI (match_dup 1) + (match_dup 4)))] +"") + +;; shift left and set +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "register_operand" "")) + (set (match_operand:HI 2 "register_operand" "") + (match_dup 0)) + (set (match_dup 2) + (and:HI (match_dup 2) + (match_operand 3 "const_int_operand" ""))) + (set (match_dup 2) + (ashift:HI (match_dup 2) + (match_operand 4 "const_int_operand" ""))) + (set (match_dup 1) (match_dup 2))] +"dead_or_set_in_peep(4,insn, operands[2])" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 1) + (and:HI (match_dup 1) + (match_dup 3))) + (set (match_dup 1) + (ashift:HI (match_dup 1) + (match_dup 4)))] +"") + + +;; +;; these for some shifts and stuff. +;; every peephole saves up to 4 bytes. +;; + +(define_insn "*addc_reg" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (unspec:HI [(match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "general_operand_msp430" "rP,mi")] 0))] +"" +"addc %2, %0" +[(set_attr "length" "1,2") + (set_attr "cc" "clobber,clobber")]) + + +(define_insn "*addc_any" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=m,m") + (unspec:HI [(match_operand:HI 1 "nonimmediate_operand_msp430" "%0,0") + (match_operand:HI 2 "general_operand_msp430" "rP,mi")] 5))] +"" +"addc %2, %0" +[(set_attr "length" "2,3") + (set_attr "cc" "clobber,clobber")]) + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "general_operand_msp430" "")) + (set (match_operand:SI 2 "register_operand" "") + (zero_extend:SI (match_dup 0))) + (set (match_operand:SI 3 "register_operand" "") + (plus:SI (match_dup 3) (match_dup 2)))] +"dead_or_set_in_peep(2,insn, operands[2])" + [(set (subreg:HI (match_dup 3) 0) + (plus:HI (subreg:HI (match_dup 3) 0) + (match_dup 1))) + (set (subreg:HI (match_dup 3) 2) + (unspec:HI [(subreg:HI (match_dup 3) 2) (const_int 0)] 0))] +"") + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "general_operand_msp430" "")) + (set (match_operand:SI 2 "register_operand" "") + (zero_extend:SI (match_dup 0))) + (set (match_operand:SI 3 "nonimmediate_operand_msp430" "") + (plus:SI (match_dup 3) (match_dup 2)))] +"dead_or_set_in_peep(2,insn, operands[2])" + [(set (subreg:HI (match_dup 3) 0) + (plus:HI (subreg:HI (match_dup 3) 0) + (match_dup 1))) + (set (subreg:HI (match_dup 3) 2) + (unspec:HI [(subreg:HI (match_dup 3) 2) (const_int 0)] 5))] +"") + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "general_operand_msp430" "")) + (set (match_operand:SI 2 "nonimmediate_operand_msp430" "") + (zero_extend:SI (match_dup 0)))] +"dead_or_set_in_peep(1,insn, operands[0])" + [(set (subreg:HI (match_dup 2) 0) (match_dup 1)) + (set (subreg:HI (match_dup 2) 2) (const_int 0))] +"") + +;; +;; these are for redudant moves. +;; + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "nonimmediate_operand_msp430" "")) + (set (match_operand:SI 2 "register_operand" "") + (ior:SI (match_dup 2) (match_dup 0))) + (set (match_dup 1) (match_dup 2))] +"dead_or_set_in_peep(1,insn, operands[0])" + [(set (match_dup 1) (ior:SI (match_dup 1) (match_dup 2)))] +"") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (ior:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set (match_dup 1) (match_dup 0))] +"dead_or_set_in_peep(1,insn, operands[0])" + [(set (match_dup 1) (ior:SI (match_dup 1) (match_dup 0)))] +"") + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "register_operand" "")) + (set (match_dup 0) + (not:HI (match_dup 0))) + (set (match_operand:HI 2 "register_operand" "") + (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0]) && dead_or_set_in_peep(0,insn, operands[1])" + [(set (match_dup 1) (not:HI (match_dup 1))) + (set (match_dup 2) (match_dup 1))] +"") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "register_operand" "")) + (set (match_dup 0) + (not:SI (match_dup 0))) + (set (match_operand:SI 2 "register_operand" "") + (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0]) && dead_or_set_in_peep(0,insn, operands[1])" + [(set (match_dup 1) (not:SI (match_dup 1))) + (set (match_dup 2) (match_dup 1))] +"") + +(define_peephole2 + [(set (match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "general_operand_msp430" "")) + (set (match_operand:SF 2 "nonimmediate_operand_msp430" "") + (match_dup 0))] +"dead_or_set_in_peep(1,insn, operands[0])" + [(set (match_dup 2) (match_dup 1))] +"") + + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "general_operand_msp430" "")) + (set (match_operand:SI 2 "nonimmediate_operand_msp430" "") + (match_dup 0))] +"dead_or_set_in_peep(1,insn, operands[0])" + [(set (match_dup 2) (match_dup 1))] +"") + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "general_operand_msp430" "")) + (set (match_operand:HI 2 "nonimmediate_operand_msp430" "") + (match_dup 0))] +"dead_or_set_in_peep(1,insn, operands[0])" + [(set (match_dup 2) (match_dup 1))] +"") + + + +;; ========================================================================= +;; This one for bit tests like: +;; volatile long a; +;; while(a&CONST_HALFNIBBLE) ; + +(define_insn "*bittest_lo" + [(set (cc0) + (unspec:SI [(match_operand:SI 0 "nonimmediate_operand_msp430" "r,r,m,m") + (match_operand:SI 1 "general_operand_msp430" "rPR,mi,rPR,mi")] 1))] +"" +"bit %A1,%A0" +[(set_attr "length" "1,2,2,3") + (set_attr "cc" "compare,compare,compare,compare")]) + +(define_insn "*bittest_hi" + [(set (cc0) + (unspec:SI [(match_operand:SI 0 "nonimmediate_operand_msp430" "r,r,m,m") + (match_operand:SI 1 "general_operand_msp430" "rPR,mi,rPR,mi")] 2))] +"" +"bit %B1,%B0" +[(set_attr "length" "1,2,2,3") + (set_attr "cc" "compare,compare,compare,compare")]) + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "nonimmediate_operand_msp430" "")) + (set (match_dup 0) (and:SI (match_dup 0) + (match_operand 2 "const_int_operand" ""))) + (set (pc) + (if_then_else (match_operator:SI 3 "equality_operator" + [(match_dup 0) (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc)))] +"(halfnibble_integer(operands[2], VOIDmode) + || halfnibble_constant(operands[2], VOIDmode)) + && dead_or_set_in_peep(2,insn, operands[0]) + && which_nibble(INTVAL(operands[2])) == 0" + [(set (cc0) + (unspec:SI [(match_dup 1) (match_dup 2)] 1)) + (set (pc) (if_then_else (match_op_dup 3 + [(cc0) (const_int 0)]) + (label_ref (match_dup 4)) + (pc)))] +"") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "nonimmediate_operand_msp430" "")) + (set (match_dup 0) (and:SI (match_dup 0) + (match_operand 2 "const_int_operand" ""))) + (set (pc) (if_then_else (match_operator:SI 3 "equality_operator" + [(match_dup 0) (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc)))] +"(halfnibble_integer(operands[2], VOIDmode) + || halfnibble_constant(operands[2], VOIDmode)) + && dead_or_set_in_peep(2,insn, operands[0]) + && which_nibble(INTVAL(operands[2])) == 1" + [(set (cc0) + (unspec:SI [(match_dup 1) (match_dup 2)] 2)) + (set (pc) (if_then_else (match_op_dup 3 + [(cc0) (const_int 0)]) + (label_ref (match_dup 4)) + (pc)))] +"") + + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "nonimmediate_operand_msp430" "")) + (set (match_dup 0) (and:SI (match_dup 0) + (match_operand 2 "const_int_operand" ""))) + (set (pc) + (if_then_else (match_operator:HI 3 "equality_operator" + [(match_operand:HI 4 "register_operand" "") (const_int 0)]) + (label_ref (match_operand 5 "" "")) + (pc)))] +"(halfnibble_integer(operands[2], VOIDmode) + || halfnibble_constant(operands[2], VOIDmode)) + && dead_or_set_in_peep(2,insn, operands[0]) + && which_nibble(INTVAL(operands[2])) == 1 + && REGNO(operands[4]) == REGNO(operands[0])+1" + [(set (cc0) + (unspec:SI [(match_dup 1) (match_dup 2)] 1)) + (set (pc) (if_then_else (match_op_dup 3 + [(cc0) (const_int 0)]) + (label_ref (match_dup 5)) + (pc)))] +"") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "nonimmediate_operand_msp430" "")) + (set (match_dup 0) (and:SI (match_dup 0) + (match_operand 2 "const_int_operand" ""))) + (set (pc) + (if_then_else (match_operator:HI 3 "equality_operator" + [(match_operand:HI 4 "register_operand" "") (const_int 0)]) + (label_ref (match_operand 5 "" "")) + (pc)))] +"(halfnibble_integer(operands[2], VOIDmode) + || halfnibble_constant(operands[2], VOIDmode)) + && dead_or_set_in_peep(2,insn, operands[0]) + && which_nibble(INTVAL(operands[2])) == 0 + && REGNO(operands[4]) == REGNO(operands[0])" + [(set (cc0) + (unspec:SI [(match_dup 1) (match_dup 2)] 1)) + (set (pc) (if_then_else (match_op_dup 3 + [(cc0) (const_int 0)]) + (label_ref (match_dup 5)) + (pc)))] +"") + +;; +;; The same for HI mode: while(smts&0xXXXX) ; +;; +(define_insn "*bittest" + [(set (cc0) + (unspec:HI [(match_operand:HI 0 "general_operand_msp430" "r,r,m,m") + (match_operand:HI 1 "general_operand_msp430" "rPR,mi,rPR,mi")] 6))] +"" +"bit %1,%0" +[(set_attr "length" "1,2,2,3") + (set_attr "cc" "compare,compare,compare,compare")]) + + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "nonimmediate_operand_msp430" "")) + (set (match_dup 0) (and:HI (match_dup 0) + (match_operand 2 "const_int_operand" ""))) + (set (pc) (if_then_else (match_operator:HI 3 "equality_operator" + [(match_dup 0) (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc)))] +"dead_or_set_in_peep(2,insn, operands[0]) " + [(set (cc0) + (unspec:HI [(match_dup 1) (match_dup 2)] 6)) + (set (pc) (if_then_else (match_op_dup 3 + [(cc0) (const_int 0)]) + (label_ref (match_dup 4)) + (pc)))] +"") + + +;; The same for QI mode + +(define_insn "*bittest_b" + [(set (cc0) + (unspec:QI [(match_operand:QI 0 "general_operand_msp430" "r,r,m,m") + (match_operand:QI 1 "general_operand_msp430" "rPR,mi,rPR,mi")] 7))] +"" +"bit.b %1,%0" +[(set_attr "length" "1,2,2,3") + (set_attr "cc" "compare,compare,compare,compare")]) + + +(define_peephole2 + [(set (match_operand:QI 0 "register_operand" "") + (match_operand:QI 1 "nonimmediate_operand_msp430" "")) + (set (match_dup 0) (and:QI (match_dup 0) + (match_operand 2 "const_int_operand" ""))) + (set (pc) (if_then_else (match_operator:QI 3 "equality_operator" + [(match_dup 0) (const_int 0)]) + (label_ref (match_operand 4 "" "")) + (pc)))] +"dead_or_set_in_peep(2,insn, operands[0]) " + [(set (cc0) + (unspec:QI [(match_dup 1) (match_dup 2)] 7)) + (set (pc) (if_then_else (match_op_dup 3 + [(cc0) (const_int 0)]) + (label_ref (match_dup 4)) + (pc)))] +"") + + + +;;=========================================================================== + +(define_peephole2 + [(set (match_operand:QI 0 "register_operand" "") + (match_operand:QI 1 "general_operand_msp430" "")) + (set (match_dup 0) + (minus:QI (match_dup 0) + (match_operand:QI 2 "general_operand_msp430" ""))) + (set (match_operand:QI 3 "register_operand" "") + (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0]) && 0" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 3) (minus:QI (match_dup 3) (match_dup 2)))] +"") + + +(define_peephole2 + [(set (match_operand:QI 0 "register_operand" "") + (match_operand:QI 1 "general_operand_msp430" "")) + (set (match_dup 0) + (plus:QI (match_dup 0) + (match_operand:QI 2 "general_operand_msp430" ""))) + (set (match_operand:QI 3 "register_operand" "") + (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0]) && 0" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 3) (plus:QI (match_dup 3) (match_dup 2)))] +"") + + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "general_operand_msp430" "")) + (set (match_dup 0) + (minus:HI (match_dup 0) + (match_operand:HI 2 "general_operand_msp430" ""))) + (set (match_operand:HI 3 "register_operand" "") + (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0]) && 0" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 3) (minus:HI (match_dup 3) (match_dup 2)))] +"") + + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "general_operand_msp430" "")) + (set (match_dup 0) + (plus:HI (match_dup 0) + (match_operand:HI 2 "general_operand_msp430" ""))) + (set (match_operand:HI 3 "register_operand" "") + (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0]) && 0" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 3) (plus:HI (match_dup 3) (match_dup 2)))] +"") + + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "general_operand_msp430" "")) + (set (match_dup 0) + (minus:SI (match_dup 0) + (match_operand:SI 2 "general_operand_msp430" ""))) + (set (match_operand:SI 3 "register_operand" "") + (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0]) && 0" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 3) (minus:SI (match_dup 3) (match_dup 2)))] +"") + + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "general_operand_msp430" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "general_operand_msp430" ""))) + (set (match_operand:SI 3 "register_operand" "") + (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0]) && 0" + [(set (match_dup 3) (match_dup 1)) + (set (match_dup 3) (plus:SI (match_dup 3) (match_dup 2)))] +"") + + +;; ============================================================= +;; +;; adjust frame pointer index +;; +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (sign_extend:HI (match_operand:QI 1 "general_operand_msp430" ""))) + (set (match_dup 0) + (plus:HI (match_dup 0) (match_operand:HI 2 "general_operand_msp430" ""))) + (set (match_operand:HI 3 "register_operand" "") + (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0])" + [(set (match_dup 3) (sign_extend:HI (match_dup 1))) + (set (match_dup 3) (plus:HI (match_dup 3) (match_dup 2)))] +"") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "general_operand_msp430" ""))) + (set (match_dup 0) + (plus:SI (match_dup 0) (match_operand:SI 2 "general_operand_msp430" ""))) + (set (match_operand:SI 3 "register_operand" "") + (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0])" + [(set (match_dup 3) (sign_extend:SI (match_dup 1))) + (set (match_dup 3) (plus:SI (match_dup 3) (match_dup 2)))] +"") + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (sign_extend:HI (match_operand:QI 1 "general_operand_msp430" ""))) + (set (match_dup 0) + (minus:HI (match_dup 0) (match_operand:HI 2 "general_operand_msp430" ""))) + (set (match_operand:HI 3 "register_operand" "") + (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0])" + [(set (match_dup 3) (sign_extend:HI (match_dup 1))) + (set (match_dup 3) (minus:HI (match_dup 3) (match_dup 2)))] +"") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "general_operand_msp430" ""))) + (set (match_dup 0) + (minus:SI (match_dup 0) (match_operand:SI 2 "general_operand_msp430" ""))) + (set (match_operand:SI 3 "register_operand" "") + (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0])" + [(set (match_dup 3) (sign_extend:SI (match_dup 1))) + (set (match_dup 3) (minus:SI (match_dup 3) (match_dup 2)))] +"") + +;; ============================================================= +;; mov & 'and' + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (match_operand:HI 1 "nonimmediate_operand_msp430" "")) + (set (match_dup 0) + (and:HI (match_dup 0) + (match_operand:HI 2 "general_operand_msp430" ""))) + (set (match_dup 1) (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0])" + [(set (match_dup 1) + (and:HI (match_dup 1) (match_dup 2)))] +"") + + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "nonimmediate_operand_msp430" "")) + (set (match_dup 0) + (and:SI (match_dup 0) + (match_operand:SI 2 "general_operand_msp430" ""))) + (set (match_dup 1) (match_dup 0))] +"dead_or_set_in_peep(2,insn, operands[0])" + [(set (match_dup 1) + (and:SI (match_dup 1) (match_dup 2)))] +"") + + + +;; ============================================================= +;; SWAP BYTES (should be a pattern for: +;; r = (a<<8)|(a>>8); + +(define_insn "swpb" + [(set (match_operand:HI 0 "nonimmediate_operand_msp430" "=rR,m") + (unspec:HI [(match_operand:HI 1 "nonimmediate_operand_msp430" "0,0")] 4))] +"" +"swpb %0" +[(set_attr "length" "1,2") + (set_attr "cc" "clobber,clobber")]) + +;; +;; after mult and stuff +;; +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (reg:SI 14)) + (set (match_operand:SI 1 "nonimmediate_operand_msp430" "") + (match_dup 0))] +"dead_or_set_in_peep(1,insn,operands[0])" + [(set (match_dup 1) (reg:SI 14))] +"") + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (reg:HI 14)) + (set (match_operand:HI 1 "nonimmediate_operand_msp430" "") + (match_dup 0))] +"dead_or_set_in_peep(1,insn,operands[0])" + [(set (match_dup 1) (reg:HI 14))] +"") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (reg:SI 12)) + (set (match_operand:SI 1 "nonimmediate_operand_msp430" "") + (match_dup 0))] +"dead_or_set_in_peep(1,insn,operands[0])" + [(set (match_dup 1) (reg:SI 12))] +"") + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (reg:HI 12)) + (set (match_operand:HI 1 "nonimmediate_operand_msp430" "") + (match_dup 0))] +"dead_or_set_in_peep(1,insn,operands[0])" + [(set (match_dup 1) (reg:HI 12))] +"") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:QI 1 "general_operand_msp430" ""))) + (set (match_operand:SI 2 "nonimmediate_operand_msp430" "") + (match_dup 0))] +"dead_or_set_in_peep(1,insn,operands[0])" + [(set (match_dup 2) (sign_extend:SI (match_dup 1)))] +"") + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "general_operand_msp430" ""))) + (set (match_operand:SI 2 "nonimmediate_operand_msp430" "") + (match_dup 0))] +"dead_or_set_in_peep(1,insn,operands[0])" + [(set (match_dup 2) (sign_extend:SI (match_dup 1)))] +"") + + +;; ============================================================= + +(define_peephole + [(set (match_operand:HI 0 "register_operand" "") + (sign_extend:HI (match_operand:QI 1 "register_operand" ""))) + (set (match_operand:HI 2 "register_operand" "") + (plus:HI (match_dup 2) (match_dup 0)))] +"dead_or_set_in_peep(1,insn,operands[0])" +"sxt %1 + add %1, %2" +[(set_attr "length" "3") + (set_attr "cc" "clobber")]) + + +(define_peephole + [(set (match_operand:HI 0 "register_operand" "") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand_msp430" ""))) + (set (match_operand:HI 2 "register_operand" "") (match_dup 0))] +"dead_or_set_in_peep(1,insn,operands[0])" +"mov.b %1, %2 + sxt %2" +[(set_attr "length" "2") + (set_attr "cc" "clobber")]) + +;; ============================================================= +;; a = (uint16_t)( (uint8_t)SFR ) << 8; +;; (inderect_jump + 50) +(define_peephole + [(set (match_operand:QI 0 "register_operand" "") + (match_operand:QI 1 "memory_operand_msp430" "m")) + (set (match_operand:HI 2 "register_operand" "") + (ashift:HI (match_dup 2) (const_int 8)))] + "REGNO(operands[0]) == REGNO(operands[2])" +"mov.b %1, %0 + swpb %2" +[(set_attr "length" "3") + (set_attr "cc" "clobber")]) + +(define_peephole2 + [(set (match_operand:HI 0 "register_operand" "") + (ior:HI (match_dup 0) + (match_operand:HI 1 "register_operand" ""))) + (set (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "register_operand" ""))] +"(REGNO(operands[0]) == REGNO(operands[2]) + && REGNO(operands[3])+1 == REGNO(operands[0]))" + [(set (match_dup 1) + (ior:HI (match_dup 1) + (match_dup 0))) + (set (subreg:HI (match_dup 2) 0) + (subreg:HI (match_dup 3) 0))] +"") + + + +;; ============================================================= +;; combine ior and mov. +;; +(define_peephole2 +[(set (match_operand:QI 0 "register_operand" "") + (ior:QI (match_dup 0) + (match_operand:QI 1 "nonimmediate_operand_msp430" ""))) + (set (match_dup 1) (match_dup 0))] +"dead_or_set_in_peep(1,insn,operands[0])" +[(set (match_dup 1) (ior:QI (match_dup 1) (match_dup 0)))] +"") + +(define_peephole2 +[(set (match_operand:HI 0 "register_operand" "") + (ior:HI (match_dup 0) + (match_operand:HI 1 "nonimmediate_operand_msp430" ""))) + (set (match_dup 1) (match_dup 0))] +"dead_or_set_in_peep(1,insn,operands[0])" +[(set (match_dup 1) (ior:HI (match_dup 1) (match_dup 0)))] +"") + +(define_peephole2 +[(set (match_operand:SI 0 "register_operand" "") + (ior:SI (match_dup 0) + (match_operand:SI 1 "nonimmediate_operand_msp430" ""))) + (set (match_dup 1) (match_dup 0))] +"dead_or_set_in_peep(1,insn,operands[0])" +[(set (match_dup 1) (ior:SI (match_dup 1) (match_dup 0)))] +"") + +(define_peephole2 +[(set (match_operand:DI 0 "register_operand" "") + (ior:DI (match_dup 0) + (match_operand:DI 1 "nonimmediate_operand_msp430" ""))) + (set (match_dup 1) (match_dup 0))] +"dead_or_set_in_peep(1,insn,operands[0])" +[(set (match_dup 1) (ior:DI (match_dup 1) (match_dup 0)))] +"") + + + diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/msp430-protos.h gcc-3.2.3/gcc/config/msp430/msp430-protos.h --- gcc-3.2.3.orig/gcc/config/msp430/msp430-protos.h 1969-12-31 17:00:00.000000000 -0700 +++ gcc-3.2.3/gcc/config/msp430/msp430-protos.h 2008-08-22 09:17:00.000000000 -0600 @@ -0,0 +1,301 @@ +/* Prototypes for exported functions defined in msp430.c + + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Contributed by Dmitry Diky + + This file is part of GNU CC. + + GNU CC is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU CC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU CC; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + + +extern void bootloader_section PARAMS ((void)); +extern void infomem_section PARAMS ((void)); + +extern void asm_file_start PARAMS ((FILE *file)); +extern void asm_file_end PARAMS ((FILE *file)); +extern void msp430_init_once PARAMS ((void)); +extern void msp430_override_options PARAMS ((void)); +extern void function_prologue PARAMS ((FILE *file, int size)); +extern void function_epilogue PARAMS ((FILE *file, int size)); +extern void gas_output_limited_string PARAMS ((FILE *file, const char *str)); +extern void gas_output_ascii PARAMS ((FILE *file, const char *str, + size_t length)); +extern void order_regs_for_local_alloc PARAMS ((void)); +extern void msp430_trampoline_template PARAMS ((FILE *fd)); + + +extern int frame_pointer_required_p PARAMS ((void)); +extern int msp430_empty_epilogue PARAMS ((void)); + +int msp430_regno_ok_for_base_p PARAMS ((int)); + + +#ifdef HAVE_MACHINE_MODES +extern int msp430_hard_regno_mode_ok PARAMS ((int regno, + enum machine_mode mode)); +#endif + +extern int initial_elimination_offset PARAMS ((int, int)); + + + +#ifdef TREE_CODE +extern void asm_output_external PARAMS ((FILE *file, tree decl, + char *name)); +extern void unique_section PARAMS ((tree decl, int reloc)); +extern void encode_section_info PARAMS ((tree decl)); +extern void asm_output_section_name PARAMS ((FILE *file, tree decl, + const char *name, + int reloc)); +extern int valid_machine_type_attribute PARAMS ((tree type, tree attributes, + tree identifier, + tree args)); +extern int valid_machine_decl_attribute PARAMS ((tree decl, tree attributes, + tree attr, tree args)); +extern void asm_declare_function_name PARAMS ((FILE *, char *, tree)); +unsigned int msp430_section_type_flags PARAMS (( tree DECL, const char *NAME, int RELOC)); + + +#ifdef RTX_CODE /* inside TREE_CODE */ +extern rtx msp430_function_value PARAMS ((tree type, tree func)); +extern void init_cumulative_args PARAMS ((CUMULATIVE_ARGS *cum, + tree fntype, rtx libname, + int indirect)); +extern rtx function_arg PARAMS ((CUMULATIVE_ARGS *cum, + enum machine_mode mode, + tree type, int named)); +extern void init_cumulative_incoming_args PARAMS ((CUMULATIVE_ARGS *cum, + tree fntype, rtx libname)); +extern rtx function_incoming_arg PARAMS ((CUMULATIVE_ARGS *cum, + enum machine_mode mode, + tree type, int named)); + + + +#endif /* RTX_CODE inside TREE_CODE */ + +#ifdef HAVE_MACHINE_MODES /* inside TREE_CODE */ +extern void function_arg_advance PARAMS ((CUMULATIVE_ARGS *cum, + enum machine_mode mode, tree type, + int named)); +#endif /* HAVE_MACHINE_MODES inside TREE_CODE*/ +#endif /* TREE_CODE */ + +#ifdef RTX_CODE + + +extern enum rtx_code msp430_canonicalize_comparison PARAMS ((enum rtx_code,rtx *,rtx *)); + + +extern void msp430_emit_cbranch PARAMS ((enum rtx_code, rtx)); +extern void msp430_emit_cset PARAMS ((enum rtx_code, rtx)); + +extern int dead_or_set_in_peep PARAMS ((int, rtx, rtx)); +extern void msp430_initialize_trampoline PARAMS ((rtx,rtx,rtx)); + + +extern enum reg_class msp430_reg_class_from_letter PARAMS ((int)); +extern enum reg_class preferred_reload_class PARAMS ((rtx,enum reg_class)); +enum reg_class msp430_regno_reg_class PARAMS ((int)); + +extern RTX_CODE followed_compare_condition PARAMS ((rtx)); + +extern const char * msp430_movesi_code PARAMS ((rtx insn, rtx operands[], int *l)); +extern const char * msp430_movedi_code PARAMS ((rtx insn, rtx operands[], int *l)); +extern const char * msp430_addsi_code PARAMS ((rtx insn, rtx operands[], int *l)); +extern const char * msp430_subsi_code PARAMS ((rtx insn, rtx operands[], int *l)); +extern const char * msp430_andsi_code PARAMS ((rtx insn, rtx operands[], int *l)); +extern const char * msp430_iorsi_code PARAMS ((rtx insn, rtx operands[], int *l)); +extern const char * msp430_xorsi_code PARAMS ((rtx insn, rtx operands[], int *l)); +extern const char * msp430_adddi_code PARAMS ((rtx insn, rtx operands[], int *l)); +extern const char * msp430_subdi_code PARAMS ((rtx insn, rtx operands[], int *l)); +extern const char * msp430_anddi_code PARAMS ((rtx insn, rtx operands[], int *l)); +extern const char * msp430_iordi_code PARAMS ((rtx insn, rtx operands[], int *l)); +extern const char * msp430_xordi_code PARAMS ((rtx insn, rtx operands[], int *l)); + + +extern int zero_shifted PARAMS ((rtx )); +extern int indexed_location PARAMS ((rtx )); + + +extern int regsi_ok_safe PARAMS ((rtx operands[])); +extern int regsi_ok_clobber PARAMS ((rtx operands[])); +extern int regdi_ok_safe PARAMS ((rtx operands[])); +extern int regdi_ok_clobber PARAMS ((rtx operands[])); +extern int sameoperand PARAMS ((rtx operands[], int)); + +extern int general_operand_msp430 PARAMS ((rtx, enum machine_mode )); +extern int nonimmediate_operand_msp430 PARAMS ((rtx, enum machine_mode )); +extern int memory_operand_msp430 PARAMS ((rtx, enum machine_mode )); +extern int halfnibble_constant PARAMS ((rtx, enum machine_mode )); +extern int halfnibble_integer PARAMS ((rtx, enum machine_mode )); +extern int halfnibble_constant_shift PARAMS ((rtx, enum machine_mode )); +extern int halfnibble_integer_shift PARAMS ((rtx, enum machine_mode )); +extern int which_nibble PARAMS ((int)); +extern int which_nibble_shift PARAMS ((int)); + + +extern void asm_output_external_libcall PARAMS ((FILE *file, rtx symref)); +extern int legitimate_address_p PARAMS ((enum machine_mode mode, rtx x, + int strict)); +extern int compare_diff_p PARAMS ((rtx insn)); + +extern int emit_indexed_arith PARAMS ((rtx insn, rtx operands[], int, const char *, int)); + +extern const char * msp430_emit_abssi PARAMS ((rtx insn, rtx operands[], int *l)); +extern const char * msp430_emit_absdi PARAMS ((rtx insn, rtx operands[], int *l)); + +extern const char * msp430_emit_indexed_add2 PARAMS ((rtx insn, rtx op[], int *l)); +extern const char * msp430_emit_indexed_add4 PARAMS ((rtx insn, rtx op[], int *l)); + +extern const char * msp430_emit_indexed_sub2 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_indexed_sub4 PARAMS ((rtx insn, rtx operands[], int *len)); + +extern const char * msp430_emit_indexed_and2 PARAMS ((rtx insn, rtx op[], int *l)); +extern const char * msp430_emit_indexed_and4 PARAMS ((rtx insn, rtx op[], int *l)); +extern const char * msp430_emit_immediate_and2 PARAMS ((rtx insn, rtx op[], int *l)); +extern const char * msp430_emit_immediate_and4 PARAMS ((rtx insn, rtx op[], int *l)); + +extern const char * msp430_emit_indexed_ior2 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_indexed_ior4 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_immediate_ior2 PARAMS ((rtx insn, rtx op[], int *l)); +extern const char * msp430_emit_immediate_ior4 PARAMS ((rtx insn, rtx op[], int *l)); + + +extern int msp430_emit_indexed_mov PARAMS ((rtx insn, rtx operands[], int len, const char *)); +extern const char * movstrsi_insn PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * clrstrsi_insn PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * movstrhi_insn PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * clrstrhi_insn PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_indexed_mov2 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_indexed_mov4 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * movsisf_regmode PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * movdidf_regmode PARAMS ((rtx insn, rtx operands[], int *len)); + + +extern int is_shift_better_in_reg PARAMS ((rtx operands[])); +extern int msp430_emit_shift_cnt PARAMS ((int (*funct)(rtx, int, int), const char *, rtx insn, rtx operands[], int *len, int)); +extern const char * msp430_emit_ashlqi3 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_ashlhi3 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_ashlsi3 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_ashldi3 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_ashrqi3 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_ashrhi3 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_ashrsi3 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_ashrdi3 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_lshrqi3 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_lshrhi3 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_lshrsi3 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_lshrdi3 PARAMS ((rtx insn, rtx operands[], int *len)); + +extern const char * signextendqihi PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * signextendqisi PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * signextendqidi PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * signextendhisi PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * signextendhidi PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * signextendsidi PARAMS ((rtx insn, rtx operands[], int *len)); + +extern const char * msp430_emit_indexed_sub2 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_indexed_sub4 PARAMS ((rtx insn, rtx operands[], int *len)); + +extern const char * msp430_emit_indexed_xor2 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_indexed_xor4 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_indexed_xor2_3 PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_emit_indexed_xor4_3 PARAMS ((rtx insn, rtx operands[], int *len)); + +extern const char * zeroextendqihi PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * zeroextendqisi PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * zeroextendqidi PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * zeroextendhisi PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * zeroextendhidi PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * zeroextendsidi PARAMS ((rtx insn, rtx operands[], int *len)); + +extern const char * msp430_emit_blt0si PARAMS ((rtx operands[], int len)); +extern const char * msp430_emit_beq PARAMS ((rtx operands[], int len)); +extern const char * msp430_emit_bne PARAMS ((rtx operands[], int len)); +extern const char * msp430_emit_bgt PARAMS ((rtx operands[], int len)); +extern const char * msp430_emit_bgtu PARAMS ((rtx operands[], int len)); +extern const char * msp430_emit_blt PARAMS ((rtx operands[], int len)); +extern const char * msp430_emit_bltu PARAMS ((rtx operands[], int len)); +extern const char * msp430_emit_bge PARAMS ((rtx operands[], int len)); +extern const char * msp430_emit_bgeu PARAMS ((rtx operands[], int len)); +extern const char * msp430_emit_ble PARAMS ((rtx operands[], int len)); +extern const char * msp430_emit_bleu PARAMS ((rtx operands[], int len)); + +extern const char * msp430_pushsisf PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_pushdi PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_pushhi PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char * msp430_pushqi PARAMS ((rtx insn, rtx operands[], int *len)); + +extern const char * msp430_emit_return PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char *msp430_cbranch PARAMS ((rtx insn, rtx operands[], int *len)); +extern const char *msp430_cset PARAMS ((rtx insn, rtx operands[], int *len)); + +extern void notice_update_cc PARAMS ((rtx body, rtx insn)); +extern int msp430_peep2_scratch_safe PARAMS ((rtx reg_rtx)); +extern int test_hard_reg_class PARAMS ((enum reg_class class, rtx x)); +extern void machine_dependent_reorg PARAMS ((rtx first_insn)); +extern void msp430_output_addr_vec_elt PARAMS ((FILE *stream, int value)); +extern void final_prescan_insn PARAMS ((rtx insn, rtx *operand, + int num_operands)); +extern int adjust_insn_length PARAMS ((rtx insn, int len)); + + +extern int msp430_address_cost PARAMS ((rtx x)); +extern int extra_constraint PARAMS ((rtx x, int c)); +extern rtx legitimize_address PARAMS ((rtx x, rtx oldx, + enum machine_mode mode)); +extern rtx msp430_libcall_value PARAMS ((enum machine_mode mode)); +extern int default_rtx_costs PARAMS ((rtx X, RTX_CODE code, + RTX_CODE outer_code)); +extern void asm_output_char PARAMS ((FILE *file, rtx value)); +extern void asm_output_short PARAMS ((FILE *file, rtx value)); +extern void asm_output_byte PARAMS ((FILE *file, int value)); + +extern void print_operand PARAMS ((FILE *file, rtx x, int code)); +extern void print_operand_address PARAMS ((FILE *file, rtx addr)); +extern int reg_unused_after PARAMS ((rtx insn, rtx reg)); +extern int msp430_jump_dist PARAMS ((rtx x, rtx insn)); +extern int call_insn_operand PARAMS ((rtx op, enum machine_mode mode)); +extern int msp430_branch_mode PARAMS ((rtx x, rtx insn)); + +extern int msp430_easy_mul PARAMS ((rtx [],int)); +extern int msp430_mul3_guard PARAMS ((rtx [], int )); +extern int msp430_umul3_guard PARAMS ((rtx [], int )); +extern int msp430_mulhisi_guard PARAMS ((rtx [] )); +extern int msp430_umulhisi_guard PARAMS ((rtx [] )); +extern int msp430_ashlhi3 PARAMS ((rtx [] )); +extern int msp430_ashlsi3 PARAMS ((rtx [] )); +extern int msp430_ashrhi3 PARAMS ((rtx [] )); +extern int msp430_ashrsi3 PARAMS ((rtx [] )); +extern int msp430_lshrhi3 PARAMS ((rtx [] )); +extern int msp430_lshrsi3 PARAMS ((rtx [] )); + + +#endif /* RTX_CODE */ + +#ifdef HAVE_MACHINE_MODES +extern int class_max_nregs PARAMS ((enum reg_class class, + enum machine_mode mode)); +#endif /* HAVE_MACHINE_MODES */ + +#ifdef REAL_VALUE_TYPE + +extern void asm_output_float PARAMS ((FILE *file, REAL_VALUE_TYPE n)); + +#endif + + diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/t-msp430 gcc-3.2.3/gcc/config/msp430/t-msp430 --- gcc-3.2.3.orig/gcc/config/msp430/t-msp430 1969-12-31 17:00:00.000000000 -0700 +++ gcc-3.2.3/gcc/config/msp430/t-msp430 2008-08-22 09:17:00.000000000 -0600 @@ -0,0 +1,116 @@ +# Specific names for MSP430 tools +AR_FOR_TARGET = msp430-ar +RANLIB_FOR_TARGET = msp430-ranlib +NM_FOR_TARGET = msp430-nm + +CROSS_LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = msp430/libgcc.S +LIB1ASMFUNCS = _cmpdi2 \ + _cmpsf2 \ + __stop_progExec__ \ + _mulqi3 \ + _mulhi3 \ + _mulsi3 \ + _mulsi3hw \ + _umulqihi3 \ + _umulhisi3 \ + _mulqihi3 \ + _mulhisi3 \ + _udivmodqi4 \ + _divmodqi4 \ + _udivmodhi4 \ + _divmodhi4 \ + _udivmodsi4 \ + _divmodsi4 \ + _reset_vector__ \ + __prologue_saver \ + __epilogue_restorer \ + __epilogue_restorer_intr \ + _udivmoddi3_parts \ + _udivdi3 \ + _umoddi3 \ + _divdi3 \ + _moddi3 \ + _muldi3 \ + __low_level_init \ + __init_stack \ + _copy_data \ + _clear_bss \ + _ctors \ + __jump_to_main \ + _dtors + + + +# libgcc... +LIBGCC1_TEST = + +# We do not have the DF type. +# Most of the C functions in libgcc2 use almost all registers, +TARGET_LIBGCC2_CFLAGS = -DDF=SF -Dinhibit_libc -g + +fp-bit.c: $(srcdir)/config/fp-bit.c $(srcdir)/config/msp430/t-msp430 + echo '#define FLOAT' > fp-bit.c + echo '#define FLOAT_ONLY' >> fp-bit.c + echo '#define CMPtype HItype' >> fp-bit.c + echo '#define DF SF' >> fp-bit.c + echo '#define DI SI' >> fp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c + echo '#define SMALL_MACHINE' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +FPBIT = fp-bit.c + +MULTILIB_OPTIONS = mmcu=msp1/mmcu=msp2 +MULTILIB_DIRNAMES = msp1 msp2 + + +MULTILIB_MATCHES = \ + mmcu?msp1=mmcu?msp430x110 mmcu?msp1=mmcu?msp430x112 \ + mmcu?msp1=mmcu?msp430x1101 mmcu?msp1=mmcu?msp430x1111 mmcu?msp1=mmcu?msp430x1121 \ + mmcu?msp1=mmcu?msp430x1122 mmcu?msp1=mmcu?msp430x1132 \ + mmcu?msp1=mmcu?msp430x122 mmcu?msp1=mmcu?msp430x123 \ + mmcu?msp1=mmcu?msp430x1222 mmcu?msp1=mmcu?msp430x1232 \ + mmcu?msp1=mmcu?msp430x133 mmcu?msp1=mmcu?msp430x135 \ + mmcu?msp1=mmcu?msp430x1331 mmcu?msp1=mmcu?msp430x1351 \ + mmcu?msp2=mmcu?msp430x147 mmcu?msp2=mmcu?msp430x148 mmcu?msp2=mmcu?msp430x149 \ + mmcu?msp2=mmcu?msp430x1471 mmcu?msp2=mmcu?msp430x1481 mmcu?msp2=mmcu?msp430x1491 \ + mmcu?msp1=mmcu?msp430x155 mmcu?msp1=mmcu?msp430x156 mmcu?msp1=mmcu?msp430x157 \ + mmcu?msp2=mmcu?msp430x167 mmcu?msp2=mmcu?msp430x168 mmcu?msp2=mmcu?msp430x169 \ + mmcu?msp2=mmcu?msp430x1610 mmcu?msp2=mmcu?msp430x1611 mmcu?msp2=mmcu?msp430x1612 \ + mmcu?msp1=mmcu?msp430x2001 mmcu?msp1=mmcu?msp430x2011 \ + mmcu?msp1=mmcu?msp430x2002 mmcu?msp1=mmcu?msp430x2012 \ + mmcu?msp1=mmcu?msp430x2003 mmcu?msp1=mmcu?msp430x2013 \ + mmcu?msp1=mmcu?msp430x2101 mmcu?msp1=mmcu?msp430x2111 mmcu?msp1=mmcu?msp430x2121 \ + mmcu?msp1=mmcu?msp430x2131 \ + mmcu?msp1=mmcu?msp430x2232 mmcu?msp1=mmcu?msp430x2252 mmcu?msp1=mmcu?msp430x2272 \ + mmcu?msp1=mmcu?msp430x2234 mmcu?msp1=mmcu?msp430x2254 mmcu?msp1=mmcu?msp430x2274 \ + mmcu?msp2=mmcu?msp430x247 mmcu?msp2=mmcu?msp430x248 mmcu?msp2=mmcu?msp430x249 \ + mmcu?msp2=mmcu?msp430x2410 \ + mmcu?msp2=mmcu?msp430x2471 mmcu?msp2=mmcu?msp430x2481 mmcu?msp2=mmcu?msp430x2491 \ + mmcu?msp2=mmcu?msp430x2416 mmcu?msp2=mmcu?msp430x2417 mmcu?msp2=mmcu?msp430x2418 \ + mmcu?msp2=mmcu?msp430x2419 \ + mmcu?msp2=mmcu?msp430x2616 mmcu?msp2=mmcu?msp430x2617 mmcu?msp2=mmcu?msp430x2618 \ + mmcu?msp2=mmcu?msp430x2619 \ + mmcu?msp1=mmcu?msp430x311 mmcu?msp1=mmcu?msp430x312 mmcu?msp1=mmcu?msp430x313 \ + mmcu?msp1=mmcu?msp430x314 mmcu?msp1=mmcu?msp430x315 \ + mmcu?msp1=mmcu?msp430x323 mmcu?msp1=mmcu?msp430x325 \ + mmcu?msp2=mmcu?msp430x336 mmcu?msp2=mmcu?msp430x337 \ + mmcu?msp1=mmcu?msp430x412 mmcu?msp1=mmcu?msp430x413 \ + mmcu?msp1=mmcu?msp430x415 mmcu?msp1=mmcu?msp430x417 \ + mmcu?msp2=mmcu?msp430x423 mmcu?msp2=mmcu?msp430x425 mmcu?msp2=mmcu?msp430x427 \ + mmcu?msp1=mmcu?msp430x4250 mmcu?msp1=mmcu?msp430x4260 mmcu?msp1=mmcu?msp430x4270 \ + mmcu?msp2=mmcu?msp430xE423 mmcu?msp2=mmcu?msp430xE425 mmcu?msp2=mmcu?msp430xE427 \ + mmcu?msp1=mmcu?msp430xW423 mmcu?msp1=mmcu?msp430xW425 mmcu?msp1=mmcu?msp430xW427 \ + mmcu?msp1=mmcu?msp430xG437 mmcu?msp1=mmcu?msp430xG438 mmcu?msp1=mmcu?msp430xG439 \ + mmcu?msp1=mmcu?msp430x435 mmcu?msp1=mmcu?msp430x436 mmcu?msp1=mmcu?msp430x437 \ + mmcu?msp2=mmcu?msp430x447 mmcu?msp2=mmcu?msp430x448 mmcu?msp2=mmcu?msp430x449 \ + mmcu?msp2=mmcu?msp430xG4616 mmcu?msp2=mmcu?msp430xG4617 mmcu?msp2=mmcu?msp430xG4618 \ + mmcu?msp2=mmcu?msp430xG4619 + +MULTILIB_EXCEPTIONS = + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + +##STMP_FIXINC = diff -urN -x CVS gcc-3.2.3.orig/gcc/config/msp430/xm-msp430.h gcc-3.2.3/gcc/config/msp430/xm-msp430.h --- gcc-3.2.3.orig/gcc/config/msp430/xm-msp430.h 1969-12-31 17:00:00.000000000 -0700 +++ gcc-3.2.3/gcc/config/msp430/xm-msp430.h 2008-08-22 09:17:00.000000000 -0600 @@ -0,0 +1 @@ +#include "tm.h" diff -urN -x CVS gcc-3.2.3.orig/gcc/config.gcc gcc-3.2.3/gcc/config.gcc --- gcc-3.2.3.orig/gcc/config.gcc 2003-02-28 11:38:19.000000000 -0700 +++ gcc-3.2.3/gcc/config.gcc 2008-08-22 09:17:00.000000000 -0600 @@ -2667,6 +2667,8 @@ ;; mmix-knuth-mmixware) ;; +msp430-*-*) + ;; mn10200-*-*) float_format=i32 tm_file="dbxelf.h elfos.h svr4.h ${tm_file}" diff -urN -x CVS gcc-3.2.3.orig/gcc/cp/decl.c gcc-3.2.3/gcc/cp/decl.c --- gcc-3.2.3.orig/gcc/cp/decl.c 2003-03-17 16:16:55.000000000 -0700 +++ gcc-3.2.3/gcc/cp/decl.c 2008-08-22 09:17:00.000000000 -0600 @@ -454,9 +454,9 @@ /* The binding level currently in effect. */ #define current_binding_level \ - (cfun && cp_function_chain->bindings \ - ? cp_function_chain->bindings \ - : scope_chain->bindings) + (*(cfun && cp_function_chain->bindings \ + ? &cp_function_chain->bindings \ + : &scope_chain->bindings)) /* The binding level of the current class, if any. */ diff -urN -x CVS gcc-3.2.3.orig/gcc-3.2.3-cygwin.patch gcc-3.2.3/gcc-3.2.3-cygwin.patch --- gcc-3.2.3.orig/gcc-3.2.3-cygwin.patch 1969-12-31 17:00:00.000000000 -0700 +++ gcc-3.2.3/gcc-3.2.3-cygwin.patch 2008-08-22 09:17:00.000000000 -0600 @@ -0,0 +1,57 @@ +--- gcc-3.2.3.orig/ggc/gcc-page.c 2003-05-06 15:37:04 +0800 ++++ gcc-3.2.3/gcc/ggc-page.c 2003-05-06 15:37:54 +0800 +@@ -495,28 +495,35 @@ + } + printf ("NULL\n"); + fflush (stdout); + } + ++static char *last_allocated_page = NULL; ++ + #ifdef USING_MMAP + /* Allocate SIZE bytes of anonymous memory, preferably near PREF, + (if non-null). The ifdef structure here is intended to cause a + compile error unless exactly one of the HAVE_* is defined. */ + + static inline char * + alloc_anon (pref, size) + char *pref ATTRIBUTE_UNUSED; + size_t size; + { ++ char *page; ++ ++ do { + #ifdef HAVE_MMAP_ANON +- char *page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE, +- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ++ page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + #endif + #ifdef HAVE_MMAP_DEV_ZERO +- char *page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE, +- MAP_PRIVATE, G.dev_zero_fd, 0); ++ page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE, G.dev_zero_fd, 0); + #endif ++ } while (page == last_allocated_page); ++ last_allocated_page = page; + + if (page == (char *) MAP_FAILED) + { + perror ("virtual memory exhausted"); + exit (FATAL_EXIT_CODE); +--- gcc-3.2.3.orig/gcc/fixinc/gnu-regex.c 2003-05-06 15:37:04 +0800 ++++ gcc-3.2.3/gcc/fixinc/gnu-regex.c 2003-05-06 15:37:42 +0800 +@@ -5718,11 +5718,11 @@ + if (errbuf_size != 0) + { + if (msg_size > errbuf_size) + { + #if defined HAVE_MEMPCPY || defined _LIBC +- *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0'; ++ *((char *) mempcpy (errbuf, msg, errbuf_size - 1)) = '\0'; + #else + memcpy (errbuf, msg, errbuf_size - 1); + errbuf[errbuf_size - 1] = 0; + #endif + } diff -urN -x CVS gcc-3.2.3.orig/include/obstack.h gcc-3.2.3/include/obstack.h --- gcc-3.2.3.orig/include/obstack.h 2001-03-14 12:44:38.000000000 -0700 +++ gcc-3.2.3/include/obstack.h 2008-08-22 09:17:00.000000000 -0600 @@ -423,7 +423,8 @@ ({ struct obstack *__o = (OBSTACK); \ if (__o->next_free + sizeof (void *) > __o->chunk_limit) \ _obstack_newchunk (__o, sizeof (void *)); \ - *((void **)__o->next_free)++ = ((void *)datum); \ + *((void **)__o->next_free) = ((void *)datum); \ + __o->next_free += sizeof (void *); \ (void) 0; }) # define obstack_int_grow(OBSTACK,datum) \ diff -urN -x CVS gcc-3.2.3.orig/THIS_ACTUALLY_WORKS_WITH_VERSION_3_2_AND_BELOW_2002_09_02 gcc-3.2.3/THIS_ACTUALLY_WORKS_WITH_VERSION_3_2_AND_BELOW_2002_09_02 --- gcc-3.2.3.orig/THIS_ACTUALLY_WORKS_WITH_VERSION_3_2_AND_BELOW_2002_09_02 1969-12-31 17:00:00.000000000 -0700 +++ gcc-3.2.3/THIS_ACTUALLY_WORKS_WITH_VERSION_3_2_AND_BELOW_2002_09_02 2008-08-22 09:17:00.000000000 -0600 @@ -0,0 +1,6 @@ +------------------------------------------------------------------- +this directory works with gcc-3.2.x (tested with 3.2.3) + +The mismatch between the numbering of gcc and this directory is an +historical accident. +-------------------------------------------------------------------