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