Annotation of gcc/config/out-pyr.c, revision 1.1.1.1

1.1       root        1: /* Subroutines for insn-output.c for Pyramid 90 Series.
                      2:    Copyright (C) 1989 Free Software Foundation, Inc.
                      3: 
                      4: This file is part of GNU CC.
                      5: 
                      6: GNU CC is free software; you can redistribute it and/or modify
                      7: it under the terms of the GNU General Public License as published by
                      8: the Free Software Foundation; either version 1, or (at your option)
                      9: any later version.
                     10: 
                     11: GNU CC is distributed in the hope that it will be useful,
                     12: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14: GNU General Public License for more details.
                     15: 
                     16: You should have received a copy of the GNU General Public License
                     17: along with GNU CC; see the file COPYING.  If not, write to
                     18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     19: 
                     20: /* Some output-actions in pyr.md need these.  */
                     21: #include <stdio.h>
                     22: extern FILE *asm_out_file;
                     23: #include "tree.h"
                     24: 
                     25: /*
                     26:  * Do FUNCTION_ARG.
                     27:  * This cannot be defined as a macro on pyramids, because Pyramid Technology's
                     28:  * C compiler dies on (several equivalent definitions of) this macro.
                     29:  * The only way around this cc bug was to make this a function.
                     30:  * While it would be possible to use a macro version for gcc, it seems
                     31:  * more reliable to have a single version of the code.
                     32:  */
                     33: void *
                     34: pyr_function_arg(cum, mode, type, named)
                     35:   CUMULATIVE_ARGS cum;
                     36:   enum machine_mode mode;
                     37:   tree type;
                     38: {
                     39:   return (void *)(FUNCTION_ARG_HELPER (cum, mode,type,named));
                     40: }
                     41: 
                     42: /* Do the hard part of PARAM_SAFE_FOR_REG_P.
                     43:  * This cannot be defined as a macro on pyramids, because Pyramid Technology's
                     44:  * C compiler dies on (several equivalent definitions of) this macro.
                     45:  * The only way around this cc bug was to make this a function.
                     46:  */
                     47: int
                     48: inner_param_safe_helper (type)
                     49:     tree type;
                     50: {
                     51:   return (INNER_PARAM_SAFE_HELPER(type));
                     52: }
                     53: 
                     54: 
                     55: /* Return 1 if OP is a non-indexed operand of mode MODE.
                     56:    This is either a register reference, a memory reference,
                     57:    or a constant.  In the case of a memory reference, the address
                     58:    is checked to make sure it isn't indexed.
                     59: 
                     60:    Register and memory references must have mode MODE in order to be valid,
                     61:    but some constants have no machine mode and are valid for any mode.
                     62: 
                     63:    If MODE is VOIDmode, OP is checked for validity for whatever mode
                     64:    it has.
                     65: 
                     66:    The main use of this function is as a predicate in match_operand
                     67:    expressions in the machine description.
                     68: 
                     69:    It is  useful to compare this with general_operand().  They should
                     70:    be identical except for one line.
                     71: 
                     72:    This function seems necessary because of the non-orthogonality of
                     73:    Pyramid insns.
                     74:    For any 2-operand insn, and any combination of operand modes,
                     75:    if indexing is valid for the isn's second operand, it is invalid
                     76:    for the first operand to be indexed. */
                     77: 
                     78: extern int volatile_ok;
                     79: 
                     80: int
                     81: nonindexed_operand(op, mode)
                     82:     register rtx op;
                     83:     enum machine_mode mode;
                     84: {
                     85:   register enum rtx_code code = GET_CODE (op);
                     86:   int mode_altering_drug = 0;
                     87: 
                     88:   if (mode == VOIDmode)
                     89:     mode = GET_MODE (op);
                     90: 
                     91:   if (CONSTANT_P (op))
                     92:     return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode)
                     93:            && LEGITIMATE_CONSTANT_P (op));
                     94: 
                     95:   /* Except for certain constants with VOIDmode, already checked for,
                     96:      OP's mode must match MODE if MODE specifies a mode.  */
                     97: 
                     98:   if (GET_MODE (op) != mode)
                     99:     return 0;
                    100: 
                    101:   while (code == SUBREG)
                    102:     {
                    103:       op = SUBREG_REG (op);
                    104:       code = GET_CODE (op);
                    105: #if 0
                    106:       /* No longer needed, since (SUBREG (MEM...))
                    107:         will load the MEM into a reload reg in the MEM's own mode.  */
                    108:       mode_altering_drug = 1;
                    109: #endif
                    110:     }
                    111:   if (code == REG)
                    112:     return 1;
                    113:   if (code == CONST_DOUBLE)
                    114:     return LEGITIMATE_CONSTANT_P (op);
                    115:   if (code == MEM)
                    116:     {
                    117:       register rtx y = XEXP (op, 0);
                    118:       if (! volatile_ok && MEM_VOLATILE_P (op))
                    119:        return 0;
                    120:     GO_IF_NONINDEXED_ADDRESS (y, win);
                    121:     }
                    122:   return 0;
                    123: 
                    124:  win:
                    125:   if (mode_altering_drug)
                    126:     return ! mode_dependent_address_p (XEXP (op, 0));
                    127:   return 1;
                    128: }
                    129: 
                    130: int
                    131: has_direct_base (op)
                    132:      rtx op;
                    133: {
                    134:   if ((GET_CODE (op) == PLUS
                    135:        && (CONSTANT_ADDRESS_P (XEXP (op, 1))
                    136:           || CONSTANT_ADDRESS_P (XEXP (op, 0))))
                    137:       || CONSTANT_ADDRESS_P (op))
                    138:     return 1;
                    139: 
                    140:   return 0;
                    141: }
                    142: 
                    143: int
                    144: has_index (op)
                    145:      rtx op;
                    146: {
                    147:   if (GET_CODE (op) == PLUS
                    148:       && (GET_CODE (XEXP (op, 0)) == MULT
                    149:          || (GET_CODE (XEXP (op, 1)) == MULT)))
                    150:     return 1;
                    151:   else
                    152:     return 0;
                    153: }
                    154: 
                    155: int swap_operands;
                    156: 
                    157: /* weird_memory_memory -- return 1 if OP1 and OP2 can be compared (or
                    158:    exchanged with xchw) with one instruction.  If the operands need to
                    159:    be swapped, set the global variable SWAP_OPERANDS.  This function
                    160:    silently assumes that both OP0 and OP1 are valid memory references.
                    161:    */
                    162: 
                    163: int
                    164: weird_memory_memory (op0, op1)
                    165:      rtx op0, op1;
                    166: {
                    167:   int ret;
                    168:   int c;
                    169:   enum rtx_code code0, code1;
                    170: 
                    171:   op0 = XEXP (op0, 0);
                    172:   op1 = XEXP (op1, 0);
                    173:   code0 = GET_CODE (op0);
                    174:   code1 = GET_CODE (op1);
                    175: 
                    176:   swap_operands = 0;
                    177: 
                    178:   if (code1 == REG)
                    179:     {
                    180:       return 1;
                    181:     }
                    182:   if (code0 == REG)
                    183:     {
                    184:       swap_operands = 1;
                    185:       return 1;
                    186:     }
                    187:   if (has_direct_base (op0) && has_direct_base (op1))
                    188:     {
                    189:       if (has_index (op1))
                    190:        {
                    191:          if (has_index (op0))
                    192:            return 0;
                    193:          swap_operands = 1;
                    194:        }
                    195: 
                    196:       return 1;
                    197:     }
                    198:   return 0;
                    199: }
                    200: 
                    201: int
                    202: signed_comparison (x, mode)
                    203:      rtx x;
                    204:      enum machine_mode mode;
                    205: {
                    206:   enum rtx_code code = GET_CODE (x);
                    207: 
                    208:   return (code == NE || code == EQ || code == GE || code == GT || code == LE
                    209:         || code == LT);
                    210: }
                    211: 
                    212: char *
                    213: output_branch (code)
                    214:      enum rtx_code code;
                    215: {
                    216:   switch (code)
                    217:     {
                    218:     case NE:  return "bne %l4";
                    219:     case EQ:  return "beq %l4";
                    220:     case GE:  return "bge %l4";
                    221:     case GT:  return "bgt %l4";
                    222:     case LE:  return "ble %l4";
                    223:     case LT:  return "blt %l4";
                    224:     }
                    225: }
                    226: 
                    227: char *
                    228: output_inv_branch (code)
                    229:      enum rtx_code code;
                    230: {
                    231:   switch (code)
                    232:     {
                    233:     case NE:  return "beq %l4";
                    234:     case EQ:  return "bne %l4";
                    235:     case GE:  return "ble %l4";
                    236:     case GT:  return "blt %l4";
                    237:     case LE:  return "bge %l4";
                    238:     case LT:  return "bgt %l4";
                    239:     }
                    240: }
                    241: 
                    242: extern rtx force_reg ();
                    243: rtx test_op0, test_op1;
                    244: 
                    245: rtx
                    246: ensure_extended (op, extop)
                    247:      rtx op;
                    248:      enum rtx_code extop;
                    249: {
                    250:   if (GET_MODE (op) == HImode || GET_MODE (op) == QImode)
                    251:     op = gen_rtx (extop, SImode, op);
                    252:   op = force_reg (SImode, op);
                    253:   return op;
                    254: }
                    255: 
                    256: /* Sign-extend or zero-extend constant X from FROM_MODE to TO_MODE.  */
                    257: 
                    258: rtx
                    259: extend_const (x, extop, from_mode, to_mode)
                    260:     rtx x;
                    261:     enum rtx_code extop;
                    262:     enum machine_mode from_mode, to_mode;
                    263: {
                    264:   int val = INTVAL (x);
                    265:   int negative = val & (1 << (GET_MODE_BITSIZE (from_mode) - 1));
                    266:   if (from_mode == to_mode)
                    267:     return x;
                    268:   if (GET_MODE_BITSIZE (from_mode) == HOST_BITS_PER_INT)
                    269:     abort ();
                    270:   if (negative && extop == SIGN_EXTEND)
                    271:     val = val | ((-1) << (GET_MODE_BITSIZE (from_mode)));
                    272:   else
                    273:     val = val & ~((-1) << (GET_MODE_BITSIZE (from_mode)));
                    274:   if (GET_MODE_BITSIZE (to_mode) == HOST_BITS_PER_INT)
                    275:     return gen_rtx (CONST_INT, VOIDmode, val);
                    276:   return gen_rtx (CONST_INT, VOIDmode,
                    277:                  val & ~((-1) << (GET_MODE_BITSIZE (to_mode))));
                    278: }
                    279: 
                    280: /* Emit rtl for a branch, as well as any delayed (integer) compare insns.
                    281:    The compare insn to perform is determined by the global variables
                    282:    test_op0 and test_op1.  */
                    283: 
                    284: void
                    285: extend_and_branch (extop)
                    286:      enum rtx_code extop;
                    287: {
                    288:   rtx op0, op1;
                    289:   enum rtx_code code0, code1;
                    290: 
                    291:   op0 = test_op0, op1 = test_op1;
                    292:   if (op0 == 0)
                    293:     return;
                    294: 
                    295:   code0 = GET_CODE (op0);
                    296:   if (op1 != 0)
                    297:     code1 = GET_CODE (op1);
                    298:   test_op0 = test_op1 = 0;
                    299: 
                    300:   if (op1 == 0)
                    301:     {
                    302:       op0 = ensure_extended (op0, extop);
                    303:       emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, op0));
                    304:     }
                    305:   else
                    306:     {
                    307:       if (CONSTANT_P (op0) && CONSTANT_P (op1))
                    308:        {
                    309:          op0 = force_reg (SImode, op0);
                    310:          op1 = force_reg (SImode, op1);
                    311:        }
                    312:       else if (extop == ZERO_EXTEND && GET_MODE (op0) == HImode)
                    313:        {
                    314:          /* Pyramids have no unsigned "cmphi" instructions.  We need to
                    315:             zero extend unsigned halfwords into temporary registers. */
                    316:          op0 = ensure_extended (op0, extop);
                    317:          op1 = ensure_extended (op1, extop);
                    318:        }
                    319:       else if (CONSTANT_P (op0))
                    320:        {
                    321:          op0 = extend_const (op0, extop, GET_MODE (op1), SImode);
                    322:          op1 = ensure_extended (op1, extop);
                    323:        }
                    324:       else if (CONSTANT_P (op1))
                    325:        {
                    326:          op1 = extend_const (op1, extop, GET_MODE (op0), SImode);
                    327:          op0 = ensure_extended (op0, extop);
                    328:        }
                    329:       else if (code0 == REG && code1 == REG)
                    330:        {
                    331:          /* I could do this case without extension, by using the virtual
                    332:             register address (but that would lose for global regs).  */
                    333:          op0 = ensure_extended (op0, extop);
                    334:          op1 = ensure_extended (op1, extop);
                    335:        }
                    336:       else if (code0 == MEM && code1 == MEM)
                    337:        {
                    338:          /* Load into a reg if the address combination can't be handled
                    339:             directly.  */
                    340:          if (! weird_memory_memory (op0, op1))
                    341:            op0 = force_reg (GET_MODE (op0), op0);
                    342:        }
                    343: 
                    344:       emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx,
                    345:                          gen_rtx (COMPARE, VOIDmode, op0, op1)));
                    346:     }
                    347: }
                    348: 
                    349: /* Return non-zero if the two single-word operations with operands[0]
                    350:    and operands[1] for the first single-word operation, and operands[2]
                    351:    and operands[3] for the second single-word operation, is possible to
                    352:    combine to a double word operation.
                    353: 
                    354:    The criterion is whether the operands are in consecutive memory cells,
                    355:    registers, etc.  */
                    356: 
                    357: int
                    358: movdi_possible (operands)
                    359:      rtx operands[];
                    360: {
                    361:   int cnst_diff0, cnst_diff1;
                    362: 
                    363:   cnst_diff0 = consecutive_operands (operands[0], operands[2]);
                    364:   if (cnst_diff0 == 0)
                    365:     return 0;
                    366: 
                    367:   cnst_diff1 = consecutive_operands (operands[1], operands[3]);
                    368:   if (cnst_diff0 & cnst_diff1)
                    369:     {
                    370:       if (cnst_diff0 & 1)
                    371:        swap_operands = 0;
                    372:       else
                    373:        swap_operands = 1;
                    374:       return 1;
                    375:     }
                    376:   return 0;
                    377: }
                    378: 
                    379: /* Return +1 of OP0 is a consecutive operand to OP1, -1 if OP1 is a
                    380:    consecutive operand to OP0.
                    381: 
                    382:    This function is used to determine if addresses are consecutive,
                    383:    and therefore possible to combine to fewer instructions.  */
                    384: 
                    385: int
                    386: consecutive_operands (op0, op1)
                    387:      rtx op0, op1;
                    388: {
                    389:   enum rtx_code code0, code1;
                    390:   int cnst_diff;
                    391: 
                    392:   code0 = GET_CODE (op0);
                    393:   code1 = GET_CODE (op1);
                    394: 
                    395:   if (CONSTANT_P (op0) && CONSTANT_P (op1))
                    396:     {
                    397:       if (op0 == const0_rtx)
                    398:        if (op1 == const0_rtx)
                    399:          return 3;
                    400:        else
                    401:          return 2;
                    402:       if (op1 == const0_rtx)
                    403:        return 1;
                    404:     }
                    405: 
                    406:   if (code0 != code1)
                    407:     return 0;
                    408: 
                    409:   if (code0 == REG)
                    410:     {
                    411:       cnst_diff = REGNO (op0) - REGNO (op1);
                    412:       if (cnst_diff == 1)
                    413:        return 1;
                    414:       else if (cnst_diff == -1)
                    415:        return 2;
                    416:     }
                    417:   else if (code0 == MEM)
                    418:     {
                    419:       cnst_diff = radr_diff (XEXP (op0, 0), XEXP (op1, 0));
                    420:       if (cnst_diff)
                    421:        if (cnst_diff == 4)
                    422:          return 1;
                    423:        else if (cnst_diff == -4)
                    424:          return 2;
                    425:     }
                    426:   return 0;
                    427: }
                    428: 
                    429: /* Return the constant difference of the rtx expressions OP0 and OP1,
                    430:    or 0 if the y don't have a constant difference.
                    431: 
                    432:    This function is used to determine if addresses are consecutive,
                    433:    and therefore possible to combine to fewer instructions.  */
                    434: 
                    435: int
                    436: radr_diff (op0, op1)
                    437:      rtx op0, op1;
                    438: {
                    439:   enum rtx_code code0, code1;
                    440:   int cnst_diff;
                    441: 
                    442:   code0 = GET_CODE (op0);
                    443:   code1 = GET_CODE (op1);
                    444: 
                    445:   if (code0 != code1)
                    446:     {
                    447:       if (code0 == PLUS)
                    448:        {
                    449:          if (GET_CODE (XEXP (op0, 1)) == CONST_INT
                    450:              && rtx_equal_p (op1, XEXP (op0, 0)))
                    451:            return INTVAL (XEXP (op0, 1));
                    452:        }
                    453:       else if (code1 == PLUS)
                    454:        {
                    455:          if (GET_CODE (XEXP (op1, 1)) == CONST_INT
                    456:              && rtx_equal_p (op0, XEXP (op1, 0)))
                    457:            return -INTVAL (XEXP (op1, 1));
                    458:        }
                    459:       return 0;
                    460:     }
                    461: 
                    462:   if (code0 == CONST_INT)
                    463:     return INTVAL (op0) - INTVAL (op1);
                    464: 
                    465:   if (code0 == PLUS)
                    466:     {
                    467:       cnst_diff = radr_diff (XEXP (op0, 0), XEXP (op1, 0));
                    468:       if (cnst_diff)
                    469:        return (rtx_equal_p (XEXP (op0, 1), XEXP (op1, 1)))
                    470:          ? cnst_diff : 0;
                    471:       cnst_diff = radr_diff (XEXP (op0, 1), XEXP (op1, 1));
                    472:       if (cnst_diff)
                    473:        return (rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0)))
                    474:          ? cnst_diff : 0;
                    475:     }
                    476: 
                    477:   return 0;
                    478: }
                    479: 
                    480: int
                    481: already_sign_extended (insn, from_mode, op)
                    482:      rtx insn;
                    483:      enum machine_mode from_mode;
                    484:      rtx op;
                    485: {
                    486:   rtx xinsn;
                    487: 
                    488:   return 0;
                    489: 
                    490: #if 0
                    491:   for (;;)
                    492:     {
                    493:       insn = PREV_INSN (insn);
                    494:       if (insn == 0)
                    495:        return 0;
                    496:       if (GET_CODE (insn) == NOTE)
                    497:        continue;
                    498:       if (GET_CODE (insn) != INSN)
                    499:        return 0;
                    500:       xinsn = PATTERN (insn);
                    501: 
                    502:       if (GET_CODE (xinsn) != SET)
                    503:        return 0;
                    504: 
                    505:       /* Is it another register that is set in this insn?  */
                    506:       if (GET_CODE (SET_DEST (xinsn)) != REG
                    507:          || REGNO (SET_DEST (xinsn)) != REGNO (op))
                    508:        continue;
                    509: 
                    510:       if (GET_CODE (SET_SRC (xinsn)) == SIGN_EXTEND
                    511:          || (GET_CODE (SET_SRC (xinsn)) == MEM
                    512:              && GET_MODE (SET_SRC (xinsn)) == from_mode))
                    513:        return 1;
                    514: 
                    515:       /* Is the register modified by another operation?  */
                    516:       if (REGNO (SET_DEST (xinsn)) == REGNO (op))
                    517:        return 0;
                    518:     }
                    519: #endif
                    520: }
                    521: 
                    522: char *
                    523: output_move_double (operands)
                    524:      rtx *operands;
                    525: {
                    526:   CC_STATUS_INIT;
                    527:   if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    528:     {
                    529:       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT)
                    530:        {
                    531:          /* In an integer, the low-order word is in CONST_DOUBLE_LOW.  */
                    532:          rtx const_op = operands[1];
                    533:          if (CONST_DOUBLE_HIGH (const_op) == 0)
                    534:            {
                    535:              operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    536:                                     CONST_DOUBLE_LOW (const_op));
                    537:              return "movl %1,%0";
                    538:            }
                    539:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    540:                                 CONST_DOUBLE_HIGH (const_op));
                    541:          output_asm_insn ("movw %1,%0", operands);
                    542:          operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    543:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    544:                                 CONST_DOUBLE_LOW (const_op));
                    545:          return "movw %1,%0";
                    546:        }
                    547:       else
                    548:        {
                    549:          /* In a real, the low-address word is in CONST_DOUBLE_LOW.  */
                    550:          rtx const_op = operands[1];
                    551:          if (CONST_DOUBLE_LOW (const_op) == 0)
                    552:            {
                    553:              operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    554:                                     CONST_DOUBLE_HIGH (const_op));
                    555:              return "movl %1,%0";
                    556:            }
                    557:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    558:                                 CONST_DOUBLE_LOW (const_op));
                    559:          output_asm_insn ("movw %1,%0", operands);
                    560:          operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    561:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    562:                                 CONST_DOUBLE_HIGH (const_op));
                    563:          return "movw %1,%0";
                    564:        }
                    565:     }
                    566: 
                    567:   return "movl %1,%0";
                    568: }
                    569: 
                    570: /* Return non-zero if the code of this rtx pattern is a relop.  */
                    571: int
                    572: relop (op, mode)
                    573:      rtx op;
                    574:      enum machine_mode mode;
                    575: {
                    576:   switch (GET_CODE (op))
                    577:     {
                    578:     case EQ:
                    579:     case NE:
                    580:     case LT:
                    581:     case LE:
                    582:     case GE:
                    583:     case GT:
                    584:     case LTU:
                    585:     case LEU:
                    586:     case GEU:
                    587:     case GTU:
                    588:       return 1;
                    589:     }
                    590:   return 0;
                    591: }

unix.superglobalmegacorp.com

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