|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Hitachi H8/300. ! 2: Copyright (C) 1992,1993 Free Software Foundation, Inc. ! 3: ! 4: Contributed by Steve Chamberlain ([email protected]) and ! 5: Jim Wilson ([email protected]). ! 6: ! 7: This file is part of GNU CC. ! 8: ! 9: GNU CC is free software; you can redistribute it and/or modify ! 10: it under the terms of the GNU General Public License as published by ! 11: the Free Software Foundation; either version 2, or (at your option) ! 12: any later version. ! 13: ! 14: GNU CC is distributed in the hope that it will be useful, ! 15: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 16: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 17: GNU General Public License for more details. ! 18: ! 19: You should have received a copy of the GNU General Public License ! 20: along with GNU CC; see the file COPYING. If not, write to ! 21: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 22: ! 23: #include <stdio.h> ! 24: #include "config.h" ! 25: #include "rtl.h" ! 26: #include "regs.h" ! 27: #include "hard-reg-set.h" ! 28: #include "real.h" ! 29: #include "insn-config.h" ! 30: #include "conditions.h" ! 31: #include "insn-flags.h" ! 32: #include "output.h" ! 33: #include "insn-attr.h" ! 34: #include "flags.h" ! 35: #include "recog.h" ! 36: #include "expr.h" ! 37: #include "tree.h" ! 38: ! 39: /* Forward declarations. */ ! 40: void print_operand_address (); ! 41: char *index (); ! 42: ! 43: /* True if a #pragma interrupt has been seen for the current function. */ ! 44: int pragma_interrupt; ! 45: ! 46: /* True if a #pragma saveall has been seen for the current function. */ ! 47: int pragma_saveall; ! 48: ! 49: char *names_big[] ! 50: = {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7"}; ! 51: ! 52: char * ! 53: byte_reg (x, b) ! 54: rtx x; ! 55: int b; ! 56: { ! 57: static char *names_small[] ! 58: = {"r0l", "r0h", "r1l", "r1h", "r2l", "r2h", "r3l", "r3h", ! 59: "r4l", "r4h", "r5l", "r5h", "r6l", "r6h", "r7lBAD", "r7hBAD"}; ! 60: ! 61: return names_small[REGNO (x) * 2 + b]; ! 62: } ! 63: ! 64: /* REGNO must be saved/restored across calls if this macro is true. */ ! 65: static int ! 66: word_reg_used (regno) ! 67: int regno; ! 68: { ! 69: if (regno < 7 ! 70: && (pragma_interrupt || pragma_saveall ! 71: || (regno == FRAME_POINTER_REGNUM && regs_ever_live[regno]) ! 72: || (regs_ever_live[regno] & ! call_used_regs[regno]))) ! 73: return 1; ! 74: return 0; ! 75: } ! 76: ! 77: /* Output assembly language to FILE for the operation OP with operand size ! 78: SIZE. */ ! 79: static void ! 80: dosize (file, op, size, fped) ! 81: FILE *file; ! 82: char *op; ! 83: unsigned int size; ! 84: int fped; ! 85: { ! 86: switch (size) ! 87: { ! 88: case 4: ! 89: case 3: ! 90: fprintf (file, "\t%ss\t#%d,sp\n", op, 2); ! 91: size -= 2; ! 92: /* Fall through... */ ! 93: case 2: ! 94: case 1: ! 95: fprintf (file, "\t%ss\t#%d,sp\n", op, size); ! 96: size = 0; ! 97: break; ! 98: case 0: ! 99: break; ! 100: default: ! 101: fprintf (file, "\tmov.w\t#%d,r5\n\t%s.w\tr5,sp\n", size, op); ! 102: size = 0; ! 103: break; ! 104: } ! 105: } ! 106: ! 107: /* Output assembly language code for the function prologue. */ ! 108: static int push_order[FIRST_PSEUDO_REGISTER] ! 109: = {6, 5, 4, 3, 2, 1, 0, -1, -1}; ! 110: static int pop_order[FIRST_PSEUDO_REGISTER] ! 111: = {0, 1, 2, 3, 4, 5, 6, -1, -1}; ! 112: ! 113: /* This is what the stack looks like after the prolog of ! 114: a function with a frame has been set up: ! 115: ! 116: <pushed args> ! 117: return pc ! 118: fp-> old fp ! 119: <locals> ! 120: <saved register-0> ! 121: <saved register-1> ! 122: sp-> <saved register-n> ! 123: ! 124: ! 125: This is what the stack looks like after the prolog of ! 126: a function which doesn't have a frame: ! 127: ! 128: <pushed args> ! 129: return pc ! 130: <locals> ! 131: <saved register-0> ! 132: sp-> <saved register-n> ! 133: */ ! 134: ! 135: void ! 136: function_prologue (file, size) ! 137: FILE *file; ! 138: int size; ! 139: { ! 140: register int mask = 0; ! 141: int fsize = (size + 1) & -2; ! 142: int idx; ! 143: ! 144: if (frame_pointer_needed) ! 145: { ! 146: /* Push the fp. */ ! 147: fprintf (file, "\tpush\t%s\n", names_big[FRAME_POINTER_REGNUM]); ! 148: fprintf (file, "\tmov.w\tr7,r6\n"); ! 149: ! 150: /* Leave room for the locals. */ ! 151: dosize (file, "sub", fsize, 1); ! 152: ! 153: /* Push the rest of the registers. */ ! 154: for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++) ! 155: { ! 156: int regno = push_order[idx]; ! 157: ! 158: if (regno >= 0 && word_reg_used (regno) ! 159: && regno != FRAME_POINTER_REGNUM) ! 160: fprintf (file, "\tpush\t%s\n", names_big[regno]); ! 161: } ! 162: } ! 163: else ! 164: { ! 165: dosize (file, "sub", fsize, 0); ! 166: for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++) ! 167: { ! 168: int regno = push_order[idx]; ! 169: ! 170: if (regno >= 0 && word_reg_used (regno)) ! 171: fprintf (file, "\tpush\t%s\n", names_big[regno]); ! 172: } ! 173: } ! 174: } ! 175: ! 176: /* Output assembly language code for the function epilogue. */ ! 177: ! 178: void ! 179: function_epilogue (file, size) ! 180: FILE *file; ! 181: int size; ! 182: { ! 183: register int regno; ! 184: register int mask = 0; ! 185: int fsize = (size + 1) & -2; ! 186: int nregs; ! 187: int offset; ! 188: int idx; ! 189: rtx insn = get_last_insn (); ! 190: ! 191: /* If the last insn was a BARRIER, we don't have to write any code. */ ! 192: if (GET_CODE (insn) == NOTE) ! 193: insn = prev_nonnote_insn (insn); ! 194: if (insn && GET_CODE (insn) == BARRIER) ! 195: return; ! 196: ! 197: nregs = 0; ! 198: ! 199: if (frame_pointer_needed) ! 200: { ! 201: /* Pop saved registers. */ ! 202: for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++) ! 203: { ! 204: regno = pop_order[idx]; ! 205: if (regno >= 0 && regno != FRAME_POINTER_REGNUM ! 206: && word_reg_used (regno)) ! 207: fprintf (file, "\tpop\t%s\n", names_big[regno]); ! 208: } ! 209: /* Deallocate locals. */ ! 210: dosize (file, "add", fsize, 1); ! 211: /* Pop frame pointer. */ ! 212: fprintf (file, "\tpop\t%s\n", names_big[FRAME_POINTER_REGNUM]); ! 213: } ! 214: else ! 215: { ! 216: /* Deallocate locals and pop saved registers. */ ! 217: for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++) ! 218: { ! 219: regno = pop_order[idx]; ! 220: if (regno >= 0 && word_reg_used (regno)) ! 221: fprintf (file, "\tpop\t%s\n", names_big[regno]); ! 222: } ! 223: dosize (file, "add", fsize, 0); ! 224: } ! 225: if (pragma_interrupt) ! 226: fprintf (file, "\trte\n"); ! 227: else ! 228: fprintf (file, "\trts\n"); ! 229: ! 230: pragma_interrupt = 0; ! 231: pragma_saveall = 0; ! 232: } ! 233: ! 234: /* Return true if VALUE is a valid constant for constraint 'P'. */ ! 235: ! 236: int ! 237: potl8 (value) ! 238: { ! 239: switch (value) ! 240: { ! 241: case 1: ! 242: case 2: ! 243: case 4: ! 244: case 8: ! 245: case 16: ! 246: case 32: ! 247: case 64: ! 248: case 128: ! 249: return 1; ! 250: } ! 251: return 0; ! 252: } ! 253: ! 254: /* Return true if VALUE is a valid constant for constraint 'O'. */ ! 255: int ! 256: potg8 (value) ! 257: int value; ! 258: { ! 259: switch (value) ! 260: { ! 261: case 256: ! 262: case 512: ! 263: case 1024: ! 264: case 2048: ! 265: case 4096: ! 266: case 8192: ! 267: case 16384: ! 268: case 32768: ! 269: return 1; ! 270: } ! 271: return 0; ! 272: } ! 273: ! 274: /* Return true is OP is a valid source operand for an integer move ! 275: instruction. */ ! 276: int ! 277: general_operand_src (op, mode) ! 278: rtx op; ! 279: enum machine_mode mode; ! 280: { ! 281: /* We can't have a pre-dec as a source. */ ! 282: if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == PRE_DEC) ! 283: return 0; ! 284: return general_operand (op, mode); ! 285: } ! 286: ! 287: /* Return true if OP is a valid destination operand for an integer move ! 288: instruction. */ ! 289: int ! 290: general_operand_dst (op, mode) ! 291: rtx op; ! 292: enum machine_mode mode; ! 293: { ! 294: /* We can't have a post-inc as a dest. */ ! 295: if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == POST_INC) ! 296: return 0; ! 297: return general_operand (op, mode); ! 298: } ! 299: ! 300: /* Handle machine specific pragmas for compatibility with existing ! 301: compilers for the H8/300 ! 302: ! 303: pragma saveall generates prolog/epilog code which saves and ! 304: restores all the registers on function entry. ! 305: ! 306: pragma interrupt saves and restores all registers, and exits with ! 307: an rte instruction rather than an rts. A pointer to a function ! 308: with this attribute may be safely used in an interrupt vector. */ ! 309: int ! 310: handle_pragma (file) ! 311: FILE *file; ! 312: { ! 313: int c; ! 314: char pbuf[20]; ! 315: int psize; ! 316: ! 317: c = getc (file); ! 318: while (c == ' ' || c == '\t') ! 319: c = getc (file); ! 320: ! 321: if (c == '\n' || c == EOF) ! 322: return c; ! 323: ! 324: for (psize = 0; psize < sizeof (pbuf) - 1 && isalpha (c); psize++) ! 325: { ! 326: pbuf[psize] = c; ! 327: c = getc (file); ! 328: } ! 329: ! 330: pbuf[psize] = 0; ! 331: ! 332: if (strcmp (pbuf, "interrupt") == 0) ! 333: pragma_interrupt = 1; ! 334: ! 335: if (strcmp (pbuf, "saveall") == 0) ! 336: pragma_saveall = 1; ! 337: ! 338: return c; ! 339: } ! 340: ! 341: /* If the next arg with MODE and TYPE is to be passed in a register, return ! 342: the rtx to represent where it is passed. CUM represents the state after ! 343: the last argument. NAMED is not used. */ ! 344: ! 345: rtx ! 346: function_arg (cum, mode, type, named) ! 347: CUMULATIVE_ARGS *cum; ! 348: enum machine_mode mode; ! 349: tree type; ! 350: int named; ! 351: { ! 352: rtx result = 0; ! 353: int libcall = 0; ! 354: ! 355: /* Right now reload has a problem with reg passing with small reg ! 356: classes. */ ! 357: ! 358: if (cum->libcall || (named && TARGET_QUICKCALL)) ! 359: libcall = 1; ! 360: ! 361: if (TARGET_NOQUICK) ! 362: libcall = 0; ! 363: ! 364: if (mode != VOIDmode && libcall && mode != DFmode && mode != SFmode) ! 365: { ! 366: switch (cum->nbytes) ! 367: { ! 368: case 0: ! 369: result = gen_rtx (REG, mode, 0); ! 370: break; ! 371: case 2: ! 372: result = gen_rtx (REG, mode, 1); ! 373: break; ! 374: case 4: ! 375: result = gen_rtx (REG, mode, 4); ! 376: break; ! 377: case 6: ! 378: result = gen_rtx (REG, mode, 5); ! 379: break; ! 380: default: ! 381: return 0; ! 382: } ! 383: } ! 384: return result; ! 385: } ! 386: ! 387: /* Documentation for the machine specific operand escapes: ! 388: ! 389: 'C' print (operand - 2). ! 390: 'E' low byte of reg or -ve lsb of constant ! 391: 'F' high byte of reg of -ve msb of constant ! 392: ! 393: 'G' negate constant ! 394: 'L' fake label, changed after used twice. ! 395: 'M' turn a 'M' constant into its negative mod 2. ! 396: 'T' print operand as a word ! 397: 'V' print log2 of constant - used for bset instructions ! 398: 'X' 8 bit register or other operand ! 399: ! 400: 'Y' print either l or h depending on whether last 'Z' operand < 8 or >= 8. ! 401: 'Z' print int & 7 ! 402: ! 403: 'e' first word of 32 bit value ! 404: 'f' second word of 32 bit value ! 405: ! 406: 'j' print operand as condition code. ! 407: 'k' print operand as reverse condition code. ! 408: ! 409: 's' low byte of 16 bit value ! 410: 't' high byte of 16 bit value ! 411: ! 412: 'w' 1st byte of 32 bit value zzzzzzzz yyyyyyyy xxxxxxxx wwwwwwww ! 413: 'x' 2nd byte of 32 bit value ! 414: 'y' 3rd byte of 32 bit value ! 415: 'z' 4th byte of 32 bit value ! 416: ! 417: */ ! 418: ! 419: /* Return assembly language string which identifies a comparison type. */ ! 420: ! 421: char * ! 422: cond_string (code) ! 423: enum rtx_code code; ! 424: { ! 425: switch (code) ! 426: { ! 427: case NE: ! 428: return "ne"; ! 429: case EQ: ! 430: return "eq"; ! 431: case GE: ! 432: return "ge"; ! 433: case GT: ! 434: return "gt"; ! 435: case LE: ! 436: return "le"; ! 437: case LT: ! 438: return "lt"; ! 439: case GEU: ! 440: return "hs"; ! 441: case GTU: ! 442: return "hi"; ! 443: case LEU: ! 444: return "ls"; ! 445: case LTU: ! 446: return "lo"; ! 447: default: ! 448: abort (); ! 449: } ! 450: } ! 451: ! 452: /* Print operand X using operand code CODE to assembly language output file ! 453: FILE. */ ! 454: ! 455: void ! 456: print_operand (file, x, code) ! 457: FILE *file; ! 458: rtx x; ! 459: int code; ! 460: { ! 461: /* This is used to general unique labels for the 'L' code. */ ! 462: static int lab = 1000; ! 463: ! 464: /* This is used for communication between the 'P' and 'U' codes. */ ! 465: static char *last_p; ! 466: ! 467: /* This is used for communication between the 'Z' and 'Y' codes. */ ! 468: static int bitint; ! 469: ! 470: switch (code) ! 471: { ! 472: case 'L': ! 473: /* 'L' must always be used twice in a single pattern. It generates ! 474: the same lable twice, and then will generate a unique label the ! 475: next time it is used. */ ! 476: asm_fprintf (file, "tl%d", (lab++) / 2); ! 477: break; ! 478: ! 479: case 'X': ! 480: if (GET_CODE (x) == REG) ! 481: fprintf (file, "%s", byte_reg (x, 0)); ! 482: else ! 483: goto def; ! 484: break; ! 485: ! 486: case 'G': ! 487: if (GET_CODE (x) != CONST_INT) ! 488: abort (); ! 489: fprintf (file, "#%d", 0xff & (-INTVAL (x))); ! 490: break; ! 491: ! 492: case 'T': ! 493: if (GET_CODE (x) == REG) ! 494: fprintf (file, "%s", names_big[REGNO (x)]); ! 495: else ! 496: goto def; ! 497: break; ! 498: ! 499: case 'w': ! 500: if (GET_CODE (x) == CONST_INT) ! 501: fprintf (file, "#%d", INTVAL (x) & 0xff); ! 502: else ! 503: fprintf (file, "%s", byte_reg (x, 2)); ! 504: break; ! 505: ! 506: case 'x': ! 507: if (GET_CODE (x) == CONST_INT) ! 508: fprintf (file, "#%d", (INTVAL (x) >> 8) & 0xff); ! 509: else ! 510: fprintf (file, "%s", byte_reg (x, 3)); ! 511: break; ! 512: ! 513: case 'y': ! 514: if (GET_CODE (x) == CONST_INT) ! 515: fprintf (file, "#%d", (INTVAL (x) >> 16) & 0xff); ! 516: else ! 517: fprintf (file, "%s", byte_reg (x, 0)); ! 518: break; ! 519: ! 520: case 'z': ! 521: if (GET_CODE (x) == CONST_INT) ! 522: fprintf (file, "#%d", (INTVAL (x) >> 24) & 0xff); ! 523: else ! 524: fprintf (file, "%s", byte_reg (x, 1)); ! 525: break; ! 526: ! 527: /* FOR 16 bits. */ ! 528: case 't': ! 529: if (GET_CODE (x) == CONST_INT) ! 530: fprintf (file, "#%d", (INTVAL (x) >> 8) & 0xff); ! 531: else ! 532: fprintf (file, "%s", byte_reg (x, 1)); ! 533: break; ! 534: ! 535: case 's': ! 536: if (GET_CODE (x) == CONST_INT) ! 537: fprintf (file, "#%d", (INTVAL (x)) & 0xff); ! 538: else ! 539: fprintf (file, "%s", byte_reg (x, 0)); ! 540: break; ! 541: ! 542: case 'u': ! 543: if (GET_CODE (x) != CONST_INT) ! 544: abort (); ! 545: fprintf (file, "%d", INTVAL (x)); ! 546: break; ! 547: ! 548: case 'Z': ! 549: bitint = INTVAL (x); ! 550: fprintf (file, "#%d", bitint & 7); ! 551: break; ! 552: ! 553: case 'Y': ! 554: fprintf (file, "%c", bitint > 7 ? 'h' : 'l'); ! 555: break; ! 556: ! 557: case 'O': ! 558: bitint = exact_log2 ((~INTVAL (x)) & 0xff); ! 559: if (bitint == -1) ! 560: abort (); ! 561: fprintf (file, "#%d", bitint & 7); ! 562: break; ! 563: ! 564: case 'V': ! 565: bitint = exact_log2 (INTVAL (x)); ! 566: if (bitint == -1) ! 567: abort (); ! 568: fprintf (file, "#%d", bitint & 7); ! 569: break; ! 570: ! 571: case 'P': ! 572: if (REGNO (XEXP (XEXP (x, 0), 0)) == STACK_POINTER_REGNUM) ! 573: { ! 574: last_p = ""; ! 575: fprintf (file, ".w"); ! 576: } ! 577: else ! 578: { ! 579: last_p = "l"; ! 580: fprintf (file, ".b"); ! 581: } ! 582: break; ! 583: ! 584: case 'U': ! 585: fprintf (file, "%s%s", names_big[REGNO (x)], last_p); ! 586: break; ! 587: ! 588: case 'M': ! 589: /* For -4 and -2, the other 2 is handled separately. */ ! 590: switch (INTVAL (x)) ! 591: { ! 592: case -2: ! 593: case -4: ! 594: fprintf (file, "#2"); ! 595: break; ! 596: case -1: ! 597: case -3: ! 598: fprintf (file, "#1"); ! 599: break; ! 600: ! 601: default: ! 602: abort (); ! 603: } ! 604: break; ! 605: ! 606: case 'e': ! 607: switch (GET_CODE (x)) ! 608: { ! 609: case REG: ! 610: fprintf (file, "%s", names_big[REGNO (x)]); ! 611: break; ! 612: case MEM: ! 613: x = adj_offsettable_operand (x, 0); ! 614: print_operand (file, x, 0); ! 615: break; ! 616: case CONST_INT: ! 617: fprintf (file, "#%d", ((INTVAL (x) >> 16) & 0xffff)); ! 618: break; ! 619: default: ! 620: abort (); ! 621: break; ! 622: } ! 623: break; ! 624: ! 625: case 'f': ! 626: switch (GET_CODE (x)) ! 627: { ! 628: case REG: ! 629: fprintf (file, "%s", names_big[REGNO (x) + 1]); ! 630: break; ! 631: ! 632: case MEM: ! 633: x = adj_offsettable_operand (x, 2); ! 634: print_operand (file, x, 0); ! 635: break; ! 636: ! 637: case CONST_INT: ! 638: fprintf (file, "#%d", INTVAL (x) & 0xffff); ! 639: break; ! 640: ! 641: default: ! 642: abort (); ! 643: } ! 644: break; ! 645: ! 646: case 'C': ! 647: fprintf (file, "#%d", INTVAL (x) - 2); ! 648: break; ! 649: ! 650: case 'E': ! 651: switch (GET_CODE (x)) ! 652: { ! 653: case REG: ! 654: fprintf (file, "%sl", names_big[REGNO (x)]); ! 655: break; ! 656: ! 657: case CONST_INT: ! 658: fprintf (file, "#%d", (-INTVAL (x)) & 0xff); ! 659: break; ! 660: ! 661: default: ! 662: abort (); ! 663: } ! 664: break; ! 665: ! 666: case 'F': ! 667: switch (GET_CODE (x)) ! 668: { ! 669: case REG: ! 670: fprintf (file, "%sh", names_big[REGNO (x)]); ! 671: break; ! 672: ! 673: case CONST_INT: ! 674: fprintf (file, "#%d", ((-INTVAL (x)) & 0xff00) >> 8); ! 675: break; ! 676: ! 677: default: ! 678: abort (); ! 679: } ! 680: break; ! 681: ! 682: case 'j': ! 683: asm_fprintf (file, cond_string (GET_CODE (x))); ! 684: break; ! 685: ! 686: case 'k': ! 687: asm_fprintf (file, cond_string (reverse_condition (GET_CODE (x)))); ! 688: break; ! 689: def: ; ! 690: default: ! 691: switch (GET_CODE (x)) ! 692: { ! 693: case REG: ! 694: fprintf (file, "%s", names_big[REGNO (x)]); ! 695: break; ! 696: ! 697: case MEM: ! 698: fprintf (file, "@"); ! 699: output_address (XEXP (x, 0)); ! 700: break; ! 701: ! 702: case CONST_INT: ! 703: case SYMBOL_REF: ! 704: case CONST: ! 705: case LABEL_REF: ! 706: fprintf (file, "#"); ! 707: print_operand_address (file, x); ! 708: break; ! 709: } ! 710: } ! 711: } ! 712: ! 713: /* Output assembly language output for the address ADDR to FILE. */ ! 714: ! 715: void ! 716: print_operand_address (file, addr) ! 717: FILE *file; ! 718: rtx addr; ! 719: { ! 720: switch (GET_CODE (addr)) ! 721: { ! 722: case REG: ! 723: fprintf (file, "%s", names_big[REGNO (addr)]); ! 724: break; ! 725: ! 726: case PRE_DEC: ! 727: fprintf (file, "-%s", names_big[REGNO (XEXP (addr, 0))]); ! 728: break; ! 729: ! 730: case POST_INC: ! 731: fprintf (file, "%s+", names_big[REGNO (XEXP (addr, 0))]); ! 732: break; ! 733: ! 734: case PLUS: ! 735: fprintf (file, "("); ! 736: if (GET_CODE (XEXP (addr, 0)) == REG) ! 737: { ! 738: /* reg,foo */ ! 739: print_operand_address (file, XEXP (addr, 1)); ! 740: fprintf (file, ","); ! 741: print_operand_address (file, XEXP (addr, 0)); ! 742: } ! 743: else ! 744: { ! 745: /* foo+k */ ! 746: print_operand_address (file, XEXP (addr, 0)); ! 747: fprintf (file, "+"); ! 748: print_operand_address (file, XEXP (addr, 1)); ! 749: } ! 750: fprintf (file, ")"); ! 751: break; ! 752: ! 753: case CONST_INT: ! 754: if (INTVAL (addr) < 0) ! 755: { ! 756: int v = -INTVAL (addr); ! 757: ! 758: fprintf (file, "-%d", v); ! 759: } ! 760: else ! 761: fprintf (file, "%d", INTVAL (addr)); ! 762: break; ! 763: ! 764: default: ! 765: output_addr_const (file, addr); ! 766: break; ! 767: } ! 768: } ! 769: ! 770: /* Output to FILE a reference to the user-level label NAME. ! 771: Strip off the section name if any. It is separated from the label name ! 772: by a space. */ ! 773: ! 774: void ! 775: asm_output_labelref (file, name) ! 776: FILE *file; ! 777: char *name; ! 778: { ! 779: char *p; ! 780: ! 781: fputc ('_', file); ! 782: ! 783: for (p = name; *p; p++) ! 784: { ! 785: if (*p == ' ') ! 786: { ! 787: /* If we found a space in the name, then we've skipped over the ! 788: section encoding. */ ! 789: fputs (p + 1, file); ! 790: return; ! 791: } ! 792: } ! 793: ! 794: /* No space, so no section. */ ! 795: fputs (name, file); ! 796: } ! 797: ! 798: /* Output all insn addresses and their sizes into the assembly language ! 799: output file. This is helpful for debugging whether the length attributes ! 800: in the md file are correct. This is not meant to be a user selectable ! 801: option. */ ! 802: ! 803: void ! 804: final_prescan_insn (insn, operand, num_operands) ! 805: rtx insn, *operand; ! 806: int num_operands; ! 807: { ! 808: /* This holds the last insn address. */ ! 809: static int last_insn_address = 0; ! 810: ! 811: int uid = INSN_UID (insn); ! 812: ! 813: if (TARGET_ADDRESSES) ! 814: { ! 815: fprintf (asm_out_file, "; %d %d\n", insn_addresses[uid], ! 816: insn_addresses[uid] - last_insn_address); ! 817: last_insn_address = insn_addresses[uid]; ! 818: } ! 819: } ! 820: ! 821: static void ! 822: shift_n_bits (lval, operand, f, notzero) ! 823: rtx lval; ! 824: rtx operand; ! 825: rtx (*f) (); ! 826: int notzero; ! 827: { ! 828: rtx label = gen_label_rtx (); ! 829: rtx bot = gen_label_rtx (); ! 830: ! 831: if (! notzero) ! 832: { ! 833: /* Have to put a zero test at the top. */ ! 834: emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, lval)); ! 835: emit_jump_insn (gen_beq (bot)); ! 836: } ! 837: emit_label (label); ! 838: f (operand); ! 839: emit_insn (gen_rtx (SET, QImode, lval, ! 840: gen_rtx (MINUS, QImode, lval, const1_rtx))); ! 841: emit_insn (gen_rtx (SET, VOIDmode, cc0_rtx, lval)); ! 842: emit_jump_insn (gen_bne (label)); ! 843: ! 844: emit_label (bot); ! 845: /* We can't end an expand with a label. */ ! 846: emit_move_insn (operand, operand); ! 847: } ! 848: ! 849: int ! 850: can_shift (code, operands, f, limit, fby_eight) ! 851: int code; ! 852: rtx operands[]; ! 853: rtx (*f) (); ! 854: int limit; ! 855: rtx (*fby_eight) (); ! 856: { ! 857: extern int rtx_equal_function_value_matters; ! 858: ! 859: emit_move_insn (operands[0], operands[1]); ! 860: ! 861: if (GET_CODE (operands[2]) != CONST_INT) ! 862: { ! 863: rtx lval; ! 864: ! 865: /* Can't define expand a loop after rtl generation. */ ! 866: if (! rtx_equal_function_value_matters) ! 867: return 0; ! 868: ! 869: lval = gen_reg_rtx (QImode); ! 870: ! 871: convert_move (lval, operands[2], 1); ! 872: shift_n_bits (lval, operands[0], f, 0); ! 873: } ! 874: else ! 875: { ! 876: int i; ! 877: ! 878: i = INTVAL (operands[2]); ! 879: if (i >= 8 && fby_eight) ! 880: { ! 881: fby_eight (operands[0]); ! 882: i -= 8; ! 883: } ! 884: if (i > limit) ! 885: { ! 886: rtx lval; ! 887: ! 888: /* Can't define expand a loop after rtl generation. */ ! 889: if (! rtx_equal_function_value_matters) ! 890: return 0; ! 891: lval = gen_reg_rtx (QImode); ! 892: emit_move_insn (lval, gen_rtx (CONST_INT, VOIDmode, i)); ! 893: shift_n_bits (lval, operands[0], f, 1); ! 894: } ! 895: else ! 896: { ! 897: while (i--) ! 898: f (operands[0]); ! 899: } ! 900: } ! 901: return 1; ! 902: } ! 903: ! 904: int ! 905: domovsi (operands) ! 906: rtx operands[]; ! 907: { ! 908: rtx src = operands[1]; ! 909: rtx dst = operands[0]; ! 910: ! 911: if (push_operand (dst, GET_MODE (dst))) ! 912: { ! 913: /* Source must be a reg. */ ! 914: if (! REG_P (src)) ! 915: { ! 916: rtx tmp = gen_reg_rtx (GET_MODE (dst)); ! 917: ! 918: emit_move_insn (tmp, src); ! 919: operands[1] = tmp; ! 920: } ! 921: } ! 922: return 0; ! 923: } ! 924: ! 925: int ! 926: io (FROM, TO) ! 927: { ! 928: int OFFSET = 0; ! 929: ! 930: if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM) ! 931: (OFFSET) = 2 + frame_pointer_needed * 2; ! 932: else ! 933: { ! 934: int regno; ! 935: int offset = 0; ! 936: ! 937: for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) ! 938: if ((regs_ever_live[regno] ! 939: && (! call_used_regs[regno] || regno == FRAME_POINTER_REGNUM))) ! 940: offset += 2; ! 941: ! 942: (OFFSET) = offset + get_frame_size (); ! 943: ! 944: if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) ! 945: (OFFSET) += 2; /* Skip saved PC. */ ! 946: } ! 947: return OFFSET; ! 948: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.