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

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>
1.1.1.2 ! root       22: 
1.1       root       23: extern FILE *asm_out_file;
                     24: #include "tree.h"
                     25: 
                     26: /*
                     27:  * Do FUNCTION_ARG.
                     28:  * This cannot be defined as a macro on pyramids, because Pyramid Technology's
                     29:  * C compiler dies on (several equivalent definitions of) this macro.
                     30:  * The only way around this cc bug was to make this a function.
                     31:  * While it would be possible to use a macro version for gcc, it seems
                     32:  * more reliable to have a single version of the code.
                     33:  */
                     34: void *
                     35: pyr_function_arg(cum, mode, type, named)
                     36:   CUMULATIVE_ARGS cum;
                     37:   enum machine_mode mode;
                     38:   tree type;
                     39: {
                     40:   return (void *)(FUNCTION_ARG_HELPER (cum, mode,type,named));
                     41: }
                     42: 
                     43: /* Do the hard part of PARAM_SAFE_FOR_REG_P.
                     44:  * This cannot be defined as a macro on pyramids, because Pyramid Technology's
                     45:  * C compiler dies on (several equivalent definitions of) this macro.
                     46:  * The only way around this cc bug was to make this a function.
                     47:  */
                     48: int
                     49: inner_param_safe_helper (type)
                     50:     tree type;
                     51: {
                     52:   return (INNER_PARAM_SAFE_HELPER(type));
                     53: }
                     54: 
                     55: 
                     56: /* Return 1 if OP is a non-indexed operand of mode MODE.
                     57:    This is either a register reference, a memory reference,
                     58:    or a constant.  In the case of a memory reference, the address
                     59:    is checked to make sure it isn't indexed.
                     60: 
                     61:    Register and memory references must have mode MODE in order to be valid,
                     62:    but some constants have no machine mode and are valid for any mode.
                     63: 
                     64:    If MODE is VOIDmode, OP is checked for validity for whatever mode
                     65:    it has.
                     66: 
                     67:    The main use of this function is as a predicate in match_operand
                     68:    expressions in the machine description.
                     69: 
                     70:    It is  useful to compare this with general_operand().  They should
                     71:    be identical except for one line.
                     72: 
                     73:    This function seems necessary because of the non-orthogonality of
                     74:    Pyramid insns.
                     75:    For any 2-operand insn, and any combination of operand modes,
                     76:    if indexing is valid for the isn's second operand, it is invalid
                     77:    for the first operand to be indexed. */
                     78: 
                     79: extern int volatile_ok;
                     80: 
                     81: int
                     82: nonindexed_operand(op, mode)
                     83:     register rtx op;
                     84:     enum machine_mode mode;
                     85: {
1.1.1.2 ! root       86:   register RTX_CODE code = GET_CODE (op);
1.1       root       87:   int mode_altering_drug = 0;
                     88: 
                     89:   if (mode == VOIDmode)
                     90:     mode = GET_MODE (op);
                     91: 
                     92:   if (CONSTANT_P (op))
                     93:     return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode)
                     94:            && LEGITIMATE_CONSTANT_P (op));
                     95: 
                     96:   /* Except for certain constants with VOIDmode, already checked for,
                     97:      OP's mode must match MODE if MODE specifies a mode.  */
                     98: 
                     99:   if (GET_MODE (op) != mode)
                    100:     return 0;
                    101: 
                    102:   while (code == SUBREG)
                    103:     {
                    104:       op = SUBREG_REG (op);
                    105:       code = GET_CODE (op);
                    106: #if 0
                    107:       /* No longer needed, since (SUBREG (MEM...))
                    108:         will load the MEM into a reload reg in the MEM's own mode.  */
                    109:       mode_altering_drug = 1;
                    110: #endif
                    111:     }
                    112:   if (code == REG)
                    113:     return 1;
                    114:   if (code == CONST_DOUBLE)
                    115:     return LEGITIMATE_CONSTANT_P (op);
                    116:   if (code == MEM)
                    117:     {
                    118:       register rtx y = XEXP (op, 0);
                    119:       if (! volatile_ok && MEM_VOLATILE_P (op))
                    120:        return 0;
                    121:     GO_IF_NONINDEXED_ADDRESS (y, win);
                    122:     }
                    123:   return 0;
                    124: 
                    125:  win:
                    126:   if (mode_altering_drug)
                    127:     return ! mode_dependent_address_p (XEXP (op, 0));
                    128:   return 1;
                    129: }
                    130: 
