|
|
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. */ 1.1.1.6 ! root 285: if (MEM_IN_STRUCT_P (operands[1])) 1.1.1.4 root 286: return "ldd %1,%0"; 1.1.1.6 ! root 287: else if (MEM_IN_STRUCT_P (operands[0])) 1.1.1.4 root 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 1.1.1.6 ! root 314: && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0))) 1.1.1.3 root 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)); 1.1.1.6 ! root 691: xoperands[0] = 0; ! 692: xoperands[1] = 0; ! 693: xoperands[2] = 0; 1.1.1.5 root 694: 1.1 root 695: /* Get past the MEMs. */ 696: operands[0] = XEXP (operands[0], 0); 697: operands[1] = XEXP (operands[1], 0); 698: 1.1.1.5 root 699: /* See which operands use which registers. */ 700: for (i = 0; i < 3; i++) 1.1 root 701: { 1.1.1.5 root 702: for (j = 0; j < 3; j++) 703: { 1.1.1.6 ! root 704: if (reg_overlap_mentioned_p (regs[i], operands[j])) 1.1.1.5 root 705: { 706: reg_conflicts[i].ops[reg_conflicts[i].n_ops++] = operands[j]; 707: op_conflicts[j].regs[op_conflicts[j].n_regs++] = i; 708: } 709: } 1.1 root 710: } 1.1.1.5 root 711: 712: /* We need to know the alignment in order to set up 713: the destination address for a pipelined move. 714: Set it up first, if that is at all easy to do. */ 715: if (op_conflicts[2].n_regs == 0 716: || (op_conflicts[2].n_regs == 1 717: && (reg_conflicts[op_conflicts[2].regs[0]].n_ops == 0 718: || (reg_conflicts[op_conflicts[2].regs[0]].n_ops == 1 719: && (reg_conflicts[op_conflicts[2].regs[0]].ops[0] 720: == operands[2]))))) 721: { 722: /* This is the size of the transfer. 723: Either use the register which already contains the size, 724: or use a free register (used by no operands). */ 725: rtx reg = op_conflicts[2].n_regs == 1 726: ? regs[op_conflicts[2].regs[0]] 727: : reg_conflicts[0].n_ops == 0 728: ? regs[0] 729: : reg_conflicts[1].n_ops == 0 730: ? regs[1] : regs[2]; 731: 732: align = output_size_for_block_move (operands[2], reg); 733: 734: /* Mark this registers as being unavailable. */ 735: reg_conflicts[REGNO (reg) - 8].n_ops = -1; 736: 737: /* Update register usage information for the size operand. */ 738: op_conflicts[2].n_regs = 0; 739: xoperands[2] = reg; 740: } 741: 742: /* If register is used by only one operand, 743: make that register the home for that operand. */ 1.1 root 744: for (i = 0; i < 3; i++) 745: { 1.1.1.5 root 746: if (reg_conflicts[i].n_ops == 0) 1.1 root 747: { 1.1.1.5 root 748: /* No conflicts for this register. We can 749: immediately load it with an operand. Try 750: size first, then source, last dest. */ 751: if (xoperands[2] == 0) 752: { 753: j = 2; 754: /* This is the size of the transfer. */ 755: align = output_size_for_block_move (operands[2], regs[i]); 756: xoperands[2] = regs[i]; 757: } 758: else if (xoperands[1] == 0) 759: { 760: /* The source. */ 761: j = 1; 762: xoperands[1] = regs[i]; 763: xoperands[4] = operands[1]; 764: output_load_address (xoperands + 1); 765: } 766: else 767: { 768: /* The destination. */ 769: j = 0; 770: xoperands[0] = regs[i]; 771: xoperands[3] = plus_constant (operands[0], align); 772: output_load_address (xoperands); 773: } 774: /* Mark this register as now unavailable. */ 775: reg_conflicts[i].n_ops = -1; 1.1 root 776: } 1.1.1.5 root 777: else if (reg_conflicts[i].n_ops == 1) 1.1 root 778: { 1.1.1.5 root 779: /* One conflict. If the conflict is one which 780: does not clobber anything which depends on this 781: register, go ahead and load the operand 782: into this register. */ 783: if (COMPATIBLE (i, 2)) 784: { 785: j = 2; 786: /* This is the size of the transfer. */ 787: align = output_size_for_block_move (operands[2], regs[i]); 788: xoperands[2] = regs[i]; 789: } 790: else 791: { 792: /* An address for the transfer. 793: Set up for pipelined operation: dest must contain 794: a pre-incremented address, because its index is 795: pre-decremented. */ 796: 797: if (COMPATIBLE (i, 0)) 798: { 799: /* The destination. */ 800: if (align < 0) 801: continue; 802: j = 0; 803: xoperands[0] = regs[i]; 804: xoperands[3] = plus_constant (operands[0], align); 805: output_load_address (xoperands); 806: } 807: else if (COMPATIBLE (i, 1)) 808: { 809: /* The source. */ 810: j = 1; 811: xoperands[1] = regs[i]; 812: xoperands[4] = operands[1]; 813: output_load_address (xoperands + 1); 814: } 815: else continue; 816: } 817: /* Mark this register as now unavailable. */ 818: reg_conflicts[i].n_ops = -1; 819: 820: /* Update register usage information for operands. */ 821: op_conflicts[j].n_regs--; 822: if (op_conflicts[j].n_regs && op_conflicts[j].regs[0] == i) 823: op_conflicts[j].regs[0] = op_conflicts[j].regs[1]; 1.1 root 824: } 825: } 826: 1.1.1.5 root 827: if (xoperands[0] == 0 || xoperands[1] == 0 || xoperands[2] == 0) 1.1 root 828: { 1.1.1.5 root 829: /* There were interlocking register requirements. First 830: user to submit code which triggered that wins a prize. */ 831: abort (); 1.1 root 832: } 833: 834: xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++); 835: xoperands[4] = gen_rtx (CONST_INT, VOIDmode, align); 836: 1.1.1.5 root 837: if (align == 1) 838: 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); 839: else if (align == 2) 840: 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); 841: else 842: 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 843: return ""; 844: } 1.1.1.5 root 845: 846: /* What the sparc lacks in hardware, make up for in software. 847: Compute a fairly good sequence of shift and add insns 848: to make a multiply happen. */ 1.1 root 849: 850: #define ABS(x) ((x) < 0 ? -(x) : x) 851: 852: char * 853: output_mul_by_constant (insn, operands, unsignedp) 854: rtx insn; 855: rtx *operands; 856: int unsignedp; 857: { 858: int c; /* Size of constant */ 859: int shifts[BITS_PER_WORD]; /* Table of shifts */ 1.1.1.4 root 860: unsigned int p, log; /* A power of two, and its log */ 1.1 root 861: int d1, d2; /* Differences of c and p */ 862: int first = 1; /* True if dst has unknown data in it */ 863: int i; 864: 865: c = INTVAL (operands[2]); 866: if (c == 0) 867: { 868: /* should not happen. */ 869: abort (); 870: if (GET_CODE (operands[0]) == MEM) 871: return "st %%g0,%0"; 872: return "mov %%g0,%0"; 873: } 874: 875: output_asm_insn ("! start open coded multiply"); 876: 877: /* Clear out the table of shifts. */ 878: for (i = 0; i < BITS_PER_WORD; ++i) 879: shifts[i] = 0; 880: 881: while (c) 882: { 883: /* Find the power of two nearest ABS(c) */ 884: p = 1, log = 0; 885: do 886: { 887: d1 = ABS(c) - p; 888: p *= 2; 889: ++log; 890: } 891: while (p < ABS(c)); 892: d2 = p - ABS(c); 893: 894: /* Make an appropriate entry in shifts for p. */ 895: if (d2 < d1) 896: { 897: shifts[log] = c < 0 ? -1 : 1; 898: c = c < 0 ? d2 : -d2; 899: } 900: else 901: { 902: shifts[log - 1] = c < 0 ? -1 : 1; 903: c = c < 0 ? -d1 : d1; 904: } 905: } 906: 907: /* Take care of the first insn in sequence. 908: We know we have at least one. */ 909: 910: /* A value of -1 in shifts says to subtract that power of two, and a value 911: of 1 says to add that power of two. */ 912: for (i = 0; ; i++) 913: if (shifts[i]) 914: { 915: if (i) 916: { 917: operands[2] = gen_rtx (CONST_INT, VOIDmode, i); 1.1.1.5 root 918: output_asm_insn ("sll %1,%2,%%g1", operands); 1.1 root 919: } 1.1.1.5 root 920: else output_asm_insn ("mov %1,%%g1", operands); 1.1 root 921: 922: log = i; 923: if (shifts[i] < 0) 1.1.1.5 root 924: output_asm_insn ("sub %%g0,%%g1,%0", operands); 1.1 root 925: else 1.1.1.5 root 926: output_asm_insn ("mov %%g1,%0", operands); 1.1 root 927: break; 928: } 929: 930: /* A value of -1 in shifts says to subtract that power of two, and a value 931: of 1 says to add that power of two--continued. */ 932: for (i += 1; i < BITS_PER_WORD; ++i) 933: if (shifts[i]) 934: { 935: if (i - log > 0) 936: { 937: operands[2] = gen_rtx (CONST_INT, VOIDmode, i - log); 1.1.1.5 root 938: output_asm_insn ("sll %%g1,%2,%%g1", operands); 1.1 root 939: } 940: else 941: { 942: operands[2] = gen_rtx (CONST_INT, VOIDmode, log - i); 1.1.1.5 root 943: output_asm_insn ("sra %%g1,%2,%%g1", operands); 1.1 root 944: } 945: log = i; 946: if (shifts[i] < 0) 1.1.1.5 root 947: output_asm_insn ("sub %0,%%g1,%0", operands); 1.1 root 948: else 1.1.1.5 root 949: output_asm_insn ("add %0,%%g1,%0", operands); 1.1 root 950: } 951: 952: output_asm_insn ("! end open coded multiply"); 953: 954: return ""; 955: } 956: 957: char * 958: output_mul_insn (operands, unsignedp) 959: rtx *operands; 960: int unsignedp; 961: { 962: int lucky1 = ((unsigned)REGNO (operands[1]) - 8) <= 1; 963: int lucky2 = ((unsigned)REGNO (operands[2]) - 8) <= 1; 964: 965: if (lucky1) 966: if (lucky2) 967: output_asm_insn ("call .mul,2\n\tnop", operands); 968: else 969: { 970: rtx xoperands[2]; 971: xoperands[0] = gen_rtx (REG, SImode, 972: 8 ^ (REGNO (operands[1]) == 8)); 973: xoperands[1] = operands[2]; 974: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); 975: } 976: else if (lucky2) 977: { 978: rtx xoperands[2]; 979: xoperands[0] = gen_rtx (REG, SImode, 980: 8 ^ (REGNO (operands[2]) == 8)); 981: xoperands[1] = operands[1]; 982: output_asm_insn ("call .mul,2\n\tmov %1,%0", xoperands); 983: } 984: else 985: { 986: output_asm_insn ("mov %1,%%o0\n\tcall .mul,2\n\tmov %2,%%o1", 987: operands); 988: } 989: 990: if (REGNO (operands[0]) == 8) 991: return ""; 992: return "mov %%o0,%0"; 993: } 994: 995: /* Make floating point register f0 contain 0. 996: SIZE is the number of registers (including f0) 997: which should contain 0. */ 998: 999: void 1000: make_f0_contain_0 (size) 1001: int size; 1002: { 1003: if (size == 1) 1.1.1.3 root 1004: output_asm_insn ("ld [%%fp-16],%%f0", 0); 1.1 root 1005: else if (size == 2) 1.1.1.3 root 1006: output_asm_insn ("ldd [%%fp-16],%%f0", 0); 1.1 root 1007: } 1.1.1.4 root 1008: 1009: /* Output reasonable peephole for set-on-condition-code insns. 1010: Note that these insns assume a particular way of defining 1011: labels. Therefore, *both* tm-sparc.h and this function must 1012: be changed if a new syntax is needed. */ 1013: 1014: char * 1015: output_scc_insn (code, operands) 1016: enum rtx_code code; 1017: rtx *operands; 1018: { 1019: rtx xoperands[2]; 1020: rtx label = gen_label_rtx (); 1021: 1022: xoperands[0] = operands[0]; 1023: xoperands[1] = label; 1024: 1025: switch (code) 1026: { 1027: case NE: 1028: if (cc_status.flags & CC_IN_FCCR) 1.1.1.5 root 1029: output_asm_insn ("fbne,a %l0", &label); 1.1.1.4 root 1030: else 1.1.1.5 root 1031: output_asm_insn ("bne,a %l0", &label); 1.1.1.4 root 1032: break; 1033: case EQ: 1034: if (cc_status.flags & CC_IN_FCCR) 1.1.1.5 root 1035: output_asm_insn ("fbe,a %l0", &label); 1.1.1.4 root 1036: else 1.1.1.5 root 1037: output_asm_insn ("be,a %l0", &label); 1.1.1.4 root 1038: break; 1039: case GE: 1040: if (cc_status.flags & CC_IN_FCCR) 1.1.1.5 root 1041: output_asm_insn ("fbge,a %l0", &label); 1.1.1.4 root 1042: else 1.1.1.5 root 1043: output_asm_insn ("bge,a %l0", &label); 1.1.1.4 root 1044: break; 1045: case GT: 1046: if (cc_status.flags & CC_IN_FCCR) 1.1.1.5 root 1047: output_asm_insn ("fbg,a %l0", &label); 1.1.1.4 root 1048: else 1.1.1.5 root 1049: output_asm_insn ("bg,a %l0", &label); 1.1.1.4 root 1050: break; 1051: case LE: 1052: if (cc_status.flags & CC_IN_FCCR) 1.1.1.5 root 1053: output_asm_insn ("fble,a %l0", &label); 1.1.1.4 root 1054: else 1.1.1.5 root 1055: output_asm_insn ("ble,a %l0", &label); 1.1.1.4 root 1056: break; 1057: case LT: 1058: if (cc_status.flags & CC_IN_FCCR) 1.1.1.5 root 1059: output_asm_insn ("fbl,a %l0", &label); 1.1.1.4 root 1060: else 1.1.1.5 root 1061: output_asm_insn ("bl,a %l0", &label); 1.1.1.4 root 1062: break; 1063: case GEU: 1064: if (cc_status.flags & CC_IN_FCCR) 1065: abort (); 1066: else 1.1.1.5 root 1067: output_asm_insn ("bgeu,a %l0", &label); 1.1.1.4 root 1068: break; 1069: case GTU: 1070: if (cc_status.flags & CC_IN_FCCR) 1071: abort (); 1072: else 1.1.1.5 root 1073: output_asm_insn ("bgu,a %l0", &label); 1.1.1.4 root 1074: break; 1075: case LEU: 1076: if (cc_status.flags & CC_IN_FCCR) 1077: abort (); 1078: else 1.1.1.5 root 1079: output_asm_insn ("bleu,a %l0", &label); 1.1.1.4 root 1080: break; 1081: case LTU: 1082: if (cc_status.flags & CC_IN_FCCR) 1083: abort (); 1084: else 1.1.1.5 root 1085: output_asm_insn ("blu,a %l0", &label); 1.1.1.4 root 1086: break; 1087: default: 1088: abort (); 1089: } 1.1.1.5 root 1090: output_asm_insn ("mov 1,%0\n\tmov 0,%0\n%l1", xoperands); 1.1.1.4 root 1091: return ""; 1092: } 1093: 1.1.1.5 root 1094: /* Output a delayed branch insn with the delay insn in its 1095: branch slot. The delayed branch insn template is in TEMPLATE, 1096: with operands OPERANDS. The insn in its delay slot is INSN. */ 1.1.1.4 root 1097: 1098: char * 1099: output_delay_insn (template, operands, insn) 1100: char *template; 1101: rtx *operands; 1102: rtx insn; 1103: { 1104: extern char *insn_template[]; 1105: extern char *(*insn_outfun[])(); 1106: rtx pat = gen_rtx (SET, VOIDmode, 1107: XVECEXP (PATTERN (insn), 0, 0), 1108: XVECEXP (PATTERN (insn), 0, 1)); 1109: rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0); 1110: int insn_code_number; 1111: 1112: /* Output the branch instruction first. */ 1113: output_asm_insn (template, operands); 1114: 1115: /* Now recognize the insn which we put in its delay slot. 1116: We must do this after outputing the branch insn, 1117: since operands may just be a pointer to `recog_operands'. */ 1118: insn_code_number = recog (pat, delay_insn); 1119: if (insn_code_number == -1) 1120: abort (); 1121: 1122: /* Now get the template for what this insn would 1123: have been, without the branch. Its operands are 1124: exactly the same as they would be, so we don't 1125: need to do an insn_extract. */ 1126: template = insn_template[insn_code_number]; 1127: if (template == 0) 1128: template = (*insn_outfun[insn_code_number]) (operands, delay_insn); 1129: output_asm_insn (template, operands); 1130: return ""; 1131: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.