|
|
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: /* Following a conditional branch, we have a new basic block. */
850: if (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
851: && GET_CODE (SET_SRC (body)) != LABEL_REF)
852: new_block = 1;
853:
854: /* If this is a conditional branch, maybe modify it
855: if the cc's are in a nonstandard state
856: so that it accomplishes the same thing that it would
857: do straightforwardly if the cc's were set up normally. */
858:
859: if (cc_status.flags != 0
860: && GET_CODE (insn) == JUMP_INSN
861: && GET_CODE (body) == SET
862: && SET_DEST (body) == pc_rtx
863: && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
864: /* This is done during prescan; it is not done again
865: in final scan when prescan has been done. */
866: && prescan >= 0)
867: {
868: /* This function may alter the contents of its argument
869: and clear some of the cc_status.flags bits.
870: It may also return 1 meaning condition now always true
871: or -1 meaning condition now always false
872: or 2 meaning condition nontrivial but altered. */
873: register int result = alter_cond (XEXP (SET_SRC (body), 0));
874: /* If condition now has fixed value, replace the IF_THEN_ELSE
875: with its then-operand or its else-operand. */
876: if (result == 1)
877: SET_SRC (body) = XEXP (SET_SRC (body), 1);
878: if (result == -1)
879: SET_SRC (body) = XEXP (SET_SRC (body), 2);
880: /* The jump is now either unconditional or a no-op.
881: If it has become a no-op, don't try to output it.
882: (It would not be recognized.) */
883: if (SET_SRC (body) == pc_rtx)
884: {
885: PUT_CODE (insn, NOTE);
886: NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
887: NOTE_SOURCE_FILE (insn) = 0;
888: break;
889: }
890: /* Rerecognize the instruction if it has changed. */
891: if (result != 0)
892: INSN_CODE (insn) = -1;
893: }
1.1 root 894:
1.1.1.15 root 895: #ifdef STORE_FLAG_VALUE
896: /* Make same adjustments to instructions that examine the
897: condition codes without jumping (if this machine has them). */
1.1.1.12 root 898:
1.1.1.15 root 899: if (cc_status.flags != 0
900: && GET_CODE (body) == SET)
901: switch (GET_CODE (SET_SRC (body)))
902: {
903: case GTU:
904: case GT:
905: case LTU:
906: case LT:
907: case GEU:
908: case GE:
909: case LEU:
910: case LE:
911: case EQ:
912: case NE:
1.1 root 913: {
1.1.1.15 root 914: register int result;
915: if (GET_CODE (XEXP (SET_SRC (body), 0)) != CC0)
916: break;
917: result = alter_cond (SET_SRC (body));
1.1 root 918: if (result == 1)
1.1.1.15 root 919: SET_SRC (body) = gen_rtx (CONST_INT, VOIDmode,
920: STORE_FLAG_VALUE);
1.1 root 921: if (result == -1)
1.1.1.15 root 922: SET_SRC (body) = const0_rtx;
1.1 root 923: if (result != 0)
924: INSN_CODE (insn) = -1;
925: }
1.1.1.15 root 926: }
927: #endif /* STORE_FLAG_VALUE */
1.1 root 928:
1.1.1.15 root 929: /* Do machine-specific peephole optimizations if desired. */
1.1 root 930:
1.1.1.15 root 931: if (optimize && !flag_no_peephole && !nopeepholes)
932: {
933: rtx next = peephole (insn);
934: /* When peepholing, if there were notes within the peephole,
935: emit them before the peephole. */
936: if (next != 0 && next != NEXT_INSN (insn))
937: {
938: rtx note = NEXT_INSN (insn);
939: rtx prev = PREV_INSN (insn);
940: while (note != next)
1.1 root 941: {
1.1.1.15 root 942: final_scan_insn (note, file, write_symbols, optimize,
943: prescan, nopeepholes);
944: note = NEXT_INSN (note);
1.1 root 945: }
1.1.1.15 root 946: /* In case this is prescan, put the notes
947: in proper position for later rescan. */
948: note = NEXT_INSN (insn);
949: PREV_INSN (note) = prev;
950: NEXT_INSN (prev) = note;
951: NEXT_INSN (PREV_INSN (next)) = insn;
952: PREV_INSN (insn) = PREV_INSN (next);
953: NEXT_INSN (insn) = next;
954: PREV_INSN (next) = insn;
1.1.1.12 root 955: }
956:
1.1.1.15 root 957: /* PEEPHOLE might have changed this. */
958: body = PATTERN (insn);
959: }
960:
961: /* Try to recognize the instruction.
962: If successful, verify that the operands satisfy the
963: constraints for the instruction. Crash if they don't,
964: since `reload' should have changed them so that they do. */
965:
966: insn_code_number = recog_memoized (insn);
967: insn_extract (insn);
968: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
969: {
970: if (GET_CODE (recog_operand[i]) == SUBREG)
971: recog_operand[i] = alter_subreg (recog_operand[i]);
972: }
1.1 root 973:
974: #ifdef REGISTER_CONSTRAINTS
1.1.1.15 root 975: if (! constrain_operands (insn_code_number))
976: abort ();
1.1 root 977: #endif
978:
1.1.1.15 root 979: /* Some target machines need to prescan each insn before
980: it is output. */
1.1.1.4 root 981:
982: #ifdef FINAL_PRESCAN_INSN
1.1.1.15 root 983: FINAL_PRESCAN_INSN (insn, recog_operand,
984: insn_n_operands[insn_code_number]);
1.1.1.4 root 985: #endif
986:
1.1.1.15 root 987: cc_prev_status = cc_status;
988:
989: /* Update `cc_status' for this instruction.
990: The instruction's output routine may change it further.
991: If the output routine for a jump insn needs to depend
992: on the cc status, it should look at cc_prev_status. */
1.1.1.2 root 993:
1.1.1.15 root 994: NOTICE_UPDATE_CC (body, insn);
1.1 root 995:
1.1.1.15 root 996: /* If the proper template needs to be chosen by some C code,
997: run that code and get the real template. */
1.1 root 998:
1.1.1.15 root 999: template = insn_template[insn_code_number];
1000: if (template == 0)
1001: {
1002: template = (*insn_outfun[insn_code_number]) (recog_operand, insn);
1.1 root 1003:
1.1.1.15 root 1004: /* If the C code returns 0, it means that it is a jump insn
1005: which follows a deleted test insn, and that test insn
1006: needs to be reinserted. */
1.1 root 1007: if (template == 0)
1.1.1.12 root 1008: {
1.1.1.15 root 1009: if (PREV_INSN (insn) != last_ignored_compare)
1010: abort ();
1011: new_block = 0;
1012: return PREV_INSN (insn);
1.1.1.12 root 1013: }
1.1.1.15 root 1014: }
1.1 root 1015:
1.1.1.15 root 1016: if (prescan > 0)
1017: break;
1.1.1.8 root 1018:
1.1.1.15 root 1019: /* Output assembler code from the template. */
1.1 root 1020:
1.1.1.15 root 1021: output_asm_insn (template, recog_operand);
1.1.1.12 root 1022:
1.1.1.15 root 1023: /* Mark this insn as having been output. */
1024: INSN_DELETED_P (insn) = 1;
1025: }
1.1 root 1026: }
1.1.1.15 root 1027: return NEXT_INSN (insn);
1.1.1.2 root 1028: }
1029:
1030: /* Set up FILENAME as the current file for GDB line-number output. */
1.1 root 1031:
1.1.1.2 root 1032: void
1033: set_current_gdbfile (filename)
1034: char *filename;
1035: {
1036: register struct gdbfile *f;
1037: for (f = gdbfiles; f; f = f->next)
1038: if (!strcmp (f->name, filename))
1039: break;
1.1 root 1040:
1.1.1.2 root 1041: if (!f)
1042: {
1043: f = (struct gdbfile *) permalloc (sizeof (struct gdbfile));
1044: f->next = gdbfiles;
1045: gdbfiles = f;
1046: f->name = filename;
1047: f->filenum = next_gdb_filenum++;
1048: f->nlines = 0;
1049: }
1050: current_gdbfile = f;
1051: lastfile = filename;
1.1 root 1052: }
1053:
1.1.1.2 root 1054: /* Output debugging info to the assembler file FILE
1055: based on the NOTE-insn INSN, assumed to be a line number. */
1.1 root 1056:
1.1.1.2 root 1057: static void
1058: output_source_line (file, insn, write_symbols)
1.1 root 1059: FILE *file;
1060: rtx insn;
1.1.1.4 root 1061: enum debugger write_symbols;
1.1 root 1062: {
1063: register char *filename = NOTE_SOURCE_FILE (insn);
1.1.1.4 root 1064:
1065: last_linenum = NOTE_LINE_NUMBER (insn);
1066:
1067: if (write_symbols == GDB_DEBUG)
1.1.1.2 root 1068: {
1069: /* Output GDB-format line number info. */
1.1 root 1070:
1.1.1.2 root 1071: /* If this is not the same source file as last time,
1072: find or assign a GDB-file-number to this file. */
1073: if (filename && (lastfile == 0 || strcmp (filename, lastfile)
1074: || current_gdbfile == 0))
1075: set_current_gdbfile (filename);
1076:
1077: ++current_gdbfile->nlines;
1078: fprintf (file, "\t.gdbline %d,%d\n",
1079: current_gdbfile->filenum, NOTE_LINE_NUMBER (insn));
1080: }
1.1.1.4 root 1081:
1.1.1.6 root 1082: if (write_symbols == SDB_DEBUG || write_symbols == DBX_DEBUG)
1.1.1.4 root 1083: {
1.1.1.6 root 1084: #ifdef SDB_DEBUGGING_INFO
1085: if (write_symbols == SDB_DEBUG
1.1.1.15 root 1086: #if 0 /* People like having line numbers even in wrong file! */
1.1.1.6 root 1087: /* COFF can't handle multiple source files--lose, lose. */
1.1.1.10 root 1088: && !strcmp (filename, main_input_filename)
1.1.1.15 root 1089: #endif
1090: /* COFF relative line numbers must be positive. */
1091: && last_linenum > sdb_begin_function_line)
1.1.1.6 root 1092: {
1.1.1.4 root 1093: #ifdef ASM_OUTPUT_SOURCE_LINE
1.1.1.6 root 1094: ASM_OUTPUT_SOURCE_LINE (file, last_linenum);
1.1.1.4 root 1095: #else
1.1.1.6 root 1096: fprintf (file, "\t.ln\t%d\n",
1097: (sdb_begin_function_line
1098: ? last_linenum - sdb_begin_function_line : 1));
1.1.1.4 root 1099: #endif
1.1.1.6 root 1100: }
1.1.1.4 root 1101: #endif
1102:
1103: #ifdef DBX_DEBUGGING_INFO
1.1.1.6 root 1104: if (write_symbols == DBX_DEBUG)
1.1.1.4 root 1105: {
1.1.1.6 root 1106: /* Write DBX line number data. */
1107:
1108: if (filename && (lastfile == 0 || strcmp (filename, lastfile)))
1109: {
1.1.1.2 root 1110: #ifdef ASM_OUTPUT_SOURCE_FILENAME
1.1.1.6 root 1111: ASM_OUTPUT_SOURCE_FILENAME (file, filename);
1.1.1.2 root 1112: #else
1.1.1.6 root 1113: fprintf (file, "\t.stabs \"%s\",%d,0,0,Ltext\n",
1114: filename, N_SOL);
1.1.1.2 root 1115: #endif
1.1.1.6 root 1116: lastfile = filename;
1117: }
1.1.1.4 root 1118: }
1.1.1.2 root 1119:
1120: #ifdef ASM_OUTPUT_SOURCE_LINE
1121: ASM_OUTPUT_SOURCE_LINE (file, NOTE_LINE_NUMBER (insn));
1122: #else
1123: fprintf (file, "\t.stabd %d,0,%d\n",
1124: N_SLINE, NOTE_LINE_NUMBER (insn));
1125: #endif
1.1.1.4 root 1126: #endif /* DBX_DEBUGGING_INFO */
1.1.1.2 root 1127: }
1.1 root 1128: }
1129:
1.1.1.2 root 1130: /* If X is a SUBREG, replace it with a REG or a MEM,
1131: based on the thing it is a subreg of. */
1.1 root 1132:
1.1.1.10 root 1133: rtx
1.1 root 1134: alter_subreg (x)
1135: register rtx x;
1136: {
1137: register rtx y = SUBREG_REG (x);
1138: if (GET_CODE (y) == SUBREG)
1.1.1.6 root 1139: y = alter_subreg (y);
1.1 root 1140:
1141: if (GET_CODE (y) == REG)
1142: {
1143: /* If the containing reg really gets a hard reg, so do we. */
1144: PUT_CODE (x, REG);
1145: REGNO (x) = REGNO (y) + SUBREG_WORD (x);
1146: }
1147: else if (GET_CODE (y) == MEM)
1148: {
1.1.1.2 root 1149: register int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
1.1 root 1150: #ifdef BYTES_BIG_ENDIAN
1.1.1.2 root 1151: offset -= (min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))
1152: - min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y))));
1.1 root 1153: #endif
1154: PUT_CODE (x, MEM);
1.1.1.14 root 1155: MEM_VOLATILE_P (x) = MEM_VOLATILE_P (y);
1.1 root 1156: XEXP (x, 0) = plus_constant (XEXP (y, 0), offset);
1157: }
1.1.1.6 root 1158: else if (GET_CODE (y) == CONST_DOUBLE)
1159: return y;
1160:
1161: return x;
1.1 root 1162: }
1163:
1.1.1.2 root 1164: /* Do alter_subreg on all the SUBREGs contained in X. */
1.1 root 1165:
1.1.1.2 root 1166: static rtx
1167: walk_alter_subreg (x)
1168: rtx x;
1169: {
1170: switch (GET_CODE (x))
1.1 root 1171: {
1.1.1.2 root 1172: case PLUS:
1173: case MULT:
1174: XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0));
1175: XEXP (x, 1) = walk_alter_subreg (XEXP (x, 1));
1176: break;
1177:
1178: case MEM:
1179: XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0));
1180: break;
1181:
1182: case SUBREG:
1.1.1.6 root 1183: return alter_subreg (x);
1.1 root 1184: }
1185:
1.1.1.2 root 1186: return x;
1.1 root 1187: }
1188:
1189: /* Given BODY, the body of a jump instruction, alter the jump condition
1190: as required by the bits that are set in cc_status.flags.
1191: Not all of the bits there can be handled at this level in all cases.
1192:
1193: The value is normally 0.
1194: 1 means that the condition has become always true.
1.1.1.8 root 1195: -1 means that the condition has become always false.
1196: 2 means that COND has been altered. */
1.1 root 1197:
1198: static int
1199: alter_cond (cond)
1200: register rtx cond;
1201: {
1202: int value = 0;
1203:
1204: if (cc_status.flags & CC_REVERSED)
1205: {
1206: value = 2;
1207: switch (GET_CODE (cond))
1208: {
1209: case LE:
1210: PUT_CODE (cond, GE);
1211: break;
1212: case GE:
1213: PUT_CODE (cond, LE);
1214: break;
1215: case LT:
1216: PUT_CODE (cond, GT);
1217: break;
1218: case GT:
1219: PUT_CODE (cond, LT);
1220: break;
1221: case LEU:
1222: PUT_CODE (cond, GEU);
1223: break;
1224: case GEU:
1225: PUT_CODE (cond, LEU);
1226: break;
1227: case LTU:
1228: PUT_CODE (cond, GTU);
1229: break;
1230: case GTU:
1231: PUT_CODE (cond, LTU);
1232: break;
1233: }
1234: }
1235:
1.1.1.8 root 1236: if (cc_status.flags & CC_NOT_POSITIVE)
1.1 root 1237: switch (GET_CODE (cond))
1238: {
1239: case LE:
1240: case LEU:
1241: case GEU:
1242: /* Jump becomes unconditional. */
1243: return 1;
1244:
1245: case GT:
1246: case GTU:
1247: case LTU:
1248: /* Jump becomes no-op. */
1249: return -1;
1250:
1251: case GE:
1252: PUT_CODE (cond, EQ);
1253: value = 2;
1254: break;
1255:
1256: case LT:
1257: PUT_CODE (cond, NE);
1258: value = 2;
1259: break;
1260: }
1261:
1.1.1.8 root 1262: if (cc_status.flags & CC_NOT_NEGATIVE)
1.1 root 1263: switch (GET_CODE (cond))
1264: {
1265: case GE:
1266: case GEU:
1267: /* Jump becomes unconditional. */
1268: return 1;
1269:
1270: case LT:
1271: case LTU:
1272: /* Jump becomes no-op. */
1273: return -1;
1274:
1275: case LE:
1276: case LEU:
1277: PUT_CODE (cond, EQ);
1278: value = 2;
1279: break;
1280:
1281: case GT:
1282: case GTU:
1283: PUT_CODE (cond, NE);
1284: value = 2;
1285: break;
1286: }
1287:
1.1.1.8 root 1288: if (cc_status.flags & CC_NO_OVERFLOW)
1.1 root 1289: switch (GET_CODE (cond))
1290: {
1291: case GEU:
1292: /* Jump becomes unconditional. */
1293: return 1;
1294:
1295: case LEU:
1296: PUT_CODE (cond, EQ);
1297: value = 2;
1298: break;
1299:
1300: case GTU:
1301: PUT_CODE (cond, NE);
1302: value = 2;
1303: break;
1304:
1305: case LTU:
1306: /* Jump becomes no-op. */
1307: return -1;
1308: }
1309:
1.1.1.8 root 1310: if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
1311: switch (GET_CODE (cond))
1312: {
1313: case LE:
1314: case LEU:
1315: case GE:
1316: case GEU:
1317: case LT:
1318: case LTU:
1319: case GT:
1320: case GTU:
1321: abort ();
1322:
1323: case NE:
1324: PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
1325: value = 2;
1326: break;
1327:
1328: case EQ:
1329: PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE);
1330: value = 2;
1331: break;
1332: }
1333:
1.1 root 1334: return value;
1335: }
1336:
1.1.1.9 root 1337: /* Report inconsistency between the assembler template and the operands.
1338: In an `asm', it's the user's fault; otherwise, the compiler's fault. */
1339:
1340: static void
1341: output_operand_lossage (str)
1342: char *str;
1343: {
1344: if (this_is_asm_operands)
1.1.1.11 root 1345: error_for_asm (this_is_asm_operands, "invalid `asm': %s", str);
1.1.1.9 root 1346: else
1347: abort ();
1348: }
1349:
1.1 root 1350: /* Output of assembler code from a template, and its subroutines. */
1351:
1352: /* Output text from TEMPLATE to the assembler output file,
1353: obeying %-directions to substitute operands taken from
1354: the vector OPERANDS.
1355:
1356: %N (for N a digit) means print operand N in usual manner.
1357: %lN means require operand N to be a CODE_LABEL or LABEL_REF
1358: and print the label name with no punctuation.
1359: %cN means require operand N to be a constant
1360: and print the constant expression with no punctuation.
1361: %aN means expect operand N to be a memory address
1362: (not a memory reference!) and print a reference
1363: to that address.
1364: %nN means expect operand N to be a constant
1365: and print a constant expression for minus the value
1366: of the operand, with no other punctuation. */
1367:
1368: void
1369: output_asm_insn (template, operands)
1370: char *template;
1371: rtx *operands;
1372: {
1373: register char *p;
1374: register int c;
1375:
1.1.1.2 root 1376: /* An insn may return a null string template
1377: in a case where no assembler code is needed. */
1378: if (*template == 0)
1379: return;
1380:
1.1 root 1381: p = template;
1.1.1.2 root 1382: putc ('\t', asm_out_file);
1383:
1384: #ifdef ASM_OUTPUT_OPCODE
1385: ASM_OUTPUT_OPCODE (asm_out_file, p);
1386: #endif
1387:
1.1 root 1388: while (c = *p++)
1389: {
1.1.1.2 root 1390: #ifdef ASM_OUTPUT_OPCODE
1391: if (c == '\n')
1.1 root 1392: {
1.1.1.2 root 1393: putc (c, asm_out_file);
1394: while ((c = *p) == '\t')
1.1 root 1395: {
1.1.1.2 root 1396: putc (c, asm_out_file);
1397: p++;
1.1 root 1398: }
1.1.1.2 root 1399: ASM_OUTPUT_OPCODE (asm_out_file, p);
1400: }
1401: else
1402: #endif
1403: if (c != '%')
1404: putc (c, asm_out_file);
1405: else
1406: {
1407: /* %% outputs a single %. */
1408: if (*p == '%')
1.1 root 1409: {
1.1.1.2 root 1410: p++;
1411: putc (c, asm_out_file);
1.1 root 1412: }
1.1.1.2 root 1413: /* % followed by a letter and some digits
1414: outputs an operand in a special way depending on the letter.
1415: Letters `acln' are implemented here.
1416: Other letters are passed to `output_operand' so that
1417: the PRINT_OPERAND macro can define them. */
1418: else if ((*p >= 'a' && *p <= 'z')
1419: || (*p >= 'A' && *p <= 'Z'))
1.1 root 1420: {
1.1.1.2 root 1421: int letter = *p++;
1422: c = atoi (p);
1423:
1.1.1.14 root 1424: if (! (*p >= '0' && *p <= '9'))
1425: output_operand_lossage ("operand number missing after %-letter");
1426: else if (this_is_asm_operands && c >= (unsigned) insn_noperands)
1.1.1.9 root 1427: output_operand_lossage ("operand number out of range");
1428: else if (letter == 'l')
1.1.1.2 root 1429: output_asm_label (operands[c]);
1430: else if (letter == 'a')
1431: output_address (operands[c]);
1432: else if (letter == 'c')
1433: {
1434: if (CONSTANT_ADDRESS_P (operands[c]))
1435: output_addr_const (asm_out_file, operands[c]);
1436: else
1437: output_operand (operands[c], 'c');
1438: }
1439: else if (letter == 'n')
1.1 root 1440: {
1.1.1.2 root 1441: if (GET_CODE (operands[c]) == CONST_INT)
1442: fprintf (asm_out_file, "%d", - INTVAL (operands[c]));
1443: else
1444: {
1445: putc ('-', asm_out_file);
1446: output_addr_const (asm_out_file, operands[c]);
1447: }
1.1 root 1448: }
1.1.1.2 root 1449: else
1.1.1.14 root 1450: output_operand (operands[c], letter);
1.1.1.2 root 1451:
1452: while ((c = *p) >= '0' && c <= '9') p++;
1.1 root 1453: }
1.1.1.2 root 1454: /* % followed by a digit outputs an operand the default way. */
1455: else if (*p >= '0' && *p <= '9')
1.1 root 1456: {
1457: c = atoi (p);
1.1.1.9 root 1458: if (this_is_asm_operands && c >= (unsigned) insn_noperands)
1459: output_operand_lossage ("operand number out of range");
1460: else
1461: output_operand (operands[c], 0);
1.1.1.2 root 1462: while ((c = *p) >= '0' && c <= '9') p++;
1.1 root 1463: }
1.1.1.2 root 1464: /* % followed by punctuation: output something for that
1465: punctuation character alone, with no operand.
1466: The PRINT_OPERAND macro decides what is actually done. */
1.1.1.15 root 1467: #ifdef PRINT_OPERAND_PUNCT_VALID_P
1468: else if (PRINT_OPERAND_PUNCT_VALID_P (*p))
1.1.1.2 root 1469: output_operand (0, *p++);
1.1.1.15 root 1470: #endif
1471: else
1472: output_operand_lossage ("invalid %%-code");
1.1 root 1473: }
1474: }
1475:
1.1.1.2 root 1476: putc ('\n', asm_out_file);
1.1 root 1477: }
1.1.1.9 root 1478:
1.1.1.3 root 1479: /* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */
1480:
1481: void
1.1 root 1482: output_asm_label (x)
1483: rtx x;
1484: {
1.1.1.15 root 1485: char buf[256];
1.1.1.2 root 1486:
1.1 root 1487: if (GET_CODE (x) == LABEL_REF)
1.1.1.2 root 1488: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
1.1 root 1489: else if (GET_CODE (x) == CODE_LABEL)
1.1.1.2 root 1490: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
1.1 root 1491: else
1.1.1.9 root 1492: output_operand_lossage ("`%l' operand isn't a label");
1.1.1.2 root 1493:
1494: assemble_name (asm_out_file, buf);
1.1 root 1495: }
1496:
1497: /* Print operand X using machine-dependent assembler syntax.
1.1.1.2 root 1498: The macro PRINT_OPERAND is defined just to control this function.
1499: CODE is a non-digit that preceded the operand-number in the % spec,
1500: such as 'z' if the spec was `%z3'. CODE is 0 if there was no char
1501: between the % and the digits.
1502: When CODE is a non-letter, X is 0.
1503:
1504: The meanings of the letters are machine-dependent and controlled
1505: by PRINT_OPERAND. */
1.1 root 1506:
1507: static void
1.1.1.2 root 1508: output_operand (x, code)
1.1 root 1509: rtx x;
1.1.1.2 root 1510: int code;
1.1 root 1511: {
1.1.1.2 root 1512: if (x && GET_CODE (x) == SUBREG)
1.1.1.6 root 1513: x = alter_subreg (x);
1.1.1.2 root 1514: PRINT_OPERAND (asm_out_file, x, code);
1.1 root 1515: }
1516:
1517: /* Print a memory reference operand for address X
1518: using machine-dependent assembler syntax.
1519: The macro PRINT_OPERAND_ADDRESS exists just to control this function. */
1520:
1.1.1.2 root 1521: void
1.1 root 1522: output_address (x)
1523: rtx x;
1524: {
1.1.1.2 root 1525: walk_alter_subreg (x);
1526: PRINT_OPERAND_ADDRESS (asm_out_file, x);
1.1 root 1527: }
1528:
1529: /* Print an integer constant expression in assembler syntax.
1530: Addition and subtraction are the only arithmetic
1531: that may appear in these expressions. */
1532:
1533: void
1534: output_addr_const (file, x)
1535: FILE *file;
1536: rtx x;
1537: {
1.1.1.15 root 1538: char buf[256];
1.1.1.2 root 1539:
1.1 root 1540: restart:
1541: switch (GET_CODE (x))
1542: {
1543: case SYMBOL_REF:
1.1.1.2 root 1544: assemble_name (file, XSTR (x, 0));
1.1 root 1545: break;
1546:
1547: case LABEL_REF:
1.1.1.2 root 1548: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
1549: assemble_name (asm_out_file, buf);
1.1 root 1550: break;
1551:
1552: case CODE_LABEL:
1.1.1.2 root 1553: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
1554: assemble_name (asm_out_file, buf);
1.1 root 1555: break;
1556:
1557: case CONST_INT:
1558: fprintf (file, "%d", INTVAL (x));
1559: break;
1560:
1561: case CONST:
1562: x = XEXP (x, 0);
1563: goto restart;
1564:
1.1.1.8 root 1565: case CONST_DOUBLE:
1566: if (GET_MODE (x) == DImode)
1567: {
1568: /* We can use %d if the number is <32 bits and positive. */
1.1.1.12 root 1569: if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
1570: fprintf (file, "0x%x%08x",
1571: CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
1.1.1.8 root 1572: else
1.1.1.12 root 1573: fprintf (file, "%d", CONST_DOUBLE_LOW (x));
1.1.1.8 root 1574: }
1575: else
1576: /* We can't handle floating point constants;
1577: PRINT_OPERAND must handle them. */
1.1.1.9 root 1578: output_operand_lossage ("floating constant misused");
1.1.1.8 root 1579: break;
1580:
1.1 root 1581: case PLUS:
1.1.1.4 root 1582: /* Some assemblers need integer constants to appear last (eg masm). */
1583: if (GET_CODE (XEXP (x, 0)) == CONST_INT)
1584: {
1585: output_addr_const (file, XEXP (x, 1));
1.1.1.11 root 1586: if (INTVAL (XEXP (x, 0)) >= 0)
1587: fprintf (file, "+");
1.1.1.4 root 1588: output_addr_const (file, XEXP (x, 0));
1589: }
1590: else
1591: {
1592: output_addr_const (file, XEXP (x, 0));
1.1.1.11 root 1593: if (INTVAL (XEXP (x, 1)) >= 0)
1594: fprintf (file, "+");
1.1.1.4 root 1595: output_addr_const (file, XEXP (x, 1));
1596: }
1.1 root 1597: break;
1598:
1599: case MINUS:
1600: output_addr_const (file, XEXP (x, 0));
1601: fprintf (file, "-");
1602: output_addr_const (file, XEXP (x, 1));
1603: break;
1604:
1605: default:
1.1.1.9 root 1606: output_operand_lossage ("invalid expression as operand");
1.1 root 1607: }
1608: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.