|
|
1.1 ! root 1: /* Output routines for GCC for Hitachi Super-H ! 2: Copyright (C) 1993 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU CC. ! 5: ! 6: GNU CC is free software; you can redistribute it and/or modify ! 7: it under the terms of the GNU General Public License as published by ! 8: the Free Software Foundation; either version 2, or (at your option) ! 9: any later version. ! 10: ! 11: GNU CC is distributed in the hope that it will be useful, ! 12: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: GNU General Public License for more details. ! 15: ! 16: You should have received a copy of the GNU General Public License ! 17: along with GNU CC; see the file COPYING. If not, write to ! 18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 19: ! 20: ! 21: /* Contributed by Steve Chamberlain ([email protected]) */ ! 22: ! 23: #include <stdio.h> ! 24: #include "assert.h" ! 25: #include "config.h" ! 26: #include "rtl.h" ! 27: #include "regs.h" ! 28: #include "hard-reg-set.h" ! 29: #include "real.h" ! 30: #include "insn-config.h" ! 31: #include "conditions.h" ! 32: #include "insn-flags.h" ! 33: #include "tree.h" ! 34: #include "output.h" ! 35: #include "insn-attr.h" ! 36: #include "flags.h" ! 37: #include "obstack.h" ! 38: #include "expr.h" ! 39: ! 40: ! 41: static int add_constant (); ! 42: int dump_constants (); ! 43: ! 44: int current_function_anonymous_args; ! 45: extern int current_function_pretend_args_size; ! 46: extern char *version_string; ! 47: extern int flag_traditional; ! 48: ! 49: ! 50: enum attr_cpu sh_cpu; /* target cpu */ ! 51: ! 52: /* Global variables for machine-dependent things. */ ! 53: ! 54: /* Saved operands from the last compare to use when we generate an scc ! 55: or bcc insn. */ ! 56: ! 57: rtx sh_compare_op0; ! 58: rtx sh_compare_op1; ! 59: ! 60: /* Provides the class number of the smallest class containing ! 61: reg number */ ! 62: ! 63: int regno_reg_class[FIRST_PSEUDO_REGISTER] = ! 64: { ! 65: R0_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, ! 66: GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, ! 67: GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, ! 68: GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, ! 69: GENERAL_REGS, PR_REGS, T_REGS, NO_REGS, MAC_REGS, ! 70: MAC_REGS, ! 71: }; ! 72: ! 73: /* Provide reg_class from a letter such as appears in the machine ! 74: description. */ ! 75: ! 76: enum reg_class reg_class_from_letter[] = ! 77: { ! 78: /* a */ NO_REGS, /* b */ NO_REGS, /* c */ NO_REGS, /* d */ NO_REGS, ! 79: /* e */ NO_REGS, /* f */ NO_REGS, /* g */ NO_REGS, /* h */ NO_REGS, ! 80: /* i */ NO_REGS, /* j */ NO_REGS, /* k */ NO_REGS, /* l */ PR_REGS, ! 81: /* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS, ! 82: /* q */ NO_REGS, /* r */ NO_REGS, /* s */ NO_REGS, /* t */ T_REGS, ! 83: /* u */ NO_REGS, /* v */ NO_REGS, /* w */ NO_REGS, /* x */ MAC_REGS, ! 84: /* y */ NO_REGS, /* z */ R0_REGS ! 85: }; ! 86: ! 87: ! 88: ! 89: ! 90: /* Local label counter, used for constants in the pool and inside ! 91: pattern branches. */ ! 92: ! 93: static int lf = 100; ! 94: ! 95: /* Used to work out sizes of instructions */ ! 96: static int first_pc; ! 97: static int pc; ! 98: #define MAYBE_DUMP_LEVEL 900 ! 99: #define MUST_DUMP_LEVEL 1000 ! 100: static int dumpnext; ! 101: ! 102: ! 103: void ! 104: push (rn) ! 105: { ! 106: emit_insn (gen_push (gen_rtx (REG, SImode, rn))); ! 107: } ! 108: ! 109: void ! 110: pop (rn) ! 111: { ! 112: emit_insn (gen_pop (gen_rtx (REG, SImode, rn))); ! 113: } ! 114: ! 115: ! 116: /* Adjust the stack and return the number of bytes taken to do it */ ! 117: ! 118: static void ! 119: output_stack_adjust (direction, size) ! 120: int direction; ! 121: int size; ! 122: { ! 123: if (size) ! 124: { ! 125: rtx val = GEN_INT (size); ! 126: rtx insn; ! 127: ! 128: if (size > 120) ! 129: { ! 130: rtx nval = gen_rtx (REG, SImode, 13); ! 131: emit_insn (gen_movsi (nval, val)); ! 132: val = nval; ! 133: } ! 134: ! 135: if (direction > 0) ! 136: insn = gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, val); ! 137: else ! 138: insn = gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, val); ! 139: ! 140: emit_insn (insn); ! 141: } ! 142: } ! 143: ! 144: ! 145: ! 146: /* Generate code to push the regs specified in the mask, and return ! 147: the number of bytes the insns take. */ ! 148: ! 149: static void ! 150: push_regs (mask) ! 151: int mask; ! 152: { ! 153: int i; ! 154: int size = 0; ! 155: ! 156: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ! 157: { ! 158: if (mask & (1 << i)) ! 159: { ! 160: push (i); ! 161: } ! 162: } ! 163: } ! 164: ! 165: ! 166: /* ! 167: Print an instruction which would have gone into a delay slot ! 168: after an instructiuon, but couldn't because the instruction expanded ! 169: into a sequence where putting the slot insn at the end wouldn't work. ! 170: */ ! 171: ! 172: void ! 173: print_slot (insn) ! 174: rtx insn; ! 175: { ! 176: final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file, optimize, 0, 1); ! 177: ! 178: INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1; ! 179: } ! 180: ! 181: /* Number of bytes pushed for anonymous args */ ! 182: ! 183: static int extra_push; ! 184: ! 185: /* Work out the registers which need to be saved, both as a mask and a ! 186: count */ ! 187: ! 188: int ! 189: calc_live_regs (count) ! 190: int *count; ! 191: { ! 192: int reg; ! 193: int live_regs_mask = 0; ! 194: *count = 0; ! 195: ! 196: for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg++) ! 197: { ! 198: if (regs_ever_live[reg] && !call_used_regs[reg]) ! 199: { ! 200: (*count)++; ! 201: live_regs_mask |= (1 << reg); ! 202: } ! 203: } ! 204: return live_regs_mask; ! 205: } ! 206: ! 207: ! 208: ! 209: ! 210: static int ! 211: need_slot (insn) ! 212: rtx insn; ! 213: { ! 214: return (insn && !INSN_ANNULLED_BRANCH_P (XVECEXP (insn, 0, 0))); ! 215: } ! 216: ! 217: /* Print the operand address in x to the stream */ ! 218: ! 219: void ! 220: print_operand_address (stream, x) ! 221: FILE *stream; ! 222: rtx x; ! 223: { ! 224: switch (GET_CODE (x)) ! 225: { ! 226: case REG: ! 227: fprintf (stream, "@%s", reg_names[REGNO (x)]); ! 228: break; ! 229: case PLUS: ! 230: { ! 231: rtx base = XEXP (x, 0); ! 232: rtx index = XEXP (x, 1); ! 233: ! 234: if (GET_CODE (base) != REG) ! 235: { ! 236: /* Ensure that BASE is a register (one of them must be). */ ! 237: rtx temp = base; ! 238: base = index; ! 239: index = temp; ! 240: } ! 241: ! 242: switch (GET_CODE (index)) ! 243: { ! 244: case CONST_INT: ! 245: fprintf (stream, "@(%d,%s)", ! 246: INTVAL (index), ! 247: reg_names[REGNO (base)]); ! 248: break; ! 249: ! 250: case REG: ! 251: fprintf (stream, "@(r0,%s)", ! 252: reg_names[MAX (REGNO (base), REGNO (index))]); ! 253: ! 254: break; ! 255: ! 256: default: ! 257: debug_rtx (x); ! 258: ! 259: abort (); ! 260: } ! 261: } ! 262: ! 263: break; ! 264: case PRE_DEC: ! 265: fprintf (stream, "@-%s", reg_names[REGNO (XEXP (x, 0))]); ! 266: break; ! 267: ! 268: case POST_INC: ! 269: fprintf (stream, "@%s+", reg_names[REGNO (XEXP (x, 0))]); ! 270: break; ! 271: ! 272: default: ! 273: output_addr_const (stream, x); ! 274: break; ! 275: } ! 276: } ! 277: ! 278: /* Print operand x (an rtx) in assembler syntax to file stream ! 279: according to modifier code. ! 280: ! 281: '.' print a .s if insn needs delay slot ! 282: '*' print a local label ! 283: '^' increment the local label number ! 284: '!' dump the constant table ! 285: '#' output a nop if there is nothing to put in the delay slot ! 286: 'R' print the next register or memory location along, ie the lsw in ! 287: a double word value ! 288: 'O' print a constant without the # ! 289: 'M' print a constant as its negative ! 290: 'I' put something into the constant pool and print its label */ ! 291: ! 292: void ! 293: print_operand (stream, x, code) ! 294: FILE *stream; ! 295: rtx x; ! 296: int code; ! 297: { ! 298: switch (code) ! 299: { ! 300: ! 301: ! 302: case '.': ! 303: if (need_slot (final_sequence)) ! 304: fprintf (stream, ".s"); ! 305: break; ! 306: case '*': ! 307: fprintf (stream, "LF%d", lf); ! 308: break; ! 309: case '!': ! 310: dump_constants (0); ! 311: break; ! 312: case '^': ! 313: lf++; ! 314: break; ! 315: ! 316: case '#': ! 317: /* Output a nop if there's nothing in the delay slot */ ! 318: if (dbr_sequence_length () == 0) ! 319: { ! 320: fprintf (stream, "\n\tor r0,r0\t!wasted slot"); ! 321: } ! 322: break; ! 323: case 'O': ! 324: fprintf (asm_out_file, "%d", INTVAL (x)); ! 325: break; ! 326: ! 327: case 'I': ! 328: fprintf (asm_out_file, "LK%d", add_constant (x, SImode)); ! 329: break; ! 330: ! 331: case 'M': ! 332: fprintf (asm_out_file, "#%d", -INTVAL (x)); ! 333: break; ! 334: ! 335: case 'R': ! 336: /* Next location along in memory or register*/ ! 337: switch (GET_CODE (x)) ! 338: { ! 339: case REG: ! 340: fputs (reg_names[REGNO (x) + 1], (stream)); ! 341: break; ! 342: case MEM: ! 343: print_operand_address (stream, ! 344: XEXP (adj_offsettable_operand (x, 4), 0), 0); ! 345: break; ! 346: } ! 347: break; ! 348: ! 349: default: ! 350: switch (GET_CODE (x)) ! 351: { ! 352: case REG: ! 353: fputs (reg_names[REGNO (x)], (stream)); ! 354: break; ! 355: case MEM: ! 356: output_address (XEXP (x, 0)); ! 357: break; ! 358: default: ! 359: fputc ('#', stream); ! 360: output_addr_const (stream, x); ! 361: break; ! 362: ! 363: } ! 364: break; ! 365: } ! 366: } ! 367: ! 368: ! 369: ! 370: /* Define the offset between two registers, one to be eliminated, and ! 371: the other its replacement, at the start of a routine. */ ! 372: ! 373: int ! 374: initial_elimination_offset (from, to) ! 375: { ! 376: int regs_saved; ! 377: int d = calc_live_regs (®s_saved); ! 378: int total_saved_regs_space = (regs_saved) * 4; ! 379: int total_auto_space = get_frame_size (); ! 380: ! 381: ! 382: if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) ! 383: { ! 384: return total_saved_regs_space; ! 385: } ! 386: ! 387: if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) ! 388: { ! 389: return total_saved_regs_space + total_auto_space; ! 390: } ! 391: ! 392: if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) ! 393: { ! 394: return total_auto_space; ! 395: } ! 396: } ! 397: ! 398: ! 399: /* Prepare operands for a move define_expand; specifically, one of the ! 400: operands must be in a register. Take this chance to remove ! 401: addressing modes which can't be coped with very well. */ ! 402: ! 403: int ! 404: prepare_move_operands (operands, mode) ! 405: rtx operands[]; ! 406: enum machine_mode mode; ! 407: { ! 408: /* One of the operands has to be a register */ ! 409: if ((!register_operand (operands[0], mode) ! 410: && !register_operand (operands[1], mode)) ! 411: || GET_CODE (operands[1]) == PLUS) ! 412: { ! 413: /* copy the source to a register */ ! 414: operands[1] = copy_to_mode_reg (mode, operands[1]); ! 415: } ! 416: ! 417: /* If we've got a negative index, break it down */ ! 418: ! 419: if (GET_CODE (operands[0]) == MEM && !reload_in_progress) ! 420: { ! 421: ! 422: rtx inside = XEXP (operands[0], 0); ! 423: if (GET_CODE (inside) == PLUS) ! 424: { ! 425: rtx inside1 = XEXP (inside, 1); ! 426: if (GET_CODE (inside1) == CONST_INT ! 427: && INTVAL (inside1) < 0) ! 428: { ! 429: /* Catch this now and break it into bits, it will only cause ! 430: problems later */ ! 431: ! 432: rtx sub = copy_to_mode_reg (SImode, inside); ! 433: XEXP (operands[0], 0) = sub; ! 434: } ! 435: } ! 436: } ! 437: return 0; ! 438: } ! 439: ! 440: ! 441: /* Prepare the operands for an scc instruction; make sure that the ! 442: compare has been done. */ ! 443: rtx ! 444: prepare_scc_operands (code) ! 445: { ! 446: if (GET_CODE (sh_compare_op0) != REG ! 447: || REGNO (sh_compare_op0) != T_REG) ! 448: { ! 449: /* First need a compare insn */ ! 450: emit_insn (gen_rtx (SET, SImode, ! 451: gen_rtx (REG, SImode, T_REG), ! 452: gen_rtx (code, SImode, sh_compare_op0, ! 453: sh_compare_op1))); ! 454: } ! 455: return gen_rtx (REG, SImode, T_REG); ! 456: } ! 457: ! 458: ! 459: /* Functions to output assembly */ ! 460: ! 461: /* Return a sequence of instructions to perform DI or DF move. ! 462: ! 463: Since the SH cannot move a DI or DF in one instruction, we have ! 464: to take care when we see overlapping source and dest registers. ! 465: ! 466: */ ! 467: char * ! 468: output_movedouble (operands, mode) ! 469: rtx operands[]; ! 470: enum machine_mode mode; ! 471: { ! 472: rtx dst = operands[0]; ! 473: rtx src = operands[1]; ! 474: int lowfirst; ! 475: ! 476: if (register_operand (dst, mode) ! 477: && register_operand (src, mode)) ! 478: { ! 479: if (REGNO (src) == MACH_REG) ! 480: return "sts mach,%0\n\tsts macl,%R0"; ! 481: ! 482: /* ! 483: when mov.d r1,r2 do r2->r3 then r1->r2 ! 484: when mov.d r1,r0 do r1->r0 then r2->r1 ! 485: */ ! 486: ! 487: if (REGNO (src) + 1 == REGNO (dst)) ! 488: return "mov %1,%0\n\tmov %R1,%R0 ! cr"; ! 489: else ! 490: return "mov %R1,%R0\n\tmov %1,%0 "; ! 491: ! 492: } ! 493: else if (GET_CODE (src) == CONST_INT) ! 494: { ! 495: if (INTVAL (src) < 0) ! 496: return "mov #-1,%0\n\tmov %1,%R0"; ! 497: else ! 498: return "mov #0,%0\n\tmov %1,%R0"; ! 499: } ! 500: ! 501: else if (GET_CODE (src) == MEM) ! 502: { ! 503: int ptrreg1 = -1; ! 504: int ptrreg2 = -1; ! 505: int dreg = REGNO (dst); ! 506: rtx inside = XEXP (src, 0); ! 507: ! 508: if (GET_CODE (inside) == REG) ! 509: { ! 510: ptrreg1 = REGNO (inside); ! 511: } ! 512: else if (GET_CODE (inside) == PLUS) ! 513: { ! 514: rtx lhs = XEXP (inside, 0); ! 515: rtx rhs = XEXP (inside, 1); ! 516: if (GET_CODE (lhs) == REG) ! 517: ptrreg1 = REGNO (lhs); ! 518: if (GET_CODE (rhs) == REG) ! 519: ptrreg2 = REGNO (rhs); ! 520: } ! 521: else ! 522: abort (); ! 523: ! 524: ! 525: if ((ptrreg1 >= 0 && ptrreg2 >= 0) ! 526: && (dreg == ptrreg1 ! 527: || dreg == ptrreg2 ! 528: || dreg + 1 == ptrreg1 ! 529: || dreg + 1 == ptrreg2)) ! 530: { ! 531: /* This move clobbers both index registers, ! 532: calculate the sum in one register. */ ! 533: fprintf (asm_out_file, " add %s,%s ! special fix\n", ! 534: reg_names[ptrreg2], reg_names[ptrreg1]); ! 535: ! 536: if (dreg == ptrreg1) ! 537: { ! 538: /* Copy into dreg+1 first. */ ! 539: fprintf (asm_out_file, " mov.l @(4,%s),%s\n", ! 540: reg_names[ptrreg1], ! 541: reg_names[dreg + 1]); ! 542: ! 543: fprintf (asm_out_file, " mov.l @(%s),%s\n", ! 544: reg_names[ptrreg1], ! 545: reg_names[dreg]); ! 546: } ! 547: else ! 548: { ! 549: /* Copy into dreg first. */ ! 550: fprintf (asm_out_file, " mov.l @(%s),%s\n", ! 551: reg_names[ptrreg1], ! 552: reg_names[dreg]); ! 553: ! 554: fprintf (asm_out_file, " mov.l @(4,%s),%s\n", ! 555: reg_names[ptrreg1], ! 556: reg_names[dreg + 1]); ! 557: ! 558: } ! 559: warning ("generated complex amode"); ! 560: return ""; ! 561: } ! 562: ! 563: /* Work out the safe way to copy */ ! 564: if (dreg == ptrreg1) ! 565: { ! 566: /* Copy into the second half first */ ! 567: return "mov.l %R1,%R0\n\tmov.l %1,%0 ! cr"; ! 568: } ! 569: } ! 570: ! 571: return "mov.l %1,%0\n\tmov.l %R1,%R0"; ! 572: } ! 573: ! 574: /* Emit assembly to shift reg by k bits */ ! 575: ! 576: char * ! 577: output_shift (string, reg, k, code) ! 578: char *string; ! 579: rtx reg; ! 580: rtx k; ! 581: int code; ! 582: ! 583: { ! 584: int s = INTVAL (k); ! 585: ! 586: if (code == ASHIFT && s == 31) ! 587: { ! 588: /* Shift left by 31 moving into the t bit, clearing and rotating the other way */ ! 589: ! 590: fprintf (asm_out_file, "\trotr r%d\n", REGNO (reg)); ! 591: fprintf (asm_out_file, "\tmov #0,r%d\n", REGNO (reg)); ! 592: fprintf (asm_out_file, "\trotcr r%d\n", REGNO (reg)); ! 593: s = 0; ! 594: } ! 595: ! 596: if (code == LSHIFTRT && s == 31) ! 597: { ! 598: fprintf (asm_out_file, "\trotl r%d\n", REGNO (reg)); ! 599: fprintf (asm_out_file, "\tmov #0,r%d\n", REGNO (reg)); ! 600: fprintf (asm_out_file, "\trotcl r%d\n", REGNO (reg)); ! 601: s = 0; ! 602: } ! 603: ! 604: while (s) ! 605: { ! 606: char *out; ! 607: int d; ! 608: ! 609: if (s >= 16) ! 610: { ! 611: d = 16; ! 612: out = "16"; ! 613: } ! 614: else if (s >= 8) ! 615: { ! 616: d = 8; ! 617: out = "8"; ! 618: } ! 619: else if (s >= 2) ! 620: { ! 621: d = 2; ! 622: out = "2"; ! 623: } ! 624: else ! 625: { ! 626: d = 1; ! 627: out = ""; ! 628: } ! 629: fprintf (asm_out_file, "\t%s%s\tr%d\n", string, out, REGNO (reg)); ! 630: s -= d; ! 631: } ! 632: return ""; ! 633: } ! 634: ! 635: /* Return the text of the branch instruction which matches its length ! 636: attribute. ! 637: ! 638: This gets tricky if we have an insn in the delay slot of a branch ! 639: and the branch needs more than 1 insn to complete.*/ ! 640: ! 641: ! 642: ! 643: char * ! 644: output_branch (logic, insn) ! 645: int logic; ! 646: rtx insn; ! 647: { ! 648: extern rtx recog_operand[]; ! 649: int label = lf++; ! 650: int rn = -1; ! 651: int need_save; ! 652: ! 653: switch (get_attr_length (insn)) ! 654: { ! 655: case 2: ! 656: /* Simple branch in range -200..+200 bytes */ ! 657: return logic ? "bt%. %l0" : "bf%. %l0"; ! 658: ! 659: case 6: ! 660: /* Branch in range -4000..+4000 bytes */ ! 661: { ! 662: rtx oldop = recog_operand[0]; ! 663: ! 664: ! 665: if (need_slot (final_sequence)) ! 666: { ! 667: fprintf (asm_out_file, "\tb%c.s\tLF%d\n", logic ? 'f' : 't', ! 668: label); ! 669: ! 670: print_slot (final_sequence); ! 671: } ! 672: ! 673: else ! 674: { ! 675: fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', ! 676: label); ! 677: } ! 678: recog_operand[0] = oldop; ! 679: ! 680: output_asm_insn ("bra %l0 ! 12 bit cond ", recog_operand); ! 681: fprintf (asm_out_file, "\tor r0,r0\n"); ! 682: label = dump_constants (label); ! 683: fprintf (asm_out_file, "LF%d:\n", label); ! 684: } ! 685: ! 686: return ""; ! 687: ! 688: case 8: ! 689: /* Branches a long way away */ ! 690: { ! 691: ! 692: rtx oldop = recog_operand[0]; ! 693: ! 694: if (need_slot (final_sequence)) ! 695: { ! 696: fprintf (asm_out_file, "\tb%c.s\tLF%d\n", logic ? 'f' : 't', label); ! 697: print_slot (final_sequence); ! 698: ! 699: } ! 700: else ! 701: { ! 702: fprintf (asm_out_file, "\tb%c\tLF%d\n", logic ? 'f' : 't', label); ! 703: } ! 704: ! 705: recog_operand[0] = oldop; ! 706: ! 707: /* We use r13 as a scratch */ ! 708: need_save = 0; ! 709: rn = 13; ! 710: ! 711: if (need_save) ! 712: fprintf (asm_out_file, "\tpush r%d\n", rn); ! 713: fprintf (asm_out_file, "\tmov.l LK%d,r%d\n", add_constant (oldop, SImode), rn); ! 714: fprintf (asm_out_file, "\tjmp @r%d ! 32 cond \n", rn); ! 715: if (need_save) ! 716: fprintf (asm_out_file, "\tpop r%d\n", rn); ! 717: else ! 718: fprintf (asm_out_file, "\tor r0,r0\n"); ! 719: fprintf (asm_out_file, "LF%d:\n", label); ! 720: return ""; ! 721: } ! 722: } ! 723: return "bad"; ! 724: } ! 725: ! 726: ! 727: /* Predicates used by the templates */ ! 728: ! 729: /* Non zero if op is an immediate ok for a byte index */ ! 730: ! 731: int ! 732: byte_index_operand (op, mode) ! 733: rtx op; ! 734: enum machine_mode mode; ! 735: { ! 736: return (GET_CODE (op) == CONST_INT ! 737: && INTVAL (op) >= 0 && INTVAL (op) <= 15); ! 738: } ! 739: ! 740: /* Non zero if OP is a pop operand */ ! 741: ! 742: int ! 743: pop_operand (op, mode) ! 744: rtx op; ! 745: enum machine_mode mode; ! 746: { ! 747: if (GET_CODE (op) != MEM) ! 748: return 0; ! 749: ! 750: if (GET_MODE (op) != mode) ! 751: return 0; ! 752: ! 753: op = XEXP (op, 0); ! 754: ! 755: if (GET_CODE (op) != POST_INC) ! 756: return 0; ! 757: ! 758: return XEXP (op, 0) == stack_pointer_rtx; ! 759: } ! 760: ! 761: /* Non zero if OP is an immediate which can be made from two insns. */ ! 762: ! 763: int ! 764: painful_immediate_operand (op, mode) ! 765: rtx op; ! 766: enum machine_mode mode; ! 767: { ! 768: if (GET_CODE (op) == CONST_INT) ! 769: { ! 770: int i = INTVAL (op); ! 771: ! 772: if (i > 127 && i < 255) ! 773: return 1; /* two adds */ ! 774: } ! 775: return 0; ! 776: } ! 777: ! 778: ! 779: /* Non zero if OP can be source of a simple move operation. */ ! 780: ! 781: int ! 782: general_movsrc_operand (op, mode) ! 783: rtx op; ! 784: enum machine_mode mode; ! 785: { ! 786: if (GET_CODE (op) == REG ! 787: || GET_CODE (op) == SUBREG ! 788: || (GET_CODE (op) == CONST_INT && ! 789: CONST_OK_FOR_I (INTVAL (op))) ! 790: || GET_CODE (op) == MEM) ! 791: return general_operand (op, mode); ! 792: return 0; ! 793: } ! 794: ! 795: ! 796: ! 797: /* Nonzero if OP is a normal arithmetic register. */ ! 798: ! 799: int ! 800: arith_reg_operand (op, mode) ! 801: rtx op; ! 802: enum machine_mode mode; ! 803: { ! 804: if (register_operand (op, mode)) ! 805: { ! 806: if (GET_CODE (op) == REG) ! 807: return REGNO (op) != T_REG; ! 808: return 1; ! 809: } ! 810: return 0; ! 811: } ! 812: ! 813: ! 814: /* Nonzero if OP is a valid source operand for an arithmetic insn. */ ! 815: ! 816: int ! 817: arith_operand (op, mode) ! 818: rtx op; ! 819: enum machine_mode mode; ! 820: { ! 821: if (register_operand (op, mode)) ! 822: return 1; ! 823: ! 824: if (GET_CODE (op) == CONST_INT) ! 825: { ! 826: if (CONST_OK_FOR_I (INTVAL (op))) ! 827: return 1; ! 828: } ! 829: return 0; ! 830: } ! 831: ! 832: ! 833: /* Nonzero if OP is a valid source operand for a logical operation */ ! 834: ! 835: int ! 836: logical_operand (op, mode) ! 837: rtx op; ! 838: enum machine_mode mode; ! 839: { ! 840: if (register_operand (op, mode)) ! 841: return 1; ! 842: ! 843: if (GET_CODE (op) == CONST_INT) ! 844: { ! 845: if (CONST_OK_FOR_L (INTVAL (op))) ! 846: return 1; ! 847: } ! 848: return 0; ! 849: } ! 850: ! 851: /* Nonzero if p is a valid shift operand for lshr and ashl */ ! 852: ! 853: int ! 854: ok_shift_value (p) ! 855: rtx p; ! 856: { ! 857: if (GET_CODE (p) == CONST_INT) ! 858: { ! 859: switch (INTVAL (p)) ! 860: { ! 861: case 1: ! 862: case 2: ! 863: case 8: ! 864: case 16: ! 865: return 1; ! 866: default: ! 867: if (TARGET_FASTCODE) ! 868: return INTVAL (p) >= 0; ! 869: } ! 870: } ! 871: return 0; ! 872: } ! 873: ! 874: /* Nonzero if the arg is an immediate which has to be loaded from ! 875: memory */ ! 876: ! 877: int ! 878: hard_immediate_operand (op, mode) ! 879: rtx op; ! 880: enum machine_mode mode; ! 881: { ! 882: if (immediate_operand (op, mode)) ! 883: { ! 884: if (GET_CODE (op) == CONST_INT ! 885: && INTVAL (op) >= -128 && INTVAL (op) < 127) ! 886: return 0; ! 887: return 1; ! 888: } ! 889: return 0; ! 890: } ! 891: ! 892: /* The SH cannot load a large constant into a register, constants have to ! 893: come from a pc relative load. The reference of a pc relative load ! 894: instruction must be less than 1k infront of the instruction. This ! 895: means that we often have to dump a constant inside a function, and ! 896: generate code to branch around it. ! 897: ! 898: It is important to minimize this, since the branches will slow things ! 899: down and make things bigger. ! 900: ! 901: Worst case code looks like: ! 902: ! 903: mov.l L1,rn ! 904: bra L2 ! 905: nop ! 906: align ! 907: L1: .long value ! 908: L2: ! 909: .. ! 910: ! 911: mov.l L3,rn ! 912: bra L4 ! 913: nop ! 914: align ! 915: L3: .long value ! 916: L4: ! 917: .. ! 918: ! 919: During shorten_branches we notice the instructions which can have a ! 920: constant table in them, if we see two that are close enough ! 921: together, we move the constants from the first table to the second ! 922: table and continue. This process can happen again and again, and ! 923: in the best case, moves the constant table outside of the function. ! 924: ! 925: In the above example, we can tell that L3 is within 1k of L1, so ! 926: the first move can be shrunk from the 3 insn+constant sequence into ! 927: just 1 insn, and the constant moved to L3 to make: ! 928: ! 929: mov.l L1,rn ! 930: .. ! 931: mov.l L3,rn ! 932: bra L4 ! 933: nop ! 934: align ! 935: L3:.long value ! 936: L4:.long value ! 937: ! 938: Then the second move becomes the target for the shortening process. ! 939: ! 940: We keep a simple list of all the constants accumulated in the ! 941: current pool so there are no duplicates in a single table, but ! 942: they are not factored into the size estimates. ! 943: ! 944: */ ! 945: ! 946: typedef struct ! 947: { ! 948: rtx value; ! 949: int number; ! 950: enum machine_mode mode; ! 951: } pool_node; ! 952: ! 953: /* The maximum number of constants that can fit into one pool, since ! 954: the pc relative range is 0...1020 bytes and constants are at least 4 ! 955: bytes long */ ! 956: ! 957: #define MAX_POOL_SIZE (1020/4) ! 958: static pool_node pool_vector[MAX_POOL_SIZE]; ! 959: static int pool_size; ! 960: ! 961: ! 962: /* Add a constant to the pool and return its label number. */ ! 963: ! 964: static int ! 965: add_constant (x, mode) ! 966: rtx x; ! 967: enum machine_mode mode; ! 968: { ! 969: int i; ! 970: ! 971: /* Start the countdown on the first constant */ ! 972: ! 973: if (!pool_size) ! 974: { ! 975: first_pc = pc; ! 976: } ! 977: ! 978: /* First see if we've already got it */ ! 979: ! 980: for (i = 0; i < pool_size; i++) ! 981: { ! 982: ! 983: if (x->code == pool_vector[i].value->code ! 984: && mode == pool_vector[i].mode) ! 985: { ! 986: if (x->code == CODE_LABEL) ! 987: { ! 988: if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) ! 989: continue; ! 990: } ! 991: } ! 992: ! 993: if (rtx_equal_p (x, pool_vector[i].value)) ! 994: return pool_vector[i].number; ! 995: } ! 996: ! 997: ! 998: pool_vector[pool_size].value = x; ! 999: pool_vector[pool_size].mode = mode; ! 1000: pool_vector[pool_size].number = lf; ! 1001: pool_size++; ! 1002: ! 1003: return lf++; ! 1004: } ! 1005: ! 1006: /* Nonzero if the insn could take a constant table. */ ! 1007: ! 1008: static int ! 1009: has_constant_table (insn) ! 1010: rtx insn; ! 1011: { ! 1012: rtx body; ! 1013: ! 1014: if (GET_CODE (insn) == NOTE ! 1015: || GET_CODE (insn) == BARRIER ! 1016: || GET_CODE (insn) == CODE_LABEL) ! 1017: return 0; ! 1018: ! 1019: body = PATTERN (insn); ! 1020: if (GET_CODE (body) == SEQUENCE) ! 1021: return 0; ! 1022: if (GET_CODE (body) == ADDR_VEC) ! 1023: return 0; ! 1024: if (GET_CODE (body) == USE) ! 1025: return 0; ! 1026: if (GET_CODE (body) == CLOBBER) ! 1027: return 0; ! 1028: if (get_attr_constneed (insn) == CONSTNEED_YES) ! 1029: return 1; ! 1030: ! 1031: if (GET_CODE (body) == UNSPEC_VOLATILE) ! 1032: { ! 1033: return INTVAL (XVECEXP (body, 0, 0)) == 1; ! 1034: } ! 1035: return 0; ! 1036: } ! 1037: ! 1038: /* Adjust the length of an instruction. ! 1039: ! 1040: We'll look at the previous instruction which holds a constant ! 1041: table and see if we can move the table to here instead. */ ! 1042: ! 1043: int target_insn_uid; ! 1044: int target_insn_smallest_size; ! 1045: ! 1046: int target_pc; ! 1047: int target_insn_range; ! 1048: int current_pc; ! 1049: int pool_bytes; ! 1050: ! 1051: int last_uid; ! 1052: int last_pc; ! 1053: ! 1054: void ! 1055: adjust_insn_length (insn, insn_lengths) ! 1056: rtx insn; ! 1057: short *insn_lengths; ! 1058: { ! 1059: int uid = INSN_UID (insn); ! 1060: rtx body = PATTERN (insn); ! 1061: ! 1062: current_pc += insn_lengths[uid]; ! 1063: ! 1064: ! 1065: if (GET_CODE (body) == SEQUENCE) ! 1066: { ! 1067: int i; ! 1068: ! 1069: for (i = 0; i < XVECLEN (body, 0); i++) ! 1070: { ! 1071: adjust_insn_length (XVECEXP (body, 0, i), insn_lengths); ! 1072: } ! 1073: } ! 1074: else ! 1075: { ! 1076: if (has_constant_table (insn)) ! 1077: { ! 1078: if (current_pc >= target_insn_range) ! 1079: { ! 1080: /* This instruction is further away from the referencing ! 1081: instruction than it can reach, so we'll stop accumulating ! 1082: from that one and start fresh. */ ! 1083: target_pc = current_pc; ! 1084: target_insn_range = current_pc + MAYBE_DUMP_LEVEL; ! 1085: } ! 1086: else ! 1087: { ! 1088: /* This instruction is within the reach of the target, ! 1089: remove the constant table from the target by adjusting ! 1090: downwards, and increase the size of this one to ! 1091: compensate. */ ! 1092: ! 1093: ! 1094: /* Add the stuff from this insn to what will go in the ! 1095: growing table. */ ! 1096: ! 1097: pool_bytes += get_attr_constantsize (insn); ! 1098: ! 1099: /* The target shinks to its smallest natural size */ ! 1100: insn_lengths[target_insn_uid] = target_insn_smallest_size; ! 1101: ! 1102: /* The current insn grows to be its larger size plust the ! 1103: table size. */ ! 1104: ! 1105: insn_lengths[uid] = get_attr_largestsize (insn) + pool_bytes; ! 1106: ! 1107: } ! 1108: /* Current insn becomes the target. */ ! 1109: target_insn_uid = uid; ! 1110: target_insn_smallest_size = get_attr_smallestsize (insn); ! 1111: ! 1112: } ! 1113: } ! 1114: } ! 1115: ! 1116: ! 1117: ! 1118: /* Dump out the pending constant pool. ! 1119: If label provided then insert an branch in the middle of the table ! 1120: */ ! 1121: ! 1122: int ! 1123: dump_constants (label) ! 1124: { ! 1125: int i; ! 1126: int rlabel = label; ! 1127: int size = 0; ! 1128: ! 1129: if (pool_size) ! 1130: { ! 1131: fprintf (asm_out_file, "\n\t! constants - waited %d\n", pc - first_pc); ! 1132: fprintf (asm_out_file, "\t.align\t2\n"); ! 1133: ! 1134: for (i = 0; i < pool_size; i++) ! 1135: { ! 1136: pool_node *p = pool_vector + i; ! 1137: ! 1138: fprintf (asm_out_file, "LK%d:", p->number); ! 1139: size += GET_MODE_SIZE (p->mode); ! 1140: ! 1141: switch (GET_MODE_CLASS (p->mode)) ! 1142: { ! 1143: case MODE_INT: ! 1144: case MODE_PARTIAL_INT: ! 1145: assemble_integer (p->value, GET_MODE_SIZE (p->mode), 1); ! 1146: break; ! 1147: case MODE_FLOAT: ! 1148: { ! 1149: union real_extract u; ! 1150: bcopy (&CONST_DOUBLE_LOW (p->value), &u, sizeof u); ! 1151: assemble_real (u.d, p->mode); ! 1152: } ! 1153: } ! 1154: ! 1155: /* After 200 bytes of table, stick in another branch */ ! 1156: if (label && size > 200) ! 1157: { ! 1158: rlabel = lf++; ! 1159: fprintf (asm_out_file, "LF%d:\tbra LF%d\n", label, rlabel); ! 1160: fprintf (asm_out_file, "\tor r0,r0\n"); ! 1161: label = 0; ! 1162: } ! 1163: ! 1164: } ! 1165: } ! 1166: ! 1167: pool_size = 0; ! 1168: current_pc = 0; ! 1169: pc = 0; ! 1170: pool_bytes = 0; ! 1171: ! 1172: target_insn_range = 0; ! 1173: return rlabel; ! 1174: ! 1175: } ! 1176: ! 1177: ! 1178: /* Emit the text to load a value from a constant table. */ ! 1179: ! 1180: char * ! 1181: output_movepcrel (insn, operands, mode) ! 1182: rtx insn; ! 1183: rtx operands[]; ! 1184: enum machine_mode mode; ! 1185: { ! 1186: int len = GET_MODE_SIZE (mode); ! 1187: int rn = REGNO (operands[0]); ! 1188: ! 1189: fprintf (asm_out_file, "\tmov.l LK%d,r%d\n", ! 1190: add_constant (operands[1], mode), rn); ! 1191: ! 1192: if (GET_MODE_SIZE (mode) > 4) ! 1193: { ! 1194: fprintf (asm_out_file, ! 1195: "\tmov.l LK%d+4,r%d\n", ! 1196: add_constant (operands[1], mode), ! 1197: rn + 1); ! 1198: ! 1199: } ! 1200: ! 1201: /* This may have been the last move in the function, so nothing ! 1202: took its constant table, we may be able to move it past the end ! 1203: of the function (after the rts) if we are careful */ ! 1204: ! 1205: if (target_insn_uid == INSN_UID (insn) ! 1206: && current_pc < target_insn_range) ! 1207: return ""; ! 1208: ! 1209: ! 1210: /* If this instruction is as small as it can be, there can be no ! 1211: constant table attached to it. */ ! 1212: if (get_attr_length (insn) != get_attr_smallestsize (insn)) ! 1213: { ! 1214: /* This needs a constant table */ ! 1215: fprintf (asm_out_file, "\t!constant table start\n"); ! 1216: fprintf (asm_out_file, "\tbra LF%d\n", lf); ! 1217: fprintf (asm_out_file, "\tor r0,r0 ! wasted slot\n"); ! 1218: dump_constants (0); ! 1219: fprintf (asm_out_file, "LF%d:\n", lf++); ! 1220: fprintf (asm_out_file, "\t!constant table end\n"); ! 1221: } ! 1222: return ""; ! 1223: } ! 1224: ! 1225: ! 1226: /* Dump out interesting debug info */ ! 1227: ! 1228: rtx ! 1229: final_prescan_insn (insn, opvec, noperands) ! 1230: rtx insn; ! 1231: rtx *opvec; ! 1232: int noperands; ! 1233: { ! 1234: register rtx body = PATTERN (insn); ! 1235: ! 1236: if (target_flags & ISIZE_BIT) ! 1237: { ! 1238: extern int *insn_addresses; ! 1239: ! 1240: fprintf (asm_out_file, "\n!%04x*\n", ! 1241: insn_addresses[INSN_UID (insn)] + 0x10); ! 1242: ! 1243: fprintf (asm_out_file, "\n!%04x %d %04x len=%d\n", ! 1244: pc, pool_size, first_pc, get_attr_length (insn)); ! 1245: ! 1246: if (TARGET_DUMP_RTL) ! 1247: print_rtl (asm_out_file, body); ! 1248: ! 1249: ! 1250: } ! 1251: ! 1252: pc += get_attr_length (insn); ! 1253: if (pool_size && pc - first_pc > MUST_DUMP_LEVEL) ! 1254: { ! 1255: /* For some reason we have not dumped out a constant table, and ! 1256: we have emitted a lot of code. This can happen if the think ! 1257: which wants the table is a long conditional branch (which has no ! 1258: room for a constant table), and there has not been a move ! 1259: constant anywhere. */ ! 1260: int label = lf++; ! 1261: fprintf (asm_out_file, "\t!forced constant table\n"); ! 1262: fprintf (asm_out_file, "\tbra LF%d\n", label); ! 1263: fprintf (asm_out_file, "\tor r0,r0 ! wasted slot\n"); ! 1264: label = dump_constants (label); ! 1265: fprintf (asm_out_file, "LF%d:\n", label); ! 1266: fprintf (asm_out_file, "\t!constant table end\n"); ! 1267: } ! 1268: } ! 1269: ! 1270: ! 1271: ! 1272: /* Block move stuff stolen from m88k*/ ! 1273: ! 1274: /* Emit code to perform a block move. Choose the best method. ! 1275: ! 1276: OPERANDS[0] is the destination. ! 1277: OPERANDS[1] is the source. ! 1278: OPERANDS[2] is the size. ! 1279: OPERANDS[3] is the alignment safe to use. */ ! 1280: ! 1281: /* Emit code to perform a block move with an offset sequence of ld/st ! 1282: instructions (..., ld 0, st 1, ld 1, st 0, ...). SIZE and ALIGN are ! 1283: known constants. DEST and SRC are registers. OFFSET is the known ! 1284: starting point for the output pattern. */ ! 1285: ! 1286: static enum machine_mode mode_from_align[] = ! 1287: {VOIDmode, QImode, HImode, VOIDmode, SImode, ! 1288: VOIDmode, VOIDmode, VOIDmode, DImode}; ! 1289: static void ! 1290: ! 1291: block_move_sequence (dest, dest_mem, src, src_mem, size, align, offset) ! 1292: rtx dest, dest_mem; ! 1293: rtx src, src_mem; ! 1294: int size; ! 1295: int align; ! 1296: int offset; ! 1297: { ! 1298: rtx temp[2]; ! 1299: enum machine_mode mode[2]; ! 1300: int amount[2]; ! 1301: int active[2]; ! 1302: int phase = 0; ! 1303: int next; ! 1304: int offset_ld = offset; ! 1305: int offset_st = offset; ! 1306: ! 1307: active[0] = active[1] = FALSE; ! 1308: ! 1309: /* Establish parameters for the first load and for the second load if ! 1310: it is known to be the same mode as the first. */ ! 1311: amount[0] = amount[1] = align; ! 1312: ! 1313: ! 1314: mode[0] = mode_from_align[align]; ! 1315: ! 1316: temp[0] = gen_reg_rtx (mode[0]); ! 1317: if (size >= 2 * align) ! 1318: { ! 1319: mode[1] = mode[0]; ! 1320: temp[1] = gen_reg_rtx (mode[1]); ! 1321: } ! 1322: ! 1323: do ! 1324: { ! 1325: rtx srcp, dstp; ! 1326: next = phase; ! 1327: phase = !phase; ! 1328: ! 1329: if (size > 0) ! 1330: { ! 1331: /* Change modes as the sequence tails off. */ ! 1332: if (size < amount[next]) ! 1333: { ! 1334: amount[next] = (size >= 4 ? 4 : (size >= 2 ? 2 : 1)); ! 1335: mode[next] = mode_from_align[amount[next]]; ! 1336: temp[next] = gen_reg_rtx (mode[next]); ! 1337: } ! 1338: size -= amount[next]; ! 1339: srcp = gen_rtx (MEM, ! 1340: MEM_IN_STRUCT_P (src_mem) ? mode[next] : BLKmode, ! 1341: gen_rtx (PLUS, Pmode, src, ! 1342: gen_rtx (CONST_INT, SImode, offset_ld))); ! 1343: RTX_UNCHANGING_P (srcp) = RTX_UNCHANGING_P (src_mem); ! 1344: MEM_VOLATILE_P (srcp) = MEM_VOLATILE_P (src_mem); ! 1345: MEM_IN_STRUCT_P (srcp) = 1; ! 1346: emit_insn (gen_rtx (SET, VOIDmode, temp[next], srcp)); ! 1347: offset_ld += amount[next]; ! 1348: active[next] = TRUE; ! 1349: } ! 1350: ! 1351: if (active[phase]) ! 1352: { ! 1353: active[phase] = FALSE; ! 1354: dstp = gen_rtx (MEM, ! 1355: MEM_IN_STRUCT_P (dest_mem) ? mode[phase] : BLKmode, ! 1356: gen_rtx (PLUS, Pmode, dest, ! 1357: gen_rtx (CONST_INT, SImode, offset_st))); ! 1358: RTX_UNCHANGING_P (dstp) = RTX_UNCHANGING_P (dest_mem); ! 1359: MEM_VOLATILE_P (dstp) = MEM_VOLATILE_P (dest_mem); ! 1360: MEM_IN_STRUCT_P (dstp) = 1; ! 1361: emit_insn (gen_rtx (SET, VOIDmode, dstp, temp[phase])); ! 1362: offset_st += amount[phase]; ! 1363: } ! 1364: } ! 1365: while (active[next]); ! 1366: } ! 1367: ! 1368: void ! 1369: expand_block_move (dest_mem, src_mem, operands) ! 1370: rtx dest_mem; ! 1371: rtx src_mem; ! 1372: rtx *operands; ! 1373: { ! 1374: int align = INTVAL (operands[3]); ! 1375: int constp = (GET_CODE (operands[2]) == CONST_INT); ! 1376: int bytes = (constp ? INTVAL (operands[2]) : 0); ! 1377: ! 1378: #if 0 ! 1379: if (constp && bytes <= 0) ! 1380: return; ! 1381: ! 1382: if (align > 4) ! 1383: align = 4; ! 1384: ! 1385: if (constp && bytes <= 3 * align) ! 1386: block_move_sequence (operands[0], dest_mem, operands[1], src_mem, ! 1387: bytes, align, 0); ! 1388: ! 1389: #if 0 ! 1390: else if (constp && bytes <= best_from_align[target][align]) ! 1391: block_move_no_loop (operands[0], dest_mem, operands[1], src_mem, ! 1392: bytes, align); ! 1393: ! 1394: else if (constp && align == 4 && TARGET_88100) ! 1395: block_move_loop (operands[0], dest_mem, operands[1], src_mem, ! 1396: bytes, align); ! 1397: #endif ! 1398: else ! 1399: #endif ! 1400: { ! 1401: emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0, ! 1402: VOIDmode, 3, ! 1403: operands[0], Pmode, ! 1404: operands[1], Pmode, ! 1405: operands[2], SImode); ! 1406: } ! 1407: } ! 1408: ! 1409: ! 1410: override_options () ! 1411: { ! 1412: sh_cpu = CPU_SH0; ! 1413: if (TARGET_SH1) ! 1414: sh_cpu = CPU_SH1; ! 1415: if (TARGET_SH2) ! 1416: sh_cpu = CPU_SH2; ! 1417: if (TARGET_SH3) ! 1418: sh_cpu = CPU_SH3; ! 1419: } ! 1420: ! 1421: ! 1422: /* Stuff taken from m88k.c */ ! 1423: ! 1424: /* Output to FILE the start of the assembler file. */ ! 1425: ! 1426: struct option ! 1427: { ! 1428: char *string; ! 1429: int *variable; ! 1430: int on_value; ! 1431: }; ! 1432: ! 1433: static int ! 1434: output_option (file, sep, type, name, indent, pos, max) ! 1435: FILE *file; ! 1436: char *sep; ! 1437: char *type; ! 1438: char *name; ! 1439: char *indent; ! 1440: int pos; ! 1441: int max; ! 1442: { ! 1443: if (strlen (sep) + strlen (type) + strlen (name) + pos > max) ! 1444: { ! 1445: fprintf (file, indent); ! 1446: return fprintf (file, "%s%s", type, name); ! 1447: } ! 1448: return pos + fprintf (file, "%s%s%s", sep, type, name); ! 1449: } ! 1450: ! 1451: static struct ! 1452: { ! 1453: char *name; ! 1454: int value; ! 1455: } ! 1456: ! 1457: m_options[] = TARGET_SWITCHES; ! 1458: ! 1459: static void ! 1460: output_options (file, f_options, f_len, W_options, W_len, ! 1461: pos, max, sep, indent, term) ! 1462: FILE *file; ! 1463: struct option *f_options; ! 1464: struct option *W_options; ! 1465: int f_len, W_len; ! 1466: int pos; ! 1467: int max; ! 1468: char *sep; ! 1469: char *indent; ! 1470: char *term; ! 1471: { ! 1472: register int j; ! 1473: ! 1474: ! 1475: if (optimize) ! 1476: pos = output_option (file, sep, "-O", "", indent, pos, max); ! 1477: if (write_symbols != NO_DEBUG) ! 1478: pos = output_option (file, sep, "-g", "", indent, pos, max); ! 1479: if (flag_traditional) ! 1480: pos = output_option (file, sep, "-traditional", "", indent, pos, max); ! 1481: if (profile_flag) ! 1482: pos = output_option (file, sep, "-p", "", indent, pos, max); ! 1483: if (profile_block_flag) ! 1484: pos = output_option (file, sep, "-a", "", indent, pos, max); ! 1485: ! 1486: for (j = 0; j < f_len; j++) ! 1487: if (*f_options[j].variable == f_options[j].on_value) ! 1488: pos = output_option (file, sep, "-f", f_options[j].string, ! 1489: indent, pos, max); ! 1490: ! 1491: for (j = 0; j < W_len; j++) ! 1492: if (*W_options[j].variable == W_options[j].on_value) ! 1493: pos = output_option (file, sep, "-W", W_options[j].string, ! 1494: indent, pos, max); ! 1495: ! 1496: for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++) ! 1497: if (m_options[j].name[0] != '\0' ! 1498: && m_options[j].value > 0 ! 1499: && ((m_options[j].value & target_flags) ! 1500: == m_options[j].value)) ! 1501: pos = output_option (file, sep, "-m", m_options[j].name, ! 1502: indent, pos, max); ! 1503: ! 1504: ! 1505: fprintf (file, term); ! 1506: } ! 1507: ! 1508: void ! 1509: output_file_start (file, f_options, f_len, W_options, W_len) ! 1510: FILE *file; ! 1511: struct option *f_options; ! 1512: struct option *W_options; ! 1513: int f_len, W_len; ! 1514: { ! 1515: register int pos; ! 1516: ! 1517: output_file_directive (file, main_input_filename); ! 1518: ! 1519: /* Switch to the data section so that the coffsem symbol and the ! 1520: gcc2_compiled. symbol aren't in the text section. */ ! 1521: data_section (); ! 1522: ! 1523: ! 1524: pos = fprintf (file, "\n! Hitachi SH cc1 (%s) arguments:", version_string); ! 1525: output_options (file, f_options, f_len, W_options, W_len, ! 1526: pos, 75, " ", "\n! ", "\n\n"); ! 1527: } ! 1528: ! 1529: ! 1530: /* Code to generate prologue and epilogue sequences */ ! 1531: ! 1532: void ! 1533: sh_expand_prologue () ! 1534: { ! 1535: int live_regs_mask; ! 1536: int d; ! 1537: ! 1538: live_regs_mask = calc_live_regs (&d); ! 1539: ! 1540: output_stack_adjust (-1, current_function_pretend_args_size); ! 1541: ! 1542: if (current_function_anonymous_args) ! 1543: { ! 1544: /* Push arg regs as if they'd been provided by caller in stack */ ! 1545: int i; ! 1546: for (i = 0; i < NPARM_REGS; i++) ! 1547: { ! 1548: int rn = NPARM_REGS + FIRST_PARM_REG - i - 1; ! 1549: if (i > NPARM_REGS - current_function_args_info) ! 1550: break; ! 1551: push (rn); ! 1552: ! 1553: extra_push += 4; ! 1554: } ! 1555: } ! 1556: ! 1557: if (frame_pointer_needed) ! 1558: { ! 1559: push_regs (live_regs_mask); ! 1560: emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); ! 1561: } ! 1562: else ! 1563: { ! 1564: push_regs (live_regs_mask); ! 1565: } ! 1566: ! 1567: output_stack_adjust (-1, get_frame_size ()); ! 1568: } ! 1569: ! 1570: void ! 1571: sh_expand_epilogue () ! 1572: { ! 1573: int live_regs_mask; ! 1574: int d; ! 1575: int i; ! 1576: ! 1577: live_regs_mask = calc_live_regs (&d); ! 1578: ! 1579: if (frame_pointer_needed) ! 1580: { ! 1581: emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx)); ! 1582: } ! 1583: else ! 1584: { ! 1585: output_stack_adjust (1, get_frame_size ()); ! 1586: } ! 1587: ! 1588: ! 1589: /* Pop all the registers */ ! 1590: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ! 1591: { ! 1592: int j = (FIRST_PSEUDO_REGISTER - 1) - i; ! 1593: if (live_regs_mask & (1 << j)) ! 1594: { ! 1595: pop (j); ! 1596: } ! 1597: } ! 1598: output_stack_adjust (1, extra_push + ! 1599: current_function_pretend_args_size); ! 1600: ! 1601: extra_push = 0; ! 1602: ! 1603: current_function_anonymous_args = 0; ! 1604: } ! 1605: ! 1606: ! 1607: /* Return the cost of a shift */ ! 1608: ! 1609: int ! 1610: shiftcosts (RTX) ! 1611: rtx RTX; ! 1612: { ! 1613: /* If shift by a non constant, then this will be expensive. */ ! 1614: if (GET_CODE (XEXP (RTX, 1)) != CONST_INT) ! 1615: return 20; ! 1616: ! 1617: /* otherwise, it will be very cheap if by one of the constants ! 1618: we can cope with. */ ! 1619: if (CONST_OK_FOR_K (INTVAL (XEXP (RTX, 1)))) ! 1620: return 1; ! 1621: ! 1622: /* otherwise it will be several insns. */ ! 1623: return 4; ! 1624: } ! 1625: ! 1626: /* Return the cost of a multiply */ ! 1627: int ! 1628: multcosts (RTX) ! 1629: rtx RTX; ! 1630: { ! 1631: /* If we we're aiming at small code, then just count the number of ! 1632: insns in a multiply call sequence, otherwise, count all the insnsn ! 1633: inside the call. */ ! 1634: if (TARGET_SMALLCODE) ! 1635: return 3; ! 1636: return 30; ! 1637: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.