1.1.1.2 ! root      131: /* Return non-zero if the rtx OP has an immediate component.  An
        !           132:    immediate component or additive term equal to zero is rejected
        !           133:    due to assembler problems.  */
        !           134: 
1.1       root      135: int
                    136: has_direct_base (op)
                    137:      rtx op;
                    138: {
1.1.1.2 ! root      139:   if ((CONSTANT_ADDRESS_P (op)
        !           140:        && op != const0_rtx)
        !           141:       || (GET_CODE (op) == PLUS
        !           142:          && ((CONSTANT_ADDRESS_P (XEXP (op, 1))
        !           143:               && XEXP (op, 1) != const0_rtx)
        !           144:              || (CONSTANT_ADDRESS_P (XEXP (op, 0))
        !           145:                  && XEXP (op, 0) != const0_rtx))))
1.1       root      146:     return 1;
                    147: 
                    148:   return 0;
                    149: }
                    150: 
                    151: int
                    152: has_index (op)
                    153:      rtx op;
                    154: {
                    155:   if (GET_CODE (op) == PLUS
                    156:       && (GET_CODE (XEXP (op, 0)) == MULT
                    157:          || (GET_CODE (XEXP (op, 1)) == MULT)))
                    158:     return 1;
                    159:   else
                    160:     return 0;
                    161: }
                    162: 
                    163: int swap_operands;
                    164: 
                    165: /* weird_memory_memory -- return 1 if OP1 and OP2 can be compared (or
                    166:    exchanged with xchw) with one instruction.  If the operands need to
                    167:    be swapped, set the global variable SWAP_OPERANDS.  This function
                    168:    silently assumes that both OP0 and OP1 are valid memory references.
                    169:    */
                    170: 
                    171: int
                    172: weird_memory_memory (op0, op1)
                    173:      rtx op0, op1;
                    174: {
                    175:   int ret;
                    176:   int c;
1.1.1.2 ! root      177:   RTX_CODE code0, code1;
1.1       root      178: 
                    179:   op0 = XEXP (op0, 0);
                    180:   op1 = XEXP (op1, 0);
                    181:   code0 = GET_CODE (op0);
                    182:   code1 = GET_CODE (op1);
                    183: 
                    184:   swap_operands = 0;
                    185: 
1.1.1.2 ! root      186:   if (code1 == REG || code1 == SUBREG)
1.1       root      187:     {
                    188:       return 1;
                    189:     }
1.1.1.2 ! root      190:   if (code0 == REG || code0 == SUBREG)
1.1       root      191:     {
                    192:       swap_operands = 1;
                    193:       return 1;
                    194:     }
                    195:   if (has_direct_base (op0) && has_direct_base (op1))
                    196:     {
                    197:       if (has_index (op1))
                    198:        {
                    199:          if (has_index (op0))
                    200:            return 0;
                    201:          swap_operands = 1;
                    202:        }
                    203: 
                    204:       return 1;
                    205:     }
                    206:   return 0;
                    207: }
                    208: 
                    209: int
                    210: signed_comparison (x, mode)
                    211:      rtx x;
                    212:      enum machine_mode mode;
                    213: {
1.1.1.2 ! root      214:   return ! TRULY_UNSIGNED_COMPARE_P (GET_CODE (x));
1.1       root      215: }
                    216: 
                    217: extern rtx force_reg ();
                    218: rtx test_op0, test_op1;
1.1.1.2 ! root      219: enum machine_mode test_mode;
1.1       root      220: 
                    221: /* Sign-extend or zero-extend constant X from FROM_MODE to TO_MODE.  */
                    222: 
                    223: rtx
                    224: extend_const (x, extop, from_mode, to_mode)
                    225:     rtx x;
1.1.1.2 ! root      226:     RTX_CODE extop;
1.1       root      227:     enum machine_mode from_mode, to_mode;
                    228: {
1.1.1.2 ! root      229:   int val;
        !           230:   int negative;
1.1       root      231:   if (from_mode == to_mode)
                    232:     return x;
1.1.1.2 ! root      233:   if (GET_CODE (x) != CONST_INT)
        !           234:     abort ();
        !           235:   val = INTVAL (x);
        !           236:   negative = val & (1 << (GET_MODE_BITSIZE (from_mode) - 1));
1.1       root      237:   if (GET_MODE_BITSIZE (from_mode) == HOST_BITS_PER_INT)
                    238:     abort ();
                    239:   if (negative && extop == SIGN_EXTEND)
                    240:     val = val | ((-1) << (GET_MODE_BITSIZE (from_mode)));
                    241:   else
                    242:     val = val & ~((-1) << (GET_MODE_BITSIZE (from_mode)));
                    243:   if (GET_MODE_BITSIZE (to_mode) == HOST_BITS_PER_INT)
                    244:     return gen_rtx (CONST_INT, VOIDmode, val);
                    245:   return gen_rtx (CONST_INT, VOIDmode,
                    246:                  val & ~((-1) << (GET_MODE_BITSIZE (to_mode))));
                    247: }
                    248: 
