Annotation of gcc/config/tahoe/tahoe.c, revision 1.1.1.2

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

unix.superglobalmegacorp.com

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