Annotation of GNUtools/cc/config/ns32k/ns32k.c, revision 1.1

1.1     ! root        1: /* Subroutines for assembler code output on the NS32000.
        !             2:    Copyright (C) 1988 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 2, 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 ns32k.md need these.  */
        !            21: #include <stdio.h>
        !            22: #include "config.h"
        !            23: #include "rtl.h"
        !            24: #include "regs.h"
        !            25: #include "hard-reg-set.h"
        !            26: #include "real.h"
        !            27: #include "insn-config.h"
        !            28: #include "conditions.h"
        !            29: #include "insn-flags.h"
        !            30: #include "output.h"
        !            31: #include "insn-attr.h"
        !            32: 
        !            33: #ifdef OSF_OS
        !            34: int ns32k_num_files = 0;
        !            35: #endif
        !            36: 
        !            37: void
        !            38: trace (s, s1, s2)
        !            39:      char *s, *s1, *s2;
        !            40: {
        !            41:   fprintf (stderr, s, s1, s2);
        !            42: }
        !            43: 
        !            44: /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ 
        !            45: 
        !            46: int
        !            47: hard_regno_mode_ok (regno, mode)
        !            48:      int regno;
        !            49:      enum machine_mode mode;
        !            50: {
        !            51:   switch (mode)
        !            52:     {
        !            53:     case QImode:
        !            54:     case HImode:
        !            55:     case PSImode:
        !            56:     case SImode:
        !            57:     case PDImode:
        !            58:     case VOIDmode:
        !            59:     case BLKmode:
        !            60:       if (regno < 8 || regno == 16 || regno == 17)
        !            61:        return 1;
        !            62:       else
        !            63:        return 0;
        !            64: 
        !            65:     case DImode:
        !            66:       if (regno < 8 && (regno & 1) == 0)
        !            67:        return 1;
        !            68:       else
        !            69:        return 0;
        !            70: 
        !            71:     case SFmode:
        !            72:     case SCmode:
        !            73:       if (TARGET_32081)
        !            74:        {
        !            75:          if (regno < 16)
        !            76:            return 1;
        !            77:          else
        !            78:            return 0;
        !            79:        }
        !            80:       else
        !            81:        {
        !            82:          if (regno < 8)
        !            83:            return 1;
        !            84:          else 
        !            85:            return 0;
        !            86:        }
        !            87: 
        !            88:     case DFmode:
        !            89:     case DCmode:
        !            90:       if ((regno & 1) == 0)
        !            91:        {       
        !            92:          if (TARGET_32081)
        !            93:            {
        !            94:              if (regno < 16)
        !            95:                return 1;
        !            96:              else
        !            97:                return 0;
        !            98:            }
        !            99:          else
        !           100:            {
        !           101:              if (regno < 8)
        !           102:                return 1;
        !           103:              else
        !           104:                return 0;
        !           105:            }
        !           106:        }
        !           107:       else
        !           108:        return 0;
        !           109:     }
        !           110: 
        !           111:   /* Used to abort here, but simply saying "no" handles TImode
        !           112:      much better.  */
        !           113:   return 0;
        !           114: }
        !           115: 
        !           116: /* ADDRESS_COST calls this.  This function is not optimal
        !           117:    for the 32032 & 32332, but it probably is better than
        !           118:    the default. */
        !           119: 
        !           120: int
        !           121: calc_address_cost (operand)
        !           122:      rtx operand;
        !           123: {
        !           124:   int i;
        !           125:   int cost = 0;
        !           126:   
        !           127:   if (GET_CODE (operand) == MEM)
        !           128:     cost += 3;
        !           129:   if (GET_CODE (operand) == MULT)
        !           130:     cost += 2;
        !           131: #if 0
        !           132:   if (GET_CODE (operand) == REG)
        !           133:     cost += 1;                 /* not really, but the documentation
        !           134:                                   says different amount of registers
        !           135:                                   shouldn't return the same costs */
        !           136: #endif
        !           137:   switch (GET_CODE (operand))
        !           138:     {
        !           139:     case REG:
        !           140:     case CONST:
        !           141:     case CONST_INT:
        !           142:     case CONST_DOUBLE:
        !           143:     case SYMBOL_REF:
        !           144:     case LABEL_REF:
        !           145:     case POST_DEC:
        !           146:     case PRE_DEC:
        !           147:       break;
        !           148:     case MULT:
        !           149:     case MEM:
        !           150:     case PLUS:
        !           151:       for (i = 0; i < GET_RTX_LENGTH (GET_CODE (operand)); i++)
        !           152:        {
        !           153:          cost += calc_address_cost (XEXP (operand, i));
        !           154:        }
        !           155:     default:
        !           156:       break;
        !           157:     }
        !           158:   return cost;
        !           159: }
        !           160: 
        !           161: /* Return the register class of a scratch register needed to copy IN into
        !           162:    or out of a register in CLASS in MODE.  If it can be done directly,
        !           163:    NO_REGS is returned.  */
        !           164: 
        !           165: enum reg_class
        !           166: secondary_reload_class (class, mode, in)
        !           167:      enum reg_class class;
        !           168:      enum machine_mode mode;
        !           169:      rtx in;
        !           170: {
        !           171:   int regno = true_regnum (in);
        !           172: 
        !           173:   if (regno >= FIRST_PSEUDO_REGISTER)
        !           174:     regno = -1;
        !           175: 
        !           176:   /* We can place anything into GENERAL_REGS and can put GENERAL_REGS
        !           177:      into anything.  */
        !           178:   if (class == GENERAL_REGS || (regno >= 0 && regno < 8))
        !           179:     return NO_REGS;
        !           180: 
        !           181:   /* Constants, memory, and FP registers can go into FP registers.  */
        !           182:   if ((regno == -1 || (regno >= 8 && regno < 16)) && (class == FLOAT_REGS))
        !           183:     return NO_REGS;
        !           184: 
        !           185: #if 0 /* This isn't strictly true (can't move fp to sp or vice versa),
        !           186:         so it's cleaner to use PREFERRED_RELOAD_CLASS
        !           187:         to make the right things happen.  */
        !           188:   if (regno >= 16 && class == GEN_AND_MEM_REGS)
        !           189:     return NO_REGS;
        !           190: #endif
        !           191: 
        !           192:   /* Otherwise, we need GENERAL_REGS. */
        !           193:   return GENERAL_REGS;
        !           194: }
        !           195: /* Generate the rtx that comes from an address expression in the md file */
        !           196: /* The expression to be build is BASE[INDEX:SCALE].  To recognize this,
        !           197:    scale must be converted from an exponent (from ASHIFT) to a
        !           198:    multiplier (for MULT). */
        !           199: rtx
        !           200: gen_indexed_expr (base, index, scale)
        !           201:      rtx base, index, scale;
        !           202: {
        !           203:   rtx addr;
        !           204: 
        !           205:   /* This generates an illegal addressing mode, if BASE is
        !           206:      fp or sp.  This is handled by PRINT_OPERAND_ADDRESS.  */
        !           207:   if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
        !           208:     base = gen_rtx (MEM, SImode, base);
        !           209:   addr = gen_rtx (MULT, SImode, index,
        !           210:                  gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale)));
        !           211:   addr = gen_rtx (PLUS, SImode, base, addr);
        !           212:   return addr;
        !           213: }
        !           214: 
        !           215: /* Return 1 if OP is a valid operand of mode MODE.  This
        !           216:    predicate rejects operands which do not have a mode
        !           217:    (such as CONST_INT which are VOIDmode).  */
        !           218: int
        !           219: reg_or_mem_operand (op, mode)
        !           220:      register rtx op;
        !           221:      enum machine_mode mode;
        !           222: {
        !           223:   return (GET_MODE (op) == mode
        !           224:          && (GET_CODE (op) == REG
        !           225:              || GET_CODE (op) == SUBREG
        !           226:              || GET_CODE (op) == MEM));
        !           227: }
        !           228: 
        !           229: /* Return the best assembler insn template
        !           230:    for moving operands[1] into operands[0] as a fullword.  */
        !           231: 
        !           232: static char *
        !           233: singlemove_string (operands)
        !           234:      rtx *operands;
        !           235: {
        !           236:   if (GET_CODE (operands[1]) == CONST_INT
        !           237:       && INTVAL (operands[1]) <= 7
        !           238:       && INTVAL (operands[1]) >= -8)
        !           239:     return "movqd %1,%0";
        !           240:   return "movd %1,%0";
        !           241: }
        !           242: 
        !           243: char *
        !           244: output_move_double (operands)
        !           245:      rtx *operands;
        !           246: {
        !           247:   enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1;
        !           248:   rtx latehalf[2];
        !           249: 
        !           250:   /* First classify both operands.  */
        !           251: 
        !           252:   if (REG_P (operands[0]))
        !           253:     optype0 = REGOP;
        !           254:   else if (offsettable_memref_p (operands[0]))
        !           255:     optype0 = OFFSOP;
        !           256:   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
        !           257:     optype0 = PUSHOP;
        !           258:   else
        !           259:     optype0 = RNDOP;
        !           260: 
        !           261:   if (REG_P (operands[1]))
        !           262:     optype1 = REGOP;
        !           263:   else if (CONSTANT_ADDRESS_P (operands[1])
        !           264:           || GET_CODE (operands[1]) == CONST_DOUBLE)
        !           265:     optype1 = CNSTOP;
        !           266:   else if (offsettable_memref_p (operands[1]))
        !           267:     optype1 = OFFSOP;
        !           268:   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
        !           269:     optype1 = PUSHOP;
        !           270:   else
        !           271:     optype1 = RNDOP;
        !           272: 
        !           273:   /* Check for the cases that the operand constraints are not
        !           274:      supposed to allow to happen.  Abort if we get one,
        !           275:      because generating code for these cases is painful.  */
        !           276: 
        !           277:   if (optype0 == RNDOP || optype1 == RNDOP)
        !           278:     abort ();
        !           279: 
        !           280:   /* Ok, we can do one word at a time.
        !           281:      Normally we do the low-numbered word first,
        !           282:      but if either operand is autodecrementing then we
        !           283:      do the high-numbered word first.
        !           284: 
        !           285:      In either case, set up in LATEHALF the operands to use
        !           286:      for the high-numbered word and in some cases alter the
        !           287:      operands in OPERANDS to be suitable for the low-numbered word.  */
        !           288: 
        !           289:   if (optype0 == REGOP)
        !           290:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
        !           291:   else if (optype0 == OFFSOP)
        !           292:     latehalf[0] = adj_offsettable_operand (operands[0], 4);
        !           293:   else
        !           294:     latehalf[0] = operands[0];
        !           295: 
        !           296:   if (optype1 == REGOP)
        !           297:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
        !           298:   else if (optype1 == OFFSOP)
        !           299:     latehalf[1] = adj_offsettable_operand (operands[1], 4);
        !           300:   else if (optype1 == CNSTOP)
        !           301:     {
        !           302:       if (CONSTANT_ADDRESS_P (operands[1]))
        !           303:        latehalf[1] = const0_rtx;
        !           304:       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
        !           305:        split_double (operands[1], &operands[1], &latehalf[1]);
        !           306:     }
        !           307:   else
        !           308:     latehalf[1] = operands[1];
        !           309: 
        !           310:   /* If insn is effectively movd N(sp),tos then we will do the
        !           311:      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
        !           312:      for the low word as well, to compensate for the first decrement of sp.
        !           313:      Given this, it doesn't matter which half we do "first".  */
        !           314:   if (optype0 == PUSHOP
        !           315:       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
        !           316:       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
        !           317:     operands[1] = latehalf[1];
        !           318: 
        !           319:   /* If one or both operands autodecrementing,
        !           320:      do the two words, high-numbered first.  */
        !           321:   else if (optype0 == PUSHOP || optype1 == PUSHOP)
        !           322:     {
        !           323:       output_asm_insn (singlemove_string (latehalf), latehalf);
        !           324:       return singlemove_string (operands);
        !           325:     }
        !           326: 
        !           327:   /* If the first move would clobber the source of the second one,
        !           328:      do them in the other order.  */
        !           329: 
        !           330:   /* Overlapping registers.  */
        !           331:   if (optype0 == REGOP && optype1 == REGOP
        !           332:       && REGNO (operands[0]) == REGNO (latehalf[1]))
        !           333:     {
        !           334:       /* Do that word.  */
        !           335:       output_asm_insn (singlemove_string (latehalf), latehalf);
        !           336:       /* Do low-numbered word.  */
        !           337:       return singlemove_string (operands);
        !           338:     }
        !           339:   /* Loading into a register which overlaps a register used in the address.  */
        !           340:   else if (optype0 == REGOP && optype1 != REGOP
        !           341:           && reg_overlap_mentioned_p (operands[0], operands[1]))
        !           342:     {
        !           343:       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
        !           344:          && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
        !           345:        {
        !           346:          /* If both halves of dest are used in the src memory address,
        !           347:             add the two regs and put them in the low reg (operands[0]).
        !           348:             Then it works to load latehalf first.  */
        !           349:          rtx xops[2];
        !           350:          xops[0] = latehalf[0];
        !           351:          xops[1] = operands[0];
        !           352:          output_asm_insn ("addd %0,%1", xops);
        !           353:          operands[1] = gen_rtx (MEM, DImode, operands[0]);
        !           354:          latehalf[1] = adj_offsettable_operand (operands[1], 4);
        !           355:          /* The first half has the overlap, Do the late half first.  */
        !           356:          output_asm_insn (singlemove_string (latehalf), latehalf);
        !           357:          /* Then clobber.  */
        !           358:          return singlemove_string (operands);
        !           359:        }
        !           360:       if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
        !           361:        {
        !           362:          /* The first half has the overlap, Do the late half first.  */
        !           363:          output_asm_insn (singlemove_string (latehalf), latehalf);
        !           364:          /* Then clobber.  */
        !           365:          return singlemove_string (operands);
        !           366:        }
        !           367:     }
        !           368: 
        !           369:   /* Normal case.  Do the two words, low-numbered first.  */
        !           370: 
        !           371:   output_asm_insn (singlemove_string (operands), operands);
        !           372: 
        !           373:   operands[0] = latehalf[0];
        !           374:   operands[1] = latehalf[1];
        !           375:   return singlemove_string (operands);
        !           376: }
        !           377: 
        !           378: int
        !           379: check_reg (oper, reg)
        !           380:      rtx oper;
        !           381:      int reg;
        !           382: {
        !           383:   register int i;
        !           384: 
        !           385:   if (oper == 0)
        !           386:     return 0;
        !           387:   switch (GET_CODE(oper))
        !           388:     {
        !           389:     case REG:
        !           390:       return (REGNO(oper) == reg) ? 1 : 0;
        !           391:     case MEM:
        !           392:       return check_reg(XEXP(oper, 0), reg);
        !           393:     case PLUS:
        !           394:     case MULT:
        !           395:       return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
        !           396:     }
        !           397:   return 0;
        !           398: }
        !           399: 
        !           400: /* PRINT_OPERAND is defined to call this function,
        !           401:    which is easier to debug than putting all the code in
        !           402:    a macro definition in ns32k.h.  */
        !           403: 
        !           404: void
        !           405: print_operand (file, x, code)
        !           406:      FILE *file;
        !           407:      rtx x;
        !           408:      char code;
        !           409: {
        !           410:   if (code == '$')
        !           411:     PUT_IMMEDIATE_PREFIX (file);
        !           412:   else if (code == '?')
        !           413:     PUT_EXTERNAL_PREFIX (file);
        !           414:   else if (GET_CODE (x) == REG)
        !           415:     fprintf (file, "%s", reg_names[REGNO (x)]);
        !           416:   else if (GET_CODE (x) == MEM)
        !           417:     {
        !           418:       rtx tmp = XEXP (x, 0);
        !           419: #if ! (defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC))
        !           420:       if (GET_CODE (tmp) != CONST_INT)
        !           421:        {
        !           422:          char *out = XSTR (tmp, 0);
        !           423:          if (out[0] == '*')
        !           424:            {
        !           425:              PUT_ABSOLUTE_PREFIX (file);
        !           426:              fprintf (file, "%s", &out[1]);
        !           427:            }
        !           428:          else
        !           429:            ASM_OUTPUT_LABELREF (file, out);
        !           430:        }
        !           431:       else
        !           432: #endif
        !           433:        output_address (XEXP (x, 0));
        !           434:     }
        !           435:   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode)
        !           436:     {
        !           437:       if (GET_MODE (x) == DFmode)
        !           438:        { 
        !           439:          union { double d; int i[2]; } u;
        !           440:          u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
        !           441:          PUT_IMMEDIATE_PREFIX(file);
        !           442: #ifdef SEQUENT_ASM
        !           443:          /* Sequent likes it's floating point constants as integers */
        !           444:          fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
        !           445: #else
        !           446: #ifdef ENCORE_ASM
        !           447:          fprintf (file, "0f%.20e", u.d); 
        !           448: #else
        !           449:          fprintf (file, "0d%.20e", u.d); 
        !           450: #endif
        !           451: #endif
        !           452:        }
        !           453:       else
        !           454:        { 
        !           455:          union { double d; int i[2]; } u;
        !           456:          u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
        !           457:          PUT_IMMEDIATE_PREFIX (file);
        !           458: #ifdef SEQUENT_ASM
        !           459:          /* We have no way of winning if we can't get the bits
        !           460:             for a sequent floating point number.  */
        !           461: #if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
        !           462:          abort ();
        !           463: #endif
        !           464:          {
        !           465:            union { float f; long l; } uu;
        !           466:            uu.f = u.d;
        !           467:            fprintf (file, "0Fx%08x", uu.l);
        !           468:          }
        !           469: #else
        !           470:          fprintf (file, "0f%.20e", u.d); 
        !           471: #endif
        !           472:        }
        !           473:     }
        !           474:   else
        !           475:     {
        !           476: #ifdef NO_IMMEDIATE_PREFIX_IF_SYMBOLIC
        !           477:       if (GET_CODE (x) == CONST_INT)
        !           478: #endif
        !           479:        PUT_IMMEDIATE_PREFIX (file);
        !           480:       output_addr_const (file, x);
        !           481:     }
        !           482: }
        !           483: 
        !           484: /* PRINT_OPERAND_ADDRESS is defined to call this function,
        !           485:    which is easier to debug than putting all the code in
        !           486:    a macro definition in ns32k.h .  */
        !           487: 
        !           488: /* Completely rewritten to get this to work with Gas for PC532 Mach.
        !           489:    This function didn't work and I just wasn't able (nor very willing) to
        !           490:    figure out how it worked.
        !           491:    90-11-25 Tatu Yl|nen <[email protected]> */
        !           492: 
        !           493: print_operand_address (file, addr)
        !           494:      register FILE *file;
        !           495:      register rtx addr;
        !           496: {
        !           497:   static char scales[] = { 'b', 'w', 'd', 0, 'q', };
        !           498:   rtx offset, base, indexexp, tmp;
        !           499:   int scale;
        !           500: 
        !           501:   if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == POST_DEC)
        !           502:     {
        !           503:       fprintf (file, "tos");
        !           504:       return;
        !           505:     }
        !           506: 
        !           507:   offset = NULL;
        !           508:   base = NULL;
        !           509:   indexexp = NULL;
        !           510:   while (addr != NULL)
        !           511:     {
        !           512:       if (GET_CODE (addr) == PLUS)
        !           513:        {
        !           514:          if (GET_CODE (XEXP (addr, 0)) == PLUS)
        !           515:            {
        !           516:              tmp = XEXP (addr, 1);
        !           517:              addr = XEXP (addr, 0);
        !           518:            }
        !           519:          else
        !           520:            {
        !           521:              tmp = XEXP (addr,0);
        !           522:              addr = XEXP (addr,1);
        !           523:            }
        !           524:        }
        !           525:       else
        !           526:        {
        !           527:          tmp = addr;
        !           528:          addr = NULL;
        !           529:        }
        !           530:       switch (GET_CODE (tmp))
        !           531:        {
        !           532:        case PLUS:
        !           533:          abort ();
        !           534:        case MEM:
        !           535:          if (base)
        !           536:            {
        !           537:              indexexp = base;
        !           538:              base = tmp;
        !           539:            }
        !           540:          else
        !           541:            base = tmp;
        !           542:          break;
        !           543:        case REG:
        !           544:          if (REGNO (tmp) < 8)
        !           545:            if (base)
        !           546:              {
        !           547:                indexexp = tmp;
        !           548:              }
        !           549:            else
        !           550:              base = tmp;
        !           551:          else
        !           552:            if (base)
        !           553:              {
        !           554:                indexexp = base;
        !           555:                base = tmp;
        !           556:              }
        !           557:            else
        !           558:              base = tmp;
        !           559:          break;
        !           560:        case MULT:
        !           561:          indexexp = tmp;
        !           562:          break;
        !           563:        case CONST:
        !           564:        case CONST_INT:
        !           565:        case SYMBOL_REF:
        !           566:        case LABEL_REF:
        !           567:          if (offset)
        !           568:            offset = gen_rtx (PLUS, SImode, tmp, offset);
        !           569:          else
        !           570:            offset = tmp;
        !           571:          break;
        !           572:        default:
        !           573:          abort ();
        !           574:        }
        !           575:     }
        !           576:   if (! offset)
        !           577:     offset = const0_rtx;
        !           578: 
        !           579: #ifdef INDEX_RATHER_THAN_BASE
        !           580:   /* This is a re-implementation of the SEQUENT_ADDRESS_BUG fix.  */
        !           581:   if (base && !indexexp && GET_CODE (base) == REG
        !           582:       && REG_OK_FOR_INDEX_P (base))
        !           583:     {
        !           584:       indexexp = base;
        !           585:       base = 0;
        !           586:     }
        !           587: #endif
        !           588: 
        !           589:   /* now, offset, base and indexexp are set */
        !           590:   if (! base)
        !           591:     {
        !           592: #if defined (PC_RELATIVE) || defined (NO_ABSOLUTE_PREFIX_IF_SYMBOLIC)
        !           593:       if (GET_CODE (offset) == CONST_INT)
        !           594: /*      if (! (GET_CODE (offset) == LABEL_REF
        !           595:             || GET_CODE (offset) == SYMBOL_REF)) */
        !           596: #endif
        !           597:        PUT_ABSOLUTE_PREFIX (file);
        !           598:     }
        !           599: 
        !           600:   output_addr_const (file, offset);
        !           601:   if (base) /* base can be (REG ...) or (MEM ...) */
        !           602:     switch (GET_CODE (base))
        !           603:       {
        !           604:        /* now we must output base.  Possible alternatives are:
        !           605:           (rN)       (REG ...)
        !           606:           (sp)       (REG ...)
        !           607:           (fp)       (REG ...)
        !           608:           (pc)       (REG ...)  used for SYMBOL_REF and LABEL_REF, output
        !           609:           (disp(fp)) (MEM ...)       just before possible [rX:y]
        !           610:           (disp(sp)) (MEM ...)
        !           611:           (disp(sb)) (MEM ...)
        !           612:           */
        !           613:       case REG:
        !           614:        fprintf (file, "(%s)", reg_names[REGNO (base)]);
        !           615:        break;
        !           616:       case MEM:
        !           617:        addr = XEXP(base,0);
        !           618:        base = NULL;
        !           619:        offset = NULL;
        !           620:        while (addr != NULL)
        !           621:          {
        !           622:            if (GET_CODE (addr) == PLUS)
        !           623:              {
        !           624:                if (GET_CODE (XEXP (addr, 0)) == PLUS)
        !           625:                  {
        !           626:                    tmp = XEXP (addr, 1);
        !           627:                    addr = XEXP (addr, 0);
        !           628:                  }
        !           629:                else
        !           630:                  {
        !           631:                    tmp = XEXP (addr, 0);
        !           632:                    addr = XEXP (addr, 1);
        !           633:                  }
        !           634:              }
        !           635:            else
        !           636:              {
        !           637:                tmp = addr;
        !           638:                addr = NULL;
        !           639:              }
        !           640:            switch (GET_CODE (tmp))
        !           641:              {
        !           642:              case REG:
        !           643:                base = tmp;
        !           644:                break;
        !           645:              case CONST:
        !           646:              case CONST_INT:
        !           647:              case SYMBOL_REF:
        !           648:              case LABEL_REF:
        !           649:                if (offset)
        !           650:                  offset = gen_rtx (PLUS, SImode, tmp, offset);
        !           651:                else
        !           652:                  offset = tmp;
        !           653:                break;
        !           654:              default:
        !           655:                abort ();
        !           656:              }
        !           657:          }
        !           658:        if (! offset)
        !           659:          offset = const0_rtx;
        !           660:        fprintf (file, "(");
        !           661:        output_addr_const (file, offset);
        !           662:        if (base)
        !           663:          fprintf (file, "(%s)", reg_names[REGNO (base)]);
        !           664: #ifdef BASE_REG_NEEDED
        !           665:        else if (TARGET_SB)
        !           666:          fprintf (file, "(sb)");
        !           667:        else
        !           668:          abort ();
        !           669: #endif
        !           670:        fprintf (file, ")");
        !           671:        break;
        !           672: 
        !           673:       default:
        !           674:        abort ();
        !           675:       }
        !           676: #ifdef PC_RELATIVE
        !           677:   else                         /* no base */
        !           678:     if (GET_CODE (offset) == LABEL_REF || GET_CODE (offset) == SYMBOL_REF)
        !           679:       fprintf (file, "(pc)");
        !           680: #endif
        !           681: #ifdef BASE_REG_NEEDED         /* this is defined if the assembler always
        !           682:                                   needs a base register */
        !           683:     else if (TARGET_SB)
        !           684:       fprintf (file, "(sb)");
        !           685:     else
        !           686:       abort ();
        !           687: #endif
        !           688:   /* now print index if we have one */
        !           689:   if (indexexp)
        !           690:     {
        !           691:       if (GET_CODE (indexexp) == MULT)
        !           692:        {
        !           693:          scale = INTVAL (XEXP (indexexp, 1)) >> 1;
        !           694:          indexexp = XEXP (indexexp, 0);
        !           695:        }
        !           696:       else
        !           697:        scale = 0;
        !           698:       if (GET_CODE (indexexp) != REG || REGNO (indexexp) >= 8)
        !           699:        abort ();
        !           700: 
        !           701: #ifdef UTEK_ASM
        !           702:       fprintf (file, "[%c`%s]",
        !           703:               scales[scale],
        !           704:               reg_names[REGNO (indexexp)]);
        !           705: #else
        !           706:       fprintf (file, "[%s:%c]",
        !           707:               reg_names[REGNO (indexexp)],
        !           708:               scales[scale]);
        !           709: #endif
        !           710:     }
        !           711: }
        !           712: 
        !           713: /* National 32032 shifting is so bad that we can get
        !           714:    better performance in many common cases by using other
        !           715:    techniques.  */
        !           716: char *
        !           717: output_shift_insn (operands)
        !           718:      rtx *operands;
        !           719: {
        !           720:   if (GET_CODE (operands[2]) == CONST_INT
        !           721:       && INTVAL (operands[2]) > 0
        !           722:       && INTVAL (operands[2]) <= 3)
        !           723:     if (GET_CODE (operands[0]) == REG)
        !           724:       {
        !           725:        if (GET_CODE (operands[1]) == REG)
        !           726:          {
        !           727:            if (REGNO (operands[0]) == REGNO (operands[1]))
        !           728:              {
        !           729:                if (operands[2] == const1_rtx)
        !           730:                  return "addd %0,%0";
        !           731:                else if (INTVAL (operands[2]) == 2)
        !           732:                  return "addd %0,%0\n\taddd %0,%0";
        !           733:              }
        !           734:            if (operands[2] == const1_rtx)
        !           735:              return "movd %1,%0\n\taddd %0,%0";
        !           736:            
        !           737:            operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
        !           738:            return "addr %a1,%0";
        !           739:          }
        !           740:        if (operands[2] == const1_rtx)
        !           741:          return "movd %1,%0\n\taddd %0,%0";
        !           742:       }
        !           743:     else if (GET_CODE (operands[1]) == REG)
        !           744:       {
        !           745:        operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
        !           746:        return "addr %a1,%0";
        !           747:       }
        !           748:     else if (INTVAL (operands[2]) == 1
        !           749:             && GET_CODE (operands[1]) == MEM
        !           750:             && rtx_equal_p (operands [0], operands[1]))
        !           751:       {
        !           752:        rtx temp = XEXP (operands[1], 0);
        !           753:        
        !           754:        if (GET_CODE (temp) == REG
        !           755:            || (GET_CODE (temp) == PLUS
        !           756:                && GET_CODE (XEXP (temp, 0)) == REG
        !           757:                && GET_CODE (XEXP (temp, 1)) == CONST_INT))
        !           758:          return "addd %0,%0";
        !           759:       }
        !           760:     else return "ashd %2,%0";
        !           761:   return "ashd %2,%0";
        !           762: }

unix.superglobalmegacorp.com

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