Annotation of gcc/config/out-pyr.c, revision 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.