Annotation of researchv10dc/cmd/gcc/output-m68k.c, revision 1.1.1.1

1.1       root        1: /* Subroutines for insn-output.c for Motorola 68000 family.
                      2:    Copyright (C) 1987 Free Software Foundation, Inc.
                      3: 
                      4: This file is part of GNU CC.
                      5: 
                      6: GNU CC is distributed in the hope that it will be useful,
                      7: but WITHOUT ANY WARRANTY.  No author or distributor
                      8: accepts responsibility to anyone for the consequences of using it
                      9: or for whether it serves any particular purpose or works at all,
                     10: unless he says so in writing.  Refer to the GNU CC General Public
                     11: License for full details.
                     12: 
                     13: Everyone is granted permission to copy, modify and redistribute
                     14: GNU CC, but only under the conditions described in the
                     15: GNU CC General Public License.   A copy of this license is
                     16: supposed to have been given to you along with GNU CC so you
                     17: can know your rights and responsibilities.  It should be in a
                     18: file named COPYING.  Among other things, the copyright notice
                     19: and this notice must be preserved on all copies.  */
                     20: 
                     21: 
                     22: /* Some output-actions in m68k.md need these.  */
                     23: #include <stdio.h>
                     24: extern FILE *asm_out_file;
                     25: 
                     26: static rtx find_addr_reg ();
                     27: 
                     28: char *
                     29: output_btst (operands, countop, dataop, insn, signpos)
                     30:      rtx *operands;
                     31:      rtx countop, dataop;
                     32:      rtx insn;
                     33:      int signpos;
                     34: {
                     35:   operands[0] = countop;
                     36:   operands[1] = dataop;
                     37:   if (GET_CODE (countop) == CONST_INT)
                     38:     {
                     39:       register int count = INTVAL (countop);
                     40:       if (count == signpos)
                     41:        cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
                     42:       else
                     43:        cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
                     44: 
                     45:       if (count == 31
                     46:          && next_insn_tests_no_inequality (insn))
                     47:        return "tst%.l %1";
                     48:       if (count == 15
                     49:          && next_insn_tests_no_inequality (insn))
                     50:        return "tst%.w %1";
                     51:       if (count == 7
                     52:          && next_insn_tests_no_inequality (insn))
                     53:        return "tst%.b %1";
                     54: 
                     55:       cc_status.flags = CC_NOT_NEGATIVE;
                     56:     }
                     57:   return "btst %0,%1";
                     58: }
                     59: 
                     60: /* Return the best assembler insn template
                     61:    for moving operands[1] into operands[0] as a fullword.  */
                     62: 
                     63: static char *
                     64: singlemove_string (operands)
                     65:      rtx *operands;
                     66: {
                     67:   if (operands[1] != const0_rtx)
                     68:     return "move%.l %1,%0";
                     69:   if (! ADDRESS_REG_P (operands[0]))
                     70:     return "clr%.l %0";
                     71:   return "sub%.l %0,%0";
                     72: }
                     73: 
                     74: /* Output assembler code to perform a doubleword move insn
                     75:    with operands OPERANDS.  */
                     76: 
                     77: char *
                     78: output_move_double (operands)
                     79:      rtx *operands;
                     80: {
                     81:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                     82:   rtx latehalf[2];
                     83:   rtx addreg0 = 0, addreg1 = 0;
                     84: 
                     85:   /* First classify both operands.  */
                     86: 
                     87:   if (REG_P (operands[0]))
                     88:     optype0 = REGOP;
                     89:   else if (offsetable_memref_p (operands[0]))
                     90:     optype0 = OFFSOP;
                     91:   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
                     92:     optype0 = POPOP;
                     93:   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
                     94:     optype0 = PUSHOP;
                     95:   else if (GET_CODE (operands[0]) == MEM)
                     96:     optype0 = MEMOP;
                     97:   else
                     98:     optype0 = RNDOP;
                     99: 
                    100:   if (REG_P (operands[1]))
                    101:     optype1 = REGOP;
                    102:   else if (CONSTANT_P (operands[1])
                    103:           || GET_CODE (operands[1]) == CONST_DOUBLE)
                    104:     optype1 = CNSTOP;
                    105:   else if (offsetable_memref_p (operands[1]))
                    106:     optype1 = OFFSOP;
                    107:   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
                    108:     optype1 = POPOP;
                    109:   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
                    110:     optype1 = PUSHOP;
                    111:   else if (GET_CODE (operands[1]) == MEM)
                    112:     optype1 = MEMOP;
                    113:   else
                    114:     optype1 = RNDOP;
                    115: 
                    116:   /* Check for the cases that the operand constraints are not
                    117:      supposed to allow to happen.  Abort if we get one,
                    118:      because generating code for these cases is painful.  */
                    119: 
                    120:   if (optype0 == RNDOP || optype1 == RNDOP)
                    121:     abort ();
                    122: 
                    123:   /* If one operand is decrementing and one is incrementing
                    124:      decrement the former register explicitly
                    125:      and change that operand into ordinary indexing.  */
                    126: 
                    127:   if (optype0 == PUSHOP && optype1 == POPOP)
                    128:     {
                    129:       operands[0] = XEXP (XEXP (operands[0], 0), 0);
                    130:       output_asm_insn ("subq%.l %#8,%0", operands);
                    131:       operands[0] = gen_rtx (MEM, DImode, operands[0]);
                    132:       optype0 = OFFSOP;
                    133:     }
                    134:   if (optype0 == POPOP && optype1 == PUSHOP)
                    135:     {
                    136:       operands[1] = XEXP (XEXP (operands[1], 0), 0);
                    137:       output_asm_insn ("subq%.l %#8,%1", operands);
                    138:       operands[1] = gen_rtx (MEM, DImode, operands[1]);
                    139:       optype1 = OFFSOP;
                    140:     }
                    141: 
                    142:   /* If an operand is an unoffsettable memory ref, find a register
                    143:      we can increment temporarily to make it refer to the second word.  */
                    144: 
                    145:   if (optype0 == MEMOP)
                    146:     addreg0 = find_addr_reg (operands[0]);
                    147: 
                    148:   if (optype1 == MEMOP)
                    149:     addreg1 = find_addr_reg (operands[1]);
                    150: 
                    151:   /* Ok, we can do one word at a time.
                    152:      Normally we do the low-numbered word first,
                    153:      but if either operand is autodecrementing then we
                    154:      do the high-numbered word first.
                    155: 
                    156:      In either case, set up in LATEHALF the operands to use
                    157:      for the high-numbered word and in some cases alter the
                    158:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    159: 
                    160:   if (optype0 == REGOP)
                    161:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    162:   else if (optype0 == OFFSOP)
                    163:     latehalf[0] = adj_offsetable_operand (operands[0], 4);
                    164:   else
                    165:     latehalf[0] = operands[0];
                    166: 
                    167:   if (optype1 == REGOP)
                    168:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    169:   else if (optype1 == OFFSOP)
                    170:     latehalf[1] = adj_offsetable_operand (operands[1], 4);
                    171:   else if (optype1 == CNSTOP)
                    172:     {
                    173:       if (CONSTANT_P (operands[1]))
                    174:        latehalf[1] = const0_rtx;
                    175:       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    176:        {
                    177:          latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1));
                    178:          operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0));
                    179:        }
                    180:     }
                    181:   else
                    182:     latehalf[1] = operands[1];
                    183: 
                    184:   /* If insn is effectively movd N(sp),-(sp) then we will do the
                    185:      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
                    186:      for the low word as well, to compensate for the first decrement of sp.  */
                    187:   if (optype0 == PUSHOP
                    188:       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
                    189:       && reg_mentioned_p (XEXP (XEXP (operands[0], 0), 0), operands[1]))
                    190:     operands[1] = latehalf[1];
                    191: 
                    192:   /* If one or both operands autodecrementing,
                    193:      do the two words, high-numbered first.  */
                    194: 
                    195:   /* Likewise,  the first move would clobber the source of the second one,
                    196:      do them in the other order.  This happens only for registers;
                    197:      such overlap can't happen in memory unless the user explicitly
                    198:      sets it up, and that is an undefined circumstance.  */
                    199: 
                    200:   if (optype0 == PUSHOP || optype1 == PUSHOP
                    201:       || (optype0 == REGOP && optype1 == REGOP
                    202:          && REGNO (operands[0]) == REGNO (latehalf[1])))
                    203:     {
                    204:       /* Make any unoffsetable addresses point at high-numbered word.  */
                    205:       if (addreg0)
                    206:        output_asm_insn ("addql %#4,%0", &addreg0);
                    207:       if (addreg1)
                    208:        output_asm_insn ("addql %#4,%0", &addreg1);
                    209: 
                    210:       /* Do that word.  */
                    211:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    212: 
                    213:       /* Undo the adds we just did.  */
                    214:       if (addreg0)
                    215:        output_asm_insn ("subql %#4,%0", &addreg0);
                    216:       if (addreg1)
                    217:        output_asm_insn ("subql %#4,%0", &addreg1);
                    218: 
                    219:       /* Do low-numbered word.  */
                    220:       return singlemove_string (operands);
                    221:     }
                    222: 
                    223:   /* Normal case: do the two words, low-numbered first.  */
                    224: 
                    225:   output_asm_insn (singlemove_string (operands), operands);
                    226: 
                    227:   /* Make any unoffsetable addresses point at high-numbered word.  */
                    228:   if (addreg0)
                    229:     output_asm_insn ("addql %#4,%0", &addreg0);
                    230:   if (addreg1)
                    231:     output_asm_insn ("addql %#4,%0", &addreg1);
                    232: 
                    233:   /* Do that word.  */
                    234:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    235: 
                    236:   /* Undo the adds we just did.  */
                    237:   if (addreg0)
                    238:     output_asm_insn ("subql %#4,%0", &addreg0);
                    239:   if (addreg1)
                    240:     output_asm_insn ("subql %#4,%0", &addreg1);
                    241: 
                    242:   return "";
                    243: }
                    244: 
                    245: /* Return a REG that occurs in ADDR with coefficient 1.
                    246:    ADDR can be effectively incremented by incrementing REG.  */
                    247: 
                    248: static rtx
                    249: find_addr_reg (addr)
                    250:      rtx addr;
                    251: {
                    252:   while (GET_CODE (addr) == PLUS)
                    253:     {
                    254:       if (GET_CODE (XEXP (addr, 0)) == REG)
                    255:        addr = XEXP (addr, 0);
                    256:       if (GET_CODE (XEXP (addr, 1)) == REG)
                    257:        addr = XEXP (addr, 1);
                    258:       if (CONSTANT_P (XEXP (addr, 0)))
                    259:        addr = XEXP (addr, 1);
                    260:       if (CONSTANT_P (XEXP (addr, 1)))
                    261:        addr = XEXP (addr, 0);
                    262:     }
                    263:   if (GET_CODE (addr) == REG)
                    264:     return addr;
                    265:   return 0;
                    266: }
                    267: 
                    268: char *
                    269: output_move_const_double (operands)
                    270:      rtx *operands;
                    271: {
                    272:   int code = standard_68881_constant_p (operands[1]);
                    273: 
                    274:   if (code != 0)
                    275:     {
                    276:       static char buf[40];
                    277: 
                    278:       sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
                    279:       return buf;
                    280:     }
                    281:   return "fmove%.d %1,%0";
                    282: }
                    283: 
                    284: char *
                    285: output_move_const_single (operands)
                    286:      rtx *operands;
                    287: {
                    288:   int code = standard_68881_constant_p (operands[1]);
                    289: 
                    290:   if (code != 0)
                    291:     {
                    292:       static char buf[40];
                    293: 
                    294:       sprintf (buf, "fmovecr %%#0x%x,%%0", code & 0xff);
                    295:       return buf;
                    296:     }
                    297:   return "fmove%.s %f1,%0";
                    298: }
                    299: 
                    300: /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
                    301:    from the "fmovecr" instruction.
                    302:    The value, anded with 0xff, gives the code to use in fmovecr
                    303:    to get the desired constant.  */
                    304: 
                    305: int
                    306: standard_68881_constant_p (x)
                    307:      rtx x;
                    308: {
                    309:   union {double d; int i[2];} u;
                    310:   register double d;
                    311:   u.i[0] = XINT (x, 0);
                    312:   u.i[1] = XINT (x, 1);
                    313:   d = u.d;
                    314: 
                    315:   if (d == 0)
                    316:     return 0x0f;
                    317:   /* Note: there are various other constants available
                    318:      but it is a nuisance to put in their values here.  */
                    319:   if (d == 1)
                    320:     return 0x32;
                    321:   if (d == 10)
                    322:     return 0x33;
                    323:   if (d == 100)
                    324:     return 0x34;
                    325:   if (d == 10000)
                    326:     return 0x35;
                    327:   if (d == 1e8)
                    328:     return 0x36;
                    329:   if (GET_MODE (x) == SFmode)
                    330:     return 0;
                    331:   if (d == 1e16)
                    332:     return 0x37;
                    333:   /* larger powers of ten in the constants ram are not used
                    334:      because they are not equal to a `double' C constant.  */
                    335:   return 0;
                    336: }

unix.superglobalmegacorp.com

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