|
|
1.1 ! root 1: /* Subroutines for insn-output.c for HPPA. ! 2: Copyright (C) 1992 Free Software Foundation, Inc. ! 3: Contributed by Tim Moore ([email protected]), based on sparc.c ! 4: ! 5: This file is part of GNU CC. ! 6: ! 7: GNU CC is free software; you can redistribute it and/or modify ! 8: it under the terms of the GNU General Public License as published by ! 9: the Free Software Foundation; either version 2, or (at your option) ! 10: any later version. ! 11: ! 12: GNU CC is distributed in the hope that it will be useful, ! 13: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: GNU General Public License for more details. ! 16: ! 17: You should have received a copy of the GNU General Public License ! 18: along with GNU CC; see the file COPYING. If not, write to ! 19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 20: ! 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 "flags.h" ! 33: #include "tree.h" ! 34: #include "c-tree.h" ! 35: #include "expr.h" ! 36: #include "obstack.h" ! 37: ! 38: /* Save the operands last given to a compare for use when we ! 39: generate a scc or bcc insn. */ ! 40: ! 41: rtx hppa_compare_op0, hppa_compare_op1; ! 42: enum cmp_type hppa_branch_type; ! 43: ! 44: rtx hppa_save_pic_table_rtx; ! 45: ! 46: /* Set by the FUNCTION_PROFILER macro. */ ! 47: int hp_profile_labelno; ! 48: ! 49: static rtx find_addr_reg (); ! 50: ! 51: /* Return non-zero only if OP is a register of mode MODE, ! 52: or CONST0_RTX. */ ! 53: int ! 54: reg_or_0_operand (op, mode) ! 55: rtx op; ! 56: enum machine_mode mode; ! 57: { ! 58: return (op == CONST0_RTX (mode) || register_operand (op, mode)); ! 59: } ! 60: ! 61: int ! 62: call_operand_address (op, mode) ! 63: rtx op; ! 64: enum machine_mode mode; ! 65: { ! 66: return (REG_P (op) ! 67: || (CONSTANT_P (op) && ! TARGET_LONG_CALLS)); ! 68: } ! 69: ! 70: /* Return 1 if X contains a symbolic expression. We know these ! 71: expressions will have one of a few well defined forms, so ! 72: we need only check those forms. */ ! 73: int ! 74: symbolic_expression_p (x) ! 75: register rtx x; ! 76: { ! 77: ! 78: /* Strip off any HIGH. */ ! 79: if (GET_CODE (x) == HIGH) ! 80: x = XEXP (x, 0); ! 81: ! 82: return (symbolic_operand (x, VOIDmode)); ! 83: } ! 84: ! 85: int ! 86: symbolic_operand (op, mode) ! 87: register rtx op; ! 88: enum machine_mode mode; ! 89: { ! 90: switch (GET_CODE (op)) ! 91: { ! 92: case SYMBOL_REF: ! 93: case LABEL_REF: ! 94: return 1; ! 95: case CONST: ! 96: op = XEXP (op, 0); ! 97: return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF ! 98: || GET_CODE (XEXP (op, 0)) == LABEL_REF) ! 99: && GET_CODE (XEXP (op, 1)) == CONST_INT); ! 100: default: ! 101: return 0; ! 102: } ! 103: } ! 104: ! 105: /* Return truth value of statement that OP is a symbolic memory ! 106: operand of mode MODE. */ ! 107: ! 108: int ! 109: symbolic_memory_operand (op, mode) ! 110: rtx op; ! 111: enum machine_mode mode; ! 112: { ! 113: if (GET_CODE (op) == SUBREG) ! 114: op = SUBREG_REG (op); ! 115: if (GET_CODE (op) != MEM) ! 116: return 0; ! 117: op = XEXP (op, 0); ! 118: return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST ! 119: || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF); ! 120: } ! 121: ! 122: /* Return 1 if the operand is either a register or a memory operand that is ! 123: not symbolic. */ ! 124: ! 125: int ! 126: reg_or_nonsymb_mem_operand (op, mode) ! 127: register rtx op; ! 128: enum machine_mode mode; ! 129: { ! 130: if (register_operand (op, mode)) ! 131: return 1; ! 132: ! 133: if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode)) ! 134: return 1; ! 135: ! 136: return 0; ! 137: } ! 138: ! 139: /* Return 1 if the operand is either a register, zero, or a memory operand ! 140: that is not symbolic. */ ! 141: ! 142: int ! 143: reg_or_0_or_nonsymb_mem_operand (op, mode) ! 144: register rtx op; ! 145: enum machine_mode mode; ! 146: { ! 147: if (register_operand (op, mode)) ! 148: return 1; ! 149: ! 150: if (op == CONST0_RTX (mode)) ! 151: return 1; ! 152: ! 153: if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode)) ! 154: return 1; ! 155: ! 156: return 0; ! 157: } ! 158: ! 159: /* Accept any constant that can be moved in one instructions into a ! 160: general register. */ ! 161: int ! 162: cint_ok_for_move (intval) ! 163: int intval; ! 164: { ! 165: /* OK if ldo, ldil, or zdepi, can be used. */ ! 166: return (VAL_14_BITS_P (intval) || (intval & 0x7ff) == 0 ! 167: || zdepi_cint_p (intval)); ! 168: } ! 169: ! 170: /* Accept anything that can be moved in one instruction into a general ! 171: register. */ ! 172: int ! 173: move_operand (op, mode) ! 174: rtx op; ! 175: enum machine_mode mode; ! 176: { ! 177: if (register_operand (op, mode)) ! 178: return 1; ! 179: ! 180: if (GET_CODE (op) == CONST_INT) ! 181: return cint_ok_for_move (INTVAL (op)); ! 182: ! 183: if (GET_MODE (op) != mode) ! 184: return 0; ! 185: if (GET_CODE (op) == SUBREG) ! 186: op = SUBREG_REG (op); ! 187: if (GET_CODE (op) != MEM) ! 188: return 0; ! 189: ! 190: op = XEXP (op, 0); ! 191: if (GET_CODE (op) == LO_SUM) ! 192: return (register_operand (XEXP (op, 0), Pmode) ! 193: && CONSTANT_P (XEXP (op, 1))); ! 194: return memory_address_p (mode, op); ! 195: } ! 196: ! 197: /* Accept REG and any CONST_INT that can be moved in one instruction into a ! 198: general register. */ ! 199: int ! 200: reg_or_cint_move_operand (op, mode) ! 201: rtx op; ! 202: enum machine_mode mode; ! 203: { ! 204: if (register_operand (op, mode)) ! 205: return 1; ! 206: ! 207: if (GET_CODE (op) == CONST_INT) ! 208: return cint_ok_for_move (INTVAL (op)); ! 209: ! 210: return 0; ! 211: } ! 212: ! 213: int ! 214: pic_operand (op, mode) ! 215: rtx op; ! 216: enum machine_mode mode; ! 217: { ! 218: return flag_pic && GET_CODE (op) == LABEL_REF; ! 219: } ! 220: ! 221: int ! 222: fp_reg_operand (op, mode) ! 223: rtx op; ! 224: enum machine_mode mode; ! 225: { ! 226: return reg_renumber && FP_REG_P (op); ! 227: } ! 228: ! 229: ! 230: extern int current_function_uses_pic_offset_table; ! 231: extern rtx force_reg (), validize_mem (); ! 232: ! 233: /* The rtx for the global offset table which is a special form ! 234: that *is* a position independent symbolic constant. */ ! 235: rtx pic_pc_rtx; ! 236: ! 237: /* Ensure that we are not using patterns that are not OK with PIC. */ ! 238: ! 239: int ! 240: check_pic (i) ! 241: int i; ! 242: { ! 243: extern rtx recog_operand[]; ! 244: switch (flag_pic) ! 245: { ! 246: case 1: ! 247: if (GET_CODE (recog_operand[i]) == SYMBOL_REF ! 248: || (GET_CODE (recog_operand[i]) == CONST ! 249: && ! rtx_equal_p (pic_pc_rtx, recog_operand[i]))) ! 250: abort (); ! 251: case 2: ! 252: default: ! 253: return 1; ! 254: } ! 255: } ! 256: ! 257: /* Return truth value of whether OP can be used as an operand in a ! 258: three operand arithmetic insn that accepts registers of mode MODE ! 259: or 14-bit signed integers. */ ! 260: int ! 261: arith_operand (op, mode) ! 262: rtx op; ! 263: enum machine_mode mode; ! 264: { ! 265: return (register_operand (op, mode) ! 266: || (GET_CODE (op) == CONST_INT && INT_14_BITS (op))); ! 267: } ! 268: ! 269: /* Return truth value of whether OP can be used as an operand in a ! 270: three operand arithmetic insn that accepts registers of mode MODE ! 271: or 11-bit signed integers. */ ! 272: int ! 273: arith11_operand (op, mode) ! 274: rtx op; ! 275: enum machine_mode mode; ! 276: { ! 277: return (register_operand (op, mode) ! 278: || (GET_CODE (op) == CONST_INT && INT_11_BITS (op))); ! 279: } ! 280: ! 281: /* A constant integer suitable for use in a PRE_MODIFY memory ! 282: reference. */ ! 283: int ! 284: pre_cint_operand (op, mode) ! 285: rtx op; ! 286: enum machine_mode mode; ! 287: { ! 288: return (GET_CODE (op) == CONST_INT ! 289: && INTVAL (op) >= -0x2000 && INTVAL (op) < 0x10); ! 290: } ! 291: ! 292: /* A constant integer suitable for use in a POST_MODIFY memory ! 293: reference. */ ! 294: int ! 295: post_cint_operand (op, mode) ! 296: rtx op; ! 297: enum machine_mode mode; ! 298: { ! 299: return (GET_CODE (op) == CONST_INT ! 300: && INTVAL (op) < 0x2000 && INTVAL (op) >= -0x10); ! 301: } ! 302: ! 303: int ! 304: arith_double_operand (op, mode) ! 305: rtx op; ! 306: enum machine_mode mode; ! 307: { ! 308: return (register_operand (op, mode) ! 309: || (GET_CODE (op) == CONST_DOUBLE ! 310: && GET_MODE (op) == mode ! 311: && VAL_14_BITS_P (CONST_DOUBLE_LOW (op)) ! 312: && (CONST_DOUBLE_HIGH (op) >= 0 ! 313: == ((CONST_DOUBLE_LOW (op) & 0x1000) == 0)))); ! 314: } ! 315: ! 316: /* Return truth value of whether OP is a integer which fits the ! 317: range constraining immediate operands in three-address insns. */ ! 318: ! 319: int ! 320: int5_operand (op, mode) ! 321: rtx op; ! 322: enum machine_mode mode; ! 323: { ! 324: return (GET_CODE (op) == CONST_INT && INT_5_BITS (op)); ! 325: } ! 326: ! 327: int ! 328: uint5_operand (op, mode) ! 329: rtx op; ! 330: enum machine_mode mode; ! 331: { ! 332: return (GET_CODE (op) == CONST_INT && INT_U5_BITS (op)); ! 333: } ! 334: ! 335: ! 336: int ! 337: int11_operand (op, mode) ! 338: rtx op; ! 339: enum machine_mode mode; ! 340: { ! 341: return (GET_CODE (op) == CONST_INT && INT_11_BITS (op)); ! 342: } ! 343: ! 344: int ! 345: arith5_operand (op, mode) ! 346: rtx op; ! 347: enum machine_mode mode; ! 348: { ! 349: return register_operand (op, mode) || int5_operand (op, mode); ! 350: } ! 351: ! 352: /* True iff zdepi can be used to generate this CONST_INT. */ ! 353: int ! 354: zdepi_cint_p (x) ! 355: unsigned x; ! 356: { ! 357: unsigned lsb_mask, t; ! 358: ! 359: /* This might not be obvious, but it's at least fast. ! 360: This function is critcal; we don't have the time loops would take. */ ! 361: lsb_mask = x & -x; ! 362: t = ((x >> 4) + lsb_mask) & ~(lsb_mask - 1); ! 363: /* Return true iff t is a power of two. */ ! 364: return ((t & (t - 1)) == 0); ! 365: } ! 366: ! 367: /* True iff depi or extru can be used to compute (reg & mask). */ ! 368: int ! 369: and_mask_p (mask) ! 370: unsigned mask; ! 371: { ! 372: mask = ~mask; ! 373: mask += mask & -mask; ! 374: return (mask & (mask - 1)) == 0; ! 375: } ! 376: ! 377: /* True iff depi or extru can be used to compute (reg & OP). */ ! 378: int ! 379: and_operand (op, mode) ! 380: rtx op; ! 381: enum machine_mode mode; ! 382: { ! 383: return (register_operand (op, mode) ! 384: || (GET_CODE (op) == CONST_INT && and_mask_p (INTVAL (op)))); ! 385: } ! 386: ! 387: /* True iff depi can be used to compute (reg | MASK). */ ! 388: int ! 389: ior_mask_p (mask) ! 390: unsigned mask; ! 391: { ! 392: mask += mask & -mask; ! 393: return (mask & (mask - 1)) == 0; ! 394: } ! 395: ! 396: /* True iff depi can be used to compute (reg | OP). */ ! 397: int ! 398: ior_operand (op, mode) ! 399: rtx op; ! 400: enum machine_mode mode; ! 401: { ! 402: return (GET_CODE (op) == CONST_INT && ior_mask_p (INTVAL (op))); ! 403: } ! 404: ! 405: int ! 406: lhs_lshift_operand (op, mode) ! 407: rtx op; ! 408: enum machine_mode mode; ! 409: { ! 410: return register_operand (op, mode) || lhs_lshift_cint_operand (op, mode); ! 411: } ! 412: ! 413: /* True iff OP is a CONST_INT of the forms 0...0xxxx or 0...01...1xxxx. ! 414: Such values can be the left hand side x in (x << r), using the zvdepi ! 415: instruction. */ ! 416: int ! 417: lhs_lshift_cint_operand (op, mode) ! 418: rtx op; ! 419: enum machine_mode mode; ! 420: { ! 421: unsigned x; ! 422: if (GET_CODE (op) != CONST_INT) ! 423: return 0; ! 424: x = INTVAL (op) >> 4; ! 425: return (x & (x + 1)) == 0; ! 426: } ! 427: ! 428: int ! 429: arith32_operand (op, mode) ! 430: rtx op; ! 431: enum machine_mode mode; ! 432: { ! 433: return register_operand (op, mode) || GET_CODE (op) == CONST_INT; ! 434: } ! 435: ! 436: int ! 437: pc_or_label_operand (op, mode) ! 438: rtx op; ! 439: enum machine_mode mode; ! 440: { ! 441: return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF); ! 442: } ! 443: ! 444: /* Legitimize PIC addresses. If the address is already ! 445: position-independent, we return ORIG. Newly generated ! 446: position-independent addresses go to REG. If we need more ! 447: than one register, we lose. */ ! 448: ! 449: rtx ! 450: legitimize_pic_address (orig, mode, reg) ! 451: rtx orig, reg; ! 452: enum machine_mode mode; ! 453: { ! 454: rtx pic_ref = orig; ! 455: ! 456: if (GET_CODE (orig) == SYMBOL_REF) ! 457: { ! 458: if (reg == 0) ! 459: abort (); ! 460: ! 461: if (flag_pic == 2) ! 462: { ! 463: emit_insn (gen_rtx (SET, VOIDmode, reg, ! 464: gen_rtx (HIGH, Pmode, orig))); ! 465: emit_insn (gen_rtx (SET, VOIDmode, reg, ! 466: gen_rtx (LO_SUM, Pmode, reg, orig))); ! 467: orig = reg; ! 468: } ! 469: pic_ref = gen_rtx (MEM, Pmode, ! 470: gen_rtx (PLUS, Pmode, ! 471: pic_offset_table_rtx, orig)); ! 472: current_function_uses_pic_offset_table = 1; ! 473: RTX_UNCHANGING_P (pic_ref) = 1; ! 474: emit_move_insn (reg, pic_ref); ! 475: return reg; ! 476: } ! 477: else if (GET_CODE (orig) == CONST) ! 478: { ! 479: rtx base, offset; ! 480: ! 481: if (GET_CODE (XEXP (orig, 0)) == PLUS ! 482: && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) ! 483: return orig; ! 484: ! 485: if (reg == 0) ! 486: abort (); ! 487: ! 488: if (GET_CODE (XEXP (orig, 0)) == PLUS) ! 489: { ! 490: base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); ! 491: orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, ! 492: base == reg ? 0 : reg); ! 493: } ! 494: else abort (); ! 495: if (GET_CODE (orig) == CONST_INT) ! 496: { ! 497: if (INT_14_BITS (orig)) ! 498: return plus_constant_for_output (base, INTVAL (orig)); ! 499: orig = force_reg (Pmode, orig); ! 500: } ! 501: pic_ref = gen_rtx (PLUS, Pmode, base, orig); ! 502: /* Likewise, should we set special REG_NOTEs here? */ ! 503: } ! 504: return pic_ref; ! 505: } ! 506: ! 507: /* Set up PIC-specific rtl. This should not cause any insns ! 508: to be emitted. */ ! 509: ! 510: void ! 511: initialize_pic () ! 512: { ! 513: } ! 514: ! 515: /* Emit special PIC prologues and epilogues. */ ! 516: ! 517: void ! 518: finalize_pic () ! 519: { ! 520: if (hppa_save_pic_table_rtx) ! 521: { ! 522: emit_insn_after (gen_rtx (SET, VOIDmode, ! 523: hppa_save_pic_table_rtx, ! 524: gen_rtx (REG, Pmode, 19)), ! 525: get_insns ()); ! 526: /* Need to emit this whether or not we obey regdecls, ! 527: since setjmp/longjmp can cause life info to screw up. */ ! 528: hppa_save_pic_table_rtx = 0; ! 529: } ! 530: emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx)); ! 531: ! 532: } ! 533: ! 534: /* Try machine-dependent ways of modifying an illegitimate address ! 535: to be legitimate. If we find one, return the new, valid address. ! 536: This macro is used in only one place: `memory_address' in explow.c. ! 537: ! 538: OLDX is the address as it was before break_out_memory_refs was called. ! 539: In some cases it is useful to look at this to decide what needs to be done. ! 540: ! 541: MODE and WIN are passed so that this macro can use ! 542: GO_IF_LEGITIMATE_ADDRESS. ! 543: ! 544: It is always safe for this macro to do nothing. It exists to recognize ! 545: opportunities to optimize the output. ! 546: ! 547: For the PA, transform: ! 548: ! 549: memory(X + <large int>) ! 550: ! 551: into: ! 552: ! 553: if (<large int> & mask) >= 16 ! 554: Y = (<large int> & ~mask) + mask + 1 Round up. ! 555: else ! 556: Y = (<large int> & ~mask) Round down. ! 557: Z = X + Y ! 558: memory (Z + (<large int> - Y)); ! 559: ! 560: This is for CSE to find several similar references, and only use one Z. ! 561: ! 562: X can either be a SYMBOL_REF or REG, but because combine can not ! 563: perform a 4->2 combination we do nothing for SYMBOL_REF + D where ! 564: D will not fit in 14 bits. ! 565: ! 566: MODE_FLOAT references allow displacements which fit in 5 bits, so use ! 567: 0x1f as the mask. ! 568: ! 569: MODE_INT references allow displacements which fit in 14 bits, so use ! 570: 0x3fff as the mask. ! 571: ! 572: This relies on the fact that most mode MODE_FLOAT references will use FP ! 573: registers and most mode MODE_INT references will use integer registers. ! 574: (In the rare case of an FP register used in an integer MODE, we depend ! 575: on secondary reloads to clean things up.) ! 576: ! 577: ! 578: It is also beneficial to handle (plus (mult (X) (Y)) (Z)) in a special ! 579: manner if Y is 2, 4, or 8. (allows more shadd insns and shifted indexed ! 580: adressing modes to be used). ! 581: ! 582: Put X and Z into registers. Then put the entire expression into ! 583: a register. */ ! 584: ! 585: rtx ! 586: hppa_legitimize_address (x, oldx, mode) ! 587: rtx x, oldx; ! 588: enum machine_mode mode; ! 589: { ! 590: ! 591: rtx orig = x; ! 592: ! 593: /* Strip off CONST. */ ! 594: if (GET_CODE (x) == CONST) ! 595: x = XEXP (x, 0); ! 596: ! 597: if (GET_CODE (x) == PLUS ! 598: && GET_CODE (XEXP (x, 1)) == CONST_INT ! 599: && (GET_CODE (XEXP (x, 0)) == SYMBOL_REF ! 600: || GET_CODE (XEXP (x, 0)) == REG)) ! 601: { ! 602: rtx int_part, ptr_reg; ! 603: int newoffset; ! 604: int offset = INTVAL (XEXP (x, 1)); ! 605: int mask = GET_MODE_CLASS (mode) == MODE_FLOAT ? 0x1f : 0x3fff; ! 606: ! 607: /* Choose which way to round the offset. Round up if we ! 608: are >= halfway to the next boundary. */ ! 609: if ((offset & mask) >= ((mask + 1) / 2)) ! 610: newoffset = (offset & ~ mask) + mask + 1; ! 611: else ! 612: newoffset = (offset & ~ mask); ! 613: ! 614: /* If the newoffset will not fit in 14 bits (ldo), then ! 615: handling this would take 4 or 5 instructions (2 to load ! 616: the SYMBOL_REF + 1 or 2 to load the newoffset + 1 to ! 617: add the new offset and the SYMBOL_REF.) Combine can ! 618: not handle 4->2 or 5->2 combinations, so do not create ! 619: them. */ ! 620: if (! VAL_14_BITS_P (newoffset) ! 621: && GET_CODE (XEXP (x, 0)) == SYMBOL_REF) ! 622: { ! 623: rtx const_part = gen_rtx (CONST, VOIDmode, ! 624: gen_rtx (PLUS, Pmode, ! 625: XEXP (x, 0), ! 626: GEN_INT (newoffset))); ! 627: rtx tmp_reg ! 628: = force_reg (Pmode, ! 629: gen_rtx (HIGH, Pmode, const_part)); ! 630: ptr_reg ! 631: = force_reg (Pmode, ! 632: gen_rtx (LO_SUM, Pmode, ! 633: tmp_reg, const_part)); ! 634: } ! 635: else ! 636: { ! 637: if (! VAL_14_BITS_P (newoffset)) ! 638: int_part = force_reg (Pmode, GEN_INT (newoffset)); ! 639: else ! 640: int_part = GEN_INT (newoffset); ! 641: ! 642: ptr_reg = force_reg (Pmode, ! 643: gen_rtx (PLUS, Pmode, ! 644: force_reg (Pmode, XEXP (x, 0)), ! 645: int_part)); ! 646: } ! 647: return plus_constant (ptr_reg, offset - newoffset); ! 648: } ! 649: if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT ! 650: && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT ! 651: && shadd_constant_p (INTVAL (XEXP (XEXP (x, 0), 1)))) ! 652: { ! 653: int val = INTVAL (XEXP (XEXP (x, 0), 1)); ! 654: rtx reg1, reg2; ! 655: reg1 = force_reg (Pmode, force_operand (XEXP (x, 1), 0)); ! 656: reg2 = force_reg (Pmode, ! 657: force_operand (XEXP (XEXP (x, 0), 0), 0)); ! 658: return force_reg (Pmode, ! 659: gen_rtx (PLUS, Pmode, ! 660: gen_rtx (MULT, Pmode, reg2, ! 661: GEN_INT (val)), ! 662: reg1)); ! 663: } ! 664: if (flag_pic) ! 665: return legitimize_pic_address (x, mode, gen_reg_rtx (Pmode)); ! 666: ! 667: return orig; ! 668: } ! 669: ! 670: /* For the HPPA, REG and REG+CONST is cost 0 ! 671: and addresses involving symbolic constants are cost 2. ! 672: ! 673: PIC addresses are very expensive. ! 674: ! 675: It is no coincidence that this has the same structure ! 676: as GO_IF_LEGITIMATE_ADDRESS. */ ! 677: int ! 678: hppa_address_cost (X) ! 679: rtx X; ! 680: { ! 681: if (GET_CODE (X) == PLUS) ! 682: return 1; ! 683: else if (GET_CODE (X) == LO_SUM) ! 684: return 1; ! 685: else if (GET_CODE (X) == HIGH) ! 686: return 2; ! 687: return 4; ! 688: } ! 689: ! 690: /* Emit insns to move operands[1] into operands[0]. ! 691: ! 692: Return 1 if we have written out everything that needs to be done to ! 693: do the move. Otherwise, return 0 and the caller will emit the move ! 694: normally. */ ! 695: ! 696: int ! 697: emit_move_sequence (operands, mode, scratch_reg) ! 698: rtx *operands; ! 699: enum machine_mode mode; ! 700: rtx scratch_reg; ! 701: { ! 702: register rtx operand0 = operands[0]; ! 703: register rtx operand1 = operands[1]; ! 704: ! 705: /* Handle secondary reloads for loads/stores of FP registers from ! 706: REG+D addresses where D does not fit in 5 bits. */ ! 707: if (fp_reg_operand (operand0, mode) ! 708: && GET_CODE (operand1) == MEM ! 709: /* Using DFmode forces only short displacements be be ! 710: recognized as valid in reg+d addressing modes. */ ! 711: && ! memory_address_p (DFmode, XEXP (operand1, 0)) ! 712: && scratch_reg) ! 713: { ! 714: emit_move_insn (scratch_reg, XEXP (operand1 , 0)); ! 715: emit_insn (gen_rtx (SET, VOIDmode, operand0, gen_rtx (MEM, mode, ! 716: scratch_reg))); ! 717: return 1; ! 718: } ! 719: else if (fp_reg_operand (operand1, mode) ! 720: && GET_CODE (operand0) == MEM ! 721: /* Using DFmode forces only short displacements be be ! 722: recognized as valid in reg+d addressing modes. */ ! 723: && ! memory_address_p (DFmode, XEXP (operand0, 0)) ! 724: && scratch_reg) ! 725: { ! 726: emit_move_insn (scratch_reg, XEXP (operand0 , 0)); ! 727: emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (MEM, mode, scratch_reg), ! 728: operand1)); ! 729: return 1; ! 730: } ! 731: /* Handle secondary reloads for loads of FP registers from constant ! 732: expressions by forcing the constant into memory. ! 733: ! 734: use scratch_reg to hold the address of the memory location. ! 735: ! 736: ??? The proper fix is to change PREFERRED_RELOAD_CLASS to return ! 737: NO_REGS when presented with a const_int and an register class ! 738: containing only FP registers. Doing so unfortunately creates ! 739: more problems than it solves. Fix this for 2.5. */ ! 740: else if (fp_reg_operand (operand0, mode) ! 741: && CONSTANT_P (operand1) ! 742: && scratch_reg) ! 743: { ! 744: rtx xoperands[2]; ! 745: ! 746: /* Force the constant into memory and put the address of the ! 747: memory location into scratch_reg. */ ! 748: xoperands[0] = scratch_reg; ! 749: xoperands[1] = XEXP (force_const_mem (mode, operand1), 0); ! 750: emit_move_sequence (xoperands, mode, 0); ! 751: ! 752: /* Now load the destination register. */ ! 753: emit_insn (gen_rtx (SET, mode, operand0, ! 754: gen_rtx (MEM, mode, scratch_reg))); ! 755: return 1; ! 756: } ! 757: /* Handle secondary reloads for SAR. These occur when trying to load ! 758: the SAR from memory or from a FP register. */ ! 759: else if (GET_CODE (operand0) == REG ! 760: && REGNO_REG_CLASS (REGNO (operand0)) == SHIFT_REGS ! 761: && (GET_CODE (operand1) == MEM ! 762: || (GET_CODE (operand1) == REG ! 763: && FP_REG_CLASS_P (REGNO_REG_CLASS (REGNO (operand1))))) ! 764: && scratch_reg) ! 765: { ! 766: emit_move_insn (scratch_reg, operand1); ! 767: emit_move_insn (operand0, scratch_reg); ! 768: return 1; ! 769: } ! 770: /* Handle most common case: storing into a register. */ ! 771: else if (register_operand (operand0, mode)) ! 772: { ! 773: if (register_operand (operand1, mode) ! 774: || (GET_CODE (operand1) == CONST_INT && INT_14_BITS (operand1)) ! 775: || (operand1 == CONST0_RTX (mode)) ! 776: || (GET_CODE (operand1) == HIGH ! 777: && !symbolic_operand (XEXP (operand1, 0))) ! 778: /* Only `general_operands' can come here, so MEM is ok. */ ! 779: || GET_CODE (operand1) == MEM) ! 780: { ! 781: /* Run this case quickly. */ ! 782: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1)); ! 783: return 1; ! 784: } ! 785: } ! 786: else if (GET_CODE (operand0) == MEM) ! 787: { ! 788: if (register_operand (operand1, mode) || operand1 == CONST0_RTX (mode)) ! 789: { ! 790: /* Run this case quickly. */ ! 791: emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1)); ! 792: return 1; ! 793: } ! 794: if (! reload_in_progress) ! 795: { ! 796: operands[0] = validize_mem (operand0); ! 797: operands[1] = operand1 = force_reg (mode, operand1); ! 798: } ! 799: } ! 800: ! 801: /* Simplify the source if we need to. */ ! 802: if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode) ! 803: || (GET_CODE (operand1) == HIGH ! 804: && symbolic_operand (XEXP (operand1, 0), mode) ! 805: && TARGET_KERNEL)) ! 806: { ! 807: int ishighonly = 0; ! 808: ! 809: if (GET_CODE (operand1) == HIGH) ! 810: { ! 811: ishighonly = 1; ! 812: operand1 = XEXP (operand1, 0); ! 813: } ! 814: if (symbolic_operand (operand1, mode)) ! 815: { ! 816: if (flag_pic) ! 817: { ! 818: rtx temp = reload_in_progress ? operand0 : gen_reg_rtx (Pmode); ! 819: operands[1] = legitimize_pic_address (operand1, mode, temp); ! 820: emit_insn (gen_rtx (SET, VOIDmode, operand0, operands[1])); ! 821: } ! 822: /* On the HPPA, references to data space are supposed to */ ! 823: /* use dp, register 27, but showing it in the RTL inhibits various ! 824: cse and loop optimizations. */ ! 825: else ! 826: { ! 827: rtx temp, set; ! 828: ! 829: if (reload_in_progress) ! 830: temp = scratch_reg ? scratch_reg : operand0; ! 831: else ! 832: temp = gen_reg_rtx (mode); ! 833: ! 834: if (ishighonly) ! 835: set = gen_rtx (SET, mode, operand0, temp); ! 836: else ! 837: set = gen_rtx (SET, VOIDmode, ! 838: operand0, ! 839: gen_rtx (LO_SUM, mode, temp, operand1)); ! 840: ! 841: emit_insn (gen_rtx (SET, VOIDmode, ! 842: temp, ! 843: gen_rtx (HIGH, mode, operand1))); ! 844: if (TARGET_SHARED_LIBS ! 845: && function_label_operand (operand1, mode)) ! 846: { ! 847: rtx temp = reload_in_progress ? scratch_reg ! 848: : gen_reg_rtx (mode); ! 849: if (!temp) ! 850: abort (); ! 851: emit_insn (gen_rtx (PARALLEL, VOIDmode, ! 852: gen_rtvec (2, ! 853: set, ! 854: gen_rtx (CLOBBER, VOIDmode, ! 855: temp)))); ! 856: } ! 857: else ! 858: emit_insn (set); ! 859: return 1; ! 860: } ! 861: return 1; ! 862: } ! 863: else if (GET_CODE (operand1) != CONST_INT ! 864: || (! INT_14_BITS (operand1) ! 865: && ! ((INTVAL (operand1) & 0x7ff) == 0) ! 866: && ! zdepi_cint_p (INTVAL (operand1)))) ! 867: { ! 868: rtx temp = reload_in_progress ? operand0 : gen_reg_rtx (mode); ! 869: emit_insn (gen_rtx (SET, VOIDmode, temp, ! 870: gen_rtx (HIGH, mode, operand1))); ! 871: operands[1] = gen_rtx (LO_SUM, mode, temp, operand1); ! 872: } ! 873: } ! 874: /* Now have insn-emit do whatever it normally does. */ ! 875: return 0; ! 876: } ! 877: ! 878: /* Does operand (which is a symbolic_operand) live in text space? If ! 879: so SYMBOL_REF_FLAG, which is set by ENCODE_SECTION_INFO, will be true. */ ! 880: ! 881: int ! 882: read_only_operand (operand) ! 883: rtx operand; ! 884: { ! 885: if (GET_CODE (operand) == CONST) ! 886: operand = XEXP (XEXP (operand, 0), 0); ! 887: if (GET_CODE (operand) == SYMBOL_REF) ! 888: return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand); ! 889: return 1; ! 890: } ! 891: ! 892: ! 893: /* Return the best assembler insn template ! 894: for moving operands[1] into operands[0] as a fullword. ! 895: ! 896: For CONST_DOUBLE and CONST_INT we should also check for ! 897: other values we can load directly via zdepi, ldil, etc. ! 898: ??? Do this for 2.5. */ ! 899: ! 900: char * ! 901: singlemove_string (operands) ! 902: rtx *operands; ! 903: { ! 904: if (GET_CODE (operands[0]) == MEM) ! 905: return "stw %r1,%0"; ! 906: else if (GET_CODE (operands[1]) == MEM) ! 907: return "ldw %1,%0"; ! 908: else if (GET_CODE (operands[1]) == CONST_DOUBLE ! 909: && GET_MODE (operands[1]) == SFmode) ! 910: { ! 911: int i; ! 912: union real_extract u; ! 913: union float_extract { float f; int i; } v; ! 914: ! 915: bcopy (&CONST_DOUBLE_LOW (operands[1]), &u, sizeof u); ! 916: v.f = REAL_VALUE_TRUNCATE (SFmode, u.d); ! 917: i = v.i; ! 918: ! 919: operands[1] = gen_rtx (CONST_INT, VOIDmode, i); ! 920: ! 921: if (INT_14_BITS (operands[1])) ! 922: return (INTVAL (operands[1]) == 0 ? "copy 0,%0" : "ldi %1,%0"); ! 923: else ! 924: return "ldil L'%1,%0\n\tldo R'%1(%0),%0"; ! 925: } ! 926: ! 927: else if (GET_CODE (operands[1]) == CONST_INT) ! 928: { ! 929: if (INT_14_BITS (operands[1])) ! 930: return (INTVAL (operands[1]) == 0 ? "copy 0,%0" : "ldi %1,%0"); ! 931: else ! 932: return "ldil L'%1,%0\n\tldo R'%1(%0),%0"; ! 933: } ! 934: return "copy %1,%0"; ! 935: } ! 936: ! 937: ! 938: /* Compute position (in OP[1]) and width (in OP[2]) ! 939: useful for copying IMM to a register using the zdepi ! 940: instructions. Store the immediate value to insert in OP[0]. */ ! 941: void ! 942: compute_zdepi_operands (imm, op) ! 943: unsigned imm; ! 944: unsigned *op; ! 945: { ! 946: int lsb, len; ! 947: ! 948: /* Find the least significant set bit in IMM. */ ! 949: for (lsb = 0; lsb < 32; lsb++) ! 950: { ! 951: if ((imm & 1) != 0) ! 952: break; ! 953: imm >>= 1; ! 954: } ! 955: ! 956: /* Choose variants based on *sign* of the 5-bit field. */ ! 957: if ((imm & 0x10) == 0) ! 958: len = (lsb <= 28) ? 4 : 32 - lsb; ! 959: else ! 960: { ! 961: /* Find the width of the bitstring in IMM. */ ! 962: for (len = 5; len < 32; len++) ! 963: { ! 964: if ((imm & (1 << len)) == 0) ! 965: break; ! 966: } ! 967: ! 968: /* Sign extend IMM as a 5-bit value. */ ! 969: imm = (imm & 0xf) - 0x10; ! 970: } ! 971: ! 972: op[0] = imm; ! 973: op[1] = 31 - lsb; ! 974: op[2] = len; ! 975: } ! 976: ! 977: /* Output assembler code to perform a doubleword move insn ! 978: with operands OPERANDS. */ ! 979: ! 980: char * ! 981: output_move_double (operands) ! 982: rtx *operands; ! 983: { ! 984: enum { REGOP, OFFSOP, MEMOP, CNSTOP, RNDOP } optype0, optype1; ! 985: rtx latehalf[2]; ! 986: rtx addreg0 = 0, addreg1 = 0; ! 987: ! 988: /* First classify both operands. */ ! 989: ! 990: if (REG_P (operands[0])) ! 991: optype0 = REGOP; ! 992: else if (offsettable_memref_p (operands[0])) ! 993: optype0 = OFFSOP; ! 994: else if (GET_CODE (operands[0]) == MEM) ! 995: optype0 = MEMOP; ! 996: else ! 997: optype0 = RNDOP; ! 998: ! 999: if (REG_P (operands[1])) ! 1000: optype1 = REGOP; ! 1001: else if (CONSTANT_P (operands[1])) ! 1002: optype1 = CNSTOP; ! 1003: else if (offsettable_memref_p (operands[1])) ! 1004: optype1 = OFFSOP; ! 1005: else if (GET_CODE (operands[1]) == MEM) ! 1006: optype1 = MEMOP; ! 1007: else ! 1008: optype1 = RNDOP; ! 1009: ! 1010: /* Check for the cases that the operand constraints are not ! 1011: supposed to allow to happen. Abort if we get one, ! 1012: because generating code for these cases is painful. */ ! 1013: ! 1014: if (optype0 != REGOP && optype1 != REGOP) ! 1015: abort (); ! 1016: ! 1017: /* Handle auto decrementing and incrementing loads and stores ! 1018: specifically, since the structure of the function doesn't work ! 1019: for them without major modification. Do it better when we learn ! 1020: this port about the general inc/dec addressing of PA. ! 1021: (This was written by tege. Chide him if it doesn't work.) */ ! 1022: ! 1023: if (optype0 == MEMOP) ! 1024: { ! 1025: /* We have to output the address syntax ourselves, since print_operand ! 1026: doesn't deal with the addresses we want to use. Fix this later. */ ! 1027: ! 1028: rtx addr = XEXP (operands[0], 0); ! 1029: if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC) ! 1030: { ! 1031: rtx high_reg = gen_rtx (SUBREG, SImode, operands[1], 0); ! 1032: ! 1033: operands[0] = XEXP (addr, 0); ! 1034: if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG) ! 1035: abort (); ! 1036: ! 1037: if (!reg_overlap_mentioned_p (high_reg, addr)) ! 1038: { ! 1039: /* No overlap between high target register and address ! 1040: register. (We do this in a non-obvious way to ! 1041: save a register file writeback) */ ! 1042: if (GET_CODE (addr) == POST_INC) ! 1043: return "stws,ma %1,8(0,%0)\n\tstw %R1,-4(0,%0)"; ! 1044: return "stws,ma %1,-8(0,%0)\n\tstw %R1,12(0,%0)"; ! 1045: } ! 1046: else ! 1047: abort(); ! 1048: } ! 1049: else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC) ! 1050: { ! 1051: rtx high_reg = gen_rtx (SUBREG, SImode, operands[1], 0); ! 1052: ! 1053: operands[0] = XEXP (addr, 0); ! 1054: if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG) ! 1055: abort (); ! 1056: ! 1057: if (!reg_overlap_mentioned_p (high_reg, addr)) ! 1058: { ! 1059: /* No overlap between high target register and address ! 1060: register. (We do this in a non-obvious way to ! 1061: save a register file writeback) */ ! 1062: if (GET_CODE (addr) == PRE_INC) ! 1063: return "stws,mb %1,8(0,%0)\n\tstw %R1,4(0,%0)"; ! 1064: return "stws,mb %1,-8(0,%0)\n\tstw %R1,4(0,%0)"; ! 1065: } ! 1066: else ! 1067: abort(); ! 1068: } ! 1069: } ! 1070: if (optype1 == MEMOP) ! 1071: { ! 1072: /* We have to output the address syntax ourselves, since print_operand ! 1073: doesn't deal with the addresses we want to use. Fix this later. */ ! 1074: ! 1075: rtx addr = XEXP (operands[1], 0); ! 1076: if (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC) ! 1077: { ! 1078: rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], 0); ! 1079: ! 1080: operands[1] = XEXP (addr, 0); ! 1081: if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG) ! 1082: abort (); ! 1083: ! 1084: if (!reg_overlap_mentioned_p (high_reg, addr)) ! 1085: { ! 1086: /* No overlap between high target register and address ! 1087: register. (We do this in a non-obvious way to ! 1088: save a register file writeback) */ ! 1089: if (GET_CODE (addr) == POST_INC) ! 1090: return "ldws,ma 8(0,%1),%0\n\tldw -4(0,%1),%R0"; ! 1091: return "ldws,ma -8(0,%1),%0\n\tldw 12(0,%1),%R0"; ! 1092: } ! 1093: else ! 1094: { ! 1095: /* This is an undefined situation. We should load into the ! 1096: address register *and* update that register. Probably ! 1097: we don't need to handle this at all. */ ! 1098: if (GET_CODE (addr) == POST_INC) ! 1099: return "ldw 4(0,%1),%R0\n\tldws,ma 8(0,%1),%0"; ! 1100: return "ldw 4(0,%1),%R0\n\tldws,ma -8(0,%1),%0"; ! 1101: } ! 1102: } ! 1103: else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC) ! 1104: { ! 1105: rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], 0); ! 1106: ! 1107: operands[1] = XEXP (addr, 0); ! 1108: if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG) ! 1109: abort (); ! 1110: ! 1111: if (!reg_overlap_mentioned_p (high_reg, addr)) ! 1112: { ! 1113: /* No overlap between high target register and address ! 1114: register. (We do this in a non-obvious way to ! 1115: save a register file writeback) */ ! 1116: if (GET_CODE (addr) == PRE_INC) ! 1117: return "ldws,mb 8(0,%1),%0\n\tldw 4(0,%1),%R0"; ! 1118: return "ldws,mb -8(0,%1),%0\n\tldw 4(0,%1),%R0"; ! 1119: } ! 1120: else ! 1121: { ! 1122: /* This is an undefined situation. We should load into the ! 1123: address register *and* update that register. Probably ! 1124: we don't need to handle this at all. */ ! 1125: if (GET_CODE (addr) == PRE_INC) ! 1126: return "ldw 12(0,%1),%R0\n\tldws,mb 8(0,%1),%0"; ! 1127: return "ldw -4(0,%1),%R0\n\tldws,mb -8(0,%1),%0"; ! 1128: } ! 1129: } ! 1130: } ! 1131: ! 1132: /* If an operand is an unoffsettable memory ref, find a register ! 1133: we can increment temporarily to make it refer to the second word. */ ! 1134: ! 1135: if (optype0 == MEMOP) ! 1136: addreg0 = find_addr_reg (XEXP (operands[0], 0)); ! 1137: ! 1138: if (optype1 == MEMOP) ! 1139: addreg1 = find_addr_reg (XEXP (operands[1], 0)); ! 1140: ! 1141: /* Ok, we can do one word at a time. ! 1142: Normally we do the low-numbered word first. ! 1143: ! 1144: In either case, set up in LATEHALF the operands to use ! 1145: for the high-numbered word and in some cases alter the ! 1146: operands in OPERANDS to be suitable for the low-numbered word. */ ! 1147: ! 1148: if (optype0 == REGOP) ! 1149: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 1150: else if (optype0 == OFFSOP) ! 1151: latehalf[0] = adj_offsettable_operand (operands[0], 4); ! 1152: else ! 1153: latehalf[0] = operands[0]; ! 1154: ! 1155: if (optype1 == REGOP) ! 1156: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); ! 1157: else if (optype1 == OFFSOP) ! 1158: latehalf[1] = adj_offsettable_operand (operands[1], 4); ! 1159: else if (optype1 == CNSTOP) ! 1160: split_double (operands[1], &operands[1], &latehalf[1]); ! 1161: else ! 1162: latehalf[1] = operands[1]; ! 1163: ! 1164: /* If the first move would clobber the source of the second one, ! 1165: do them in the other order. ! 1166: ! 1167: RMS says "This happens only for registers; ! 1168: such overlap can't happen in memory unless the user explicitly ! 1169: sets it up, and that is an undefined circumstance." ! 1170: ! 1171: but it happens on the HP-PA when loading parameter registers, ! 1172: so I am going to define that circumstance, and make it work ! 1173: as expected. */ ! 1174: ! 1175: if (optype0 == REGOP && (optype1 == MEMOP || optype1 == OFFSOP) ! 1176: && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0))) ! 1177: { ! 1178: /* XXX THIS PROBABLY DOESN'T WORK. */ ! 1179: /* Do the late half first. */ ! 1180: if (addreg1) ! 1181: output_asm_insn ("ldo 4(%0),%0", &addreg1); ! 1182: output_asm_insn (singlemove_string (latehalf), latehalf); ! 1183: if (addreg1) ! 1184: output_asm_insn ("ldo -4(%0),%0", &addreg1); ! 1185: /* Then clobber. */ ! 1186: return singlemove_string (operands); ! 1187: } ! 1188: ! 1189: if (optype0 == REGOP && optype1 == REGOP ! 1190: && REGNO (operands[0]) == REGNO (operands[1]) + 1) ! 1191: { ! 1192: output_asm_insn (singlemove_string (latehalf), latehalf); ! 1193: return singlemove_string (operands); ! 1194: } ! 1195: ! 1196: /* Normal case: do the two words, low-numbered first. */ ! 1197: ! 1198: output_asm_insn (singlemove_string (operands), operands); ! 1199: ! 1200: /* Make any unoffsettable addresses point at high-numbered word. */ ! 1201: if (addreg0) ! 1202: output_asm_insn ("ldo 4(%0),%0", &addreg0); ! 1203: if (addreg1) ! 1204: output_asm_insn ("ldo 4(%0),%0", &addreg1); ! 1205: ! 1206: /* Do that word. */ ! 1207: output_asm_insn (singlemove_string (latehalf), latehalf); ! 1208: ! 1209: /* Undo the adds we just did. */ ! 1210: if (addreg0) ! 1211: output_asm_insn ("ldo -4(%0),%0", &addreg0); ! 1212: if (addreg1) ! 1213: output_asm_insn ("ldo -4(%0),%0", &addreg1); ! 1214: ! 1215: return ""; ! 1216: } ! 1217: ! 1218: char * ! 1219: output_fp_move_double (operands) ! 1220: rtx *operands; ! 1221: { ! 1222: if (FP_REG_P (operands[0])) ! 1223: { ! 1224: if (FP_REG_P (operands[1]) ! 1225: || operands[1] == CONST0_RTX (GET_MODE (operands[0]))) ! 1226: output_asm_insn ("fcpy,dbl %r1,%0", operands); ! 1227: else ! 1228: output_asm_insn ("fldds%F1 %1,%0", operands); ! 1229: } ! 1230: else if (FP_REG_P (operands[1])) ! 1231: { ! 1232: output_asm_insn ("fstds%F0 %1,%0", operands); ! 1233: } ! 1234: else if (operands[1] == CONST0_RTX (GET_MODE (operands[0]))) ! 1235: { ! 1236: if (GET_CODE (operands[0]) == REG) ! 1237: { ! 1238: rtx xoperands[2]; ! 1239: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); ! 1240: xoperands[0] = operands[0]; ! 1241: output_asm_insn ("copy %%r0,%0\n\tcopy %%r0,%1", xoperands); ! 1242: } ! 1243: /* This is a pain. You have to be prepared to deal with an ! 1244: arbritary address here including pre/post increment/decrement. ! 1245: ! 1246: so avoid this in the MD. */ ! 1247: else ! 1248: abort (); ! 1249: } ! 1250: else abort (); ! 1251: return ""; ! 1252: } ! 1253: ! 1254: /* Return a REG that occurs in ADDR with coefficient 1. ! 1255: ADDR can be effectively incremented by incrementing REG. */ ! 1256: ! 1257: static rtx ! 1258: find_addr_reg (addr) ! 1259: rtx addr; ! 1260: { ! 1261: while (GET_CODE (addr) == PLUS) ! 1262: { ! 1263: if (GET_CODE (XEXP (addr, 0)) == REG) ! 1264: addr = XEXP (addr, 0); ! 1265: else if (GET_CODE (XEXP (addr, 1)) == REG) ! 1266: addr = XEXP (addr, 1); ! 1267: else if (CONSTANT_P (XEXP (addr, 0))) ! 1268: addr = XEXP (addr, 1); ! 1269: else if (CONSTANT_P (XEXP (addr, 1))) ! 1270: addr = XEXP (addr, 0); ! 1271: else ! 1272: abort (); ! 1273: } ! 1274: if (GET_CODE (addr) == REG) ! 1275: return addr; ! 1276: abort (); ! 1277: } ! 1278: ! 1279: /* Emit code to perform a block move. ! 1280: ! 1281: Restriction: If the length argument is non-constant, alignment ! 1282: must be 4. ! 1283: ! 1284: OPERANDS[0] is the destination pointer as a REG, clobbered. ! 1285: OPERANDS[1] is the source pointer as a REG, clobbered. ! 1286: if SIZE_IS_CONSTANT ! 1287: OPERANDS[2] is a register for temporary storage. ! 1288: OPERANDS[4] is the size as a CONST_INT ! 1289: else ! 1290: OPERANDS[2] is a REG which will contain the size, clobbered. ! 1291: OPERANDS[3] is a register for temporary storage. ! 1292: OPERANDS[5] is the alignment safe to use, as a CONST_INT. */ ! 1293: ! 1294: char * ! 1295: output_block_move (operands, size_is_constant) ! 1296: rtx *operands; ! 1297: int size_is_constant; ! 1298: { ! 1299: int align = INTVAL (operands[5]); ! 1300: unsigned long n_bytes; ! 1301: ! 1302: /* We can't move more than four bytes at a time because the PA ! 1303: has no longer integer move insns. (Could use fp mem ops?) */ ! 1304: if (align > 4) ! 1305: align = 4; ! 1306: ! 1307: if (size_is_constant) ! 1308: { ! 1309: unsigned long n_items; ! 1310: unsigned long offset; ! 1311: rtx temp; ! 1312: ! 1313: n_bytes = INTVAL (operands[4]); ! 1314: if (n_bytes == 0) ! 1315: return ""; ! 1316: ! 1317: if (align >= 4) ! 1318: { ! 1319: /* Don't unroll too large blocks. */ ! 1320: if (n_bytes > 64) ! 1321: goto copy_with_loop; ! 1322: ! 1323: /* Read and store using two registers, and hide latency ! 1324: by deferring the stores until three instructions after ! 1325: the corresponding load. The last load insn will read ! 1326: the entire word were the last bytes are, possibly past ! 1327: the end of the source block, but since loads are aligned, ! 1328: this is harmless. */ ! 1329: ! 1330: output_asm_insn ("ldws,ma 4(0,%1),%2", operands); ! 1331: ! 1332: for (offset = 4; offset < n_bytes; offset += 4) ! 1333: { ! 1334: output_asm_insn ("ldws,ma 4(0,%1),%3", operands); ! 1335: output_asm_insn ("stws,ma %2,4(0,%0)", operands); ! 1336: ! 1337: temp = operands[2]; ! 1338: operands[2] = operands[3]; ! 1339: operands[3] = temp; ! 1340: } ! 1341: if (n_bytes % 4 == 0) ! 1342: /* Store the last word. */ ! 1343: output_asm_insn ("stw %2,0(0,%0)", operands); ! 1344: else ! 1345: { ! 1346: /* Store the last, partial word. */ ! 1347: operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes % 4); ! 1348: output_asm_insn ("stbys,e %2,%4(0,%0)", operands); ! 1349: } ! 1350: return ""; ! 1351: } ! 1352: ! 1353: if (align >= 2 && n_bytes >= 2) ! 1354: { ! 1355: output_asm_insn ("ldhs,ma 2(0,%1),%2", operands); ! 1356: ! 1357: for (offset = 2; offset + 2 <= n_bytes; offset += 2) ! 1358: { ! 1359: output_asm_insn ("ldhs,ma 2(0,%1),%3", operands); ! 1360: output_asm_insn ("sths,ma %2,2(0,%0)", operands); ! 1361: ! 1362: temp = operands[2]; ! 1363: operands[2] = operands[3]; ! 1364: operands[3] = temp; ! 1365: } ! 1366: if (n_bytes % 2 != 0) ! 1367: output_asm_insn ("ldb 0(0,%1),%3", operands); ! 1368: ! 1369: output_asm_insn ("sths,ma %2,2(0,%0)", operands); ! 1370: ! 1371: if (n_bytes % 2 != 0) ! 1372: output_asm_insn ("stb %3,0(0,%0)", operands); ! 1373: ! 1374: return ""; ! 1375: } ! 1376: ! 1377: output_asm_insn ("ldbs,ma 1(0,%1),%2", operands); ! 1378: ! 1379: for (offset = 1; offset + 1 <= n_bytes; offset += 1) ! 1380: { ! 1381: output_asm_insn ("ldbs,ma 1(0,%1),%3", operands); ! 1382: output_asm_insn ("stbs,ma %2,1(0,%0)", operands); ! 1383: ! 1384: temp = operands[2]; ! 1385: operands[2] = operands[3]; ! 1386: operands[3] = temp; ! 1387: } ! 1388: output_asm_insn ("stb %2,0(0,%0)", operands); ! 1389: ! 1390: return ""; ! 1391: } ! 1392: ! 1393: if (align != 4) ! 1394: abort(); ! 1395: ! 1396: copy_with_loop: ! 1397: ! 1398: if (size_is_constant) ! 1399: { ! 1400: /* Size is compile-time determined, and also not ! 1401: very small (such small cases are handled above). */ ! 1402: operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes - 4); ! 1403: output_asm_insn ("ldo %4(0),%2", operands); ! 1404: } ! 1405: else ! 1406: { ! 1407: /* Decrement counter by 4, and if it becomes negative, jump past the ! 1408: word copying loop. */ ! 1409: output_asm_insn ("addib,<,n -4,%2,.+16", operands); ! 1410: } ! 1411: ! 1412: /* Copying loop. Note that the first load is in the annulled delay slot ! 1413: of addib. Is it OK on PA to have a load in a delay slot, i.e. is a ! 1414: possible page fault stopped in time? */ ! 1415: output_asm_insn ("ldws,ma 4(0,%1),%3", operands); ! 1416: output_asm_insn ("addib,>= -4,%2,.-4", operands); ! 1417: output_asm_insn ("stws,ma %3,4(0,%0)", operands); ! 1418: ! 1419: /* The counter is negative, >= -4. The remaining number of bytes are ! 1420: determined by the two least significant bits. */ ! 1421: ! 1422: if (size_is_constant) ! 1423: { ! 1424: if (n_bytes % 4 != 0) ! 1425: { ! 1426: /* Read the entire word of the source block tail. */ ! 1427: output_asm_insn ("ldw 0(0,%1),%3", operands); ! 1428: operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes % 4); ! 1429: output_asm_insn ("stbys,e %3,%4(0,%0)", operands); ! 1430: } ! 1431: } ! 1432: else ! 1433: { ! 1434: /* Add 4 to counter. If it becomes zero, we're done. */ ! 1435: output_asm_insn ("addib,=,n 4,%2,.+16", operands); ! 1436: ! 1437: /* Read the entire word of the source block tail. (Also this ! 1438: load is in an annulled delay slot.) */ ! 1439: output_asm_insn ("ldw 0(0,%1),%3", operands); ! 1440: ! 1441: /* Make %0 point at the first byte after the destination block. */ ! 1442: output_asm_insn ("add %2,%0,%0", operands); ! 1443: /* Store the leftmost bytes, up to, but not including, the address ! 1444: in %0. */ ! 1445: output_asm_insn ("stbys,e %3,0(0,%0)", operands); ! 1446: } ! 1447: return ""; ! 1448: } ! 1449: ! 1450: /* Count the number of insns necessary to handle this block move. ! 1451: ! 1452: Basic structure is the same as emit_block_move, except that we ! 1453: count insns rather than emit them. */ ! 1454: ! 1455: int ! 1456: compute_movstrsi_length (insn) ! 1457: rtx insn; ! 1458: { ! 1459: rtx pat = PATTERN (insn); ! 1460: int size_is_constant; ! 1461: int align = INTVAL (XEXP (XVECEXP (pat, 0, 6), 0)); ! 1462: unsigned long n_bytes; ! 1463: int insn_count = 0; ! 1464: ! 1465: if (GET_CODE (XEXP (XVECEXP (pat, 0, 5), 0)) == CONST_INT) ! 1466: { ! 1467: size_is_constant = 1; ! 1468: n_bytes = INTVAL (XEXP (XVECEXP (pat, 0, 5), 0)); ! 1469: } ! 1470: else ! 1471: { ! 1472: size_is_constant = 0; ! 1473: n_bytes = 0; ! 1474: } ! 1475: ! 1476: /* We can't move more than four bytes at a time because the PA ! 1477: has no longer integer move insns. (Could use fp mem ops?) */ ! 1478: if (align > 4) ! 1479: align = 4; ! 1480: ! 1481: if (size_is_constant) ! 1482: { ! 1483: unsigned long n_items; ! 1484: unsigned long offset; ! 1485: rtx temp; ! 1486: ! 1487: if (n_bytes == 0) ! 1488: return 0; ! 1489: ! 1490: if (align >= 4) ! 1491: { ! 1492: /* Don't unroll too large blocks. */ ! 1493: if (n_bytes > 64) ! 1494: goto copy_with_loop; ! 1495: ! 1496: /* first load */ ! 1497: insn_count = 1; ! 1498: ! 1499: /* Count the unrolled insns. */ ! 1500: for (offset = 4; offset < n_bytes; offset += 4) ! 1501: insn_count += 2; ! 1502: ! 1503: /* Count last store or partial store. */ ! 1504: insn_count += 1; ! 1505: return insn_count; ! 1506: } ! 1507: ! 1508: if (align >= 2 && n_bytes >= 2) ! 1509: { ! 1510: /* initial load. */ ! 1511: insn_count = 1; ! 1512: ! 1513: /* Unrolled loop. */ ! 1514: for (offset = 2; offset + 2 <= n_bytes; offset += 2) ! 1515: insn_count += 2; ! 1516: ! 1517: /* ??? odd load/store */ ! 1518: if (n_bytes % 2 != 0) ! 1519: insn_count += 2; ! 1520: ! 1521: /* ??? final store from loop. */ ! 1522: insn_count += 1; ! 1523: ! 1524: return insn_count; ! 1525: } ! 1526: ! 1527: /* First load. */ ! 1528: insn_count = 1; ! 1529: ! 1530: /* The unrolled loop. */ ! 1531: for (offset = 1; offset + 1 <= n_bytes; offset += 1) ! 1532: insn_count += 2; ! 1533: ! 1534: /* Final store. */ ! 1535: insn_count += 1; ! 1536: ! 1537: return insn_count; ! 1538: } ! 1539: ! 1540: if (align != 4) ! 1541: abort(); ! 1542: ! 1543: copy_with_loop: ! 1544: ! 1545: /* setup for constant and non-constant case. */ ! 1546: insn_count = 1; ! 1547: ! 1548: /* The copying loop. */ ! 1549: insn_count += 3; ! 1550: ! 1551: /* The counter is negative, >= -4. The remaining number of bytes are ! 1552: determined by the two least significant bits. */ ! 1553: ! 1554: if (size_is_constant) ! 1555: { ! 1556: if (n_bytes % 4 != 0) ! 1557: insn_count += 2; ! 1558: } ! 1559: else ! 1560: insn_count += 4; ! 1561: return insn_count; ! 1562: } ! 1563: ! 1564: ! 1565: char * ! 1566: output_and (operands) ! 1567: rtx *operands; ! 1568: { ! 1569: if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0) ! 1570: { ! 1571: unsigned mask = INTVAL (operands[2]); ! 1572: int ls0, ls1, ms0, p, len; ! 1573: ! 1574: for (ls0 = 0; ls0 < 32; ls0++) ! 1575: if ((mask & (1 << ls0)) == 0) ! 1576: break; ! 1577: ! 1578: for (ls1 = ls0; ls1 < 32; ls1++) ! 1579: if ((mask & (1 << ls1)) != 0) ! 1580: break; ! 1581: ! 1582: for (ms0 = ls1; ms0 < 32; ms0++) ! 1583: if ((mask & (1 << ms0)) == 0) ! 1584: break; ! 1585: ! 1586: if (ms0 != 32) ! 1587: abort(); ! 1588: ! 1589: if (ls1 == 32) ! 1590: { ! 1591: len = ls0; ! 1592: ! 1593: if (len == 0) ! 1594: abort (); ! 1595: ! 1596: operands[2] = gen_rtx (CONST_INT, VOIDmode, len); ! 1597: return "extru %1,31,%2,%0"; ! 1598: } ! 1599: else ! 1600: { ! 1601: /* We could use this `depi' for the case above as well, but `depi' ! 1602: requires one more register file access than an `extru'. */ ! 1603: ! 1604: p = 31 - ls0; ! 1605: len = ls1 - ls0; ! 1606: ! 1607: operands[2] = gen_rtx (CONST_INT, VOIDmode, p); ! 1608: operands[3] = gen_rtx (CONST_INT, VOIDmode, len); ! 1609: return "depi 0,%2,%3,%0"; ! 1610: } ! 1611: } ! 1612: else ! 1613: return "and %1,%2,%0"; ! 1614: } ! 1615: ! 1616: char * ! 1617: output_ior (operands) ! 1618: rtx *operands; ! 1619: { ! 1620: unsigned mask = INTVAL (operands[2]); ! 1621: int bs0, bs1, bs2, p, len; ! 1622: ! 1623: if (INTVAL (operands[2]) == 0) ! 1624: return "copy %1,%0"; ! 1625: ! 1626: for (bs0 = 0; bs0 < 32; bs0++) ! 1627: if ((mask & (1 << bs0)) != 0) ! 1628: break; ! 1629: ! 1630: for (bs1 = bs0; bs1 < 32; bs1++) ! 1631: if ((mask & (1 << bs1)) == 0) ! 1632: break; ! 1633: ! 1634: if (bs1 != 32 && ((unsigned) 1 << bs1) <= mask) ! 1635: abort(); ! 1636: ! 1637: p = 31 - bs0; ! 1638: len = bs1 - bs0; ! 1639: ! 1640: operands[2] = gen_rtx (CONST_INT, VOIDmode, p); ! 1641: operands[3] = gen_rtx (CONST_INT, VOIDmode, len); ! 1642: return "depi -1,%2,%3,%0"; ! 1643: } ! 1644: ! 1645: /* Output an ascii string. */ ! 1646: output_ascii (file, p, size) ! 1647: FILE *file; ! 1648: unsigned char *p; ! 1649: int size; ! 1650: { ! 1651: int i; ! 1652: int chars_output; ! 1653: unsigned char partial_output[16]; /* Max space 4 chars can occupy. */ ! 1654: ! 1655: /* The HP assembler can only take strings of 256 characters at one ! 1656: time. This is a limitation on input line length, *not* the ! 1657: length of the string. Sigh. Even worse, it seems that the ! 1658: restriction is in number of input characters (see \xnn & ! 1659: \whatever). So we have to do this very carefully. */ ! 1660: ! 1661: fprintf (file, "\t.STRING \""); ! 1662: ! 1663: chars_output = 0; ! 1664: for (i = 0; i < size; i += 4) ! 1665: { ! 1666: int co = 0; ! 1667: int io = 0; ! 1668: for (io = 0, co = 0; io < MIN (4, size - i); io++) ! 1669: { ! 1670: register unsigned int c = p[i + io]; ! 1671: ! 1672: if (c == '\"' || c == '\\') ! 1673: partial_output[co++] = '\\'; ! 1674: if (c >= ' ' && c < 0177) ! 1675: partial_output[co++] = c; ! 1676: else ! 1677: { ! 1678: unsigned int hexd; ! 1679: partial_output[co++] = '\\'; ! 1680: partial_output[co++] = 'x'; ! 1681: hexd = c / 16 - 0 + '0'; ! 1682: if (hexd > '9') ! 1683: hexd -= '9' - 'a' + 1; ! 1684: partial_output[co++] = hexd; ! 1685: hexd = c % 16 - 0 + '0'; ! 1686: if (hexd > '9') ! 1687: hexd -= '9' - 'a' + 1; ! 1688: partial_output[co++] = hexd; ! 1689: } ! 1690: } ! 1691: if (chars_output + co > 243) ! 1692: { ! 1693: fprintf (file, "\"\n\t.STRING \""); ! 1694: chars_output = 0; ! 1695: } ! 1696: fwrite (partial_output, 1, co, file); ! 1697: chars_output += co; ! 1698: co = 0; ! 1699: } ! 1700: fprintf (file, "\"\n"); ! 1701: } ! 1702: ! 1703: /* You may have trouble believing this, but this is the HP-PA stack ! 1704: layout. Wow. ! 1705: ! 1706: Offset Contents ! 1707: ! 1708: Variable arguments (optional; any number may be allocated) ! 1709: ! 1710: SP-(4*(N+9)) arg word N ! 1711: : : ! 1712: SP-56 arg word 5 ! 1713: SP-52 arg word 4 ! 1714: ! 1715: Fixed arguments (must be allocated; may remain unused) ! 1716: ! 1717: SP-48 arg word 3 ! 1718: SP-44 arg word 2 ! 1719: SP-40 arg word 1 ! 1720: SP-36 arg word 0 ! 1721: ! 1722: Frame Marker ! 1723: ! 1724: SP-32 External Data Pointer (DP) ! 1725: SP-28 External sr4 ! 1726: SP-24 External/stub RP (RP') ! 1727: SP-20 Current RP ! 1728: SP-16 Static Link ! 1729: SP-12 Clean up ! 1730: SP-8 Calling Stub RP (RP'') ! 1731: SP-4 Previous SP ! 1732: ! 1733: Top of Frame ! 1734: ! 1735: SP-0 Stack Pointer (points to next available address) ! 1736: ! 1737: */ ! 1738: ! 1739: /* This function saves registers as follows. Registers marked with ' are ! 1740: this function's registers (as opposed to the previous function's). ! 1741: If a frame_pointer isn't needed, r4 is saved as a general register; ! 1742: the space for the frame pointer is still allocated, though, to keep ! 1743: things simple. ! 1744: ! 1745: ! 1746: Top of Frame ! 1747: ! 1748: SP (FP') Previous FP ! 1749: SP + 4 Alignment filler (sigh) ! 1750: SP + 8 Space for locals reserved here. ! 1751: . ! 1752: . ! 1753: . ! 1754: SP + n All call saved register used. ! 1755: . ! 1756: . ! 1757: . ! 1758: SP + o All call saved fp registers used. ! 1759: . ! 1760: . ! 1761: . ! 1762: SP + p (SP') points to next available address. ! 1763: ! 1764: */ ! 1765: ! 1766: /* Emit RTL to store REG at the memory location specified by BASE+DISP. ! 1767: Handle case where DISP > 8k by using the add_high_const pattern. ! 1768: ! 1769: Note in DISP > 8k case, we will leave the high part of the address ! 1770: in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/ ! 1771: static void ! 1772: store_reg (reg, disp, base) ! 1773: int reg, disp, base; ! 1774: { ! 1775: if (VAL_14_BITS_P (disp)) ! 1776: { ! 1777: emit_move_insn (gen_rtx (MEM, SImode, ! 1778: gen_rtx (PLUS, SImode, ! 1779: gen_rtx (REG, SImode, base), ! 1780: GEN_INT (disp))), ! 1781: gen_rtx (REG, SImode, reg)); ! 1782: } ! 1783: else ! 1784: { ! 1785: emit_insn (gen_add_high_const (gen_rtx (REG, SImode, 1), ! 1786: gen_rtx (REG, SImode, base), ! 1787: GEN_INT (disp))); ! 1788: emit_move_insn (gen_rtx (MEM, SImode, ! 1789: gen_rtx (LO_SUM, SImode, ! 1790: gen_rtx (REG, SImode, 1), ! 1791: GEN_INT (disp))), ! 1792: gen_rtx (REG, SImode, reg)); ! 1793: } ! 1794: } ! 1795: ! 1796: /* Emit RTL to load REG from the memory location specified by BASE+DISP. ! 1797: Handle case where DISP > 8k by using the add_high_const pattern. ! 1798: ! 1799: Note in DISP > 8k case, we will leave the high part of the address ! 1800: in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/ ! 1801: static void ! 1802: load_reg (reg, disp, base) ! 1803: int reg, disp, base; ! 1804: { ! 1805: if (VAL_14_BITS_P (disp)) ! 1806: { ! 1807: emit_move_insn (gen_rtx (REG, SImode, reg), ! 1808: gen_rtx (MEM, SImode, ! 1809: gen_rtx (PLUS, SImode, ! 1810: gen_rtx (REG, SImode, base), ! 1811: GEN_INT (disp)))); ! 1812: ! 1813: } ! 1814: else ! 1815: { ! 1816: emit_insn (gen_add_high_const (gen_rtx (REG, SImode, 1), ! 1817: gen_rtx (REG, SImode, base), ! 1818: GEN_INT (disp))); ! 1819: emit_move_insn (gen_rtx (REG, SImode, reg), ! 1820: gen_rtx (MEM, SImode, ! 1821: gen_rtx (LO_SUM, SImode, ! 1822: gen_rtx (REG, SImode, 1), ! 1823: GEN_INT (disp)))); ! 1824: } ! 1825: } ! 1826: ! 1827: /* Emit RTL to set REG to the value specified by BASE+DISP. ! 1828: Handle case where DISP > 8k by using the add_high_const pattern. ! 1829: ! 1830: Note in DISP > 8k case, we will leave the high part of the address ! 1831: in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/ ! 1832: static void ! 1833: set_reg_plus_d(reg, base, disp) ! 1834: int reg, base, disp; ! 1835: { ! 1836: if (VAL_14_BITS_P (disp)) ! 1837: { ! 1838: emit_move_insn (gen_rtx (REG, SImode, reg), ! 1839: gen_rtx (PLUS, SImode, ! 1840: gen_rtx (REG, SImode, base), ! 1841: GEN_INT (disp))); ! 1842: ! 1843: } ! 1844: else ! 1845: { ! 1846: emit_insn (gen_add_high_const (gen_rtx (REG, SImode, 1), ! 1847: gen_rtx (REG, SImode, base), ! 1848: GEN_INT (disp))); ! 1849: emit_move_insn (gen_rtx (REG, SImode, reg), ! 1850: gen_rtx (LO_SUM, SImode, ! 1851: gen_rtx (REG, SImode, 1), ! 1852: GEN_INT (disp))); ! 1853: } ! 1854: } ! 1855: ! 1856: /* Global variables set by FUNCTION_PROLOGUE. */ ! 1857: /* Size of frame. Need to know this to emit return insns from ! 1858: leaf procedures. */ ! 1859: static int actual_fsize; ! 1860: static int local_fsize, save_fregs; ! 1861: ! 1862: int ! 1863: compute_frame_size (size, fregs_live) ! 1864: int size; ! 1865: int *fregs_live; ! 1866: { ! 1867: extern int current_function_outgoing_args_size; ! 1868: int i, fsize; ! 1869: ! 1870: /* 8 is space for frame pointer + filler. If any frame is allocated ! 1871: we need to add this in because of STARTING_FRAME_OFFSET. */ ! 1872: fsize = size + (size || frame_pointer_needed ? 8 : 0); ! 1873: ! 1874: /* fp is stored in a special place. */ ! 1875: if (frame_pointer_needed) ! 1876: { ! 1877: for (i = 18; i >= 5; i--) ! 1878: if (regs_ever_live[i]) ! 1879: fsize += 4; ! 1880: ! 1881: if (regs_ever_live[3]) ! 1882: fsize += 4; ! 1883: } ! 1884: else ! 1885: { ! 1886: for (i = 18; i >= 3; i--) ! 1887: if (regs_ever_live[i]) ! 1888: fsize += 4; ! 1889: } ! 1890: fsize = (fsize + 7) & ~7; ! 1891: ! 1892: if (!TARGET_SNAKE) ! 1893: { ! 1894: for (i = 43; i >= 40; i--) ! 1895: if (regs_ever_live[i]) ! 1896: { ! 1897: fsize += 8; ! 1898: if (fregs_live) ! 1899: *fregs_live = 1; ! 1900: } ! 1901: } ! 1902: else ! 1903: { ! 1904: for (i = 78; i >= 60; i -= 2) ! 1905: if (regs_ever_live[i] || regs_ever_live[i + 1]) ! 1906: { ! 1907: fsize += 8; ! 1908: if (fregs_live) ! 1909: *fregs_live = 1; ! 1910: } ! 1911: } ! 1912: fsize += current_function_outgoing_args_size; ! 1913: if (! leaf_function_p () || fsize) ! 1914: fsize += 32; ! 1915: return TARGET_SNAKE ? (fsize + 63 & ~63) : fsize; ! 1916: } ! 1917: ! 1918: rtx hp_profile_label_rtx; ! 1919: static char hp_profile_label_name[8]; ! 1920: void ! 1921: output_function_prologue (file, size) ! 1922: FILE *file; ! 1923: int size; ! 1924: { ! 1925: ! 1926: /* hppa_expand_prologue does the dirty work now. We just need ! 1927: to output the assembler directives which denote the start ! 1928: of a function. */ ! 1929: fprintf (file, "\t.PROC\n\t.CALLINFO FRAME=%d", actual_fsize); ! 1930: if (regs_ever_live[2] || profile_flag) ! 1931: fprintf (file, ",CALLS,SAVE_RP\n"); ! 1932: else ! 1933: fprintf (file, ",NO_CALLS\n"); ! 1934: fprintf (file, "\t.ENTRY\n"); ! 1935: ! 1936: /* Horrid hack. emit_function_prologue will modify this RTL in ! 1937: place to get the expected results. */ ! 1938: if (profile_flag) ! 1939: sprintf(hp_profile_label_name, "LP$%04d", hp_profile_labelno); ! 1940: } ! 1941: ! 1942: hppa_expand_prologue() ! 1943: { ! 1944: ! 1945: extern char call_used_regs[]; ! 1946: int size = get_frame_size (); ! 1947: int merge_sp_adjust_with_store = 0; ! 1948: int i, offset; ! 1949: rtx tmpreg, size_rtx; ! 1950: ! 1951: ! 1952: save_fregs = 0; ! 1953: local_fsize = size + (size || frame_pointer_needed ? 8 : 0); ! 1954: actual_fsize = compute_frame_size (size, &save_fregs); ! 1955: ! 1956: /* Compute a few things we will use often. */ ! 1957: tmpreg = gen_rtx (REG, SImode, 1); ! 1958: size_rtx = GEN_INT (actual_fsize); ! 1959: ! 1960: /* Save RP first. The calling conventions manual states RP will ! 1961: always be stored into the caller's frame at sp-20. */ ! 1962: if (regs_ever_live[2] || profile_flag) ! 1963: store_reg (2, -20, STACK_POINTER_REGNUM); ! 1964: ! 1965: /* Allocate the local frame and set up the frame pointer if needed. */ ! 1966: if (actual_fsize) ! 1967: if (frame_pointer_needed) ! 1968: { ! 1969: /* Copy the old frame pointer temporarily into %r1. Set up the ! 1970: new stack pointer, then store away the saved old frame pointer ! 1971: into the stack at sp+actual_fsize and at the same time update ! 1972: the stack pointer by actual_fsize bytes. Two versions, first ! 1973: handles small (<8k) frames. The second handles large (>8k) ! 1974: frames. */ ! 1975: emit_move_insn (tmpreg, frame_pointer_rtx); ! 1976: emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); ! 1977: if (VAL_14_BITS_P (actual_fsize)) ! 1978: emit_insn (gen_post_stwm (stack_pointer_rtx, ! 1979: stack_pointer_rtx, ! 1980: size_rtx, tmpreg)); ! 1981: else ! 1982: { ! 1983: store_reg (1, 0, FRAME_POINTER_REGNUM); ! 1984: set_reg_plus_d (STACK_POINTER_REGNUM, ! 1985: STACK_POINTER_REGNUM, ! 1986: actual_fsize); ! 1987: } ! 1988: } ! 1989: /* no frame pointer needed. */ ! 1990: else ! 1991: { ! 1992: /* In some cases we can perform the first callee register save ! 1993: and allocating the stack frame at the same time. If so, just ! 1994: make a note of it and defer allocating the frame until saving ! 1995: the callee registers. */ ! 1996: if (VAL_14_BITS_P (-actual_fsize) ! 1997: && local_fsize == 0 ! 1998: && ! profile_flag ! 1999: && ! flag_pic) ! 2000: merge_sp_adjust_with_store = 1; ! 2001: /* Can not optimize. Adjust the stack frame by actual_fsize bytes. */ ! 2002: else if (actual_fsize != 0) ! 2003: set_reg_plus_d (STACK_POINTER_REGNUM, ! 2004: STACK_POINTER_REGNUM, ! 2005: actual_fsize); ! 2006: } ! 2007: /* The hppa calling conventions say that that %r19, the pic offset ! 2008: register, is saved at sp - 32 (in this function's frame) when ! 2009: generating PIC code. */ ! 2010: if (flag_pic) ! 2011: store_reg (19, -32, STACK_POINTER_REGNUM); ! 2012: ! 2013: /* Profiling code. ! 2014: ! 2015: Instead of taking one argument, the counter label, as most normal ! 2016: mcounts do, _mcount appears to behave differently on the HPPA. It ! 2017: takes the return address of the caller, the address of this routine, ! 2018: and the address of the label. Also, it isn't magic, so ! 2019: argument registre hsave to be preserved. */ ! 2020: if (profile_flag) ! 2021: { ! 2022: int pc_offset, i, arg_offset, basereg, offsetadj; ! 2023: ! 2024: pc_offset = 4 + (frame_pointer_needed ! 2025: ? (VAL_14_BITS_P (actual_fsize) ? 12 : 20) ! 2026: : (VAL_14_BITS_P (actual_fsize) ? 4 : 8)); ! 2027: ! 2028: /* When the function has a frame pointer, use it as the base ! 2029: register for saving/restore registers. Else use the stack ! 2030: pointer. Adjust the offset according to the frame size if ! 2031: this function does not have a frame pointer. */ ! 2032: ! 2033: basereg = frame_pointer_needed ? FRAME_POINTER_REGNUM ! 2034: : STACK_POINTER_REGNUM; ! 2035: offsetadj = frame_pointer_needed ? 0 : actual_fsize; ! 2036: ! 2037: /* Horrid hack. emit_function_prologue will modify this RTL in ! 2038: place to get the expected results. sprintf here is just to ! 2039: put something in the name. */ ! 2040: sprintf(hp_profile_label_name, "LP$%04d", -1); ! 2041: hp_profile_label_rtx = gen_rtx (SYMBOL_REF, SImode, ! 2042: hp_profile_label_name); ! 2043: if (current_function_returns_struct) ! 2044: store_reg (STRUCT_VALUE_REGNUM, - 12 - offsetadj, basereg); ! 2045: ! 2046: for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4) ! 2047: if (regs_ever_live [i]) ! 2048: { ! 2049: store_reg (i, arg_offset, basereg); ! 2050: /* Deal with arg_offset not fitting in 14 bits. */ ! 2051: pc_offset += VAL_14_BITS_P (arg_offset) ? 4 : 8; ! 2052: } ! 2053: ! 2054: emit_move_insn (gen_rtx (REG, SImode, 26), gen_rtx (REG, SImode, 2)); ! 2055: emit_move_insn (tmpreg, gen_rtx (HIGH, SImode, hp_profile_label_rtx)); ! 2056: emit_move_insn (gen_rtx (REG, SImode, 24), ! 2057: gen_rtx (LO_SUM, SImode, tmpreg, hp_profile_label_rtx)); ! 2058: /* %r25 is set from within the output pattern. */ ! 2059: emit_insn (gen_call_profiler (GEN_INT (- pc_offset - 20))); ! 2060: ! 2061: /* Restore argument registers. */ ! 2062: for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4) ! 2063: if (regs_ever_live [i]) ! 2064: load_reg (i, arg_offset, basereg); ! 2065: ! 2066: if (current_function_returns_struct) ! 2067: load_reg (STRUCT_VALUE_REGNUM, -12 - offsetadj, basereg); ! 2068: ! 2069: } ! 2070: ! 2071: /* Normal register save. ! 2072: ! 2073: Do not save the frame pointer in the frame_pointer_needed case. It ! 2074: was done earlier. */ ! 2075: if (frame_pointer_needed) ! 2076: { ! 2077: for (i = 18, offset = local_fsize; i >= 3; i--) ! 2078: if (regs_ever_live[i] && ! call_used_regs[i] ! 2079: && i != FRAME_POINTER_REGNUM) ! 2080: { ! 2081: store_reg (i, offset, FRAME_POINTER_REGNUM); ! 2082: offset += 4; ! 2083: } ! 2084: } ! 2085: /* No frame pointer needed. */ ! 2086: else ! 2087: { ! 2088: for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--) ! 2089: if (regs_ever_live[i] && ! call_used_regs[i]) ! 2090: { ! 2091: /* If merge_sp_adjust_with_store is nonzero, then we can ! 2092: optimize the first GR save. */ ! 2093: if (merge_sp_adjust_with_store) ! 2094: { ! 2095: merge_sp_adjust_with_store = 0; ! 2096: emit_insn (gen_post_stwm (stack_pointer_rtx, ! 2097: stack_pointer_rtx, ! 2098: GEN_INT (-offset), ! 2099: gen_rtx (REG, SImode, i))); ! 2100: } ! 2101: else ! 2102: store_reg (i, offset, STACK_POINTER_REGNUM); ! 2103: offset += 4; ! 2104: } ! 2105: ! 2106: /* If we wanted to merge the SP adjustment with a GR save, but we never ! 2107: did any GR saves, then just emit the adjustment here. */ ! 2108: if (merge_sp_adjust_with_store) ! 2109: set_reg_plus_d (STACK_POINTER_REGNUM, ! 2110: STACK_POINTER_REGNUM, ! 2111: actual_fsize); ! 2112: } ! 2113: ! 2114: /* Align pointer properly (doubleword boundary). */ ! 2115: offset = (offset + 7) & ~7; ! 2116: ! 2117: /* Floating point register store. */ ! 2118: if (save_fregs) ! 2119: { ! 2120: ! 2121: /* First get the frame or stack pointer to the start of the FP register ! 2122: save area. */ ! 2123: if (frame_pointer_needed) ! 2124: set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset); ! 2125: else ! 2126: set_reg_plus_d (1, STACK_POINTER_REGNUM, offset); ! 2127: ! 2128: /* Now actually save the FP registers. */ ! 2129: if (! TARGET_SNAKE) ! 2130: { ! 2131: for (i = 43; i >= 40; i--) ! 2132: { ! 2133: if (regs_ever_live[i]) ! 2134: emit_move_insn (gen_rtx (MEM, DFmode, ! 2135: gen_rtx (POST_INC, DFmode, tmpreg)), ! 2136: gen_rtx (REG, DFmode, i)); ! 2137: } ! 2138: } ! 2139: else ! 2140: { ! 2141: for (i = 78; i >= 60; i -= 2) ! 2142: if (regs_ever_live[i] || regs_ever_live[i + 1]) ! 2143: { ! 2144: emit_move_insn (gen_rtx (MEM, DFmode, ! 2145: gen_rtx (POST_INC, DFmode, tmpreg)), ! 2146: gen_rtx (REG, DFmode, i)); ! 2147: } ! 2148: } ! 2149: } ! 2150: } ! 2151: ! 2152: ! 2153: void ! 2154: output_function_epilogue (file, size) ! 2155: FILE *file; ! 2156: int size; ! 2157: { ! 2158: ! 2159: rtx insn = get_last_insn (); ! 2160: ! 2161: /* hppa_expand_epilogue does the dirty work now. We just need ! 2162: to output the assembler directives which denote the end ! 2163: of a function. ! 2164: ! 2165: To make debuggers happy, emit a nop if the epilogue was completely ! 2166: eliminated due to a volatile call as the last insn in the ! 2167: current function. That way the return address (in %r2) will ! 2168: always point to a valid instruction in the current function. */ ! 2169: ! 2170: /* Get the last real insn. */ ! 2171: if (GET_CODE (insn) == NOTE) ! 2172: insn = prev_real_insn (insn); ! 2173: ! 2174: /* If it is a sequence, then look inside. */ ! 2175: if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) ! 2176: insn = XVECEXP (PATTERN (insn), 0, 0); ! 2177: ! 2178: /* If insn is a CALL_INSN, then it must be a call to a volatile ! 2179: function (otherwise there would be epilogue insns). */ ! 2180: if (insn && GET_CODE (insn) == CALL_INSN) ! 2181: fprintf (file, "\tnop\n"); ! 2182: ! 2183: fprintf (file, "\t.EXIT\n\t.PROCEND\n"); ! 2184: } ! 2185: ! 2186: void ! 2187: hppa_expand_epilogue () ! 2188: { ! 2189: rtx tmpreg; ! 2190: int offset,i; ! 2191: int merge_sp_adjust_with_load = 0; ! 2192: ! 2193: /* We will use this often. */ ! 2194: tmpreg = gen_rtx (REG, SImode, 1); ! 2195: ! 2196: /* Try to restore RP early to avoid load/use interlocks when ! 2197: RP gets used in the return (bv) instruction. This appears to still ! 2198: be necessary even when we schedule the prologue and epilogue. */ ! 2199: if (frame_pointer_needed ! 2200: && (regs_ever_live [2] || profile_flag)) ! 2201: load_reg (2, -20, FRAME_POINTER_REGNUM); ! 2202: ! 2203: /* No frame pointer, and stack is smaller than 8k. */ ! 2204: else if (! frame_pointer_needed ! 2205: && VAL_14_BITS_P (actual_fsize + 20) ! 2206: && (regs_ever_live[2] || profile_flag)) ! 2207: load_reg (2, - (actual_fsize + 20), STACK_POINTER_REGNUM); ! 2208: ! 2209: /* General register restores. */ ! 2210: if (frame_pointer_needed) ! 2211: { ! 2212: for (i = 18, offset = local_fsize; i >= 3; i--) ! 2213: if (regs_ever_live[i] && ! call_used_regs[i] ! 2214: && i != FRAME_POINTER_REGNUM) ! 2215: { ! 2216: load_reg (i, offset, FRAME_POINTER_REGNUM); ! 2217: offset += 4; ! 2218: } ! 2219: } ! 2220: else ! 2221: { ! 2222: for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--) ! 2223: if (regs_ever_live[i] && ! call_used_regs[i]) ! 2224: { ! 2225: /* Only for the first load. ! 2226: merge_sp_adjust_with_load holds the register load ! 2227: with which we will merge the sp adjustment. */ ! 2228: if (VAL_14_BITS_P (actual_fsize + 20) ! 2229: && local_fsize == 0 ! 2230: && ! merge_sp_adjust_with_load) ! 2231: merge_sp_adjust_with_load = i; ! 2232: else ! 2233: load_reg (i, offset, STACK_POINTER_REGNUM); ! 2234: offset += 4; ! 2235: } ! 2236: } ! 2237: ! 2238: /* Align pointer properly (doubleword boundary). */ ! 2239: offset = (offset + 7) & ~7; ! 2240: ! 2241: /* FP register restores. */ ! 2242: if (save_fregs) ! 2243: { ! 2244: /* Adjust the register to index off of. */ ! 2245: if (frame_pointer_needed) ! 2246: set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset); ! 2247: else ! 2248: set_reg_plus_d (1, STACK_POINTER_REGNUM, offset); ! 2249: ! 2250: /* Actually do the restores now. */ ! 2251: if (! TARGET_SNAKE) ! 2252: { ! 2253: for (i = 43; i >= 40; i--) ! 2254: if (regs_ever_live[i]) ! 2255: emit_move_insn (gen_rtx (REG, DFmode, i), ! 2256: gen_rtx (MEM, DFmode, ! 2257: gen_rtx (POST_INC, DFmode, tmpreg))); ! 2258: ! 2259: } ! 2260: else ! 2261: { ! 2262: for (i = 78; i >= 60; i -= 2) ! 2263: if (regs_ever_live[i] || regs_ever_live[i + 1]) ! 2264: emit_move_insn (gen_rtx (REG, DFmode, i), ! 2265: gen_rtx (MEM, DFmode, ! 2266: gen_rtx (POST_INC, DFmode, tmpreg))); ! 2267: } ! 2268: } ! 2269: ! 2270: /* No frame pointer, but we have a stack greater than 8k. We restore ! 2271: %r2 very late in this case. (All other cases are restored as early ! 2272: as possible.) */ ! 2273: if (! frame_pointer_needed ! 2274: && ! VAL_14_BITS_P (actual_fsize + 20) ! 2275: && (regs_ever_live[2] || profile_flag)) ! 2276: { ! 2277: set_reg_plus_d (STACK_POINTER_REGNUM, ! 2278: STACK_POINTER_REGNUM, ! 2279: - actual_fsize); ! 2280: /* Uses value left over in %r1 by set_reg_plus_d. */ ! 2281: load_reg (2, - (actual_fsize + 20 + ((- actual_fsize) & ~0x7ff)), 1); ! 2282: } ! 2283: ! 2284: /* Reset stack pointer (and possibly frame pointer). The stack */ ! 2285: /* pointer is initially set to fp + 64 to avoid a race condition. ! 2286: ??? What race condition?!? */ ! 2287: else if (frame_pointer_needed) ! 2288: { ! 2289: /* Emit a blockage insn here to keep these insns from being moved ! 2290: to the beginning of the prologue or into the main instruction ! 2291: stream, doing so avoids some very obscure problems. */ ! 2292: emit_insn (gen_blockage ()); ! 2293: set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64); ! 2294: emit_insn (gen_pre_ldwm (stack_pointer_rtx, stack_pointer_rtx, ! 2295: GEN_INT (-64), frame_pointer_rtx)); ! 2296: } ! 2297: /* If we were deferring a callee register restore, do it now. */ ! 2298: else if (! frame_pointer_needed && merge_sp_adjust_with_load) ! 2299: emit_insn (gen_pre_ldwm (stack_pointer_rtx, ! 2300: stack_pointer_rtx, ! 2301: GEN_INT (- actual_fsize), ! 2302: gen_rtx (REG, SImode, ! 2303: merge_sp_adjust_with_load))); ! 2304: else if (actual_fsize != 0) ! 2305: set_reg_plus_d (STACK_POINTER_REGNUM, ! 2306: STACK_POINTER_REGNUM, ! 2307: - actual_fsize); ! 2308: } ! 2309: ! 2310: /* This is only valid once reload has completed because it depends on ! 2311: knowing exactly how much (if any) frame there is and... ! 2312: ! 2313: It's only valid if there is no frame marker to de-allocate and... ! 2314: ! 2315: It's only valid if %r2 hasn't been saved into the caller's frame ! 2316: (we're not profiling and %r2 isn't live anywhere). */ ! 2317: int ! 2318: hppa_can_use_return_insn_p () ! 2319: { ! 2320: return (reload_completed ! 2321: && (compute_frame_size (get_frame_size (), 0) ? 0 : 1) ! 2322: && ! profile_flag ! 2323: && ! regs_ever_live[2] ! 2324: && ! frame_pointer_needed); ! 2325: } ! 2326: ! 2327: void ! 2328: emit_bcond_fp (code, operand0) ! 2329: enum rtx_code code; ! 2330: rtx operand0; ! 2331: { ! 2332: emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, ! 2333: gen_rtx (IF_THEN_ELSE, VOIDmode, ! 2334: gen_rtx (code, VOIDmode, ! 2335: gen_rtx (REG, CCFPmode, 0), ! 2336: const0_rtx), ! 2337: gen_rtx (LABEL_REF, VOIDmode, operand0), ! 2338: pc_rtx))); ! 2339: ! 2340: } ! 2341: ! 2342: rtx ! 2343: gen_cmp_fp (code, operand0, operand1) ! 2344: enum rtx_code code; ! 2345: rtx operand0, operand1; ! 2346: { ! 2347: return gen_rtx (SET, VOIDmode, gen_rtx (REG, CCFPmode, 0), ! 2348: gen_rtx (code, CCFPmode, operand0, operand1)); ! 2349: } ! 2350: ! 2351: /* Adjust the cost of a scheduling dependency. Return the new cost of ! 2352: a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ ! 2353: ! 2354: int ! 2355: pa_adjust_cost (insn, link, dep_insn, cost) ! 2356: rtx insn; ! 2357: rtx link; ! 2358: rtx dep_insn; ! 2359: int cost; ! 2360: { ! 2361: if (! recog_memoized (insn)) ! 2362: return 0; ! 2363: ! 2364: if (REG_NOTE_KIND (link) == 0) ! 2365: { ! 2366: /* Data dependency; DEP_INSN writes a register that INSN reads some ! 2367: cycles later. */ ! 2368: ! 2369: if (get_attr_type (insn) == TYPE_FPSTORE) ! 2370: { ! 2371: rtx pat = PATTERN (insn); ! 2372: rtx dep_pat = PATTERN (dep_insn); ! 2373: if (GET_CODE (pat) == PARALLEL) ! 2374: { ! 2375: /* This happens for the fstXs,mb patterns. */ ! 2376: pat = XVECEXP (pat, 0, 0); ! 2377: } ! 2378: if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET) ! 2379: /* If this happens, we have to extend this to schedule ! 2380: optimally. Return 0 for now. */ ! 2381: return 0; ! 2382: ! 2383: if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat))) ! 2384: { ! 2385: if (! recog_memoized (dep_insn)) ! 2386: return 0; ! 2387: /* DEP_INSN is writing its result to the register ! 2388: being stored in the fpstore INSN. */ ! 2389: switch (get_attr_type (dep_insn)) ! 2390: { ! 2391: case TYPE_FPLOAD: ! 2392: /* This cost 3 cycles, not 2 as the md says. */ ! 2393: return cost + 1; ! 2394: ! 2395: case TYPE_FPALU: ! 2396: case TYPE_FPMUL: ! 2397: case TYPE_FPDIVSGL: ! 2398: case TYPE_FPDIVDBL: ! 2399: case TYPE_FPSQRTSGL: ! 2400: case TYPE_FPSQRTDBL: ! 2401: /* In these important cases, we save one cycle compared to ! 2402: when flop instruction feed each other. */ ! 2403: return cost - 1; ! 2404: ! 2405: default: ! 2406: return cost; ! 2407: } ! 2408: } ! 2409: } ! 2410: ! 2411: /* For other data dependencies, the default cost specified in the ! 2412: md is correct. */ ! 2413: return cost; ! 2414: } ! 2415: else if (REG_NOTE_KIND (link) == REG_DEP_ANTI) ! 2416: { ! 2417: /* Anti dependency; DEP_INSN reads a register that INSN writes some ! 2418: cycles later. */ ! 2419: ! 2420: if (get_attr_type (insn) == TYPE_FPLOAD) ! 2421: { ! 2422: rtx pat = PATTERN (insn); ! 2423: rtx dep_pat = PATTERN (dep_insn); ! 2424: if (GET_CODE (pat) == PARALLEL) ! 2425: { ! 2426: /* This happens for the fldXs,mb patterns. */ ! 2427: pat = XVECEXP (pat, 0, 0); ! 2428: } ! 2429: if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET) ! 2430: /* If this happens, we have to extend this to schedule ! 2431: optimally. Return 0 for now. */ ! 2432: return 0; ! 2433: ! 2434: if (reg_mentioned_p (SET_DEST (pat), SET_SRC (dep_pat))) ! 2435: { ! 2436: if (! recog_memoized (dep_insn)) ! 2437: return 0; ! 2438: switch (get_attr_type (dep_insn)) ! 2439: { ! 2440: case TYPE_FPALU: ! 2441: case TYPE_FPMUL: ! 2442: case TYPE_FPDIVSGL: ! 2443: case TYPE_FPDIVDBL: ! 2444: case TYPE_FPSQRTSGL: ! 2445: case TYPE_FPSQRTDBL: ! 2446: /* A fpload can't be issued until one cycle before a ! 2447: preceeding arithmetic operation has finished, if ! 2448: the target of the fpload is any of the sources ! 2449: (or destination) of the arithmetic operation. */ ! 2450: return cost - 1; ! 2451: ! 2452: default: ! 2453: return 0; ! 2454: } ! 2455: } ! 2456: } ! 2457: ! 2458: /* For other anti dependencies, the cost is 0. */ ! 2459: return 0; ! 2460: } ! 2461: ! 2462: /* For output dependencies, the cost is often one too high. */ ! 2463: return cost - 1; ! 2464: } ! 2465: ! 2466: /* Return any length adjustment needed by INSN which already has its length ! 2467: computed as LENGTH. Return zero if no adjustment is necessary. ! 2468: ! 2469: For the PA: function calls, millicode calls, and short conditional branches ! 2470: with unfilled delay slots need an adjustment by +1 (to account for ! 2471: the NOP which will be inserted into the instruction stream). ! 2472: ! 2473: Also compute the length of an inline block move here as it is too ! 2474: complicated to express as a length attribute in pa.md. ! 2475: ! 2476: (For 2.5) Indirect calls do not need length adjustment as their ! 2477: delay slot is filled internally in the output template. ! 2478: ! 2479: (For 2.5) No adjustment is necessary for jump tables or casesi insns. */ ! 2480: int ! 2481: pa_adjust_insn_length (insn, length) ! 2482: rtx insn; ! 2483: int length; ! 2484: { ! 2485: rtx pat = PATTERN (insn); ! 2486: ! 2487: /* Call insn with an unfilled delay slot. */ ! 2488: if (GET_CODE (insn) == CALL_INSN) ! 2489: return 1; ! 2490: /* Millicode insn with an unfilled delay slot. */ ! 2491: else if (GET_CODE (insn) == INSN ! 2492: && GET_CODE (pat) != SEQUENCE ! 2493: && GET_CODE (pat) != USE ! 2494: && GET_CODE (pat) != CLOBBER ! 2495: && get_attr_type (insn) == TYPE_MILLI) ! 2496: return 1; ! 2497: /* Block move pattern. */ ! 2498: else if (GET_CODE (insn) == INSN ! 2499: && GET_CODE (pat) == PARALLEL ! 2500: && GET_CODE (XEXP (XVECEXP (pat, 0, 0), 0)) == MEM ! 2501: && GET_CODE (XEXP (XVECEXP (pat, 0, 0), 1)) == MEM ! 2502: && GET_MODE (XEXP (XVECEXP (pat, 0, 0), 0)) == BLKmode ! 2503: && GET_MODE (XEXP (XVECEXP (pat, 0, 0), 1)) == BLKmode) ! 2504: return compute_movstrsi_length (insn) - 1; ! 2505: /* Conditional branch with an unfilled delay slot. */ ! 2506: else if (GET_CODE (insn) == JUMP_INSN && ! simplejump_p (insn) ! 2507: && length != 2 && length != 4) ! 2508: return 1; ! 2509: else ! 2510: return 0; ! 2511: } ! 2512: ! 2513: /* Print operand X (an rtx) in assembler syntax to file FILE. ! 2514: CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. ! 2515: For `%' followed by punctuation, CODE is the punctuation and X is null. */ ! 2516: ! 2517: void ! 2518: print_operand (file, x, code) ! 2519: FILE *file; ! 2520: rtx x; ! 2521: int code; ! 2522: { ! 2523: switch (code) ! 2524: { ! 2525: case '#': ! 2526: /* Output a 'nop' if there's nothing for the delay slot. */ ! 2527: if (dbr_sequence_length () == 0) ! 2528: fputs ("\n\tnop", file); ! 2529: return; ! 2530: case '*': ! 2531: /* Output an nullification completer if there's nothing for the */ ! 2532: /* delay slot or nullification is requested. */ ! 2533: if (dbr_sequence_length () == 0 || ! 2534: (final_sequence && ! 2535: INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0)))) ! 2536: fputs (",n", file); ! 2537: return; ! 2538: case 'R': ! 2539: /* Print out the second register name of a register pair. ! 2540: I.e., R (6) => 7. */ ! 2541: fputs (reg_names[REGNO (x)+1], file); ! 2542: return; ! 2543: case 'r': ! 2544: /* A register or zero. */ ! 2545: if (x == const0_rtx ! 2546: || (x == CONST0_RTX (DFmode)) ! 2547: || (x == CONST0_RTX (SFmode))) ! 2548: { ! 2549: fputs ("0", file); ! 2550: return; ! 2551: } ! 2552: else ! 2553: break; ! 2554: case 'C': /* Plain (C)ondition */ ! 2555: case 'X': ! 2556: switch (GET_CODE (x)) ! 2557: { ! 2558: case EQ: ! 2559: fprintf (file, "="); break; ! 2560: case NE: ! 2561: fprintf (file, "<>"); break; ! 2562: case GT: ! 2563: fprintf (file, ">"); break; ! 2564: case GE: ! 2565: fprintf (file, ">="); break; ! 2566: case GEU: ! 2567: fprintf (file, ">>="); break; ! 2568: case GTU: ! 2569: fprintf (file, ">>"); break; ! 2570: case LT: ! 2571: fprintf (file, "<"); break; ! 2572: case LE: ! 2573: fprintf (file, "<="); break; ! 2574: case LEU: ! 2575: fprintf (file, "<<="); break; ! 2576: case LTU: ! 2577: fprintf (file, "<<"); break; ! 2578: default: ! 2579: printf ("Can't grok '%c' operator:\n", code); ! 2580: debug_rtx (x); ! 2581: abort (); ! 2582: } ! 2583: return; ! 2584: case 'N': /* Condition, (N)egated */ ! 2585: switch (GET_CODE (x)) ! 2586: { ! 2587: case EQ: ! 2588: fprintf (file, "<>"); break; ! 2589: case NE: ! 2590: fprintf (file, "="); break; ! 2591: case GT: ! 2592: fprintf (file, "<="); break; ! 2593: case GE: ! 2594: fprintf (file, "<"); break; ! 2595: case GEU: ! 2596: fprintf (file, "<<"); break; ! 2597: case GTU: ! 2598: fprintf (file, "<<="); break; ! 2599: case LT: ! 2600: fprintf (file, ">="); break; ! 2601: case LE: ! 2602: fprintf (file, ">"); break; ! 2603: case LEU: ! 2604: fprintf (file, ">>"); break; ! 2605: case LTU: ! 2606: fprintf (file, ">>="); break; ! 2607: default: ! 2608: printf ("Can't grok '%c' operator:\n", code); ! 2609: debug_rtx (x); ! 2610: abort (); ! 2611: } ! 2612: return; ! 2613: /* For floating point comparisons. Need special conditions to deal ! 2614: with NaNs properly. */ ! 2615: case 'Y': ! 2616: switch (GET_CODE (x)) ! 2617: { ! 2618: case EQ: ! 2619: fprintf (file, "!="); break; ! 2620: case NE: ! 2621: fprintf (file, "="); break; ! 2622: case GT: ! 2623: fprintf (file, "!>"); break; ! 2624: case GE: ! 2625: fprintf (file, "!>="); break; ! 2626: case LT: ! 2627: fprintf (file, "!<"); break; ! 2628: case LE: ! 2629: fprintf (file, "!<="); break; ! 2630: default: ! 2631: printf ("Can't grok '%c' operator:\n", code); ! 2632: debug_rtx (x); ! 2633: abort (); ! 2634: } ! 2635: return; ! 2636: case 'S': /* Condition, operands are (S)wapped. */ ! 2637: switch (GET_CODE (x)) ! 2638: { ! 2639: case EQ: ! 2640: fprintf (file, "="); break; ! 2641: case NE: ! 2642: fprintf (file, "<>"); break; ! 2643: case GT: ! 2644: fprintf (file, "<"); break; ! 2645: case GE: ! 2646: fprintf (file, "<="); break; ! 2647: case GEU: ! 2648: fprintf (file, "<<="); break; ! 2649: case GTU: ! 2650: fprintf (file, "<<"); break; ! 2651: case LT: ! 2652: fprintf (file, ">"); break; ! 2653: case LE: ! 2654: fprintf (file, ">="); break; ! 2655: case LEU: ! 2656: fprintf (file, ">>="); break; ! 2657: case LTU: ! 2658: fprintf (file, ">>"); break; ! 2659: default: ! 2660: printf ("Can't grok '%c' operator:\n", code); ! 2661: debug_rtx (x); ! 2662: abort (); ! 2663: } ! 2664: return; ! 2665: case 'B': /* Condition, (B)oth swapped and negate. */ ! 2666: switch (GET_CODE (x)) ! 2667: { ! 2668: case EQ: ! 2669: fprintf (file, "<>"); break; ! 2670: case NE: ! 2671: fprintf (file, "="); break; ! 2672: case GT: ! 2673: fprintf (file, ">="); break; ! 2674: case GE: ! 2675: fprintf (file, ">"); break; ! 2676: case GEU: ! 2677: fprintf (file, ">>"); break; ! 2678: case GTU: ! 2679: fprintf (file, ">>="); break; ! 2680: case LT: ! 2681: fprintf (file, "<="); break; ! 2682: case LE: ! 2683: fprintf (file, "<"); break; ! 2684: case LEU: ! 2685: fprintf (file, "<<"); break; ! 2686: case LTU: ! 2687: fprintf (file, "<<="); break; ! 2688: default: ! 2689: printf ("Can't grok '%c' operator:\n", code); ! 2690: debug_rtx (x); ! 2691: abort (); ! 2692: } ! 2693: return; ! 2694: case 'k': ! 2695: if (GET_CODE (x) == CONST_INT) ! 2696: { ! 2697: fprintf (file, "%d", ~INTVAL (x)); ! 2698: return; ! 2699: } ! 2700: abort(); ! 2701: case 'L': ! 2702: if (GET_CODE (x) == CONST_INT) ! 2703: { ! 2704: fprintf (file, "%d", 32 - (INTVAL (x) & 31)); ! 2705: return; ! 2706: } ! 2707: abort(); ! 2708: case 'O': ! 2709: if (GET_CODE (x) == CONST_INT && exact_log2 (INTVAL (x)) >= 0) ! 2710: { ! 2711: fprintf (file, "%d", exact_log2 (INTVAL (x))); ! 2712: return; ! 2713: } ! 2714: abort(); ! 2715: case 'P': ! 2716: if (GET_CODE (x) == CONST_INT) ! 2717: { ! 2718: fprintf (file, "%d", 31 - (INTVAL (x) & 31)); ! 2719: return; ! 2720: } ! 2721: abort(); ! 2722: case 'I': ! 2723: if (GET_CODE (x) == CONST_INT) ! 2724: fputs ("i", file); ! 2725: return; ! 2726: case 'M': ! 2727: switch (GET_CODE (XEXP (x, 0))) ! 2728: { ! 2729: case PRE_DEC: ! 2730: case PRE_INC: ! 2731: fprintf (file, "s,mb"); ! 2732: break; ! 2733: case POST_DEC: ! 2734: case POST_INC: ! 2735: fprintf (file, "s,ma"); ! 2736: break; ! 2737: default: ! 2738: break; ! 2739: } ! 2740: return; ! 2741: case 'F': ! 2742: switch (GET_CODE (XEXP (x, 0))) ! 2743: { ! 2744: case PRE_DEC: ! 2745: case PRE_INC: ! 2746: fprintf (file, ",mb"); ! 2747: break; ! 2748: case POST_DEC: ! 2749: case POST_INC: ! 2750: fprintf (file, ",ma"); ! 2751: break; ! 2752: default: ! 2753: break; ! 2754: } ! 2755: return; ! 2756: case 'G': ! 2757: output_global_address (file, x); ! 2758: return; ! 2759: case 0: /* Don't do anything special */ ! 2760: break; ! 2761: case 'Z': ! 2762: { ! 2763: unsigned op[3]; ! 2764: compute_zdepi_operands (INTVAL (x), op); ! 2765: fprintf (file, "%d,%d,%d", op[0], op[1], op[2]); ! 2766: return; ! 2767: } ! 2768: default: ! 2769: abort (); ! 2770: } ! 2771: if (GET_CODE (x) == REG) ! 2772: fprintf (file, "%s", reg_names [REGNO (x)]); ! 2773: else if (GET_CODE (x) == MEM) ! 2774: { ! 2775: int size = GET_MODE_SIZE (GET_MODE (x)); ! 2776: rtx base = XEXP (XEXP (x, 0), 0); ! 2777: switch (GET_CODE (XEXP (x, 0))) ! 2778: { ! 2779: case PRE_DEC: ! 2780: case POST_DEC: ! 2781: fprintf (file, "-%d(0,%s)", size, reg_names [REGNO (base)]); ! 2782: break; ! 2783: case PRE_INC: ! 2784: case POST_INC: ! 2785: fprintf (file, "%d(0,%s)", size, reg_names [REGNO (base)]); ! 2786: break; ! 2787: default: ! 2788: output_address (XEXP (x, 0)); ! 2789: break; ! 2790: } ! 2791: } ! 2792: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode) ! 2793: { ! 2794: union { double d; int i[2]; } u; ! 2795: union { float f; int i; } u1; ! 2796: u.i[0] = XINT (x, 0); u.i[1] = XINT (x, 1); ! 2797: u1.f = u.d; ! 2798: if (code == 'f') ! 2799: fprintf (file, "0r%.9g", u1.f); ! 2800: else ! 2801: fprintf (file, "0x%x", u1.i); ! 2802: } ! 2803: else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != DImode) ! 2804: { ! 2805: union { double d; int i[2]; } u; ! 2806: u.i[0] = XINT (x, 0); u.i[1] = XINT (x, 1); ! 2807: fprintf (file, "0r%.20g", u.d); ! 2808: } ! 2809: else ! 2810: output_addr_const (file, x); ! 2811: } ! 2812: ! 2813: /* output a SYMBOL_REF or a CONST expression involving a SYMBOL_REF. */ ! 2814: ! 2815: void ! 2816: output_global_address (file, x) ! 2817: FILE *file; ! 2818: rtx x; ! 2819: { ! 2820: ! 2821: /* Imagine (high (const (plus ...))). */ ! 2822: if (GET_CODE (x) == HIGH) ! 2823: x = XEXP (x, 0); ! 2824: ! 2825: if (GET_CODE (x) == SYMBOL_REF && read_only_operand (x)) ! 2826: assemble_name (file, XSTR (x, 0)); ! 2827: else if (GET_CODE (x) == SYMBOL_REF) ! 2828: { ! 2829: assemble_name (file, XSTR (x, 0)); ! 2830: fprintf (file, "-$global$"); ! 2831: } ! 2832: else if (GET_CODE (x) == CONST) ! 2833: { ! 2834: char *sep = ""; ! 2835: int offset = 0; /* assembler wants -$global$ at end */ ! 2836: rtx base; ! 2837: ! 2838: if (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF) ! 2839: { ! 2840: base = XEXP (XEXP (x, 0), 0); ! 2841: output_addr_const (file, base); ! 2842: } ! 2843: else if (GET_CODE (XEXP (XEXP (x, 0), 0)) == CONST_INT) ! 2844: offset = INTVAL (XEXP (XEXP (x, 0), 0)); ! 2845: else abort (); ! 2846: ! 2847: if (GET_CODE (XEXP (XEXP (x, 0), 1)) == SYMBOL_REF) ! 2848: { ! 2849: base = XEXP (XEXP (x, 0), 1); ! 2850: output_addr_const (file, base); ! 2851: } ! 2852: else if (GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) ! 2853: offset = INTVAL (XEXP (XEXP (x, 0),1)); ! 2854: else abort (); ! 2855: ! 2856: if (GET_CODE (XEXP (x, 0)) == PLUS) ! 2857: { ! 2858: if (offset < 0) ! 2859: { ! 2860: offset = -offset; ! 2861: sep = "-"; ! 2862: } ! 2863: else ! 2864: sep = "+"; ! 2865: } ! 2866: else if (GET_CODE (XEXP (x, 0)) == MINUS ! 2867: && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)) ! 2868: sep = "-"; ! 2869: else abort (); ! 2870: ! 2871: if (!read_only_operand (base)) ! 2872: fprintf (file, "-$global$"); ! 2873: fprintf (file, "%s", sep); ! 2874: if (offset) fprintf (file,"%d", offset); ! 2875: } ! 2876: else ! 2877: output_addr_const (file, x); ! 2878: } ! 2879: ! 2880: /* HP's millicode routines mean something special to the assembler. ! 2881: Keep track of which ones we have used. */ ! 2882: ! 2883: enum millicodes { remI, remU, divI, divU, mulI, mulU, end1000 }; ! 2884: static char imported[(int)end1000]; ! 2885: static char *milli_names[] = {"remI", "remU", "divI", "divU", "mulI", "mulU"}; ! 2886: static char import_string[] = ".IMPORT $$....,MILLICODE"; ! 2887: #define MILLI_START 10 ! 2888: ! 2889: static int ! 2890: import_milli (code) ! 2891: enum millicodes code; ! 2892: { ! 2893: char str[sizeof (import_string)]; ! 2894: ! 2895: if (!imported[(int)code]) ! 2896: { ! 2897: imported[(int)code] = 1; ! 2898: strcpy (str, import_string); ! 2899: strncpy (str + MILLI_START, milli_names[(int)code], 4); ! 2900: output_asm_insn (str, 0); ! 2901: } ! 2902: } ! 2903: ! 2904: /* The register constraints have put the operands and return value in ! 2905: the proper registers. */ ! 2906: ! 2907: char * ! 2908: output_mul_insn (unsignedp) ! 2909: int unsignedp; ! 2910: { ! 2911: if (unsignedp) ! 2912: { ! 2913: import_milli (mulU); ! 2914: return "bl $$mulU,31%#"; ! 2915: } ! 2916: else ! 2917: { ! 2918: import_milli (mulI); ! 2919: return "bl $$mulI,31%#"; ! 2920: } ! 2921: } ! 2922: ! 2923: /* If operands isn't NULL, then it's a CONST_INT with which we can do ! 2924: something */ ! 2925: ! 2926: ! 2927: /* Emit the rtl for doing a division by a constant. */ ! 2928: ! 2929: /* Do magic division millicodes exist for this value? */ ! 2930: ! 2931: static int magic_milli[]= {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, ! 2932: 1, 1}; ! 2933: ! 2934: /* We'll use an array to keep track of the magic millicodes and ! 2935: whether or not we've used them already. [n][0] is signed, [n][1] is ! 2936: unsigned. */ ! 2937: ! 2938: static int div_milli[16][2]; ! 2939: ! 2940: int ! 2941: div_operand (op, mode) ! 2942: rtx op; ! 2943: enum machine_mode mode; ! 2944: { ! 2945: return (mode == SImode ! 2946: && ((GET_CODE (op) == REG && REGNO (op) == 25) ! 2947: || (GET_CODE (op) == CONST_INT && INTVAL (op) > 0 ! 2948: && INTVAL (op) < 16 && magic_milli[INTVAL (op)]))); ! 2949: } ! 2950: ! 2951: int ! 2952: emit_hpdiv_const (operands, unsignedp) ! 2953: rtx *operands; ! 2954: int unsignedp; ! 2955: { ! 2956: if (GET_CODE (operands[2]) == CONST_INT ! 2957: && INTVAL (operands[2]) > 0 ! 2958: && INTVAL (operands[2]) < 16 ! 2959: && magic_milli[INTVAL (operands[2])]) ! 2960: { ! 2961: emit_move_insn ( gen_rtx (REG, SImode, 26), operands[1]); ! 2962: emit ! 2963: (gen_rtx ! 2964: (PARALLEL, VOIDmode, ! 2965: gen_rtvec (5, gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, 29), ! 2966: gen_rtx (unsignedp ? UDIV : DIV, SImode, ! 2967: gen_rtx (REG, SImode, 26), ! 2968: operands[2])), ! 2969: gen_rtx (CLOBBER, VOIDmode, operands[3]), ! 2970: gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 26)), ! 2971: gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 25)), ! 2972: gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, SImode, 31))))); ! 2973: emit_move_insn (operands[0], gen_rtx (REG, SImode, 29)); ! 2974: return 1; ! 2975: } ! 2976: return 0; ! 2977: } ! 2978: ! 2979: char * ! 2980: output_div_insn (operands, unsignedp) ! 2981: rtx *operands; ! 2982: int unsignedp; ! 2983: { ! 2984: int divisor; ! 2985: ! 2986: /* If the divisor is a constant, try to use one of the special ! 2987: opcodes .*/ ! 2988: if (GET_CODE (operands[0]) == CONST_INT) ! 2989: { ! 2990: divisor = INTVAL (operands[0]); ! 2991: if (!div_milli[divisor][unsignedp]) ! 2992: { ! 2993: if (unsignedp) ! 2994: output_asm_insn (".IMPORT $$divU_%0,MILLICODE", operands); ! 2995: else ! 2996: output_asm_insn (".IMPORT $$divI_%0,MILLICODE", operands); ! 2997: div_milli[divisor][unsignedp] = 1; ! 2998: } ! 2999: if (unsignedp) ! 3000: return "bl $$divU_%0,31%#"; ! 3001: return "bl $$divI_%0,31%#"; ! 3002: } ! 3003: /* Divisor isn't a special constant. */ ! 3004: else ! 3005: { ! 3006: if (unsignedp) ! 3007: { ! 3008: import_milli (divU); ! 3009: return "bl $$divU,31%#"; ! 3010: } ! 3011: else ! 3012: { ! 3013: import_milli (divI); ! 3014: return "bl $$divI,31%#"; ! 3015: } ! 3016: } ! 3017: } ! 3018: ! 3019: /* Output a $$rem millicode to do mod. */ ! 3020: ! 3021: char * ! 3022: output_mod_insn (unsignedp) ! 3023: int unsignedp; ! 3024: { ! 3025: if (unsignedp) ! 3026: { ! 3027: import_milli (remU); ! 3028: return "bl $$remU,31%#"; ! 3029: } ! 3030: else ! 3031: { ! 3032: import_milli (remI); ! 3033: return "bl $$remI,31%#"; ! 3034: } ! 3035: } ! 3036: ! 3037: void ! 3038: output_arg_descriptor (insn) ! 3039: rtx insn; ! 3040: { ! 3041: char *arg_regs[4]; ! 3042: enum machine_mode arg_mode; ! 3043: rtx prev_insn; ! 3044: int i, output_flag = 0; ! 3045: int regno; ! 3046: ! 3047: for (i = 0; i < 4; i++) ! 3048: arg_regs[i] = 0; ! 3049: ! 3050: for (prev_insn = PREV_INSN (insn); GET_CODE (prev_insn) == INSN; ! 3051: prev_insn = PREV_INSN (prev_insn)) ! 3052: { ! 3053: if (!(GET_CODE (PATTERN (prev_insn)) == USE && ! 3054: GET_CODE (XEXP (PATTERN (prev_insn), 0)) == REG && ! 3055: FUNCTION_ARG_REGNO_P (REGNO (XEXP (PATTERN (prev_insn), 0))))) ! 3056: break; ! 3057: arg_mode = GET_MODE (XEXP (PATTERN (prev_insn), 0)); ! 3058: regno = REGNO (XEXP (PATTERN (prev_insn), 0)); ! 3059: if (regno >= 23 && regno <= 26) ! 3060: { ! 3061: arg_regs[26 - regno] = "GR"; ! 3062: if (arg_mode == DImode) ! 3063: arg_regs[25 - regno] = "GR"; ! 3064: } ! 3065: else if (!TARGET_SNAKE) /* fp args */ ! 3066: { ! 3067: if (arg_mode == SFmode) ! 3068: arg_regs[regno - 32] = "FR"; ! 3069: else ! 3070: { ! 3071: #ifdef HP_FP_ARG_DESCRIPTOR_REVERSED ! 3072: arg_regs[regno - 33] = "FR"; ! 3073: arg_regs[regno - 32] = "FU"; ! 3074: #else ! 3075: arg_regs[regno - 33] = "FU"; ! 3076: arg_regs[regno - 32] = "FR"; ! 3077: #endif ! 3078: } ! 3079: } ! 3080: else ! 3081: { ! 3082: if (arg_mode == SFmode) ! 3083: arg_regs[(regno - 44) / 2] = "FR"; ! 3084: else ! 3085: { ! 3086: #ifdef HP_FP_ARG_DESCRIPTOR_REVERSED ! 3087: arg_regs[(regno - 46) / 2] = "FR"; ! 3088: arg_regs[(regno - 46) / 2 + 1] = "FU"; ! 3089: #else ! 3090: arg_regs[(regno - 46) / 2] = "FU"; ! 3091: arg_regs[(regno - 46) / 2 + 1] = "FR"; ! 3092: #endif ! 3093: } ! 3094: } ! 3095: } ! 3096: fputs ("\t.CALL ", asm_out_file); ! 3097: for (i = 0; i < 4; i++) ! 3098: { ! 3099: if (arg_regs[i]) ! 3100: { ! 3101: if (output_flag++) ! 3102: fputc (',', asm_out_file); ! 3103: fprintf (asm_out_file, "ARGW%d=%s", i, arg_regs[i]); ! 3104: } ! 3105: } ! 3106: fputc ('\n', asm_out_file); ! 3107: } ! 3108: ! 3109: /* Memory loads/stores to/from the shift need to go through ! 3110: the general registers. */ ! 3111: ! 3112: enum reg_class ! 3113: secondary_reload_class (class, mode, in) ! 3114: enum reg_class class; ! 3115: enum machine_mode mode; ! 3116: rtx in; ! 3117: { ! 3118: int regno = true_regnum (in); ! 3119: ! 3120: if ((TARGET_SHARED_LIBS && function_label_operand (in, mode)) ! 3121: || ((regno >= FIRST_PSEUDO_REGISTER || regno == -1) ! 3122: && GET_MODE_CLASS (mode) == MODE_INT ! 3123: && FP_REG_CLASS_P (class)) ! 3124: || (class == SHIFT_REGS && (regno <= 0 || regno >= 32))) ! 3125: return GENERAL_REGS; ! 3126: ! 3127: if (GET_CODE (in) == HIGH) ! 3128: in = XEXP (in, 0); ! 3129: ! 3130: if (TARGET_KERNEL && class != R1_REGS && symbolic_operand (in, VOIDmode)) ! 3131: return R1_REGS; ! 3132: ! 3133: return NO_REGS; ! 3134: } ! 3135: ! 3136: enum direction ! 3137: function_arg_padding (mode, type) ! 3138: enum machine_mode mode; ! 3139: tree type; ! 3140: { ! 3141: int size; ! 3142: ! 3143: if (mode == BLKmode) ! 3144: { ! 3145: if (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST) ! 3146: size = int_size_in_bytes (type) * BITS_PER_UNIT; ! 3147: else ! 3148: return upward; /* Don't know if this is right, but */ ! 3149: /* same as old definition. */ ! 3150: } ! 3151: else ! 3152: size = GET_MODE_BITSIZE (mode); ! 3153: if (size < PARM_BOUNDARY) ! 3154: return downward; ! 3155: else if (size % PARM_BOUNDARY) ! 3156: return upward; ! 3157: else ! 3158: return none; ! 3159: } ! 3160: ! 3161: ! 3162: /* Do what is necessary for `va_start'. The argument is ignored; ! 3163: We look at the current function to determine if stdargs or varargs ! 3164: is used and fill in an initial va_list. A pointer to this constructor ! 3165: is returned. */ ! 3166: ! 3167: struct rtx_def * ! 3168: hppa_builtin_saveregs (arglist) ! 3169: tree arglist; ! 3170: { ! 3171: rtx block, float_addr, offset, float_mem; ! 3172: tree fntype = TREE_TYPE (current_function_decl); ! 3173: int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0 ! 3174: && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) ! 3175: != void_type_node))) ! 3176: ? UNITS_PER_WORD : 0); ! 3177: ! 3178: if (argadj) ! 3179: offset = plus_constant (current_function_arg_offset_rtx, argadj); ! 3180: else ! 3181: offset = current_function_arg_offset_rtx; ! 3182: ! 3183: /* Store general registers on the stack. */ ! 3184: move_block_from_reg (23, ! 3185: gen_rtx (MEM, BLKmode, ! 3186: plus_constant ! 3187: (current_function_internal_arg_pointer, -16)), ! 3188: 4); ! 3189: return copy_to_reg (expand_binop (Pmode, add_optab, ! 3190: current_function_internal_arg_pointer, ! 3191: offset, 0, 0, OPTAB_LIB_WIDEN)); ! 3192: } ! 3193: ! 3194: /* This routine handles all the normal conditional branch sequences we ! 3195: might need to generate. It handles compare immediate vs compare ! 3196: register, nullification of delay slots, varying length branches, ! 3197: negated branches, and all combinations of the above. It returns the ! 3198: output appropriate to emit the branch corresponding to all given ! 3199: parameters. */ ! 3200: ! 3201: char * ! 3202: output_cbranch (operands, nullify, length, negated, insn) ! 3203: rtx *operands; ! 3204: int nullify, length, negated; ! 3205: rtx insn; ! 3206: { ! 3207: static char buf[100]; ! 3208: int useskip = 0; ! 3209: ! 3210: /* A forward branch over a single nullified insn can be done with a ! 3211: comclr instruction. This avoids a single cycle penalty due to ! 3212: mis-predicted branch if we fall through (branch not taken). */ ! 3213: ! 3214: if (length == 1 ! 3215: && JUMP_LABEL (insn) == next_nonnote_insn (NEXT_INSN (insn)) ! 3216: && nullify) ! 3217: useskip = 1; ! 3218: ! 3219: switch (length) ! 3220: { ! 3221: ! 3222: /* Short conditional branch. May nullify either direction. */ ! 3223: case 1: ! 3224: if (useskip) ! 3225: strcpy (buf, "com%I2clr,"); ! 3226: else ! 3227: strcpy (buf, "com%I2b,"); ! 3228: if (negated) ! 3229: strcat (buf, "%B3"); ! 3230: else ! 3231: strcat (buf, "%S3"); ! 3232: if (useskip) ! 3233: strcat (buf, " %2,%1,0"); ! 3234: else if (nullify) ! 3235: strcat (buf, ",n %2,%1,%0"); ! 3236: else ! 3237: strcat (buf, " %2,%1,%0%#"); ! 3238: break; ! 3239: ! 3240: /* Long conditional branch, possible forward nullification. Also ! 3241: note all conditional branches have a length of 4 when not ! 3242: optimizing! */ ! 3243: case 2: ! 3244: case 4: ! 3245: strcpy (buf, "com%I2clr,"); ! 3246: if (negated) ! 3247: strcat (buf, "%S3"); ! 3248: else ! 3249: strcat (buf, "%B3"); ! 3250: /* Nullify the delay slot if the delay slot was explicitly ! 3251: nullified by the delay branch scheduler or if no insn ! 3252: could be placed in the delay slot. */ ! 3253: if (nullify) ! 3254: strcat (buf, " %2,%1,0\n\tbl,n %0,0"); ! 3255: else ! 3256: strcat (buf, " %2,%1,0\n\tbl%* %0,0"); ! 3257: break; ! 3258: ! 3259: /* Long backward conditional branch with nullification. */ ! 3260: case 3: ! 3261: strcpy (buf, "com%I2b,"); ! 3262: if (negated) ! 3263: strcat (buf, "%S3"); ! 3264: else ! 3265: strcat (buf, "%B3"); ! 3266: strcat (buf, " %2,%1,.+16\n\tnop\n\t bl %0,0"); ! 3267: break; ! 3268: ! 3269: default: ! 3270: abort(); ! 3271: } ! 3272: return buf; ! 3273: } ! 3274: ! 3275: /* This routine handles all the branch-on-bit conditional branch sequences we ! 3276: might need to generate. It handles nullification of delay slots, ! 3277: varying length branches, negated branches and all combinations of the ! 3278: above. it returns the appropriate output template to emit the branch. */ ! 3279: ! 3280: char * ! 3281: output_bb (operands, nullify, length, negated, insn, which) ! 3282: rtx *operands; ! 3283: int nullify, length, negated; ! 3284: rtx insn; ! 3285: int which; ! 3286: { ! 3287: static char buf[100]; ! 3288: int useskip = 0; ! 3289: ! 3290: /* A forward branch over a single nullified insn can be done with a ! 3291: extrs instruction. This avoids a single cycle penalty due to ! 3292: mis-predicted branch if we fall through (branch not taken). */ ! 3293: ! 3294: if (length == 1 ! 3295: && JUMP_LABEL (insn) == next_nonnote_insn (NEXT_INSN (insn)) ! 3296: && nullify) ! 3297: useskip = 1; ! 3298: ! 3299: switch (length) ! 3300: { ! 3301: ! 3302: /* Short conditional branch. May nullify either direction. */ ! 3303: case 1: ! 3304: if (useskip) ! 3305: strcpy (buf, "extrs,"); ! 3306: else ! 3307: strcpy (buf, "bb,"); ! 3308: if ((which == 0 && negated) ! 3309: || (which == 1 && ! negated)) ! 3310: strcat (buf, ">="); ! 3311: else ! 3312: strcat (buf, "<"); ! 3313: if (useskip) ! 3314: strcat (buf, " %0,%1,1,0"); ! 3315: else if (nullify && negated) ! 3316: strcat (buf, ",n %0,%1,%3"); ! 3317: else if (nullify && ! negated) ! 3318: strcat (buf, ",n %0,%1,%2"); ! 3319: else if (! nullify && negated) ! 3320: strcat (buf, "%0,%1,%3%#"); ! 3321: else if (! nullify && ! negated) ! 3322: strcat (buf, " %0,%1,%2%#"); ! 3323: break; ! 3324: ! 3325: /* Long conditional branch, possible forward nullification. Also ! 3326: note all conditional branches have a length of 4 when not ! 3327: optimizing! */ ! 3328: case 2: ! 3329: case 4: ! 3330: strcpy (buf, "extrs,"); ! 3331: if ((which == 0 && negated) ! 3332: || (which == 1 && ! negated)) ! 3333: strcat (buf, "<"); ! 3334: else ! 3335: strcat (buf, ">="); ! 3336: /* Nullify the delay slot if the delay slot was explicitly ! 3337: nullified by the delay branch scheduler or if no insn ! 3338: could be placed in the delay slot. */ ! 3339: if (nullify && negated) ! 3340: strcat (buf, " %0,%1,1,0\n\tbl,n %3,0"); ! 3341: else if (nullify && ! negated) ! 3342: strcat (buf, " %0,%1,1,0\n\tbl,n %2,0"); ! 3343: else if (negated) ! 3344: strcat (buf, " %0,%1,1,0\n\tbl%* %3,0"); ! 3345: else ! 3346: strcat (buf, " %0,%1,1,0\n\tbl%* %2,0"); ! 3347: break; ! 3348: ! 3349: /* Long backward conditional branch with nullification. */ ! 3350: case 3: ! 3351: strcpy (buf, "bb,"); ! 3352: if ((which == 0 && negated) ! 3353: || (which == 1 && ! negated)) ! 3354: strcat (buf, "<"); ! 3355: else ! 3356: strcat (buf, ">="); ! 3357: if (negated) ! 3358: strcat (buf, " %0,%1,.+16\n\tnop\n\t bl %3,0"); ! 3359: else ! 3360: strcat (buf, " %0,%1,.+16\n\tnop\n\t bl %2,0"); ! 3361: break; ! 3362: ! 3363: default: ! 3364: abort(); ! 3365: } ! 3366: return buf; ! 3367: } ! 3368: ! 3369: extern struct obstack *saveable_obstack; ! 3370: ! 3371: /* In HPUX 8.0's shared library scheme, special relocations are needed ! 3372: for function labels if they might be passed to a function ! 3373: in a shared library (because shared libraries don't live in code ! 3374: space), and special magic is needed to construct their address. */ ! 3375: ! 3376: void ! 3377: hppa_encode_label (sym) ! 3378: rtx sym; ! 3379: { ! 3380: char *str = XSTR (sym, 0); ! 3381: int len = strlen (str); ! 3382: char *newstr = obstack_alloc (saveable_obstack, len + 2) ; ! 3383: ! 3384: if (str[0] == '*') ! 3385: *newstr++ = *str++; ! 3386: strcpy (newstr + 1, str); ! 3387: *newstr = '@'; ! 3388: XSTR (sym,0) = newstr; ! 3389: } ! 3390: ! 3391: int ! 3392: function_label_operand (op, mode) ! 3393: rtx op; ! 3394: enum machine_mode mode; ! 3395: { ! 3396: return GET_CODE (op) == SYMBOL_REF && FUNCTION_NAME_P (XSTR (op, 0)); ! 3397: } ! 3398: ! 3399: /* Returns 1 if the 6 operands specified in OPERANDS are suitable for ! 3400: use in fmpyadd instructions. */ ! 3401: int ! 3402: fmpyaddoperands(operands) ! 3403: rtx *operands; ! 3404: { ! 3405: enum machine_mode mode = GET_MODE (operands[0]); ! 3406: ! 3407: /* All modes must be the same. */ ! 3408: if (! (mode == GET_MODE (operands[1]) ! 3409: && mode == GET_MODE (operands[2]) ! 3410: && mode == GET_MODE (operands[3]) ! 3411: && mode == GET_MODE (operands[4]) ! 3412: && mode == GET_MODE (operands[5]))) ! 3413: return 0; ! 3414: ! 3415: /* Both DFmode and SFmode should work. But using SFmode makes the ! 3416: assembler complain. Just turn it off for now. */ ! 3417: if (mode != DFmode) ! 3418: return 0; ! 3419: ! 3420: /* Only 2 real operands to the addition. One of the input operands must ! 3421: be the same as the output operand. */ ! 3422: if (! rtx_equal_p (operands[3], operands[4]) ! 3423: && ! rtx_equal_p (operands[3], operands[5])) ! 3424: return 0; ! 3425: ! 3426: /* Inout operand of add can not conflict with any operands from multiply. */ ! 3427: if (rtx_equal_p (operands[3], operands[0]) ! 3428: || rtx_equal_p (operands[3], operands[1]) ! 3429: || rtx_equal_p (operands[3], operands[2])) ! 3430: return 0; ! 3431: ! 3432: /* multiply can not feed into addition operands. */ ! 3433: if (rtx_equal_p (operands[4], operands[0]) ! 3434: || rtx_equal_p (operands[5], operands[0])) ! 3435: return 0; ! 3436: ! 3437: /* Passed. Operands are suitable for fmpyadd. */ ! 3438: return 1; ! 3439: } ! 3440: ! 3441: /* Returns 1 if the 6 operands specified in OPERANDS are suitable for ! 3442: use in fmpysub instructions. */ ! 3443: int ! 3444: fmpysuboperands(operands) ! 3445: rtx *operands; ! 3446: { ! 3447: enum machine_mode mode = GET_MODE (operands[0]); ! 3448: ! 3449: /* All modes must be the same. */ ! 3450: if (! (mode == GET_MODE (operands[1]) ! 3451: && mode == GET_MODE (operands[2]) ! 3452: && mode == GET_MODE (operands[3]) ! 3453: && mode == GET_MODE (operands[4]) ! 3454: && mode == GET_MODE (operands[5]))) ! 3455: return 0; ! 3456: ! 3457: /* Both DFmode and SFmode should work. But using SFmode makes the ! 3458: assembler complain. Just turn it off for now. */ ! 3459: if (mode != DFmode) ! 3460: return 0; ! 3461: ! 3462: /* Only 2 real operands to the subtraction. Subtraction is not a commutative ! 3463: operation, so operands[4] must be the same as operand[3]. */ ! 3464: if (! rtx_equal_p (operands[3], operands[4])) ! 3465: return 0; ! 3466: ! 3467: /* multiply can not feed into subtraction. */ ! 3468: if (rtx_equal_p (operands[5], operands[0])) ! 3469: return 0; ! 3470: ! 3471: /* Inout operand of sub can not conflict with any operands from multiply. */ ! 3472: if (rtx_equal_p (operands[3], operands[0]) ! 3473: || rtx_equal_p (operands[3], operands[1]) ! 3474: || rtx_equal_p (operands[3], operands[2])) ! 3475: return 0; ! 3476: ! 3477: /* Passed. Operands are suitable for fmpysub. */ ! 3478: return 1; ! 3479: } ! 3480: ! 3481: int ! 3482: plus_xor_ior_operator (op, mode) ! 3483: rtx op; ! 3484: enum machine_mode mode; ! 3485: { ! 3486: return (GET_CODE (op) == PLUS || GET_CODE (op) == XOR ! 3487: || GET_CODE (op) == IOR); ! 3488: } ! 3489: ! 3490: /* Return 1 if the given constant is 2, 4, or 8. These are the valid ! 3491: constants for shadd instructions. */ ! 3492: int ! 3493: shadd_constant_p (val) ! 3494: int val; ! 3495: { ! 3496: if (val == 2 || val == 4 || val == 8) ! 3497: return 1; ! 3498: else ! 3499: return 0; ! 3500: } ! 3501: ! 3502: /* Return 1 if OP is a CONST_INT with the value 2, 4, or 8. These are ! 3503: the valid constant for shadd instructions. */ ! 3504: int ! 3505: shadd_operand (op, mode) ! 3506: rtx op; ! 3507: enum machine_mode mode; ! 3508: { ! 3509: return (GET_CODE (op) == CONST_INT && shadd_constant_p (INTVAL (op))); ! 3510: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.