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

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

unix.superglobalmegacorp.com

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