|
|
1.1 root 1: /* Subroutines for insn-output.c for Convex. 1.1.1.2 ! root 2: Copyright (C) 1988, 1993, 1994 Free Software Foundation, Inc. 1.1 root 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: 1.1.1.2 ! root 416: int ! 417: check_float_value (mode, dp, overflow) 1.1 root 418: enum machine_mode mode; 419: REAL_VALUE_TYPE *dp; 1.1.1.2 ! root 420: int overflow; 1.1 root 421: { 422: REAL_VALUE_TYPE d = *dp; 423: 1.1.1.2 ! root 424: if (overflow) ! 425: { ! 426: *dp = MAX_FLOAT; ! 427: return 1; ! 428: } ! 429: 1.1 root 430: if (mode == SFmode) 431: { 432: if (d > MAX_FLOAT) 433: { 434: *dp = MAX_FLOAT; 1.1.1.2 ! root 435: return 1; 1.1 root 436: } 437: else if (d < -MAX_FLOAT) 438: { 439: *dp = -MAX_FLOAT; 1.1.1.2 ! root 440: return 1; 1.1 root 441: } 442: else if ((d > 0 && d < MIN_FLOAT) || (d < 0 && d > -MIN_FLOAT)) 443: { 444: *dp = 0.0; 1.1.1.2 ! root 445: return 1; 1.1 root 446: } 447: } 1.1.1.2 ! root 448: ! 449: return 0; 1.1 root 450: } 451: 452: /* Output the label at the start of a function. 453: Precede it with the number of formal args so debuggers will have 454: some idea of how many args to print. */ 455: 456: void 457: asm_declare_function_name (file, name, decl) 458: FILE *file; 459: char *name; 460: tree decl; 461: { 462: tree parms; 463: int nargs = list_length (DECL_ARGUMENTS (decl)); 464: 465: char *p, c; 466: extern char *version_string; 467: static char vers[4]; 468: int i; 469: 470: p = version_string; 471: for (i = 0; i < 3; ) { 472: c = *p; 473: if (c - '0' < (unsigned) 10) 474: vers[i++] = c; 475: if (c == 0 || c == ' ') 476: vers[i++] = '0'; 477: else 478: p++; 479: } 480: fprintf (file, "\tds.b \"g%s\"\n", vers); 481: 482: if (nargs < 100) 483: fprintf (file, "\tds.b \"+%02d\\0\"\n", nargs); 484: else 485: fprintf (file, "\tds.b \"+00\\0\"\n"); 486: 487: ASM_OUTPUT_LABEL (file, name); 488: } 489: 490: /* Print an instruction operand X on file FILE. 491: CODE is the code from the %-spec that requested printing this operand; 492: if `%z3' was used to print operand 3, then CODE is 'z'. */ 493: /* Convex codes: 494: %u prints a CONST_DOUBLE's high word 495: %v prints a CONST_DOUBLE's low word 496: %z prints a CONST_INT shift count as a multiply operand -- viz. 1 << n. 497: */ 498: 499: print_operand (file, x, code) 500: FILE *file; 501: rtx x; 502: char code; 503: { 504: long u[2]; 505: REAL_VALUE_TYPE d; 506: 507: switch (GET_CODE (x)) 508: { 509: case REG: 510: fprintf (file, "%s", reg_names[REGNO (x)]); 511: break; 512: 513: case MEM: 514: output_address (XEXP (x, 0)); 515: break; 516: 517: case CONST_DOUBLE: 518: REAL_VALUE_FROM_CONST_DOUBLE (d, x); 519: switch (GET_MODE (x)) { 520: case DFmode: 521: #if 0 /* doesn't work, produces dfloats */ 522: REAL_VALUE_TO_TARGET_DOUBLE (d, u); 523: #else 524: { 525: union { double d; int i[2]; } t; 526: t.d = d; 527: u[0] = t.i[0]; 528: u[1] = t.i[1]; 529: } 530: #endif 531: if (code == 'u') 532: fprintf (file, "#%#x", u[0]); 533: else if (code == 'v') 534: fprintf (file, "#%#x", u[1]); 535: else 536: outfloat (file, d, "%.17e", "#", ""); 537: break; 538: case SFmode: 539: outfloat (file, d, "%.9e", "#", ""); 540: break; 541: default: 542: if (code == 'u') 543: fprintf (file, "#%d", CONST_DOUBLE_HIGH (x)); 544: else 545: fprintf (file, "#%d", CONST_DOUBLE_LOW (x)); 546: } 547: break; 548: 549: default: 550: if (code == 'z') 551: { 552: if (GET_CODE (x) != CONST_INT) 553: abort (); 554: fprintf (file, "#%d", 1 << INTVAL (x)); 555: } 556: else 557: { 558: putc ('#', file); 559: output_addr_const (file, x); 560: } 561: } 562: } 563: 564: /* Print a memory operand whose address is X, on file FILE. */ 565: 566: print_operand_address (file, addr) 567: FILE *file; 568: rtx addr; 569: { 570: rtx index = 0; 571: rtx offset = 0; 572: 573: if (GET_CODE (addr) == MEM) 574: { 575: fprintf (file, "@"); 576: addr = XEXP (addr, 0); 577: } 578: 579: switch (GET_CODE (addr)) 580: { 581: case REG: 582: index = addr; 583: break; 584: 585: case PLUS: 586: index = XEXP (addr, 0); 587: if (REG_P (index)) 588: offset = XEXP (addr, 1); 589: else 590: { 591: offset = XEXP (addr, 0); 592: index = XEXP (addr, 1); 593: if (! REG_P (index)) 594: abort (); 595: } 596: break; 597: 598: default: 599: offset = addr; 600: break; 601: } 602: 603: if (offset) 604: output_addr_const (file, offset); 605: 606: if (index) 607: fprintf (file, "(%s)", reg_names[REGNO (index)]); 608: } 609: 610: /* Output a float to FILE, value VALUE, format FMT, preceded by PFX 611: and followed by SFX. */ 612: 613: outfloat (file, value, fmt, pfx, sfx) 614: FILE *file; 615: REAL_VALUE_TYPE value; 616: char *fmt, *pfx, *sfx; 617: { 618: char buf[64]; 619: fputs (pfx, file); 620: REAL_VALUE_TO_DECIMAL (value, fmt, buf); 621: fputs (buf, file); 622: fputs (sfx, file); 623: } 624: 625: /* Here during RTL generation of return. If we are at the final return 626: in a function, go through the function and replace pushes with stores 627: into a frame arg block. This is similar to what ACCUMULATE_OUTGOING_ARGS 628: does, but we must index off the frame pointer, not the stack pointer, 629: and the calling sequence does not require the arg block to be at the 630: top of the stack. */ 631: 632: replace_arg_pushes () 633: { 634: /* Doesn't work yet. */ 635: } 636: 637: /* Output the insns needed to do a call. operands[] are 638: 0 - MEM, the place to call 639: 1 - CONST_INT, the number of bytes in the arg list 640: 2 - CONST_INT, the number of arguments 641: 3 - CONST_INT, the number of bytes to pop 642: 4 - address of the arg list. 643: */ 644: 645: char * 646: output_call (insn, operands) 647: rtx insn, *operands; 648: { 649: if (operands[4] == stack_pointer_rtx) 650: output_asm_insn ("mov sp,ap", operands); 651: else 652: abort (); 653: 654: if (TARGET_ARGCOUNT) 655: output_asm_insn ("pshea %a2", operands); 656: 657: output_asm_insn ("calls %0", operands); 658: 659: output_asm_insn ("ld.w 12(fp),ap", operands); 660: 661: if (operands[4] == stack_pointer_rtx && operands[3] != const0_rtx) 662: output_asm_insn ("add.w %3,sp", operands); 663: 664: return ""; 665: } 666: 667: 668: /* Here after reloading, before the second scheduling pass. */ 669: 670: emit_ap_optimizations () 671: { 672: /* Removed for now. */ 673: } 674:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.