|
|
1.1 root 1: /* Subroutines for insn-output.c for Sun SPARC. 1.1.1.4 ! root 2: Copyright (C) 1987, 1988 Free Software Foundation, Inc. 1.1 root 3: Contributed by Michael Tiemann ([email protected]) 4: 5: This file is part of GNU CC. 6: 7: GNU CC is distributed in the hope that it will be useful, 8: but WITHOUT ANY WARRANTY. No author or distributor 9: accepts responsibility to anyone for the consequences of using it 10: or for whether it serves any particular purpose or works at all, 11: unless he says so in writing. Refer to the GNU CC General Public 12: License for full details. 13: 14: Everyone is granted permission to copy, modify and redistribute 15: GNU CC, but only under the conditions described in the 16: GNU CC General Public License. A copy of this license is 17: supposed to have been given to you along with GNU CC so you 18: can know your rights and responsibilities. It should be in a 19: file named COPYING. Among other things, the copyright notice 20: and this notice must be preserved on all copies. */ 21: 22: /* Global variables for machine-dependend things. */ 23: 24: /* This should go away if we pass floats to regs via 1.1.1.4 ! root 25: the stack instead of the frame, and if we learn how ! 26: to renumber all the registers when we don't do a save (hard!). */ 1.1 root 27: extern int frame_pointer_needed; 28: 29: static rtx find_addr_reg (); 30: 1.1.1.4 ! root 31: /* Return non-zero if this pattern, as a source to a "SET", ! 32: is known to yield an instruction of unit size. */ ! 33: int ! 34: single_insn_src_p (op, mode) ! 35: rtx op; ! 36: enum machine_mode mode; 1.1 root 37: { 1.1.1.4 ! root 38: switch (GET_CODE (op)) ! 39: { ! 40: case CONST_INT: ! 41: if (SMALL_INT (op)) ! 42: return 1; ! 43: return 0; ! 44: ! 45: case REG: ! 46: case MEM: ! 47: return 1; ! 48: ! 49: /* We never need to negate or complement constants. */ ! 50: case NOT: ! 51: case NEG: ! 52: return 1; ! 53: ! 54: case PLUS: ! 55: case MINUS: ! 56: case AND: ! 57: case IOR: ! 58: case XOR: ! 59: case LSHIFT: ! 60: case ASHIFT: ! 61: case ASHIFTRT: ! 62: case LSHIFTRT: ! 63: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) ! 64: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) ! 65: return 0; ! 66: return 1; ! 67: ! 68: case SUBREG: ! 69: if (SUBREG_WORD (op) != 0) ! 70: return 0; ! 71: return single_insn_src_p (SUBREG_REG (op), mode); ! 72: ! 73: case SIGN_EXTEND: ! 74: case ZERO_EXTEND: ! 75: /* Lazy... could check for these. */ ! 76: return 0; ! 77: ! 78: /* Not doing floating point, since they probably ! 79: take longer than the branch slot they might fill. */ ! 80: case FLOAT_EXTEND: ! 81: case FLOAT_TRUNCATE: ! 82: case FLOAT: ! 83: case FIX: ! 84: case UNSIGNED_FLOAT: ! 85: case UNSIGNED_FIX: ! 86: return 0; ! 87: ! 88: default: ! 89: return 0; ! 90: } 1.1 root 91: } 1.1.1.4 ! root 92: ! 93: /* ??? Comment needed here */ 1.1 root 94: 95: int 96: arith_operand (op, mode) 97: rtx op; 98: enum machine_mode mode; 99: { 100: return (register_operand (op, mode) 101: || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); 102: } 103: 1.1.1.4 ! root 104: /* ??? Comment needed here */ ! 105: 1.1 root 106: int 107: arith32_operand (op, mode) 108: rtx op; 109: enum machine_mode mode; 110: { 111: return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); 112: } 113: 1.1.1.3 root 114: int 115: small_int (op, mode) 116: rtx op; 117: enum machine_mode mode; 118: { 119: return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); 120: } 121: 1.1 root 122: /* Return the best assembler insn template 123: for moving operands[1] into operands[0] as a fullword. */ 124: 125: static char * 126: singlemove_string (operands) 127: rtx *operands; 128: { 129: if (GET_CODE (operands[0]) == MEM) 130: return "st %r1,%0"; 131: if (GET_CODE (operands[1]) == MEM) 132: return "ld %1,%0"; 1.1.1.3 root 133: return "mov %1,%0"; 1.1 root 134: } 135: 136: /* Output assembler code to perform a doubleword move insn 137: with operands OPERANDS. */ 138: 139: char * 140: output_move_double (operands) 141: rtx *operands; 142: { 143: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; 144: rtx latehalf[2]; 145: rtx addreg0 = 0, addreg1 = 0; 146: 147: /* First classify both operands. */ 148: 149: if (REG_P (operands[0])) 150: optype0 = REGOP; 151: else if (offsetable_memref_p (operands[0])) 152: optype0 = OFFSOP; 153: else if (GET_CODE (operands[0]) == MEM) 154: optype0 = MEMOP; 155: else 156: optype0 = RNDOP; 157: 158: if (REG_P (operands[1])) 159: optype1 = REGOP; 160: else if (CONSTANT_P (operands[1]) 161: || GET_CODE (operands[1]) == CONST_DOUBLE) 162: optype1 = CNSTOP; 163: else if (offsetable_memref_p (operands[1])) 164: optype1 = OFFSOP; 165: else if (GET_CODE (operands[1]) == MEM) 166: optype0 = MEMOP; 167: else 168: optype1 = RNDOP; 169: 170: /* Check for the cases that the operand constraints are not 171: supposed to allow to happen. Abort if we get one, 172: because generating code for these cases is painful. */ 173: 174: if (optype0 == RNDOP || optype1 == RNDOP) 175: abort (); 176: 177: /* If an operand is an unoffsettable memory ref, find a register 178: we can increment temporarily to make it refer to the second word. */ 179: 180: if (optype0 == MEMOP) 181: addreg0 = find_addr_reg (operands[0]); 182: 183: if (optype1 == MEMOP) 184: addreg1 = find_addr_reg (operands[1]); 185: 186: /* Ok, we can do one word at a time. 187: Normally we do the low-numbered word first, 188: but if either operand is autodecrementing then we 189: do the high-numbered word first. 190: 191: In either case, set up in LATEHALF the operands to use 192: for the high-numbered word and in some cases alter the 193: operands in OPERANDS to be suitable for the low-numbered word. */ 194: 195: if (optype0 == REGOP) 196: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); 197: else if (optype0 == OFFSOP) 198: latehalf[0] = adj_offsetable_operand (operands[0], 4); 199: else 200: latehalf[0] = operands[0]; 201: 202: if (optype1 == REGOP) 203: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); 204: else if (optype1 == OFFSOP) 205: latehalf[1] = adj_offsetable_operand (operands[1], 4); 206: else if (optype1 == CNSTOP) 207: { 208: if (CONSTANT_P (operands[1])) 209: latehalf[1] = const0_rtx; 210: else if (GET_CODE (operands[1]) == CONST_DOUBLE) 211: { 212: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1)); 213: operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0)); 214: } 215: } 216: else 217: latehalf[1] = operands[1]; 218: 219: /* If the first move would clobber the source of the second one, 1.1.1.3 root 220: do them in the other order. 221: 222: RMS says "This happens only for registers; 1.1 root 223: such overlap can't happen in memory unless the user explicitly 1.1.1.3 root 224: sets it up, and that is an undefined circumstance." 225: 226: but it happens on the sparc when loading parameter registers, 227: so I am going to define that circumstance, and make it work 228: as expected. */ 229: 230: /* Easy case: try moving both words at once. */ 231: if ((optype0 == REGOP && optype1 != REGOP 232: && (REGNO (operands[0]) & 1) == 0) 233: || (optype0 != REGOP && optype1 == REGOP 234: && (REGNO (operands[1]) & 1) == 0)) 235: { 236: rtx op1, op2; 237: rtx base = 0, offset = const0_rtx; 1.1 root 238: 1.1.1.3 root 239: if (optype0 == REGOP) 240: op1 = operands[0], op2 = XEXP (operands[1], 0); 241: else 242: op1 = operands[1], op2 = XEXP (operands[0], 0); 243: 1.1.1.4 ! root 244: /* Trust global variables. */ 1.1.1.3 root 245: if (GET_CODE (op2) == SYMBOL_REF 246: || GET_CODE (op2) == CONST 247: || GET_CODE (op2) == REG) 1.1.1.4 ! root 248: { ! 249: if (op1 == operands[0]) ! 250: return "ldd %1,%0"; ! 251: else ! 252: return "std %1,%0"; ! 253: } 1.1.1.3 root 254: 1.1.1.4 ! root 255: if (GET_CODE (op2) == PLUS) ! 256: { ! 257: if (GET_CODE (XEXP (op2, 0)) == REG) ! 258: base = XEXP (op2, 0), offset = XEXP (op2, 1); ! 259: else if (GET_CODE (XEXP (op2, 1)) == REG) ! 260: base = XEXP (op2, 1), offset = XEXP (op2, 0); ! 261: } ! 262: ! 263: /* Trust round enough offsets from the stack or frame pointer. */ 1.1.1.3 root 264: if (base 1.1.1.4 ! root 265: && (REGNO (base) == FRAME_POINTER_REGNUM ! 266: || REGNO (base) == STACK_POINTER_REGNUM)) ! 267: { ! 268: if (GET_CODE (offset) == CONST_INT ! 269: && (INTVAL (offset) & 0x7) == 0) ! 270: { ! 271: if (op1 == operands[0]) ! 272: return "ldd %1,%0"; ! 273: else ! 274: return "std %1,%0"; ! 275: } ! 276: } ! 277: else ! 278: { ! 279: /* We know structs not on the stack are properly aligned. */ ! 280: if (operands[1]->in_struct) ! 281: return "ldd %1,%0"; ! 282: else if (operands[0]->in_struct) ! 283: return "std %1,%0"; ! 284: } 1.1.1.3 root 285: } 1.1.1.4 ! root 286: 1.1 root 287: if (optype0 == REGOP && optype1 == REGOP 288: && REGNO (operands[0]) == REGNO (latehalf[1])) 289: { 290: /* Make any unoffsetable addresses point at high-numbered word. */ 291: if (addreg0) 292: output_asm_insn ("add %0,0x4,%0", &addreg0); 293: if (addreg1) 294: output_asm_insn ("add %0,0x4,%0", &addreg1); 295: 296: /* Do that word. */ 297: output_asm_insn (singlemove_string (latehalf), latehalf); 298: 299: /* Undo the adds we just did. */ 300: if (addreg0) 301: output_asm_insn ("add %0,-0x4,%0", &addreg0); 302: if (addreg1) 303: output_asm_insn ("add %0,-0x4,%0", &addreg0); 304: 305: /* Do low-numbered word. */ 306: return singlemove_string (operands); 307: } 1.1.1.3 root 308: else if (optype0 == REGOP && optype1 != REGOP 309: && reg_mentioned_p (operands[0], XEXP (operands[1], 0))) 310: { 311: /* Do the late half first. */ 312: output_asm_insn (singlemove_string (latehalf), latehalf); 313: /* Then clobber. */ 314: return singlemove_string (operands); 315: } 1.1 root 316: 317: /* Normal case: do the two words, low-numbered first. */ 318: 319: output_asm_insn (singlemove_string (operands), operands); 320: 321: /* Make any unoffsetable addresses point at high-numbered word. */ 322: if (addreg0) 323: output_asm_insn ("add %0,0x4,%0", &addreg0); 324: if (addreg1) 325: output_asm_insn ("add %0,0x4,%0", &addreg1); 326: 327: /* Do that word. */ 328: output_asm_insn (singlemove_string (latehalf), latehalf); 329: 330: /* Undo the adds we just did. */ 331: if (addreg0) 332: output_asm_insn ("add %0,-0x4,%0", &addreg0); 333: if (addreg1) 334: output_asm_insn ("add %0,-0x4,%0", &addreg1); 335: 336: return ""; 337: } 338: 339: static char * 340: output_fp_move_double (operands) 341: rtx *operands; 342: { 343: if (FP_REG_P (operands[0])) 344: { 345: if (FP_REG_P (operands[1])) 346: { 347: output_asm_insn ("fmovs %1,%0", operands); 348: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); 349: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); 350: return "fmovs %1,%0"; 351: } 352: if (GET_CODE (operands[1]) == REG) 353: { 1.1.1.3 root 354: if ((REGNO (operands[1]) & 1) == 0) 355: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; 356: else 357: { 358: rtx xoperands[3]; 359: xoperands[0] = operands[0]; 360: xoperands[1] = operands[1]; 361: xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); 362: output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands); 363: return ""; 364: } 1.1 root 365: } 1.1.1.4 ! root 366: if (GET_CODE (XEXP (operands[1], 0)) == PLUS ! 367: && (XEXP (XEXP (operands[1], 0), 0) == frame_pointer_rtx ! 368: || XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx) ! 369: && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT ! 370: && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x7) != 0) ! 371: { ! 372: rtx xoperands[2]; ! 373: output_asm_insn ("ld %1,%0", operands); ! 374: xoperands[0] = gen_rtx (REG, GET_MODE (operands[0]), ! 375: REGNO (operands[0]) + 1); ! 376: xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]), ! 377: plus_constant (XEXP (operands[1], 0), 4)); ! 378: output_asm_insn ("ld %1,%0", xoperands); ! 379: return ""; ! 380: } 1.1 root 381: return "ldd %1,%0"; 382: } 383: else if (FP_REG_P (operands[1])) 384: { 385: if (GET_CODE (operands[0]) == REG) 386: { 1.1.1.3 root 387: if ((REGNO (operands[0]) & 1) == 0) 388: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; 389: else 390: { 391: rtx xoperands[3]; 392: xoperands[2] = operands[1]; 393: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); 394: xoperands[0] = operands[0]; 395: output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands); 396: return ""; 397: } 1.1 root 398: } 1.1.1.4 ! root 399: if (GET_CODE (XEXP (operands[0], 0)) == PLUS ! 400: && (XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx ! 401: || XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx) ! 402: && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT ! 403: && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) != 0) ! 404: { ! 405: rtx xoperands[2]; ! 406: output_asm_insn ("st %1,%0", operands); ! 407: xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]), ! 408: REGNO (operands[1]) + 1); ! 409: xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]), ! 410: plus_constant (XEXP (operands[0], 0), 4)); ! 411: output_asm_insn ("st %1,%0", xoperands); ! 412: return ""; ! 413: } 1.1 root 414: return "std %1,%0"; 415: } 1.1.1.3 root 416: else abort (); 1.1 root 417: } 418: 419: /* Return a REG that occurs in ADDR with coefficient 1. 420: ADDR can be effectively incremented by incrementing REG. */ 421: 422: static rtx 423: find_addr_reg (addr) 424: rtx addr; 425: { 426: while (GET_CODE (addr) == PLUS) 427: { 428: if (GET_CODE (XEXP (addr, 0)) == REG) 429: addr = XEXP (addr, 0); 430: if (GET_CODE (XEXP (addr, 1)) == REG) 431: addr = XEXP (addr, 1); 432: if (CONSTANT_P (XEXP (addr, 0))) 433: addr = XEXP (addr, 1); 434: if (CONSTANT_P (XEXP (addr, 1))) 435: addr = XEXP (addr, 0); 436: } 437: if (GET_CODE (addr) == REG) 438: return addr; 439: return 0; 440: } 441: 442: /* Load the address specified by OPERANDS[3] into the register 443: specified by OPERANDS[0]. 444: 445: OPERANDS[3] may be the result of a sum, hence it could either be: 446: 447: (1) CONST 448: (2) REG 449: (2) REG + CONST_INT 450: (3) REG + REG + CONST_INT 451: 452: All cases are handled here. */ 453: 454: void 455: output_load_address (operands) 456: rtx *operands; 457: { 458: rtx base, offset; 459: 460: if (CONSTANT_P (operands[3])) 461: { 462: output_asm_insn ("set %3,%0", operands); 463: return; 464: } 465: 466: if (REG_P (operands[3])) 467: { 468: if (REGNO (operands[0]) != REGNO (operands[3])) 469: output_asm_insn ("mov %3,%0", operands); 470: return; 471: } 472: 473: base = XEXP (operands[3], 0); 474: offset = XEXP (operands[3], 1); 475: 476: if (GET_CODE (base) == CONST_INT) 477: { 478: rtx tmp = base; 479: base = offset; 480: offset = tmp; 481: } 482: 483: if (GET_CODE (offset) != CONST_INT) 484: abort (); 485: 486: if (REG_P (base)) 487: { 488: operands[6] = base; 489: operands[7] = offset; 490: if (SMALL_INT (offset)) 491: output_asm_insn ("add %6,%7,%0", operands); 492: else 493: output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands); 494: } 495: else 496: { 497: operands[6] = XEXP (base, 0); 498: operands[7] = XEXP (base, 1); 499: operands[8] = offset; 500: 501: if (SMALL_INT (offset)) 502: output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands); 503: else 504: output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands); 505: } 506: } 507: 508: char * 509: output_block_move (operands) 510: rtx *operands; 511: { 512: static int movstrsi_label = 0; 513: int align = 4; 514: 515: rtx xoperands[9]; 516: int available[3]; 517: int i, j; 518: 519: /* Since we clobber untold things, nix the condition codes. */ 520: CC_STATUS_INIT; 521: 522: /* Get past the MEMs. */ 523: operands[0] = XEXP (operands[0], 0); 524: operands[1] = XEXP (operands[1], 0); 525: 526: xoperands[0] = 0; 527: xoperands[1] = 0; 528: xoperands[2] = 0; 529: 530: available[0] = 1; 531: available[1] = 1; 532: available[2] = 1; 533: #if 1 534: /* Prepare to juggle registers if necessary. */ 535: if (REG_P (operands[0]) && (unsigned) (REGNO (operands[0]) - 8) < 3) 536: { 537: xoperands[0] = operands[0]; 538: available[REGNO (operands[0]) - 8] = 0; 539: } 540: if (REG_P (operands[1]) && (unsigned) (REGNO (operands[1]) - 8) < 3) 541: { 542: xoperands[1] = operands[1]; 543: available[REGNO (operands[1]) - 8] = 0; 544: } 545: if (REG_P (operands[2]) && (unsigned) (REGNO (operands[2]) - 8) < 3) 546: { 547: xoperands[2] = operands[2]; 548: available[REGNO (operands[2]) - 8] = 0; 549: } 550: for (i = 0; i < 3; i++) 551: { 552: if (xoperands[i]) 553: continue; 554: if (available[0]) 555: { 556: xoperands[i] = gen_rtx (REG, SImode, 8); 557: available[0] = 0; 558: continue; 559: } 560: if (available[1]) 561: { 562: xoperands[i] = gen_rtx (REG, SImode, 9); 563: available[1] = 0; 564: continue; 565: } 566: xoperands[i] = gen_rtx (REG, SImode, 10); 567: available[2] = 0; 568: } 569: #endif 570: 571: /* First, figure out best alignment we may assume. */ 572: if (REG_P (operands[2])) 573: { 574: xoperands[5] = operands[2]; 575: output_asm_insn ("sub %5,0x1,%2", xoperands); 576: align = 1; 577: } 578: else 579: { 580: int i = INTVAL (operands[2]); 581: 582: if (i & 1) 583: align = 1; 584: else if (i & 3) 585: align = 2; 586: 587: /* predecrement count. */ 588: i -= align; 589: if (i < 0) abort (); 590: 591: xoperands[5] = gen_rtx (CONST_INT, VOIDmode, i); 592: 593: output_asm_insn ("set %5,%2", xoperands); 594: } 595: 596: /* Now, set up for pipelined operation: dest must contain 597: a pre-incremented address, because its index is pre-decremented. */ 598: 599: xoperands[3] = plus_constant (operands[0], align); 600: output_load_address (xoperands); 601: 602: xoperands[4] = operands[1]; 603: output_load_address (xoperands+1); 604: 605: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); 606: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align); 607: 1.1.1.4 ! root 608: output_asm_insn ("\nLm%3:\n\tld [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tst %%g1,[%0+%2]", xoperands); 1.1 root 609: return ""; 610: } 611: 612: #define ABS(x) ((x) < 0 ? -(x) : x) 613: 614: char * 615: output_mul_by_constant (insn, operands, unsignedp) 616: rtx insn; 617: rtx *operands; 618: int unsignedp; 619: { 620: int c; /* Size of constant */ 621: int shifts[BITS_PER_WORD]; /* Table of shifts */ 1.1.1.4 ! root 622: unsigned int p, log; /* A power of two, and its log */ 1.1 root 623: int d1, d2; /* Differences of c and p */ 624: int first = 1; /* True if dst has unknown data in it */ 625: int i; 626: 627: c = INTVAL (operands[2]); 628: if (c == 0) 629: { 630: /* should not happen. */ 631: abort (); 632: if (GET_CODE (operands[0]) == MEM) 633: return "st %%g0,%0"; 634: return "mov %%g0,%0"; 635: } 636: 637: #if 0 638: printf ("open coding insn:\n"); 639: debug_rtx (insn); 640: printf ("done.\n"); 641: #endif 642: 643: output_asm_insn ("! start open coded multiply"); 644: 645: /* Clear out the table of shifts. */ 646: for (i = 0; i < BITS_PER_WORD; ++i) 647: shifts[i] = 0; 648: 649: while (c) 650: { 651: /* Find the power of two nearest ABS(c) */ 652: p = 1, log = 0; 653: do 654: { 655: d1 = ABS(c) - p; 656: p *= 2; 657: ++log; 658: } 659: while (p < ABS(c)); 660: d2 = p - ABS(c); 661: 662: /* Make an appropriate entry in shifts for p. */ 663: if (d2 < d1) 664: { 665: shifts[log] = c < 0 ? -1 : 1; 666: c = c < 0 ? d2 : -d2; 667: } 668: else 669: { 670: shifts[log - 1] = c < 0 ? -1 : 1; 671: c = c < 0 ? -d1 : d1; 672: } 673: } 674: 675: /* For now, use a known clobberable register. This could 676: be improved by looking at insn, and seeing if we 677: have a dying register contained therein. */ 678: regs_ever_live[15] = 1; 679: operands[3] = gen_rtx (REG, SImode, 15); 680: 681: /* Take care of the first insn in sequence. 682: We know we have at least one. */ 683: 684: /* A value of -1 in shifts says to subtract that power of two, and a value 685: of 1 says to add that power of two. */ 686: for (i = 0; ; i++) 687: if (shifts[i]) 688: { 689: if (i) 690: { 691: operands[2] = gen_rtx (CONST_INT, VOIDmode, i); 692: output_asm_insn ("sll %1,%2,%3", operands); 693: } 694: else if (REGNO (operands[3]) == 15) 695: output_asm_insn ("mov %1,%3", operands); 696: 697: log = i; 698: if (shifts[i] < 0) 699: output_asm_insn ("sub %%g0,%3,%0", operands); 700: else 701: output_asm_insn ("mov %3,%0", operands); 702: break; 703: } 704: 705: /* A value of -1 in shifts says to subtract that power of two, and a value 706: of 1 says to add that power of two--continued. */ 707: for (i += 1; i < BITS_PER_WORD; ++i) 708: if (shifts[i]) 709: { 710: if (i - log > 0) 711: { 712: operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log); 713: output_asm_insn ("sll %3,%2,%3", operands); 714: } 715: else 716: { 717: operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i); 718: output_asm_insn ("sra %3,%2,%3", operands); 719: } 720: log = i; 721: if (shifts[i] < 0) 722: output_asm_insn ("sub %0,%3,%0", operands); 723: else 724: output_asm_insn ("add %0,%3,%0", operands); 725: } 726: 727: output_asm_insn ("! end open coded multiply"); 728: 729: return ""; 730: } 731: 732: char * 733: output_mul_insn (operands, unsignedp) 734: rtx *operands; 735: int unsignedp; 736: { 737: int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1; 738: int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1; 739: 740: if (lucky1) 741: if (lucky2) 742: output_asm_insn ("call .mul,2\n\tnop", operands); 743: else 744: { 745: rtx xoperands[2]; 746: xoperands[0] = gen_rtx (REG, SImode, 747: 8 ^ (REGNO (operands[1]) == 8)); 748: xoperands[1] = operands[2]; 749: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); 750: } 751: else if (lucky2) 752: { 753: rtx xoperands[2]; 754: xoperands[0] = gen_rtx (REG, SImode, 755: 8 ^ (REGNO (operands[2]) == 8)); 756: xoperands[1] = operands[1]; 757: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); 758: } 759: else 760: { 761: output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1", 762: operands); 763: } 764: 765: if (REGNO (operands[0]) == 8) 766: return ""; 767: return "mov %%o0,%0"; 768: } 769: 770: #if 0 771: /* This function does not properly protect its operands. */ 772: char * 773: output_arith_insn (operands, name) 774: rtx *operands; 775: char *name; 776: { 777: extern struct _iobuf *asm_out_file; 778: 779: /* Does not commute. */ 780: rtx op1 = 0; 781: rtx op2 = 0; 782: 783: abort (); 784: if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 8) 785: op1 = operands[1]; 786: if (GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 8) 787: op2 = operands[2]; 788: 789: if (op1 && op2) 790: { 791: /* ?? should have been done earlier. */ 792: abort (); 793: } 794: else 795: { 796: if (op2) 797: { 798: op1 = operands[1]; 799: if (REG_P (op1) && REGNO (op1) == 9) 800: { 801: output_asm_insn ("mov %%o1,%%o2\n\tmov %%o0,%%o1", operands); 802: fprintf (asm_out_file, "\tcall %s,2\n", name); 803: output_asm_insn ("mov %%o2,%%o0", operands); 804: goto done; 805: } 806: output_asm_insn ("mov %%o0,%%o1", operands); 807: if (GET_CODE (op1) == CONST_INT && ! SMALL_INT (op1)) 808: { 809: output_asm_insn ("sethi %%hi(%1),%%o0", operands); 810: fprintf (asm_out_file, "\tcall %s,2\n", name); 811: output_asm_insn ("add %%o0,%%lo(%1),%%o0", operands); 812: } 813: else 814: { 815: fprintf (asm_out_file, "\tcall %s,2\n", name); 816: if (GET_CODE (op1) == MEM) 817: output_asm_insn ("ld %1,%%o0", operands); 818: else 819: output_asm_insn ("mov %1,%%o0", operands); 820: } 821: } 822: else if (op1) 823: { 824: op2 = operands[2]; 825: if (REG_P (op2) && REGNO (operands[1]) == 9) 826: { 827: fprintf (asm_out_file, "\tcall %s,2\n\tnop\n"); 828: goto done; 829: } 830: if (GET_CODE (op2) == CONST_INT && ! SMALL_INT (op2)) 831: { 832: output_asm_insn ("sethi %%hi(%2),%%o1", operands); 833: fprintf (asm_out_file, "\tcall %s,2\n", name); 834: output_asm_insn ("add %%o1,%%lo(%2),%%o1", operands); 835: } 836: else 837: { 838: fprintf (asm_out_file, "\tcall %s,2\n", name); 839: if (GET_CODE (op2) == MEM) 840: output_asm_insn ("ld %2,%%o1", operands); 841: else 842: output_asm_insn ("mov %2,%%o1", operands); 843: } 844: } 845: else 846: { 847: op1 = operands[1]; 848: op2 = operands[2]; 849: 850: if (! REG_P (op2) || REGNO (op2) != 9) 851: if (GET_CODE (op2) == MEM) 852: output_asm_insn ("ld %2,%%o1", operands); 853: else if (GET_CODE (op2) != CONST_INT || SMALL_INT (op2)) 854: output_asm_insn ("mov %2,%%o1", operands); 855: else 856: output_asm_insn ("sethi %%hi(%2),%%o1\n\tadd %%o1,%%lo(%2),%%o1", operands); 857: if (GET_CODE (op1) == CONST_INT && ! SMALL_INT (op1)) 858: { 859: output_asm_insn ("sethi %%hi(%1),%%o0", operands); 860: fprintf (asm_out_file, "\tcall %s,2\n", name); 861: output_asm_insn ("add %%o0,%%lo(%1),%%o0", operands); 862: } 863: else 864: { 865: fprintf (asm_out_file, "\tcall %s,2\n", name); 866: if (GET_CODE (op1) == MEM) 867: output_asm_insn ("ld %1,%%o0", operands); 868: else 869: output_asm_insn ("mov %1,%%o0", operands); 870: } 871: } 872: done: 873: if (REG_P (operands[0]) && REGNO (operands[0]) == 8) 874: return ""; 875: if (GET_CODE (operands[0]) == MEM) 876: return "st %%o0,%0"; 877: return "mov %%o0,%0"; 878: } 879: } 880: #endif 881: 882: /* Make floating point register f0 contain 0. 883: SIZE is the number of registers (including f0) 884: which should contain 0. */ 885: 886: void 887: make_f0_contain_0 (size) 888: int size; 889: { 890: if (size == 1) 1.1.1.3 root 891: output_asm_insn ("ld [%%fp-16],%%f0", 0); 1.1 root 892: else if (size == 2) 1.1.1.3 root 893: output_asm_insn ("ldd [%%fp-16],%%f0", 0); 1.1 root 894: } 1.1.1.4 ! root 895: ! 896: /* Output reasonable peephole for set-on-condition-code insns. ! 897: Note that these insns assume a particular way of defining ! 898: labels. Therefore, *both* tm-sparc.h and this function must ! 899: be changed if a new syntax is needed. */ ! 900: ! 901: char * ! 902: output_scc_insn (code, operands) ! 903: enum rtx_code code; ! 904: rtx *operands; ! 905: { ! 906: rtx xoperands[2]; ! 907: rtx label = gen_label_rtx (); ! 908: ! 909: xoperands[0] = operands[0]; ! 910: xoperands[1] = label; ! 911: ! 912: switch (code) ! 913: { ! 914: case NE: ! 915: if (cc_status.flags & CC_IN_FCCR) ! 916: output_asm_insn ("fbne,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 917: else ! 918: output_asm_insn ("bne,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 919: break; ! 920: case EQ: ! 921: if (cc_status.flags & CC_IN_FCCR) ! 922: output_asm_insn ("fbe,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 923: else ! 924: output_asm_insn ("be,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 925: break; ! 926: case GE: ! 927: if (cc_status.flags & CC_IN_FCCR) ! 928: output_asm_insn ("fbge,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 929: else ! 930: output_asm_insn ("bge,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 931: break; ! 932: case GT: ! 933: if (cc_status.flags & CC_IN_FCCR) ! 934: output_asm_insn ("fbg,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 935: else ! 936: output_asm_insn ("bg,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 937: break; ! 938: case LE: ! 939: if (cc_status.flags & CC_IN_FCCR) ! 940: output_asm_insn ("fble,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 941: else ! 942: output_asm_insn ("ble,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 943: break; ! 944: case LT: ! 945: if (cc_status.flags & CC_IN_FCCR) ! 946: output_asm_insn ("fbl,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 947: else ! 948: output_asm_insn ("bl,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 949: break; ! 950: case GEU: ! 951: if (cc_status.flags & CC_IN_FCCR) ! 952: abort (); ! 953: else ! 954: output_asm_insn ("bgeu,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 955: break; ! 956: case GTU: ! 957: if (cc_status.flags & CC_IN_FCCR) ! 958: abort (); ! 959: else ! 960: output_asm_insn ("bgu,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 961: break; ! 962: case LEU: ! 963: if (cc_status.flags & CC_IN_FCCR) ! 964: abort (); ! 965: else ! 966: output_asm_insn ("bleu,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 967: break; ! 968: case LTU: ! 969: if (cc_status.flags & CC_IN_FCCR) ! 970: abort (); ! 971: else ! 972: output_asm_insn ("blu,a %l1\n\tmov 1,%0\n\tmov 0,%0\n%l1:", xoperands); ! 973: break; ! 974: default: ! 975: abort (); ! 976: } ! 977: return ""; ! 978: } ! 979: ! 980: /* ??? Comment needed here */ ! 981: ! 982: char * ! 983: output_delay_insn (template, operands, insn) ! 984: char *template; ! 985: rtx *operands; ! 986: rtx insn; ! 987: { ! 988: extern char *insn_template[]; ! 989: extern char *(*insn_outfun[])(); ! 990: rtx pat = gen_rtx (SET, VOIDmode, ! 991: XVECEXP (PATTERN (insn), 0, 0), ! 992: XVECEXP (PATTERN (insn), 0, 1)); ! 993: rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); ! 994: int insn_code_number; ! 995: ! 996: /* Output the branch instruction first. */ ! 997: output_asm_insn (template, operands); ! 998: ! 999: /* Now recognize the insn which we put in its delay slot. ! 1000: We must do this after outputing the branch insn, ! 1001: since operands may just be a pointer to `recog_operands'. */ ! 1002: insn_code_number = recog (pat, delay_insn); ! 1003: if (insn_code_number == -1) ! 1004: abort (); ! 1005: ! 1006: /* Now get the template for what this insn would ! 1007: have been, without the branch. Its operands are ! 1008: exactly the same as they would be, so we don't ! 1009: need to do an insn_extract. */ ! 1010: template = insn_template[insn_code_number]; ! 1011: if (template == 0) ! 1012: template = (*insn_outfun[insn_code_number]) (operands, delay_insn); ! 1013: output_asm_insn (template, operands); ! 1014: return ""; ! 1015: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.