|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Convex. ! 2: Copyright (C) 1988, 1993 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: #include "config.h" ! 21: #include "tree.h" ! 22: #include "rtl.h" ! 23: #include "regs.h" ! 24: #include "hard-reg-set.h" ! 25: #include "real.h" ! 26: #include "insn-config.h" ! 27: #include "conditions.h" ! 28: #include "insn-flags.h" ! 29: #include "insn-attr.h" ! 30: #include "output.h" ! 31: #include "expr.h" ! 32: ! 33: #undef NULL ! 34: #include <stdio.h> ! 35: ! 36: /* Tables used in convex.h */ ! 37: ! 38: char regno_ok_for_index_p_base[1 + LAST_VIRTUAL_REGISTER + 1]; ! 39: enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER]; ! 40: enum reg_class reg_class_from_letter[256]; ! 41: ! 42: /* Target cpu index. */ ! 43: ! 44: int target_cpu; ! 45: ! 46: /* Boolean to keep track of whether the current section is .text or not. ! 47: Used by .align handler in convex.h. */ ! 48: ! 49: int current_section_is_text; ! 50: ! 51: /* Communication between output_compare and output_condjump. */ ! 52: ! 53: static rtx cmp_operand0, cmp_operand1; ! 54: static char cmp_modech; ! 55: ! 56: /* Forwards */ ! 57: ! 58: static rtx frame_argblock; ! 59: static int frame_argblock_size; ! 60: static rtx convert_arg_pushes (); ! 61: static void expand_movstr_call (); ! 62: ! 63: /* Here from OVERRIDE_OPTIONS at startup. Initialize constant tables. */ ! 64: ! 65: init_convex () ! 66: { ! 67: int regno; ! 68: ! 69: /* Set A and S reg classes. */ ! 70: for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) ! 71: if (A_REGNO_P (regno)) ! 72: { ! 73: regno_ok_for_index_p[regno] = 1; ! 74: regno_reg_class[regno] = INDEX_REGS; ! 75: } ! 76: else ! 77: { ! 78: regno_ok_for_index_p[regno] = 0; ! 79: regno_reg_class[regno] = S_REGS; ! 80: } ! 81: ! 82: /* Can't index off the stack pointer, register 0. */ ! 83: regno_ok_for_index_p[STACK_POINTER_REGNUM] = 0; ! 84: regno_reg_class[STACK_POINTER_REGNUM] = SP_REGS; ! 85: ! 86: /* Can't index off aliases of the stack pointer. */ ! 87: regno_ok_for_index_p[VIRTUAL_INCOMING_ARGS_REGNUM] = 1; ! 88: regno_ok_for_index_p[VIRTUAL_STACK_VARS_REGNUM] = 1; ! 89: regno_ok_for_index_p[VIRTUAL_STACK_DYNAMIC_REGNUM] = 0; ! 90: regno_ok_for_index_p[VIRTUAL_OUTGOING_ARGS_REGNUM] = 0; ! 91: ! 92: /* Can't index off hard reg -1 == pseudos not assigned */ ! 93: regno_ok_for_index_p[-1] = 0; ! 94: ! 95: /* Set reg class letters */ ! 96: reg_class_from_letter['a'] = A_REGS; ! 97: reg_class_from_letter['A'] = INDEX_REGS; ! 98: reg_class_from_letter['d'] = S_REGS; ! 99: ! 100: /* Turn off floating point exception enables in the psw. */ ! 101: psw_disable_float (); ! 102: } ! 103: ! 104: psw_disable_float () ! 105: { ! 106: #if __convex__ && __GNUC__ ! 107: register int *p; ! 108: asm ("mov fp,%0" : "=a" (p)); ! 109: while (p) ! 110: { ! 111: p[1] &= ~0x1000c400; ! 112: p = (int *) p[2]; ! 113: } ! 114: #endif ! 115: } ! 116: ! 117: /* Here to output code for a compare insn. Output nothing, just ! 118: record the operands and their mode. */ ! 119: ! 120: char * ! 121: output_cmp (operand0, operand1, modech) ! 122: rtx operand0, operand1; ! 123: char modech; ! 124: { ! 125: cmp_operand0 = operand0; ! 126: cmp_operand1 = operand1; ! 127: cmp_modech = modech; ! 128: return ""; ! 129: } ! 130: ! 131: /* Output code for a conditional jump. The preceding instruction ! 132: is necessarily a compare. Output two instructions, for example ! 133: eq.w a1,a2 ! 134: jbra.t L5 ! 135: for ! 136: (cmpsi a1 a2) ! 137: (beq L5) ! 138: */ ! 139: ! 140: char * ! 141: output_condjump (label, cond, jbr_sense) ! 142: rtx label; ! 143: char *cond; ! 144: char jbr_sense; ! 145: { ! 146: rtx operands[3]; ! 147: char cmp_op[4]; ! 148: char buf[80]; ! 149: char jbr_regch; ! 150: ! 151: strcpy (cmp_op, cond); ! 152: ! 153: /* [BL] mean the value is being compared against immediate 0. ! 154: Use neg.x, which produces the same carry that eq.x #0 would if it ! 155: existed. In this case operands[1] is a scratch register, not a ! 156: compare operand. */ ! 157: ! 158: if (cmp_modech == 'B' || cmp_modech == 'L') ! 159: { ! 160: cmp_modech = cmp_modech - 'A' + 'a'; ! 161: strcpy (cmp_op, "neg"); ! 162: } ! 163: ! 164: /* [WH] mean the value being compared resulted from "add.[wh] #-1,rk" ! 165: when rk was nonnegative -- we can omit equality compares against -1 ! 166: or inequality compares against 0. */ ! 167: ! 168: else if (cmp_modech == 'W' || cmp_modech == 'H') ! 169: { ! 170: if (! strcmp (cmp_op, "eq") && cmp_operand1 == constm1_rtx) ! 171: jbr_sense ^= 't' ^ 'f'; ! 172: else if (! strcmp (cmp_op, "lt") && cmp_operand1 == const0_rtx) ! 173: ; ! 174: else ! 175: cmp_modech = cmp_modech - 'A' + 'a'; ! 176: } ! 177: ! 178: /* Constant must be first; swap operands if necessary. ! 179: If lt, le, ltu, leu are swapped, change to le, lt, leu, ltu ! 180: and reverse the sense of the jump. */ ! 181: ! 182: if (! REG_P (cmp_operand1)) ! 183: { ! 184: operands[0] = cmp_operand1; ! 185: operands[1] = cmp_operand0; ! 186: if (cmp_op[0] == 'l') ! 187: { ! 188: cmp_op[1] ^= 'e' ^ 't'; ! 189: jbr_sense ^= 't' ^ 'f'; ! 190: } ! 191: } ! 192: else ! 193: { ! 194: operands[0] = cmp_operand0; ! 195: operands[1] = cmp_operand1; ! 196: } ! 197: ! 198: operands[2] = label; ! 199: ! 200: if (S_REG_P (operands[1])) ! 201: jbr_regch = 's'; ! 202: else if (A_REG_P (operands[1])) ! 203: jbr_regch = 'a'; ! 204: else ! 205: abort (); ! 206: ! 207: if (cmp_modech == 'W' || cmp_modech == 'H') ! 208: sprintf (buf, "jbr%c.%c %%l2", jbr_regch, jbr_sense); ! 209: else ! 210: sprintf (buf, "%s.%c %%0,%%1\n\tjbr%c.%c %%l2", ! 211: cmp_op, cmp_modech, jbr_regch, jbr_sense); ! 212: output_asm_insn (buf, operands); ! 213: return ""; ! 214: } ! 215: ! 216: /* Return 1 if OP is valid for cmpsf. ! 217: In IEEE mode, +/- zero compares are not handled by ! 218: the immediate versions of eq.s and on some machines, lt.s, and le.s. ! 219: So disallow 0.0 as the immediate operand of xx.s compares in IEEE mode. */ ! 220: ! 221: int ! 222: nonmemory_cmpsf_operand (op, mode) ! 223: rtx op; ! 224: enum machine_mode mode; ! 225: { ! 226: #if _IEEE_FLOAT_ ! 227: if (op == CONST0_RTX (SFmode)) ! 228: return 0; ! 229: #endif ! 230: ! 231: return nonmemory_operand (op, mode); ! 232: } ! 233: ! 234: /* Convex /bin/as does not like unary minus in some contexts. ! 235: Simplify CONST addresses to remove it. */ ! 236: ! 237: rtx ! 238: simplify_for_convex (x) ! 239: rtx x; ! 240: { ! 241: switch (GET_CODE (x)) ! 242: { ! 243: case MINUS: ! 244: if (GET_CODE (XEXP (x, 1)) == CONST_INT ! 245: && INTVAL (XEXP (x, 1)) < 0) ! 246: { ! 247: PUT_CODE (x, PLUS); ! 248: XEXP (x, 1) = GEN_INT (- INTVAL (XEXP (x, 1))); ! 249: } ! 250: break; ! 251: ! 252: case CONST: ! 253: return simplify_for_convex (XEXP (x, 0)); ! 254: } ! 255: ! 256: return x; ! 257: } ! 258: ! 259: /* Routines to separate CONST_DOUBLEs into component parts. */ ! 260: ! 261: int ! 262: const_double_high_int (x) ! 263: rtx x; ! 264: { ! 265: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) ! 266: return CONST_DOUBLE_LOW (x); ! 267: else ! 268: return CONST_DOUBLE_HIGH (x); ! 269: } ! 270: ! 271: int ! 272: const_double_low_int (x) ! 273: rtx x; ! 274: { ! 275: if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) ! 276: return CONST_DOUBLE_HIGH (x); ! 277: else ! 278: return CONST_DOUBLE_LOW (x); ! 279: } ! 280: ! 281: /* Inline block copy. */ ! 282: ! 283: void ! 284: expand_movstr (operands) ! 285: rtx *operands; ! 286: { ! 287: rtx dest = operands[0]; ! 288: rtx src = operands[1]; ! 289: int align = INTVAL (operands[3]); ! 290: int nregs, maxsize; ! 291: unsigned len; ! 292: enum machine_mode mode; ! 293: rtx reg, load, store, prev_store, prev_store_2; ! 294: int size; ! 295: ! 296: /* Decide how many regs to use, depending on load latency, and what ! 297: size pieces to move, depending on whether machine does unaligned ! 298: loads and stores efficiently. */ ! 299: ! 300: if (TARGET_C1) ! 301: { ! 302: /* ld.l latency is 4, no alignment problems. */ ! 303: nregs = 3, maxsize = 8; ! 304: } ! 305: else if (TARGET_C2) ! 306: { ! 307: /* loads are latency 2 if we avoid ld.l not at least word aligned. */ ! 308: if (align >= 4) ! 309: nregs = 2, maxsize = 8; ! 310: else ! 311: nregs = 2, maxsize = 4; ! 312: } ! 313: else if (TARGET_C34) ! 314: { ! 315: /* latency is 4 if aligned, horrible if not. */ ! 316: nregs = 3, maxsize = align; ! 317: } ! 318: else if (TARGET_C38) ! 319: { ! 320: /* latency is 2 if at least word aligned, 3 or 4 if unaligned. */ ! 321: if (align >= 4) ! 322: nregs = 2, maxsize = 8; ! 323: else ! 324: nregs = 3, maxsize = 8; ! 325: } ! 326: else ! 327: abort (); ! 328: ! 329: /* Caller is not necessarily prepared for us to fail in this ! 330: expansion. So fall back by generating memcpy call here. */ ! 331: ! 332: if (GET_CODE (operands[2]) != CONST_INT ! 333: || (len = INTVAL (operands[2])) > (unsigned) 32 * maxsize) ! 334: { ! 335: expand_movstr_call (operands); ! 336: return; ! 337: } ! 338: ! 339: reg = 0; ! 340: prev_store = prev_store_2 = 0; ! 341: ! 342: while (len > 0) ! 343: { ! 344: if (len >= 8 && maxsize >= 8) ! 345: mode = DImode; ! 346: else if (len >= 4 && maxsize >= 4) ! 347: mode = SImode; ! 348: else if (len >= 2 && maxsize >= 2) ! 349: mode = HImode; ! 350: else ! 351: mode = QImode; ! 352: ! 353: /* If no temp pseudo to reuse, or not the right mode, make one */ ! 354: if (! reg || GET_MODE (reg) != mode) ! 355: reg = gen_reg_rtx (mode); ! 356: ! 357: /* Get src and dest in the right mode */ ! 358: if (GET_MODE (src) != mode) ! 359: src = change_address (src, mode, 0), ! 360: dest = change_address (dest, mode, 0); ! 361: ! 362: /* Make load and store patterns for this piece */ ! 363: load = gen_rtx (SET, VOIDmode, reg, src); ! 364: store = gen_rtx (SET, VOIDmode, dest, reg); ! 365: ! 366: /* Emit the load and the store from last time. ! 367: When we emit a store, we can reuse its temp reg. */ ! 368: emit_insn (load); ! 369: if (prev_store) ! 370: { ! 371: reg = SET_SRC (prev_store); ! 372: emit_insn (prev_store); ! 373: } ! 374: else ! 375: reg = 0; ! 376: ! 377: /* Queue up the store, for next time or the time after that. */ ! 378: if (nregs == 2) ! 379: prev_store = store; ! 380: else ! 381: prev_store = prev_store_2, prev_store_2 = store; ! 382: ! 383: /* Advance to next piece. */ ! 384: size = GET_MODE_SIZE (mode); ! 385: src = adj_offsettable_operand (src, size); ! 386: dest = adj_offsettable_operand (dest, size); ! 387: len -= size; ! 388: } ! 389: ! 390: /* Finally, emit the last stores. */ ! 391: if (prev_store) ! 392: emit_insn (prev_store); ! 393: if (prev_store_2) ! 394: emit_insn (prev_store_2); ! 395: } ! 396: ! 397: static void ! 398: expand_movstr_call (operands) ! 399: rtx *operands; ! 400: { ! 401: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0, ! 402: VOIDmode, 3, ! 403: XEXP (operands[0], 0), Pmode, ! 404: XEXP (operands[1], 0), Pmode, ! 405: operands[2], SImode); ! 406: } ! 407: ! 408: #if _IEEE_FLOAT_ ! 409: #define MAX_FLOAT 3.4028234663852886e+38 ! 410: #define MIN_FLOAT 1.1754943508222875e-38 ! 411: #else ! 412: #define MAX_FLOAT 1.7014117331926443e+38 ! 413: #define MIN_FLOAT 2.9387358770557188e-39 ! 414: #endif ! 415: ! 416: void ! 417: check_float_value (mode, dp) ! 418: enum machine_mode mode; ! 419: REAL_VALUE_TYPE *dp; ! 420: { ! 421: REAL_VALUE_TYPE d = *dp; ! 422: ! 423: if (mode == SFmode) ! 424: { ! 425: if (d > MAX_FLOAT) ! 426: { ! 427: error ("magnitude of constant too large for `float'"); ! 428: *dp = MAX_FLOAT; ! 429: } ! 430: else if (d < -MAX_FLOAT) ! 431: { ! 432: error ("magnitude of constant too large for `float'"); ! 433: *dp = -MAX_FLOAT; ! 434: } ! 435: else if ((d > 0 && d < MIN_FLOAT) || (d < 0 && d > -MIN_FLOAT)) ! 436: { ! 437: warning ("`float' constant truncated to zero"); ! 438: *dp = 0.0; ! 439: } ! 440: } ! 441: } ! 442: ! 443: /* Output the label at the start of a function. ! 444: Precede it with the number of formal args so debuggers will have ! 445: some idea of how many args to print. */ ! 446: ! 447: void ! 448: asm_declare_function_name (file, name, decl) ! 449: FILE *file; ! 450: char *name; ! 451: tree decl; ! 452: { ! 453: tree parms; ! 454: int nargs = list_length (DECL_ARGUMENTS (decl)); ! 455: ! 456: char *p, c; ! 457: extern char *version_string; ! 458: static char vers[4]; ! 459: int i; ! 460: ! 461: p = version_string; ! 462: for (i = 0; i < 3; ) { ! 463: c = *p; ! 464: if (c - '0' < (unsigned) 10) ! 465: vers[i++] = c; ! 466: if (c == 0 || c == ' ') ! 467: vers[i++] = '0'; ! 468: else ! 469: p++; ! 470: } ! 471: fprintf (file, "\tds.b \"g%s\"\n", vers); ! 472: ! 473: if (nargs < 100) ! 474: fprintf (file, "\tds.b \"+%02d\\0\"\n", nargs); ! 475: else ! 476: fprintf (file, "\tds.b \"+00\\0\"\n"); ! 477: ! 478: ASM_OUTPUT_LABEL (file, name); ! 479: } ! 480: ! 481: /* Print an instruction operand X on file FILE. ! 482: CODE is the code from the %-spec that requested printing this operand; ! 483: if `%z3' was used to print operand 3, then CODE is 'z'. */ ! 484: /* Convex codes: ! 485: %u prints a CONST_DOUBLE's high word ! 486: %v prints a CONST_DOUBLE's low word ! 487: %z prints a CONST_INT shift count as a multiply operand -- viz. 1 << n. ! 488: */ ! 489: ! 490: print_operand (file, x, code) ! 491: FILE *file; ! 492: rtx x; ! 493: char code; ! 494: { ! 495: long u[2]; ! 496: REAL_VALUE_TYPE d; ! 497: ! 498: switch (GET_CODE (x)) ! 499: { ! 500: case REG: ! 501: fprintf (file, "%s", reg_names[REGNO (x)]); ! 502: break; ! 503: ! 504: case MEM: ! 505: output_address (XEXP (x, 0)); ! 506: break; ! 507: ! 508: case CONST_DOUBLE: ! 509: REAL_VALUE_FROM_CONST_DOUBLE (d, x); ! 510: switch (GET_MODE (x)) { ! 511: case DFmode: ! 512: #if 0 /* doesn't work, produces dfloats */ ! 513: REAL_VALUE_TO_TARGET_DOUBLE (d, u); ! 514: #else ! 515: { ! 516: union { double d; int i[2]; } t; ! 517: t.d = d; ! 518: u[0] = t.i[0]; ! 519: u[1] = t.i[1]; ! 520: } ! 521: #endif ! 522: if (code == 'u') ! 523: fprintf (file, "#%#x", u[0]); ! 524: else if (code == 'v') ! 525: fprintf (file, "#%#x", u[1]); ! 526: else ! 527: outfloat (file, d, "%.17e", "#", ""); ! 528: break; ! 529: case SFmode: ! 530: outfloat (file, d, "%.9e", "#", ""); ! 531: break; ! 532: default: ! 533: if (code == 'u') ! 534: fprintf (file, "#%d", CONST_DOUBLE_HIGH (x)); ! 535: else ! 536: fprintf (file, "#%d", CONST_DOUBLE_LOW (x)); ! 537: } ! 538: break; ! 539: ! 540: default: ! 541: if (code == 'z') ! 542: { ! 543: if (GET_CODE (x) != CONST_INT) ! 544: abort (); ! 545: fprintf (file, "#%d", 1 << INTVAL (x)); ! 546: } ! 547: else ! 548: { ! 549: putc ('#', file); ! 550: output_addr_const (file, x); ! 551: } ! 552: } ! 553: } ! 554: ! 555: /* Print a memory operand whose address is X, on file FILE. */ ! 556: ! 557: print_operand_address (file, addr) ! 558: FILE *file; ! 559: rtx addr; ! 560: { ! 561: rtx index = 0; ! 562: rtx offset = 0; ! 563: ! 564: if (GET_CODE (addr) == MEM) ! 565: { ! 566: fprintf (file, "@"); ! 567: addr = XEXP (addr, 0); ! 568: } ! 569: ! 570: switch (GET_CODE (addr)) ! 571: { ! 572: case REG: ! 573: index = addr; ! 574: break; ! 575: ! 576: case PLUS: ! 577: index = XEXP (addr, 0); ! 578: if (REG_P (index)) ! 579: offset = XEXP (addr, 1); ! 580: else ! 581: { ! 582: offset = XEXP (addr, 0); ! 583: index = XEXP (addr, 1); ! 584: if (! REG_P (index)) ! 585: abort (); ! 586: } ! 587: break; ! 588: ! 589: default: ! 590: offset = addr; ! 591: break; ! 592: } ! 593: ! 594: if (offset) ! 595: output_addr_const (file, offset); ! 596: ! 597: if (index) ! 598: fprintf (file, "(%s)", reg_names[REGNO (index)]); ! 599: } ! 600: ! 601: /* Output a float to FILE, value VALUE, format FMT, preceded by PFX ! 602: and followed by SFX. */ ! 603: ! 604: outfloat (file, value, fmt, pfx, sfx) ! 605: FILE *file; ! 606: REAL_VALUE_TYPE value; ! 607: char *fmt, *pfx, *sfx; ! 608: { ! 609: char buf[64]; ! 610: fputs (pfx, file); ! 611: REAL_VALUE_TO_DECIMAL (value, fmt, buf); ! 612: fputs (buf, file); ! 613: fputs (sfx, file); ! 614: } ! 615: ! 616: /* Here during RTL generation of return. If we are at the final return ! 617: in a function, go through the function and replace pushes with stores ! 618: into a frame arg block. This is similar to what ACCUMULATE_OUTGOING_ARGS ! 619: does, but we must index off the frame pointer, not the stack pointer, ! 620: and the calling sequence does not require the arg block to be at the ! 621: top of the stack. */ ! 622: ! 623: replace_arg_pushes () ! 624: { ! 625: /* Doesn't work yet. */ ! 626: } ! 627: ! 628: /* Output the insns needed to do a call. operands[] are ! 629: 0 - MEM, the place to call ! 630: 1 - CONST_INT, the number of bytes in the arg list ! 631: 2 - CONST_INT, the number of arguments ! 632: 3 - CONST_INT, the number of bytes to pop ! 633: 4 - address of the arg list. ! 634: */ ! 635: ! 636: char * ! 637: output_call (insn, operands) ! 638: rtx insn, *operands; ! 639: { ! 640: if (operands[4] == stack_pointer_rtx) ! 641: output_asm_insn ("mov sp,ap", operands); ! 642: else ! 643: abort (); ! 644: ! 645: if (TARGET_ARGCOUNT) ! 646: output_asm_insn ("pshea %a2", operands); ! 647: ! 648: output_asm_insn ("calls %0", operands); ! 649: ! 650: output_asm_insn ("ld.w 12(fp),ap", operands); ! 651: ! 652: if (operands[4] == stack_pointer_rtx && operands[3] != const0_rtx) ! 653: output_asm_insn ("add.w %3,sp", operands); ! 654: ! 655: return ""; ! 656: } ! 657: ! 658: ! 659: /* Here after reloading, before the second scheduling pass. */ ! 660: ! 661: emit_ap_optimizations () ! 662: { ! 663: /* Removed for now. */ ! 664: } ! 665:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.