1.1.1.2 ! root      249: rtx
        !           250: ensure_extended (op, extop, from_mode)
        !           251:      rtx op;
        !           252:      RTX_CODE extop;
        !           253:      enum machine_mode from_mode;
        !           254: {
        !           255:   if (GET_CODE (op) == CONST_INT)
        !           256:     return extend_const (op, extop, from_mode, SImode);
        !           257:   else
        !           258:     return force_reg (SImode, gen_rtx (extop, SImode, op));
        !           259: }
        !           260: 
1.1       root      261: /* Emit rtl for a branch, as well as any delayed (integer) compare insns.
                    262:    The compare insn to perform is determined by the global variables
                    263:    test_op0 and test_op1.  */
                    264: 
                    265: void
                    266: extend_and_branch (extop)
1.1.1.2 ! root      267:      RTX_CODE extop;
1.1       root      268: {
                    269:   rtx op0, op1;
1.1.1.2 ! root      270:   RTX_CODE code0, code1;
1.1       root      271: 
                    272:   op0 = test_op0, op1 = test_op1;
                    273:   if (op0 == 0)
                    274:     return;
                    275: 
                    276:   code0 = GET_CODE (op0);
                    277:   if (op1 != 0)
                    278:     code1 = GET_CODE (op1);
                    279:   test_op0 = test_op1 = 0;
                    280: 
                    281:   if (op1 == 0)
                    282:     {
1.1.1.2 ! root      283:       op0 = ensure_extended (op0, extop, test_mode);
1.1       root      284:       emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, op0));
                    285:     }
                    286:   else
                    287:     {
                    288:       if (CONSTANT_P (op0) && CONSTANT_P (op1))
                    289:        {
1.1.1.2 ! root      290:          op0 = ensure_extended (op0, extop, test_mode);
        !           291:          op1 = ensure_extended (op1, extop, test_mode);
1.1       root      292:        }
1.1.1.2 ! root      293:       else if (extop == ZERO_EXTEND && test_mode == HImode)
1.1       root      294:        {
                    295:          /* Pyramids have no unsigned "cmphi" instructions.  We need to
                    296:             zero extend unsigned halfwords into temporary registers. */
1.1.1.2 ! root      297:          op0 = ensure_extended (op0, extop, test_mode);
        !           298:          op1 = ensure_extended (op1, extop, test_mode);
1.1       root      299:        }
                    300:       else if (CONSTANT_P (op0))
                    301:        {
1.1.1.2 ! root      302:          op0 = ensure_extended (op0, extop, test_mode);
        !           303:          op1 = ensure_extended (op1, extop, test_mode);
1.1       root      304:        }
                    305:       else if (CONSTANT_P (op1))
                    306:        {
1.1.1.2 ! root      307:          op1 = ensure_extended (op1, extop, test_mode);
        !           308:          op0 = ensure_extended (op0, extop, test_mode);
1.1       root      309:        }
1.1.1.2 ! root      310:       else if ((code0 == REG || code0 == SUBREG)
        !           311:               && (code1 == REG || code1 == SUBREG))
1.1       root      312:        {
                    313:          /* I could do this case without extension, by using the virtual
                    314:             register address (but that would lose for global regs).  */
1.1.1.2 ! root      315:          op0 = ensure_extended (op0, extop, test_mode);
        !           316:          op1 = ensure_extended (op1, extop, test_mode);
1.1       root      317:        }
                    318:       else if (code0 == MEM && code1 == MEM)
                    319:        {
                    320:          /* Load into a reg if the address combination can't be handled
                    321:             directly.  */
                    322:          if (! weird_memory_memory (op0, op1))
1.1.1.2 ! root      323:            op0 = force_reg (test_mode, op0);
1.1       root      324:        }
                    325: 
                    326:       emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx,
                    327:                          gen_rtx (COMPARE, VOIDmode, op0, op1)));
                    328:     }
                    329: }
                    330: 
