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

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

unix.superglobalmegacorp.com

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