|
|
1.1 root 1: /* Convert RTL to assembler code and output it, for GNU compiler.
1.1.1.13 root 2: Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc.
1.1 root 3:
4: This file is part of GNU CC.
5:
1.1.1.13 root 6: GNU CC is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License as published by
8: the Free Software Foundation; either version 1, or (at your option)
9: any later version.
10:
1.1 root 11: GNU CC is distributed in the hope that it will be useful,
1.1.1.13 root 12: but WITHOUT ANY WARRANTY; without even the implied warranty of
13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: GNU General Public License for more details.
15:
16: You should have received a copy of the GNU General Public License
17: along with GNU CC; see the file COPYING. If not, write to
18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
1.1 root 19:
20:
21: /* This is the final pass of the compiler.
22: It looks at the rtl code for a function and outputs assembler code.
23:
1.1.1.2 root 24: Call `final_start_function' to output the assembler code for function entry,
25: `final' to output assembler code for some RTL code,
26: `final_end_function' to output assembler code for function exit.
27: If a function is compiled in several pieces, each piece is
28: output separately with `final'.
1.1 root 29:
30: Some optimizations are also done at this level.
31: Move instructions that were made unnecessary by good register allocation
1.1.1.2 root 32: are detected and omitted from the output. (Though most of these
33: are removed by the last jump pass.)
34:
1.1 root 35: Instructions to set the condition codes are omitted when it can be
36: seen that the condition codes already had the desired values.
1.1.1.2 root 37:
1.1 root 38: In some cases it is sufficient if the inherited condition codes
39: have related values, but this may require the following insn
40: (the one that tests the condition codes) to be modified.
41:
42: The code for the function prologue and epilogue are generated
43: directly as assembler code by the macros FUNCTION_PROLOGUE and
44: FUNCTION_EPILOGUE. Those instructions never exist as rtl. */
45:
46: #include <stdio.h>
47: #include "config.h"
48: #include "rtl.h"
49: #include "regs.h"
50: #include "insn-config.h"
51: #include "recog.h"
52: #include "conditions.h"
1.1.1.2 root 53: #include "gdbfiles.h"
1.1.1.4 root 54: #include "flags.h"
1.1.1.12 root 55: #include "real.h"
1.1.1.15! root 56: #include "output.h"
1.1.1.2 root 57:
1.1.1.3 root 58: /* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist. */
1.1.1.4 root 59: #ifdef DBX_DEBUGGING_INFO
1.1.1.12 root 60: #ifdef USG
61: #include "stab.h" /* If doing DBX on sysV, use our own stab.h. */
62: #else
63: #include <stab.h> /* On BSD, use the system's stab.h. */
64: #endif /* not USG */
65: #endif /* DBX_DEBUGGING_INFO */
1.1.1.3 root 66:
1.1.1.2 root 67: /* .stabd code for line number. */
68: #ifndef N_SLINE
69: #define N_SLINE 0x44
70: #endif
71:
72: /* .stabs code for included file name. */
73: #ifndef N_SOL
74: #define N_SOL 0x84
75: #endif
1.1 root 76:
77: #define min(A,B) ((A) < (B) ? (A) : (B))
78:
1.1.1.15! root 79: rtx peephole ();
1.1 root 80: void output_asm_insn ();
1.1.1.10 root 81: rtx alter_subreg ();
1.1 root 82: static int alter_cond ();
1.1.1.3 root 83: void output_asm_label ();
1.1 root 84: static void output_operand ();
1.1.1.2 root 85: void output_address ();
1.1 root 86: void output_addr_const ();
1.1.1.2 root 87: static void output_source_line ();
1.1.1.15! root 88: rtx final_scan_insn ();
1.1 root 89:
1.1.1.4 root 90: /* the sdb debugger needs the line given as an offset from the beginning
91: of the current function -wfs*/
92:
93: extern int sdb_begin_function_line;
94:
95: /* Line number of last NOTE. */
96: static int last_linenum;
97:
1.1.1.13 root 98: /* Number of basic blocks seen so far;
99: used if profile_block_flag is set. */
100: static int count_basic_blocks;
101:
1.1.1.9 root 102: /* Nonzero while outputting an `asm' with operands.
1.1.1.10 root 103: This means that inconsistencies are the user's fault, so don't abort.
104: The precise value is the insn being output, to pass to error_for_asm. */
105: static rtx this_is_asm_operands;
1.1.1.9 root 106:
107: /* Number of operands of this insn, for an `asm' with operands. */
108: static int insn_noperands;
109:
1.1 root 110: /* File in which assembler code is being written. */
111:
1.1.1.2 root 112: extern FILE *asm_out_file;
1.1 root 113:
1.1.1.15! root 114: /* Compare optimization flag. */
! 115:
! 116: static rtx last_ignored_compare = 0;
! 117:
! 118: /* Flag indicating this insn is the start of a new basic block. */
! 119:
! 120: static int new_block = 1;
! 121:
1.1 root 122: /* All the symbol-blocks (levels of scoping) in the compilation
123: are assigned sequence numbers in order of appearance of the
124: beginnings of the symbol-blocks. Both final and dbxout do this,
125: and assume that they will both give the same number to each block.
126: Final uses these sequence numbers to generate assembler label names
127: LBBnnn and LBEnnn for the beginning and end of the symbol-block.
128: Dbxout uses the sequence nunbers to generate references to the same labels
1.1.1.4 root 129: from the dbx debugging information.
130:
131: Sdb records this level at the beginning
132: of each function, so that when it recurses down the declarations, it may
133: find the current level, since it outputs the block beginning and endings
134: at the point in the asm file, where the blocks would begin and end. */
1.1 root 135:
1.1.1.4 root 136: int next_block_index;
1.1 root 137:
1.1.1.2 root 138: /* Chain of all `struct gdbfile's. */
139:
140: struct gdbfile *gdbfiles;
141:
142: /* `struct gdbfile' for the last file we wrote a line number for. */
143:
144: static struct gdbfile *current_gdbfile;
145:
146: /* Filenum to assign to the next distinct source file encountered. */
147:
148: static int next_gdb_filenum;
149:
1.1 root 150: /* This variable contains machine-dependent flags (defined in tm-...h)
151: set and examined by output routines
152: that describe how to interpret the condition codes properly. */
153:
154: CC_STATUS cc_status;
155:
1.1.1.2 root 156: /* During output of an insn, this contains a copy of cc_status
157: from before the insn. */
158:
159: CC_STATUS cc_prev_status;
160:
1.1 root 161: /* Last source file name mentioned in a NOTE insn. */
162:
163: static char *lastfile;
164:
165: /* Indexed by hardware reg number, is 1 if that register is ever
166: used in the current function.
167:
168: In life_analysis, or in stupid_life_analysis, this is set
169: up to record the hard regs used explicitly. Reload adds
170: in the hard regs used for holding pseudo regs. Final uses
171: it to generate the code in the function prologue and epilogue
172: to save and restore registers as needed. */
173:
174: char regs_ever_live[FIRST_PSEUDO_REGISTER];
175:
1.1.1.2 root 176: /* Nonzero means current function must be given a frame pointer.
177: Set in stmt.c if anything is allocated on the stack there.
178: Set in reload1.c if anything is allocated on the stack there. */
179:
180: int frame_pointer_needed;
181:
182: /* Assign unique numbers to labels generated for profiling. */
183:
184: int profile_label_no;
185:
186: /* Length so far allocated in PENDING_BLOCKS. */
187:
188: static int max_block_depth;
189:
190: /* Stack of sequence numbers of symbol-blocks of which we have seen the
191: beginning but not yet the end. Sequence numbers are assigned at
192: the beginning; this stack allows us to find the sequence number
193: of a block that is ending. */
1.1 root 194:
1.1.1.2 root 195: static int *pending_blocks;
196:
197: /* Number of elements currently in use in PENDING_BLOCKS. */
198:
199: static int block_depth;
200:
201: /* Nonzero if have enabled APP processing of our assembler output. */
202:
203: static int app_on;
1.1.1.15! root 204:
! 205: /* If we are outputting an insn sequence, this contains the sequence rtx.
! 206: Zero otherwise. */
! 207:
! 208: rtx final_sequence;
1.1 root 209:
210: /* Initialize data in final at the beginning of a compilation. */
211:
212: void
213: init_final (filename)
214: char *filename;
215: {
216: next_block_index = 2;
217: lastfile = filename;
1.1.1.2 root 218: app_on = 0;
219: max_block_depth = 20;
220: pending_blocks = (int *) xmalloc (20 * sizeof *pending_blocks);
221: gdbfiles = 0;
222: next_gdb_filenum = 0;
1.1.1.15! root 223: final_sequence = 0;
1.1 root 224: }
225:
1.1.1.13 root 226: /* Called at end of source file,
227: to output the block-profiling table for this entire compilation. */
228:
229: void
230: end_final (filename)
231: char *filename;
232: {
233: int i;
234:
235: if (profile_block_flag)
236: {
237: char name[12];
238:
239: data_section ();
240:
241: /* Output the main header, of 6 words:
242: 0: 1 if this file's initialized, else 0.
243: 1: address of file name.
244: 2: address of table of counts.
245: 4: number of counts in the table.
246: 5: always 0, for compatibility with Sun.
247: 6: extra word added by GNU: address of address table
248: which contains addresses of basic blocks,
249: in parallel with the table of counts. */
250: ASM_OUTPUT_ALIGN (asm_out_file,
251: exact_log2 (min (UNITS_PER_WORD,
252: BIGGEST_ALIGNMENT / BITS_PER_UNIT)));
253:
254: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
255: assemble_integer_zero ();
256:
257: ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1);
258: ASM_OUTPUT_INT (asm_out_file, gen_rtx (SYMBOL_REF, Pmode, name));
259: ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
260: ASM_OUTPUT_INT (asm_out_file, gen_rtx (SYMBOL_REF, Pmode, name));
261: ASM_OUTPUT_INT (asm_out_file, gen_rtx (CONST_INT, VOIDmode,
262: count_basic_blocks));
263: assemble_integer_zero ();
264: ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
265: ASM_OUTPUT_INT (asm_out_file, gen_rtx (SYMBOL_REF, Pmode, name));
266:
267: /* Output the file name. */
268: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
269: assemble_string (filename, strlen (filename) + 1);
270:
1.1.1.15! root 271: /* Realign data section. */
! 272: ASM_OUTPUT_ALIGN (asm_out_file,
! 273: exact_log2 (min (UNITS_PER_WORD,
! 274: BIGGEST_ALIGNMENT / BITS_PER_UNIT)));
! 275:
1.1.1.13 root 276: /* Make space for the table of counts. */
277: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2);
278: ASM_OUTPUT_SKIP (asm_out_file, UNITS_PER_WORD * count_basic_blocks);
279:
280: /* Output the table of addresses. */
281: text_section ();
282: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 3);
283: for (i = 0; i < count_basic_blocks; i++)
284: {
285: char name[12];
286: ASM_GENERATE_INTERNAL_LABEL (name, "LPB", i);
287: ASM_OUTPUT_INT (asm_out_file, gen_rtx (SYMBOL_REF, Pmode, name));
288: }
289:
290: /* End with the address of the table of addresses,
291: so we can find it easily, as the last word in the file's text. */
292: ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
293: ASM_OUTPUT_INT (asm_out_file, gen_rtx (SYMBOL_REF, Pmode, name));
294: }
295: }
296:
1.1.1.2 root 297: /* Enable APP processing of subsequent output.
298: Used before the output from an `asm' statement. */
299:
300: void
301: app_enable ()
302: {
303: if (! app_on)
304: {
305: fprintf (asm_out_file, ASM_APP_ON);
306: app_on = 1;
307: }
308: }
309:
310: /* Enable APP processing of subsequent output.
311: Called from varasm.c before most kinds of output. */
312:
313: void
314: app_disable ()
315: {
316: if (app_on)
317: {
318: fprintf (asm_out_file, ASM_APP_OFF);
319: app_on = 0;
320: }
321: }
322:
1.1.1.15! root 323: /* Return the number of slots filled in the current
! 324: delayed branch sequence. */
! 325:
! 326: #ifdef HAVE_DELAYED_BRANCH
! 327: int
! 328: dbr_sequence_length ()
! 329: {
! 330: int i;
! 331: int slots = 0;
! 332: /* It's zero if we are not scheduling or not in a sequence.
! 333: (We never count the first insn.) */
! 334: if (flag_delayed_branch && final_sequence != 0)
! 335: {
! 336: for (i = 1; i < XVECLEN (final_sequence, 0); i++)
! 337: slots += DBR_INSN_SLOTS (XVECEXP (final_sequence, 0, i));
! 338: }
! 339: return slots;
! 340: }
! 341: #endif
! 342:
1.1.1.2 root 343: /* Output assembler code for the start of a function,
344: and initialize some of the variables in this file
345: for the new function. The label for the function and associated
346: assembler pseudo-ops have already been output in `assemble_function'.
347:
1.1 root 348: FIRST is the first insn of the rtl for the function being compiled.
349: FILE is the file to write assembler code to.
1.1.1.4 root 350: WRITE_SYMBOLS says which kind of debugging info to write (or none).
1.1 root 351: OPTIMIZE is nonzero if we should eliminate redundant
352: test and compare insns. */
353:
354: void
1.1.1.2 root 355: final_start_function (first, file, write_symbols, optimize)
1.1 root 356: rtx first;
357: FILE *file;
1.1.1.4 root 358: enum debugger write_symbols;
1.1 root 359: int optimize;
360: {
1.1.1.2 root 361: block_depth = 0;
1.1 root 362:
1.1.1.9 root 363: this_is_asm_operands = 0;
364:
1.1 root 365: /* Record beginning of the symbol-block that's the entire function. */
366:
1.1.1.4 root 367: if (write_symbols == GDB_DEBUG)
1.1 root 368: {
1.1.1.2 root 369: pending_blocks[block_depth++] = next_block_index;
1.1 root 370: fprintf (file, "\t.gdbbeg %d\n", next_block_index++);
371: }
372:
373: /* Initial line number is supposed to be output
374: before the function's prologue and label
375: so that the function's address will not appear to be
376: in the last statement of the preceding function. */
377: if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
1.1.1.2 root 378: output_source_line (file, first, write_symbols);
1.1 root 379:
380: #ifdef FUNCTION_PROLOGUE
381: /* First output the function prologue: code to set up the stack frame. */
382: FUNCTION_PROLOGUE (file, get_frame_size ());
383: #endif
384:
1.1.1.4 root 385: #ifdef SDB_DEBUGGING_INFO
386: next_block_index = 1;
387: #endif
388:
1.1.1.13 root 389: #ifdef FUNCTION_BLOCK_PROFILER
390: if (profile_block_flag)
391: {
392: FUNCTION_BLOCK_PROFILER (file, profile_label_no);
393: }
394: #endif /* FUNCTION_BLOCK_PROFILER */
395:
1.1.1.2 root 396: if (profile_flag)
1.1.1.4 root 397: {
1.1.1.2 root 398: int align = min (BIGGEST_ALIGNMENT, BITS_PER_WORD);
1.1.1.8 root 399: extern int current_function_returns_struct;
400: extern int current_function_needs_context;
401: int sval = current_function_returns_struct;
402: int cxt = current_function_needs_context;
1.1.1.13 root 403:
1.1.1.6 root 404: data_section ();
1.1.1.2 root 405: ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
406: ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no);
407: assemble_integer_zero ();
1.1.1.13 root 408:
1.1.1.6 root 409: text_section ();
1.1.1.8 root 410:
411: #ifdef STRUCT_VALUE_INCOMING_REGNUM
412: if (sval)
413: ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM);
414: #else
415: #ifdef STRUCT_VALUE_REGNUM
416: if (sval)
417: ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM);
418: #endif
419: #endif
420:
421: #if 0
422: #ifdef STATIC_CHAIN_INCOMING_REGNUM
423: if (cxt)
424: ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
425: #else
426: #ifdef STATIC_CHAIN_REGNUM
427: if (cxt)
428: ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
429: #endif
430: #endif
431: #endif /* 0 */
432:
1.1.1.2 root 433: FUNCTION_PROFILER (file, profile_label_no);
434:
1.1.1.8 root 435: #if 0
436: #ifdef STATIC_CHAIN_INCOMING_REGNUM
437: if (cxt)
438: ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
439: #else
440: #ifdef STATIC_CHAIN_REGNUM
441: if (cxt)
442: ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
443: #endif
444: #endif
445: #endif /* 0 */
446:
447: #ifdef STRUCT_VALUE_INCOMING_REGNUM
448: if (sval)
449: ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM);
450: #else
451: #ifdef STRUCT_VALUE_REGNUM
452: if (sval)
453: ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM);
454: #endif
455: #endif
456: }
1.1.1.13 root 457:
458: profile_label_no++;
1.1.1.2 root 459: }
460:
461: /* Output assembler code for the end of a function.
462: For clarity, args are same as those of `final_start_function'
463: even though not all of them are needed. */
464:
465: void
466: final_end_function (first, file, write_symbols, optimize)
467: rtx first;
468: FILE *file;
1.1.1.4 root 469: enum debugger write_symbols;
1.1.1.2 root 470: int optimize;
471: {
472: if (app_on)
473: {
474: fprintf (file, ASM_APP_OFF);
475: app_on = 0;
476: }
477:
1.1.1.4 root 478: if (write_symbols == GDB_DEBUG)
1.1.1.2 root 479: fprintf (file, "\t.gdbend %d\n", pending_blocks[0]);
480:
1.1.1.4 root 481: #ifdef SDB_DEBUGGING_INFO
482: if (write_symbols == SDB_DEBUG)
483: sdbout_end_function (last_linenum);
484: #endif
485:
1.1.1.2 root 486: #ifdef FUNCTION_EPILOGUE
487: /* Finally, output the function epilogue:
488: code to restore the stack frame and return to the caller. */
489: FUNCTION_EPILOGUE (file, get_frame_size ());
490: #endif
491:
1.1.1.6 root 492: #ifdef SDB_DEBUGGING_INFO
493: if (write_symbols == SDB_DEBUG)
494: sdbout_end_epilogue ();
495: #endif
496:
1.1.1.2 root 497: /* If FUNCTION_EPILOGUE is not defined, then the function body
498: itself contains return instructions wherever needed. */
499: }
500:
501: /* Output assembler code for some insns: all or part of a function.
1.1.1.8 root 502: For description of args, see `final_start_function', above.
503:
504: PRESCAN is 1 if we are not really outputting,
505: just scanning as if we were outputting.
506: Prescanning deletes and rearranges insns just like ordinary output.
507: PRESCAN is -2 if we are outputting after having prescanned.
508: In this case, don't try to delete or rearrange insns
509: because that has already been done.
510: Prescanning is done only on certain machines. */
1.1.1.2 root 511:
512: void
1.1.1.8 root 513: final (first, file, write_symbols, optimize, prescan)
1.1.1.2 root 514: rtx first;
515: FILE *file;
1.1.1.4 root 516: enum debugger write_symbols;
1.1.1.2 root 517: int optimize;
1.1.1.8 root 518: int prescan;
1.1.1.2 root 519: {
520: register rtx insn;
1.1.1.15! root 521:
! 522: last_ignored_compare = 0;
! 523: new_block = 1;
1.1 root 524:
1.1.1.8 root 525: init_recog ();
526:
527: CC_STATUS_INIT;
528:
1.1.1.15! root 529: for (insn = NEXT_INSN (first); insn;)
! 530: insn = final_scan_insn (insn, file, write_symbols, optimize,
! 531: prescan, 0);
! 532: }
! 533:
! 534: /* The final scan for one insn, INSN.
! 535: Args are same as in `final', except that INSN
! 536: is the insn being scanned.
! 537: Value returned is the next insn to be scanned.
! 538:
! 539: NOPEEPHOLES is the flag to disallow peephole processing (currently
! 540: used for within delayed branch sequence output). */
! 541:
! 542: rtx
! 543: final_scan_insn (insn, file, write_symbols, optimize, prescan, nopeepholes)
! 544: rtx insn;
! 545: FILE *file;
! 546: enum debugger write_symbols;
! 547: int optimize;
! 548: int prescan;
! 549: int nopeepholes;
! 550: {
! 551: register int i;
! 552: switch (GET_CODE (insn))
1.1 root 553: {
1.1.1.15! root 554: case NOTE:
! 555: if (prescan > 0)
! 556: break;
! 557: if (write_symbols == NO_DEBUG)
! 558: break;
! 559: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
1.1 root 560: {
1.1.1.15! root 561: #ifdef SDB_DEBUGGING_INFO
! 562: if (write_symbols == SDB_DEBUG)
! 563: sdbout_begin_function (last_linenum);
! 564: #endif
! 565: break;
! 566: }
! 567: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
! 568: || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
! 569: break;
! 570: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
! 571: break; /* An insn that was "deleted" */
! 572: if (app_on)
! 573: {
! 574: fprintf (file, ASM_APP_OFF);
! 575: app_on = 0;
! 576: }
! 577: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
! 578: {
! 579: /* Beginning of a symbol-block. Assign it a sequence number
! 580: and push the number onto the stack PENDING_BLOCKS. */
! 581:
! 582: if (block_depth == max_block_depth)
1.1.1.2 root 583: {
1.1.1.15! root 584: /* PENDING_BLOCKS is full; make it longer. */
! 585: max_block_depth *= 2;
! 586: pending_blocks
! 587: = (int *) xrealloc (pending_blocks,
! 588: max_block_depth * sizeof (int));
1.1.1.2 root 589: }
1.1.1.15! root 590: pending_blocks[block_depth++] = next_block_index;
1.1 root 591:
1.1.1.15! root 592: /* Output debugging info about the symbol-block beginning. */
1.1 root 593:
1.1.1.4 root 594: #ifdef SDB_DEBUGGING_INFO
1.1.1.15! root 595: if (write_symbols == SDB_DEBUG)
! 596: sdbout_begin_block (file, last_linenum, next_block_index);
1.1.1.4 root 597: #endif
598: #ifdef DBX_DEBUGGING_INFO
1.1.1.15! root 599: if (write_symbols == DBX_DEBUG)
! 600: ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", next_block_index);
1.1.1.4 root 601: #endif
1.1.1.15! root 602: if (write_symbols == GDB_DEBUG)
! 603: fprintf (file, "\t.gdbbeg %d\n", next_block_index);
1.1.1.4 root 604:
1.1.1.15! root 605: next_block_index++;
! 606: }
! 607: else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
! 608: {
! 609: /* End of a symbol-block. Pop its sequence number off
! 610: PENDING_BLOCKS and output debugging info based on that. */
1.1 root 611:
1.1.1.15! root 612: --block_depth;
1.1.1.4 root 613:
614: #ifdef DBX_DEBUGGING_INFO
1.1.1.15! root 615: if (write_symbols == DBX_DEBUG && block_depth >= 0)
! 616: ASM_OUTPUT_INTERNAL_LABEL (file, "LBE",
! 617: pending_blocks[block_depth]);
1.1.1.4 root 618: #endif
619:
620: #ifdef SDB_DEBUGGING_INFO
1.1.1.15! root 621: if (write_symbols == SDB_DEBUG && block_depth >= 0)
! 622: sdbout_end_block (file, last_linenum);
1.1.1.4 root 623: #endif
624:
1.1.1.15! root 625: if (write_symbols == GDB_DEBUG)
! 626: fprintf (file, "\t.gdbend %d\n", pending_blocks[block_depth]);
! 627: }
! 628: else if (NOTE_LINE_NUMBER (insn) > 0)
! 629: /* This note is a line-number. */
! 630: output_source_line (file, insn, write_symbols);
! 631: break;
1.1 root 632:
1.1.1.15! root 633: case BARRIER:
1.1.1.11 root 634: #ifdef ASM_OUTPUT_ALIGN_CODE
1.1.1.15! root 635: ASM_OUTPUT_ALIGN_CODE (file);
1.1.1.11 root 636: #endif
1.1.1.15! root 637: break;
1.1 root 638:
1.1.1.15! root 639: case CODE_LABEL:
! 640: CC_STATUS_INIT;
! 641: if (prescan > 0)
! 642: break;
! 643: new_block = 1;
! 644: if (app_on)
! 645: {
! 646: fprintf (file, ASM_APP_OFF);
! 647: app_on = 0;
! 648: }
1.1.1.2 root 649: #ifdef ASM_OUTPUT_CASE_LABEL
1.1.1.15! root 650: if (NEXT_INSN (insn) != 0
! 651: && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN)
! 652: {
! 653: rtx nextbody = PATTERN (NEXT_INSN (insn));
1.1.1.2 root 654:
1.1.1.15! root 655: /* If this label is followed by a jump-table,
! 656: output the two of them together in a special way. */
1.1.1.2 root 657:
1.1.1.15! root 658: if (GET_CODE (nextbody) == ADDR_VEC
! 659: || GET_CODE (nextbody) == ADDR_DIFF_VEC)
! 660: {
! 661: ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
! 662: NEXT_INSN (insn));
! 663: break;
1.1.1.2 root 664: }
1.1.1.15! root 665: }
1.1.1.2 root 666: #endif
667:
1.1.1.15! root 668: ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
! 669: break;
1.1 root 670:
1.1.1.15! root 671: default:
! 672: {
! 673: register rtx body = PATTERN (insn);
! 674: int insn_code_number;
! 675: char *template;
1.1 root 676:
1.1.1.15! root 677: /* An INSN, JUMP_INSN or CALL_INSN.
! 678: First check for special kinds that recog doesn't recognize. */
1.1.1.4 root 679:
1.1.1.15! root 680: if (GET_CODE (body) == USE /* These are just declarations */
! 681: || GET_CODE (body) == CLOBBER)
! 682: break;
1.1.1.13 root 683:
1.1.1.15! root 684: if (profile_block_flag && new_block)
! 685: {
! 686: new_block = 0;
! 687: /* Enable the table of basic-block use counts
! 688: to point at the code it applies to. */
! 689: ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks);
! 690: /* Before first insn of this basic block, increment the
! 691: count of times it was entered. */
1.1.1.13 root 692: #ifdef BLOCK_PROFILER
1.1.1.15! root 693: BLOCK_PROFILER (file, count_basic_blocks);
1.1.1.13 root 694: #endif
1.1.1.15! root 695: count_basic_blocks++;
! 696: }
1.1.1.13 root 697:
1.1.1.15! root 698: if (GET_CODE (body) == ASM_INPUT)
! 699: {
! 700: /* There's no telling what that did to the condition codes. */
! 701: CC_STATUS_INIT;
! 702: if (prescan > 0)
! 703: break;
! 704: if (! app_on)
1.1 root 705: {
1.1.1.15! root 706: fprintf (file, ASM_APP_ON);
! 707: app_on = 1;
1.1 root 708: }
1.1.1.15! root 709: fprintf (asm_out_file, "\t%s\n", XSTR (body, 0));
! 710: break;
! 711: }
1.1 root 712:
1.1.1.15! root 713: /* Detect `asm' construct with operands. */
! 714: if (asm_noperands (body) >= 0)
! 715: {
! 716: int noperands = asm_noperands (body);
! 717: rtx *ops;
! 718: char *string;
1.1.1.8 root 719:
1.1.1.15! root 720: /* There's no telling what that did to the condition codes. */
! 721: CC_STATUS_INIT;
! 722: if (prescan > 0)
! 723: break;
1.1.1.2 root 724:
1.1.1.15! root 725: /* alloca won't do here, since only return from `final'
! 726: would free it. */
! 727: if (noperands > 0)
! 728: ops = (rtx *) xmalloc (noperands * sizeof (rtx));
1.1.1.2 root 729:
1.1.1.15! root 730: if (! app_on)
1.1.1.2 root 731: {
1.1.1.15! root 732: fprintf (file, ASM_APP_ON);
! 733: app_on = 1;
1.1.1.2 root 734: }
735:
1.1.1.15! root 736: /* Get out the operand values. */
! 737: string = decode_asm_operands (body, ops, 0, 0, 0);
! 738: /* Inhibit aborts on what would otherwise be compiler bugs. */
! 739: insn_noperands = noperands;
! 740: this_is_asm_operands = insn;
! 741: /* Output the insn using them. */
! 742: output_asm_insn (string, ops);
! 743: this_is_asm_operands = 0;
! 744: if (noperands > 0)
! 745: free (ops);
! 746: break;
! 747: }
1.1 root 748:
1.1.1.15! root 749: if (prescan <= 0 && app_on)
! 750: {
! 751: fprintf (file, ASM_APP_OFF);
! 752: app_on = 0;
! 753: }
1.1.1.8 root 754:
1.1.1.15! root 755: /* Detect insns that are really jump-tables
! 756: and output them as such. */
1.1.1.8 root 757:
1.1.1.15! root 758: if (GET_CODE (body) == ADDR_VEC)
! 759: {
! 760: register int vlen, idx;
! 761:
! 762: if (prescan > 0)
! 763: break;
! 764:
! 765: vlen = XVECLEN (body, 0);
! 766: for (idx = 0; idx < vlen; idx++)
! 767: ASM_OUTPUT_ADDR_VEC_ELT (file,
! 768: CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
1.1.1.4 root 769: #ifdef ASM_OUTPUT_CASE_END
1.1.1.15! root 770: ASM_OUTPUT_CASE_END (file,
! 771: CODE_LABEL_NUMBER (PREV_INSN (insn)),
! 772: insn);
1.1.1.4 root 773: #endif
1.1.1.15! root 774: break;
! 775: }
! 776: if (GET_CODE (body) == ADDR_DIFF_VEC)
! 777: {
! 778: register int vlen, idx;
1.1.1.8 root 779:
1.1.1.15! root 780: if (prescan > 0)
! 781: break;
1.1.1.8 root 782:
1.1.1.15! root 783: vlen = XVECLEN (body, 1);
! 784: for (idx = 0; idx < vlen; idx++)
! 785: ASM_OUTPUT_ADDR_DIFF_ELT (file,
! 786: CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
! 787: CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
1.1.1.4 root 788: #ifdef ASM_OUTPUT_CASE_END
1.1.1.15! root 789: ASM_OUTPUT_CASE_END (file,
! 790: CODE_LABEL_NUMBER (PREV_INSN (insn)),
! 791: insn);
1.1.1.4 root 792: #endif
1.1.1.15! root 793: break;
! 794: }
1.1 root 795:
1.1.1.15! root 796: if (recog_memoized (insn) == -1
! 797: && GET_CODE (body) == SEQUENCE) /* A delayed-branch sequence */
! 798: {
! 799: register int i;
! 800: if (prescan > 0)
! 801: break;
! 802: final_sequence = body;
! 803: for (i = 0; i < XVECLEN (body, 0); i++)
! 804: final_scan_insn (XVECEXP (body, 0, i), file, write_symbols,
! 805: optimize, prescan, 1);
! 806: final_sequence = 0;
! 807: #ifdef DBR_OUTPUT_SEQEND
! 808: DBR_OUTPUT_SEQEND (file);
! 809: #endif
! 810: break;
! 811: }
1.1 root 812:
1.1.1.15! root 813: /* We have a real machine instruction as rtl. */
! 814:
! 815: body = PATTERN (insn);
1.1 root 816:
1.1.1.15! root 817: /* Check for redundant test and compare instructions
! 818: (when the condition codes are already set up as desired).
! 819: This is done only when optimizing; if not optimizing,
! 820: it should be possible for the user to alter a variable
! 821: with the debugger in between statements
! 822: and the next statement should reexamine the variable
! 823: to compute the condition codes. */
! 824:
! 825: if (optimize
! 826: && GET_CODE (body) == SET
! 827: && GET_CODE (SET_DEST (body)) == CC0
! 828: && insn != last_ignored_compare)
! 829: {
! 830: if (GET_CODE (SET_SRC (body)) == SUBREG)
! 831: SET_SRC (body) = alter_subreg (SET_SRC (body));
! 832: if ((cc_status.value1 != 0
! 833: && rtx_equal_p (SET_SRC (body), cc_status.value1))
! 834: || (cc_status.value2 != 0
! 835: && rtx_equal_p (SET_SRC (body), cc_status.value2)))
1.1 root 836: {
1.1.1.15! root 837: /* Don't delete insn if has an addressing side-effect */
! 838: if (! find_reg_note (insn, REG_INC, 0)
! 839: /* or if anything in it is volatile. */
! 840: && ! volatile_refs_p (PATTERN (insn)))
1.1.1.2 root 841: {
1.1.1.15! root 842: /* We don't really delete the insn; just ignore it. */
! 843: last_ignored_compare = insn;
! 844: break;
1.1.1.2 root 845: }
1.1 root 846: }
1.1.1.15! root 847: }
! 848:
! 849: reinsert_compare:
! 850:
! 851: /* Following a conditional branch, we have a new basic block. */
! 852: if (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
! 853: && GET_CODE (SET_SRC (body)) != LABEL_REF)
! 854: new_block = 1;
! 855:
! 856: /* If this is a conditional branch, maybe modify it
! 857: if the cc's are in a nonstandard state
! 858: so that it accomplishes the same thing that it would
! 859: do straightforwardly if the cc's were set up normally. */
! 860:
! 861: if (cc_status.flags != 0
! 862: && GET_CODE (insn) == JUMP_INSN
! 863: && GET_CODE (body) == SET
! 864: && SET_DEST (body) == pc_rtx
! 865: && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
! 866: /* This is done during prescan; it is not done again
! 867: in final scan when prescan has been done. */
! 868: && prescan >= 0)
! 869: {
! 870: /* This function may alter the contents of its argument
! 871: and clear some of the cc_status.flags bits.
! 872: It may also return 1 meaning condition now always true
! 873: or -1 meaning condition now always false
! 874: or 2 meaning condition nontrivial but altered. */
! 875: register int result = alter_cond (XEXP (SET_SRC (body), 0));
! 876: /* If condition now has fixed value, replace the IF_THEN_ELSE
! 877: with its then-operand or its else-operand. */
! 878: if (result == 1)
! 879: SET_SRC (body) = XEXP (SET_SRC (body), 1);
! 880: if (result == -1)
! 881: SET_SRC (body) = XEXP (SET_SRC (body), 2);
! 882: /* The jump is now either unconditional or a no-op.
! 883: If it has become a no-op, don't try to output it.
! 884: (It would not be recognized.) */
! 885: if (SET_SRC (body) == pc_rtx)
! 886: {
! 887: PUT_CODE (insn, NOTE);
! 888: NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
! 889: NOTE_SOURCE_FILE (insn) = 0;
! 890: break;
! 891: }
! 892: /* Rerecognize the instruction if it has changed. */
! 893: if (result != 0)
! 894: INSN_CODE (insn) = -1;
! 895: }
1.1 root 896:
1.1.1.15! root 897: #ifdef STORE_FLAG_VALUE
! 898: /* Make same adjustments to instructions that examine the
! 899: condition codes without jumping (if this machine has them). */
1.1.1.12 root 900:
1.1.1.15! root 901: if (cc_status.flags != 0
! 902: && GET_CODE (body) == SET)
! 903: switch (GET_CODE (SET_SRC (body)))
! 904: {
! 905: case GTU:
! 906: case GT:
! 907: case LTU:
! 908: case LT:
! 909: case GEU:
! 910: case GE:
! 911: case LEU:
! 912: case LE:
! 913: case EQ:
! 914: case NE:
1.1 root 915: {
1.1.1.15! root 916: register int result;
! 917: if (GET_CODE (XEXP (SET_SRC (body), 0)) != CC0)
! 918: break;
! 919: result = alter_cond (SET_SRC (body));
1.1 root 920: if (result == 1)
1.1.1.15! root 921: SET_SRC (body) = gen_rtx (CONST_INT, VOIDmode,
! 922: STORE_FLAG_VALUE);
1.1 root 923: if (result == -1)
1.1.1.15! root 924: SET_SRC (body) = const0_rtx;
1.1 root 925: if (result != 0)
926: INSN_CODE (insn) = -1;
927: }
1.1.1.15! root 928: }
! 929: #endif /* STORE_FLAG_VALUE */
1.1 root 930:
1.1.1.15! root 931: /* Do machine-specific peephole optimizations if desired. */
1.1 root 932:
1.1.1.15! root 933: if (optimize && !flag_no_peephole && !nopeepholes)
! 934: {
! 935: rtx next = peephole (insn);
! 936: /* When peepholing, if there were notes within the peephole,
! 937: emit them before the peephole. */
! 938: if (next != 0 && next != NEXT_INSN (insn))
! 939: {
! 940: rtx note = NEXT_INSN (insn);
! 941: rtx prev = PREV_INSN (insn);
! 942: while (note != next)
1.1 root 943: {
1.1.1.15! root 944: final_scan_insn (note, file, write_symbols, optimize,
! 945: prescan, nopeepholes);
! 946: note = NEXT_INSN (note);
1.1 root 947: }
1.1.1.15! root 948: /* In case this is prescan, put the notes
! 949: in proper position for later rescan. */
! 950: note = NEXT_INSN (insn);
! 951: PREV_INSN (note) = prev;
! 952: NEXT_INSN (prev) = note;
! 953: NEXT_INSN (PREV_INSN (next)) = insn;
! 954: PREV_INSN (insn) = PREV_INSN (next);
! 955: NEXT_INSN (insn) = next;
! 956: PREV_INSN (next) = insn;
1.1.1.12 root 957: }
958:
1.1.1.15! root 959: /* PEEPHOLE might have changed this. */
! 960: body = PATTERN (insn);
! 961: }
! 962:
! 963: /* Try to recognize the instruction.
! 964: If successful, verify that the operands satisfy the
! 965: constraints for the instruction. Crash if they don't,
! 966: since `reload' should have changed them so that they do. */
! 967:
! 968: insn_code_number = recog_memoized (insn);
! 969: insn_extract (insn);
! 970: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
! 971: {
! 972: if (GET_CODE (recog_operand[i]) == SUBREG)
! 973: recog_operand[i] = alter_subreg (recog_operand[i]);
! 974: }
1.1 root 975:
976: #ifdef REGISTER_CONSTRAINTS
1.1.1.15! root 977: if (! constrain_operands (insn_code_number))
! 978: abort ();
1.1 root 979: #endif
980:
1.1.1.15! root 981: /* Some target machines need to prescan each insn before
! 982: it is output. */
1.1.1.4 root 983:
984: #ifdef FINAL_PRESCAN_INSN
1.1.1.15! root 985: FINAL_PRESCAN_INSN (insn, recog_operand,
! 986: insn_n_operands[insn_code_number]);
1.1.1.4 root 987: #endif
988:
1.1.1.15! root 989: cc_prev_status = cc_status;
! 990:
! 991: /* Update `cc_status' for this instruction.
! 992: The instruction's output routine may change it further.
! 993: If the output routine for a jump insn needs to depend
! 994: on the cc status, it should look at cc_prev_status. */
1.1.1.2 root 995:
1.1.1.15! root 996: NOTICE_UPDATE_CC (body, insn);
1.1 root 997:
1.1.1.15! root 998: /* If the proper template needs to be chosen by some C code,
! 999: run that code and get the real template. */
1.1 root 1000:
1.1.1.15! root 1001: template = insn_template[insn_code_number];
! 1002: if (template == 0)
! 1003: {
! 1004: template = (*insn_outfun[insn_code_number]) (recog_operand, insn);
1.1 root 1005:
1.1.1.15! root 1006: /* If the C code returns 0, it means that it is a jump insn
! 1007: which follows a deleted test insn, and that test insn
! 1008: needs to be reinserted. */
1.1 root 1009: if (template == 0)
1.1.1.12 root 1010: {
1.1.1.15! root 1011: if (PREV_INSN (insn) != last_ignored_compare)
! 1012: abort ();
! 1013: new_block = 0;
! 1014: return PREV_INSN (insn);
1.1.1.12 root 1015: }
1.1.1.15! root 1016: }
1.1 root 1017:
1.1.1.15! root 1018: if (prescan > 0)
! 1019: break;
1.1.1.8 root 1020:
1.1.1.15! root 1021: /* Output assembler code from the template. */
1.1 root 1022:
1.1.1.15! root 1023: output_asm_insn (template, recog_operand);
1.1.1.12 root 1024:
1.1.1.15! root 1025: /* Mark this insn as having been output. */
! 1026: INSN_DELETED_P (insn) = 1;
! 1027: }
1.1 root 1028: }
1.1.1.15! root 1029: return NEXT_INSN (insn);
1.1.1.2 root 1030: }
1031:
1032: /* Set up FILENAME as the current file for GDB line-number output. */
1.1 root 1033:
1.1.1.2 root 1034: void
1035: set_current_gdbfile (filename)
1036: char *filename;
1037: {
1038: register struct gdbfile *f;
1039: for (f = gdbfiles; f; f = f->next)
1040: if (!strcmp (f->name, filename))
1041: break;
1.1 root 1042:
1.1.1.2 root 1043: if (!f)
1044: {
1045: f = (struct gdbfile *) permalloc (sizeof (struct gdbfile));
1046: f->next = gdbfiles;
1047: gdbfiles = f;
1048: f->name = filename;
1049: f->filenum = next_gdb_filenum++;
1050: f->nlines = 0;
1051: }
1052: current_gdbfile = f;
1053: lastfile = filename;
1.1 root 1054: }
1055:
1.1.1.2 root 1056: /* Output debugging info to the assembler file FILE
1057: based on the NOTE-insn INSN, assumed to be a line number. */
1.1 root 1058:
1.1.1.2 root 1059: static void
1060: output_source_line (file, insn, write_symbols)
1.1 root 1061: FILE *file;
1062: rtx insn;
1.1.1.4 root 1063: enum debugger write_symbols;
1.1 root 1064: {
1065: register char *filename = NOTE_SOURCE_FILE (insn);
1.1.1.4 root 1066:
1067: last_linenum = NOTE_LINE_NUMBER (insn);
1068:
1069: if (write_symbols == GDB_DEBUG)
1.1.1.2 root 1070: {
1071: /* Output GDB-format line number info. */
1.1 root 1072:
1.1.1.2 root 1073: /* If this is not the same source file as last time,
1074: find or assign a GDB-file-number to this file. */
1075: if (filename && (lastfile == 0 || strcmp (filename, lastfile)
1076: || current_gdbfile == 0))
1077: set_current_gdbfile (filename);
1078:
1079: ++current_gdbfile->nlines;
1080: fprintf (file, "\t.gdbline %d,%d\n",
1081: current_gdbfile->filenum, NOTE_LINE_NUMBER (insn));
1082: }
1.1.1.4 root 1083:
1.1.1.6 root 1084: if (write_symbols == SDB_DEBUG || write_symbols == DBX_DEBUG)
1.1.1.4 root 1085: {
1.1.1.6 root 1086: #ifdef SDB_DEBUGGING_INFO
1087: if (write_symbols == SDB_DEBUG
1.1.1.15! root 1088: #if 0 /* People like having line numbers even in wrong file! */
1.1.1.6 root 1089: /* COFF can't handle multiple source files--lose, lose. */
1.1.1.10 root 1090: && !strcmp (filename, main_input_filename)
1.1.1.15! root 1091: #endif
! 1092: /* COFF relative line numbers must be positive. */
! 1093: && last_linenum > sdb_begin_function_line)
1.1.1.6 root 1094: {
1.1.1.4 root 1095: #ifdef ASM_OUTPUT_SOURCE_LINE
1.1.1.6 root 1096: ASM_OUTPUT_SOURCE_LINE (file, last_linenum);
1.1.1.4 root 1097: #else
1.1.1.6 root 1098: fprintf (file, "\t.ln\t%d\n",
1099: (sdb_begin_function_line
1100: ? last_linenum - sdb_begin_function_line : 1));
1.1.1.4 root 1101: #endif
1.1.1.6 root 1102: }
1.1.1.4 root 1103: #endif
1104:
1105: #ifdef DBX_DEBUGGING_INFO
1.1.1.6 root 1106: if (write_symbols == DBX_DEBUG)
1.1.1.4 root 1107: {
1.1.1.6 root 1108: /* Write DBX line number data. */
1109:
1110: if (filename && (lastfile == 0 || strcmp (filename, lastfile)))
1111: {
1.1.1.2 root 1112: #ifdef ASM_OUTPUT_SOURCE_FILENAME
1.1.1.6 root 1113: ASM_OUTPUT_SOURCE_FILENAME (file, filename);
1.1.1.2 root 1114: #else
1.1.1.6 root 1115: fprintf (file, "\t.stabs \"%s\",%d,0,0,Ltext\n",
1116: filename, N_SOL);
1.1.1.2 root 1117: #endif
1.1.1.6 root 1118: lastfile = filename;
1119: }
1.1.1.4 root 1120: }
1.1.1.2 root 1121:
1122: #ifdef ASM_OUTPUT_SOURCE_LINE
1123: ASM_OUTPUT_SOURCE_LINE (file, NOTE_LINE_NUMBER (insn));
1124: #else
1125: fprintf (file, "\t.stabd %d,0,%d\n",
1126: N_SLINE, NOTE_LINE_NUMBER (insn));
1127: #endif
1.1.1.4 root 1128: #endif /* DBX_DEBUGGING_INFO */
1.1.1.2 root 1129: }
1.1 root 1130: }
1131:
1.1.1.2 root 1132: /* If X is a SUBREG, replace it with a REG or a MEM,
1133: based on the thing it is a subreg of. */
1.1 root 1134:
1.1.1.10 root 1135: rtx
1.1 root 1136: alter_subreg (x)
1137: register rtx x;
1138: {
1139: register rtx y = SUBREG_REG (x);
1140: if (GET_CODE (y) == SUBREG)
1.1.1.6 root 1141: y = alter_subreg (y);
1.1 root 1142:
1143: if (GET_CODE (y) == REG)
1144: {
1145: /* If the containing reg really gets a hard reg, so do we. */
1146: PUT_CODE (x, REG);
1147: REGNO (x) = REGNO (y) + SUBREG_WORD (x);
1148: }
1149: else if (GET_CODE (y) == MEM)
1150: {
1.1.1.2 root 1151: register int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
1.1 root 1152: #ifdef BYTES_BIG_ENDIAN
1.1.1.2 root 1153: offset -= (min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))
1154: - min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y))));
1.1 root 1155: #endif
1156: PUT_CODE (x, MEM);
1.1.1.14 root 1157: MEM_VOLATILE_P (x) = MEM_VOLATILE_P (y);
1.1 root 1158: XEXP (x, 0) = plus_constant (XEXP (y, 0), offset);
1159: }
1.1.1.6 root 1160: else if (GET_CODE (y) == CONST_DOUBLE)
1161: return y;
1162:
1163: return x;
1.1 root 1164: }
1165:
1.1.1.2 root 1166: /* Do alter_subreg on all the SUBREGs contained in X. */
1.1 root 1167:
1.1.1.2 root 1168: static rtx
1169: walk_alter_subreg (x)
1170: rtx x;
1171: {
1172: switch (GET_CODE (x))
1.1 root 1173: {
1.1.1.2 root 1174: case PLUS:
1175: case MULT:
1176: XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0));
1177: XEXP (x, 1) = walk_alter_subreg (XEXP (x, 1));
1178: break;
1179:
1180: case MEM:
1181: XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0));
1182: break;
1183:
1184: case SUBREG:
1.1.1.6 root 1185: return alter_subreg (x);
1.1 root 1186: }
1187:
1.1.1.2 root 1188: return x;
1.1 root 1189: }
1190:
1191: /* Given BODY, the body of a jump instruction, alter the jump condition
1192: as required by the bits that are set in cc_status.flags.
1193: Not all of the bits there can be handled at this level in all cases.
1194:
1195: The value is normally 0.
1196: 1 means that the condition has become always true.
1.1.1.8 root 1197: -1 means that the condition has become always false.
1198: 2 means that COND has been altered. */
1.1 root 1199:
1200: static int
1201: alter_cond (cond)
1202: register rtx cond;
1203: {
1204: int value = 0;
1205:
1206: if (cc_status.flags & CC_REVERSED)
1207: {
1208: value = 2;
1209: switch (GET_CODE (cond))
1210: {
1211: case LE:
1212: PUT_CODE (cond, GE);
1213: break;
1214: case GE:
1215: PUT_CODE (cond, LE);
1216: break;
1217: case LT:
1218: PUT_CODE (cond, GT);
1219: break;
1220: case GT:
1221: PUT_CODE (cond, LT);
1222: break;
1223: case LEU:
1224: PUT_CODE (cond, GEU);
1225: break;
1226: case GEU:
1227: PUT_CODE (cond, LEU);
1228: break;
1229: case LTU:
1230: PUT_CODE (cond, GTU);
1231: break;
1232: case GTU:
1233: PUT_CODE (cond, LTU);
1234: break;
1235: }
1236: }
1237:
1.1.1.8 root 1238: if (cc_status.flags & CC_NOT_POSITIVE)
1.1 root 1239: switch (GET_CODE (cond))
1240: {
1241: case LE:
1242: case LEU:
1243: case GEU:
1244: /* Jump becomes unconditional. */
1245: return 1;
1246:
1247: case GT:
1248: case GTU:
1249: case LTU:
1250: /* Jump becomes no-op. */
1251: return -1;
1252:
1253: case GE:
1254: PUT_CODE (cond, EQ);
1255: value = 2;
1256: break;
1257:
1258: case LT:
1259: PUT_CODE (cond, NE);
1260: value = 2;
1261: break;
1262: }
1263:
1.1.1.8 root 1264: if (cc_status.flags & CC_NOT_NEGATIVE)
1.1 root 1265: switch (GET_CODE (cond))
1266: {
1267: case GE:
1268: case GEU:
1269: /* Jump becomes unconditional. */
1270: return 1;
1271:
1272: case LT:
1273: case LTU:
1274: /* Jump becomes no-op. */
1275: return -1;
1276:
1277: case LE:
1278: case LEU:
1279: PUT_CODE (cond, EQ);
1280: value = 2;
1281: break;
1282:
1283: case GT:
1284: case GTU:
1285: PUT_CODE (cond, NE);
1286: value = 2;
1287: break;
1288: }
1289:
1.1.1.8 root 1290: if (cc_status.flags & CC_NO_OVERFLOW)
1.1 root 1291: switch (GET_CODE (cond))
1292: {
1293: case GEU:
1294: /* Jump becomes unconditional. */
1295: return 1;
1296:
1297: case LEU:
1298: PUT_CODE (cond, EQ);
1299: value = 2;
1300: break;
1301:
1302: case GTU:
1303: PUT_CODE (cond, NE);
1304: value = 2;
1305: break;
1306:
1307: case LTU:
1308: /* Jump becomes no-op. */
1309: return -1;
1310: }
1311:
1.1.1.8 root 1312: if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
1313: switch (GET_CODE (cond))
1314: {
1315: case LE:
1316: case LEU:
1317: case GE:
1318: case GEU:
1319: case LT:
1320: case LTU:
1321: case GT:
1322: case GTU:
1323: abort ();
1324:
1325: case NE:
1326: PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
1327: value = 2;
1328: break;
1329:
1330: case EQ:
1331: PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE);
1332: value = 2;
1333: break;
1334: }
1335:
1.1 root 1336: return value;
1337: }
1338:
1.1.1.9 root 1339: /* Report inconsistency between the assembler template and the operands.
1340: In an `asm', it's the user's fault; otherwise, the compiler's fault. */
1341:
1342: static void
1343: output_operand_lossage (str)
1344: char *str;
1345: {
1346: if (this_is_asm_operands)
1.1.1.11 root 1347: error_for_asm (this_is_asm_operands, "invalid `asm': %s", str);
1.1.1.9 root 1348: else
1349: abort ();
1350: }
1351:
1.1 root 1352: /* Output of assembler code from a template, and its subroutines. */
1353:
1354: /* Output text from TEMPLATE to the assembler output file,
1355: obeying %-directions to substitute operands taken from
1356: the vector OPERANDS.
1357:
1358: %N (for N a digit) means print operand N in usual manner.
1359: %lN means require operand N to be a CODE_LABEL or LABEL_REF
1360: and print the label name with no punctuation.
1361: %cN means require operand N to be a constant
1362: and print the constant expression with no punctuation.
1363: %aN means expect operand N to be a memory address
1364: (not a memory reference!) and print a reference
1365: to that address.
1366: %nN means expect operand N to be a constant
1367: and print a constant expression for minus the value
1368: of the operand, with no other punctuation. */
1369:
1370: void
1371: output_asm_insn (template, operands)
1372: char *template;
1373: rtx *operands;
1374: {
1375: register char *p;
1376: register int c;
1377:
1.1.1.2 root 1378: /* An insn may return a null string template
1379: in a case where no assembler code is needed. */
1380: if (*template == 0)
1381: return;
1382:
1.1 root 1383: p = template;
1.1.1.2 root 1384: putc ('\t', asm_out_file);
1385:
1386: #ifdef ASM_OUTPUT_OPCODE
1387: ASM_OUTPUT_OPCODE (asm_out_file, p);
1388: #endif
1389:
1.1 root 1390: while (c = *p++)
1391: {
1.1.1.2 root 1392: #ifdef ASM_OUTPUT_OPCODE
1393: if (c == '\n')
1.1 root 1394: {
1.1.1.2 root 1395: putc (c, asm_out_file);
1396: while ((c = *p) == '\t')
1.1 root 1397: {
1.1.1.2 root 1398: putc (c, asm_out_file);
1399: p++;
1.1 root 1400: }
1.1.1.2 root 1401: ASM_OUTPUT_OPCODE (asm_out_file, p);
1402: }
1403: else
1404: #endif
1405: if (c != '%')
1406: putc (c, asm_out_file);
1407: else
1408: {
1409: /* %% outputs a single %. */
1410: if (*p == '%')
1.1 root 1411: {
1.1.1.2 root 1412: p++;
1413: putc (c, asm_out_file);
1.1 root 1414: }
1.1.1.2 root 1415: /* % followed by a letter and some digits
1416: outputs an operand in a special way depending on the letter.
1417: Letters `acln' are implemented here.
1418: Other letters are passed to `output_operand' so that
1419: the PRINT_OPERAND macro can define them. */
1420: else if ((*p >= 'a' && *p <= 'z')
1421: || (*p >= 'A' && *p <= 'Z'))
1.1 root 1422: {
1.1.1.2 root 1423: int letter = *p++;
1424: c = atoi (p);
1425:
1.1.1.14 root 1426: if (! (*p >= '0' && *p <= '9'))
1427: output_operand_lossage ("operand number missing after %-letter");
1428: else if (this_is_asm_operands && c >= (unsigned) insn_noperands)
1.1.1.9 root 1429: output_operand_lossage ("operand number out of range");
1430: else if (letter == 'l')
1.1.1.2 root 1431: output_asm_label (operands[c]);
1432: else if (letter == 'a')
1433: output_address (operands[c]);
1434: else if (letter == 'c')
1435: {
1436: if (CONSTANT_ADDRESS_P (operands[c]))
1437: output_addr_const (asm_out_file, operands[c]);
1438: else
1439: output_operand (operands[c], 'c');
1440: }
1441: else if (letter == 'n')
1.1 root 1442: {
1.1.1.2 root 1443: if (GET_CODE (operands[c]) == CONST_INT)
1444: fprintf (asm_out_file, "%d", - INTVAL (operands[c]));
1445: else
1446: {
1447: putc ('-', asm_out_file);
1448: output_addr_const (asm_out_file, operands[c]);
1449: }
1.1 root 1450: }
1.1.1.2 root 1451: else
1.1.1.14 root 1452: output_operand (operands[c], letter);
1.1.1.2 root 1453:
1454: while ((c = *p) >= '0' && c <= '9') p++;
1.1 root 1455: }
1.1.1.2 root 1456: /* % followed by a digit outputs an operand the default way. */
1457: else if (*p >= '0' && *p <= '9')
1.1 root 1458: {
1459: c = atoi (p);
1.1.1.9 root 1460: if (this_is_asm_operands && c >= (unsigned) insn_noperands)
1461: output_operand_lossage ("operand number out of range");
1462: else
1463: output_operand (operands[c], 0);
1.1.1.2 root 1464: while ((c = *p) >= '0' && c <= '9') p++;
1.1 root 1465: }
1.1.1.2 root 1466: /* % followed by punctuation: output something for that
1467: punctuation character alone, with no operand.
1468: The PRINT_OPERAND macro decides what is actually done. */
1.1.1.15! root 1469: #ifdef PRINT_OPERAND_PUNCT_VALID_P
! 1470: else if (PRINT_OPERAND_PUNCT_VALID_P (*p))
1.1.1.2 root 1471: output_operand (0, *p++);
1.1.1.15! root 1472: #endif
! 1473: else
! 1474: output_operand_lossage ("invalid %%-code");
1.1 root 1475: }
1476: }
1477:
1.1.1.2 root 1478: putc ('\n', asm_out_file);
1.1 root 1479: }
1.1.1.9 root 1480:
1.1.1.3 root 1481: /* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */
1482:
1483: void
1.1 root 1484: output_asm_label (x)
1485: rtx x;
1486: {
1.1.1.15! root 1487: char buf[256];
1.1.1.2 root 1488:
1.1 root 1489: if (GET_CODE (x) == LABEL_REF)
1.1.1.2 root 1490: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
1.1 root 1491: else if (GET_CODE (x) == CODE_LABEL)
1.1.1.2 root 1492: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
1.1 root 1493: else
1.1.1.9 root 1494: output_operand_lossage ("`%l' operand isn't a label");
1.1.1.2 root 1495:
1496: assemble_name (asm_out_file, buf);
1.1 root 1497: }
1498:
1499: /* Print operand X using machine-dependent assembler syntax.
1.1.1.2 root 1500: The macro PRINT_OPERAND is defined just to control this function.
1501: CODE is a non-digit that preceded the operand-number in the % spec,
1502: such as 'z' if the spec was `%z3'. CODE is 0 if there was no char
1503: between the % and the digits.
1504: When CODE is a non-letter, X is 0.
1505:
1506: The meanings of the letters are machine-dependent and controlled
1507: by PRINT_OPERAND. */
1.1 root 1508:
1509: static void
1.1.1.2 root 1510: output_operand (x, code)
1.1 root 1511: rtx x;
1.1.1.2 root 1512: int code;
1.1 root 1513: {
1.1.1.2 root 1514: if (x && GET_CODE (x) == SUBREG)
1.1.1.6 root 1515: x = alter_subreg (x);
1.1.1.2 root 1516: PRINT_OPERAND (asm_out_file, x, code);
1.1 root 1517: }
1518:
1519: /* Print a memory reference operand for address X
1520: using machine-dependent assembler syntax.
1521: The macro PRINT_OPERAND_ADDRESS exists just to control this function. */
1522:
1.1.1.2 root 1523: void
1.1 root 1524: output_address (x)
1525: rtx x;
1526: {
1.1.1.2 root 1527: walk_alter_subreg (x);
1528: PRINT_OPERAND_ADDRESS (asm_out_file, x);
1.1 root 1529: }
1530:
1531: /* Print an integer constant expression in assembler syntax.
1532: Addition and subtraction are the only arithmetic
1533: that may appear in these expressions. */
1534:
1535: void
1536: output_addr_const (file, x)
1537: FILE *file;
1538: rtx x;
1539: {
1.1.1.15! root 1540: char buf[256];
1.1.1.2 root 1541:
1.1 root 1542: restart:
1543: switch (GET_CODE (x))
1544: {
1545: case SYMBOL_REF:
1.1.1.2 root 1546: assemble_name (file, XSTR (x, 0));
1.1 root 1547: break;
1548:
1549: case LABEL_REF:
1.1.1.2 root 1550: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
1551: assemble_name (asm_out_file, buf);
1.1 root 1552: break;
1553:
1554: case CODE_LABEL:
1.1.1.2 root 1555: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
1556: assemble_name (asm_out_file, buf);
1.1 root 1557: break;
1558:
1559: case CONST_INT:
1560: fprintf (file, "%d", INTVAL (x));
1561: break;
1562:
1563: case CONST:
1564: x = XEXP (x, 0);
1565: goto restart;
1566:
1.1.1.8 root 1567: case CONST_DOUBLE:
1568: if (GET_MODE (x) == DImode)
1569: {
1570: /* We can use %d if the number is <32 bits and positive. */
1.1.1.12 root 1571: if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
1572: fprintf (file, "0x%x%08x",
1573: CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
1.1.1.8 root 1574: else
1.1.1.12 root 1575: fprintf (file, "%d", CONST_DOUBLE_LOW (x));
1.1.1.8 root 1576: }
1577: else
1578: /* We can't handle floating point constants;
1579: PRINT_OPERAND must handle them. */
1.1.1.9 root 1580: output_operand_lossage ("floating constant misused");
1.1.1.8 root 1581: break;
1582:
1.1 root 1583: case PLUS:
1.1.1.4 root 1584: /* Some assemblers need integer constants to appear last (eg masm). */
1585: if (GET_CODE (XEXP (x, 0)) == CONST_INT)
1586: {
1587: output_addr_const (file, XEXP (x, 1));
1.1.1.11 root 1588: if (INTVAL (XEXP (x, 0)) >= 0)
1589: fprintf (file, "+");
1.1.1.4 root 1590: output_addr_const (file, XEXP (x, 0));
1591: }
1592: else
1593: {
1594: output_addr_const (file, XEXP (x, 0));
1.1.1.11 root 1595: if (INTVAL (XEXP (x, 1)) >= 0)
1596: fprintf (file, "+");
1.1.1.4 root 1597: output_addr_const (file, XEXP (x, 1));
1598: }
1.1 root 1599: break;
1600:
1601: case MINUS:
1602: output_addr_const (file, XEXP (x, 0));
1603: fprintf (file, "-");
1604: output_addr_const (file, XEXP (x, 1));
1605: break;
1606:
1607: default:
1.1.1.9 root 1608: output_operand_lossage ("invalid expression as operand");
1.1 root 1609: }
1610: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.