1.1.1.2 ! root      331: /* Return non-zero if the two single-word moves with operands[0]
        !           332:    and operands[1] for the first single-word move, and operands[2]
        !           333:    and operands[3] for the second single-word move, is possible to
        !           334:    combine to a double word move.
1.1       root      335: 
                    336:    The criterion is whether the operands are in consecutive memory cells,
                    337:    registers, etc.  */
                    338: 
                    339: int
                    340: movdi_possible (operands)
                    341:      rtx operands[];
                    342: {
                    343:   int cnst_diff0, cnst_diff1;
1.1.1.2 ! root      344:   RTX_CODE code0 = GET_CODE (operands[0]);
        !           345:   RTX_CODE code1 = GET_CODE (operands[1]);
        !           346: 
        !           347:   /* Don't dare to combine (possibly overlapping) memory -> memory moves.  */
        !           348:   /* It would be possible to detect the cases where we dare, by using
        !           349:      constant_diff (operands[0], operands[1])!!!  */
        !           350:   if (code0 == MEM && code1 == MEM)
        !           351:     return 0;
1.1       root      352: 
                    353:   cnst_diff0 = consecutive_operands (operands[0], operands[2]);
                    354:   if (cnst_diff0 == 0)
                    355:     return 0;
                    356: 
                    357:   cnst_diff1 = consecutive_operands (operands[1], operands[3]);
1.1.1.2 ! root      358:   if (cnst_diff1 == 0)
        !           359:     return 0;
        !           360: 
1.1       root      361:   if (cnst_diff0 & cnst_diff1)
                    362:     {
1.1.1.2 ! root      363:       /* The source and destination operands are consecutive.  */
        !           364: 
        !           365:       /* If the first move writes into the source of the second move,
        !           366:         we cannot combine.  */
        !           367:       if ((code0 == REG
        !           368:           && reg_overlap_mentioned_p (operands[0], operands[3]))
        !           369:          || (code0 == SUBREG
        !           370:              && subreg_overlap_mentioned_p (operands[0], operands[3])))
        !           371:          return 0;
        !           372: 
1.1       root      373:       if (cnst_diff0 & 1)
1.1.1.2 ! root      374:        /* operands[0],[1] has higher addresses than operands[2],[3].  */
1.1       root      375:        swap_operands = 0;
                    376:       else
1.1.1.2 ! root      377:        /* operands[0],[1] has lower addresses than operands[2],[3].  */
1.1       root      378:        swap_operands = 1;
                    379:       return 1;
                    380:     }
                    381:   return 0;
                    382: }
                    383: 
1.1.1.2 ! root      384: /* Like reg_overlap_mentioned_p, but accepts a subreg rtx instead
        !           385:    of a reg.  */
        !           386: 
        !           387: int
        !           388: subreg_overlap_mentioned_p (subreg, x)
        !           389:      rtx subreg, x;
        !           390: {
        !           391:   rtx reg = SUBREG_REG (subreg);
        !           392:   int regno = REGNO (reg) + SUBREG_WORD (subreg);
        !           393:   int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (subreg));
        !           394:   return refers_to_regno_p (regno, endregno, x, 0);
        !           395: }
        !           396: 
        !           397: /* Return 1 if OP0 is a consecutive operand to OP1, 2 if OP1 is a
1.1       root      398:    consecutive operand to OP0.
                    399: 
                    400:    This function is used to determine if addresses are consecutive,
                    401:    and therefore possible to combine to fewer instructions.  */
                    402: 
                    403: int
                    404: consecutive_operands (op0, op1)
                    405:      rtx op0, op1;
                    406: {
1.1.1.2 ! root      407:   RTX_CODE code0, code1;
1.1       root      408:   int cnst_diff;
1.1.1.2 ! root      409:   int regno_off0, regno_off1;
1.1       root      410: 
                    411:   code0 = GET_CODE (op0);
                    412:   code1 = GET_CODE (op1);
                    413: 
1.1.1.2 ! root      414:   regno_off0 = 0;
        !           415:   if (code0 == SUBREG)
1.1       root      416:     {
1.1.1.2 ! root      417:       if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))) <= UNITS_PER_WORD)
        !           418:        return 0;
        !           419:       regno_off0 = SUBREG_WORD (op0);
        !           420:       op0 = SUBREG_REG (op0);
        !           421:       code0 = REG;
        !           422:     }
        !           423: 
        !           424:   regno_off1 = 0;
        !           425:   if (code1 == SUBREG)
        !           426:     {
        !           427:       if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))) <= UNITS_PER_WORD)
        !           428:        return 0;
        !           429:       regno_off1 = SUBREG_WORD (op1);
        !           430:       op1 = SUBREG_REG (op1);
        !           431:       code1 = REG;
