Annotation of GNUtools/cc/config/spur/spur.c, revision 1.1.1.1

1.1       root        1: /* Subroutines for insn-output.c for SPUR.  Adapted from routines for
                      2:    the Motorola 68000 family.
                      3:    Copyright (C) 1988, 1991 Free Software Foundation, Inc.
                      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 2, 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: #include "config.h"
                     22: #include "rtl.h"
                     23: #include "regs.h"
                     24: #include "hard-reg-set.h"
                     25: #include "real.h"
                     26: #include "insn-config.h"
                     27: #include "conditions.h"
                     28: #include "insn-flags.h"
                     29: #include "output.h"
                     30: #include "insn-attr.h"
                     31: 
                     32: static rtx find_addr_reg ();
                     33: 
                     34: char *
                     35: output_compare (operands, opcode, exchange_opcode, 
                     36:                neg_opcode, neg_exchange_opcode)
                     37:      rtx *operands;
                     38:      char *opcode;
                     39:      char *exchange_opcode;
                     40:      char *neg_opcode;
                     41:      char *neg_exchange_opcode;
                     42: {
                     43:   static char buf[100];
                     44:   operands[2] = operands[0];
                     45:   if (GET_CODE (cc_prev_status.value1) == CONST_INT)
                     46:     {
                     47:       operands[1] = cc_prev_status.value1;
                     48:       operands[0] = cc_prev_status.value2;
                     49:       opcode = exchange_opcode, neg_opcode = neg_exchange_opcode;
                     50:     }
                     51:   else
                     52:     {
                     53:       operands[0] = cc_prev_status.value1;
                     54:       operands[1] = cc_prev_status.value2;
                     55:     }
                     56:   if (TARGET_LONG_JUMPS)
                     57:     sprintf (buf,
                     58:             "cmp_br_delayed %s,%%0,%%1,1f\n\tnop\n\tjump %%l2\n\tnop\n1:",
                     59:             neg_opcode);
                     60:   else 
                     61:     sprintf (buf, "cmp_br_delayed %s,%%0,%%1,%%l2\n\tnop", opcode);
                     62:   return buf;
                     63: }
                     64: 
                     65: /* Return the best assembler insn template
                     66:    for moving operands[1] into operands[0] as a fullword.  */
                     67: 
                     68: static char *
                     69: singlemove_string (operands)
                     70:      rtx *operands;
                     71: {
                     72:   if (GET_CODE (operands[0]) == MEM)
                     73:     return "st_32 %r1,%0";
                     74:   if (GET_CODE (operands[1]) == MEM)
                     75:     return "ld_32 %0,%1\n\tnop";
                     76:   if (GET_CODE (operands[1]) == REG)
                     77:     return "add_nt %0,%1,$0";
                     78:   return "add_nt %0,r0,%1";
                     79: }
                     80: 
                     81: /* Output assembler code to perform a doubleword move insn
                     82:    with operands OPERANDS.  */
                     83: 
                     84: char *
                     85: output_move_double (operands)
                     86:      rtx *operands;
                     87: {
                     88:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                     89:   rtx latehalf[2];
                     90:   rtx addreg0 = 0, addreg1 = 0;
                     91: 
                     92:   /* First classify both operands.  */
                     93: 
                     94:   if (REG_P (operands[0]))
                     95:     optype0 = REGOP;
                     96:   else if (offsettable_memref_p (operands[0]))
                     97:     optype0 = OFFSOP;
                     98:   else if (GET_CODE (operands[0]) == MEM)
                     99:     optype0 = MEMOP;
                    100:   else
                    101:     optype0 = RNDOP;
                    102: 
                    103:   if (REG_P (operands[1]))
                    104:     optype1 = REGOP;
                    105:   else if (CONSTANT_P (operands[1]))
                    106:     optype1 = CNSTOP;
                    107:   else if (offsettable_memref_p (operands[1]))
                    108:     optype1 = OFFSOP;
                    109:   else if (GET_CODE (operands[1]) == MEM)
                    110:     optype1 = MEMOP;
                    111:   else
                    112:     optype1 = RNDOP;
                    113: 
                    114:   /* Check for the cases that the operand constraints are not
                    115:      supposed to allow to happen.  Abort if we get one,
                    116:      because generating code for these cases is painful.  */
                    117: 
                    118:   if (optype0 == RNDOP || optype1 == RNDOP)
                    119:     abort ();
                    120: 
                    121:   /* If an operand is an unoffsettable memory ref, find a register
                    122:      we can increment temporarily to make it refer to the second word.  */
                    123: 
                    124:   if (optype0 == MEMOP)
                    125:     addreg0 = find_addr_reg (XEXP (operands[0], 0));
                    126: 
                    127:   if (optype1 == MEMOP)
                    128:     addreg1 = find_addr_reg (XEXP (operands[1], 0));
                    129: 
                    130:   /* Ok, we can do one word at a time.
                    131:      Normally we do the low-numbered word first,
                    132:      but if either operand is autodecrementing then we
                    133:      do the high-numbered word first.
                    134: 
                    135:      In either case, set up in LATEHALF the operands to use
                    136:      for the high-numbered word and in some cases alter the
                    137:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    138: 
                    139:   if (optype0 == REGOP)
                    140:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    141:   else if (optype0 == OFFSOP)
                    142:     latehalf[0] = adj_offsettable_operand (operands[0], 4);
                    143:   else
                    144:     latehalf[0] = operands[0];
                    145: 
                    146:   if (optype1 == REGOP)
                    147:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    148:   else if (optype1 == OFFSOP)
                    149:     latehalf[1] = adj_offsettable_operand (operands[1], 4);
                    150:   else if (optype1 == CNSTOP)
                    151:     {
                    152:       if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    153:        {
                    154:          latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
                    155:                                 CONST_DOUBLE_HIGH (operands[1]));
                    156:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    157:                                 CONST_DOUBLE_LOW (operands[1]));
                    158:        }
                    159:       else if (CONSTANT_P (operands[1]))
                    160:        latehalf[1] = const0_rtx;
                    161:     }
                    162:   else
                    163:     latehalf[1] = operands[1];
                    164: 
                    165:   /* If the first move would clobber the source of the second one,
                    166:      do them in the other order.  This happens only for registers;
                    167:      such overlap can't happen in memory unless the user explicitly
                    168:      sets it up, and that is an undefined circumstance.  */
                    169: 
                    170:   if (optype0 == REGOP && optype1 == REGOP
                    171:       && REGNO (operands[0]) == REGNO (latehalf[1]))
                    172:     {
                    173:       /* Make any unoffsettable addresses point at high-numbered word.  */
                    174:       if (addreg0)
                    175:        output_asm_insn ("add_nt %0,%0,$4", &addreg0);
                    176:       if (addreg1)
                    177:        output_asm_insn ("add_nt %0,%0,$4", &addreg1);
                    178: 
                    179:       /* Do that word.  */
                    180:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    181: 
                    182:       /* Undo the adds we just did.  */
                    183:       if (addreg0)
                    184:        output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
                    185:       if (addreg1)
                    186:        output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
                    187: 
                    188:       /* Do low-numbered word.  */
                    189:       return singlemove_string (operands);
                    190:     }
                    191: 
                    192:   /* Normal case: do the two words, low-numbered first.  */
                    193: 
                    194:   output_asm_insn (singlemove_string (operands), operands);
                    195: 
                    196:   /* Make any unoffsettable addresses point at high-numbered word.  */
                    197:   if (addreg0)
                    198:     output_asm_insn ("add_nt %0,%0,$4", &addreg0);
                    199:   if (addreg1)
                    200:     output_asm_insn ("add_nt %0,%0,$4", &addreg1);
                    201: 
                    202:   /* Do that word.  */
                    203:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    204: 
                    205:   /* Undo the adds we just did.  */
                    206:   if (addreg0)
                    207:     output_asm_insn ("add_nt %0,%0,$-4", &addreg0);
                    208:   if (addreg1)
                    209:     output_asm_insn ("add_nt %0,%0,$-4", &addreg1);
                    210: 
                    211:   return "";
                    212: }
                    213: 
                    214: static char *
                    215: output_fp_move_double (operands)
                    216:      rtx *operands;
                    217: {
                    218:   if (FP_REG_P (operands[0]))
                    219:     {
                    220:       if (FP_REG_P (operands[1]))
                    221:        return "fmov %0,%1";
                    222:       if (GET_CODE (operands[1]) == REG)
                    223:        {
                    224:          rtx xoperands[2];
                    225:          int offset = - get_frame_size () - 8;
                    226:          xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    227:          xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4);
                    228:          output_asm_insn ("st_32 %1,r25,%0", xoperands);
                    229:          xoperands[1] = operands[1];
                    230:          xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset);
                    231:          output_asm_insn ("st_32 %1,r25,%0", xoperands);
                    232:          xoperands[1] = operands[0];
                    233:          output_asm_insn ("ld_dbl %1,r25,%0\n\tnop", xoperands);
                    234:          return "";
                    235:        }
                    236:       return "ld_dbl %0,%1\n\tnop";
                    237:     }
                    238:   else if (FP_REG_P (operands[1]))
                    239:     {
                    240:       if (GET_CODE (operands[0]) == REG)
                    241:        {
                    242:          rtx xoperands[2];
                    243:          int offset = - get_frame_size () - 8;
                    244:          xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset);
                    245:          xoperands[1] = operands[1];
                    246:          output_asm_insn ("st_dbl %1,r25,%0", xoperands);
                    247:          xoperands[1] = operands[0];
                    248:          output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands);
                    249:          xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    250:          xoperands[0] = gen_rtx (CONST_INT, VOIDmode, offset + 4);
                    251:          output_asm_insn ("ld_32 %1,r25,%0\n\tnop", xoperands);
                    252:          return "";
                    253:        }
                    254:       return "st_dbl %1,%0";
                    255:     }
                    256: }
                    257: 
                    258: /* Return a REG that occurs in ADDR with coefficient 1.
                    259:    ADDR can be effectively incremented by incrementing REG.  */
                    260: 
                    261: static rtx
                    262: find_addr_reg (addr)
                    263:      rtx addr;
                    264: {
                    265:   while (GET_CODE (addr) == PLUS)
                    266:     {
                    267:       if (GET_CODE (XEXP (addr, 0)) == REG)
                    268:        addr = XEXP (addr, 0);
                    269:       else if (GET_CODE (XEXP (addr, 1)) == REG)
                    270:        addr = XEXP (addr, 1);
                    271:       else if (CONSTANT_P (XEXP (addr, 0)))
                    272:        addr = XEXP (addr, 1);
                    273:       else if (CONSTANT_P (XEXP (addr, 1)))
                    274:        addr = XEXP (addr, 0);
                    275:       else
                    276:        abort ();
                    277:     }
                    278:   if (GET_CODE (addr) == REG)
                    279:     return addr;
                    280:   abort ();
                    281: }
                    282: 
                    283: /* Generate code to add a large integer constant to register, reg, storing
                    284:  * the result in a register, target.  Offset must be 27-bit signed quantity */
                    285: 
                    286: static char *
                    287: output_add_large_offset (target, reg, offset)
                    288:      rtx target, reg;
                    289:      int offset;
                    290: {
                    291:   rtx operands[3];
                    292:   int high, n, i;
                    293:   operands[0] = target, operands[1] = reg;
                    294:     
                    295:   for (high = offset, n = 0; 
                    296:        (unsigned) (high + 0x2000) >= 0x4000; 
                    297:        high >>= 1, n += 1)
                    298:     ;
                    299:   operands[2] = gen_rtx (CONST_INT, VOIDmode, high);
                    300:   output_asm_insn ("add_nt r2,r0,%2", operands);
                    301:   i = n;
                    302:   while (i >= 3)
                    303:     output_asm_insn ("sll r2,r2,$3", operands), i -= 3;
                    304:   if (i == 2) 
                    305:     output_asm_insn ("sll r2,r2,$2", operands);
                    306:   else if (i == 1)
                    307:     output_asm_insn ("sll r2,r2,$1", operands);
                    308:   output_asm_insn ("add_nt %0,r2,%1", operands);
                    309:   if (offset - (high << n) != 0)
                    310:     {
                    311:       operands[2] = gen_rtx (CONST_INT, VOIDmode, offset - (high << n));
                    312:       output_asm_insn ("add_nt %0,%0,%2", operands);
                    313:     }
                    314:   return "";
                    315: }
                    316: 
                    317: /* Additional TESTFN for matching. Like immediate_operand, but matches big
                    318:  * constants */
                    319: 
                    320: int
                    321: big_immediate_operand (op, mode)
                    322:      rtx op;
                    323:      enum machine_mode mode;
                    324: {
                    325:   return (GET_CODE (op) == CONST_INT);
                    326: }

unix.superglobalmegacorp.com

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