|
|
1.1 ! root 1: /* Convert RTL to assembler code and output it, for GNU compiler. ! 2: Copyright (C) 1987, 1988 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU CC. ! 5: ! 6: GNU CC is distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU CC General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU CC, but only under the conditions described in the ! 15: GNU CC General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU CC so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: /* This is the final pass of the compiler. ! 23: It looks at the rtl code for a function and outputs assembler code. ! 24: ! 25: Call `final_start_function' to output the assembler code for function entry, ! 26: `final' to output assembler code for some RTL code, ! 27: `final_end_function' to output assembler code for function exit. ! 28: If a function is compiled in several pieces, each piece is ! 29: output separately with `final'. ! 30: ! 31: Some optimizations are also done at this level. ! 32: Move instructions that were made unnecessary by good register allocation ! 33: are detected and omitted from the output. (Though most of these ! 34: are removed by the last jump pass.) ! 35: ! 36: Instructions to set the condition codes are omitted when it can be ! 37: seen that the condition codes already had the desired values. ! 38: ! 39: In some cases it is sufficient if the inherited condition codes ! 40: have related values, but this may require the following insn ! 41: (the one that tests the condition codes) to be modified. ! 42: ! 43: The code for the function prologue and epilogue are generated ! 44: directly as assembler code by the macros FUNCTION_PROLOGUE and ! 45: FUNCTION_EPILOGUE. Those instructions never exist as rtl. */ ! 46: ! 47: #include <stdio.h> ! 48: #include "config.h" ! 49: #include "rtl.h" ! 50: #include "regs.h" ! 51: #include "insn-config.h" ! 52: #include "recog.h" ! 53: #include "conditions.h" ! 54: #include "gdbfiles.h" ! 55: ! 56: /* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist. */ ! 57: #ifndef NO_DBX_FORMAT ! 58: #include <stab.h> ! 59: #endif ! 60: ! 61: /* .stabd code for line number. */ ! 62: #ifndef N_SLINE ! 63: #define N_SLINE 0x44 ! 64: #endif ! 65: ! 66: /* .stabs code for included file name. */ ! 67: #ifndef N_SOL ! 68: #define N_SOL 0x84 ! 69: #endif ! 70: ! 71: #define min(A,B) ((A) < (B) ? (A) : (B)) ! 72: ! 73: void output_asm_insn (); ! 74: static void alter_subreg (); ! 75: static int alter_cond (); ! 76: void output_asm_label (); ! 77: static void output_operand (); ! 78: void output_address (); ! 79: void output_addr_const (); ! 80: static void output_source_line (); ! 81: ! 82: static char *reg_name[] = REGISTER_NAMES; ! 83: ! 84: /* File in which assembler code is being written. */ ! 85: ! 86: extern FILE *asm_out_file; ! 87: ! 88: /* All the symbol-blocks (levels of scoping) in the compilation ! 89: are assigned sequence numbers in order of appearance of the ! 90: beginnings of the symbol-blocks. Both final and dbxout do this, ! 91: and assume that they will both give the same number to each block. ! 92: Final uses these sequence numbers to generate assembler label names ! 93: LBBnnn and LBEnnn for the beginning and end of the symbol-block. ! 94: Dbxout uses the sequence nunbers to generate references to the same labels ! 95: from the dbx debugging information. */ ! 96: ! 97: static next_block_index; ! 98: ! 99: /* Chain of all `struct gdbfile's. */ ! 100: ! 101: struct gdbfile *gdbfiles; ! 102: ! 103: /* `struct gdbfile' for the last file we wrote a line number for. */ ! 104: ! 105: static struct gdbfile *current_gdbfile; ! 106: ! 107: /* Filenum to assign to the next distinct source file encountered. */ ! 108: ! 109: static int next_gdb_filenum; ! 110: ! 111: /* This variable contains machine-dependent flags (defined in tm-...h) ! 112: set and examined by output routines ! 113: that describe how to interpret the condition codes properly. */ ! 114: ! 115: CC_STATUS cc_status; ! 116: ! 117: /* During output of an insn, this contains a copy of cc_status ! 118: from before the insn. */ ! 119: ! 120: CC_STATUS cc_prev_status; ! 121: ! 122: /* Last source file name mentioned in a NOTE insn. */ ! 123: ! 124: static char *lastfile; ! 125: ! 126: /* Indexed by hardware reg number, is 1 if that register is ever ! 127: used in the current function. ! 128: ! 129: In life_analysis, or in stupid_life_analysis, this is set ! 130: up to record the hard regs used explicitly. Reload adds ! 131: in the hard regs used for holding pseudo regs. Final uses ! 132: it to generate the code in the function prologue and epilogue ! 133: to save and restore registers as needed. */ ! 134: ! 135: char regs_ever_live[FIRST_PSEUDO_REGISTER]; ! 136: ! 137: /* Nonzero means current function must be given a frame pointer. ! 138: Set in stmt.c if anything is allocated on the stack there. ! 139: Set in reload1.c if anything is allocated on the stack there. */ ! 140: ! 141: int frame_pointer_needed; ! 142: ! 143: /* Assign unique numbers to labels generated for profiling. */ ! 144: ! 145: int profile_label_no; ! 146: ! 147: /* Length so far allocated in PENDING_BLOCKS. */ ! 148: ! 149: static int max_block_depth; ! 150: ! 151: /* Stack of sequence numbers of symbol-blocks of which we have seen the ! 152: beginning but not yet the end. Sequence numbers are assigned at ! 153: the beginning; this stack allows us to find the sequence number ! 154: of a block that is ending. */ ! 155: ! 156: static int *pending_blocks; ! 157: ! 158: /* Number of elements currently in use in PENDING_BLOCKS. */ ! 159: ! 160: static int block_depth; ! 161: ! 162: /* Nonzero if have enabled APP processing of our assembler output. */ ! 163: ! 164: static int app_on; ! 165: ! 166: /* Initialize data in final at the beginning of a compilation. */ ! 167: ! 168: void ! 169: init_final (filename) ! 170: char *filename; ! 171: { ! 172: next_block_index = 2; ! 173: lastfile = filename; ! 174: app_on = 0; ! 175: max_block_depth = 20; ! 176: pending_blocks = (int *) xmalloc (20 * sizeof *pending_blocks); ! 177: gdbfiles = 0; ! 178: next_gdb_filenum = 0; ! 179: } ! 180: ! 181: /* Enable APP processing of subsequent output. ! 182: Used before the output from an `asm' statement. */ ! 183: ! 184: void ! 185: app_enable () ! 186: { ! 187: if (! app_on) ! 188: { ! 189: fprintf (asm_out_file, ASM_APP_ON); ! 190: app_on = 1; ! 191: } ! 192: } ! 193: ! 194: /* Enable APP processing of subsequent output. ! 195: Called from varasm.c before most kinds of output. */ ! 196: ! 197: void ! 198: app_disable () ! 199: { ! 200: if (app_on) ! 201: { ! 202: fprintf (asm_out_file, ASM_APP_OFF); ! 203: app_on = 0; ! 204: } ! 205: } ! 206: ! 207: /* Output assembler code for the start of a function, ! 208: and initialize some of the variables in this file ! 209: for the new function. The label for the function and associated ! 210: assembler pseudo-ops have already been output in `assemble_function'. ! 211: ! 212: FIRST is the first insn of the rtl for the function being compiled. ! 213: FILE is the file to write assembler code to. ! 214: WRITE_SYMBOLS is 1 for gdb symbols, 2 for dbx symbols. ! 215: OPTIMIZE is nonzero if we should eliminate redundant ! 216: test and compare insns. */ ! 217: ! 218: void ! 219: final_start_function (first, file, write_symbols, optimize) ! 220: rtx first; ! 221: FILE *file; ! 222: int write_symbols; ! 223: int optimize; ! 224: { ! 225: extern int profile_flag; ! 226: ! 227: init_recog (); ! 228: ! 229: block_depth = 0; ! 230: ! 231: /* Record beginning of the symbol-block that's the entire function. */ ! 232: ! 233: if (write_symbols == 1) ! 234: { ! 235: pending_blocks[block_depth++] = next_block_index; ! 236: fprintf (file, "\t.gdbbeg %d\n", next_block_index++); ! 237: } ! 238: ! 239: /* Initial line number is supposed to be output ! 240: before the function's prologue and label ! 241: so that the function's address will not appear to be ! 242: in the last statement of the preceding function. */ ! 243: if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED) ! 244: output_source_line (file, first, write_symbols); ! 245: ! 246: #ifdef FUNCTION_PROLOGUE ! 247: /* First output the function prologue: code to set up the stack frame. */ ! 248: FUNCTION_PROLOGUE (file, get_frame_size ()); ! 249: #endif ! 250: ! 251: if (profile_flag) ! 252: { ! 253: int align = min (BIGGEST_ALIGNMENT, BITS_PER_WORD); ! 254: fprintf (file, "\t%s\n", DATA_SECTION_ASM_OP); ! 255: ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); ! 256: ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no); ! 257: assemble_integer_zero (); ! 258: fprintf (file, "\t%s\n", TEXT_SECTION_ASM_OP); ! 259: FUNCTION_PROFILER (file, profile_label_no); ! 260: profile_label_no++; ! 261: } ! 262: ! 263: CC_STATUS_INIT; ! 264: } ! 265: ! 266: /* Output assembler code for the end of a function. ! 267: For clarity, args are same as those of `final_start_function' ! 268: even though not all of them are needed. */ ! 269: ! 270: void ! 271: final_end_function (first, file, write_symbols, optimize) ! 272: rtx first; ! 273: FILE *file; ! 274: int write_symbols; ! 275: int optimize; ! 276: { ! 277: if (app_on) ! 278: { ! 279: fprintf (file, ASM_APP_OFF); ! 280: app_on = 0; ! 281: } ! 282: ! 283: if (write_symbols == 1) ! 284: fprintf (file, "\t.gdbend %d\n", pending_blocks[0]); ! 285: ! 286: #ifdef FUNCTION_EPILOGUE ! 287: /* Finally, output the function epilogue: ! 288: code to restore the stack frame and return to the caller. */ ! 289: FUNCTION_EPILOGUE (file, get_frame_size ()); ! 290: #endif ! 291: ! 292: /* If FUNCTION_EPILOGUE is not defined, then the function body ! 293: itself contains return instructions wherever needed. */ ! 294: } ! 295: ! 296: /* Output assembler code for some insns: all or part of a function. ! 297: For description of args, see `final_start_function', above. */ ! 298: ! 299: void ! 300: final (first, file, write_symbols, optimize) ! 301: rtx first; ! 302: FILE *file; ! 303: int write_symbols; ! 304: int optimize; ! 305: { ! 306: register rtx insn; ! 307: register int i; ! 308: ! 309: for (insn = NEXT_INSN (first); insn; insn = NEXT_INSN (insn)) ! 310: { ! 311: switch (GET_CODE (insn)) ! 312: { ! 313: case NOTE: ! 314: if (! write_symbols) ! 315: break; ! 316: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) ! 317: abort (); /* Obsolete; shouldn't appear */ ! 318: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG ! 319: || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) ! 320: break; ! 321: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED) ! 322: break; /* An insn that was "deleted" */ ! 323: if (app_on) ! 324: { ! 325: fprintf (file, ASM_APP_OFF); ! 326: app_on = 0; ! 327: } ! 328: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG) ! 329: { ! 330: /* Beginning of a symbol-block. Assign it a sequence number ! 331: and push the number onto the stack PENDING_BLOCKS. */ ! 332: ! 333: if (block_depth == max_block_depth) ! 334: { ! 335: /* PENDING_BLOCKS is full; make it longer. */ ! 336: max_block_depth *= 2; ! 337: pending_blocks ! 338: = (int *) xrealloc (pending_blocks, ! 339: max_block_depth * sizeof (int)); ! 340: } ! 341: pending_blocks[block_depth++] = next_block_index; ! 342: ! 343: /* Output debugging info about the symbol-block beginning. */ ! 344: ! 345: if (write_symbols == 2) ! 346: ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", next_block_index); ! 347: else ! 348: fprintf (file, "\t.gdbbeg %d\n", next_block_index); ! 349: next_block_index++; ! 350: } ! 351: else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END) ! 352: { ! 353: /* End of a symbol-block. Pop its sequence number off ! 354: PENDING_BLOCKS and output debugging info based on that. */ ! 355: ! 356: if (write_symbols == 2) ! 357: { ! 358: if (block_depth > 0) ! 359: ASM_OUTPUT_INTERNAL_LABEL (file, "LBE", ! 360: pending_blocks[--block_depth]); ! 361: } ! 362: else ! 363: fprintf (file, "\t.gdbend %d\n", pending_blocks[--block_depth]); ! 364: } ! 365: else if (NOTE_LINE_NUMBER (insn) > 0) ! 366: /* This note is a line-number. */ ! 367: output_source_line (file, insn, write_symbols); ! 368: break; ! 369: ! 370: case BARRIER: ! 371: break; ! 372: ! 373: case CODE_LABEL: ! 374: if (app_on) ! 375: { ! 376: fprintf (file, ASM_APP_OFF); ! 377: app_on = 0; ! 378: } ! 379: #ifdef ASM_OUTPUT_CASE_LABEL ! 380: if (NEXT_INSN (insn) != 0 ! 381: && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN) ! 382: { ! 383: rtx nextbody = PATTERN (NEXT_INSN (insn)); ! 384: ! 385: /* If this label is followed by a jump-table, ! 386: output the two of them together in a special way. */ ! 387: ! 388: if (GET_CODE (nextbody) == ADDR_VEC ! 389: || GET_CODE (nextbody) == ADDR_DIFF_VEC) ! 390: { ! 391: ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), ! 392: NEXT_INSN (insn)); ! 393: break; ! 394: } ! 395: } ! 396: #endif ! 397: ! 398: ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); ! 399: CC_STATUS_INIT; ! 400: break; ! 401: ! 402: default: ! 403: { ! 404: register rtx body = PATTERN (insn); ! 405: int insn_code_number; ! 406: char *template; ! 407: ! 408: /* An INSN, JUMP_INSN or CALL_INSN. ! 409: First check for special kinds that recog doesn't recognize. */ ! 410: ! 411: if (GET_CODE (body) == USE /* These are just declarations */ ! 412: || GET_CODE (body) == CLOBBER) ! 413: break; ! 414: if (GET_CODE (body) == ASM_INPUT) ! 415: { ! 416: if (! app_on) ! 417: { ! 418: fprintf (file, ASM_APP_ON); ! 419: app_on = 1; ! 420: } ! 421: fprintf (asm_out_file, "\t%s\n", XSTR (body, 0)); ! 422: ! 423: /* There's no telling what that did to the condition codes. */ ! 424: CC_STATUS_INIT; ! 425: break; ! 426: } ! 427: ! 428: /* Detect `asm' construct with operands. */ ! 429: if (asm_noperands (body) > 0) ! 430: { ! 431: int noperands = asm_noperands (body); ! 432: rtx *ops = (rtx *) malloc (noperands * sizeof (rtx)); ! 433: char *string; ! 434: ! 435: if (! app_on) ! 436: { ! 437: fprintf (file, ASM_APP_ON); ! 438: app_on = 1; ! 439: } ! 440: ! 441: /* Get out the operand values. */ ! 442: string = decode_asm_operands (body, ops, 0, 0, 0); ! 443: /* Output the insn using them. */ ! 444: output_asm_insn (string, ops); ! 445: ! 446: /* There's no telling what that did to the condition codes. */ ! 447: CC_STATUS_INIT; ! 448: break; ! 449: } ! 450: ! 451: if (app_on) ! 452: { ! 453: fprintf (file, ASM_APP_OFF); ! 454: app_on = 0; ! 455: } ! 456: ! 457: /* Detect insns that are really jump-tables ! 458: and output them as such. */ ! 459: ! 460: if (GET_CODE (body) == ADDR_VEC) ! 461: { ! 462: enum machine_mode mode = GET_MODE (body); ! 463: register int vlen, idx; ! 464: vlen = XVECLEN (body, 0); ! 465: for (idx = 0; idx < vlen; idx++) ! 466: ASM_OUTPUT_ADDR_VEC_ELT (file, ! 467: CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); ! 468: break; ! 469: } ! 470: if (GET_CODE (body) == ADDR_DIFF_VEC) ! 471: { ! 472: enum machine_mode mode = GET_MODE (body); ! 473: register int vlen, idx; ! 474: vlen = XVECLEN (body, 1); ! 475: for (idx = 0; idx < vlen; idx++) ! 476: ASM_OUTPUT_ADDR_DIFF_ELT (file, ! 477: CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), ! 478: CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0))); ! 479: break; ! 480: } ! 481: ! 482: /* We have a real machine instruction as rtl. */ ! 483: ! 484: body = PATTERN (insn); ! 485: ! 486: /* Check for redundant move insns moving a reg into itself. ! 487: This takes little time and does not affect the semantics ! 488: so we do it even when `optimize' is 0. ! 489: It is not safe to do this for memory references; ! 490: we would not know if they were volatile. */ ! 491: if (GET_CODE (body) == SET ! 492: && SET_DEST (body) == SET_SRC (body) ! 493: && GET_CODE (SET_DEST (body)) == REG) ! 494: break; ! 495: ! 496: /* Check for redundant test and compare instructions ! 497: (when the condition codes are already set up as desired). ! 498: This is done only when optimizing; if not optimizing, ! 499: it should be possible for the user to alter a variable ! 500: with the debugger in between statements ! 501: and the next statement should reexamine the variable ! 502: to compute the condition codes. */ ! 503: ! 504: if (optimize ! 505: && GET_CODE (body) == SET ! 506: && GET_CODE (SET_DEST (body)) == CC0) ! 507: { ! 508: if (GET_CODE (SET_SRC (body)) == SUBREG) ! 509: alter_subreg (SET_SRC (body)); ! 510: if ((cc_status.value1 != 0 ! 511: && rtx_equal_p (SET_SRC (body), cc_status.value1)) ! 512: || (cc_status.value2 != 0 ! 513: && rtx_equal_p (SET_SRC (body), cc_status.value2))) ! 514: { ! 515: /* Don't delete insn if has an addressing side-effect */ ! 516: if (! find_reg_note (insn, REG_INC, 0)) ! 517: break; ! 518: } ! 519: } ! 520: ! 521: /* If this is a conditional branch, maybe modify it ! 522: if the cc's are in a nonstandard state ! 523: so that it accomplishes the same thing that it would ! 524: do straightforwardly if the cc's were set up normally. */ ! 525: ! 526: if (cc_status.flags != 0 ! 527: && GET_CODE (insn) == JUMP_INSN ! 528: && GET_CODE (body) == SET ! 529: && SET_DEST (body) == pc_rtx ! 530: && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE) ! 531: { ! 532: /* This function may alter the contents of its argument ! 533: and clear some of the cc_status.flags bits. ! 534: It may also return 1 meaning condition now always true ! 535: or -1 meaning condition now always false ! 536: or 2 meaning condition nontrivial but altered. */ ! 537: register int result = alter_cond (XEXP (SET_SRC (body), 0)); ! 538: /* If condition now has fixed value, replace the IF_THEN_ELSE ! 539: with its then-operand or its else-operand. */ ! 540: if (result == 1) ! 541: SET_SRC (body) = XEXP (SET_SRC (body), 1); ! 542: if (result == -1) ! 543: SET_SRC (body) = XEXP (SET_SRC (body), 2); ! 544: /* The jump is now either unconditional or a no-op. ! 545: If it has become a no-op, don't try to output it. ! 546: (It would not be recognized.) */ ! 547: if (SET_SRC (body) == pc_rtx) ! 548: continue; ! 549: /* Rerecognize the instruction if it has changed. */ ! 550: if (result != 0) ! 551: INSN_CODE (insn) = -1; ! 552: } ! 553: ! 554: /* Make same adjustments to instructions that examine the ! 555: condition codes without jumping. */ ! 556: ! 557: if (cc_status.flags != 0 ! 558: && GET_CODE (body) == SET) ! 559: switch (GET_CODE (SET_SRC (body))) ! 560: { ! 561: case GTU: ! 562: case GT: ! 563: case LTU: ! 564: case LT: ! 565: case GEU: ! 566: case GE: ! 567: case LEU: ! 568: case LE: ! 569: case EQ: ! 570: case NE: ! 571: { ! 572: register int result = alter_cond (SET_SRC (body)); ! 573: if (result == 1) ! 574: SET_SRC (body) = gen_rtx (CONST_INT, VOIDmode, -1); ! 575: if (result == -1) ! 576: SET_SRC (body) = const0_rtx; ! 577: if (result != 0) ! 578: INSN_CODE (insn) = -1; ! 579: } ! 580: } ! 581: ! 582: /* Try to recognize the instruction. ! 583: If successful, verify that the operands satisfy the ! 584: constraints for the instruction. Crash if they don't, ! 585: since `reload' should have changed them so that they do. */ ! 586: ! 587: insn_code_number = recog_memoized (insn); ! 588: insn_extract (insn); ! 589: for (i = 0; i < insn_n_operands[insn_code_number]; i++) ! 590: if (GET_CODE (recog_operand[i]) == SUBREG) ! 591: alter_subreg (recog_operand[i]); ! 592: ! 593: #ifdef REGISTER_CONSTRAINTS ! 594: if (! constrain_operands (insn_code_number)) ! 595: abort (); ! 596: #endif ! 597: ! 598: cc_prev_status = cc_status; ! 599: ! 600: /* Update `cc_status' for this instruction. ! 601: The instruction's output routine may change it further. ! 602: This should be a no-op for jump instructions ! 603: because their output routines may need to examine `cc_status', ! 604: below. That's ok since jump insns don't normally alter ! 605: the condition codes. */ ! 606: ! 607: NOTICE_UPDATE_CC (body); ! 608: ! 609: /* If the proper template needs to be chosen by some C code, ! 610: run that code and get the real template. */ ! 611: ! 612: template = insn_template[insn_code_number]; ! 613: if (template == 0) ! 614: template = insn_outfun[insn_code_number] (recog_operand, insn); ! 615: ! 616: /* Output assembler code from the template. */ ! 617: ! 618: output_asm_insn (template, recog_operand); ! 619: } ! 620: } ! 621: } ! 622: } ! 623: ! 624: /* Set up FILENAME as the current file for GDB line-number output. */ ! 625: ! 626: void ! 627: set_current_gdbfile (filename) ! 628: char *filename; ! 629: { ! 630: register struct gdbfile *f; ! 631: for (f = gdbfiles; f; f = f->next) ! 632: if (!strcmp (f->name, filename)) ! 633: break; ! 634: ! 635: if (!f) ! 636: { ! 637: f = (struct gdbfile *) permalloc (sizeof (struct gdbfile)); ! 638: f->next = gdbfiles; ! 639: gdbfiles = f; ! 640: f->name = filename; ! 641: f->filenum = next_gdb_filenum++; ! 642: f->nlines = 0; ! 643: } ! 644: current_gdbfile = f; ! 645: lastfile = filename; ! 646: } ! 647: ! 648: /* Output debugging info to the assembler file FILE ! 649: based on the NOTE-insn INSN, assumed to be a line number. */ ! 650: ! 651: static void ! 652: output_source_line (file, insn, write_symbols) ! 653: FILE *file; ! 654: rtx insn; ! 655: int write_symbols; ! 656: { ! 657: register char *filename = NOTE_SOURCE_FILE (insn); ! 658: if (write_symbols == 1) ! 659: { ! 660: /* Output GDB-format line number info. */ ! 661: ! 662: /* If this is not the same source file as last time, ! 663: find or assign a GDB-file-number to this file. */ ! 664: if (filename && (lastfile == 0 || strcmp (filename, lastfile) ! 665: || current_gdbfile == 0)) ! 666: set_current_gdbfile (filename); ! 667: ! 668: ++current_gdbfile->nlines; ! 669: fprintf (file, "\t.gdbline %d,%d\n", ! 670: current_gdbfile->filenum, NOTE_LINE_NUMBER (insn)); ! 671: } ! 672: else ! 673: { ! 674: /* Write DBX line number data. */ ! 675: ! 676: if (filename && (lastfile == 0 || strcmp (filename, lastfile))) ! 677: #ifdef ASM_OUTPUT_SOURCE_FILENAME ! 678: ASM_OUTPUT_SOURCE_FILENAME (file, filename); ! 679: #else ! 680: fprintf (file, "\t.stabs \"%s\",%d,0,0,Ltext\n", ! 681: filename, N_SOL); ! 682: #endif ! 683: lastfile = filename; ! 684: ! 685: #ifdef ASM_OUTPUT_SOURCE_LINE ! 686: ASM_OUTPUT_SOURCE_LINE (file, NOTE_LINE_NUMBER (insn)); ! 687: #else ! 688: fprintf (file, "\t.stabd %d,0,%d\n", ! 689: N_SLINE, NOTE_LINE_NUMBER (insn)); ! 690: #endif ! 691: } ! 692: } ! 693: ! 694: /* If X is a SUBREG, replace it with a REG or a MEM, ! 695: based on the thing it is a subreg of. */ ! 696: ! 697: static void ! 698: alter_subreg (x) ! 699: register rtx x; ! 700: { ! 701: register rtx y = SUBREG_REG (x); ! 702: if (GET_CODE (y) == SUBREG) ! 703: alter_subreg (y); ! 704: ! 705: if (GET_CODE (y) == REG) ! 706: { ! 707: /* If the containing reg really gets a hard reg, so do we. */ ! 708: PUT_CODE (x, REG); ! 709: REGNO (x) = REGNO (y) + SUBREG_WORD (x); ! 710: } ! 711: else if (GET_CODE (y) == MEM) ! 712: { ! 713: register int offset = SUBREG_WORD (x) * UNITS_PER_WORD; ! 714: #ifdef BYTES_BIG_ENDIAN ! 715: offset -= (min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))) ! 716: - min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y)))); ! 717: #endif ! 718: PUT_CODE (x, MEM); ! 719: XEXP (x, 0) = plus_constant (XEXP (y, 0), offset); ! 720: } ! 721: } ! 722: ! 723: /* Do alter_subreg on all the SUBREGs contained in X. */ ! 724: ! 725: static rtx ! 726: walk_alter_subreg (x) ! 727: rtx x; ! 728: { ! 729: switch (GET_CODE (x)) ! 730: { ! 731: case PLUS: ! 732: case MULT: ! 733: XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0)); ! 734: XEXP (x, 1) = walk_alter_subreg (XEXP (x, 1)); ! 735: break; ! 736: ! 737: case MEM: ! 738: XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0)); ! 739: break; ! 740: ! 741: case SUBREG: ! 742: alter_subreg (x); ! 743: } ! 744: ! 745: return x; ! 746: } ! 747: ! 748: /* Given BODY, the body of a jump instruction, alter the jump condition ! 749: as required by the bits that are set in cc_status.flags. ! 750: Not all of the bits there can be handled at this level in all cases. ! 751: The bits that are taken care of here are cleared. ! 752: ! 753: The value is normally 0. ! 754: In this case, COND itself has usually been altered. ! 755: 1 means that the condition has become always true. ! 756: -1 means that the condition has become always false. */ ! 757: ! 758: static int ! 759: alter_cond (cond) ! 760: register rtx cond; ! 761: { ! 762: int value = 0; ! 763: ! 764: if (cc_status.flags & CC_REVERSED) ! 765: { ! 766: value = 2; ! 767: switch (GET_CODE (cond)) ! 768: { ! 769: case LE: ! 770: PUT_CODE (cond, GE); ! 771: break; ! 772: case GE: ! 773: PUT_CODE (cond, LE); ! 774: break; ! 775: case LT: ! 776: PUT_CODE (cond, GT); ! 777: break; ! 778: case GT: ! 779: PUT_CODE (cond, LT); ! 780: break; ! 781: case LEU: ! 782: PUT_CODE (cond, GEU); ! 783: break; ! 784: case GEU: ! 785: PUT_CODE (cond, LEU); ! 786: break; ! 787: case LTU: ! 788: PUT_CODE (cond, GTU); ! 789: break; ! 790: case GTU: ! 791: PUT_CODE (cond, LTU); ! 792: break; ! 793: } ! 794: } ! 795: ! 796: if (cond != 0 && cc_status.flags & CC_NOT_POSITIVE) ! 797: switch (GET_CODE (cond)) ! 798: { ! 799: case LE: ! 800: case LEU: ! 801: case GEU: ! 802: /* Jump becomes unconditional. */ ! 803: return 1; ! 804: ! 805: case GT: ! 806: case GTU: ! 807: case LTU: ! 808: /* Jump becomes no-op. */ ! 809: return -1; ! 810: ! 811: case GE: ! 812: PUT_CODE (cond, EQ); ! 813: value = 2; ! 814: break; ! 815: ! 816: case LT: ! 817: PUT_CODE (cond, NE); ! 818: value = 2; ! 819: break; ! 820: } ! 821: ! 822: if (cond != 0 && cc_status.flags & CC_NOT_NEGATIVE) ! 823: switch (GET_CODE (cond)) ! 824: { ! 825: case GE: ! 826: case GEU: ! 827: /* Jump becomes unconditional. */ ! 828: return 1; ! 829: ! 830: case LT: ! 831: case LTU: ! 832: /* Jump becomes no-op. */ ! 833: return -1; ! 834: ! 835: case LE: ! 836: case LEU: ! 837: PUT_CODE (cond, EQ); ! 838: value = 2; ! 839: break; ! 840: ! 841: case GT: ! 842: case GTU: ! 843: PUT_CODE (cond, NE); ! 844: value = 2; ! 845: break; ! 846: } ! 847: ! 848: if (cond != 0 && cc_status.flags & CC_NO_OVERFLOW) ! 849: switch (GET_CODE (cond)) ! 850: { ! 851: case GEU: ! 852: /* Jump becomes unconditional. */ ! 853: return 1; ! 854: ! 855: case LEU: ! 856: PUT_CODE (cond, EQ); ! 857: value = 2; ! 858: break; ! 859: ! 860: case GTU: ! 861: PUT_CODE (cond, NE); ! 862: value = 2; ! 863: break; ! 864: ! 865: case LTU: ! 866: /* Jump becomes no-op. */ ! 867: return -1; ! 868: } ! 869: ! 870: return value; ! 871: } ! 872: ! 873: /* Output of assembler code from a template, and its subroutines. */ ! 874: ! 875: /* Output text from TEMPLATE to the assembler output file, ! 876: obeying %-directions to substitute operands taken from ! 877: the vector OPERANDS. ! 878: ! 879: %N (for N a digit) means print operand N in usual manner. ! 880: %lN means require operand N to be a CODE_LABEL or LABEL_REF ! 881: and print the label name with no punctuation. ! 882: %cN means require operand N to be a constant ! 883: and print the constant expression with no punctuation. ! 884: %aN means expect operand N to be a memory address ! 885: (not a memory reference!) and print a reference ! 886: to that address. ! 887: %nN means expect operand N to be a constant ! 888: and print a constant expression for minus the value ! 889: of the operand, with no other punctuation. */ ! 890: ! 891: void ! 892: output_asm_insn (template, operands) ! 893: char *template; ! 894: rtx *operands; ! 895: { ! 896: register char *p; ! 897: register int c; ! 898: ! 899: /* An insn may return a null string template ! 900: in a case where no assembler code is needed. */ ! 901: if (*template == 0) ! 902: return; ! 903: ! 904: p = template; ! 905: putc ('\t', asm_out_file); ! 906: ! 907: #ifdef ASM_OUTPUT_OPCODE ! 908: ASM_OUTPUT_OPCODE (asm_out_file, p); ! 909: #endif ! 910: ! 911: while (c = *p++) ! 912: { ! 913: #ifdef ASM_OUTPUT_OPCODE ! 914: if (c == '\n') ! 915: { ! 916: putc (c, asm_out_file); ! 917: while ((c = *p) == '\t') ! 918: { ! 919: putc (c, asm_out_file); ! 920: p++; ! 921: } ! 922: ASM_OUTPUT_OPCODE (asm_out_file, p); ! 923: } ! 924: else ! 925: #endif ! 926: if (c != '%') ! 927: putc (c, asm_out_file); ! 928: else ! 929: { ! 930: /* %% outputs a single %. */ ! 931: if (*p == '%') ! 932: { ! 933: p++; ! 934: putc (c, asm_out_file); ! 935: } ! 936: /* % followed by a letter and some digits ! 937: outputs an operand in a special way depending on the letter. ! 938: Letters `acln' are implemented here. ! 939: Other letters are passed to `output_operand' so that ! 940: the PRINT_OPERAND macro can define them. */ ! 941: else if ((*p >= 'a' && *p <= 'z') ! 942: || (*p >= 'A' && *p <= 'Z')) ! 943: { ! 944: int letter = *p++; ! 945: c = atoi (p); ! 946: ! 947: if (letter == 'l') ! 948: output_asm_label (operands[c]); ! 949: else if (letter == 'a') ! 950: output_address (operands[c]); ! 951: else if (letter == 'c') ! 952: { ! 953: if (CONSTANT_ADDRESS_P (operands[c])) ! 954: output_addr_const (asm_out_file, operands[c]); ! 955: else ! 956: output_operand (operands[c], 'c'); ! 957: } ! 958: else if (letter == 'n') ! 959: { ! 960: if (GET_CODE (operands[c]) == CONST_INT) ! 961: fprintf (asm_out_file, "%d", - INTVAL (operands[c])); ! 962: else ! 963: { ! 964: putc ('-', asm_out_file); ! 965: output_addr_const (asm_out_file, operands[c]); ! 966: } ! 967: } ! 968: else if (*p >= '0' && *p <= '9') ! 969: output_operand (operands[c], letter); ! 970: else ! 971: /* No operand-number follows the letter. */ ! 972: output_operand (0, letter); ! 973: ! 974: while ((c = *p) >= '0' && c <= '9') p++; ! 975: } ! 976: /* % followed by a digit outputs an operand the default way. */ ! 977: else if (*p >= '0' && *p <= '9') ! 978: { ! 979: c = atoi (p); ! 980: output_operand (operands[c], 0); ! 981: while ((c = *p) >= '0' && c <= '9') p++; ! 982: } ! 983: /* % followed by punctuation: output something for that ! 984: punctuation character alone, with no operand. ! 985: The PRINT_OPERAND macro decides what is actually done. */ ! 986: else ! 987: output_operand (0, *p++); ! 988: } ! 989: } ! 990: ! 991: putc ('\n', asm_out_file); ! 992: } ! 993: ! 994: /* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */ ! 995: ! 996: void ! 997: output_asm_label (x) ! 998: rtx x; ! 999: { ! 1000: char buf[20]; ! 1001: ! 1002: if (GET_CODE (x) == LABEL_REF) ! 1003: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); ! 1004: else if (GET_CODE (x) == CODE_LABEL) ! 1005: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); ! 1006: else ! 1007: abort (); ! 1008: ! 1009: assemble_name (asm_out_file, buf); ! 1010: } ! 1011: ! 1012: /* Print operand X using machine-dependent assembler syntax. ! 1013: The macro PRINT_OPERAND is defined just to control this function. ! 1014: CODE is a non-digit that preceded the operand-number in the % spec, ! 1015: such as 'z' if the spec was `%z3'. CODE is 0 if there was no char ! 1016: between the % and the digits. ! 1017: When CODE is a non-letter, X is 0. ! 1018: ! 1019: The meanings of the letters are machine-dependent and controlled ! 1020: by PRINT_OPERAND. */ ! 1021: ! 1022: static void ! 1023: output_operand (x, code) ! 1024: rtx x; ! 1025: int code; ! 1026: { ! 1027: if (x && GET_CODE (x) == SUBREG) ! 1028: alter_subreg (x); ! 1029: PRINT_OPERAND (asm_out_file, x, code); ! 1030: } ! 1031: ! 1032: /* Print a memory reference operand for address X ! 1033: using machine-dependent assembler syntax. ! 1034: The macro PRINT_OPERAND_ADDRESS exists just to control this function. */ ! 1035: ! 1036: void ! 1037: output_address (x) ! 1038: rtx x; ! 1039: { ! 1040: walk_alter_subreg (x); ! 1041: PRINT_OPERAND_ADDRESS (asm_out_file, x); ! 1042: } ! 1043: ! 1044: /* Print an integer constant expression in assembler syntax. ! 1045: Addition and subtraction are the only arithmetic ! 1046: that may appear in these expressions. */ ! 1047: ! 1048: void ! 1049: output_addr_const (file, x) ! 1050: FILE *file; ! 1051: rtx x; ! 1052: { ! 1053: char buf[20]; ! 1054: ! 1055: restart: ! 1056: switch (GET_CODE (x)) ! 1057: { ! 1058: case SYMBOL_REF: ! 1059: assemble_name (file, XSTR (x, 0)); ! 1060: break; ! 1061: ! 1062: case LABEL_REF: ! 1063: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); ! 1064: assemble_name (asm_out_file, buf); ! 1065: break; ! 1066: ! 1067: case CODE_LABEL: ! 1068: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); ! 1069: assemble_name (asm_out_file, buf); ! 1070: break; ! 1071: ! 1072: case CONST_INT: ! 1073: fprintf (file, "%d", INTVAL (x)); ! 1074: break; ! 1075: ! 1076: case CONST: ! 1077: x = XEXP (x, 0); ! 1078: goto restart; ! 1079: ! 1080: case PLUS: ! 1081: output_addr_const (file, XEXP (x, 0)); ! 1082: fprintf (file, "+"); ! 1083: output_addr_const (file, XEXP (x, 1)); ! 1084: break; ! 1085: ! 1086: case MINUS: ! 1087: output_addr_const (file, XEXP (x, 0)); ! 1088: fprintf (file, "-"); ! 1089: output_addr_const (file, XEXP (x, 1)); ! 1090: break; ! 1091: ! 1092: default: ! 1093: abort (); ! 1094: } ! 1095: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.