1.1       root      432:     }
                    433: 
                    434:   if (code0 != code1)
                    435:     return 0;
                    436: 
1.1.1.2 ! root      437:   switch (code0)
1.1       root      438:     {
1.1.1.2 ! root      439:     case CONST_INT:
        !           440:       /* Cannot permit any symbolic constants, even if the consecutive
        !           441:         operand is 0, since a movl really performs sign extension.  */
        !           442:       if (code1 != CONST_INT)
        !           443:        return 0;
        !           444:       if ((INTVAL (op0) == 0 && INTVAL (op1) == 0)
        !           445:          || (INTVAL (op0) == -1 && INTVAL (op1) == -1))
        !           446:        return 3;
        !           447:       if ((INTVAL (op0) == 0 && INTVAL (op1) > 0)
        !           448:          || (INTVAL (op0) == -1 && INTVAL (op1) < 0))
        !           449:        return 2;
        !           450:       if ((INTVAL (op1) == 0 && INTVAL (op0) > 0)
        !           451:          || (INTVAL (op1) == -1 && INTVAL (op0) < 0))
1.1       root      452:        return 1;
1.1.1.2 ! root      453:       break;
        !           454: 
        !           455:     case REG:
        !           456:       regno_off0 = REGNO (op0) + regno_off0;
        !           457:       regno_off1 = REGNO (op1) + regno_off1;
        !           458: 
        !           459:       cnst_diff = regno_off0 - regno_off1;
        !           460:       if (cnst_diff == 1)
        !           461:        {
        !           462:          /* movl with the highest numbered parameter (local) register as
        !           463:             source or destination, doesn't wrap to the lowest numbered local
        !           464:             (temporary) register.  */
        !           465: 
        !           466:          if (regno_off0 % 16 != 0)
        !           467:            return 1;
        !           468:          else
        !           469:            return 0;
        !           470:        }
1.1       root      471:       else if (cnst_diff == -1)
1.1.1.2 ! root      472:        {
        !           473:          if (regno_off1 % 16 != 0)
        !           474:            return 2;
        !           475:          else
        !           476:            return 0;
        !           477:        }
        !           478:       break;
        !           479: 
        !           480:     case MEM:
        !           481:       op0 = XEXP (op0, 0);
        !           482:       op1 = XEXP (op1, 0);
        !           483:       if (GET_CODE (op0) == CONST)
        !           484:        op0 = XEXP (op0, 0);
        !           485:       if (GET_CODE (op1) == CONST)
        !           486:        op1 = XEXP (op1, 0);
        !           487: 
        !           488:       cnst_diff = constant_diff (op0, op1);
1.1       root      489:       if (cnst_diff)
1.1.1.2 ! root      490:        {
        !           491:          if (cnst_diff == 4)
        !           492:            return 1;
        !           493:          else if (cnst_diff == -4)
        !           494:            return 2;
        !           495:        }
        !           496:       break;
1.1       root      497:     }
                    498:   return 0;
                    499: }
                    500: 
                    501: /* Return the constant difference of the rtx expressions OP0 and OP1,
1.1.1.2 ! root      502:    or 0 if they don't have a constant difference.
1.1       root      503: 
                    504:    This function is used to determine if addresses are consecutive,
                    505:    and therefore possible to combine to fewer instructions.  */
                    506: 
                    507: int
