|
|
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.7 ! root 31: /* Return non-zero only if OP is a hard register of mode MODE. */ ! 32: ! 33: static int ! 34: hardreg (op, mode) ! 35: rtx op; ! 36: enum machine_mode mode; ! 37: { ! 38: return (REG_P (op) && GET_MODE (op) == mode ! 39: && REGNO (op) < FIRST_PSEUDO_REGISTER); ! 40: } ! 41: 1.1.1.4 root 42: /* Return non-zero if this pattern, as a source to a "SET", 43: is known to yield an instruction of unit size. */ 44: int 45: single_insn_src_p (op, mode) 46: rtx op; 47: enum machine_mode mode; 1.1 root 48: { 1.1.1.4 root 49: switch (GET_CODE (op)) 50: { 51: case CONST_INT: 52: if (SMALL_INT (op)) 53: return 1; 54: return 0; 55: 56: case REG: 1.1.1.7 ! root 57: return 1; ! 58: 1.1.1.4 root 59: case MEM: 1.1.1.7 ! root 60: if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF) ! 61: return 0; 1.1.1.4 root 62: return 1; 63: 64: /* We never need to negate or complement constants. */ 65: case NOT: 66: case NEG: 67: return 1; 68: 69: case PLUS: 70: case MINUS: 71: case AND: 72: case IOR: 73: case XOR: 74: case LSHIFT: 75: case ASHIFT: 76: case ASHIFTRT: 77: case LSHIFTRT: 78: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) 79: || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) 80: return 0; 81: return 1; 82: 83: case SUBREG: 84: if (SUBREG_WORD (op) != 0) 85: return 0; 86: return single_insn_src_p (SUBREG_REG (op), mode); 87: 88: case SIGN_EXTEND: 89: case ZERO_EXTEND: 90: /* Lazy... could check for these. */ 91: return 0; 92: 93: /* Not doing floating point, since they probably 94: take longer than the branch slot they might fill. */ 95: case FLOAT_EXTEND: 96: case FLOAT_TRUNCATE: 97: case FLOAT: 98: case FIX: 99: case UNSIGNED_FLOAT: 100: case UNSIGNED_FIX: 101: return 0; 102: 103: default: 104: return 0; 105: } 1.1 root 106: } 1.1.1.4 root 107: 1.1.1.5 root 108: /* Return truth value of whether OP can be used as an operands in a three 109: address arithmetic insn (such as add %o1,7,%l2) of mode MODE. */ 1.1 root 110: 111: int 112: arith_operand (op, mode) 113: rtx op; 114: enum machine_mode mode; 115: { 116: return (register_operand (op, mode) 117: || (GET_CODE (op) == CONST_INT && SMALL_INT (op))); 118: } 119: 1.1.1.5 root 120: /* Return truth value of whether OP can be used as an operand in a two 121: address arithmetic insn (such as set 123456,%o4) of mode MODE. */ 1.1.1.4 root 122: 1.1 root 123: int 124: arith32_operand (op, mode) 125: rtx op; 126: enum machine_mode mode; 127: { 128: return (register_operand (op, mode) || GET_CODE (op) == CONST_INT); 129: } 130: 1.1.1.5 root 131: /* Return truth value of whether OP is a integer which fits the 132: range constraining immediate operands in three-address insns. */ 133: 1.1.1.3 root 134: int 135: small_int (op, mode) 136: rtx op; 137: enum machine_mode mode; 138: { 139: return (GET_CODE (op) == CONST_INT && SMALL_INT (op)); 140: } 141: 1.1 root 142: /* Return the best assembler insn template 143: for moving operands[1] into operands[0] as a fullword. */ 144: 145: static char * 146: singlemove_string (operands) 147: rtx *operands; 148: { 149: if (GET_CODE (operands[0]) == MEM) 150: return "st %r1,%0"; 151: if (GET_CODE (operands[1]) == MEM) 152: return "ld %1,%0"; 1.1.1.3 root 153: return "mov %1,%0"; 1.1 root 154: } 155: 156: /* Output assembler code to perform a doubleword move insn 157: with operands OPERANDS. */ 158: 159: char * 160: output_move_double (operands) 161: rtx *operands; 162: { 163: enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; 164: rtx latehalf[2]; 165: rtx addreg0 = 0, addreg1 = 0; 166: 167: /* First classify both operands. */ 168: 169: if (REG_P (operands[0])) 170: optype0 = REGOP; 171: else if (offsetable_memref_p (operands[0])) 172: optype0 = OFFSOP; 173: else if (GET_CODE (operands[0]) == MEM) 174: optype0 = MEMOP; 175: else 176: optype0 = RNDOP; 177: 178: if (REG_P (operands[1])) 179: optype1 = REGOP; 180: else if (CONSTANT_P (operands[1]) 181: || GET_CODE (operands[1]) == CONST_DOUBLE) 182: optype1 = CNSTOP; 183: else if (offsetable_memref_p (operands[1])) 184: optype1 = OFFSOP; 185: else if (GET_CODE (operands[1]) == MEM) 1.1.1.7 ! root 186: optype1 = MEMOP; 1.1 root 187: else 188: optype1 = RNDOP; 189: 190: /* Check for the cases that the operand constraints are not 191: supposed to allow to happen. Abort if we get one, 192: because generating code for these cases is painful. */ 193: 194: if (optype0 == RNDOP || optype1 == RNDOP) 195: abort (); 196: 197: /* If an operand is an unoffsettable memory ref, find a register 198: we can increment temporarily to make it refer to the second word. */ 199: 200: if (optype0 == MEMOP) 201: addreg0 = find_addr_reg (operands[0]); 202: 203: if (optype1 == MEMOP) 204: addreg1 = find_addr_reg (operands[1]); 205: 206: /* Ok, we can do one word at a time. 207: Normally we do the low-numbered word first, 208: but if either operand is autodecrementing then we 209: do the high-numbered word first. 210: 211: In either case, set up in LATEHALF the operands to use 212: for the high-numbered word and in some cases alter the 213: operands in OPERANDS to be suitable for the low-numbered word. */ 214: 215: if (optype0 == REGOP) 216: latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); 217: else if (optype0 == OFFSOP) 218: latehalf[0] = adj_offsetable_operand (operands[0], 4); 219: else 220: latehalf[0] = operands[0]; 221: 222: if (optype1 == REGOP) 223: latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); 224: else if (optype1 == OFFSOP) 225: latehalf[1] = adj_offsetable_operand (operands[1], 4); 226: else if (optype1 == CNSTOP) 227: { 228: if (CONSTANT_P (operands[1])) 229: latehalf[1] = const0_rtx; 230: else if (GET_CODE (operands[1]) == CONST_DOUBLE) 231: { 232: latehalf[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 1)); 233: operands[1] = gen_rtx (CONST_INT, VOIDmode, XINT (operands[1], 0)); 234: } 235: } 236: else 237: latehalf[1] = operands[1]; 238: 239: /* If the first move would clobber the source of the second one, 1.1.1.3 root 240: do them in the other order. 241: 242: RMS says "This happens only for registers; 1.1 root 243: such overlap can't happen in memory unless the user explicitly 1.1.1.3 root 244: sets it up, and that is an undefined circumstance." 245: 246: but it happens on the sparc when loading parameter registers, 247: so I am going to define that circumstance, and make it work 248: as expected. */ 249: 250: /* Easy case: try moving both words at once. */ 251: if ((optype0 == REGOP && optype1 != REGOP 252: && (REGNO (operands[0]) & 1) == 0) 253: || (optype0 != REGOP && optype1 == REGOP 254: && (REGNO (operands[1]) & 1) == 0)) 255: { 256: rtx op1, op2; 257: rtx base = 0, offset = const0_rtx; 1.1 root 258: 1.1.1.3 root 259: if (optype0 == REGOP) 260: op1 = operands[0], op2 = XEXP (operands[1], 0); 261: else 262: op1 = operands[1], op2 = XEXP (operands[0], 0); 263: 1.1.1.4 root 264: /* Trust global variables. */ 1.1.1.3 root 265: if (GET_CODE (op2) == SYMBOL_REF 266: || GET_CODE (op2) == CONST 267: || GET_CODE (op2) == REG) 1.1.1.4 root 268: { 269: if (op1 == operands[0]) 270: return "ldd %1,%0"; 271: else 272: return "std %1,%0"; 273: } 1.1.1.3 root 274: 1.1.1.4 root 275: if (GET_CODE (op2) == PLUS) 276: { 277: if (GET_CODE (XEXP (op2, 0)) == REG) 278: base = XEXP (op2, 0), offset = XEXP (op2, 1); 279: else if (GET_CODE (XEXP (op2, 1)) == REG) 280: base = XEXP (op2, 1), offset = XEXP (op2, 0); 281: } 282: 283: /* Trust round enough offsets from the stack or frame pointer. */ 1.1.1.3 root 284: if (base 1.1.1.4 root 285: && (REGNO (base) == FRAME_POINTER_REGNUM 286: || REGNO (base) == STACK_POINTER_REGNUM)) 287: { 288: if (GET_CODE (offset) == CONST_INT 289: && (INTVAL (offset) & 0x7) == 0) 290: { 291: if (op1 == operands[0]) 292: return "ldd %1,%0"; 293: else 294: return "std %1,%0"; 295: } 296: } 297: else 298: { 299: /* We know structs not on the stack are properly aligned. */ 1.1.1.6 root 300: if (MEM_IN_STRUCT_P (operands[1])) 1.1.1.4 root 301: return "ldd %1,%0"; 1.1.1.6 root 302: else if (MEM_IN_STRUCT_P (operands[0])) 1.1.1.4 root 303: return "std %1,%0"; 304: } 1.1.1.3 root 305: } 1.1.1.4 root 306: 1.1 root 307: if (optype0 == REGOP && optype1 == REGOP 308: && REGNO (operands[0]) == REGNO (latehalf[1])) 309: { 310: /* Make any unoffsetable addresses point at high-numbered word. */ 311: if (addreg0) 312: output_asm_insn ("add %0,0x4,%0", &addreg0); 313: if (addreg1) 314: output_asm_insn ("add %0,0x4,%0", &addreg1); 315: 316: /* Do that word. */ 317: output_asm_insn (singlemove_string (latehalf), latehalf); 318: 319: /* Undo the adds we just did. */ 320: if (addreg0) 321: output_asm_insn ("add %0,-0x4,%0", &addreg0); 322: if (addreg1) 323: output_asm_insn ("add %0,-0x4,%0", &addreg0); 324: 325: /* Do low-numbered word. */ 326: return singlemove_string (operands); 327: } 1.1.1.3 root 328: else if (optype0 == REGOP && optype1 != REGOP 1.1.1.6 root 329: && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0))) 1.1.1.3 root 330: { 331: /* Do the late half first. */ 332: output_asm_insn (singlemove_string (latehalf), latehalf); 333: /* Then clobber. */ 334: return singlemove_string (operands); 335: } 1.1 root 336: 337: /* Normal case: do the two words, low-numbered first. */ 338: 339: output_asm_insn (singlemove_string (operands), operands); 340: 341: /* Make any unoffsetable addresses point at high-numbered word. */ 342: if (addreg0) 343: output_asm_insn ("add %0,0x4,%0", &addreg0); 344: if (addreg1) 345: output_asm_insn ("add %0,0x4,%0", &addreg1); 346: 347: /* Do that word. */ 348: output_asm_insn (singlemove_string (latehalf), latehalf); 349: 350: /* Undo the adds we just did. */ 351: if (addreg0) 352: output_asm_insn ("add %0,-0x4,%0", &addreg0); 353: if (addreg1) 354: output_asm_insn ("add %0,-0x4,%0", &addreg1); 355: 356: return ""; 357: } 358: 359: static char * 360: output_fp_move_double (operands) 361: rtx *operands; 362: { 363: if (FP_REG_P (operands[0])) 364: { 365: if (FP_REG_P (operands[1])) 366: { 367: output_asm_insn ("fmovs %1,%0", operands); 368: operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); 369: operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); 370: return "fmovs %1,%0"; 371: } 372: if (GET_CODE (operands[1]) == REG) 373: { 1.1.1.3 root 374: if ((REGNO (operands[1]) & 1) == 0) 375: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; 376: else 377: { 378: rtx xoperands[3]; 379: xoperands[0] = operands[0]; 380: xoperands[1] = operands[1]; 381: xoperands[2] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); 382: output_asm_insn ("st %2,[%%fp-4]\n\tst %1,[%%fp-8]\n\tldd [%%fp-8],%0", xoperands); 383: return ""; 384: } 1.1 root 385: } 1.1.1.4 root 386: if (GET_CODE (XEXP (operands[1], 0)) == PLUS 387: && (XEXP (XEXP (operands[1], 0), 0) == frame_pointer_rtx 388: || XEXP (XEXP (operands[1], 0), 0) == stack_pointer_rtx) 389: && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT 390: && (INTVAL (XEXP (XEXP (operands[1], 0), 1)) & 0x7) != 0) 391: { 392: rtx xoperands[2]; 393: output_asm_insn ("ld %1,%0", operands); 394: xoperands[0] = gen_rtx (REG, GET_MODE (operands[0]), 395: REGNO (operands[0]) + 1); 396: xoperands[1] = gen_rtx (MEM, GET_MODE (operands[1]), 397: plus_constant (XEXP (operands[1], 0), 4)); 398: output_asm_insn ("ld %1,%0", xoperands); 399: return ""; 400: } 1.1 root 401: return "ldd %1,%0"; 402: } 403: else if (FP_REG_P (operands[1])) 404: { 405: if (GET_CODE (operands[0]) == REG) 406: { 1.1.1.3 root 407: if ((REGNO (operands[0]) & 1) == 0) 408: return "std %1,[%%fp-8]\n\tldd [%%fp-8],%0"; 409: else 410: { 411: rtx xoperands[3]; 412: xoperands[2] = operands[1]; 413: xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); 414: xoperands[0] = operands[0]; 415: output_asm_insn ("std %2,[%%fp-8]\n\tld [%%fp-4],%1\n\tld [%%fp-8],%0", xoperands); 416: return ""; 417: } 1.1 root 418: } 1.1.1.4 root 419: if (GET_CODE (XEXP (operands[0], 0)) == PLUS 420: && (XEXP (XEXP (operands[0], 0), 0) == frame_pointer_rtx 421: || XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx) 422: && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT 423: && (INTVAL (XEXP (XEXP (operands[0], 0), 1)) & 0x7) != 0) 424: { 425: rtx xoperands[2]; 426: output_asm_insn ("st %1,%0", operands); 427: xoperands[1] = gen_rtx (REG, GET_MODE (operands[1]), 428: REGNO (operands[1]) + 1); 429: xoperands[0] = gen_rtx (MEM, GET_MODE (operands[0]), 430: plus_constant (XEXP (operands[0], 0), 4)); 431: output_asm_insn ("st %1,%0", xoperands); 432: return ""; 433: } 1.1 root 434: return "std %1,%0"; 435: } 1.1.1.3 root 436: else abort (); 1.1 root 437: } 438: 439: /* Return a REG that occurs in ADDR with coefficient 1. 440: ADDR can be effectively incremented by incrementing REG. */ 441: 442: static rtx 443: find_addr_reg (addr) 444: rtx addr; 445: { 446: while (GET_CODE (addr) == PLUS) 447: { 448: if (GET_CODE (XEXP (addr, 0)) == REG) 449: addr = XEXP (addr, 0); 450: if (GET_CODE (XEXP (addr, 1)) == REG) 451: addr = XEXP (addr, 1); 452: if (CONSTANT_P (XEXP (addr, 0))) 453: addr = XEXP (addr, 1); 454: if (CONSTANT_P (XEXP (addr, 1))) 455: addr = XEXP (addr, 0); 456: } 457: if (GET_CODE (addr) == REG) 458: return addr; 459: return 0; 460: } 461: 462: /* Load the address specified by OPERANDS[3] into the register 463: specified by OPERANDS[0]. 464: 465: OPERANDS[3] may be the result of a sum, hence it could either be: 466: 467: (1) CONST 468: (2) REG 469: (2) REG + CONST_INT 470: (3) REG + REG + CONST_INT 471: 1.1.1.5 root 472: Note that (3) is not a legitimate address. 1.1 root 473: All cases are handled here. */ 474: 475: void 476: output_load_address (operands) 477: rtx *operands; 478: { 479: rtx base, offset; 480: 481: if (CONSTANT_P (operands[3])) 482: { 483: output_asm_insn ("set %3,%0", operands); 484: return; 485: } 486: 487: if (REG_P (operands[3])) 488: { 489: if (REGNO (operands[0]) != REGNO (operands[3])) 490: output_asm_insn ("mov %3,%0", operands); 491: return; 492: } 493: 494: base = XEXP (operands[3], 0); 495: offset = XEXP (operands[3], 1); 496: 497: if (GET_CODE (base) == CONST_INT) 498: { 499: rtx tmp = base; 500: base = offset; 501: offset = tmp; 502: } 503: 504: if (GET_CODE (offset) != CONST_INT) 505: abort (); 506: 507: if (REG_P (base)) 508: { 509: operands[6] = base; 510: operands[7] = offset; 511: if (SMALL_INT (offset)) 512: output_asm_insn ("add %6,%7,%0", operands); 513: else 514: output_asm_insn ("set %7,%0\n\tadd %0,%6,%0", operands); 515: } 516: else 517: { 518: operands[6] = XEXP (base, 0); 519: operands[7] = XEXP (base, 1); 520: operands[8] = offset; 521: 522: if (SMALL_INT (offset)) 523: output_asm_insn ("add %6,%7,%0\n\tadd %0,%8,%0", operands); 524: else 525: output_asm_insn ("set %8,%0\n\tadd %0,%6,%0\n\tadd %0,%7,%0", operands); 526: } 527: } 528: 1.1.1.5 root 529: /* Output code to place a size count SIZE in register REG. 530: If SIZE is round, then assume that we can use alignment 531: based on that roundness, and return an integer saying 532: what alignment (roundness, transfer size) we will be using. 533: 534: Because block moves are pipelined, we don't include the 535: first element in the transfer of SIZE to REG. */ 536: 537: static int 538: output_size_for_block_move (size, reg) 539: rtx size, reg; 540: { 541: int align; 542: rtx xoperands[2]; 543: xoperands[0] = reg; 544: 545: /* First, figure out best alignment we may assume. */ 546: if (REG_P (size)) 547: { 548: xoperands[1] = size; 549: output_asm_insn ("sub %1,1,%0", xoperands); 550: align = 1; 551: } 552: else 553: { 554: int i = INTVAL (size); 555: 556: if (i & 1) 557: align = 1; 558: else if (i & 3) 559: align = 2; 560: else 561: align = 4; 562: 563: /* predecrement count. */ 564: i -= align; 565: if (i < 0) abort (); 566: 567: xoperands[1] = gen_rtx (CONST_INT, VOIDmode, i); 568: 569: output_asm_insn ("set %1,%0", xoperands); 570: } 571: return align; 572: } 573: 574: /* Emit code to perform a block move. 575: 576: OPERANDS[0] is the destination. 577: OPERANDS[1] is the source. 578: OPERANDS[2] is the size. 579: 580: We clobber registers 8,9,10, and register 1 (which we 581: do not need to worry about) during this move. 582: 583: It may happen that registers 8,9, and/or 10 are live 584: up to this call, in which case we must be careful 585: to use their values before clobbering them. 586: 587: This function attempts to take advantage of natural 588: luck, such as an operand which is already in an operand 589: register, and hence does not need to be moved around. 590: 591: Perhaps some day, GNU CC will be able to handle dynamic register 592: allocation to such inline library calls. 593: [No, never, because there is already provision for handling 594: library calls at RTL generation time, and I have no interest 595: in maintaining a redundant mechanism for them. 596: I hope some day the movstrsi pattern 597: for sparc will be deleted and an ordinary library call will be 598: used instead. Then this function will be unnecessary. - rms] */ 599: 600: #define COMPATIBLE(REG,OP) \ 601: (reg_conflicts[REG].ops[0] == operands[OP] \ 602: && (op_conflicts[OP].n_regs == 0 \ 603: || (op_conflicts[OP].n_regs == 1 \ 1.1.1.7 ! root 604: && op_conflicts[OP].regs[0] == REG) \ ! 605: || (op_conflicts[OP].n_regs == 2 \ ! 606: && (op_conflicts[OP].regs[0] == REG \ ! 607: || op_conflicts[OP].regs[1] == REG)))) 1.1.1.5 root 608: 1.1 root 609: char * 610: output_block_move (operands) 611: rtx *operands; 612: { 1.1.1.5 root 613: /* A vector for our computed operands. Note that load_output_address 614: makes use of up to the 8th element of this vector. */ 615: rtx xoperands[10]; 1.1 root 616: static int movstrsi_label = 0; 1.1.1.5 root 617: int align = -1; /* not yet known */ 1.1 root 618: int i, j; 619: 1.1.1.5 root 620: /* For each of registers 8, 9, and 10, keep track of 621: which operands use them. */ 622: struct 623: { 624: int n_ops; 625: rtx ops[3]; 626: } reg_conflicts[3]; 627: 628: /* For each of the 3 operands, keep track of which registers 629: they use. Each operand can only use 2 registers. */ 630: struct 631: { 632: int n_regs; 633: char regs[2]; 634: } op_conflicts[3]; 635: 636: /* Make rtxs for the register operands we are using, and 637: initialize all data structures. */ 638: rtx regs[3]; 639: rtx reg8 = gen_rtx (REG, SImode, 8); 640: rtx reg9 = gen_rtx (REG, SImode, 9); 641: rtx reg10 = gen_rtx (REG, SImode, 10); 642: regs[0] = reg8; 643: regs[1] = reg9; 644: regs[2] = reg10; 645: 1.1 root 646: /* Since we clobber untold things, nix the condition codes. */ 647: CC_STATUS_INIT; 648: 1.1.1.5 root 649: /* Recognize special cases of block moves. These occur 650: when GNU C++ is forced to treat something as BLKmode 651: to keep it in memory, when its mode could be represented 652: with something smaller. */ 653: if (GET_CODE (operands[2]) == CONST_INT 654: && INTVAL (operands[2]) <= 16) 655: { 656: int size = INTVAL (operands[2]); 657: xoperands[0] = XEXP (operands[0], 0); 658: xoperands[1] = XEXP (operands[1], 0); 659: /* If we are lucky, then this rtx can safely have 660: its INTVAL clobbered. */ 661: xoperands[2] = gen_rtx (CONST_INT, VOIDmode, 13); 662: 663: if (size & 1) 664: { 665: if (memory_address_p (QImode, plus_constant (xoperands[0], size)) 666: && memory_address_p (QImode, plus_constant (xoperands[1], size))) 667: { 668: for (i = size-1; i >= 0; i--) 669: { 670: INTVAL (xoperands[2]) = i; 671: output_asm_insn ("ldub [%a1+%2],%%g1\n\tstb %%g1,[%a0+%2]", 672: xoperands); 673: } 674: return ""; 675: } 676: } 677: else if (size & 2) 678: { 679: if (memory_address_p (HImode, plus_constant (xoperands[0], size)) 680: && memory_address_p (HImode, plus_constant (xoperands[1], size))) 681: { 682: for (i = (size>>1)-1; i >= 0; i--) 683: { 684: INTVAL (xoperands[2]) = i<<1; 685: output_asm_insn ("lduh [%a1+%2],%%g1\n\tsth %%g1,[%a0+%2]", 686: xoperands); 687: } 688: return ""; 689: } 690: } 691: else 692: { 693: if (memory_address_p (SImode, plus_constant (xoperands[0], size)) 694: && memory_address_p (SImode, plus_constant (xoperands[1], size))) 695: { 696: for (i = (size>>2)-1; i >= 0; i--) 697: { 698: INTVAL (xoperands[2]) = i<<2; 699: output_asm_insn ("ld [%a1+%2],%%g1\n\tst %%g1,[%a0+%2]", 700: xoperands); 701: } 702: return ""; 703: } 704: } 705: } 706: 707: bzero (reg_conflicts, sizeof (reg_conflicts)); 708: bzero (op_conflicts, sizeof (op_conflicts)); 1.1.1.6 root 709: xoperands[0] = 0; 710: xoperands[1] = 0; 711: xoperands[2] = 0; 1.1.1.5 root 712: 1.1 root 713: /* Get past the MEMs. */ 714: operands[0] = XEXP (operands[0], 0); 715: operands[1] = XEXP (operands[1], 0); 716: 1.1.1.5 root 717: /* See which operands use which registers. */ 718: for (i = 0; i < 3; i++) 1.1 root 719: { 1.1.1.5 root 720: for (j = 0; j < 3; j++) 721: { 1.1.1.6 root 722: if (reg_overlap_mentioned_p (regs[i], operands[j])) 1.1.1.5 root 723: { 724: reg_conflicts[i].ops[reg_conflicts[i].n_ops++] = operands[j]; 725: op_conflicts[j].regs[op_conflicts[j].n_regs++] = i; 726: } 727: } 1.1 root 728: } 1.1.1.5 root 729: 730: /* We need to know the alignment in order to set up 731: the destination address for a pipelined move. 732: Set it up first, if that is at all easy to do. */ 733: if (op_conflicts[2].n_regs == 0 734: || (op_conflicts[2].n_regs == 1 735: && (reg_conflicts[op_conflicts[2].regs[0]].n_ops == 0 736: || (reg_conflicts[op_conflicts[2].regs[0]].n_ops == 1 737: && (reg_conflicts[op_conflicts[2].regs[0]].ops[0] 738: == operands[2]))))) 739: { 740: /* This is the size of the transfer. 741: Either use the register which already contains the size, 742: or use a free register (used by no operands). */ 743: rtx reg = op_conflicts[2].n_regs == 1 744: ? regs[op_conflicts[2].regs[0]] 745: : reg_conflicts[0].n_ops == 0 746: ? regs[0] 747: : reg_conflicts[1].n_ops == 0 748: ? regs[1] : regs[2]; 749: 750: align = output_size_for_block_move (operands[2], reg); 751: 752: /* Mark this registers as being unavailable. */ 753: reg_conflicts[REGNO (reg) - 8].n_ops = -1; 754: 755: /* Update register usage information for the size operand. */ 756: op_conflicts[2].n_regs = 0; 757: xoperands[2] = reg; 758: } 759: 760: /* If register is used by only one operand, 761: make that register the home for that operand. */ 1.1 root 762: for (i = 0; i < 3; i++) 763: { 1.1.1.5 root 764: if (reg_conflicts[i].n_ops == 0) 1.1 root 765: { 1.1.1.5 root 766: /* No conflicts for this register. We can 767: immediately load it with an operand. Try 768: size first, then source, last dest. */ 769: if (xoperands[2] == 0) 770: { 771: j = 2; 772: /* This is the size of the transfer. */ 773: align = output_size_for_block_move (operands[2], regs[i]); 774: xoperands[2] = regs[i]; 775: } 776: else if (xoperands[1] == 0) 777: { 778: /* The source. */ 779: j = 1; 780: xoperands[1] = regs[i]; 781: xoperands[4] = operands[1]; 782: output_load_address (xoperands + 1); 783: } 784: else 785: { 786: /* The destination. */ 787: j = 0; 788: xoperands[0] = regs[i]; 789: xoperands[3] = plus_constant (operands[0], align); 790: output_load_address (xoperands); 791: } 792: /* Mark this register as now unavailable. */ 793: reg_conflicts[i].n_ops = -1; 1.1 root 794: } 1.1.1.5 root 795: else if (reg_conflicts[i].n_ops == 1) 1.1 root 796: { 1.1.1.5 root 797: /* One conflict. If the conflict is one which 798: does not clobber anything which depends on this 799: register, go ahead and load the operand 800: into this register. */ 801: if (COMPATIBLE (i, 2)) 802: { 803: j = 2; 804: /* This is the size of the transfer. */ 805: align = output_size_for_block_move (operands[2], regs[i]); 806: xoperands[2] = regs[i]; 807: } 808: else 809: { 810: /* An address for the transfer. 811: Set up for pipelined operation: dest must contain 812: a pre-incremented address, because its index is 813: pre-decremented. */ 814: 815: if (COMPATIBLE (i, 0)) 816: { 817: /* The destination. */ 818: if (align < 0) 819: continue; 820: j = 0; 821: xoperands[0] = regs[i]; 822: xoperands[3] = plus_constant (operands[0], align); 823: output_load_address (xoperands); 824: } 825: else if (COMPATIBLE (i, 1)) 826: { 827: /* The source. */ 828: j = 1; 829: xoperands[1] = regs[i]; 830: xoperands[4] = operands[1]; 831: output_load_address (xoperands + 1); 832: } 833: else continue; 834: } 835: /* Mark this register as now unavailable. */ 836: reg_conflicts[i].n_ops = -1; 837: 838: /* Update register usage information for operands. */ 839: op_conflicts[j].n_regs--; 840: if (op_conflicts[j].n_regs && op_conflicts[j].regs[0] == i) 841: op_conflicts[j].regs[0] = op_conflicts[j].regs[1]; 1.1 root 842: } 843: } 844: 1.1.1.5 root 845: if (xoperands[0] == 0 || xoperands[1] == 0 || xoperands[2] == 0) 1.1 root 846: { 1.1.1.5 root 847: /* There were interlocking register requirements. First 848: user to submit code which triggered that wins a prize. */ 849: abort (); 1.1 root 850: } 851: 852: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); 853: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align); 854: 1.1.1.5 root 855: if (align == 1) 856: output_asm_insn ("\nLm%3:\n\tldub [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tstb %%g1,[%0+%2]", xoperands); 857: else if (align == 2) 858: output_asm_insn ("\nLm%3:\n\tlduh [%1+%2],%%g1\n\tsubcc %2,%4,%2\n\tbge Lm%3\n\tsth %%g1,[%0+%2]", xoperands); 859: else 860: 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 861: return ""; 862: } 1.1.1.5 root 863: 864: /* What the sparc lacks in hardware, make up for in software. 865: Compute a fairly good sequence of shift and add insns 866: to make a multiply happen. */ 1.1 root 867: 868: #define ABS(x) ((x) < 0 ? -(x) : x) 869: 870: char * 871: output_mul_by_constant (insn, operands, unsignedp) 872: rtx insn; 873: rtx *operands; 874: int unsignedp; 875: { 876: int c; /* Size of constant */ 877: int shifts[BITS_PER_WORD]; /* Table of shifts */ 1.1.1.4 root 878: unsigned int p, log; /* A power of two, and its log */ 1.1 root 879: int d1, d2; /* Differences of c and p */ 880: int first = 1; /* True if dst has unknown data in it */ 881: int i; 882: 883: c = INTVAL (operands[2]); 884: if (c == 0) 885: { 886: /* should not happen. */ 887: abort (); 888: if (GET_CODE (operands[0]) == MEM) 889: return "st %%g0,%0"; 890: return "mov %%g0,%0"; 891: } 892: 893: output_asm_insn ("! start open coded multiply"); 894: 895: /* Clear out the table of shifts. */ 896: for (i = 0; i < BITS_PER_WORD; ++i) 897: shifts[i] = 0; 898: 899: while (c) 900: { 901: /* Find the power of two nearest ABS(c) */ 902: p = 1, log = 0; 903: do 904: { 905: d1 = ABS(c) - p; 906: p *= 2; 907: ++log; 908: } 909: while (p < ABS(c)); 910: d2 = p - ABS(c); 911: 912: /* Make an appropriate entry in shifts for p. */ 913: if (d2 < d1) 914: { 915: shifts[log] = c < 0 ? -1 : 1; 916: c = c < 0 ? d2 : -d2; 917: } 918: else 919: { 920: shifts[log - 1] = c < 0 ? -1 : 1; 921: c = c < 0 ? -d1 : d1; 922: } 923: } 924: 925: /* Take care of the first insn in sequence. 926: We know we have at least one. */ 927: 928: /* A value of -1 in shifts says to subtract that power of two, and a value 929: of 1 says to add that power of two. */ 930: for (i = 0; ; i++) 931: if (shifts[i]) 932: { 933: if (i) 934: { 935: operands[2] = gen_rtx (CONST_INT, VOIDmode, i); 1.1.1.5 root 936: output_asm_insn ("sll %1,%2,%%g1", operands); 1.1 root 937: } 1.1.1.5 root 938: else output_asm_insn ("mov %1,%%g1", operands); 1.1 root 939: 940: log = i; 941: if (shifts[i] < 0) 1.1.1.5 root 942: output_asm_insn ("sub %%g0,%%g1,%0", operands); 1.1 root 943: else 1.1.1.5 root 944: output_asm_insn ("mov %%g1,%0", operands); 1.1 root 945: break; 946: } 947: 948: /* A value of -1 in shifts says to subtract that power of two, and a value 949: of 1 says to add that power of two--continued. */ 950: for (i += 1; i < BITS_PER_WORD; ++i) 951: if (shifts[i]) 952: { 953: if (i - log > 0) 954: { 955: operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log); 1.1.1.5 root 956: output_asm_insn ("sll %%g1,%2,%%g1", operands); 1.1 root 957: } 958: else 959: { 960: operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i); 1.1.1.5 root 961: output_asm_insn ("sra %%g1,%2,%%g1", operands); 1.1 root 962: } 963: log = i; 964: if (shifts[i] < 0) 1.1.1.5 root 965: output_asm_insn ("sub %0,%%g1,%0", operands); 1.1 root 966: else 1.1.1.5 root 967: output_asm_insn ("add %0,%%g1,%0", operands); 1.1 root 968: } 969: 970: output_asm_insn ("! end open coded multiply"); 971: 972: return ""; 973: } 974: 975: char * 976: output_mul_insn (operands, unsignedp) 977: rtx *operands; 978: int unsignedp; 979: { 980: int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1; 981: int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1; 982: 983: if (lucky1) 984: if (lucky2) 985: output_asm_insn ("call .mul,2\n\tnop", operands); 986: else 987: { 988: rtx xoperands[2]; 989: xoperands[0] = gen_rtx (REG, SImode, 990: 8 ^ (REGNO (operands[1]) == 8)); 991: xoperands[1] = operands[2]; 992: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); 993: } 994: else if (lucky2) 995: { 996: rtx xoperands[2]; 997: xoperands[0] = gen_rtx (REG, SImode, 998: 8 ^ (REGNO (operands[2]) == 8)); 999: xoperands[1] = operands[1]; 1000: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); 1001: } 1002: else 1003: { 1004: output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1", 1005: operands); 1006: } 1007: 1008: if (REGNO (operands[0]) == 8) 1009: return ""; 1010: return "mov %%o0,%0"; 1011: } 1012: 1013: /* Make floating point register f0 contain 0. 1014: SIZE is the number of registers (including f0) 1015: which should contain 0. */ 1016: 1017: void 1018: make_f0_contain_0 (size) 1019: int size; 1020: { 1021: if (size == 1) 1.1.1.3 root 1022: output_asm_insn ("ld [%%fp-16],%%f0", 0); 1.1 root 1023: else if (size == 2) 1.1.1.3 root 1024: output_asm_insn ("ldd [%%fp-16],%%f0", 0); 1.1 root 1025: } 1.1.1.4 root 1026: 1027: /* Output reasonable peephole for set-on-condition-code insns. 1028: Note that these insns assume a particular way of defining 1029: labels. Therefore, *both* tm-sparc.h and this function must 1030: be changed if a new syntax is needed. */ 1031: 1032: char * 1033: output_scc_insn (code, operands) 1034: enum rtx_code code; 1035: rtx *operands; 1036: { 1037: rtx xoperands[2]; 1038: rtx label = gen_label_rtx (); 1039: 1040: xoperands[0] = operands[0]; 1041: xoperands[1] = label; 1042: 1043: switch (code) 1044: { 1045: case NE: 1046: if (cc_status.flags & CC_IN_FCCR) 1.1.1.5 root 1047: output_asm_insn ("fbne,a %l0", &label); 1.1.1.4 root 1048: else 1.1.1.5 root 1049: output_asm_insn ("bne,a %l0", &label); 1.1.1.4 root 1050: break; 1051: case EQ: 1052: if (cc_status.flags & CC_IN_FCCR) 1.1.1.5 root 1053: output_asm_insn ("fbe,a %l0", &label); 1.1.1.4 root 1054: else 1.1.1.5 root 1055: output_asm_insn ("be,a %l0", &label); 1.1.1.4 root 1056: break; 1057: case GE: 1058: if (cc_status.flags & CC_IN_FCCR) 1.1.1.5 root 1059: output_asm_insn ("fbge,a %l0", &label); 1.1.1.4 root 1060: else 1.1.1.5 root 1061: output_asm_insn ("bge,a %l0", &label); 1.1.1.4 root 1062: break; 1063: case GT: 1064: if (cc_status.flags & CC_IN_FCCR) 1.1.1.5 root 1065: output_asm_insn ("fbg,a %l0", &label); 1.1.1.4 root 1066: else 1.1.1.5 root 1067: output_asm_insn ("bg,a %l0", &label); 1.1.1.4 root 1068: break; 1069: case LE: 1070: if (cc_status.flags & CC_IN_FCCR) 1.1.1.5 root 1071: output_asm_insn ("fble,a %l0", &label); 1.1.1.4 root 1072: else 1.1.1.5 root 1073: output_asm_insn ("ble,a %l0", &label); 1.1.1.4 root 1074: break; 1075: case LT: 1076: if (cc_status.flags & CC_IN_FCCR) 1.1.1.5 root 1077: output_asm_insn ("fbl,a %l0", &label); 1.1.1.4 root 1078: else 1.1.1.5 root 1079: output_asm_insn ("bl,a %l0", &label); 1.1.1.4 root 1080: break; 1081: case GEU: 1082: if (cc_status.flags & CC_IN_FCCR) 1083: abort (); 1084: else 1.1.1.5 root 1085: output_asm_insn ("bgeu,a %l0", &label); 1.1.1.4 root 1086: break; 1087: case GTU: 1088: if (cc_status.flags & CC_IN_FCCR) 1089: abort (); 1090: else 1.1.1.5 root 1091: output_asm_insn ("bgu,a %l0", &label); 1.1.1.4 root 1092: break; 1093: case LEU: 1094: if (cc_status.flags & CC_IN_FCCR) 1095: abort (); 1096: else 1.1.1.5 root 1097: output_asm_insn ("bleu,a %l0", &label); 1.1.1.4 root 1098: break; 1099: case LTU: 1100: if (cc_status.flags & CC_IN_FCCR) 1101: abort (); 1102: else 1.1.1.5 root 1103: output_asm_insn ("blu,a %l0", &label); 1.1.1.4 root 1104: break; 1105: default: 1106: abort (); 1107: } 1.1.1.5 root 1108: output_asm_insn ("mov 1,%0\n\tmov 0,%0\n%l1", xoperands); 1.1.1.4 root 1109: return ""; 1110: } 1111: 1.1.1.5 root 1112: /* Output a delayed branch insn with the delay insn in its 1113: branch slot. The delayed branch insn template is in TEMPLATE, 1114: with operands OPERANDS. The insn in its delay slot is INSN. */ 1.1.1.4 root 1115: 1116: char * 1117: output_delay_insn (template, operands, insn) 1118: char *template; 1119: rtx *operands; 1120: rtx insn; 1121: { 1122: extern char *insn_template[]; 1123: extern char *(*insn_outfun[])(); 1124: rtx pat = gen_rtx (SET, VOIDmode, 1125: XVECEXP (PATTERN (insn), 0, 0), 1126: XVECEXP (PATTERN (insn), 0, 1)); 1127: rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); 1128: int insn_code_number; 1129: 1130: /* Output the branch instruction first. */ 1131: output_asm_insn (template, operands); 1132: 1133: /* Now recognize the insn which we put in its delay slot. 1134: We must do this after outputing the branch insn, 1135: since operands may just be a pointer to `recog_operands'. */ 1136: insn_code_number = recog (pat, delay_insn); 1137: if (insn_code_number == -1) 1138: abort (); 1139: 1140: /* Now get the template for what this insn would 1141: have been, without the branch. Its operands are 1142: exactly the same as they would be, so we don't 1143: need to do an insn_extract. */ 1144: template = insn_template[insn_code_number]; 1145: if (template == 0) 1146: template = (*insn_outfun[insn_code_number]) (operands, delay_insn); 1147: output_asm_insn (template, operands); 1148: return ""; 1149: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.