|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Pyramid 90x, 9000, and MIServer Series. ! 2: Copyright (C) 1989, 1991 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 2, 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 pyr.md need these. */ ! 21: #include <stdio.h> ! 22: #include "config.h" ! 23: #include "rtl.h" ! 24: #include "regs.h" ! 25: #include "hard-reg-set.h" ! 26: #include "real.h" ! 27: #include "insn-config.h" ! 28: #include "conditions.h" ! 29: #include "insn-flags.h" ! 30: #include "output.h" ! 31: #include "insn-attr.h" ! 32: #include "tree.h" ! 33: ! 34: /* ! 35: * Do FUNCTION_ARG. ! 36: * This cannot be defined as a macro on pyramids, because Pyramid Technology's ! 37: * C compiler dies on (several equivalent definitions of) this macro. ! 38: * The only way around this cc bug was to make this a function. ! 39: * While it would be possible to use a macro version for gcc, it seems ! 40: * more reliable to have a single version of the code. ! 41: */ ! 42: void * ! 43: pyr_function_arg(cum, mode, type, named) ! 44: CUMULATIVE_ARGS cum; ! 45: enum machine_mode mode; ! 46: tree type; ! 47: { ! 48: return (void *)(FUNCTION_ARG_HELPER (cum, mode,type,named)); ! 49: } ! 50: ! 51: /* Do the hard part of PARAM_SAFE_FOR_REG_P. ! 52: * This cannot be defined as a macro on pyramids, because Pyramid Technology's ! 53: * C compiler dies on (several equivalent definitions of) this macro. ! 54: * The only way around this cc bug was to make this a function. ! 55: */ ! 56: int ! 57: inner_param_safe_helper (type) ! 58: tree type; ! 59: { ! 60: return (INNER_PARAM_SAFE_HELPER(type)); ! 61: } ! 62: ! 63: ! 64: /* Return 1 if OP is a non-indexed operand of mode MODE. ! 65: This is either a register reference, a memory reference, ! 66: or a constant. In the case of a memory reference, the address ! 67: is checked to make sure it isn't indexed. ! 68: ! 69: Register and memory references must have mode MODE in order to be valid, ! 70: but some constants have no machine mode and are valid for any mode. ! 71: ! 72: If MODE is VOIDmode, OP is checked for validity for whatever mode ! 73: it has. ! 74: ! 75: The main use of this function is as a predicate in match_operand ! 76: expressions in the machine description. ! 77: ! 78: It is useful to compare this with general_operand(). They should ! 79: be identical except for one line. ! 80: ! 81: This function seems necessary because of the non-orthogonality of ! 82: Pyramid insns. ! 83: For any 2-operand insn, and any combination of operand modes, ! 84: if indexing is valid for the isn's second operand, it is invalid ! 85: for the first operand to be indexed. */ ! 86: ! 87: extern int volatile_ok; ! 88: ! 89: int ! 90: nonindexed_operand (op, mode) ! 91: register rtx op; ! 92: enum machine_mode mode; ! 93: { ! 94: register RTX_CODE code = GET_CODE (op); ! 95: int mode_altering_drug = 0; ! 96: ! 97: if (mode == VOIDmode) ! 98: mode = GET_MODE (op); ! 99: ! 100: /* Don't accept CONST_INT or anything similar ! 101: if the caller wants something floating. */ ! 102: if (GET_MODE (op) == VOIDmode && mode != VOIDmode ! 103: && GET_MODE_CLASS (mode) != MODE_INT) ! 104: return 0; ! 105: ! 106: if (CONSTANT_P (op)) ! 107: return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode) ! 108: && LEGITIMATE_CONSTANT_P (op)); ! 109: ! 110: /* Except for certain constants with VOIDmode, already checked for, ! 111: OP's mode must match MODE if MODE specifies a mode. */ ! 112: ! 113: if (GET_MODE (op) != mode) ! 114: return 0; ! 115: ! 116: while (code == SUBREG) ! 117: { ! 118: op = SUBREG_REG (op); ! 119: code = GET_CODE (op); ! 120: #if 0 ! 121: /* No longer needed, since (SUBREG (MEM...)) ! 122: will load the MEM into a reload reg in the MEM's own mode. */ ! 123: mode_altering_drug = 1; ! 124: #endif ! 125: } ! 126: if (code == REG) ! 127: return 1; ! 128: if (code == CONST_DOUBLE) ! 129: return LEGITIMATE_CONSTANT_P (op); ! 130: if (code == MEM) ! 131: { ! 132: register rtx y = XEXP (op, 0); ! 133: if (! volatile_ok && MEM_VOLATILE_P (op)) ! 134: return 0; ! 135: GO_IF_NONINDEXED_ADDRESS (y, win); ! 136: } ! 137: return 0; ! 138: ! 139: win: ! 140: if (mode_altering_drug) ! 141: return ! mode_dependent_address_p (XEXP (op, 0)); ! 142: return 1; ! 143: } ! 144: ! 145: /* Return non-zero if the rtx OP has an immediate component. An ! 146: immediate component or additive term equal to zero is rejected ! 147: due to assembler problems. */ ! 148: ! 149: int ! 150: has_direct_base (op) ! 151: rtx op; ! 152: { ! 153: if ((CONSTANT_ADDRESS_P (op) ! 154: && op != const0_rtx) ! 155: || (GET_CODE (op) == PLUS ! 156: && ((CONSTANT_ADDRESS_P (XEXP (op, 1)) ! 157: && XEXP (op, 1) != const0_rtx) ! 158: || (CONSTANT_ADDRESS_P (XEXP (op, 0)) ! 159: && XEXP (op, 0) != const0_rtx)))) ! 160: return 1; ! 161: ! 162: return 0; ! 163: } ! 164: ! 165: /* Return zero if the rtx OP has a (scaled) index. */ ! 166: ! 167: int ! 168: has_index (op) ! 169: rtx op; ! 170: { ! 171: if (GET_CODE (op) == PLUS ! 172: && (GET_CODE (XEXP (op, 0)) == MULT ! 173: || (GET_CODE (XEXP (op, 1)) == MULT))) ! 174: return 1; ! 175: else ! 176: return 0; ! 177: } ! 178: ! 179: int swap_operands; ! 180: ! 181: /* weird_memory_memory -- return 1 if OP1 and OP2 can be compared (or ! 182: exchanged with xchw) with one instruction. If the operands need to ! 183: be swapped, set the global variable SWAP_OPERANDS. This function ! 184: silently assumes that both OP0 and OP1 are valid memory references. ! 185: */ ! 186: ! 187: int ! 188: weird_memory_memory (op0, op1) ! 189: rtx op0, op1; ! 190: { ! 191: RTX_CODE code0, code1; ! 192: ! 193: op0 = XEXP (op0, 0); ! 194: op1 = XEXP (op1, 0); ! 195: code0 = GET_CODE (op0); ! 196: code1 = GET_CODE (op1); ! 197: ! 198: swap_operands = 0; ! 199: ! 200: if (code1 == REG || code1 == SUBREG) ! 201: { ! 202: return 1; ! 203: } ! 204: if (code0 == REG || code0 == SUBREG) ! 205: { ! 206: swap_operands = 1; ! 207: return 1; ! 208: } ! 209: if (has_direct_base (op0) && has_direct_base (op1)) ! 210: { ! 211: if (has_index (op1)) ! 212: { ! 213: if (has_index (op0)) ! 214: return 0; ! 215: swap_operands = 1; ! 216: } ! 217: ! 218: return 1; ! 219: } ! 220: return 0; ! 221: } ! 222: ! 223: int ! 224: signed_comparison (x, mode) ! 225: rtx x; ! 226: enum machine_mode mode; ! 227: { ! 228: return ! TRULY_UNSIGNED_COMPARE_P (GET_CODE (x)); ! 229: } ! 230: ! 231: extern rtx force_reg (); ! 232: rtx test_op0, test_op1; ! 233: enum machine_mode test_mode; ! 234: ! 235: /* Sign-extend or zero-extend constant X from FROM_MODE to TO_MODE. */ ! 236: ! 237: rtx ! 238: extend_const (x, extop, from_mode, to_mode) ! 239: rtx x; ! 240: RTX_CODE extop; ! 241: enum machine_mode from_mode, to_mode; ! 242: { ! 243: int val; ! 244: int negative; ! 245: if (from_mode == to_mode) ! 246: return x; ! 247: if (GET_CODE (x) != CONST_INT) ! 248: abort (); ! 249: val = INTVAL (x); ! 250: negative = val & (1 << (GET_MODE_BITSIZE (from_mode) - 1)); ! 251: if (GET_MODE_BITSIZE (from_mode) == HOST_BITS_PER_INT) ! 252: abort (); ! 253: if (negative && extop == SIGN_EXTEND) ! 254: val = val | ((-1) << (GET_MODE_BITSIZE (from_mode))); ! 255: else ! 256: val = val & ~((-1) << (GET_MODE_BITSIZE (from_mode))); ! 257: if (GET_MODE_BITSIZE (to_mode) == HOST_BITS_PER_INT) ! 258: return gen_rtx (CONST_INT, VOIDmode, val); ! 259: return gen_rtx (CONST_INT, VOIDmode, ! 260: val & ~((-1) << (GET_MODE_BITSIZE (to_mode)))); ! 261: } ! 262: ! 263: rtx ! 264: ensure_extended (op, extop, from_mode) ! 265: rtx op; ! 266: RTX_CODE extop; ! 267: enum machine_mode from_mode; ! 268: { ! 269: if (GET_CODE (op) == CONST_INT) ! 270: return extend_const (op, extop, from_mode, SImode); ! 271: else ! 272: return force_reg (SImode, gen_rtx (extop, SImode, op)); ! 273: } ! 274: ! 275: /* Emit rtl for a branch, as well as any delayed (integer) compare insns. ! 276: The compare insn to perform is determined by the global variables ! 277: test_op0 and test_op1. */ ! 278: ! 279: void ! 280: extend_and_branch (extop) ! 281: RTX_CODE extop; ! 282: { ! 283: rtx op0, op1; ! 284: RTX_CODE code0, code1; ! 285: ! 286: op0 = test_op0, op1 = test_op1; ! 287: if (op0 == 0) ! 288: return; ! 289: ! 290: code0 = GET_CODE (op0); ! 291: if (op1 != 0) ! 292: code1 = GET_CODE (op1); ! 293: test_op0 = test_op1 = 0; ! 294: ! 295: if (op1 == 0) ! 296: { ! 297: op0 = ensure_extended (op0, extop, test_mode); ! 298: emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, op0)); ! 299: } ! 300: else ! 301: { ! 302: if (CONSTANT_P (op0) && CONSTANT_P (op1)) ! 303: { ! 304: op0 = ensure_extended (op0, extop, test_mode); ! 305: op1 = ensure_extended (op1, extop, test_mode); ! 306: } ! 307: else if (extop == ZERO_EXTEND && test_mode == HImode) ! 308: { ! 309: /* Pyramids have no unsigned "cmphi" instructions. We need to ! 310: zero extend unsigned halfwords into temporary registers. */ ! 311: op0 = ensure_extended (op0, extop, test_mode); ! 312: op1 = ensure_extended (op1, extop, test_mode); ! 313: } ! 314: else if (CONSTANT_P (op0)) ! 315: { ! 316: op0 = ensure_extended (op0, extop, test_mode); ! 317: op1 = ensure_extended (op1, extop, test_mode); ! 318: } ! 319: else if (CONSTANT_P (op1)) ! 320: { ! 321: op1 = ensure_extended (op1, extop, test_mode); ! 322: op0 = ensure_extended (op0, extop, test_mode); ! 323: } ! 324: else if ((code0 == REG || code0 == SUBREG) ! 325: && (code1 == REG || code1 == SUBREG)) ! 326: { ! 327: /* I could do this case without extension, by using the virtual ! 328: register address (but that would lose for global regs). */ ! 329: op0 = ensure_extended (op0, extop, test_mode); ! 330: op1 = ensure_extended (op1, extop, test_mode); ! 331: } ! 332: else if (code0 == MEM && code1 == MEM) ! 333: { ! 334: /* Load into a reg if the address combination can't be handled ! 335: directly. */ ! 336: if (! weird_memory_memory (op0, op1)) ! 337: op0 = force_reg (test_mode, op0); ! 338: } ! 339: ! 340: emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, ! 341: gen_rtx (COMPARE, VOIDmode, op0, op1))); ! 342: } ! 343: } ! 344: ! 345: /* Return non-zero if the two single-word moves with operands[0] ! 346: and operands[1] for the first single-word move, and operands[2] ! 347: and operands[3] for the second single-word move, is possible to ! 348: combine to a double word move. ! 349: ! 350: The criterion is whether the operands are in consecutive memory cells, ! 351: registers, etc. */ ! 352: ! 353: int ! 354: movdi_possible (operands) ! 355: rtx operands[]; ! 356: { ! 357: int cnst_diff0, cnst_diff1; ! 358: RTX_CODE code0 = GET_CODE (operands[0]); ! 359: RTX_CODE code1 = GET_CODE (operands[1]); ! 360: ! 361: /* Don't dare to combine (possibly overlapping) memory -> memory moves. */ ! 362: /* It would be possible to detect the cases where we dare, by using ! 363: constant_diff (operands[0], operands[1])!!! */ ! 364: if (code0 == MEM && code1 == MEM) ! 365: return 0; ! 366: ! 367: cnst_diff0 = consecutive_operands (operands[0], operands[2]); ! 368: if (cnst_diff0 == 0) ! 369: return 0; ! 370: ! 371: cnst_diff1 = consecutive_operands (operands[1], operands[3]); ! 372: if (cnst_diff1 == 0) ! 373: return 0; ! 374: ! 375: if (cnst_diff0 & cnst_diff1) ! 376: { ! 377: /* The source and destination operands are consecutive. */ ! 378: ! 379: /* If the first move writes into the source of the second move, ! 380: we cannot combine. */ ! 381: if ((code0 == REG ! 382: && reg_overlap_mentioned_p (operands[0], operands[3])) ! 383: || (code0 == SUBREG ! 384: && subreg_overlap_mentioned_p (operands[0], operands[3]))) ! 385: return 0; ! 386: ! 387: if (cnst_diff0 & 1) ! 388: /* operands[0],[1] has higher addresses than operands[2],[3]. */ ! 389: swap_operands = 0; ! 390: else ! 391: /* operands[0],[1] has lower addresses than operands[2],[3]. */ ! 392: swap_operands = 1; ! 393: return 1; ! 394: } ! 395: return 0; ! 396: } ! 397: ! 398: /* Like reg_overlap_mentioned_p, but accepts a subreg rtx instead ! 399: of a reg. */ ! 400: ! 401: int ! 402: subreg_overlap_mentioned_p (subreg, x) ! 403: rtx subreg, x; ! 404: { ! 405: rtx reg = SUBREG_REG (subreg); ! 406: int regno = REGNO (reg) + SUBREG_WORD (subreg); ! 407: int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (subreg)); ! 408: return refers_to_regno_p (regno, endregno, x, 0); ! 409: } ! 410: ! 411: /* Return 1 if OP0 is a consecutive operand to OP1, 2 if OP1 is a ! 412: consecutive operand to OP0. ! 413: ! 414: This function is used to determine if addresses are consecutive, ! 415: and therefore possible to combine to fewer instructions. */ ! 416: ! 417: int ! 418: consecutive_operands (op0, op1) ! 419: rtx op0, op1; ! 420: { ! 421: RTX_CODE code0, code1; ! 422: int cnst_diff; ! 423: int regno_off0, regno_off1; ! 424: ! 425: code0 = GET_CODE (op0); ! 426: code1 = GET_CODE (op1); ! 427: ! 428: regno_off0 = 0; ! 429: if (code0 == SUBREG) ! 430: { ! 431: if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))) <= UNITS_PER_WORD) ! 432: return 0; ! 433: regno_off0 = SUBREG_WORD (op0); ! 434: op0 = SUBREG_REG (op0); ! 435: code0 = REG; ! 436: } ! 437: ! 438: regno_off1 = 0; ! 439: if (code1 == SUBREG) ! 440: { ! 441: if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))) <= UNITS_PER_WORD) ! 442: return 0; ! 443: regno_off1 = SUBREG_WORD (op1); ! 444: op1 = SUBREG_REG (op1); ! 445: code1 = REG; ! 446: } ! 447: ! 448: if (code0 != code1) ! 449: return 0; ! 450: ! 451: switch (code0) ! 452: { ! 453: case CONST_INT: ! 454: /* Cannot permit any symbolic constants, even if the consecutive ! 455: operand is 0, since a movl really performs sign extension. */ ! 456: if (code1 != CONST_INT) ! 457: return 0; ! 458: if ((INTVAL (op0) == 0 && INTVAL (op1) == 0) ! 459: || (INTVAL (op0) == -1 && INTVAL (op1) == -1)) ! 460: return 3; ! 461: if ((INTVAL (op0) == 0 && INTVAL (op1) > 0) ! 462: || (INTVAL (op0) == -1 && INTVAL (op1) < 0)) ! 463: return 2; ! 464: if ((INTVAL (op1) == 0 && INTVAL (op0) > 0) ! 465: || (INTVAL (op1) == -1 && INTVAL (op0) < 0)) ! 466: return 1; ! 467: break; ! 468: ! 469: case REG: ! 470: regno_off0 = REGNO (op0) + regno_off0; ! 471: regno_off1 = REGNO (op1) + regno_off1; ! 472: ! 473: cnst_diff = regno_off0 - regno_off1; ! 474: if (cnst_diff == 1) ! 475: { ! 476: /* movl with the highest numbered parameter (local) register as ! 477: source or destination, doesn't wrap to the lowest numbered local ! 478: (temporary) register. */ ! 479: ! 480: if (regno_off0 % 16 != 0) ! 481: return 1; ! 482: else ! 483: return 0; ! 484: } ! 485: else if (cnst_diff == -1) ! 486: { ! 487: if (regno_off1 % 16 != 0) ! 488: return 2; ! 489: else ! 490: return 0; ! 491: } ! 492: break; ! 493: ! 494: case MEM: ! 495: op0 = XEXP (op0, 0); ! 496: op1 = XEXP (op1, 0); ! 497: if (GET_CODE (op0) == CONST) ! 498: op0 = XEXP (op0, 0); ! 499: if (GET_CODE (op1) == CONST) ! 500: op1 = XEXP (op1, 0); ! 501: ! 502: cnst_diff = constant_diff (op0, op1); ! 503: if (cnst_diff) ! 504: { ! 505: if (cnst_diff == 4) ! 506: return 1; ! 507: else if (cnst_diff == -4) ! 508: return 2; ! 509: } ! 510: break; ! 511: } ! 512: return 0; ! 513: } ! 514: ! 515: /* Return the constant difference of the rtx expressions OP0 and OP1, ! 516: or 0 if they don't have a constant difference. ! 517: ! 518: This function is used to determine if addresses are consecutive, ! 519: and therefore possible to combine to fewer instructions. */ ! 520: ! 521: int ! 522: constant_diff (op0, op1) ! 523: rtx op0, op1; ! 524: { ! 525: RTX_CODE code0, code1; ! 526: int cnst_diff; ! 527: ! 528: code0 = GET_CODE (op0); ! 529: code1 = GET_CODE (op1); ! 530: ! 531: if (code0 != code1) ! 532: { ! 533: if (code0 == PLUS) ! 534: { ! 535: if (GET_CODE (XEXP (op0, 1)) == CONST_INT ! 536: && rtx_equal_p (op1, XEXP (op0, 0))) ! 537: return INTVAL (XEXP (op0, 1)); ! 538: } ! 539: else if (code1 == PLUS) ! 540: { ! 541: if (GET_CODE (XEXP (op1, 1)) == CONST_INT ! 542: && rtx_equal_p (op0, XEXP (op1, 0))) ! 543: return -INTVAL (XEXP (op1, 1)); ! 544: } ! 545: return 0; ! 546: } ! 547: ! 548: if (code0 == CONST_INT) ! 549: return INTVAL (op0) - INTVAL (op1); ! 550: ! 551: if (code0 == PLUS) ! 552: { ! 553: cnst_diff = constant_diff (XEXP (op0, 0), XEXP (op1, 0)); ! 554: if (cnst_diff) ! 555: return (rtx_equal_p (XEXP (op0, 1), XEXP (op1, 1))) ! 556: ? cnst_diff : 0; ! 557: cnst_diff = constant_diff (XEXP (op0, 1), XEXP (op1, 1)); ! 558: if (cnst_diff) ! 559: return (rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))) ! 560: ? cnst_diff : 0; ! 561: } ! 562: ! 563: return 0; ! 564: } ! 565: ! 566: int ! 567: already_sign_extended (insn, from_mode, op) ! 568: rtx insn; ! 569: enum machine_mode from_mode; ! 570: rtx op; ! 571: { ! 572: rtx xinsn, xdest, xsrc; ! 573: ! 574: for (;;) ! 575: { ! 576: insn = PREV_INSN (insn); ! 577: if (insn == 0) ! 578: return 0; ! 579: if (GET_CODE (insn) == NOTE || GET_CODE (insn) == JUMP_INSN) ! 580: continue; ! 581: if (GET_CODE (insn) == CALL_INSN && ! call_used_regs[REGNO (op)]) ! 582: continue; ! 583: if (GET_CODE (insn) != INSN) ! 584: return 0; ! 585: xinsn = PATTERN (insn); ! 586: ! 587: if (GET_CODE (xinsn) != SET) ! 588: return 0; ! 589: ! 590: xdest = SET_DEST (xinsn); ! 591: xsrc = SET_SRC (xinsn); ! 592: ! 593: if (GET_CODE (xdest) == SUBREG) ! 594: abort (); ! 595: ! 596: if ( ! REG_P (xdest)) ! 597: continue; ! 598: ! 599: if (REGNO (op) == REGNO (xdest) ! 600: && ((GET_CODE (xsrc) == SIGN_EXTEND ! 601: && GET_MODE (XEXP (xsrc, 0)) == from_mode) ! 602: || (GET_CODE (xsrc) == MEM ! 603: && GET_MODE (xsrc) == from_mode))) ! 604: return 1; ! 605: ! 606: /* The register is modified by another operation. */ ! 607: if (reg_overlap_mentioned_p (xdest, op)) ! 608: return 0; ! 609: } ! 610: } ! 611: ! 612: char * ! 613: output_move_double (operands) ! 614: rtx *operands; ! 615: { ! 616: if (GET_CODE (operands[1]) == CONST_DOUBLE) ! 617: { ! 618: if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT) ! 619: { ! 620: /* In an integer, the low-order word is in CONST_DOUBLE_LOW. */ ! 621: rtx const_op = operands[1]; ! 622: if ((CONST_DOUBLE_HIGH (const_op) == 0 ! 623: && CONST_DOUBLE_LOW (const_op) >= 0) ! 624: || (CONST_DOUBLE_HIGH (const_op) == -1 ! 625: && CONST_DOUBLE_LOW (const_op) < 0)) ! 626: { ! 627: operands[1] = gen_rtx (CONST_INT, VOIDmode, ! 628: CONST_DOUBLE_LOW (const_op)); ! 629: return "movl %1,%0"; ! 630: } ! 631: operands[1] = gen_rtx (CONST_INT, VOIDmode, ! 632: CONST_DOUBLE_HIGH (const_op)); ! 633: output_asm_insn ("movw %1,%0", operands); ! 634: operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 635: operands[1] = gen_rtx (CONST_INT, VOIDmode, ! 636: CONST_DOUBLE_LOW (const_op)); ! 637: return "movw %1,%0"; ! 638: } ! 639: else ! 640: { ! 641: /* In a real, the low-address word is in CONST_DOUBLE_LOW. */ ! 642: rtx const_op = operands[1]; ! 643: if ((CONST_DOUBLE_LOW (const_op) == 0 ! 644: && CONST_DOUBLE_HIGH (const_op) >= 0) ! 645: || (CONST_DOUBLE_LOW (const_op) == -1 ! 646: && CONST_DOUBLE_HIGH (const_op) < 0)) ! 647: { ! 648: operands[1] = gen_rtx (CONST_INT, VOIDmode, ! 649: CONST_DOUBLE_HIGH (const_op)); ! 650: return "movl %1,%0"; ! 651: } ! 652: operands[1] = gen_rtx (CONST_INT, VOIDmode, ! 653: CONST_DOUBLE_LOW (const_op)); ! 654: output_asm_insn ("movw %1,%0", operands); ! 655: operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 656: operands[1] = gen_rtx (CONST_INT, VOIDmode, ! 657: CONST_DOUBLE_HIGH (const_op)); ! 658: return "movw %1,%0"; ! 659: } ! 660: } ! 661: ! 662: return "movl %1,%0"; ! 663: } ! 664: ! 665: /* Output a shift insns, after having reduced integer arguments to ! 666: avoid as warnings. */ ! 667: ! 668: char * ! 669: output_shift (pattern, op2, mod) ! 670: char *pattern; ! 671: rtx op2; ! 672: int mod; ! 673: { ! 674: if (GET_CODE (op2) == CONST_INT) ! 675: { ! 676: int cnt = INTVAL (op2) % mod; ! 677: if (cnt == 0) ! 678: { ! 679: cc_status = cc_prev_status; ! 680: return ""; ! 681: } ! 682: op2 = gen_rtx (CONST_INT, VOIDmode, cnt); ! 683: } ! 684: return pattern; ! 685: } ! 686: ! 687: /* Return non-zero if the code of this rtx pattern is a relop. */ ! 688: ! 689: int ! 690: relop (op, mode) ! 691: rtx op; ! 692: enum machine_mode mode; ! 693: { ! 694: switch (GET_CODE (op)) ! 695: { ! 696: case EQ: ! 697: case NE: ! 698: case LT: ! 699: case LE: ! 700: case GE: ! 701: case GT: ! 702: case LTU: ! 703: case LEU: ! 704: case GEU: ! 705: case GTU: ! 706: return 1; ! 707: } ! 708: return 0; ! 709: } ! 710: ! 711: void ! 712: notice_update_cc (EXP, INSN) ! 713: rtx EXP, INSN; ! 714: { ! 715: switch (GET_CODE (EXP)) ! 716: { ! 717: case SET: ! 718: switch (GET_CODE (SET_DEST (EXP))) ! 719: { ! 720: case CC0: ! 721: cc_status.mdep = 0; ! 722: cc_status.flags = 0; ! 723: cc_status.value1 = 0; ! 724: cc_status.value2 = SET_SRC (EXP); ! 725: break; ! 726: ! 727: case PC: ! 728: break; ! 729: ! 730: case REG: ! 731: switch (GET_CODE (SET_SRC (EXP))) ! 732: { ! 733: case CALL: ! 734: goto call; ! 735: case MEM: ! 736: if (GET_MODE (SET_SRC (EXP)) == QImode ! 737: || GET_MODE (SET_SRC (EXP)) == HImode) ! 738: { ! 739: cc_status.mdep = 0; ! 740: cc_status.flags = CC_NO_OVERFLOW; ! 741: cc_status.value1 = SET_DEST (EXP); ! 742: cc_status.value2 = SET_SRC (EXP); ! 743: break; ! 744: } ! 745: /* else: Fall through. */ ! 746: case CONST_INT: ! 747: case SYMBOL_REF: ! 748: case LABEL_REF: ! 749: case CONST: ! 750: case CONST_DOUBLE: ! 751: case REG: ! 752: if (cc_status.value1 ! 753: && reg_overlap_mentioned_p (SET_DEST (EXP), ! 754: cc_status.value1)) ! 755: cc_status.value1 = 0; ! 756: if (cc_status.value2 ! 757: && reg_overlap_mentioned_p (SET_DEST (EXP), ! 758: cc_status.value2)) ! 759: cc_status.value2 = 0; ! 760: break; ! 761: ! 762: case UDIV: ! 763: case UMOD: ! 764: cc_status.mdep = CC_VALID_FOR_UNSIGNED; ! 765: cc_status.flags = CC_NO_OVERFLOW; ! 766: cc_status.value1 = SET_DEST (EXP); ! 767: cc_status.value2 = SET_SRC (EXP); ! 768: break; ! 769: default: ! 770: cc_status.mdep = 0; ! 771: cc_status.flags = CC_NO_OVERFLOW; ! 772: cc_status.value1 = SET_DEST (EXP); ! 773: cc_status.value2 = SET_SRC (EXP); ! 774: break; ! 775: } ! 776: break; ! 777: ! 778: case MEM: ! 779: switch (GET_CODE (SET_SRC (EXP))) ! 780: { ! 781: case REG: ! 782: if (GET_MODE (SET_SRC (EXP)) == QImode ! 783: || GET_MODE (SET_SRC (EXP)) == HImode) ! 784: { ! 785: cc_status.flags = CC_NO_OVERFLOW; ! 786: cc_status.value1 = SET_DEST (EXP); ! 787: cc_status.value2 = SET_SRC (EXP); ! 788: cc_status.mdep = 0; ! 789: break; ! 790: } ! 791: /* else: Fall through. */ ! 792: case CONST_INT: ! 793: case SYMBOL_REF: ! 794: case LABEL_REF: ! 795: case CONST: ! 796: case CONST_DOUBLE: ! 797: case MEM: ! 798: /* Need to forget cc_status about memory positions each ! 799: time a memory store is made, even if the memory store ! 800: insns in question doesn't modify the condition codes. */ ! 801: if (cc_status.value1 && ! 802: GET_CODE (cc_status.value1) == MEM) ! 803: cc_status.value1 = 0; ! 804: if (cc_status.value2 && ! 805: GET_CODE (cc_status.value2) == MEM) ! 806: cc_status.value2 = 0; ! 807: break; ! 808: case SIGN_EXTEND: ! 809: case FLOAT_EXTEND: ! 810: case FLOAT_TRUNCATE: ! 811: case FLOAT: ! 812: case FIX: ! 813: cc_status.flags = CC_NO_OVERFLOW; ! 814: cc_status.value1 = SET_DEST (EXP); ! 815: cc_status.value2 = SET_SRC (EXP); ! 816: cc_status.mdep = 0; ! 817: break; ! 818: ! 819: default: ! 820: abort (); ! 821: } ! 822: break; ! 823: ! 824: default: ! 825: abort (); ! 826: } ! 827: break; ! 828: ! 829: case CALL: ! 830: call: ! 831: CC_STATUS_INIT; ! 832: break; ! 833: /* Do calls preserve the condition codes? (At least forget ! 834: cc_status expressions if they refer to registers ! 835: not preserved across calls. Also forget expressions ! 836: about memory contents.) */ ! 837: if (cc_status.value1 ! 838: && (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15), ! 839: cc_status.value1, 0) ! 840: || GET_CODE (cc_status.value1) == MEM)) ! 841: cc_status.value1 = 0; ! 842: if (cc_status.value2 ! 843: && (refers_to_regno_p (PYR_TREG (0), PYR_TREG (15), ! 844: cc_status.value2, 0) ! 845: || GET_CODE (cc_status.value2) == MEM)) ! 846: cc_status.value2 = 0; ! 847: break; ! 848: ! 849: default: ! 850: CC_STATUS_INIT; ! 851: } ! 852: } ! 853: ! 854: void ! 855: forget_cc_if_dependent (op) ! 856: rtx op; ! 857: { ! 858: cc_status = cc_prev_status; ! 859: if (cc_status.value1 && reg_overlap_mentioned_p (op, cc_status.value1)) ! 860: cc_status.value1 = 0; ! 861: if (cc_status.value2 && reg_overlap_mentioned_p (op, cc_status.value2)) ! 862: cc_status.value2 = 0; ! 863: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.