1.1.1.2 ! root      508: constant_diff (op0, op1)
1.1       root      509:      rtx op0, op1;
                    510: {
1.1.1.2 ! root      511:   RTX_CODE code0, code1;
1.1       root      512:   int cnst_diff;
                    513: 
                    514:   code0 = GET_CODE (op0);
                    515:   code1 = GET_CODE (op1);
                    516: 
                    517:   if (code0 != code1)
                    518:     {
                    519:       if (code0 == PLUS)
                    520:        {
                    521:          if (GET_CODE (XEXP (op0, 1)) == CONST_INT
                    522:              && rtx_equal_p (op1, XEXP (op0, 0)))
                    523:            return INTVAL (XEXP (op0, 1));
                    524:        }
                    525:       else if (code1 == PLUS)
                    526:        {
                    527:          if (GET_CODE (XEXP (op1, 1)) == CONST_INT
                    528:              && rtx_equal_p (op0, XEXP (op1, 0)))
                    529:            return -INTVAL (XEXP (op1, 1));
                    530:        }
                    531:       return 0;
                    532:     }
                    533: 
                    534:   if (code0 == CONST_INT)
                    535:     return INTVAL (op0) - INTVAL (op1);
                    536: 
                    537:   if (code0 == PLUS)
                    538:     {
1.1.1.2 ! root      539:       cnst_diff = constant_diff (XEXP (op0, 0), XEXP (op1, 0));
1.1       root      540:       if (cnst_diff)
                    541:        return (rtx_equal_p (XEXP (op0, 1), XEXP (op1, 1)))
                    542:          ? cnst_diff : 0;
1.1.1.2 ! root      543:       cnst_diff = constant_diff (XEXP (op0, 1), XEXP (op1, 1));
1.1       root      544:       if (cnst_diff)
                    545:        return (rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0)))
                    546:          ? cnst_diff : 0;
                    547:     }
                    548: 
                    549:   return 0;
                    550: }
                    551: 
                    552: int
                    553: already_sign_extended (insn, from_mode, op)
                    554:      rtx insn;
                    555:      enum machine_mode from_mode;
                    556:      rtx op;
                    557: {
1.1.1.2 ! root      558:   rtx xinsn, xdest, xsrc;
1.1       root      559: 
                    560:   for (;;)
                    561:     {
                    562:       insn = PREV_INSN (insn);
                    563:       if (insn == 0)
                    564:        return 0;
1.1.1.2 ! root      565:       if (GET_CODE (insn) == NOTE || GET_CODE (insn) == JUMP_INSN)
        !           566:        continue;
        !           567:       if (GET_CODE (insn) == CALL_INSN && ! call_used_regs[REGNO (op)])
1.1       root      568:        continue;
                    569:       if (GET_CODE (insn) != INSN)
                    570:        return 0;
                    571:       xinsn = PATTERN (insn);
                    572: 
                    573:       if (GET_CODE (xinsn) != SET)
                    574:        return 0;
                    575: 
1.1.1.2 ! root      576:       xdest = SET_DEST (xinsn);
        !           577:       xsrc = SET_SRC (xinsn);
        !           578: 
        !           579:       if (GET_CODE (xdest) == SUBREG)
        !           580:        abort ();
        !           581: 
        !           582:       if ( ! REG_P (xdest))
1.1       root      583:        continue;
                    584: 
1.1.1.2 ! root      585:       if (REGNO (op) == REGNO (xdest)
        !           586:          && ((GET_CODE (xsrc) == SIGN_EXTEND
        !           587:           && GET_MODE (XEXP (xsrc, 0)) == from_mode)
        !           588:          || (GET_CODE (xsrc) == MEM
        !           589:              && GET_MODE (xsrc) == from_mode)))
1.1       root      590:        return 1;
                    591: 
1.1.1.2 ! root      592:       /* The register is modified by another operation.  */
        !           593:       if (reg_overlap_mentioned_p (xdest, op))
1.1       root      594:        return 0;
                    595:     }
                    596: }
                    597: 
                    598: char *
                    599: output_move_double (operands)
                    600:      rtx *operands;
                    601: {
                    602:   if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    603:     {
                    604:       if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT)
                    605:        {
                    606:          /* In an integer, the low-order word is in CONST_DOUBLE_LOW.  */
                    607:          rtx const_op = operands[1];
1.1.1.2 ! root      608:          if ((CONST_DOUBLE_HIGH (const_op) == 0
        !           609:               && CONST_DOUBLE_LOW (const_op) >= 0)
        !           610:              || (CONST_DOUBLE_HIGH (const_op) == -1
        !           611:                  && CONST_DOUBLE_LOW (const_op) < 0))
1.1       root      612:            {
                    613:              operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    614:                                     CONST_DOUBLE_LOW (const_op));
                    615:              return "movl %1,%0";
                    616:            }
                    617:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    618:                                 CONST_DOUBLE_HIGH (const_op));
                    619:          output_asm_insn ("movw %1,%0", operands);
                    620:          operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    621:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    622:                                 CONST_DOUBLE_LOW (const_op));
                    623:          return "movw %1,%0";
                    624:        }
                    625:       else
                    626:        {
                    627:          /* In a real, the low-address word is in CONST_DOUBLE_LOW.  */
                    628:          rtx const_op = operands[1];
1.1.1.2 ! root      629:          if ((CONST_DOUBLE_LOW (const_op) == 0
        !           630:               && CONST_DOUBLE_HIGH (const_op) >= 0)
        !           631:              || (CONST_DOUBLE_LOW (const_op) == -1
        !           632:                  && CONST_DOUBLE_HIGH (const_op) < 0))
1.1       root      633:            {
                    634:              operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    635:                                     CONST_DOUBLE_HIGH (const_op));
                    636:              return "movl %1,%0";
                    637:            }
                    638:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    639:                                 CONST_DOUBLE_LOW (const_op));
                    640:          output_asm_insn ("movw %1,%0", operands);
                    641:          operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    642:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
                    643:                                 CONST_DOUBLE_HIGH (const_op));
                    644:          return "movw %1,%0";
                    645:        }
                    646:     }
                    647: 
                    648:   return "movl %1,%0";
                    649: }
                    650: 
