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