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