Annotation of gcc/output-m88k.c, revision 1.1.1.3

1.1       root        1: /* Subroutines for insn-output.c for Motorola 88000.
                      2:    Copyright (C) 1987 Free Software Foundation, Inc.
                      3:    Contributed by Michael Tiemann ([email protected])
                      4: 
                      5: This file is part of GNU CC.
                      6: 
                      7: GNU CC is distributed in the hope that it will be useful,
                      8: but WITHOUT ANY WARRANTY.  No author or distributor
                      9: accepts responsibility to anyone for the consequences of using it
                     10: or for whether it serves any particular purpose or works at all,
                     11: unless he says so in writing.  Refer to the GNU CC General Public
                     12: License for full details.
                     13: 
                     14: Everyone is granted permission to copy, modify and redistribute
                     15: GNU CC, but only under the conditions described in the
                     16: GNU CC General Public License.   A copy of this license is
                     17: supposed to have been given to you along with GNU CC so you
                     18: can know your rights and responsibilities.  It should be in a
                     19: file named COPYING.  Among other things, the copyright notice
                     20: and this notice must be preserved on all copies.  */
                     21: 
                     22: #ifndef FILE
                     23: #include <stdio.h>
                     24: #endif
                     25: 
                     26: /* This is where the condition code register lives.  */
                     27: rtx cc0_reg_rtx;
                     28: 
                     29: static rtx find_addr_reg ();
                     30: 
                     31: #if 0
                     32: char *
                     33: output_compare (operands, opcode, exchange_opcode)
                     34:      rtx *operands;
                     35:      char *opcode;
                     36:      char *exchange_opcode;
                     37: {
                     38:   static char buf[40];
                     39:   rtx op1, op2;
                     40: 
                     41:   if (GET_CODE (cc_prev_status.value2) == MINUS)
                     42:     {
                     43:       op1 = XEXP (cc_prev_status.value2, 0);
                     44:       op2 = XEXP (cc_prev_status.value2, 1);
                     45:     }
                     46:   else
                     47:     {
                     48:       op1 = cc_prev_status.value2;
                     49:       op2 = const0_rtx;
                     50:     }
                     51:   if (GET_CODE (op1) == CONST_INT)
                     52:     {
                     53:       operands[2] = op1;
                     54:       operands[1] = op2;
                     55:       opcode = exchange_opcode;
                     56:     }
                     57:   else
                     58:     {
                     59:       operands[1] = op1;
                     60:       operands[2] = op2;
                     61:     }
                     62:   sprintf (buf, "cmp r25,%%1,%%2\n\tbcnd %s,r25,%%l0", opcode);
                     63:   return buf;
                     64: }
                     65: 
                     66: char *
                     67: output_fcompare (operands, opcode, exchange_opcode)
                     68:      rtx *operands;
                     69:      char *opcode;
                     70:      char *exchange_opcode;
                     71: {
                     72:   static char buf[40];
                     73: 
                     74:   rtx op1, op2;
                     75: 
                     76:   if (GET_CODE (cc_prev_status.value2) == MINUS)
                     77:     {
                     78:       op1 = XEXP (cc_prev_status.value2, 0);
                     79:       op2 = XEXP (cc_prev_status.value2, 1);
                     80:     }
                     81:   else
                     82:     {
                     83:       op1 = cc_prev_status.value2;
                     84:       op2 = const0_rtx;
                     85:     }
                     86:   if (GET_CODE (op1) == CONST_DOUBLE)
                     87:     {
                     88:       operands[2] = op1;
                     89:       operands[1] = op2;
                     90:       opcode = exchange_opcode;
                     91:     }
                     92:   else
                     93:     {
                     94:       operands[1] = op1;
                     95:       operands[2] = op2;
                     96:     }
                     97:   sprintf (buf, "cmp r25,%%1,%%2\n\tbcnd %s,r25,%%l0", opcode);
                     98:   return buf;
                     99: }
                    100: 
                    101: char *
                    102: output_store (operands, opcode, exchange_opcode)
                    103:      rtx *operands;
                    104:      char *opcode;
                    105:      char *exchange_opcode;
                    106: {
                    107:   static char buf[40];
                    108:   rtx op1, op2;
                    109: 
                    110:   if (GET_CODE (cc_prev_status.value2) == MINUS)
                    111:     {
                    112:       op1 = XEXP (cc_prev_status.value2, 0);
                    113:       op2 = XEXP (cc_prev_status.value2, 1);
                    114:     }
                    115:   else
                    116:     {
                    117:       op1 = cc_prev_status.value2;
                    118:       op2 = const0_rtx;
                    119:     }
                    120: 
                    121:   if (GET_CODE (op1) == CONST_INT)
                    122:     {
                    123:       operands[2] = op1;
                    124:       operands[1] = op2;
                    125:       opcode = exchange_opcode;
                    126:     }
                    127:   else
                    128:     {
                    129:       operands[1] = op1;
                    130:       operands[2] = op2;
                    131:     }
                    132: 
                    133:   sprintf (buf, "cmp r25,%%1,%%2\n\textu %%0,r25,1<%s>", opcode);
                    134:   return buf;
                    135: }
                    136: #endif
                    137: 
                    138: /* Nonzero if OP is a valid second operand for an arithmetic insn.  */
                    139: 
                    140: int
                    141: arith_operand (op, mode)
                    142:      rtx op;
                    143:      enum machine_mode mode;
                    144: {
                    145:   return (register_operand (op, mode)
                    146:          || (GET_CODE (op) == CONST_INT
                    147:              && (unsigned) INTVAL (op) < 0x10000));
                    148: }
                    149: 
                    150: int
                    151: arith32_operand (op, mode)
                    152:      rtx op;
                    153:      enum machine_mode mode;
                    154: {
                    155:   return (register_operand (op, mode) || GET_CODE (op) == CONST_INT);
                    156: }
                    157: 
                    158: int
                    159: int5_operand (op, mode)
                    160:      rtx op;
                    161:      enum machine_mode mode;
                    162: {
                    163:   return (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x20);
                    164: }
                    165: 
                    166: /* Return the best assembler insn template
                    167:    for moving operands[1] into operands[0] as a fullword.  */
                    168: 
                    169: static char *
                    170: singlemove_string (operands)
                    171:      rtx *operands;
                    172: {
                    173:   if (GET_CODE (operands[0]) == MEM)
                    174:     return "st %r1,%0";
                    175:   if (GET_CODE (operands[1]) == MEM)
                    176:     return "ld %0,%1";
                    177:   return "or %0,r0,%1";
                    178: }
                    179: 
                    180: /* Output assembler code to perform a doubleword move insn
                    181:    with operands OPERANDS.  */
                    182: 
                    183: char *
                    184: output_move_double (operands)
                    185:      rtx *operands;
                    186: {
                    187:   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
                    188:   rtx latehalf[2];
                    189:   rtx addreg0 = 0, addreg1 = 0;
                    190: 
                    191:   /* First classify both operands.  */
                    192: 
                    193:   if (REG_P (operands[0]))
                    194:     optype0 = REGOP;
                    195:   else if (offsetable_memref_p (operands[0]))
                    196:     optype0 = OFFSOP;
                    197:   else if (GET_CODE (operands[0]) == MEM)
                    198:     optype0 = MEMOP;
                    199:   else
                    200:     optype0 = RNDOP;
                    201: 
                    202:   if (REG_P (operands[1]))
                    203:     optype1 = REGOP;
                    204:   else if (CONSTANT_P (operands[1])
                    205:           || GET_CODE (operands[1]) == CONST_DOUBLE)
                    206:     optype1 = CNSTOP;
                    207:   else if (offsetable_memref_p (operands[1]))
                    208:     optype1 = OFFSOP;
                    209:   else if (GET_CODE (operands[1]) == MEM)
1.1.1.2   root      210:     optype1 = MEMOP;
1.1       root      211:   else
                    212:     optype1 = RNDOP;
                    213: 
                    214:   /* Check for the cases that the operand constraints are not
                    215:      supposed to allow to happen.  Abort if we get one,
                    216:      because generating code for these cases is painful.  */
                    217: 
                    218:   if (optype0 == RNDOP || optype1 == RNDOP)
                    219:     abort ();
                    220: 
                    221:   /* If an operand is an unoffsettable memory ref, find a register
                    222:      we can increment temporarily to make it refer to the second word.  */
                    223: 
                    224:   if (optype0 == MEMOP)
                    225:     addreg0 = find_addr_reg (operands[0]);
                    226: 
                    227:   if (optype1 == MEMOP)
                    228:     addreg1 = find_addr_reg (operands[1]);
                    229: 
                    230:   /* Ok, we can do one word at a time.
                    231:      Normally we do the low-numbered word first,
                    232:      but if either operand is autodecrementing then we
                    233:      do the high-numbered word first.
                    234: 
                    235:      In either case, set up in LATEHALF the operands to use
                    236:      for the high-numbered word and in some cases alter the
                    237:      operands in OPERANDS to be suitable for the low-numbered word.  */
                    238: 
                    239:   if (optype0 == REGOP)
                    240:     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
                    241:   else if (optype0 == OFFSOP)
                    242:     latehalf[0] = adj_offsetable_operand (operands[0], 4);
                    243:   else
                    244:     latehalf[0] = operands[0];
                    245: 
                    246:   if (optype1 == REGOP)
                    247:     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
                    248:   else if (optype1 == OFFSOP)
                    249:     latehalf[1] = adj_offsetable_operand (operands[1], 4);
                    250:   else if (optype1 == CNSTOP)
                    251:     {
                    252:       if (CONSTANT_P (operands[1]))
                    253:        latehalf[1] = const0_rtx;
                    254:       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
                    255:        {
1.1.1.3 ! root      256:          latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
        !           257:                                 CONST_DOUBLE_HIGH (operands[1]));
        !           258:          operands[1] = gen_rtx (CONST_INT, VOIDmode,
        !           259:                                 CONST_DOUBLE_LOW (operands[1]));
1.1       root      260:        }
                    261:     }
                    262:   else
                    263:     latehalf[1] = operands[1];
                    264: 
                    265:   /* If the first move would clobber the source of the second one,
                    266:      do them in the other order.  This happens only for registers;
                    267:      such overlap can't happen in memory unless the user explicitly
                    268:      sets it up, and that is an undefined circumstance.  */
                    269: 
                    270:   if (optype0 == REGOP && optype1 == REGOP
                    271:       && REGNO (operands[0]) == REGNO (latehalf[1]))
                    272:     {
                    273:       /* Make any unoffsetable addresses point at high-numbered word.  */
                    274:       if (addreg0)
                    275:        output_asm_insn ("addu %0,%0,4", &addreg0);
                    276:       if (addreg1)
                    277:        output_asm_insn ("addu %0,%0,4", &addreg1);
                    278: 
                    279:       /* Do that word.  */
                    280:       output_asm_insn (singlemove_string (latehalf), latehalf);
                    281: 
                    282:       /* Undo the adds we just did.  */
                    283:       if (addreg0)
                    284:        output_asm_insn ("subu %0,%0,4", &addreg0);
                    285:       if (addreg1)
                    286:        output_asm_insn ("subu %0,%0,4", &addreg0);
                    287: 
                    288:       /* Do low-numbered word.  */
                    289:       return singlemove_string (operands);
                    290:     }
                    291: 
                    292:   /* Normal case: do the two words, low-numbered first.  */
                    293: 
                    294:   output_asm_insn (singlemove_string (operands), operands);
                    295: 
                    296:   /* Make any unoffsetable addresses point at high-numbered word.  */
                    297:   if (addreg0)
                    298:     output_asm_insn ("addu %0,%0,4", &addreg0);
                    299:   if (addreg1)
                    300:     output_asm_insn ("addu %0,%0,4", &addreg1);
                    301: 
                    302:   /* Do that word.  */
                    303:   output_asm_insn (singlemove_string (latehalf), latehalf);
                    304: 
                    305:   /* Undo the adds we just did.  */
                    306:   if (addreg0)
                    307:     output_asm_insn ("subu %0,%0,4", &addreg0);
                    308:   if (addreg1)
                    309:     output_asm_insn ("subu %0,%0,4", &addreg1);
                    310: 
                    311:   return "";
                    312: }
                    313: 
                    314: /* Return a REG that occurs in ADDR with coefficient 1.
                    315:    ADDR can be effectively incremented by incrementing REG.  */
                    316: 
                    317: static rtx
                    318: find_addr_reg (addr)
                    319:      rtx addr;
                    320: {
                    321:   while (GET_CODE (addr) == PLUS)
                    322:     {
                    323:       if (GET_CODE (XEXP (addr, 0)) == REG)
                    324:        addr = XEXP (addr, 0);
                    325:       if (GET_CODE (XEXP (addr, 1)) == REG)
                    326:        addr = XEXP (addr, 1);
                    327:       if (CONSTANT_P (XEXP (addr, 0)))
                    328:        addr = XEXP (addr, 1);
                    329:       if (CONSTANT_P (XEXP (addr, 1)))
                    330:        addr = XEXP (addr, 0);
                    331:     }
                    332:   if (GET_CODE (addr) == REG)
                    333:     return addr;
                    334:   return 0;
                    335: }
                    336: 
                    337: /* Output an ascii string.  */
                    338: output_ascii (file, p, size)
                    339:      FILE *file;
                    340:      char *p;
                    341:      int size;
                    342: {
                    343:   int i;
                    344: 
                    345:   fprintf (file, "\tstring \"");
                    346: 
                    347:   for (i = 0; i < size; i++)
                    348:     {
                    349:       register int c = p[i];
                    350:       if (c == '\"' || c == '\\')
                    351:        putc ('\\', file);
                    352:       if (c >= ' ' && c < 0177)
                    353:        putc (c, file);
                    354:       else
                    355:        {
                    356:          fprintf (file, "\\%03o", c);
                    357:          /* After an octal-escape, if a digit follows,
                    358:             terminate one string constant and start another.
                    359:             The Vax assembler fails to stop reading the escape
                    360:             after three digits, so this is the only way we
                    361:             can get it to parse the data properly.  */
                    362:          if (i < size - 1 && p[i + 1] >= '0' && p[i + 1] <= '9')
                    363:            fprintf (file, "\"\n\tstring \"");
                    364:        }
                    365:     }
                    366:   fprintf (file, "\"\n");
                    367: }
                    368: 
                    369: void
                    370: output_load_address (operands)
                    371:      rtx *operands;
                    372: {
                    373:   rtx base, offset;
                    374: 
                    375:   if (CONSTANT_P (operands[3]))
                    376:     {
                    377:       output_asm_insn ("lda %0,%3", operands);
                    378:       return;
                    379:     }
                    380: 
                    381:   if (REG_P (operands[3]))
                    382:     {
                    383:       if (REGNO (operands[0]) != REGNO (operands[3]))
                    384:        output_asm_insn ("or %0,r0,%3", operands);
                    385:       return;
                    386:     }
                    387: 
                    388:   base = XEXP (operands[3], 0);
                    389:   offset = XEXP (operands[3], 1);
                    390: 
                    391:   if (GET_CODE (base) == CONST_INT)
                    392:     {
                    393:       rtx tmp = base;
                    394:       base = offset;
                    395:       offset = tmp;
                    396:     }
                    397: 
                    398:   if (GET_CODE (offset) != CONST_INT)
                    399:     abort ();
                    400: 
                    401:   operands[6] = base;
                    402:   operands[7] = offset;
                    403: 
                    404:   if (REG_P (base))
                    405:     if (FITS_16_BITS (offset))
                    406:       output_asm_insn ("addu %0,%6,%7", operands);
                    407:     else if (INT_FITS_16_BITS (- INTVAL (offset)))
                    408:       output_asm_insn ("subu %0,%6,%7", operands);
                    409:     else
                    410:       output_asm_insn ("or.h %0,r0,hi16(%7)\n\tor %0,%0,lo16(%7)\n\tadd %0,%6,%0", operands);
                    411:   else
                    412:     {
                    413:       if (GET_CODE (base) == MULT)
                    414:        if (GET_MODE (base) == QImode)
                    415:          output_asm_insn ("lda.b %0,%6");
                    416:        else if (GET_MODE (base) == HImode)
                    417:          output_asm_insn ("lda.h %0,%6");
                    418:        else if (GET_MODE (base) == SImode)
                    419:          output_asm_insn ("lda %0,%6");
                    420:        else
                    421:          output_asm_insn ("lda.d %0,%6");
                    422:       else
                    423:        output_asm_insn ("lda %0,%6");
                    424: 
                    425:       if (FITS_16_BITS (offset))
                    426:        output_asm_insn ("addu %0,%7,%0", operands);
                    427:       else if (INT_FITS_16_BITS (- INTVAL (offset)))
                    428:        output_asm_insn ("subu %0,%7,%0", operands);
                    429:       else
                    430:        output_asm_insn ("or.h r25,r0,hi16(%7)\n\tor r25,r0,lo16(%7)\n\taddu %0,%0r25", operands);
                    431:     }
                    432: }
                    433: 
                    434: char *
                    435: output_block_move (operands)
                    436:      rtx *operands;
                    437: {
                    438:   static int movstrsi_label = 0;
                    439:   int align = 4;
                    440: 
                    441:   rtx xoperands[9];
                    442:   int available[3];
                    443:   int i, j;
                    444: 
                    445:   /* Since we clobber untold things, nix the condition codes.  */
                    446:   CC_STATUS_INIT;
                    447: 
                    448:   /* Get past the MEMs.  */
                    449:   operands[0] = XEXP (operands[0], 0);
                    450:   operands[1] = XEXP (operands[1], 0);
                    451: 
                    452:   xoperands[0] = 0;
                    453:   xoperands[1] = 0;
                    454:   xoperands[2] = 0;
                    455: 
                    456:   available[0] = 1;
                    457:   available[1] = 1;
                    458:   available[2] = 1;
                    459: #if 1
                    460:   /* Prepare to juggle registers if necessary.  */
                    461:   if (REG_P (operands[0]) && (unsigned) (REGNO (operands[0]) - 10) < 3)
                    462:     {
                    463:       xoperands[0] = operands[0];
                    464:       available[REGNO (operands[0]) - 10] = 0;
                    465:     }
                    466:   if (REG_P (operands[1]) && (unsigned) (REGNO (operands[1]) - 10) < 3)
                    467:     {
                    468:       xoperands[1] = operands[1];
                    469:       available[REGNO (operands[1]) - 10] = 0;
                    470:     }
                    471:   if (REG_P (operands[2]) && (unsigned) (REGNO (operands[2]) - 10) < 3)
                    472:     {
                    473:       xoperands[2] = operands[2];
                    474:       available[REGNO (operands[2]) - 10] = 0;
                    475:     }
                    476:   for (i = 0; i < 3; i++)
                    477:     {
                    478:       if (xoperands[i])
                    479:        continue;
                    480:       if (available[0])
                    481:        {
                    482:          xoperands[i] = gen_rtx (REG, SImode, 10);
                    483:          available[0] = 0;
                    484:          continue;
                    485:        }
                    486:       if (available[1])
                    487:        {
                    488:          xoperands[i] = gen_rtx (REG, SImode, 11);
                    489:          available[1] = 0;
                    490:          continue;
                    491:        }
                    492:       xoperands[i] = gen_rtx (REG, SImode, 12);
                    493:       available[2] = 0;
                    494:     }
                    495: #endif
                    496: 
                    497:   /* First, figure out best alignment we may assume.  */
                    498:   if (REG_P (operands[2]))
                    499:     {
                    500:       xoperands[5] = operands[2];
                    501:       output_asm_insn ("sub %5,%2,1", xoperands);
                    502:       align = 1;
                    503:     }
                    504:   else
                    505:     {
                    506:       int i = INTVAL (operands[2]);
                    507: 
                    508:       if (i & 1)
                    509:        align = 1;
                    510:       else if (i & 3)
                    511:        {
                    512:          align = 2;
                    513:          i >>= 1;
                    514:        }
                    515:       else
                    516:        i >>= 2;
                    517: 
                    518:       /* predecrement count.  */
                    519:       i -= 1;
                    520:       if (i < 0) abort ();
                    521: 
                    522:       xoperands[5] = gen_rtx (CONST_INT, VOIDmode, i);
                    523: 
                    524:       if (INT_FITS_16_BITS (i))
                    525:        output_asm_insn ("addu %2,r0,%5", xoperands);
                    526:       else if (INT_FITS_16_BITS (-i))
                    527:        {
                    528:          xoperands[5] = gen_rtx (CONST_INT, VOIDmode, -i);
                    529:          output_asm_insn ("subu %2,r0,%5", xoperands);
                    530:        }
                    531:       else
                    532:        output_asm_insn ("or.u %2,r0,hi16(%5)\n\tor %2,%2,lo16(%5)", xoperands);
                    533:     }
                    534:   /* Now, set up for pipelined operation: dest must contain
                    535:      a pre-incremented address, because its index is pre-decremented.  */
                    536: 
                    537:   xoperands[3] = plus_constant (operands[0], align);
                    538:   output_load_address (xoperands);
                    539: 
                    540:   xoperands[4] = operands[1];
                    541:   output_load_address (xoperands+1);
                    542: 
                    543:   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
                    544: 
                    545:   if (align == 4)
                    546:     output_asm_insn ("\n@Lm%3:\n\tld r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst r25,%0[%2]", xoperands);
                    547:   else if (align == 2)
                    548:     output_asm_insn ("\n@Lm%3:\n\tld.h r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst.h r25,%0[%2]", xoperands);
                    549:   else
                    550:     output_asm_insn ("\n@Lm%3:\n\tld.b r25,%1[%2]\n\tsubu %2,%2,1\n\tbcnd.n ge0,%2,@Lm%3\n\tst.b r25,%0[%2]", xoperands);
                    551:   return "";
                    552: }
                    553: 
                    554: char *
                    555: output_store_const_int (mode, operands)
                    556:      enum machine_mode mode;
                    557:      rtx *operands;
                    558: {
                    559:   int i = INTVAL (operands[1]);
                    560:   if (INT_FITS_16_BITS (i))
                    561:     return "addu %0,r0,%1";
                    562:   if (INT_FITS_16_BITS (-i))
                    563:     {
                    564:       operands[1] = gen_rtx (CONST_INT, VOIDmode, -i);
                    565:       return "subu %0,r0,%1";
                    566:     }
                    567:   if ((i & 0xffff) == 0)
                    568:     return "or.u %0,r0,hi16(%1)";
                    569:   /* Could check to see if number is a contiguous field
                    570:      of 1's.  Then we could use the SET instruction.  */
                    571:   if (mode == HImode)
                    572:     {
                    573:       warning ("truncating constant `%d' to fit in half-word", INTVAL (operands[1]));
                    574:       return "or %0,r0,lo16(%1)";
                    575:     }
                    576:   if (mode == QImode)
                    577:     {
                    578:       warning ("truncating constant `%d' to fit in byte");
                    579:       operands[1] = gen_rtx (CONST_INT, VOIDmode, i & 0xff);
                    580:       return "or %0,r0,%1";
                    581:     }
                    582: 
                    583:   return "or.u %0,r0,hi16(%1)\n\tor %0,%0,lo16(%1)";
                    584: }
                    585: 
                    586: /* This routine assumes that floating point numbers are represented
                    587:    in a manner which is consistent between host and target machines.  */
                    588: char *
                    589: output_store_const_float (mode, operands)
                    590:      enum machine_mode mode;
                    591:      rtx *operands;
                    592: {
                    593:   int i = INTVAL (operands[1]);
                    594:   if (INT_FITS_16_BITS (i))
                    595:     return "addu %0,r0,%1";
                    596:   if (INT_FITS_16_BITS (-i))
                    597:     {
                    598:       operands[1] = gen_rtx (CONST_INT, VOIDmode, -i);
                    599:       return "subu %0,r0,%1";
                    600:     }
                    601:   if ((i & 0xffff) == 0)
                    602:     return "or.u %0,r0,hi16(%1)";
                    603:   /* Could check to see if number is a contiguous field
                    604:      of 1's.  Then we could use the SET instruction.  */
                    605:   return "or.u %0,r0,hi16(%1)\n\tor %0,%0,lo16(%1)";
                    606: }

unix.superglobalmegacorp.com

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