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

unix.superglobalmegacorp.com

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