Annotation of gcc/config/pdp11/pdp11.c, revision 1.1.1.1

1.1       root        1: /* Subroutines for gcc2 for pdp11.
                      2:    Copyright (C) 1994 Free Software Foundation, Inc.
                      3:    Contributed by Michael K. Gschwind ([email protected]).
                      4: 
                      5: This file is part of GNU CC.
                      6: 
                      7: GNU CC is free software; you can redistribute it and/or modify
                      8: it under the terms of the GNU General Public License as published by
                      9: the Free Software Foundation; either version 1, or (at your option)
                     10: any later version.
                     11: 
                     12: GNU CC is distributed in the hope that it will be useful,
                     13: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     15: GNU General Public License for more details.
                     16: 
                     17: You should have received a copy of the GNU General Public License
                     18: along with GNU CC; see the file COPYING.  If not, write to
                     19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     20: 
                     21: #ifndef FILE
                     22: #include <stdio.h>
                     23: #endif
                     24: #include "config.h"
                     25: #include "rtl.h"
                     26: #include "regs.h"
                     27: #include "hard-reg-set.h"
                     28: #include "real.h"
                     29: #include "insn-config.h"
                     30: #include "conditions.h"
                     31: #include "insn-flags.h"
                     32: #include "output.h"
                     33: #include "insn-attr.h"
                     34: 
                     35: /*
                     36: #define FPU_REG_P(X)   ((X)>=8 && (X)<14)
                     37: #define CPU_REG_P(X)   ((X)>=0 && (X)<8)
                     38: */
                     39: 
                     40: /* this is the current value returned by the macro FIRST_PARM_OFFSET 
                     41:    defined in tm.h */
                     42: int current_first_parm_offset;
                     43: 
                     44: /* This is where the condition code register lives.  */
                     45: /* rtx cc0_reg_rtx; - no longer needed? */
                     46: 
                     47: static rtx find_addr_reg (); 
                     48: 
                     49: /* Nonzero if OP is a valid second operand for an arithmetic insn.  */
                     50: 
                     51: int
                     52: arith_operand (op, mode)
                     53:      rtx op;
                     54:      enum machine_mode mode;
                     55: {
                     56:   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
                     57: }
                     58: 
                     59: int
                     60: const_immediate_operand (op, mode)
                     61:      rtx op;
                     62:      enum machine_mode mode;
                     63: {
                     64:   return (GET_CODE (op) == CONST_INT);
                     65: }
                     66: 
                     67: int 
                     68: immediate15_operand (op, mode)
                     69:      rtx op;
                     70:      enum machine_mode mode;
                     71: {
                     72:     return (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0x8000) == 0x0000));
                     73: }
                     74: 
                     75: int
                     76: expand_shift_operand (op, mode)
                     77:   rtx op;
                     78:   enum machine_mode mode;
                     79: {
                     80:     return (GET_CODE (op) == CONST_INT 
                     81:            && abs (INTVAL(op)) > 1 
                     82:            && abs (INTVAL(op)) <= 4);
                     83: }
                     84: 
                     85: /*
                     86:    stream is a stdio stream to output the code to.
                     87:    size is an int: how many units of temporary storage to allocate.
                     88:    Refer to the array `regs_ever_live' to determine which registers
                     89:    to save; `regs_ever_live[I]' is nonzero if register number I
                     90:    is ever used in the function.  This macro is responsible for
                     91:    knowing which registers should not be saved even if used.  
                     92: */
                     93: 
                     94: void 
                     95: output_function_prologue(stream, size)
                     96:   FILE *stream;
                     97:   int size;
                     98: {                                                             
                     99:     extern char call_used_regs[];                                      
                    100:     extern int frame_pointer_needed;                           
                    101: 
                    102:     int fsize = ((size) + 1) & ~1;                                     
                    103:     int regno, nregs, i;                                               
                    104:     int offset = 0;
                    105: 
                    106:     int via_ac = -1;
                    107:     
                    108:     fprintf (stream, "\n\t;    /* function prologue %s*/\n", current_function_name);           
                    109: 
                    110:     /* if we are outputting code for main, 
                    111:        the switch FPU to right mode if TARGET_FPU */
                    112:     if ( (strcmp ("main", current_function_name) == 0)
                    113:         && TARGET_FPU)
                    114:     {
                    115:        fprintf(stream, "\t;/* switch cpu to double float, single integer */\n");
                    116:        fprintf(stream, "\tsetd\n");
                    117:        fprintf(stream, "\tseti\n\n");
                    118:     }
                    119:     
                    120:     if (frame_pointer_needed)                                  
                    121:     {                                                          
                    122:        fprintf(stream, "\tmov fp, -(sp)\n");                   
                    123:        fprintf(stream, "\tmov sp, fp\n");                              
                    124:     }                                                          
                    125:     else                                                               
                    126:     {                                                          
                    127:        /* DON'T SAVE FP */
                    128:     }                                                          
                    129: 
                    130:     /* make frame */
                    131:     if (fsize)                                                 
                    132:        fprintf (stream, "\tsub $%d, sp\n", fsize);                     
                    133: 
                    134:     /* save CPU registers  */
                    135:     for (regno = 0; regno < 8; regno++)                                
                    136:        if (regs_ever_live[regno] && ! call_used_regs[regno])   
                    137:            if (! ((regno == FRAME_POINTER_REGNUM)                      
                    138:                   && frame_pointer_needed))                            
                    139:                fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);        
                    140:     /* fpu regs saving */
                    141:     
                    142:     /* via_ac specifies the ac to use for saving ac4, ac5 */
                    143:     via_ac = -1;
                    144:     
                    145:     for (regno = 8; regno < FIRST_PSEUDO_REGISTER ; regno++) 
                    146:     {
                    147:        /* ac0 - ac3 */                                         
                    148:        if (LOAD_FPU_REG_P(regno)
                    149:            && regs_ever_live[regno] 
                    150:            && ! call_used_regs[regno])
                    151:        {
                    152:            fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[regno]);
                    153:            via_ac = regno;
                    154:        }
                    155:        
                    156:        /* maybe make ac4, ac5 call used regs?? */
                    157:        /* ac4 - ac5 */
                    158:        if (NO_LOAD_FPU_REG_P(regno)
                    159:            && regs_ever_live[regno]
                    160:            && ! call_used_regs[regno])
                    161:        {
                    162:            if (via_ac == -1)
                    163:                abort();
                    164:            
                    165:            fprintf (stream, "\tfldd %s, %s\n", reg_names[regno], reg_names[via_ac]);
                    166:            fprintf (stream, "\tfstd %s, -(sp)\n", reg_names[via_ac]);
                    167:        }
                    168:     }
                    169: 
                    170:     fprintf (stream, "\t;/* end of prologue */\n\n");          
                    171: }
                    172: 
                    173: /*
                    174:    The function epilogue should not depend on the current stack pointer!
                    175:    It should use the frame pointer only.  This is mandatory because
                    176:    of alloca; we also take advantage of it to omit stack adjustments
                    177:    before returning.  */
                    178: 
                    179: /* maybe we can make leaf functions faster by switching to the
                    180:    second register file - this way we don't have to save regs!
                    181:    leaf functions are ~ 50% of all functions (dynamically!) 
                    182: 
                    183:    set/clear bit 11 (dec. 2048) of status word for switching register files - 
                    184:    but how can we do this? the pdp11/45 manual says bit may only 
                    185:    be set (p.24), but not cleared!
                    186: 
                    187:    switching to kernel is probably more expensive, so we'll leave it 
                    188:    like this and not use the second set of registers... 
                    189: 
                    190:    maybe as option if you want to generate code for kernel mode? */
                    191: 
                    192: 
                    193: void 
                    194: output_function_epilogue(stream, size)
                    195:   FILE *stream;
                    196:   int size;
                    197: {                                                              
                    198:     extern char call_used_regs[];                                      
                    199:     extern int may_call_alloca;
                    200: 
                    201:     int fsize = ((size) + 1) & ~1;                                     
                    202:     int nregs, regno, i, j, k, adjust_fp;                              
                    203: 
                    204:     int via_ac;
                    205:     
                    206:     fprintf (stream, "\n\t;    /*function epilogue */\n");             
                    207: 
                    208:     if (frame_pointer_needed)                                  
                    209:     {                                                          
                    210:        /* hope this is safe - m68k does it also .... */                
                    211:        regs_ever_live[FRAME_POINTER_REGNUM] = 0;                       
                    212:                                                                
                    213:        for (i =7, j = 0 ; i >= 0 ; i--)                                
                    214:            if (regs_ever_live[i] && ! call_used_regs[i])               
                    215:                j++;
                    216:        
                    217:        /* remember # of pushed bytes for CPU regs */
                    218:        k = 2*j;
                    219:        
                    220:        for (i =7 ; i >= 0 ; i--)                                       
                    221:            if (regs_ever_live[i] && ! call_used_regs[i])               
                    222:                fprintf(stream, "\tmov %d(fp), %s\n",-fsize-2*j--, reg_names[i]);
                    223: 
                    224:        /* get ACs */                                           
                    225:        via_ac = FIRST_PSEUDO_REGISTER -1;
                    226:        
                    227:        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
                    228:            if (regs_ever_live[i] && ! call_used_regs[i])
                    229:            {
                    230:                via_ac = i;
                    231:                k += 8;
                    232:            }
                    233:        
                    234:        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
                    235:        {
                    236:            if (LOAD_FPU_REG_P(i)
                    237:                && regs_ever_live[i]
                    238:                && ! call_used_regs[i])
                    239:            {
                    240:                fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[i]);
                    241:                k -= 8;
                    242:            }
                    243:            
                    244:            if (NO_LOAD_FPU_REG_P(i)
                    245:                && regs_ever_live[i]
                    246:                && ! call_used_regs[i])
                    247:            {
                    248:                if (! LOAD_FPU_REG_P(via_ac))
                    249:                    abort();
                    250:                    
                    251:                fprintf(stream, "\tfldd %d(fp), %s\n", -fsize-k, reg_names[via_ac]);
                    252:                fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
                    253:                k -= 8;
                    254:            }
                    255:        }
                    256:        
                    257:        fprintf(stream, "\tmov fp, sp\n");                              
                    258:        fprintf (stream, "\tmov (sp)+, fp\n");                          
                    259:     }                                                          
                    260:     else                                                               
                    261:     {             
                    262:        via_ac = FIRST_PSEUDO_REGISTER -1;
                    263:        
                    264:        /* get ACs */
                    265:        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
                    266:            if (regs_ever_live[i] && call_used_regs[i])
                    267:                via_ac = i;
                    268:        
                    269:        for (i = FIRST_PSEUDO_REGISTER; i > 7; i--)
                    270:        {
                    271:            if (LOAD_FPU_REG_P(i)
                    272:                && regs_ever_live[i]
                    273:                && ! call_used_regs[i])
                    274:              fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[i]);
                    275:            
                    276:            if (NO_LOAD_FPU_REG_P(i)
                    277:                && regs_ever_live[i]
                    278:                && ! call_used_regs[i])
                    279:            {
                    280:                if (! LOAD_FPU_REG_P(via_ac))
                    281:                    abort();
                    282:                    
                    283:                fprintf(stream, "\tfldd (sp)+, %s\n", reg_names[via_ac]);
                    284:                fprintf(stream, "\tfstd %s, %s\n", reg_names[via_ac], reg_names[i]);
                    285:            }
                    286:        }
                    287: 
                    288:        for (i=7; i >= 0; i--)                                  
                    289:            if (regs_ever_live[i] && !call_used_regs[i])                
                    290:                fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]);     
                    291:                                                                
                    292:        if (fsize)                                              
                    293:            fprintf((stream), "\tadd $%d, sp\n", fsize);                
                    294:     }                  
                    295:                                        
                    296:     fprintf (stream, "\trts pc\n");                                    
                    297:     fprintf (stream, "\t;/* end of epilogue*/\n\n\n");         
                    298: }
                    299:        
                    300: /* Return the best assembler insn template
                    301:    for moving operands[1] into operands[0] as a fullword.  */
                    302: static char *
                    303: singlemove_string (operands)
                    304:      rtx *operands;
                    305: {
                    306:   if (operands[1] != const0_rtx)
                    307:     return "mov %1,%0";
                    308: 
                    309:   return "clr %0";
                    310: }
                    311: 
                    312: 
                    313: /* Output assembler code to perform a doubleword move insn
                    314:    with operands OPERANDS.  */
                    315: 
                    316: char *
                    317: output_move_double (operands)
                    318:      rtx *operands;
                    319: {
                    320:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                    321:   rtx latehalf[2];
                    322:   rtx addreg0 = 0, addreg1 = 0;
                    323: 
                    324:   /* First classify both operands.  */
                    325: 
                    326:   if (REG_P (operands[0]))
                    327:     optype0 = REGOP;
                    328:   else if (offsettable_memref_p (operands[0]))
                    329:     optype0 = OFFSOP;
                    330:   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
                    331:     optype0 = POPOP;
                    332:   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
                    333:     optype0 = PUSHOP;
                    334:   else if (GET_CODE (operands[0]) == MEM)
                    335:     optype0 = MEMOP;
                    336:   else
                    337:     optype0 = RNDOP;
                    338: 
                    339:   if (REG_P (operands[1]))
                    340:     optype1 = REGOP;
                    341:   else if (CONSTANT_P (operands[1]))
                    342: #if 0
                    343:           || GET_CODE (operands[1]) == CONST_DOUBLE)
                    344: #endif
                    345:     optype1 = CNSTOP;
                    346:   else if (offsettable_memref_p (operands[1]))
                    347:     optype1 = OFFSOP;
                    348:   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
                    349:     optype1 = POPOP;
                    350:   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
                    351:     optype1 = PUSHOP;
                    352:   else if (GET_CODE (operands[1]) == MEM)
                    353:     optype1 = MEMOP;
                    354:   else
                    355:     optype1 = RNDOP;
                    356: 
                    357:   /* Check for the cases that the operand constraints are not
                    358:      supposed to allow to happen.  Abort if we get one,
                    359:      because generating code for these cases is painful.  */
                    360: 
                    361:   if (optype0 == RNDOP || optype1 == RNDOP)
                    362:     abort ();
                    363: 
                    364:   /* If one operand is decrementing and one is incrementing
                    365:      decrement the former register explicitly
                    366:      and change that operand into ordinary indexing.  */
                    367: 
                    368:   if (optype0 == PUSHOP && optype1 == POPOP)
                    369:     {
                    370:       operands[0] = XEXP (XEXP (operands[0], 0), 0);
                    371:       output_asm_insn ("sub $4,%0", operands);
                    372:       operands[0] = gen_rtx (MEM, SImode, operands[0]);
                    373:       optype0 = OFFSOP;
                    374:     }
                    375:   if (optype0 == POPOP && optype1 == PUSHOP)
                    376:     {
                    377:       operands[1] = XEXP (XEXP (operands[1], 0), 0);
                    378:       output_asm_insn ("sub $4,%1", operands);
                    379:       operands[1] = gen_rtx (MEM, SImode, operands[1]);
                    380:       optype1 = OFFSOP;
                    381:     }
                    382: 
                    383:   /* If an operand is an unoffsettable memory ref, find a register
                    384:      we can increment temporarily to make it refer to the second word.  */
                    385: 
                    386:   if (optype0 == MEMOP)
                    387:     addreg0 = find_addr_reg (XEXP (operands[0], 0));
                    388: 
                    389:   if (optype1 == MEMOP)
                    390:     addreg1 = find_addr_reg (XEXP (operands[1], 0));
                    391: 
                    392:   /* Ok, we can do one word at a time.
                    393:      Normally we do the low-numbered word first,
                    394:      but if either operand is autodecrementing then we
                    395:      do the high-numbered word first.
                    396: 
                    397:      In either case, set up in LATEHALF the operands to use
                    398:      for the high-numbered word and in some cases alter the
                    399:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    400: 
                    401:   if (optype0 == REGOP)
                    402:     latehalf[0] = gen_rtx (REG, HImode, REGNO (operands[0]) + 1);
                    403:   else if (optype0 == OFFSOP)
                    404:     latehalf[0] = adj_offsettable_operand (operands[0], 2);
                    405:   else
                    406:     latehalf[0] = operands[0];
                    407: 
                    408:   if (optype1 == REGOP)
                    409:     latehalf[1] = gen_rtx (REG, HImode, REGNO (operands[1]) + 1);
                    410:   else if (optype1 == OFFSOP)
                    411:     latehalf[1] = adj_offsettable_operand (operands[1], 2);
                    412:   else if (optype1 == CNSTOP)
                    413:     {
                    414:        if (CONSTANT_P (operands[1]))
                    415:        {
                    416:            /* now the mess begins, high word is in lower word??? 
                    417: 
                    418:               that's what ashc makes me think, but I don't remember :-( */
                    419:            latehalf[1] = gen_rtx(CONST_INT, VOIDmode, 
                    420:                                  INTVAL(operands[1])>>16);
                    421:            operands[1] = gen_rtx(CONST_INT, VOIDmode,
                    422:                                  INTVAL(operands[1])&0xff);
                    423:        }
                    424:       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    425:        {
                    426:            /* immediate 32 bit values not allowed */
                    427:            abort();
                    428:        }
                    429:     }
                    430:   else
                    431:     latehalf[1] = operands[1];
                    432: 
                    433:   /* If insn is effectively movd N(sp),-(sp) then we will do the
                    434:      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
                    435:      for the low word as well, to compensate for the first decrement of sp.  */
                    436:   if (optype0 == PUSHOP
                    437:       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
                    438:       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
                    439:     operands[1] = latehalf[1];
                    440: 
                    441:   /* If one or both operands autodecrementing,
                    442:      do the two words, high-numbered first.  */
                    443: 
                    444:   /* Likewise,  the first move would clobber the source of the second one,
                    445:      do them in the other order.  This happens only for registers;
                    446:      such overlap can't happen in memory unless the user explicitly
                    447:      sets it up, and that is an undefined circumstance.  */
                    448: 
                    449:   if (optype0 == PUSHOP || optype1 == PUSHOP
                    450:       || (optype0 == REGOP && optype1 == REGOP
                    451:          && REGNO (operands[0]) == REGNO (latehalf[1])))
                    452:     {
                    453:       /* Make any unoffsettable addresses point at high-numbered word.  */
                    454:       if (addreg0)
                    455:        output_asm_insn ("add $2,%0", &addreg0);
                    456:       if (addreg1)
                    457:        output_asm_insn ("add $2,%0", &addreg1);
                    458: 
                    459:       /* Do that word.  */
                    460:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    461: 
                    462:       /* Undo the adds we just did.  */
                    463:       if (addreg0)
                    464:        output_asm_insn ("sub $2,%0", &addreg0);
                    465:       if (addreg1)
                    466:        output_asm_insn ("sub $2,%0", &addreg1);
                    467: 
                    468:       /* Do low-numbered word.  */
                    469:       return singlemove_string (operands);
                    470:     }
                    471: 
                    472:   /* Normal case: do the two words, low-numbered first.  */
                    473: 
                    474:   output_asm_insn (singlemove_string (operands), operands);
                    475: 
                    476:   /* Make any unoffsettable addresses point at high-numbered word.  */
                    477:   if (addreg0)
                    478:     output_asm_insn ("add $2,%0", &addreg0);
                    479:   if (addreg1)
                    480:     output_asm_insn ("add $2,%0", &addreg1);
                    481: 
                    482:   /* Do that word.  */
                    483:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    484: 
                    485:   /* Undo the adds we just did.  */
                    486:   if (addreg0)
                    487:     output_asm_insn ("sub $2,%0", &addreg0);
                    488:   if (addreg1)
                    489:     output_asm_insn ("sub $2,%0", &addreg1);
                    490: 
                    491:   return "";
                    492: }
                    493: /* Output assembler code to perform a quadword move insn
                    494:    with operands OPERANDS.  */
                    495: 
                    496: char *
                    497: output_move_quad (operands)
                    498:      rtx *operands;
                    499: {
                    500:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                    501:   rtx latehalf[2];
                    502:   rtx addreg0 = 0, addreg1 = 0;
                    503: 
                    504:   output_asm_insn(";; movdi/df: %1 -> %0", operands);
                    505:   
                    506:   if (REG_P (operands[0]))
                    507:     optype0 = REGOP;
                    508:   else if (offsettable_memref_p (operands[0]))
                    509:     optype0 = OFFSOP;
                    510:   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
                    511:     optype0 = POPOP;
                    512:   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
                    513:     optype0 = PUSHOP;
                    514:   else if (GET_CODE (operands[0]) == MEM)
                    515:     optype0 = MEMOP;
                    516:   else
                    517:     optype0 = RNDOP;
                    518: 
                    519:   if (REG_P (operands[1]))
                    520:     optype1 = REGOP;
                    521:   else if (CONSTANT_P (operands[1])
                    522:           || GET_CODE (operands[1]) == CONST_DOUBLE)
                    523:     optype1 = CNSTOP;
                    524:   else if (offsettable_memref_p (operands[1]))
                    525:     optype1 = OFFSOP;
                    526:   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
                    527:     optype1 = POPOP;
                    528:   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
                    529:     optype1 = PUSHOP;
                    530:   else if (GET_CODE (operands[1]) == MEM)
                    531:     optype1 = MEMOP;
                    532:   else
                    533:     optype1 = RNDOP;
                    534: 
                    535:   /* Check for the cases that the operand constraints are not
                    536:      supposed to allow to happen.  Abort if we get one,
                    537:      because generating code for these cases is painful.  */
                    538: 
                    539:   if (optype0 == RNDOP || optype1 == RNDOP)
                    540:     abort ();
                    541:   
                    542:   /* check if we move a CPU reg to an FPU reg, or vice versa! */
                    543:   if (optype0 == REGOP && optype1 == REGOP)
                    544:       /* bogus - 64 bit cannot reside in CPU! */
                    545:       if (CPU_REG_P(REGNO(operands[0]))
                    546:          || CPU_REG_P (REGNO(operands[1])))
                    547:          abort();
                    548:   
                    549:   if (optype0 == REGOP || optype1 == REGOP)
                    550:   {
                    551:       /* check for use of clrd???? 
                    552:          if you ever allow ac4 and ac5 (now we require secondary load) 
                    553:         you must check whether 
                    554:         you want to load into them or store from them - 
                    555:         then dump ac0 into $help$ movce ac4/5 to ac0, do the 
                    556:         store from ac0, and restore ac0 - if you can find 
                    557:         an unused ac[0-3], use that and you save a store and a load!*/
                    558: 
                    559:       if (FPU_REG_P(REGNO(operands[0])))
                    560:       {
                    561:          if (GET_CODE(operands[1]) == CONST_DOUBLE)
                    562:          {
                    563:              union { double d; int i[2]; } u;
                    564:              u.i[0] = CONST_DOUBLE_LOW (operands[1]); 
                    565:              u.i[1] = CONST_DOUBLE_HIGH (operands[1]); 
                    566:              
                    567:              if (u.d == 0.0)
                    568:                  return "clrd %0";
                    569:          }
                    570:              
                    571:          return "ldd %1, %0";
                    572:       }
                    573:       
                    574:       if (FPU_REG_P(REGNO(operands[1])))
                    575:          return "std %1, %0";
                    576:   }
                    577:       
                    578:   /* If one operand is decrementing and one is incrementing
                    579:      decrement the former register explicitly
                    580:      and change that operand into ordinary indexing.  */
                    581: 
                    582:   if (optype0 == PUSHOP && optype1 == POPOP)
                    583:     {
                    584:       operands[0] = XEXP (XEXP (operands[0], 0), 0);
                    585:       output_asm_insn ("sub $8,%0", operands);
                    586:       operands[0] = gen_rtx (MEM, DImode, operands[0]);
                    587:       optype0 = OFFSOP;
                    588:     }
                    589:   if (optype0 == POPOP && optype1 == PUSHOP)
                    590:     {
                    591:       operands[1] = XEXP (XEXP (operands[1], 0), 0);
                    592:       output_asm_insn ("sub $8,%1", operands);
                    593:       operands[1] = gen_rtx (MEM, SImode, operands[1]);
                    594:       optype1 = OFFSOP;
                    595:     }
                    596: 
                    597:   /* If an operand is an unoffsettable memory ref, find a register
                    598:      we can increment temporarily to make it refer to the second word.  */
                    599: 
                    600:   if (optype0 == MEMOP)
                    601:     addreg0 = find_addr_reg (XEXP (operands[0], 0));
                    602: 
                    603:   if (optype1 == MEMOP)
                    604:     addreg1 = find_addr_reg (XEXP (operands[1], 0));
                    605: 
                    606:   /* Ok, we can do one word at a time.
                    607:      Normally we do the low-numbered word first,
                    608:      but if either operand is autodecrementing then we
                    609:      do the high-numbered word first.
                    610: 
                    611:      In either case, set up in LATEHALF the operands to use
                    612:      for the high-numbered word and in some cases alter the
                    613:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    614: 
                    615:   if (optype0 == REGOP)
                    616:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2);
                    617:   else if (optype0 == OFFSOP)
                    618:     latehalf[0] = adj_offsettable_operand (operands[0], 4);
                    619:   else
                    620:     latehalf[0] = operands[0];
                    621: 
                    622:   if (optype1 == REGOP)
                    623:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2);
                    624:   else if (optype1 == OFFSOP)
                    625:     latehalf[1] = adj_offsettable_operand (operands[1], 4);
                    626:   else if (optype1 == CNSTOP)
                    627:     {
                    628:       if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    629:        {
                    630:            /* floats only. not yet supported!
                    631: 
                    632:             -- compute it into PDP float format, - internally,
                    633:             just use IEEE and ignore possible problems ;-)
                    634: 
                    635:             we might get away with it !!!! */
                    636: 
                    637:            abort();
                    638:            
                    639: #ifndef HOST_WORDS_BIG_ENDIAN
                    640:          latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
                    641:                                 CONST_DOUBLE_LOW (operands[1]));
                    642:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    643:                                 CONST_DOUBLE_HIGH (operands[1]));
                    644: #else /* HOST_WORDS_BIG_ENDIAN */
                    645:          latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
                    646:                                 CONST_DOUBLE_HIGH (operands[1]));
                    647:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    648:                                 CONST_DOUBLE_LOW (operands[1]));
                    649: #endif /* HOST_WORDS_BIG_ENDIAN */
                    650:        }
                    651:     }
                    652:   else
                    653:     latehalf[1] = operands[1];
                    654: 
                    655:   /* If insn is effectively movd N(sp),-(sp) then we will do the
                    656:      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
                    657:      for the low word as well, to compensate for the first decrement of sp.  */
                    658:   if (optype0 == PUSHOP
                    659:       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
                    660:       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
                    661:     operands[1] = latehalf[1];
                    662: 
                    663:   /* If one or both operands autodecrementing,
                    664:      do the two words, high-numbered first.  */
                    665: 
                    666:   /* Likewise,  the first move would clobber the source of the second one,
                    667:      do them in the other order.  This happens only for registers;
                    668:      such overlap can't happen in memory unless the user explicitly
                    669:      sets it up, and that is an undefined circumstance.  */
                    670: 
                    671:   if (optype0 == PUSHOP || optype1 == PUSHOP
                    672:       || (optype0 == REGOP && optype1 == REGOP
                    673:          && REGNO (operands[0]) == REGNO (latehalf[1])))
                    674:     {
                    675:       /* Make any unoffsettable addresses point at high-numbered word.  */
                    676:       if (addreg0)
                    677:        output_asm_insn ("add $4,%0", &addreg0);
                    678:       if (addreg1)
                    679:        output_asm_insn ("add $4,%0", &addreg1);
                    680: 
                    681:       /* Do that word.  */
                    682:       output_asm_insn(output_move_double(latehalf), latehalf);
                    683: 
                    684:       /* Undo the adds we just did.  */
                    685:       if (addreg0)
                    686:        output_asm_insn ("sub $4,%0", &addreg0);
                    687:       if (addreg1)
                    688:        output_asm_insn ("sub $4,%0", &addreg1);
                    689: 
                    690:       /* Do low-numbered word.  */
                    691:       return output_move_double (operands);
                    692:     }
                    693: 
                    694:   /* Normal case: do the two words, low-numbered first.  */
                    695: 
                    696:   output_asm_insn (output_move_double (operands), operands);
                    697: 
                    698:   /* Make any unoffsettable addresses point at high-numbered word.  */
                    699:   if (addreg0)
                    700:     output_asm_insn ("add $4,%0", &addreg0);
                    701:   if (addreg1)
                    702:     output_asm_insn ("add $4,%0", &addreg1);
                    703: 
                    704:   /* Do that word.  */
                    705:   output_asm_insn (output_move_double (latehalf), latehalf);
                    706: 
                    707:   /* Undo the adds we just did.  */
                    708:   if (addreg0)
                    709:     output_asm_insn ("sub $4,%0", &addreg0);
                    710:   if (addreg1)
                    711:     output_asm_insn ("sub $4,%0", &addreg1);
                    712: 
                    713:   return "";
                    714: }
                    715: 
                    716: 
                    717: /* Return a REG that occurs in ADDR with coefficient 1.
                    718:    ADDR can be effectively incremented by incrementing REG.  */
                    719: 
                    720: static rtx
                    721: find_addr_reg (addr)
                    722:      rtx addr;
                    723: {
                    724:   while (GET_CODE (addr) == PLUS)
                    725:     {
                    726:       if (GET_CODE (XEXP (addr, 0)) == REG)
                    727:        addr = XEXP (addr, 0);
                    728:       if (GET_CODE (XEXP (addr, 1)) == REG)
                    729:        addr = XEXP (addr, 1);
                    730:       if (CONSTANT_P (XEXP (addr, 0)))
                    731:        addr = XEXP (addr, 1);
                    732:       if (CONSTANT_P (XEXP (addr, 1)))
                    733:        addr = XEXP (addr, 0);
                    734:     }
                    735:   if (GET_CODE (addr) == REG)
                    736:     return addr;
                    737:   return 0;
                    738: }
                    739: 
                    740: /* Output an ascii string.  */
                    741: output_ascii (file, p, size)
                    742:      FILE *file;
                    743:      char *p;
                    744:      int size;
                    745: {
                    746:   int i;
                    747: 
                    748:   fprintf (file, "\t.byte \"");
                    749: 
                    750:   for (i = 0; i < size; i++)
                    751:     {
                    752:       register int c = p[i];
                    753:       if (c == '\"' || c == '\\')
                    754:        putc ('\\', file);
                    755:       if (c >= ' ' && c < 0177)
                    756:        putc (c, file);
                    757:       else
                    758:        {
                    759:          fprintf (file, "\\%03o", c);
                    760:          /* After an octal-escape, if a digit follows,
                    761:             terminate one string constant and start another.
                    762:             The Vax assembler fails to stop reading the escape
                    763:             after three digits, so this is the only way we
                    764:             can get it to parse the data properly.  */
                    765:          if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9')
                    766:            fprintf (file, "\"\n\tstring \"");
                    767:        }
                    768:     }
                    769:   fprintf (file, "\"\n");
                    770: }
                    771: 
                    772: 
                    773: /* --- stole from out-vax, needs changes */
                    774: 
                    775: print_operand_address (file, addr)
                    776:      FILE *file;
                    777:      register rtx addr;
                    778: {
                    779:   register rtx reg1, reg2, breg, ireg;
                    780:   rtx offset;
                    781: 
                    782:  retry:
                    783: 
                    784:   switch (GET_CODE (addr))
                    785:     {
                    786:     case MEM:
                    787:       fprintf (file, "@");
                    788:       addr = XEXP (addr, 0);
                    789:       goto retry;
                    790: 
                    791:     case REG:
                    792:       fprintf (file, "(%s)", reg_names[REGNO (addr)]);
                    793:       break;
                    794: 
                    795:     case PRE_DEC:
                    796:       fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]);
                    797:       break;
                    798: 
                    799:     case POST_INC:
                    800:       fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]);
                    801:       break;
                    802: 
                    803:     case PLUS:
                    804:       reg1 = 0;        reg2 = 0;
                    805:       ireg = 0;        breg = 0;
                    806:       offset = 0;
                    807:       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
                    808:          || GET_CODE (XEXP (addr, 0)) == MEM)
                    809:        {
                    810:          offset = XEXP (addr, 0);
                    811:          addr = XEXP (addr, 1);
                    812:        }
                    813:       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
                    814:               || GET_CODE (XEXP (addr, 1)) == MEM)
                    815:        {
                    816:          offset = XEXP (addr, 1);
                    817:          addr = XEXP (addr, 0);
                    818:        }
                    819:       if (GET_CODE (addr) != PLUS)
                    820:        ;
                    821:       else if (GET_CODE (XEXP (addr, 0)) == MULT)
                    822:        {
                    823:          reg1 = XEXP (addr, 0);
                    824:          addr = XEXP (addr, 1);
                    825:        }
                    826:       else if (GET_CODE (XEXP (addr, 1)) == MULT)
                    827:        {
                    828:          reg1 = XEXP (addr, 1);
                    829:          addr = XEXP (addr, 0);
                    830:        }
                    831:       else if (GET_CODE (XEXP (addr, 0)) == REG)
                    832:        {
                    833:          reg1 = XEXP (addr, 0);
                    834:          addr = XEXP (addr, 1);
                    835:        }
                    836:       else if (GET_CODE (XEXP (addr, 1)) == REG)
                    837:        {
                    838:          reg1 = XEXP (addr, 1);
                    839:          addr = XEXP (addr, 0);
                    840:        }
                    841:       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
                    842:        {
                    843:          if (reg1 == 0)
                    844:            reg1 = addr;
                    845:          else
                    846:            reg2 = addr;
                    847:          addr = 0;
                    848:        }
                    849:       if (offset != 0)
                    850:        {
                    851:          if (addr != 0) abort ();
                    852:          addr = offset;
                    853:        }
                    854:       if (reg1 != 0 && GET_CODE (reg1) == MULT)
                    855:        {
                    856:          breg = reg2;
                    857:          ireg = reg1;
                    858:        }
                    859:       else if (reg2 != 0 && GET_CODE (reg2) == MULT)
                    860:        {
                    861:          breg = reg1;
                    862:          ireg = reg2;
                    863:        }
                    864:       else if (reg2 != 0 || GET_CODE (addr) == MEM)
                    865:        {
                    866:          breg = reg2;
                    867:          ireg = reg1;
                    868:        }
                    869:       else
                    870:        {
                    871:          breg = reg1;
                    872:          ireg = reg2;
                    873:        }
                    874:       if (addr != 0)
                    875:        output_address (addr);
                    876:       if (breg != 0)
                    877:        {
                    878:          if (GET_CODE (breg) != REG)
                    879:            abort ();
                    880:          fprintf (file, "(%s)", reg_names[REGNO (breg)]);
                    881:        }
                    882:       if (ireg != 0)
                    883:        {
                    884:          if (GET_CODE (ireg) == MULT)
                    885:            ireg = XEXP (ireg, 0);
                    886:          if (GET_CODE (ireg) != REG)
                    887:            abort ();
                    888:          abort();
                    889:          fprintf (file, "[%s]", reg_names[REGNO (ireg)]);
                    890:        }
                    891:       break;
                    892: 
                    893:     default:
                    894:       output_addr_const (file, addr);
                    895:     }
                    896: }
                    897: 
                    898: /* register move costs, indexed by regs */
                    899: 
                    900: static int move_costs[N_REG_CLASSES][N_REG_CLASSES] = 
                    901: {
                    902:              /* NO  MUL  GEN  LFPU  NLFPU FPU ALL */
                    903: 
                    904: /* NO */     {  0,   0,   0,    0,    0,    0,   0},
                    905: /* MUL */    {  0,   2,   2,   10,   22,   22,  22},
                    906: /* GEN */    {  0,   2,   2,   10,   22,   22,  22},
                    907: /* LFPU */   {  0,  10,  10,    2,    2,    2,  10},
                    908: /* NLFPU */  {  0,  22,  22,    2,    2,    2,  22},
                    909: /* FPU */    {  0,  22,  22,    2,    2,    2,  22},
                    910: /* ALL */    {  0,  22,  22,   10,   22,   22,  22}
                    911: }  ;
                    912: 
                    913: 
                    914: /* -- note that some moves are tremendously expensive, 
                    915:    because they require lots of tricks! do we have to 
                    916:    charge the costs incurred by secondary reload class 
                    917:    -- as we do here with 22 -- or not ? */
                    918: 
                    919: int 
                    920: register_move_cost(c1, c2)
                    921:   enum reg_class c1, c2;
                    922: {
                    923:     return move_costs[(int)c1][(int)c2];
                    924: }
                    925: 
                    926: char *
                    927: output_jump(pos, neg, length)
                    928:   int length;
                    929:   char *pos, *neg;
                    930: {
                    931:     static int x = 0;
                    932:     
                    933:     static char buf[1000];
                    934: 
                    935: #if 0
                    936: /* currently we don't need this, because the tstdf and cmpdf 
                    937:    copy the condition code immediately, and other float operations are not 
                    938:    yet recognized as changing the FCC - if so, then the length-cost of all
                    939:    jump insns increases by one, because we have to potentially copy the 
                    940:    FCC! */
                    941:     if (cc_status.flags & CC_IN_FPU)
                    942:        output_asm_insn("cfcc", NULL);
                    943: #endif
                    944:        
                    945:     switch (length)
                    946:     {
                    947:       case 1:
                    948:        
                    949:        strcpy(buf, pos);
                    950:        strcat(buf, " %l0");
                    951:        
                    952:        return buf;
                    953:        
                    954:       case 3:
                    955:        
                    956:        sprintf(buf, "%s JMP_%d\n\tjmp %%l0\nJMP_%d:", neg, x, x);
                    957:        
                    958:        x++;
                    959:        
                    960:        return buf;
                    961:        
                    962:       default:
                    963:        
                    964:        abort();
                    965:     }
                    966:     
                    967: }
                    968: 
                    969: void
                    970: notice_update_cc_on_set(exp, insn)
                    971:   rtx exp;
                    972:   rtx insn;
                    973: {
                    974:     if (GET_CODE (SET_DEST (exp)) == CC0)
                    975:     { 
                    976:        cc_status.flags = 0;                                    
                    977:        cc_status.value1 = SET_DEST (exp);                      
                    978:        cc_status.value2 = SET_SRC (exp);                       
                    979: 
                    980: /*
                    981:        if (GET_MODE(SET_SRC(exp)) == DFmode)
                    982:            cc_status.flags |= CC_IN_FPU;
                    983: */     
                    984:     }                                                  
                    985:     else if ((GET_CODE (SET_DEST (exp)) == REG         
                    986:              || GET_CODE (SET_DEST (exp)) == MEM)              
                    987:             && GET_CODE (SET_SRC (exp)) != PC          
                    988:             && (GET_MODE (SET_DEST(exp)) == HImode             
                    989:                 || GET_MODE (SET_DEST(exp)) == QImode) 
                    990:                && (GET_CODE (SET_SRC(exp)) == PLUS             
                    991:                    || GET_CODE (SET_SRC(exp)) == MINUS 
                    992:                    || GET_CODE (SET_SRC(exp)) == AND   
                    993:                    || GET_CODE (SET_SRC(exp)) == IOR   
                    994:                    || GET_CODE (SET_SRC(exp)) == XOR   
                    995:                    || GET_CODE (SET_SRC(exp)) == NOT   
                    996:                    || GET_CODE (SET_SRC(exp)) == NEG   
                    997:                        || GET_CODE (SET_SRC(exp)) == REG       
                    998:                    || GET_CODE (SET_SRC(exp)) == MEM)) 
                    999:     { 
                   1000:        cc_status.flags = 0;                                    
                   1001:        cc_status.value1 = SET_SRC (exp);                       
                   1002:        cc_status.value2 = SET_DEST (exp);                      
                   1003:        
                   1004:        if (cc_status.value1 && GET_CODE (cc_status.value1) == REG      
                   1005:            && cc_status.value2                                 
                   1006:            && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
                   1007:            cc_status.value2 = 0;                                       
                   1008:        if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM      
                   1009:            && cc_status.value2                                 
                   1010:            && GET_CODE (cc_status.value2) == MEM)                      
                   1011:            cc_status.value2 = 0;                                       
                   1012:     }                                                  
                   1013:     else if (GET_CODE (SET_SRC (exp)) == CALL)         
                   1014:     { 
                   1015:        CC_STATUS_INIT; 
                   1016:     }
                   1017:     else if (GET_CODE (SET_DEST (exp)) == REG)                 
                   1018:        /* what's this ? */                                     
                   1019:     { 
                   1020:        if ((cc_status.value1                                   
                   1021:             && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1)))
                   1022:            cc_status.value1 = 0;                               
                   1023:        if ((cc_status.value2                                   
                   1024:             && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2)))
                   1025:            cc_status.value2 = 0;                               
                   1026:     }                                                  
                   1027:     else if (SET_DEST(exp) == pc_rtx)
                   1028:     { 
                   1029:        /* jump */
                   1030:     }
                   1031:     else /* if (GET_CODE (SET_DEST (exp)) == MEM)      */      
                   1032:     {  
                   1033:        /* the last else is a bit paranoic, but since nearly all instructions 
                   1034:           play with condition codes, it's reasonable! */
                   1035: 
                   1036:        CC_STATUS_INIT; /* paranoia*/ 
                   1037:     }                  
                   1038: }
                   1039: 
                   1040: 
                   1041: int simple_memory_operand(op, mode)
                   1042:   rtx op;
                   1043:   enum machine_mode mode;
                   1044: {
                   1045:     rtx addr, plus0, plus1;
                   1046:     int offset = 0;
                   1047: 
                   1048:     /* Eliminate non-memory operations */
                   1049:     if (GET_CODE (op) != MEM)
                   1050:        return FALSE;
                   1051: 
                   1052: #if 0
                   1053:     /* dword operations really put out 2 instructions, so eliminate them.  */
                   1054:     if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
                   1055:        return FALSE;
                   1056: #endif
                   1057: 
                   1058:     /* Decode the address now.  */
                   1059: 
                   1060:   indirection:
                   1061:     
                   1062:     addr = XEXP (op, 0);
                   1063: 
                   1064:     switch (GET_CODE (addr))
                   1065:     {
                   1066:       case REG:
                   1067:        /* (R0) - no extra cost */
                   1068:        return 1;
                   1069:        
                   1070:       case PRE_DEC:
                   1071:       case POST_INC:
                   1072:        /* -(R0), (R0)+ - cheap! */
                   1073:        return 0;
                   1074:        
                   1075:       case MEM:
                   1076:        /* cheap - is encoded in addressing mode info! 
                   1077: 
                   1078:           -- except for @(R0), which has to be @0(R0) !!! */
                   1079: 
                   1080:        if (GET_CODE (XEXP (addr, 0)) == REG)
                   1081:            return 0;
                   1082:        
                   1083:        op=addr;
                   1084:        goto indirection;
                   1085:        
                   1086:       case CONST_INT:
                   1087:       case LABEL_REF:         
                   1088:       case CONST:
                   1089:       case SYMBOL_REF:
                   1090:        /* @#address - extra cost */
                   1091:        return 0;
                   1092: 
                   1093:       case PLUS:
                   1094:        /* X(R0) - extra cost */
                   1095:        return 0;
                   1096:     }
                   1097:     
                   1098:     return FALSE;
                   1099: }
                   1100: 
                   1101: 
                   1102: /*
                   1103:  * output a block move:
                   1104:  *
                   1105:  * operands[0] ... to
                   1106:  * operands[1]  ... from
                   1107:  * operands[2]  ... length
                   1108:  * operands[3]  ... alignment
                   1109:  * operands[4]  ... scratch register
                   1110:  */
                   1111: 
                   1112:  
                   1113: char *
                   1114: output_block_move(operands)
                   1115:   rtx *operands;
                   1116: {
                   1117:     static int count = 0;
                   1118:     char buf[200];
                   1119:     
                   1120:     if (GET_CODE(operands[2]) == CONST_INT
                   1121:        && TARGET_TIME)
                   1122:     {
                   1123:        if (INTVAL(operands[2]) < 16
                   1124:            && INTVAL(operands[3]) == 1)
                   1125:        {
                   1126:            register int i;
                   1127:            
                   1128:            for (i = 1; i <= INTVAL(operands[2]); i++)
                   1129:                output_asm_insn("movb (%1)+, (%0)+", operands);
                   1130: 
                   1131:            return "";
                   1132:        }
                   1133:        else if (INTVAL(operands[2]) < 32)
                   1134:        {
                   1135:            register int i;
                   1136:            
                   1137:            for (i = 1; i <= INTVAL(operands[2])/2; i++)
                   1138:                output_asm_insn("mov (%1)+, (%0)+", operands);
                   1139:            
                   1140:            /* may I assume that moved quantity is 
                   1141:               multiple of alignment ???
                   1142: 
                   1143:               I HOPE SO !
                   1144:            */
                   1145: 
                   1146:            return "";
                   1147:        }
                   1148:        
                   1149: 
                   1150:        /* can do other clever things, maybe... */
                   1151:     }
                   1152: 
                   1153:     if (CONSTANT_P(operands[2]) )
                   1154:     {
                   1155:        /* just move count to scratch */
                   1156:        output_asm_insn("mov %2, %4", operands);
                   1157:     }
                   1158:     else
                   1159:     {
                   1160:        /* just clobber the register */
                   1161:        operands[4] = operands[2];
                   1162:     }
                   1163:     
                   1164: 
                   1165:     /* switch over alignment */
                   1166:     switch (INTVAL(operands[3]))
                   1167:     {
                   1168:       case 1:
                   1169:        
                   1170:        /* 
                   1171:          x:
                   1172:          movb (%1)+, (%0)+
                   1173:          
                   1174:          if (TARGET_45)
                   1175:             sob %4,x
                   1176:          else
                   1177:             dec %4
                   1178:             bgt x
                   1179: 
                   1180:        */
                   1181: 
                   1182:        sprintf(buf, "\nmovestrhi%d:", count);
                   1183:        output_asm_insn(buf, NULL);
                   1184:        
                   1185:        output_asm_insn("movb (%1)+, (%0)+", operands);
                   1186:        
                   1187:        if (TARGET_45)
                   1188:        {
                   1189:            sprintf(buf, "sob %%4, movestrhi%d", count);
                   1190:            output_asm_insn(buf, operands);
                   1191:        }
                   1192:        else
                   1193:        {
                   1194:            output_asm_insn("dec %4", operands);
                   1195:            
                   1196:            sprintf(buf, "bgt movestrhi%d", count);
                   1197:            output_asm_insn(buf, NULL);
                   1198:        }
                   1199:        
                   1200:        count ++;
                   1201:        break;
                   1202:        
                   1203:       case 2:
                   1204:        
                   1205:        /* 
                   1206:           asr %4
                   1207: 
                   1208:           x:
                   1209: 
                   1210:           mov (%1)+, (%0)+
                   1211: 
                   1212:           if (TARGET_45)
                   1213:             sob %4, x
                   1214:           else
                   1215:             dec %4
                   1216:             bgt x
                   1217:        */
                   1218: 
                   1219:       generate_compact_code:
                   1220: 
                   1221:        output_asm_insn("asr %4", operands);
                   1222: 
                   1223:        sprintf(buf, "\nmovestrhi%d:", count);
                   1224:        output_asm_insn(buf, NULL);
                   1225:        
                   1226:        output_asm_insn("mov (%1)+, (%0)+", operands);
                   1227:        
                   1228:        if (TARGET_45)
                   1229:        {
                   1230:            sprintf(buf, "sob %%4, movestrhi%d", count);
                   1231:            output_asm_insn(buf, operands);
                   1232:        }
                   1233:        else
                   1234:        {
                   1235:            output_asm_insn("dec %4", operands);
                   1236:            
                   1237:            sprintf(buf, "bgt movestrhi%d", count);
                   1238:            output_asm_insn(buf, NULL);
                   1239:        }
                   1240:        
                   1241:        count ++;
                   1242:        break;
                   1243: 
                   1244:       case 4:
                   1245:        
                   1246:        /*
                   1247: 
                   1248:           asr %4
                   1249:           asr %4
                   1250: 
                   1251:           x:
                   1252: 
                   1253:           mov (%1)+, (%0)+
                   1254:           mov (%1)+, (%0)+
                   1255: 
                   1256:           if (TARGET_45)
                   1257:             sob %4, x
                   1258:           else
                   1259:             dec %4
                   1260:             bgt x
                   1261:        */
                   1262: 
                   1263:        if (TARGET_SPACE)
                   1264:            goto generate_compact_code;
                   1265:        
                   1266:        output_asm_insn("asr %4", operands);
                   1267:        output_asm_insn("asr %4", operands);
                   1268: 
                   1269:        sprintf(buf, "\nmovestrhi%d:", count);
                   1270:        output_asm_insn(buf, NULL);
                   1271:        
                   1272:        output_asm_insn("mov (%1)+, (%0)+", operands);
                   1273:        output_asm_insn("mov (%1)+, (%0)+", operands);
                   1274:        
                   1275:        if (TARGET_45)
                   1276:        {
                   1277:            sprintf(buf, "sob %%4, movestrhi%d", count);
                   1278:            output_asm_insn(buf, operands);
                   1279:        }
                   1280:        else
                   1281:        {
                   1282:            output_asm_insn("dec %4", operands);
                   1283:            
                   1284:            sprintf(buf, "bgt movestrhi%d", count);
                   1285:            output_asm_insn(buf, NULL);
                   1286:        }
                   1287:        
                   1288:        count ++;
                   1289:        break;
                   1290:        
                   1291:       default:
                   1292:        
                   1293:        /*
                   1294:           
                   1295:           asr %4
                   1296:           asr %4
                   1297:           asr %4
                   1298: 
                   1299:           x:
                   1300: 
                   1301:           mov (%1)+, (%0)+
                   1302:           mov (%1)+, (%0)+
                   1303:           mov (%1)+, (%0)+
                   1304:           mov (%1)+, (%0)+
                   1305:           
                   1306:           if (TARGET_45)
                   1307:             sob %4, x
                   1308:           else
                   1309:             dec %4
                   1310:             bgt x
                   1311:        */
                   1312: 
                   1313: 
                   1314:        if (TARGET_SPACE)
                   1315:            goto generate_compact_code;
                   1316:        
                   1317:        output_asm_insn("asr %4", operands);
                   1318:        output_asm_insn("asr %4", operands);
                   1319:        output_asm_insn("asr %4", operands);
                   1320: 
                   1321:        sprintf(buf, "\nmovestrhi%d:", count);
                   1322:        output_asm_insn(buf, NULL);
                   1323:        
                   1324:        output_asm_insn("mov (%1)+, (%0)+", operands);
                   1325:        output_asm_insn("mov (%1)+, (%0)+", operands);
                   1326:        output_asm_insn("mov (%1)+, (%0)+", operands);
                   1327:        output_asm_insn("mov (%1)+, (%0)+", operands);
                   1328:        
                   1329:        if (TARGET_45)
                   1330:        {
                   1331:            sprintf(buf, "sob %%4, movestrhi%d", count);
                   1332:            output_asm_insn(buf, operands);
                   1333:        }
                   1334:        else
                   1335:        {
                   1336:            output_asm_insn("dec %4", operands);
                   1337:            
                   1338:            sprintf(buf, "bgt movestrhi%d", count);
                   1339:            output_asm_insn(buf, NULL);
                   1340:        }
                   1341:        
                   1342:        count ++;
                   1343:        break;
                   1344:        
                   1345:        ;
                   1346:        
                   1347:     }
                   1348:     
                   1349:     return "";
                   1350: }
                   1351: 
                   1352: /* for future use */
                   1353: int
                   1354: comparison_operator_index(op)
                   1355:   rtx op;
                   1356: {
                   1357:     switch (GET_CODE(op))
                   1358:     {
                   1359:       case NE:
                   1360:        return 0;
                   1361:        
                   1362:       case EQ:
                   1363:        return 1;
                   1364:        
                   1365:       case GE:
                   1366:        return 2;
                   1367:        
                   1368:       case GT:
                   1369:        return 3;
                   1370:        
                   1371:       case LE:
                   1372:        return 4;
                   1373:        
                   1374:       case LT:
                   1375:        return 5;
                   1376:        
                   1377:       case GEU:
                   1378:        return 6;
                   1379:        
                   1380:       case GTU:
                   1381:        return 7;
                   1382: 
                   1383:       case LEU:
                   1384:        return 8;
                   1385:        
                   1386:       case LTU:
                   1387:        return 9;
                   1388:        
                   1389:       default:
                   1390:        return -1;
                   1391:     }
                   1392: }    
                   1393:        
                   1394: /* tests whether the rtx is a comparison operator */
                   1395: int
                   1396: comp_operator (op, mode)
                   1397:   rtx op;
                   1398:   enum machine_mode mode;
                   1399: {
                   1400:     return comparison_operator_index(op) >= 0;
                   1401: }
                   1402: 
                   1403:     
                   1404: int
                   1405: legitimate_address_p (mode, address)
                   1406:   enum machine_mode mode;
                   1407:   rtx address;
                   1408: {
                   1409: /* #define REG_OK_STRICT */
                   1410:     GO_IF_LEGITIMATE_ADDRESS(mode, address, win);
                   1411:     
                   1412:     return 0;
                   1413:     
                   1414:   win:
                   1415:     return 1;
                   1416: 
                   1417: /* #undef REG_OK_STRICT */
                   1418: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.