|
|
1.1 ! root 1: /* Subroutines for assembler code output on the NS32000. ! 2: Copyright (C) 1988 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU CC. ! 5: ! 6: GNU CC is free software; you can redistribute it and/or modify ! 7: it under the terms of the GNU General Public License as published by ! 8: the Free Software Foundation; either version 1, or (at your option) ! 9: any later version. ! 10: ! 11: GNU CC is distributed in the hope that it will be useful, ! 12: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: GNU General Public License for more details. ! 15: ! 16: You should have received a copy of the GNU General Public License ! 17: along with GNU CC; see the file COPYING. If not, write to ! 18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 19: ! 20: /* Some output-actions in ns32k.md need these. */ ! 21: #include <stdio.h> ! 22: extern FILE *asm_out_file; ! 23: ! 24: #define FP_REG_P(X) (GET_CODE (X) == REG && REGNO (X) > 7 && REGNO (X) < 16) ! 25: ! 26: /* Generate the rtx that comes from an address expression in the md file */ ! 27: /* The expression to be build is BASE[INDEX:SCALE]. To recognize this, ! 28: scale must be converted from an exponent (from ASHIFT) to a ! 29: muliplier (for MULT). */ ! 30: rtx ! 31: gen_indexed_expr (base, index, scale) ! 32: rtx base, index, scale; ! 33: { ! 34: rtx addr; ! 35: ! 36: /* This generates an illegal addressing mode, if BASE is ! 37: fp or sp. This is handled by PRINT_OPERAND_ADDRESS. */ ! 38: if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT) ! 39: base = gen_rtx (MEM, SImode, base); ! 40: addr = gen_rtx (MULT, SImode, index, ! 41: gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale))); ! 42: addr = gen_rtx (PLUS, SImode, base, addr); ! 43: return addr; ! 44: } ! 45: ! 46: /* Return 1 if OP is a valid constant int. These can be modeless ! 47: (void mode), so we do not mess with their modes. ! 48: ! 49: The main use of this function is as a predicate in match_operand ! 50: expressions in the machine description. */ ! 51: ! 52: int ! 53: const_int (op, mode) ! 54: register rtx op; ! 55: enum machine_mode mode; ! 56: { ! 57: return (GET_CODE (op) == CONST_INT); ! 58: } ! 59: ! 60: /* Return 1 if OP is a valid operand of mode MODE. This ! 61: predicate rejects operands which do not have a mode ! 62: (such as CONST_INT which are VOIDmode). */ ! 63: int ! 64: reg_or_mem_operand (op, mode) ! 65: register rtx op; ! 66: enum machine_mode mode; ! 67: { ! 68: return (GET_MODE (op) == mode ! 69: && (GET_CODE (op) == REG ! 70: || GET_CODE (op) == SUBREG ! 71: || GET_CODE (op) == MEM)); ! 72: } ! 73: ! 74: /* Return the best assembler insn template ! 75: for moving operands[1] into operands[0] as a fullword. */ ! 76: ! 77: static char * ! 78: singlemove_string (operands) ! 79: rtx *operands; ! 80: { ! 81: if (GET_CODE (operands[1]) == CONST_INT ! 82: && INTVAL (operands[1]) <= 7 ! 83: && INTVAL (operands[1]) >= -8) ! 84: return "movqd %1,%0"; ! 85: return "movd %1,%0"; ! 86: } ! 87: ! 88: char * ! 89: output_move_double (operands) ! 90: rtx *operands; ! 91: { ! 92: enum anon1 { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1; ! 93: rtx latehalf[2]; ! 94: ! 95: /* First classify both operands. */ ! 96: ! 97: if (REG_P (operands[0])) ! 98: optype0 = REGOP; ! 99: else if (offsettable_memref_p (operands[0])) ! 100: optype0 = OFFSOP; ! 101: else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) ! 102: optype0 = POPOP; ! 103: else ! 104: optype0 = RNDOP; ! 105: ! 106: if (REG_P (operands[1])) ! 107: optype1 = REGOP; ! 108: else if (CONSTANT_ADDRESS_P (operands[1]) ! 109: || GET_CODE (operands[1]) == CONST_DOUBLE) ! 110: optype1 = CNSTOP; ! 111: else if (offsettable_memref_p (operands[1])) ! 112: optype1 = OFFSOP; ! 113: else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) ! 114: optype1 = POPOP; ! 115: else ! 116: optype1 = RNDOP; ! 117: ! 118: /* Check for the cases that the operand constraints are not ! 119: supposed to allow to happen. Abort if we get one, ! 120: because generating code for these cases is painful. */ ! 121: ! 122: if (optype0 == RNDOP || optype1 == RNDOP) ! 123: abort (); ! 124: ! 125: /* Ok, we can do one word at a time. ! 126: Normally we do the low-numbered word first, ! 127: but if either operand is autodecrementing then we ! 128: do the high-numbered word first. ! 129: ! 130: In either case, set up in LATEHALF the operands to use ! 131: for the high-numbered word and in some cases alter the ! 132: operands in OPERANDS to be suitable for the low-numbered word. */ ! 133: ! 134: if (optype0 == REGOP) ! 135: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 136: else if (optype0 == OFFSOP) ! 137: latehalf[0] = adj_offsettable_operand (operands[0], 4); ! 138: else ! 139: latehalf[0] = operands[0]; ! 140: ! 141: if (optype1 == REGOP) ! 142: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 143: else if (optype1 == OFFSOP) ! 144: latehalf[1] = adj_offsettable_operand (operands[1], 4); ! 145: else if (optype1 == CNSTOP) ! 146: { ! 147: if (CONSTANT_ADDRESS_P (operands[1])) ! 148: latehalf[1] = const0_rtx; ! 149: else if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 150: { ! 151: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, ! 152: CONST_DOUBLE_HIGH (operands[1])); ! 153: operands[1] = gen_rtx (CONST_INT, VOIDmode, ! 154: CONST_DOUBLE_LOW (operands[1])); ! 155: } ! 156: } ! 157: else ! 158: latehalf[1] = operands[1]; ! 159: ! 160: /* If one or both operands autodecrementing, ! 161: do the two words, high-numbered first. */ ! 162: ! 163: if (optype0 == POPOP || optype1 == POPOP) ! 164: { ! 165: output_asm_insn (singlemove_string (latehalf), latehalf); ! 166: return singlemove_string (operands); ! 167: } ! 168: ! 169: /* Not autodecrementing. Do the two words, low-numbered first. */ ! 170: ! 171: output_asm_insn (singlemove_string (operands), operands); ! 172: ! 173: operands[0] = latehalf[0]; ! 174: operands[1] = latehalf[1]; ! 175: return singlemove_string (operands); ! 176: } ! 177: ! 178: int ! 179: check_reg (oper, reg) ! 180: rtx oper; ! 181: int reg; ! 182: { ! 183: register int i; ! 184: ! 185: if (oper == 0) ! 186: return 0; ! 187: switch (GET_CODE(oper)) ! 188: { ! 189: case REG: ! 190: return (REGNO(oper) == reg) ? 1 : 0; ! 191: case MEM: ! 192: return check_reg(XEXP(oper, 0), reg); ! 193: case PLUS: ! 194: case MULT: ! 195: return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg); ! 196: } ! 197: return 0; ! 198: } ! 199: ! 200: /* PRINT_OPERAND_ADDRESS is defined to call this function, ! 201: which is easier to debug than putting all the code in ! 202: a macro definition in tm-ns32k.h . */ ! 203: ! 204: /* Nonzero if we have printed a base register. ! 205: If zero, on some systems, it means `(sb)' must be printed. */ ! 206: int paren_base_reg_printed = 0; ! 207: ! 208: print_operand_address (file, addr) ! 209: register FILE *file; ! 210: register rtx addr; ! 211: { ! 212: register rtx reg1, reg2, breg, ireg; ! 213: rtx offset; ! 214: static char scales[] = { 'b', 'w', 'd', 0, 'q', }; ! 215: ! 216: retry: ! 217: switch (GET_CODE (addr)) ! 218: { ! 219: case MEM: ! 220: addr = XEXP (addr, 0); ! 221: if (GET_CODE (addr) == REG) ! 222: if (REGNO (addr) == STACK_POINTER_REGNUM) ! 223: { fprintf (file, "tos"); break; } ! 224: else ! 225: { fprintf (file, "%s", reg_names[REGNO (addr)]); break; } ! 226: else if (CONSTANT_P (addr)) ! 227: { output_addr_const (file, addr); break; } ! 228: else if (GET_CODE (addr) == MULT) ! 229: { fprintf (file, "@0"); ireg = addr; goto print_index; } ! 230: else if (GET_CODE (addr) == MEM) ! 231: { ! 232: addr = XEXP (addr, 0); ! 233: if (GET_CODE (addr) == PLUS) ! 234: { ! 235: offset = XEXP (addr, 1); ! 236: addr = XEXP (addr, 0); ! 237: } ! 238: else ! 239: { ! 240: offset = const0_rtx; ! 241: } ! 242: output_addr_const (file, offset); ! 243: fprintf (file, "(%s)", reg_names[REGNO (addr)]); ! 244: break; ! 245: } ! 246: ! 247: if (GET_CODE (addr) != PLUS) ! 248: abort (); ! 249: ! 250: goto retry; ! 251: ! 252: case REG: ! 253: if (REGNO (addr) == STACK_POINTER_REGNUM) ! 254: fprintf (file, "tos"); ! 255: else ! 256: fprintf (file, "0(%s)", reg_names[REGNO (addr)]); ! 257: break; ! 258: ! 259: case PRE_DEC: ! 260: case POST_INC: ! 261: fprintf (file, "tos"); ! 262: break; ! 263: ! 264: case MULT: ! 265: fprintf (file, "@0"); ! 266: ireg = addr; /* [rX:Y] */ ! 267: goto print_index; ! 268: break; ! 269: ! 270: case PLUS: ! 271: reg1 = 0; reg2 = 0; ! 272: ireg = 0; breg = 0; ! 273: offset = const0_rtx; ! 274: if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) ! 275: { ! 276: offset = XEXP (addr, 0); ! 277: addr = XEXP (addr, 1); ! 278: } ! 279: else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) ! 280: { ! 281: offset = XEXP (addr, 1); ! 282: addr = XEXP (addr, 0); ! 283: } ! 284: if (GET_CODE (addr) != PLUS) ; ! 285: else if (GET_CODE (XEXP (addr, 0)) == MULT) ! 286: { ! 287: reg1 = XEXP (addr, 0); ! 288: addr = XEXP (addr, 1); ! 289: } ! 290: else if (GET_CODE (XEXP (addr, 1)) == MULT) ! 291: { ! 292: reg1 = XEXP (addr, 1); ! 293: addr = XEXP (addr, 0); ! 294: } ! 295: /* The case for memory is somewhat tricky: to get ! 296: a MEM here, the only RTX formats that could ! 297: get here are either (modulo commutativity) ! 298: (PLUS (PLUS (REG *MEM)) CONST) -or- ! 299: (PLUS (PLUS (CONST REG/MULT)) *MEM) ! 300: We take advantage of that knowledge here. */ ! 301: else if (GET_CODE (XEXP (addr, 0)) == MEM ! 302: || GET_CODE (XEXP (addr, 1)) == MEM) ! 303: { ! 304: rtx temp; ! 305: ! 306: if (GET_CODE (XEXP (addr, 0)) == MEM) ! 307: { ! 308: temp = XEXP (addr, 1); ! 309: addr = XEXP (addr, 0); ! 310: } ! 311: else ! 312: { ! 313: temp = XEXP (addr, 0); ! 314: addr = XEXP (addr, 1); ! 315: } ! 316: ! 317: if (GET_CODE (temp) == REG) ! 318: { ! 319: reg1 = temp; ! 320: } ! 321: else ! 322: { ! 323: if (GET_CODE (temp) != PLUS) ! 324: abort (); ! 325: ! 326: if (GET_CODE (XEXP (temp, 0)) == MULT) ! 327: { ! 328: reg1 = XEXP (temp, 0); ! 329: offset = XEXP (temp, 1); ! 330: } ! 331: if (GET_CODE (XEXP (temp, 1)) == MULT) ! 332: { ! 333: reg1 = XEXP (temp, 1); ! 334: offset = XEXP (temp, 0); ! 335: } ! 336: else ! 337: abort (); ! 338: } ! 339: } ! 340: else if (GET_CODE (XEXP (addr, 0)) == REG ! 341: || GET_CODE (XEXP (addr, 1)) == REG) ! 342: { ! 343: rtx temp; ! 344: ! 345: if (GET_CODE (XEXP (addr, 0)) == REG) ! 346: { ! 347: temp = XEXP (addr, 0); ! 348: addr = XEXP (addr, 1); ! 349: } ! 350: else ! 351: { ! 352: temp = XEXP (addr, 1); ! 353: addr = XEXP (addr, 0); ! 354: } ! 355: ! 356: if (GET_CODE (addr) == REG) ! 357: { ! 358: if (REGNO (temp) >= FRAME_POINTER_REGNUM) ! 359: { reg1 = addr; addr = temp; } ! 360: else ! 361: { reg1 = temp; } ! 362: } ! 363: else if (CONSTANT_P (addr)) ! 364: { ! 365: if (GET_CODE (offset) == CONST_INT ! 366: && INTVAL (offset)) ! 367: offset = plus_constant (addr, INTVAL (offset)); ! 368: addr = temp; ! 369: } ! 370: else if (GET_CODE (addr) != PLUS) ! 371: abort (); ! 372: else ! 373: { ! 374: if (CONSTANT_ADDRESS_P (XEXP (addr, 0))) ! 375: { ! 376: offset = XEXP (addr, 0); ! 377: addr = XEXP (addr, 1); ! 378: } ! 379: else if (CONSTANT_ADDRESS_P (XEXP (addr, 1))) ! 380: { ! 381: offset = XEXP (addr, 1); ! 382: addr = XEXP (addr, 0); ! 383: } ! 384: else abort (); ! 385: ! 386: if (GET_CODE (addr) == REG) ! 387: { ! 388: if (REGNO (temp) >= FRAME_POINTER_REGNUM) ! 389: { reg1 = addr; addr = temp; } ! 390: else ! 391: { reg1 = temp; } ! 392: } ! 393: else ! 394: reg1 = temp; ! 395: } ! 396: } ! 397: ! 398: if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT) ! 399: { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; } ! 400: if (addr != 0) ! 401: { ! 402: if (CONSTANT_P (addr) && reg1) ! 403: { ! 404: /* OFFSET comes second, to prevent outputting ! 405: operands of the form INT+SYMBOL+INT. ! 406: The Genix assembler dies on them. */ ! 407: output_addr_const (file, addr); ! 408: if (offset != const0_rtx) ! 409: { ! 410: putc ('+', file); ! 411: output_addr_const (file, offset); ! 412: } ! 413: ireg = reg1; ! 414: goto print_index; ! 415: } ! 416: else if (GET_CODE (addr) != MEM) ! 417: abort (); ! 418: ! 419: output_addr_const (file, offset); ! 420: #ifndef SEQUENT_ADDRESS_BUG ! 421: putc ('(', file); ! 422: paren_base_reg_printed = 0; ! 423: output_address (addr); ! 424: #ifdef SEQUENT_BASE_REGS ! 425: if (!paren_base_reg_printed) ! 426: fprintf (file, "(sb)"); ! 427: #endif ! 428: putc (')', file); ! 429: #else /* SEQUENT_ADDRESS_BUG */ ! 430: if ((GET_CODE (offset) == SYMBOL_REF ! 431: || GET_CODE (offset) == CONST) ! 432: && GET_CODE (addr) == REG) ! 433: { ! 434: if (reg1) abort (); ! 435: fprintf (file, "[%s:b]", reg_names[REGNO (addr)]); ! 436: } ! 437: else ! 438: { ! 439: putc ('(', file); ! 440: paren_base_reg_printed = 0; ! 441: output_address (addr); ! 442: #ifdef SEQUENT_BASE_REGS ! 443: if (!paren_base_reg_printed) ! 444: fprintf (file, "(sb)"); ! 445: #endif ! 446: putc (')', file); ! 447: } ! 448: #endif /* SEQUENT_ADDRESS_BUG */ ! 449: ireg = reg1; ! 450: goto print_index; ! 451: } ! 452: else addr = offset; ! 453: if (reg1 && GET_CODE (reg1) == MULT) ! 454: { breg = reg2; ireg = reg1; } ! 455: else if (reg2 && GET_CODE (reg2) == MULT) ! 456: { breg = reg1; ireg = reg2; } ! 457: else if (reg2 || GET_CODE (addr) == MEM) ! 458: { breg = reg2; ireg = reg1; } ! 459: else ! 460: { breg = reg1; ireg = reg2; } ! 461: if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF) ! 462: { ! 463: int scale; ! 464: if (GET_CODE (ireg) == MULT) ! 465: { ! 466: scale = INTVAL (XEXP (ireg, 1)) >> 1; ! 467: ireg = XEXP (ireg, 0); ! 468: } ! 469: else scale = 0; ! 470: output_asm_label (addr); ! 471: fprintf (file, "[%s:%c]", ! 472: reg_names[REGNO (ireg)], scales[scale]); ! 473: break; ! 474: } ! 475: if (ireg && breg && offset == const0_rtx) ! 476: fprintf (file, "0(%s)", reg_names[REGNO (breg)]); ! 477: else ! 478: { ! 479: if (addr != 0) ! 480: { ! 481: if (ireg != 0 && breg == 0 ! 482: && GET_CODE (offset) == CONST_INT) putc('@', file); ! 483: output_addr_const (file, offset); ! 484: } ! 485: if (breg != 0) ! 486: { ! 487: if (GET_CODE (breg) != REG) abort (); ! 488: #ifndef SEQUENT_ADDRESS_BUG ! 489: fprintf (file, "(%s)", reg_names[REGNO (breg)]); ! 490: paren_base_reg_printed = -1; ! 491: #else ! 492: if (GET_CODE (offset) == SYMBOL_REF || GET_CODE (offset) == CONST) ! 493: { ! 494: if (ireg) abort (); ! 495: fprintf (file, "[%s:b]", reg_names[REGNO (breg)]); ! 496: } ! 497: else ! 498: { ! 499: fprintf (file, "(%s)", reg_names[REGNO (breg)]); ! 500: paren_base_reg_printed = -1; ! 501: } ! 502: #endif ! 503: } ! 504: } ! 505: print_index: ! 506: if (ireg != 0) ! 507: { ! 508: int scale; ! 509: if (GET_CODE (ireg) == MULT) ! 510: { ! 511: scale = INTVAL (XEXP (ireg, 1)) >> 1; ! 512: ireg = XEXP (ireg, 0); ! 513: } ! 514: else scale = 0; ! 515: if (GET_CODE (ireg) != REG) abort (); ! 516: fprintf (file, "[%s:%c]", ! 517: reg_names[REGNO (ireg)], ! 518: scales[scale]); ! 519: } ! 520: break; ! 521: default: ! 522: output_addr_const (file, addr); ! 523: } ! 524: } ! 525: ! 526: /* National 32032 shifting is so bad that we can get ! 527: better performance in many common cases by using other ! 528: techniques. */ ! 529: char * ! 530: output_shift_insn (operands) ! 531: rtx *operands; ! 532: { ! 533: if (GET_CODE (operands[2]) == CONST_INT ! 534: && INTVAL (operands[2]) > 0 ! 535: && INTVAL (operands[2]) <= 3) ! 536: if (GET_CODE (operands[0]) == REG) ! 537: { ! 538: if (GET_CODE (operands[1]) == REG) ! 539: { ! 540: if (REGNO (operands[0]) == REGNO (operands[1])) ! 541: { ! 542: if (operands[2] == const1_rtx) ! 543: return "addd %0,%0"; ! 544: else if (INTVAL (operands[2]) == 2) ! 545: return "addd %0,%0\n\taddd %0,%0"; ! 546: } ! 547: if (operands[2] == const1_rtx) ! 548: return "movd %1,%0\n\taddd %0,%0"; ! 549: ! 550: operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]); ! 551: return "addr %a1,%0"; ! 552: } ! 553: if (operands[2] == const1_rtx) ! 554: return "movd %1,%0\n\taddd %0,%0"; ! 555: } ! 556: else if (GET_CODE (operands[1]) == REG) ! 557: { ! 558: operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]); ! 559: return "addr %a1,%0"; ! 560: } ! 561: else if (INTVAL (operands[2]) == 1 ! 562: && GET_CODE (operands[1]) == MEM ! 563: && rtx_equal_p (operands [0], operands[1])) ! 564: { ! 565: rtx temp = XEXP (operands[1], 0); ! 566: ! 567: if (GET_CODE (temp) == REG ! 568: || (GET_CODE (temp) == PLUS ! 569: && GET_CODE (XEXP (temp, 0)) == REG ! 570: && GET_CODE (XEXP (temp, 1)) == CONST_INT)) ! 571: return "addd %0,%0"; ! 572: } ! 573: else return "ashd %2,%0"; ! 574: return "ashd %2,%0"; ! 575: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.