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