1.1.1.2 ! root      651: /* Output a shift insns, after having reduced integer arguments to
        !           652:    avoid as warnings.  */
        !           653: 
        !           654: char *
        !           655: output_shift (pattern, op2, mod)
        !           656:      char *pattern;
        !           657:      rtx op2;
        !           658:      int mod;
        !           659: {
        !           660:   if (GET_CODE (op2) == CONST_INT)
        !           661:     {
        !           662:       int cnt = INTVAL (op2) % mod;
        !           663:       if (cnt == 0)
        !           664:        {
        !           665:          cc_status = cc_prev_status;
        !           666:          return "";
        !           667:        }
        !           668:       op2 = gen_rtx (CONST_INT, VOIDmode, cnt);
        !           669:     }
        !           670:   return pattern;
        !           671: }
        !           672: 
1.1       root      673: /* Return non-zero if the code of this rtx pattern is a relop.  */
1.1.1.2 ! root      674: 
1.1       root      675: int
                    676: relop (op, mode)
                    677:      rtx op;
                    678:      enum machine_mode mode;
                    679: {
                    680:   switch (GET_CODE (op))
                    681:     {
                    682:     case EQ:
                    683:     case NE:
                    684:     case LT:
                    685:     case LE:
                    686:     case GE:
                    687:     case GT:
                    688:     case LTU:
                    689:     case LEU:
                    690:     case GEU:
                    691:     case GTU:
                    692:       return 1;
                    693:     }
                    694:   return 0;
                    695: }
