Annotation of GNUtools/cc/config/tahoe/tahoe.c, revision 1.1.1.1

1.1       root        1: /* Subroutines for insn-output.c for Tahoe.
                      2:    Copyright (C) 1989, 1991 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: 
                     21: #include "config.h"
                     22: #include "rtl.h"
                     23: #include "regs.h"
                     24: #include "hard-reg-set.h"
                     25: #include "real.h"
                     26: #include "insn-config.h"
                     27: #include "conditions.h"
                     28: #include "insn-flags.h"
                     29: #include "output.h"
                     30: #include "insn-attr.h"
                     31: 
                     32: /*
                     33:  * File: output-tahoe.c
                     34:  *
                     35:  * Original port made at the University of Buffalo by Devon Bowen,
                     36:  * Dale Wiles and Kevin Zachmann.
                     37:  *
                     38:  * Changes for HCX by Piet van Oostrum,
                     39:  * University of Utrecht, The Netherlands ([email protected])
                     40:  *
                     41:  * Speed tweaks by Michael Tiemann ([email protected]).
                     42:  *
                     43:  * Mail bugs reports or fixes to:      [email protected]
                     44:  */
                     45: 
                     46: 
                     47: /* On tahoe, you have to go to memory to convert a register
                     48:    from sub-word to word.  */
                     49: 
                     50: rtx tahoe_reg_conversion_loc;
                     51: 
                     52: int
                     53: extendable_operand (op, mode)
                     54:      rtx op;
                     55:      enum machine_mode mode;
                     56: {
                     57:   if ((GET_CODE (op) == REG
                     58:        || (GET_CODE (op) == SUBREG
                     59:           && GET_CODE (SUBREG_REG (op)) == REG))
                     60:       && tahoe_reg_conversion_loc == 0)
                     61:     tahoe_reg_conversion_loc = assign_stack_local (SImode, GET_MODE_SIZE (SImode));
                     62:   return general_operand (op, mode);
                     63: }
                     64: 
                     65: /* most of the print_operand_address function was taken from the vax   */
                     66: /* since the modes are basically the same. I had to add a special case,        */
                     67: /* though, for symbol references with offsets.                         */
                     68: 
                     69: #include <stdio.h>
                     70: 
                     71: print_operand_address (file, addr)
                     72:      FILE *file;
                     73:      register rtx addr;
                     74: {
                     75:   register rtx reg1, reg2, breg, ireg;
                     76:   rtx offset;
                     77:   static char *reg_name[] = REGISTER_NAMES;
                     78: 
                     79:  retry:
                     80:   switch (GET_CODE (addr))
                     81:     {
                     82:     case MEM:
                     83:       fprintf (file, "*");
                     84:       addr = XEXP (addr, 0);
                     85:       goto retry;
                     86: 
                     87:     case REG:
                     88:       fprintf (file, "(%s)", reg_name [REGNO (addr)]);
                     89:       break;
                     90: 
                     91:     case PRE_DEC:
                     92:       fprintf (file, "-(%s)", reg_name [REGNO (XEXP (addr, 0))]);
                     93:       break;
                     94: 
                     95:     case POST_INC:
                     96:       fprintf (file, "(%s)+", reg_name [REGNO (XEXP (addr, 0))]);
                     97:       break;
                     98: 
                     99:     case PLUS:
                    100:       reg1 = 0;        reg2 = 0;
                    101:       ireg = 0;        breg = 0;
                    102:       offset = 0;
                    103: 
                    104:       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
                    105:          && GET_CODE (XEXP (addr, 1)) == CONST_INT)
                    106:        output_addr_const (file, addr);
                    107: 
                    108:       if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
                    109:          && GET_CODE (XEXP (addr, 0)) == CONST_INT)
                    110:        output_addr_const (file, addr);
                    111: 
                    112:       if (CONSTANT_ADDRESS_P (XEXP (addr, 0))
                    113:          || GET_CODE (XEXP (addr, 0)) == MEM)
                    114:        {
                    115:          offset = XEXP (addr, 0);
                    116:          addr = XEXP (addr, 1);
                    117:        }
                    118:       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))
                    119:               || GET_CODE (XEXP (addr, 1)) == MEM)
                    120:        {
                    121:          offset = XEXP (addr, 1);
                    122:          addr = XEXP (addr, 0);
                    123:        }
                    124:       if (GET_CODE (addr) != PLUS)
                    125:        ;
                    126:       else if (GET_CODE (XEXP (addr, 0)) == MULT)
                    127:        {
                    128:          reg1 = XEXP (addr, 0);
                    129:          addr = XEXP (addr, 1);
                    130:        }
                    131:       else if (GET_CODE (XEXP (addr, 1)) == MULT)
                    132:        {
                    133:          reg1 = XEXP (addr, 1);
                    134:          addr = XEXP (addr, 0);
                    135:        }
                    136:       else if (GET_CODE (XEXP (addr, 0)) == REG)
                    137:        {
                    138:          reg1 = XEXP (addr, 0);
                    139:          addr = XEXP (addr, 1);
                    140:        }
                    141:       else if (GET_CODE (XEXP (addr, 1)) == REG)
                    142:        {
                    143:          reg1 = XEXP (addr, 1);
                    144:          addr = XEXP (addr, 0);
                    145:        }
                    146:       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
                    147:        {
                    148:          if (reg1 == 0)
                    149:            reg1 = addr;
                    150:          else
                    151:            reg2 = addr;
                    152:          addr = 0;
                    153:        }
                    154:       if (offset != 0)
                    155:        {
                    156:          if (addr != 0) abort ();
                    157:          addr = offset;
                    158:        }
                    159:       if (reg1 != 0 && GET_CODE (reg1) == MULT)
                    160:        {
                    161:          breg = reg2;
                    162:          ireg = reg1;
                    163:        }
                    164:       else if (reg2 != 0 && GET_CODE (reg2) == MULT)
                    165:        {
                    166:          breg = reg1;
                    167:          ireg = reg2;
                    168:        }
                    169:       else if (reg2 != 0 || GET_CODE (addr) == MEM)
                    170:        {
                    171:          breg = reg2;
                    172:          ireg = reg1;
                    173:        }
                    174:       else
                    175:        {
                    176:          breg = reg1;
                    177:          ireg = reg2;
                    178:        }
                    179:       if (addr != 0)
                    180:        output_address (offset);
                    181:       if (breg != 0)
                    182:        {
                    183:          if (GET_CODE (breg) != REG)
                    184:            abort ();
                    185:          fprintf (file, "(%s)", reg_name[REGNO (breg)]);
                    186:        }
                    187:       if (ireg != 0)
                    188:        {
                    189:          if (GET_CODE (ireg) == MULT)
                    190:            ireg = XEXP (ireg, 0);
                    191:          if (GET_CODE (ireg) != REG)
                    192:            abort ();
                    193:          fprintf (file, "[%s]", reg_name[REGNO (ireg)]);
                    194:        }
                    195:       break;
                    196: 
                    197:     default:
                    198:       output_addr_const (file, addr);
                    199:     }
                    200: }
                    201: 
                    202: /* Do a quick check and find out what the best way to do the */
                    203: /* mini-move is. Could be a push or a move.....                     */
                    204: 
                    205: static char *
                    206: singlemove_string (operands)
                    207:      rtx *operands;
                    208: {
                    209:   if (operands[1] == const0_rtx)
                    210:       return "clrl %0";
                    211:   if (push_operand (operands[0], SImode))
                    212:     return "pushl %1";
                    213:   return "movl %1,%0";
                    214: }
                    215: 
                    216: /* given the rtx for an address, return true if the given */
                    217: /* register number is used in the address somewhere.     */
                    218: 
                    219: regisused(addr,regnum)
                    220: rtx addr;
                    221: int regnum;
                    222: {
                    223:        if (GET_CODE(addr) == REG)
                    224:                if (REGNO(addr) == regnum)
                    225:                        return (1);
                    226:                else
                    227:                        return (0);
                    228: 
                    229:        if (GET_CODE(addr) == MEM)
                    230:                return regisused(XEXP(addr,0),regnum);
                    231: 
                    232:        if ((GET_CODE(addr) == MULT) || (GET_CODE(addr) == PLUS))
                    233:                return ((regisused(XEXP(addr,0),regnum)) ||
                    234:                                        (regisused(XEXP(addr,1),regnum)));
                    235: 
                    236:        return 0;
                    237: }
                    238: 
                    239: 
                    240: /* Given some rtx, traverse it and return the register used in a */
                    241: /* index. If no index is found, return 0.                       */
                    242: 
                    243: rtx
                    244: index_reg(addr)
                    245: rtx addr;
                    246: {
                    247:        rtx temp;
                    248: 
                    249:        if (GET_CODE(addr) == MEM)
                    250:                return index_reg(XEXP(addr,0));
                    251: 
                    252:        if (GET_CODE(addr) == MULT)
                    253:                if (GET_CODE(XEXP(addr,0)) == REG)
                    254:                        return XEXP(addr,0);
                    255:                else
                    256:                        return XEXP(addr,1);
                    257: 
                    258:        if (GET_CODE(addr) == PLUS)
                    259:                if (temp = index_reg(XEXP(addr,0)))
                    260:                        return temp;
                    261:                else
                    262:                        return index_reg(XEXP(addr,1));
                    263: 
                    264:        return 0;
                    265: }
                    266: 
                    267: 
                    268: /* simulate the move double by generating two movl's. You have */
                    269: /* to be careful about mixing modes here.                     */
                    270: 
                    271: char *
                    272: output_move_double (operands)
                    273:      rtx *operands;
                    274: {
                    275:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, INDOP, CNSTOP, RNDOP }
                    276:     optype0, optype1;
                    277:   rtx latehalf[2];
                    278:   rtx shftreg0 = 0, shftreg1 = 0;
                    279:   rtx temp0 = 0, temp1 = 0;
                    280:   rtx addreg0 = 0, addreg1 = 0;
                    281:   int dohighfirst = 0;
                    282: 
                    283:   /* First classify both operands. */
                    284: 
                    285:   if (REG_P (operands[0]))
                    286:     optype0 = REGOP;
                    287:   else if ((GET_CODE(operands[0])==MEM) && (shftreg0=index_reg(operands[0])))
                    288:     optype0 = INDOP;
                    289:   else if (offsettable_memref_p (operands[0]))
                    290:     optype0 = OFFSOP;
                    291:   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) {
                    292:     optype0 = PUSHOP;
                    293:     dohighfirst++;
                    294:   } else if (GET_CODE (operands[0]) == MEM)
                    295:     optype0 = MEMOP;
                    296:   else
                    297:     optype0 = RNDOP;
                    298: 
                    299:   if (REG_P (operands[1]))
                    300:     optype1 = REGOP;
                    301:   else if ((GET_CODE(operands[1])==MEM) && (shftreg1=index_reg(operands[1])))
                    302:     optype1 = INDOP;
                    303:   else if (offsettable_memref_p (operands[1]))
                    304:     optype1 = OFFSOP;
                    305:   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
                    306:     optype1 = POPOP; 
                    307:   else if (GET_CODE (operands[1]) == MEM)
                    308:     optype1 = MEMOP;
                    309:   else if (CONSTANT_P (operands[1]))
                    310:     optype1 = CNSTOP;
                    311:   else
                    312:     optype1 = RNDOP;
                    313: 
                    314:   /* set up for the high byte move for operand zero */
                    315: 
                    316:   switch (optype0) {
                    317: 
                    318:        /* if it's a register, just use the next highest in the */
                    319:        /* high address move.                                   */
                    320: 
                    321:        case REGOP  : latehalf[0] = gen_rtx (REG,SImode,REGNO(operands[0])+1);
                    322:                      break;
                    323: 
                    324:        /* for an offsettable address, use the gcc function to  */
                    325:        /* modify the operand to get an offset of 4 higher for  */
                    326:        /* the second move.                                     */
                    327: 
                    328:        case OFFSOP : latehalf[0] = adj_offsettable_operand (operands[0], 4);
                    329:                      break;
                    330: 
                    331:        /* if the operand is MEMOP type, it must be a pointer   */
                    332:        /* to a pointer. So just remember to increase the mem   */
                    333:        /* location and use the same operand.                   */
                    334: 
                    335:        case MEMOP  : latehalf[0] = operands[0];
                    336:                      addreg0 = XEXP(operands[0],0);
                    337:                      break;
                    338: 
                    339:        /* if we're dealing with a push instruction, just leave */
                    340:        /* the operand alone since it auto-increments.          */
                    341: 
                    342:        case PUSHOP : latehalf[0] = operands[0];
                    343:                      break;
                    344: 
                    345:        /* YUCK! Indexed addressing!! If the address is considered   */
                    346:        /* offsettable, go use the offset in the high part. Otherwise */
                    347:        /* find what exactly is being added to the multiplication. If */
                    348:        /* it's a mem reference, increment that with the high part   */
                    349:        /* being unchanged to cause the shift. If it's a reg, do the */
                    350:        /* same. If you can't identify it, abort. Remember that the  */
                    351:        /* shift register was already set during identification.     */
                    352: 
                    353:        case INDOP  : if (offsettable_memref_p(operands[0])) {
                    354:                           latehalf[0] = adj_offsettable_operand(operands[0],4);
                    355:                           break;
                    356:                      }
                    357: 
                    358:                      latehalf[0] = operands[0];
                    359: 
                    360:                      temp0 = XEXP(XEXP(operands[0],0),0);
                    361:                       if (GET_CODE(temp0) == MULT) {
                    362:                           temp1 = temp0;
                    363:                           temp0 = XEXP(XEXP(operands[0],0),1);
                    364:                      } else {
                    365:                           temp1 = XEXP(XEXP(operands[0],0),1);
                    366:                           if (GET_CODE(temp1) != MULT)
                    367:                                abort();
                    368:                      }
                    369: 
                    370:                      if (GET_CODE(temp0) == MEM)
                    371:                           addreg0 = temp0;
                    372:                      else if (GET_CODE(temp0) == REG)
                    373:                           addreg0 = temp0;
                    374:                      else
                    375:                           abort();
                    376: 
                    377:                      break;
                    378: 
                    379:        /* if we don't know the operand type, print a friendly  */
                    380:        /* little error message...   8-)                        */
                    381: 
                    382:        case RNDOP  :
                    383:        default     : abort();
                    384:   }
                    385: 
                    386:   /* do the same setup for operand one */
                    387: 
                    388:   switch (optype1) {
                    389: 
                    390:        case REGOP  : latehalf[1] = gen_rtx(REG,SImode,REGNO(operands[1])+1);
                    391:                      break;
                    392: 
                    393:        case OFFSOP : latehalf[1] = adj_offsettable_operand (operands[1], 4);
                    394:                      break;
                    395: 
                    396:        case MEMOP  : latehalf[1] = operands[1];
                    397:                      addreg1 = XEXP(operands[1],0);
                    398:                      break;
                    399: 
                    400:        case POPOP  : latehalf[1] = operands[1];
                    401:                      break;
                    402: 
                    403:        case INDOP  : if (offsettable_memref_p(operands[1])) {
                    404:                           latehalf[1] = adj_offsettable_operand(operands[1],4);
                    405:                           break;
                    406:                      }
                    407: 
                    408:                      latehalf[1] = operands[1];
                    409: 
                    410:                      temp0 = XEXP(XEXP(operands[1],0),0);
                    411:                       if (GET_CODE(temp0) == MULT) {
                    412:                           temp1 = temp0;
                    413:                           temp0 = XEXP(XEXP(operands[1],0),1);
                    414:                      } else {
                    415:                           temp1 = XEXP(XEXP(operands[1],0),1);
                    416:                           if (GET_CODE(temp1) != MULT)
                    417:                                abort();
                    418:                      }
                    419: 
                    420:                      if (GET_CODE(temp0) == MEM)
                    421:                           addreg1 = temp0;
                    422:                      else if (GET_CODE(temp0) == REG)
                    423:                           addreg1 = temp0;
                    424:                      else
                    425:                           abort();
                    426: 
                    427:                      break;
                    428: 
                    429:        case CNSTOP :
                    430:          if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    431:            split_double (operands[1], &operands[1], &latehalf[1]);
                    432:          else if (CONSTANT_P (operands[1]))
                    433:            latehalf[1] = const0_rtx;
                    434:          else abort ();
                    435:          break;
                    436: 
                    437:        case RNDOP  :
                    438:        default     : abort();
                    439:   }
                    440: 
                    441: 
                    442:   /* double the register used for shifting in both of the operands */
                    443:   /* but make sure the same register isn't doubled twice!         */
                    444: 
                    445:   if (shftreg0 && shftreg1 && (rtx_equal_p(shftreg0,shftreg1)))
                    446:        output_asm_insn("addl2 %0,%0", &shftreg0);
                    447:   else {
                    448:        if (shftreg0)
                    449:                output_asm_insn("addl2 %0,%0", &shftreg0);
                    450:        if (shftreg1)
                    451:                output_asm_insn("addl2 %0,%0", &shftreg1);
                    452:   }
                    453: 
                    454:   /* if the destination is a register and that register is needed in  */
                    455:   /* the source addressing mode, swap the order of the moves since we */
                    456:   /* don't want this destroyed til last. If both regs are used, not   */
                    457:   /* much we can do, so abort. If these becomes a problem, maybe we   */
                    458:   /* can do it on the stack?                                         */
                    459: 
                    460:   if (GET_CODE(operands[0])==REG && regisused(operands[1],REGNO(operands[0])))
                    461:        if (regisused(latehalf[1],REGNO(latehalf[0])))
                    462:                8;
                    463:        else
                    464:                dohighfirst++;
                    465: 
                    466:   /* if we're pushing, do the high address part first. */
                    467: 
                    468:   if (dohighfirst) {
                    469: 
                    470:        if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
                    471:                output_asm_insn("addl2 $4,%0", &addreg0);
                    472:        else {
                    473:                if (addreg0)
                    474:                        output_asm_insn("addl2 $4,%0", &addreg0);
                    475:                if (addreg1)
                    476:                        output_asm_insn("addl2 $4,%0", &addreg1);
                    477:        }
                    478: 
                    479:        output_asm_insn(singlemove_string(latehalf), latehalf);
                    480: 
                    481:        if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
                    482:                output_asm_insn("subl2 $4,%0", &addreg0);
                    483:        else {
                    484:                if (addreg0)
                    485:                        output_asm_insn("subl2 $4,%0", &addreg0);
                    486:                if (addreg1)
                    487:                        output_asm_insn("subl2 $4,%0", &addreg1);
                    488:        }
                    489: 
                    490:        return singlemove_string(operands);
                    491:   }
                    492: 
                    493:   output_asm_insn(singlemove_string(operands), operands);
                    494: 
                    495:   if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
                    496:        output_asm_insn("addl2 $4,%0", &addreg0);
                    497:   else {
                    498:        if (addreg0)
                    499:                output_asm_insn("addl2 $4,%0", &addreg0);
                    500:        if (addreg1)
                    501:                output_asm_insn("addl2 $4,%0", &addreg1);
                    502:   }
                    503: 
                    504:   output_asm_insn(singlemove_string(latehalf), latehalf);
                    505: 
                    506:   if (addreg0 && addreg1 && (rtx_equal_p(addreg0,addreg1)))
                    507:        output_asm_insn("subl2 $4,%0", &addreg0);
                    508:   else {
                    509:        if (addreg0)
                    510:                output_asm_insn("subl2 $4,%0", &addreg0);
                    511:        if (addreg1)
                    512:                output_asm_insn("subl2 $4,%0", &addreg1);
                    513:   }
                    514: 
                    515:   if (shftreg0 && shftreg1 && (rtx_equal_p(shftreg0,shftreg1)))
                    516:        output_asm_insn("shar $1,%0,%0", &shftreg0);
                    517:   else {
                    518:        if (shftreg0)
                    519:                output_asm_insn("shar $1,%0,%0", &shftreg0);
                    520:        if (shftreg1)
                    521:                output_asm_insn("shar $1,%0,%0", &shftreg1);
                    522:   }
                    523: 
                    524:   return "";
                    525: }
                    526: 
                    527: 
                    528: /* This checks if a zero_extended cmp[bw] can be replaced by a sign_extended
                    529:    cmp[bw]. This can be done if the operand is a constant that fits in a
                    530:    byte/word or a memory operand. Besides that the next instruction must be an
                    531:    unsigned compare. Some of these tests are done by the machine description */
                    532: 
                    533: int
                    534: tahoe_cmp_check (insn, op, max)
                    535: rtx insn, op; int max;
                    536: {
                    537:     if (GET_CODE (op) == CONST_INT
                    538:        && ( INTVAL (op) < 0 || INTVAL (op) > max ))
                    539:        return 0;
                    540:     {
                    541:        register rtx next = NEXT_INSN (insn);
                    542: 
                    543:        if ((GET_CODE (next) == JUMP_INSN
                    544:           || GET_CODE (next) == INSN
                    545:           || GET_CODE (next) == CALL_INSN))
                    546:            {
                    547:                next = PATTERN (next);
                    548:                if (GET_CODE (next) == SET
                    549:                    && SET_DEST (next) == pc_rtx
                    550:                    && GET_CODE (SET_SRC (next)) == IF_THEN_ELSE)
                    551:                    switch (GET_CODE (XEXP (SET_SRC (next), 0)))
                    552:                        {
                    553:                        case EQ:
                    554:                        case NE:
                    555:                        case LTU:
                    556:                        case GTU:
                    557:                        case LEU:
                    558:                        case GEU:
                    559:                            return 1;
                    560:                        }
                    561:            }
                    562:     }
                    563:     return 0;
                    564: }

unix.superglobalmegacorp.com

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