|
|
1.1 ! root 1: /* Convert RTL to assembler code and output it, for GNU compiler. ! 2: Copyright (C) 1987 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: Final is responsible for changing pseudo-register references ! 26: into hard regs or stack slots. This is done by altering the ! 27: REG rtx's for the pseudo regs into either hard regs or MEM rtx's. ! 28: SUBREG rtx's must also be altered. ! 29: ! 30: Some optimizations are also done at this level. ! 31: Move instructions that were made unnecessary by good register allocation ! 32: are detected and omitted from the output. ! 33: Instructions to set the condition codes are omitted when it can be ! 34: seen that the condition codes already had the desired values. ! 35: In some cases it is sufficient if the inherited condition codes ! 36: have related values, but this may require the following insn ! 37: (the one that tests the condition codes) to be modified. ! 38: ! 39: The code for the function prologue and epilogue are generated ! 40: directly as assembler code by the macros FUNCTION_PROLOGUE and ! 41: FUNCTION_EPILOGUE. Those instructions never exist as rtl. */ ! 42: ! 43: #include <stdio.h> ! 44: #include <stab.h> ! 45: #include "config.h" ! 46: #include "rtl.h" ! 47: #include "regs.h" ! 48: #include "insn-config.h" ! 49: #include "recog.h" ! 50: #include "conditions.h" ! 51: ! 52: #define min(A,B) ((A) < (B) ? (A) : (B)) ! 53: ! 54: void output_asm_insn (); ! 55: static void alter_reg (); ! 56: static void alter_subreg (); ! 57: static int alter_cond (); ! 58: static void output_asm_label (); ! 59: static void output_operand (); ! 60: static void output_address (); ! 61: static void output_addr_reg (); ! 62: void output_addr_const (); ! 63: ! 64: static char *reg_name[] = REGISTER_NAMES; ! 65: ! 66: /* File in which assembler code is being written. */ ! 67: ! 68: static FILE *outfile; ! 69: ! 70: /* All the symbol-blocks (levels of scoping) in the compilation ! 71: are assigned sequence numbers in order of appearance of the ! 72: beginnings of the symbol-blocks. Both final and dbxout do this, ! 73: and assume that they will both give the same number to each block. ! 74: Final uses these sequence numbers to generate assembler label names ! 75: LBBnnn and LBEnnn for the beginning and end of the symbol-block. ! 76: Dbxout uses the sequence nunbers to generate references to the same labels ! 77: from the dbx debugging information. */ ! 78: ! 79: static next_block_index; ! 80: ! 81: /* This variable contains machine-dependent flags (defined in tm-...h) ! 82: set and examined by output routines ! 83: that describe how to interpret the condition codes properly. */ ! 84: ! 85: CC_STATUS cc_status; ! 86: ! 87: /* Last source file name mentioned in a NOTE insn. */ ! 88: ! 89: static char *lastfile; ! 90: ! 91: /* Indexed by hardware reg number, is 1 if that register is ever ! 92: used in the current function. ! 93: ! 94: In life_analysis, or in stupid_life_analysis, this is set ! 95: up to record the hard regs used explicitly. Reload adds ! 96: in the hard regs used for holding pseudo regs. Final uses ! 97: it to generate the code in the function prologue and epilogue ! 98: to save and restore registers as needed. */ ! 99: ! 100: char regs_ever_live[FIRST_PSEUDO_REGISTER]; ! 101: ! 102: /* Element N is nonzero if pseudo-reg N is being allocated in memory. ! 103: The value of the element is an rtx (MEM ...) to be used ! 104: to replace references to pseudo-reg N. ! 105: This is set up at the end of global allocation. ! 106: ! 107: These MEM rtx's all have VOIDmode because we do not know the correct mode. ! 108: When they are substituted into the code, they will be given the ! 109: correct mode, copied from the (REG...) being replaced. */ ! 110: ! 111: rtx *reg_spill_replacement; ! 112: ! 113: /* Initialize data in final at the beginning of a compilation. */ ! 114: ! 115: void ! 116: init_final (filename) ! 117: char *filename; ! 118: { ! 119: next_block_index = 2; ! 120: lastfile = filename; ! 121: } ! 122: ! 123: /* Main entry point for final pass: output assembler code from rtl. ! 124: FIRST is the first insn of the rtl for the function being compiled. ! 125: FILE is the file to write assembler code to. ! 126: FNNAME is the name of the function being compiled. ! 127: WRITE_SYMBOLS is 1 for gdb symbols, 2 for dbx symbols. ! 128: OPTIMIZE is nonzero if we should eliminate redundant ! 129: test and compare insns. */ ! 130: ! 131: void ! 132: final (first, file, fnname, write_symbols, optimize) ! 133: rtx first; ! 134: FILE *file; ! 135: char *fnname; ! 136: int write_symbols; ! 137: int optimize; ! 138: { ! 139: register rtx insn; ! 140: register int i; ! 141: ! 142: /* Length so far allocated in PENDING_BLOCKS. */ ! 143: int max_depth = 20; ! 144: /* Stack of sequence numbers of symbol-blocks of which we have seen the ! 145: beginning but not yet the end. Sequence numbers are assigned at ! 146: the beginning; this stack allows us to find the sequence number ! 147: of a block that is ending. */ ! 148: int *pending_blocks = (int *) alloca (max_depth * sizeof (int)); ! 149: /* Number of elements currently in use in PENDING_BLOCKS. */ ! 150: int depth = 0; ! 151: ! 152: /* Allocate in the stack frame whatever did not make it into a hard reg. */ ! 153: ! 154: reg_spill_replacement = (rtx *) alloca (max_regno * sizeof (rtx)); ! 155: bzero (reg_spill_replacement, max_regno * sizeof (rtx)); ! 156: ! 157: /* Parameter copies that didn't get into hardware registers ! 158: should be referenced in the parameter list. ! 159: For other registers, allocate a local stack slot. */ ! 160: ! 161: for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) ! 162: { ! 163: if (reg_renumber[i] < 0 && reg_n_refs[i] > 0) ! 164: reg_spill_replacement[i] ! 165: = assign_stack_local (VOIDmode, PSEUDO_REGNO_BYTES (i)); ! 166: alter_reg (regno_reg_rtx[i]); ! 167: } ! 168: ! 169: init_recog (); ! 170: outfile = file; ! 171: ! 172: /* Tell assembler to switch to text segment. */ ! 173: ! 174: fprintf (file, "%s\n", TEXT_SECTION_ASM_OP); ! 175: ! 176: /* Tell assembler to move to target machine's alignment for functions. */ ! 177: ! 178: ASM_OUTPUT_ALIGN (file, floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT)); ! 179: ! 180: /* Output label for the function. */ ! 181: ! 182: fprintf (file, "_%s:\n", fnname); ! 183: ! 184: /* Record beginning of the symbol-block that's the entire function. */ ! 185: /* Is this incorrect now? */ ! 186: ! 187: if (write_symbols == 1) ! 188: { ! 189: pending_blocks[depth++] = next_block_index; ! 190: fprintf (file, "\t.gdbbeg %d\n", next_block_index++); ! 191: } ! 192: ! 193: /* Initial line number is supposed to be output ! 194: before the function's prologue and label ! 195: so that the function's address will not appear to be ! 196: in the last statement of the preceding function. */ ! 197: if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED) ! 198: output_source_line (file, first); ! 199: ! 200: #ifdef FUNCTION_PROLOGUE ! 201: /* First output the function prologue: code to set up the stack frame. */ ! 202: FUNCTION_PROLOGUE (file, get_frame_size ()); ! 203: #endif ! 204: ! 205: CC_STATUS_INIT; ! 206: ! 207: for (insn = NEXT_INSN (first); insn; insn = NEXT_INSN (insn)) ! 208: { ! 209: switch (GET_CODE (insn)) ! 210: { ! 211: case NOTE: ! 212: if (! write_symbols) ! 213: break; ! 214: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) ! 215: abort (); /* Obsolete; shouldn't appear */ ! 216: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG ! 217: || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) ! 218: break; ! 219: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED) ! 220: break; /* An insn that was "deleted" */ ! 221: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG) ! 222: { ! 223: /* Beginning of a symbol-block. Assign it a sequence number ! 224: and push the number onto the stack PENDING_BLOCKS. */ ! 225: ! 226: if (depth == max_depth) ! 227: { ! 228: /* PENDING_BLOCKS is full; make it longer. */ ! 229: register int *new ! 230: = (int *) alloca (2 * max_depth * sizeof (int)); ! 231: bcopy (pending_blocks, new, max_depth * sizeof (int)); ! 232: pending_blocks = new; ! 233: max_depth <<= 1; ! 234: } ! 235: pending_blocks[depth++] = next_block_index; ! 236: ! 237: /* Output debugging info about the symbol-block beginning. */ ! 238: ! 239: if (write_symbols == 2) ! 240: fprintf (file, "LBB%d:\n", next_block_index++); ! 241: else ! 242: fprintf (file, "\t.gdbbeg %d\n", next_block_index++); ! 243: } ! 244: else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END) ! 245: { ! 246: /* End of a symbol-block. Pop its sequence number off ! 247: PENDING_BLOCKS and output debugging info based on that. */ ! 248: ! 249: if (write_symbols == 2) ! 250: { ! 251: if (depth > 0) ! 252: fprintf (file, "LBE%d:\n", pending_blocks[--depth]); ! 253: } ! 254: else ! 255: fprintf (file, "\t.gdbend %d\n", pending_blocks[--depth]); ! 256: } ! 257: else ! 258: /* This note is a line-number. */ ! 259: output_source_line (file, insn); ! 260: break; ! 261: ! 262: case BARRIER: ! 263: break; ! 264: ! 265: case CODE_LABEL: ! 266: fprintf (file, "L%d:\n", CODE_LABEL_NUMBER (insn)); ! 267: CC_STATUS_INIT; ! 268: break; ! 269: ! 270: default: ! 271: { ! 272: register rtx body = PATTERN (insn); ! 273: int insn_code_number; ! 274: char *template; ! 275: ! 276: /* An INSN, JUMP_INSN or CALL_INSN. ! 277: First check for special kinds. */ ! 278: ! 279: if (GET_CODE (body) == USE /* These are just declarations */ ! 280: || GET_CODE (body) == CLOBBER) ! 281: break; ! 282: if (GET_CODE (body) == ASM_INPUT) ! 283: { ! 284: output_asm_insn (XSTR (body, 0), 0); ! 285: break; ! 286: } ! 287: ! 288: /* Detect insns that are really jump-tables ! 289: and output them as such. */ ! 290: ! 291: if (GET_CODE (body) == ADDR_VEC) ! 292: { ! 293: enum machine_mode mode = GET_MODE (body); ! 294: char *pseudo = (mode == SImode) ? ".int" ! 295: : ((mode == HImode) ? ".word" : (char *) abort ()); ! 296: register int vlen, idx; ! 297: vlen = XVECLEN (body, 0); ! 298: for (idx = 0; idx < vlen; idx++) ! 299: fprintf (file, "\t%s L%d\n", pseudo, ! 300: CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); ! 301: break; ! 302: } ! 303: if (GET_CODE (body) == ADDR_DIFF_VEC) ! 304: { ! 305: enum machine_mode mode = GET_MODE (body); ! 306: char *pseudo = (mode == SImode) ? ".int" ! 307: : ((mode == HImode) ? ".word" : (char *) abort ()); ! 308: register int vlen, idx; ! 309: vlen = XVECLEN (body, 1); ! 310: for (idx = 0; idx < vlen; idx++) ! 311: fprintf (file, "\t%s L%d-L%d\n", pseudo, ! 312: CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), ! 313: CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0))); ! 314: break; ! 315: } ! 316: ! 317: /* We have a real machine instruction as rtl. */ ! 318: ! 319: body = PATTERN (insn); ! 320: ! 321: /* Detect and ignore no-op move instructions ! 322: resulting from not allocating a parameter in a register. */ ! 323: ! 324: if (GET_CODE (body) == SET ! 325: && (SET_DEST (body) == SET_SRC (body) ! 326: || (GET_CODE (SET_DEST (body)) == MEM ! 327: && GET_CODE (SET_SRC (body)) == MEM ! 328: && (XEXP (SET_DEST (body), 0) ! 329: == XEXP (SET_SRC (body), 0)))) ! 330: && GET_CODE (SET_DEST (body)) != VOLATILE) ! 331: break; ! 332: ! 333: /* Detect and ignore no-op move instructions ! 334: resulting from smart or fortuitous register allocation. */ ! 335: ! 336: if (GET_CODE (body) == SET) ! 337: { ! 338: if (GET_CODE (SET_DEST (body)) == SUBREG) ! 339: alter_subreg (SET_DEST (body)); ! 340: if (GET_CODE (SET_SRC (body)) == SUBREG) ! 341: alter_subreg (SET_SRC (body)); ! 342: if (GET_CODE (SET_DEST (body)) == REG ! 343: && GET_CODE (SET_SRC (body)) == REG) ! 344: { ! 345: rtx tem; ! 346: if (REGNO (SET_DEST (body)) ! 347: == REGNO (SET_SRC (body))) ! 348: break; ! 349: tem = find_equiv_reg (SET_DEST (body), insn, 0, ! 350: REGNO (SET_SRC (body)), 0); ! 351: if (tem != 0 ! 352: && GET_MODE (tem) == GET_MODE (SET_DEST (body))) ! 353: break; ! 354: } ! 355: } ! 356: ! 357: /* Check for redundant test and compare instructions ! 358: (when the condition codes are already set up as desired). ! 359: This is done only when optimizing; if not optimizing, ! 360: it should be possible for the user to alter a variable ! 361: with the debugger in between statements ! 362: and the next statement should reexamine the variable ! 363: to compute the condition codes. */ ! 364: ! 365: if (optimize ! 366: && GET_CODE (body) == SET ! 367: && GET_CODE (SET_DEST (body)) == CC0) ! 368: { ! 369: if (GET_CODE (SET_SRC (body)) == SUBREG) ! 370: alter_subreg (SET_SRC (body)); ! 371: if ((cc_status.value1 != 0 ! 372: && rtx_equal_p (SET_SRC (body), cc_status.value1)) ! 373: || (cc_status.value2 != 0 ! 374: && rtx_equal_p (SET_SRC (body), cc_status.value2))) ! 375: break; ! 376: } ! 377: ! 378: /* If this is a conditional branch, maybe modify it ! 379: if the cc's are in a nonstandard state ! 380: so that it accomplishes the same thing that it would ! 381: do straightforwardly if the cc's were set up normally. */ ! 382: ! 383: if (cc_status.flags != 0 ! 384: && GET_CODE (insn) == JUMP_INSN ! 385: && GET_CODE (body) == SET ! 386: && SET_DEST (body) == pc_rtx ! 387: && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE) ! 388: { ! 389: /* This function may alter the contents of its argument ! 390: and clear some of the cc_status.flags bits. ! 391: It may also return 1 meaning condition now always true ! 392: or -1 meaning condition now always false ! 393: or 2 meaning condition nontrivial but altered. */ ! 394: register int result = alter_cond (XEXP (SET_SRC (body), 0)); ! 395: /* If condition now has fixed value, replace the IF_THEN_ELSE ! 396: with its then-operand or its else-operand. */ ! 397: if (result == 1) ! 398: SET_SRC (body) = XEXP (SET_SRC (body), 1); ! 399: if (result == -1) ! 400: SET_SRC (body) = XEXP (SET_SRC (body), 2); ! 401: /* The jump is now either unconditional or a no-op. ! 402: If it has become a no-op, don't try to output it. ! 403: (It would not be recognized.) */ ! 404: if (SET_SRC (body) == pc_rtx) ! 405: continue; ! 406: /* Rerecognize the instruction if it has changed. */ ! 407: if (result != 0) ! 408: INSN_CODE (insn) = -1; ! 409: } ! 410: ! 411: /* Make same adjustments to instructions that examine the ! 412: condition codes without jumping. */ ! 413: ! 414: if (cc_status.flags != 0 ! 415: && GET_CODE (body) == SET) ! 416: switch (GET_CODE (SET_SRC (body))) ! 417: { ! 418: case GTU: ! 419: case GT: ! 420: case LTU: ! 421: case LT: ! 422: case GEU: ! 423: case GE: ! 424: case LEU: ! 425: case LE: ! 426: case EQ: ! 427: case NE: ! 428: { ! 429: register int result = alter_cond (SET_SRC (body)); ! 430: if (result == 1) ! 431: SET_SRC (body) = gen_rtx (CONST_INT, VOIDmode, -1); ! 432: if (result == -1) ! 433: SET_SRC (body) = const0_rtx; ! 434: if (result != 0) ! 435: INSN_CODE (insn) = -1; ! 436: } ! 437: } ! 438: ! 439: /* Try to recognize the instruction. ! 440: If successful, verify that the operands satisfy the ! 441: constraints for the instruction. Crash if they don't, ! 442: since `reload' should have changed them so that they do. */ ! 443: ! 444: insn_code_number = recog_memoized (insn); ! 445: insn_extract (insn); ! 446: for (i = 0; i < insn_n_operands[insn_code_number]; i++) ! 447: if (GET_CODE (recog_operand[i]) == SUBREG) ! 448: alter_subreg (recog_operand[i]); ! 449: ! 450: #ifdef REGISTER_CONSTRAINTS ! 451: if (! constrain_operands (insn_code_number)) ! 452: abort (); ! 453: #endif ! 454: ! 455: /* Update `cc_status' for this instruction. ! 456: The instruction's output routine may change it further. ! 457: This should be a no-op for jump instructions ! 458: because their output routines may need to examine `cc_status', ! 459: below. That's ok since jump insns don't normally alter ! 460: the condition codes. */ ! 461: ! 462: NOTICE_UPDATE_CC (body); ! 463: ! 464: /* If the proper template needs to be chosen by some C code, ! 465: run that code and get the real template. ! 466: In this case the template we were passed ! 467: consists of * and a decimal number. ! 468: The number is used to select which case is run, ! 469: in output_insn_hairy, a machine-generated function ! 470: that all the C code for these situations is written into. */ ! 471: ! 472: template = insn_template[insn_code_number]; ! 473: if (template == 0) ! 474: template = output_insn_hairy (insn_code_number, ! 475: recog_operand, insn); ! 476: ! 477: /* Output assembler code from the template. */ ! 478: ! 479: output_asm_insn (template, recog_operand); ! 480: } ! 481: } ! 482: } ! 483: ! 484: #ifdef FUNCTION_EPILOGUE ! 485: /* Finally, output the function epilogue: ! 486: code to restore the stack frame and return to the caller. */ ! 487: FUNCTION_EPILOGUE (file, get_frame_size ()); ! 488: #endif ! 489: ! 490: /* If FUNCTION_EPILOGUE is not defined, then the function body ! 491: itself contains return instructions wherever needed. */ ! 492: } ! 493: ! 494: /* Output debugging info to the assembler file ! 495: based on the NOTE insn INSN, assumed to be a line number. */ ! 496: ! 497: output_source_line (file, insn) ! 498: FILE *file; ! 499: rtx insn; ! 500: { ! 501: register char *filename = NOTE_SOURCE_FILE (insn); ! 502: if (filename && (lastfile == 0 || strcmp (filename, lastfile))) ! 503: fprintf (file, "\t.stabs \"%s\",%d,0,0,Ltext\n", ! 504: filename, N_SOL); ! 505: lastfile = filename; ! 506: ! 507: fprintf (file, "\t.stabd %d,0,%d\n", ! 508: N_SLINE, NOTE_LINE_NUMBER (insn)); ! 509: } ! 510: ! 511: /* Replace all pseudo regs in *X with their allocated homes: ! 512: either a hard reg found in reg_renumber ! 513: or a memory location found in reg_spill_replacement. */ ! 514: ! 515: static void ! 516: alter_subreg (x) ! 517: register rtx x; ! 518: { ! 519: register rtx y = SUBREG_REG (x); ! 520: if (GET_CODE (y) == SUBREG) ! 521: alter_subreg (y); ! 522: ! 523: if (GET_CODE (y) == REG) ! 524: { ! 525: /* If the containing reg really gets a hard reg, so do we. */ ! 526: PUT_CODE (x, REG); ! 527: REGNO (x) = REGNO (y) + SUBREG_WORD (x); ! 528: } ! 529: else if (GET_CODE (y) == MEM) ! 530: { ! 531: register int offset = SUBREG_WORD (x) * BITS_PER_WORD; ! 532: #ifdef BYTES_BIG_ENDIAN ! 533: if (GET_MODE_SIZE (GET_MODE (x)) < UNITS_PER_WORD) ! 534: offset -= (GET_MODE_SIZE (GET_MODE (x)) ! 535: - min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y)))); ! 536: #endif ! 537: PUT_CODE (x, MEM); ! 538: XEXP (x, 0) = plus_constant (XEXP (y, 0), offset); ! 539: } ! 540: } ! 541: ! 542: static void ! 543: alter_reg (reg) ! 544: rtx reg; ! 545: { ! 546: register int regno = REGNO (reg); ! 547: ! 548: if (reg_spill_replacement[regno] != 0) ! 549: { ! 550: PUT_CODE (reg, MEM); ! 551: XEXP (reg, 0) = XEXP (reg_spill_replacement[regno], 0); ! 552: } ! 553: else ! 554: REGNO (reg) = reg_renumber[regno]; ! 555: ! 556: return; ! 557: } ! 558: ! 559: /* Given BODY, the body of a jump instruction, alter the jump condition ! 560: as required by the bits that are set in cc_status.flags. ! 561: Not all of the bits there can be handled at this level in all cases. ! 562: The bits that are taken care of here are cleared. ! 563: ! 564: The value is normally 0. ! 565: In this case, COND itself has usually been altered. ! 566: 1 means that the condition has become always true. ! 567: -1 means that the condition has become always false. */ ! 568: ! 569: static int ! 570: alter_cond (cond) ! 571: register rtx cond; ! 572: { ! 573: int value = 0; ! 574: ! 575: if (cc_status.flags & CC_REVERSED) ! 576: { ! 577: value = 2; ! 578: switch (GET_CODE (cond)) ! 579: { ! 580: case LE: ! 581: PUT_CODE (cond, GE); ! 582: break; ! 583: case GE: ! 584: PUT_CODE (cond, LE); ! 585: break; ! 586: case LT: ! 587: PUT_CODE (cond, GT); ! 588: break; ! 589: case GT: ! 590: PUT_CODE (cond, LT); ! 591: break; ! 592: case LEU: ! 593: PUT_CODE (cond, GEU); ! 594: break; ! 595: case GEU: ! 596: PUT_CODE (cond, LEU); ! 597: break; ! 598: case LTU: ! 599: PUT_CODE (cond, GTU); ! 600: break; ! 601: case GTU: ! 602: PUT_CODE (cond, LTU); ! 603: break; ! 604: } ! 605: } ! 606: ! 607: if (cond != 0 && cc_status.flags & CC_NOT_POSITIVE) ! 608: switch (GET_CODE (cond)) ! 609: { ! 610: case LE: ! 611: case LEU: ! 612: case GEU: ! 613: /* Jump becomes unconditional. */ ! 614: return 1; ! 615: ! 616: case GT: ! 617: case GTU: ! 618: case LTU: ! 619: /* Jump becomes no-op. */ ! 620: return -1; ! 621: ! 622: case GE: ! 623: PUT_CODE (cond, EQ); ! 624: value = 2; ! 625: break; ! 626: ! 627: case LT: ! 628: PUT_CODE (cond, NE); ! 629: value = 2; ! 630: break; ! 631: } ! 632: ! 633: if (cond != 0 && cc_status.flags & CC_NOT_NEGATIVE) ! 634: switch (GET_CODE (cond)) ! 635: { ! 636: case GE: ! 637: case GEU: ! 638: /* Jump becomes unconditional. */ ! 639: return 1; ! 640: ! 641: case LT: ! 642: case LTU: ! 643: /* Jump becomes no-op. */ ! 644: return -1; ! 645: ! 646: case LE: ! 647: case LEU: ! 648: PUT_CODE (cond, EQ); ! 649: value = 2; ! 650: break; ! 651: ! 652: case GT: ! 653: case GTU: ! 654: PUT_CODE (cond, NE); ! 655: value = 2; ! 656: break; ! 657: } ! 658: ! 659: if (cond != 0 && cc_status.flags & CC_NO_OVERFLOW) ! 660: switch (GET_CODE (cond)) ! 661: { ! 662: case GEU: ! 663: /* Jump becomes unconditional. */ ! 664: return 1; ! 665: ! 666: case LEU: ! 667: PUT_CODE (cond, EQ); ! 668: value = 2; ! 669: break; ! 670: ! 671: case GTU: ! 672: PUT_CODE (cond, NE); ! 673: value = 2; ! 674: break; ! 675: ! 676: case LTU: ! 677: /* Jump becomes no-op. */ ! 678: return -1; ! 679: } ! 680: ! 681: return value; ! 682: } ! 683: ! 684: /* Output of assembler code from a template, and its subroutines. */ ! 685: ! 686: /* Output text from TEMPLATE to the assembler output file, ! 687: obeying %-directions to substitute operands taken from ! 688: the vector OPERANDS. ! 689: ! 690: %N (for N a digit) means print operand N in usual manner. ! 691: %lN means require operand N to be a CODE_LABEL or LABEL_REF ! 692: and print the label name with no punctuation. ! 693: %cN means require operand N to be a constant ! 694: and print the constant expression with no punctuation. ! 695: %aN means expect operand N to be a memory address ! 696: (not a memory reference!) and print a reference ! 697: to that address. ! 698: %nN means expect operand N to be a constant ! 699: and print a constant expression for minus the value ! 700: of the operand, with no other punctuation. */ ! 701: ! 702: void ! 703: output_asm_insn (template, operands) ! 704: char *template; ! 705: rtx *operands; ! 706: { ! 707: register char *p; ! 708: register int c; ! 709: ! 710: p = template; ! 711: putc ('\t', outfile); ! 712: while (c = *p++) ! 713: { ! 714: if (c != '%') ! 715: putc (c, outfile); ! 716: else ! 717: { ! 718: if (*p == 'l') ! 719: { ! 720: c = atoi (++p); ! 721: output_asm_label (operands[c]); ! 722: } ! 723: else if (*p == 'c') ! 724: { ! 725: c = atoi (++p); ! 726: output_addr_const (outfile, operands[c]); ! 727: } ! 728: else if (*p == 'a') ! 729: { ! 730: c = atoi (++p); ! 731: output_address (operands[c]); ! 732: } ! 733: else if (*p == 'n') ! 734: { ! 735: c = atoi (++p); ! 736: if (GET_CODE (operands[c]) == CONST_INT) ! 737: fprintf (outfile, "%d", - INTVAL (operands[c])); ! 738: else ! 739: { ! 740: putc ('-', outfile); ! 741: output_addr_const (operands[c]); ! 742: } ! 743: } ! 744: else ! 745: { ! 746: c = atoi (p); ! 747: output_operand (operands[c]); ! 748: } ! 749: while ((c = *p) >= '0' && c <= '9') p++; ! 750: } ! 751: } ! 752: ! 753: putc ('\n', outfile); ! 754: } ! 755: ! 756: static void ! 757: output_asm_label (x) ! 758: rtx x; ! 759: { ! 760: if (GET_CODE (x) == LABEL_REF) ! 761: fprintf (outfile, "L%d", CODE_LABEL_NUMBER (XEXP (x, 0))); ! 762: else if (GET_CODE (x) == CODE_LABEL) ! 763: fprintf (outfile, "L%d", CODE_LABEL_NUMBER (x)); ! 764: else ! 765: abort (); ! 766: } ! 767: ! 768: /* Print operand X using machine-dependent assembler syntax. ! 769: The macro PRINT_OPERAND is defined just to control this function. */ ! 770: ! 771: static void ! 772: output_operand (x) ! 773: rtx x; ! 774: { ! 775: if (GET_CODE (x) == SUBREG) ! 776: alter_subreg (x); ! 777: PRINT_OPERAND (outfile, x); ! 778: } ! 779: ! 780: /* Print a memory reference operand for address X ! 781: using machine-dependent assembler syntax. ! 782: The macro PRINT_OPERAND_ADDRESS exists just to control this function. */ ! 783: ! 784: static void ! 785: output_address (x) ! 786: rtx x; ! 787: { ! 788: if (GET_CODE (x) == SUBREG) ! 789: alter_subreg (x); ! 790: PRINT_OPERAND_ADDRESS (outfile, x); ! 791: } ! 792: ! 793: /* Print an integer constant expression in assembler syntax. ! 794: Addition and subtraction are the only arithmetic ! 795: that may appear in these expressions. */ ! 796: ! 797: void ! 798: output_addr_const (file, x) ! 799: FILE *file; ! 800: rtx x; ! 801: { ! 802: restart: ! 803: switch (GET_CODE (x)) ! 804: { ! 805: case SYMBOL_REF: ! 806: if (XSTR (x, 0)[0] == '*') ! 807: fprintf (file, "%s", XSTR (x, 0) + 1); ! 808: else ! 809: fprintf (file, "_%s", XSTR (x, 0)); ! 810: break; ! 811: ! 812: case LABEL_REF: ! 813: fprintf (file, "L%d", CODE_LABEL_NUMBER (XEXP (x, 0))); ! 814: break; ! 815: ! 816: case CODE_LABEL: ! 817: fprintf (file, "L%d", CODE_LABEL_NUMBER (x)); ! 818: break; ! 819: ! 820: case CONST_INT: ! 821: fprintf (file, "%d", INTVAL (x)); ! 822: break; ! 823: ! 824: case CONST: ! 825: x = XEXP (x, 0); ! 826: goto restart; ! 827: ! 828: case PLUS: ! 829: output_addr_const (file, XEXP (x, 0)); ! 830: fprintf (file, "+"); ! 831: output_addr_const (file, XEXP (x, 1)); ! 832: break; ! 833: ! 834: case MINUS: ! 835: output_addr_const (file, XEXP (x, 0)); ! 836: fprintf (file, "-"); ! 837: output_addr_const (file, XEXP (x, 1)); ! 838: break; ! 839: ! 840: default: ! 841: abort (); ! 842: } ! 843: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.