1.1.1.2 ! root      696: 
        !           697: void
        !           698: notice_update_cc (EXP, INSN)
        !           699:      rtx EXP, INSN;
        !           700: {
        !           701:   switch (GET_CODE (EXP))
        !           702:     {
        !           703:     case SET:
        !           704:       switch (GET_CODE (SET_DEST (EXP)))
        !           705:        {
        !           706:        case CC0:
        !           707:          cc_status.mdep = 0;
        !           708:          cc_status.flags = 0;
        !           709:          cc_status.value1 = 0;
        !           710:          cc_status.value2 = SET_SRC (EXP);
        !           711:          break;
        !           712: 
        !           713:        case PC:
        !           714:          break;
        !           715: 
        !           716:        case REG:
        !           717:          switch (GET_CODE (SET_SRC (EXP)))
        !           718:            {
        !           719:            case CALL:
        !           720:              goto call;
        !           721:            case MEM:
        !           722:              if (GET_MODE (SET_SRC (EXP)) == QImode
        !           723:                  || GET_MODE (SET_SRC (EXP)) == HImode)
        !           724:                {
        !           725:                  cc_status.mdep = 0;
        !           726:                  cc_status.flags = CC_NO_OVERFLOW;
        !           727:                  cc_status.value1 = SET_DEST (EXP);
        !           728:                  cc_status.value2 = SET_SRC (EXP);
        !           729:                  break;
        !           730:                }
        !           731:              /* else: Fall through.  */
        !           732:            case CONST_INT:
        !           733:            case SYMBOL_REF:
        !           734:            case LABEL_REF:
        !           735:            case CONST:
        !           736:            case CONST_DOUBLE:
        !           737:            case REG:
        !           738:              if (cc_status.value1
        !           739:                  && reg_overlap_mentioned_p (SET_DEST (EXP),
        !           740:                                              cc_status.value1))
        !           741:                cc_status.value1 = 0;
        !           742:              if (cc_status.value2
        !           743:                  && reg_overlap_mentioned_p (SET_DEST (EXP),
        !           744:                                              cc_status.value2))
        !           745:                cc_status.value2 = 0;
        !           746:              break;
        !           747: 
        !           748:            case UDIV:
        !           749:            case UMOD:
        !           750:              cc_status.mdep = CC_VALID_FOR_UNSIGNED;
        !           751:              cc_status.flags = CC_NO_OVERFLOW;
        !           752:              cc_status.value1 = SET_DEST (EXP);
        !           753:              cc_status.value2 = SET_SRC (EXP);
        !           754:              break;
        !           755:            default:
        !           756:              cc_status.mdep = 0;
        !           757:              cc_status.flags = CC_NO_OVERFLOW;
        !           758:              cc_status.value1 = SET_DEST (EXP);
        !           759:              cc_status.value2 = SET_SRC (EXP);
        !           760:              break;
        !           761:            }
        !           762:          break;
        !           763: 
        !           764:        case MEM:
        !           765:          switch (GET_CODE (SET_SRC (EXP)))
        !           766:            {
        !           767:            case REG:
        !           768:              if (GET_MODE (SET_SRC (EXP)) == QImode
        !           769:                  || GET_MODE (SET_SRC (EXP)) == HImode)
        !           770:                {
        !           771:                  cc_status.flags = CC_NO_OVERFLOW;
        !           772:                  cc_status.value1 = SET_DEST (EXP);
        !           773:                  cc_status.value2 = SET_SRC (EXP);
        !           774:                  cc_status.mdep = 0;
        !           775:                  break;
        !           776:                }
        !           777:              /* else: Fall through.  */
        !           778:            case CONST_INT:
        !           779:            case SYMBOL_REF:
        !           780:            case LABEL_REF:
        !           781:            case CONST:
        !           782:            case CONST_DOUBLE:
        !           783:            case MEM:
        !           784:              /* Need to forget cc_status about memory positions each
        !           785:                 time a memory store is made, even if the memory store
        !           786:                 insns in question doesn't modify the condition codes.  */
        !           787:              if (cc_status.value1 &&
        !           788:                  GET_CODE (cc_status.value1) == MEM)
        !           789:                cc_status.value1 = 0;
        !           790:              if (cc_status.value2 &&
        !           791:                  GET_CODE (cc_status.value2) == MEM)
        !           792:                cc_status.value2 = 0;
        !           793:              break;
        !           794:            case SIGN_EXTEND:
        !           795:            case FLOAT_EXTEND:
        !           796:            case FLOAT_TRUNCATE:
        !           797:            case FLOAT:
        !           798:            case FIX:
        !           799:              cc_status.flags = CC_NO_OVERFLOW;
        !           800:              cc_status.value1 = SET_DEST (EXP);
        !           801:              cc_status.value2 = SET_SRC (EXP);
        !           802:              cc_status.mdep = 0;
        !           803:              break;
        !           804: 
        !           805:            default:
        !           806:              abort ();
        !           807:            }
        !           808:          break;
        !           809: 
        !           810:        default:
        !           811:          abort ();
        !           812:        }
        !           813:       break;
        !           814: 
        !           815:     case CALL:
        !           816:     call:
        !           817:       CC_STATUS_INIT;
        !           818:       break;
        !           819:       /* Do calls preserve the condition codes?  (At least forget
        !           820:         cc_status expressions if they refer to registers
        !           821:         not preserved across calls.  Also forget expressions
        !           822:         about memory contents.)  */
        !           823:       if (cc_status.value1
        !           824:          && (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15),
        !           825:                                 cc_status.value1, 0)
        !           826:              || GET_CODE (cc_status.value1) == MEM))
        !           827:        cc_status.value1 = 0;
        !           828:       if (cc_status.value2
        !           829:          && (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15),
        !           830:                                 cc_status.value2, 0)
        !           831:              || GET_CODE (cc_status.value2) == MEM))
        !           832:        cc_status.value2 = 0;
        !           833:       break;
        !           834: 
        !           835:     default:
        !           836:       CC_STATUS_INIT;
        !           837:     }
        !           838: }
        !           839: 
        !           840: void
        !           841: forget_cc_if_dependent (op)
        !           842:      rtx op;
        !           843: {
        !           844:   cc_status = cc_prev_status;
        !           845:   if (cc_status.value1 && reg_overlap_mentioned_p (op, cc_status.value1))
        !           846:     cc_status.value1 = 0;
        !           847:   if (cc_status.value2 && reg_overlap_mentioned_p (op, cc_status.value2))
        !           848:     cc_status.value2 = 0;
        !           849: }

unix.superglobalmegacorp.com

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