|
|
1.1 root 1: /* Convert RTL to assembler code and output it, for GNU compiler.
2: Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
3:
4: This file is part of GNU CC.
5:
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 2, or (at your option)
9: any later version.
10:
11: GNU CC is distributed in the hope that it will be useful,
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. */
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:
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'.
29:
30: Some optimizations are also done at this level.
31: Move instructions that were made unnecessary by good register allocation
32: are detected and omitted from the output. (Though most of these
33: are removed by the last jump pass.)
34:
35: Instructions to set the condition codes are omitted when it can be
36: seen that the condition codes already had the desired values.
37:
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 "config.h"
47: #include "gvarargs.h"
48: #include "rtl.h"
49: #include "regs.h"
50: #include "insn-config.h"
1.1.1.4 ! root 51: #include "insn-flags.h"
1.1 root 52: #include "insn-attr.h"
53: #include "insn-codes.h"
54: #include "recog.h"
55: #include "conditions.h"
56: #include "flags.h"
57: #include "real.h"
58: #include "hard-reg-set.h"
1.1.1.4 ! root 59: #include "defaults.h"
1.1 root 60:
1.1.1.4 ! root 61: #include <stdio.h>
! 62:
! 63: #include "output.h"
1.1 root 64:
65: /* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist. */
1.1.1.2 root 66: #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
67: #if defined (USG) || defined (NO_STAB_H)
1.1 root 68: #include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */
69: #else
70: #include <stab.h> /* On BSD, use the system's stab.h. */
71: #endif /* not USG */
1.1.1.2 root 72: #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
73:
74: #ifdef XCOFF_DEBUGGING_INFO
75: #include "xcoffout.h"
76: #endif
1.1 root 77:
78: /* .stabd code for line number. */
79: #ifndef N_SLINE
80: #define N_SLINE 0x44
81: #endif
82:
83: /* .stabs code for included file name. */
84: #ifndef N_SOL
85: #define N_SOL 0x84
86: #endif
87:
88: #ifndef INT_TYPE_SIZE
89: #define INT_TYPE_SIZE BITS_PER_WORD
90: #endif
91:
92: /* If we aren't using cc0, CC_STATUS_INIT shouldn't exist. So define a
93: null default for it to save conditionalization later. */
94: #ifndef CC_STATUS_INIT
95: #define CC_STATUS_INIT
96: #endif
97:
98: /* How to start an assembler comment. */
99: #ifndef ASM_COMMENT_START
100: #define ASM_COMMENT_START ";#"
101: #endif
102:
103: rtx peephole ();
104: void output_asm_insn ();
105: rtx alter_subreg ();
106: static int alter_cond ();
107: void output_asm_label ();
108: static void output_operand ();
109: void output_address ();
110: void output_addr_const ();
111: static void output_source_line ();
112: rtx final_scan_insn ();
113: void profile_function ();
1.1.1.4 ! root 114: static void profile_after_prologue ();
1.1 root 115:
116: #ifdef HAVE_ATTR_length
117: static int asm_insn_count ();
118: #endif
119:
120: /* Nonzero means this function is a leaf function, with no function calls.
121: This variable exists to be examined in FUNCTION_PROLOGUE
122: and FUNCTION_EPILOGUE. Always zero, unless set by some action. */
123: int leaf_function;
124:
125: int leaf_function_p ();
126:
127: #ifdef LEAF_REGISTERS
128: int only_leaf_regs_used ();
129: static void leaf_renumber_regs ();
130: void leaf_renumber_regs_insn ();
131: #endif
132:
133: /* Last insn processed by final_scan_insn. */
134: static rtx debug_insn = 0;
135:
136: /* Line number of last NOTE. */
137: static int last_linenum;
138:
139: /* Number of basic blocks seen so far;
140: used if profile_block_flag is set. */
141: static int count_basic_blocks;
142:
143: /* Nonzero while outputting an `asm' with operands.
144: This means that inconsistencies are the user's fault, so don't abort.
145: The precise value is the insn being output, to pass to error_for_asm. */
146: static rtx this_is_asm_operands;
147:
148: /* Number of operands of this insn, for an `asm' with operands. */
149: static int insn_noperands;
150:
151: /* Compare optimization flag. */
152:
153: static rtx last_ignored_compare = 0;
154:
155: /* Flag indicating this insn is the start of a new basic block. */
156:
157: static int new_block = 1;
158:
159: /* All the symbol-blocks (levels of scoping) in the compilation
160: are assigned sequence numbers in order of appearance of the
161: beginnings of the symbol-blocks. Both final and dbxout do this,
162: and assume that they will both give the same number to each block.
163: Final uses these sequence numbers to generate assembler label names
164: LBBnnn and LBEnnn for the beginning and end of the symbol-block.
1.1.1.4 ! root 165: Dbxout uses the sequence numbers to generate references to the same labels
1.1 root 166: from the dbx debugging information.
167:
168: Sdb records this level at the beginning of each function,
169: in order to find the current level when recursing down declarations.
170: It outputs the block beginning and endings
171: at the point in the asm file where the blocks would begin and end. */
172:
173: int next_block_index;
174:
175: /* Assign a unique number to each insn that is output.
176: This can be used to generate unique local labels. */
177:
178: static int insn_counter = 0;
179:
180: #ifdef HAVE_cc0
181: /* This variable contains machine-dependent flags (defined in tm.h)
182: set and examined by output routines
183: that describe how to interpret the condition codes properly. */
184:
185: CC_STATUS cc_status;
186:
187: /* During output of an insn, this contains a copy of cc_status
188: from before the insn. */
189:
190: CC_STATUS cc_prev_status;
191: #endif
192:
193: /* Indexed by hardware reg number, is 1 if that register is ever
194: used in the current function.
195:
196: In life_analysis, or in stupid_life_analysis, this is set
197: up to record the hard regs used explicitly. Reload adds
198: in the hard regs used for holding pseudo regs. Final uses
199: it to generate the code in the function prologue and epilogue
200: to save and restore registers as needed. */
201:
202: char regs_ever_live[FIRST_PSEUDO_REGISTER];
203:
204: /* Nonzero means current function must be given a frame pointer.
205: Set in stmt.c if anything is allocated on the stack there.
206: Set in reload1.c if anything is allocated on the stack there. */
207:
208: int frame_pointer_needed;
209:
210: /* Assign unique numbers to labels generated for profiling. */
211:
212: int profile_label_no;
213:
214: /* Length so far allocated in PENDING_BLOCKS. */
215:
216: static int max_block_depth;
217:
218: /* Stack of sequence numbers of symbol-blocks of which we have seen the
219: beginning but not yet the end. Sequence numbers are assigned at
220: the beginning; this stack allows us to find the sequence number
221: of a block that is ending. */
222:
223: static int *pending_blocks;
224:
225: /* Number of elements currently in use in PENDING_BLOCKS. */
226:
227: static int block_depth;
228:
229: /* Nonzero if have enabled APP processing of our assembler output. */
230:
231: static int app_on;
232:
233: /* If we are outputting an insn sequence, this contains the sequence rtx.
234: Zero otherwise. */
235:
236: rtx final_sequence;
237:
238: /* Indexed by line number, nonzero if there is a note for that line. */
239:
240: static char *line_note_exists;
241:
242: /* Initialize data in final at the beginning of a compilation. */
243:
244: void
245: init_final (filename)
246: char *filename;
247: {
248: next_block_index = 2;
249: app_on = 0;
250: max_block_depth = 20;
251: pending_blocks = (int *) xmalloc (20 * sizeof *pending_blocks);
252: final_sequence = 0;
253: }
254:
255: /* Called at end of source file,
256: to output the block-profiling table for this entire compilation. */
257:
258: void
259: end_final (filename)
260: char *filename;
261: {
262: int i;
263:
264: if (profile_block_flag)
265: {
266: char name[12];
267:
268: data_section ();
269:
270: /* Output the main header, of 6 words:
271: 0: 1 if this file's initialized, else 0.
272: 1: address of file name.
273: 2: address of table of counts.
274: 4: number of counts in the table.
275: 5: always 0, for compatibility with Sun.
276: 6: extra word added by GNU: address of address table
277: which contains addresses of basic blocks,
278: in parallel with the table of counts. */
279: ASM_OUTPUT_ALIGN (asm_out_file,
280: exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
281:
282: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
283: assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
284: ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1);
285: assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
286: ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
287: assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
1.1.1.4 ! root 288: assemble_integer (GEN_INT (count_basic_blocks), UNITS_PER_WORD, 1);
1.1 root 289: assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
290: ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
291: assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
292:
293: /* Output the file name. */
294: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
295: {
296: int len = strlen (filename);
297: char *data_file = (char *) alloca (len + 3);
298: strcpy (data_file, filename);
299: strip_off_ending (data_file, len);
300: strcat (data_file, ".d");
301: assemble_string (data_file, strlen (data_file) + 1);
302: }
303:
304: /* Realign data section. */
305: ASM_OUTPUT_ALIGN (asm_out_file,
306: exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
307:
308: /* Make space for the table of counts. */
309: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2);
310: assemble_zeros (INT_TYPE_SIZE / BITS_PER_UNIT * count_basic_blocks);
311:
312: /* Output the table of addresses. */
313: readonly_data_section ();
1.1.1.4 ! root 314: /* Realign in new section */
! 315: ASM_OUTPUT_ALIGN (asm_out_file,
! 316: floor_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
1.1 root 317: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 3);
318: for (i = 0; i < count_basic_blocks; i++)
319: {
320: char name[12];
321: ASM_GENERATE_INTERNAL_LABEL (name, "LPB", i);
322: assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name),
323: UNITS_PER_WORD, 1);
324: }
325:
326: /* End with the address of the table of addresses,
327: so we can find it easily, as the last word in the file's text. */
328: ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
329: assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
330: }
331: }
332:
333: /* Enable APP processing of subsequent output.
334: Used before the output from an `asm' statement. */
335:
336: void
337: app_enable ()
338: {
339: if (! app_on)
340: {
341: fprintf (asm_out_file, ASM_APP_ON);
342: app_on = 1;
343: }
344: }
345:
346: /* Enable APP processing of subsequent output.
347: Called from varasm.c before most kinds of output. */
348:
349: void
350: app_disable ()
351: {
352: if (app_on)
353: {
354: fprintf (asm_out_file, ASM_APP_OFF);
355: app_on = 0;
356: }
357: }
358:
359: /* Return the number of slots filled in the current
360: delayed branch sequence (we don't count the insn needing the
361: delay slot). Zero if not in a delayed branch sequence. */
362:
363: #ifdef DELAY_SLOTS
364: int
365: dbr_sequence_length ()
366: {
367: if (final_sequence != 0)
368: return XVECLEN (final_sequence, 0) - 1;
369: else
370: return 0;
371: }
372: #endif
373:
374: /* The next two pages contain routines used to compute the length of an insn
375: and to shorten branches. */
376:
377: /* Arrays for insn lengths, and addresses. The latter is referenced by
378: `insn_current_length'. */
379:
380: static short *insn_lengths;
381: int *insn_addresses;
382:
383: /* Address of insn being processed. Used by `insn_current_length'. */
384: int insn_current_address;
385:
386: /* Indicate the branch shortening hasn't yet been done. */
387:
388: void
389: init_insn_lengths ()
390: {
391: insn_lengths = 0;
392: }
393:
394: /* Obtain the current length of an insn. If branch shortening has been done,
395: get its actual length. Otherwise, get its maximum length. */
396:
397: int
398: get_attr_length (insn)
399: rtx insn;
400: {
401: #ifdef HAVE_ATTR_length
402: rtx body;
403: int i;
404: int length = 0;
405:
406: if (insn_lengths)
407: return insn_lengths[INSN_UID (insn)];
408: else
409: switch (GET_CODE (insn))
410: {
411: case NOTE:
412: case BARRIER:
413: case CODE_LABEL:
414: return 0;
415:
416: case CALL_INSN:
417: length = insn_default_length (insn);
418: break;
419:
420: case JUMP_INSN:
421: body = PATTERN (insn);
422: if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
423: {
424: /* This only takes room if jump tables go into the text section. */
425: #if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION)
426: length = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC)
427: * GET_MODE_SIZE (GET_MODE (body)));
428:
429: /* Be pessimistic and assume worst-case alignment. */
430: length += (GET_MODE_SIZE (GET_MODE (body)) - 1);
431: #else
432: return 0;
433: #endif
434: }
435: else
436: length = insn_default_length (insn);
437: break;
438:
439: case INSN:
440: body = PATTERN (insn);
441: if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)
442: return 0;
443:
444: else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
445: length = asm_insn_count (insn) * insn_default_length (insn);
446: else if (GET_CODE (body) == SEQUENCE)
447: for (i = 0; i < XVECLEN (body, 0); i++)
448: length += get_attr_length (XVECEXP (body, 0, i));
449: else
450: length = insn_default_length (insn);
451: }
452:
453: #ifdef ADJUST_INSN_LENGTH
454: ADJUST_INSN_LENGTH (insn, length);
455: #endif
456: return length;
457: #else /* not HAVE_ATTR_length */
458: return 0;
459: #endif /* not HAVE_ATTR_length */
460: }
461:
462: /* Make a pass over all insns and compute their actual lengths by shortening
463: any branches of variable length if possible. */
464:
465: /* Give a default value for the lowest address in a function. */
466:
467: #ifndef FIRST_INSN_ADDRESS
468: #define FIRST_INSN_ADDRESS 0
469: #endif
470:
471: void
472: shorten_branches (first)
473: rtx first;
474: {
475: #ifdef HAVE_ATTR_length
476: rtx insn;
477: int something_changed = 1;
478: int max_uid = 0;
479: char *varying_length;
480: rtx body;
481: int uid;
482:
483: /* Compute maximum UID and allocate arrays. */
484: for (insn = first; insn; insn = NEXT_INSN (insn))
485: if (INSN_UID (insn) > max_uid)
486: max_uid = INSN_UID (insn);
487:
488: max_uid++;
489: insn_lengths = (short *) oballoc (max_uid * sizeof (short));
490: insn_addresses = (int *) oballoc (max_uid * sizeof (int));
491: varying_length = (char *) oballoc (max_uid * sizeof (char));
492:
493: /* Compute initial lengths, addresses, and varying flags for each insn. */
494: for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
495: insn != 0;
496: insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
497: {
498: uid = INSN_UID (insn);
499: insn_addresses[uid] = insn_current_address;
500: insn_lengths[uid] = 0;
501: varying_length[uid] = 0;
502:
503: if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
504: || GET_CODE (insn) == CODE_LABEL)
505: continue;
506:
507: body = PATTERN (insn);
508: if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
509: {
510: /* This only takes room if read-only data goes into the text
511: section. */
512: #if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION)
513: int unitsize = GET_MODE_SIZE (GET_MODE (body));
514:
515: insn_lengths[uid] = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC)
516: * GET_MODE_SIZE (GET_MODE (body)));
517:
518: /* Account for possible alignment. */
519: insn_lengths[uid]
520: += unitsize - (insn_current_address & (unitsize - 1));
521: #else
522: ;
523: #endif
524: }
525: else if (asm_noperands (body) >= 0)
526: insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
527: else if (GET_CODE (body) == SEQUENCE)
528: {
529: int i;
1.1.1.4 ! root 530: int const_delay_slots;
! 531: #ifdef DELAY_SLOTS
! 532: const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0));
! 533: #else
! 534: const_delay_slots = 0;
! 535: #endif
1.1 root 536: /* Inside a delay slot sequence, we do not do any branch shortening
1.1.1.4 ! root 537: if the shortening could change the number of delay slots
! 538: of the branch. */
1.1 root 539: for (i = 0; i < XVECLEN (body, 0); i++)
540: {
541: rtx inner_insn = XVECEXP (body, 0, i);
542: int inner_uid = INSN_UID (inner_insn);
543: int inner_length;
544:
545: if (asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0)
546: inner_length = (asm_insn_count (PATTERN (inner_insn))
547: * insn_default_length (inner_insn));
548: else
549: inner_length = insn_default_length (inner_insn);
550:
551: insn_lengths[inner_uid] = inner_length;
1.1.1.4 ! root 552: if (const_delay_slots)
! 553: {
! 554: if ((varying_length[inner_uid]
! 555: = insn_variable_length_p (inner_insn)) != 0)
! 556: varying_length[uid] = 1;
! 557: insn_addresses[inner_uid] = (insn_current_address +
! 558: insn_lengths[uid]);
! 559: }
! 560: else
! 561: varying_length[inner_uid] = 0;
1.1 root 562: insn_lengths[uid] += inner_length;
563: }
564: }
565: else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
566: {
567: insn_lengths[uid] = insn_default_length (insn);
568: varying_length[uid] = insn_variable_length_p (insn);
569: }
570:
571: /* If needed, do any adjustment. */
572: #ifdef ADJUST_INSN_LENGTH
573: ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);
574: #endif
575: }
576:
577: /* Now loop over all the insns finding varying length insns. For each,
578: get the current insn length. If it has changed, reflect the change.
579: When nothing changes for a full pass, we are done. */
580:
581: while (something_changed)
582: {
583: something_changed = 0;
584: for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
585: insn != 0;
1.1.1.4 ! root 586: insn = NEXT_INSN (insn))
1.1 root 587: {
588: int new_length;
589:
590: uid = INSN_UID (insn);
591: insn_addresses[uid] = insn_current_address;
592: if (! varying_length[uid])
1.1.1.4 ! root 593: {
! 594: insn_current_address += insn_lengths[uid];
! 595: continue;
! 596: }
! 597: if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
! 598: {
! 599: int i;
! 600:
! 601: body = PATTERN (insn);
! 602: new_length = 0;
! 603: for (i = 0; i < XVECLEN (body, 0); i++)
! 604: {
! 605: rtx inner_insn = XVECEXP (body, 0, i);
! 606: int inner_uid = INSN_UID (inner_insn);
! 607: int inner_length;
! 608:
! 609: insn_addresses[inner_uid] = insn_current_address;
! 610: inner_length = insn_current_length (inner_insn);
! 611: if (inner_length != insn_lengths[inner_uid])
! 612: {
! 613: insn_lengths[inner_uid] = inner_length;
! 614: something_changed = 1;
! 615: }
! 616: insn_current_address += insn_lengths[inner_uid];
! 617: new_length += inner_length;
! 618: }
! 619: }
! 620: else
! 621: {
! 622: new_length = insn_current_length (insn);
! 623: insn_current_address += new_length;
! 624: }
1.1 root 625: if (new_length != insn_lengths[uid])
626: {
627: insn_lengths[uid] = new_length;
628: something_changed = 1;
629: }
630: }
631: }
632: #endif /* HAVE_ATTR_length */
633: }
634:
635: #ifdef HAVE_ATTR_length
636: /* Given the body of an INSN known to be generated by an ASM statement, return
637: the number of machine instructions likely to be generated for this insn.
638: This is used to compute its length. */
639:
640: static int
641: asm_insn_count (body)
642: rtx body;
643: {
644: char *template;
645: int count = 1;
646:
1.1.1.4 ! root 647: for (template = decode_asm_operands (body, NULL_PTR, NULL_PTR,
! 648: NULL_PTR, NULL_PTR);
1.1 root 649: *template; template++)
650: if (*template == ';' || *template == '\n')
651: count++;
652:
653: return count;
654: }
655: #endif
656:
657: /* Output assembler code for the start of a function,
658: and initialize some of the variables in this file
659: for the new function. The label for the function and associated
660: assembler pseudo-ops have already been output in `assemble_start_function'.
661:
662: FIRST is the first insn of the rtl for the function being compiled.
663: FILE is the file to write assembler code to.
664: OPTIMIZE is nonzero if we should eliminate redundant
665: test and compare insns. */
666:
667: void
668: final_start_function (first, file, optimize)
669: rtx first;
670: FILE *file;
671: int optimize;
672: {
673: block_depth = 0;
674:
675: this_is_asm_operands = 0;
676:
677: #ifdef NON_SAVING_SETJMP
678: /* A function that calls setjmp should save and restore all the
679: call-saved registers on a system where longjmp clobbers them. */
680: if (NON_SAVING_SETJMP && current_function_calls_setjmp)
681: {
682: int i;
683:
684: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
685: if (!call_used_regs[i] && !call_fixed_regs[i])
686: regs_ever_live[i] = 1;
687: }
688: #endif
689:
690: /* Initial line number is supposed to be output
691: before the function's prologue and label
692: so that the function's address will not appear to be
693: in the last statement of the preceding function. */
694: if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
695: {
696: if (write_symbols == SDB_DEBUG)
697: /* For sdb, let's not, but say we did.
698: We need to set last_linenum for sdbout_function_begin,
699: but we can't have an actual line number before the .bf symbol.
700: (sdb_begin_function_line is not set,
701: and other compilers don't do it.) */
702: last_linenum = NOTE_LINE_NUMBER (first);
1.1.1.2 root 703: #ifdef XCOFF_DEBUGGING_INFO
704: else if (write_symbols == XCOFF_DEBUG)
705: {
706: last_linenum = NOTE_LINE_NUMBER (first);
707: xcoffout_output_first_source_line (file, last_linenum);
708: }
709: #endif
1.1 root 710: else
711: output_source_line (file, first);
712: }
713:
714: #ifdef LEAF_REG_REMAP
715: if (leaf_function)
716: leaf_renumber_regs (first);
717: #endif
718:
719: /* The Sun386i and perhaps other machines don't work right
720: if the profiling code comes after the prologue. */
721: #ifdef PROFILE_BEFORE_PROLOGUE
722: if (profile_flag)
723: profile_function (file);
724: #endif /* PROFILE_BEFORE_PROLOGUE */
725:
726: #ifdef FUNCTION_PROLOGUE
727: /* First output the function prologue: code to set up the stack frame. */
728: FUNCTION_PROLOGUE (file, get_frame_size ());
729: #endif
730:
1.1.1.2 root 731: #if defined (SDB_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
732: if (write_symbols == SDB_DEBUG || write_symbols == XCOFF_DEBUG)
1.1 root 733: next_block_index = 1;
734: #endif
735:
1.1.1.4 ! root 736: /* If the machine represents the prologue as RTL, the profiling code must
! 737: be emitted when NOTE_INSN_PROLOGUE_END is scanned. */
! 738: #ifdef HAVE_prologue
! 739: if (! HAVE_prologue)
! 740: #endif
! 741: profile_after_prologue (file);
! 742:
! 743: profile_label_no++;
! 744: }
! 745:
! 746: static void
! 747: profile_after_prologue (file)
! 748: FILE *file;
! 749: {
1.1 root 750: #ifdef FUNCTION_BLOCK_PROFILER
751: if (profile_block_flag)
752: {
753: FUNCTION_BLOCK_PROFILER (file, profile_label_no);
754: }
755: #endif /* FUNCTION_BLOCK_PROFILER */
756:
757: #ifndef PROFILE_BEFORE_PROLOGUE
758: if (profile_flag)
759: profile_function (file);
760: #endif /* not PROFILE_BEFORE_PROLOGUE */
761: }
762:
763: void
764: profile_function (file)
765: FILE *file;
766: {
767: int align = MIN (BIGGEST_ALIGNMENT, INT_TYPE_SIZE);
768: int sval = current_function_returns_struct;
769: int cxt = current_function_needs_context;
770:
771: data_section ();
772: ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
773: ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no);
774: assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
775:
776: text_section ();
777:
778: #ifdef STRUCT_VALUE_INCOMING_REGNUM
779: if (sval)
780: ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM);
781: #else
782: #ifdef STRUCT_VALUE_REGNUM
783: if (sval)
784: ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM);
785: #endif
786: #endif
787:
788: #if 0
789: #ifdef STATIC_CHAIN_INCOMING_REGNUM
790: if (cxt)
791: ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
792: #else
793: #ifdef STATIC_CHAIN_REGNUM
794: if (cxt)
795: ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
796: #endif
797: #endif
798: #endif /* 0 */
799:
800: FUNCTION_PROFILER (file, profile_label_no);
801:
802: #if 0
803: #ifdef STATIC_CHAIN_INCOMING_REGNUM
804: if (cxt)
805: ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
806: #else
807: #ifdef STATIC_CHAIN_REGNUM
808: if (cxt)
809: ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
810: #endif
811: #endif
812: #endif /* 0 */
813:
814: #ifdef STRUCT_VALUE_INCOMING_REGNUM
815: if (sval)
816: ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM);
817: #else
818: #ifdef STRUCT_VALUE_REGNUM
819: if (sval)
820: ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM);
821: #endif
822: #endif
823: }
824:
825: /* Output assembler code for the end of a function.
826: For clarity, args are same as those of `final_start_function'
827: even though not all of them are needed. */
828:
829: void
830: final_end_function (first, file, optimize)
831: rtx first;
832: FILE *file;
833: int optimize;
834: {
835: if (app_on)
836: {
837: fprintf (file, ASM_APP_OFF);
838: app_on = 0;
839: }
840:
841: #ifdef SDB_DEBUGGING_INFO
842: if (write_symbols == SDB_DEBUG)
843: sdbout_end_function (last_linenum);
844: #endif
845:
1.1.1.4 ! root 846: #ifdef DWARF_DEBUGGING_INFO
! 847: if (write_symbols == DWARF_DEBUG)
! 848: dwarfout_end_function ();
! 849: #endif
! 850:
1.1.1.2 root 851: #ifdef XCOFF_DEBUGGING_INFO
852: if (write_symbols == XCOFF_DEBUG)
853: xcoffout_end_function (file, last_linenum);
854: #endif
855:
1.1 root 856: #ifdef FUNCTION_EPILOGUE
857: /* Finally, output the function epilogue:
858: code to restore the stack frame and return to the caller. */
859: FUNCTION_EPILOGUE (file, get_frame_size ());
860: #endif
861:
862: #ifdef SDB_DEBUGGING_INFO
863: if (write_symbols == SDB_DEBUG)
864: sdbout_end_epilogue ();
865: #endif
866:
867: #ifdef DWARF_DEBUGGING_INFO
868: if (write_symbols == DWARF_DEBUG)
869: dwarfout_end_epilogue ();
870: #endif
871:
1.1.1.2 root 872: #ifdef XCOFF_DEBUGGING_INFO
873: if (write_symbols == XCOFF_DEBUG)
874: xcoffout_end_epilogue (file);
875: #endif
876:
1.1 root 877: /* If FUNCTION_EPILOGUE is not defined, then the function body
878: itself contains return instructions wherever needed. */
879: }
880:
881: /* Output assembler code for some insns: all or part of a function.
882: For description of args, see `final_start_function', above.
883:
884: PRESCAN is 1 if we are not really outputting,
885: just scanning as if we were outputting.
886: Prescanning deletes and rearranges insns just like ordinary output.
887: PRESCAN is -2 if we are outputting after having prescanned.
888: In this case, don't try to delete or rearrange insns
889: because that has already been done.
890: Prescanning is done only on certain machines. */
891:
892: void
893: final (first, file, optimize, prescan)
894: rtx first;
895: FILE *file;
896: int optimize;
897: int prescan;
898: {
899: register rtx insn;
900: int max_line = 0;
901:
902: last_ignored_compare = 0;
903: new_block = 1;
904:
1.1.1.4 ! root 905: /* Make a map indicating which line numbers appear in this function.
! 906: When producing SDB debugging info, delete troublesome line number
! 907: notes from inlined functions in other files as well as duplicate
! 908: line number notes. */
! 909: #ifdef SDB_DEBUGGING_INFO
! 910: if (write_symbols == SDB_DEBUG)
! 911: {
! 912: rtx last = 0;
! 913: for (insn = first; insn; insn = NEXT_INSN (insn))
! 914: if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
! 915: {
! 916: if ((RTX_INTEGRATED_P (insn)
! 917: && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0)
! 918: || (last != 0
! 919: && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
! 920: && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)))
! 921: {
! 922: NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
! 923: NOTE_SOURCE_FILE (insn) = 0;
! 924: continue;
! 925: }
! 926: last = insn;
! 927: if (NOTE_LINE_NUMBER (insn) > max_line)
! 928: max_line = NOTE_LINE_NUMBER (insn);
! 929: }
! 930: }
! 931: else
! 932: #endif
! 933: {
! 934: for (insn = first; insn; insn = NEXT_INSN (insn))
! 935: if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line)
! 936: max_line = NOTE_LINE_NUMBER (insn);
! 937: }
1.1 root 938:
939: line_note_exists = (char *) oballoc (max_line + 1);
940: bzero (line_note_exists, max_line + 1);
941:
942: for (insn = first; insn; insn = NEXT_INSN (insn))
943: if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
944: line_note_exists[NOTE_LINE_NUMBER (insn)] = 1;
945:
946: init_recog ();
947:
948: CC_STATUS_INIT;
949:
950: /* Output the insns. */
951: for (insn = NEXT_INSN (first); insn;)
952: insn = final_scan_insn (insn, file, optimize, prescan, 0);
953:
954: /* Do basic-block profiling here
955: if the last insn was a conditional branch. */
956: if (profile_block_flag && new_block)
957: {
958: new_block = 0;
959: /* Enable the table of basic-block use counts
960: to point at the code it applies to. */
961: ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks);
962: /* Before first insn of this basic block, increment the
963: count of times it was entered. */
964: #ifdef BLOCK_PROFILER
965: BLOCK_PROFILER (file, count_basic_blocks);
966: CC_STATUS_INIT;
967: #endif
968: count_basic_blocks++;
969: }
970: }
971:
972: /* The final scan for one insn, INSN.
973: Args are same as in `final', except that INSN
974: is the insn being scanned.
975: Value returned is the next insn to be scanned.
976:
977: NOPEEPHOLES is the flag to disallow peephole processing (currently
978: used for within delayed branch sequence output). */
979:
980: rtx
981: final_scan_insn (insn, file, optimize, prescan, nopeepholes)
982: rtx insn;
983: FILE *file;
984: int optimize;
985: int prescan;
986: int nopeepholes;
987: {
988: register int i;
989: insn_counter++;
990:
991: /* Ignore deleted insns. These can occur when we split insns (due to a
992: template of "#") while not optimizing. */
993: if (INSN_DELETED_P (insn))
994: return NEXT_INSN (insn);
995:
996: switch (GET_CODE (insn))
997: {
998: case NOTE:
999: if (prescan > 0)
1000: break;
1001:
1002: /* Align the beginning of a loop, for higher speed
1003: on certain machines. */
1004:
1005: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG && optimize > 0)
1006: {
1007: #ifdef ASM_OUTPUT_LOOP_ALIGN
1008: rtx next = next_nonnote_insn (insn);
1009: if (next && GET_CODE (next) == CODE_LABEL)
1010: {
1011: ASM_OUTPUT_LOOP_ALIGN (asm_out_file);
1012: }
1013: #endif
1014: break;
1015: }
1016: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
1017: break;
1018:
1.1.1.4 ! root 1019: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
! 1020: {
! 1021: #ifdef FUNCTION_END_PROLOGUE
! 1022: FUNCTION_END_PROLOGUE (file);
! 1023: #endif
! 1024: profile_after_prologue (file);
! 1025: break;
! 1026: }
! 1027:
! 1028: #ifdef FUNCTION_BEGIN_EPILOGUE
! 1029: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
! 1030: {
! 1031: FUNCTION_BEGIN_EPILOGUE (file);
! 1032: break;
! 1033: }
! 1034: #endif
! 1035:
1.1 root 1036: if (write_symbols == NO_DEBUG)
1037: break;
1038: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
1039: {
1040: #ifdef SDB_DEBUGGING_INFO
1041: if (write_symbols == SDB_DEBUG)
1042: sdbout_begin_function (last_linenum);
1043: #endif
1.1.1.2 root 1044: #ifdef XCOFF_DEBUGGING_INFO
1045: if (write_symbols == XCOFF_DEBUG)
1046: xcoffout_begin_function (file, last_linenum);
1047: #endif
1.1.1.4 ! root 1048: #ifdef DWARF_DEBUGGING_INFO
! 1049: if (write_symbols == DWARF_DEBUG)
! 1050: dwarfout_begin_function ();
! 1051: #endif
1.1 root 1052: break;
1053: }
1054: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
1055: break; /* An insn that was "deleted" */
1056: if (app_on)
1057: {
1058: fprintf (file, ASM_APP_OFF);
1059: app_on = 0;
1060: }
1061: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
1062: && (debug_info_level == DINFO_LEVEL_NORMAL
1.1.1.4 ! root 1063: || debug_info_level == DINFO_LEVEL_VERBOSE
! 1064: #ifdef DWARF_DEBUGGING_INFO
! 1065: || write_symbols == DWARF_DEBUG
! 1066: #endif
! 1067: )
! 1068: )
1.1 root 1069: {
1070: /* Beginning of a symbol-block. Assign it a sequence number
1071: and push the number onto the stack PENDING_BLOCKS. */
1072:
1073: if (block_depth == max_block_depth)
1074: {
1075: /* PENDING_BLOCKS is full; make it longer. */
1076: max_block_depth *= 2;
1077: pending_blocks
1078: = (int *) xrealloc (pending_blocks,
1079: max_block_depth * sizeof (int));
1080: }
1081: pending_blocks[block_depth++] = next_block_index;
1082:
1083: /* Output debugging info about the symbol-block beginning. */
1084:
1085: #ifdef SDB_DEBUGGING_INFO
1086: if (write_symbols == SDB_DEBUG)
1087: sdbout_begin_block (file, last_linenum, next_block_index);
1088: #endif
1.1.1.2 root 1089: #ifdef XCOFF_DEBUGGING_INFO
1090: if (write_symbols == XCOFF_DEBUG)
1091: xcoffout_begin_block (file, last_linenum, next_block_index);
1092: #endif
1.1 root 1093: #ifdef DBX_DEBUGGING_INFO
1094: if (write_symbols == DBX_DEBUG)
1095: ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", next_block_index);
1096: #endif
1097: #ifdef DWARF_DEBUGGING_INFO
1098: if (write_symbols == DWARF_DEBUG && block_depth > 1)
1099: dwarfout_begin_block (next_block_index);
1100: #endif
1101:
1102: next_block_index++;
1103: }
1104: else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
1105: && (debug_info_level == DINFO_LEVEL_NORMAL
1.1.1.4 ! root 1106: || debug_info_level == DINFO_LEVEL_VERBOSE
! 1107: #ifdef DWARF_DEBUGGING_INFO
! 1108: || write_symbols == DWARF_DEBUG
! 1109: #endif
! 1110: )
! 1111: )
1.1 root 1112: {
1113: /* End of a symbol-block. Pop its sequence number off
1114: PENDING_BLOCKS and output debugging info based on that. */
1115:
1116: --block_depth;
1117:
1.1.1.2 root 1118: #ifdef XCOFF_DEBUGGING_INFO
1119: if (write_symbols == XCOFF_DEBUG && block_depth >= 0)
1120: xcoffout_end_block (file, last_linenum, pending_blocks[block_depth]);
1121: #endif
1.1 root 1122: #ifdef DBX_DEBUGGING_INFO
1123: if (write_symbols == DBX_DEBUG && block_depth >= 0)
1124: ASM_OUTPUT_INTERNAL_LABEL (file, "LBE",
1125: pending_blocks[block_depth]);
1126: #endif
1127: #ifdef SDB_DEBUGGING_INFO
1128: if (write_symbols == SDB_DEBUG && block_depth >= 0)
1129: sdbout_end_block (file, last_linenum);
1130: #endif
1131: #ifdef DWARF_DEBUGGING_INFO
1132: if (write_symbols == DWARF_DEBUG && block_depth >= 1)
1133: dwarfout_end_block (pending_blocks[block_depth]);
1134: #endif
1135: }
1.1.1.4 ! root 1136: else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL
! 1137: && (debug_info_level == DINFO_LEVEL_NORMAL
! 1138: || debug_info_level == DINFO_LEVEL_VERBOSE))
! 1139: {
! 1140: #ifdef DWARF_DEBUGGING_INFO
! 1141: if (write_symbols == DWARF_DEBUG)
! 1142: dwarfout_label (insn);
! 1143: #endif
! 1144: }
1.1 root 1145: else if (NOTE_LINE_NUMBER (insn) > 0)
1146: /* This note is a line-number. */
1147: {
1148: register rtx note;
1149:
1150: #if 0 /* This is what we used to do. */
1151: output_source_line (file, insn);
1152: #endif
1153: int note_after = 0;
1154:
1155: /* If there is anything real after this note,
1156: output it. If another line note follows, omit this one. */
1157: for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note))
1158: {
1159: if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL)
1160: break;
1.1.1.3 root 1161: /* These types of notes can be significant
1.1.1.4 ! root 1162: so make sure the preceding line number stays. */
1.1.1.3 root 1163: else if (GET_CODE (note) == NOTE
1164: && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG
1165: || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END
1166: || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG))
1167: break;
1.1 root 1168: else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0)
1169: {
1.1.1.3 root 1170: /* Another line note follows; we can delete this note
1171: if no intervening line numbers have notes elsewhere. */
1.1 root 1172: int num;
1173: for (num = NOTE_LINE_NUMBER (insn) + 1;
1174: num < NOTE_LINE_NUMBER (note);
1175: num++)
1176: if (line_note_exists[num])
1177: break;
1178:
1.1.1.4 ! root 1179: if (num >= NOTE_LINE_NUMBER (note))
1.1 root 1180: note_after = 1;
1181: break;
1182: }
1183: }
1184:
1185: /* Output this line note
1186: if it is the first or the last line note in a row. */
1187: if (!note_after)
1188: output_source_line (file, insn);
1189: }
1190: break;
1191:
1192: case BARRIER:
1193: #ifdef ASM_OUTPUT_ALIGN_CODE
1.1.1.4 ! root 1194: /* Don't litter the assembler output with needless alignments. A
! 1195: BARRIER will be placed at the end of every function if HAVE_epilogue
! 1196: is true. */
! 1197: if (NEXT_INSN (insn))
! 1198: ASM_OUTPUT_ALIGN_CODE (file);
1.1 root 1199: #endif
1200: break;
1201:
1202: case CODE_LABEL:
1203: CC_STATUS_INIT;
1204: if (prescan > 0)
1205: break;
1206: new_block = 1;
1207: #ifdef SDB_DEBUGGING_INFO
1208: if (write_symbols == SDB_DEBUG && LABEL_NAME (insn))
1209: sdbout_label (insn);
1210: #endif
1211: #ifdef DWARF_DEBUGGING_INFO
1212: if (write_symbols == DWARF_DEBUG && LABEL_NAME (insn))
1213: dwarfout_label (insn);
1214: #endif
1215: if (app_on)
1216: {
1217: fprintf (file, ASM_APP_OFF);
1218: app_on = 0;
1219: }
1220: if (NEXT_INSN (insn) != 0
1221: && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN)
1222: {
1223: rtx nextbody = PATTERN (NEXT_INSN (insn));
1224:
1225: /* If this label is followed by a jump-table,
1226: make sure we put the label in the read-only section. Also
1227: possibly write the label and jump table together. */
1228:
1229: if (GET_CODE (nextbody) == ADDR_VEC
1230: || GET_CODE (nextbody) == ADDR_DIFF_VEC)
1231: {
1232: #ifndef JUMP_TABLES_IN_TEXT_SECTION
1233: readonly_data_section ();
1.1.1.4 ! root 1234: #ifdef READONLY_DATA_SECTION
! 1235: ASM_OUTPUT_ALIGN (file,
! 1236: exact_log2 (BIGGEST_ALIGNMENT
! 1237: / BITS_PER_UNIT));
! 1238: #endif /* READONLY_DATA_SECTION */
! 1239: #else /* JUMP_TABLES_IN_TEXT_SECTION */
1.1 root 1240: text_section ();
1.1.1.4 ! root 1241: #endif /* JUMP_TABLES_IN_TEXT_SECTION */
1.1 root 1242: #ifdef ASM_OUTPUT_CASE_LABEL
1243: ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
1244: NEXT_INSN (insn));
1245: #else
1246: ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
1247: #endif
1248: break;
1249: }
1250: }
1251:
1252: ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
1253: break;
1254:
1255: default:
1256: {
1257: register rtx body = PATTERN (insn);
1258: int insn_code_number;
1259: char *template;
1260: rtx note;
1261:
1262: /* An INSN, JUMP_INSN or CALL_INSN.
1263: First check for special kinds that recog doesn't recognize. */
1264:
1265: if (GET_CODE (body) == USE /* These are just declarations */
1266: || GET_CODE (body) == CLOBBER)
1267: break;
1268:
1269: #ifdef HAVE_cc0
1270: /* If there is a REG_CC_SETTER note on this insn, it means that
1271: the setting of the condition code was done in the delay slot
1272: of the insn that branched here. So recover the cc status
1273: from the insn that set it. */
1274:
1.1.1.4 ! root 1275: note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
1.1 root 1276: if (note)
1277: {
1278: NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
1279: cc_prev_status = cc_status;
1280: }
1281: #endif
1282:
1283: /* Detect insns that are really jump-tables
1284: and output them as such. */
1285:
1286: if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
1287: {
1288: register int vlen, idx;
1289:
1290: if (prescan > 0)
1291: break;
1292:
1293: if (app_on)
1294: {
1295: fprintf (file, ASM_APP_OFF);
1296: app_on = 0;
1297: }
1298:
1299: vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC);
1300: for (idx = 0; idx < vlen; idx++)
1301: {
1302: if (GET_CODE (body) == ADDR_VEC)
1.1.1.4 ! root 1303: {
! 1304: #ifdef ASM_OUTPUT_ADDR_VEC_ELT
! 1305: ASM_OUTPUT_ADDR_VEC_ELT
! 1306: (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
! 1307: #else
! 1308: abort ();
! 1309: #endif
! 1310: }
1.1 root 1311: else
1.1.1.4 ! root 1312: {
! 1313: #ifdef ASM_OUTPUT_ADDR_DIFF_ELT
! 1314: ASM_OUTPUT_ADDR_DIFF_ELT
! 1315: (file,
! 1316: CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
! 1317: CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
! 1318: #else
! 1319: abort ();
! 1320: #endif
! 1321: }
1.1 root 1322: }
1323: #ifdef ASM_OUTPUT_CASE_END
1324: ASM_OUTPUT_CASE_END (file,
1325: CODE_LABEL_NUMBER (PREV_INSN (insn)),
1326: insn);
1327: #endif
1328:
1329: text_section ();
1330:
1331: break;
1332: }
1333:
1334: /* Do basic-block profiling when we reach a new block.
1335: Done here to avoid jump tables. */
1336: if (profile_block_flag && new_block)
1337: {
1338: new_block = 0;
1339: /* Enable the table of basic-block use counts
1340: to point at the code it applies to. */
1341: ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks);
1342: /* Before first insn of this basic block, increment the
1343: count of times it was entered. */
1344: #ifdef BLOCK_PROFILER
1345: BLOCK_PROFILER (file, count_basic_blocks);
1346: CC_STATUS_INIT;
1347: #endif
1348: count_basic_blocks++;
1349: }
1350:
1351: if (GET_CODE (body) == ASM_INPUT)
1352: {
1353: /* There's no telling what that did to the condition codes. */
1354: CC_STATUS_INIT;
1355: if (prescan > 0)
1356: break;
1357: if (! app_on)
1358: {
1359: fprintf (file, ASM_APP_ON);
1360: app_on = 1;
1361: }
1362: fprintf (asm_out_file, "\t%s\n", XSTR (body, 0));
1363: break;
1364: }
1365:
1366: /* Detect `asm' construct with operands. */
1367: if (asm_noperands (body) >= 0)
1368: {
1369: int noperands = asm_noperands (body);
1370: rtx *ops;
1371: char *string;
1372:
1373: /* There's no telling what that did to the condition codes. */
1374: CC_STATUS_INIT;
1375: if (prescan > 0)
1376: break;
1377:
1378: /* alloca won't do here, since only return from `final'
1379: would free it. */
1380: if (noperands > 0)
1381: ops = (rtx *) xmalloc (noperands * sizeof (rtx));
1382:
1383: if (! app_on)
1384: {
1385: fprintf (file, ASM_APP_ON);
1386: app_on = 1;
1387: }
1388:
1389: /* Get out the operand values. */
1.1.1.4 ! root 1390: string = decode_asm_operands (body, ops, NULL_PTR,
! 1391: NULL_PTR, NULL_PTR);
1.1 root 1392: /* Inhibit aborts on what would otherwise be compiler bugs. */
1393: insn_noperands = noperands;
1394: this_is_asm_operands = insn;
1395: /* Output the insn using them. */
1396: output_asm_insn (string, ops);
1397: this_is_asm_operands = 0;
1398: if (noperands > 0)
1399: free (ops);
1400: break;
1401: }
1402:
1403: if (prescan <= 0 && app_on)
1404: {
1405: fprintf (file, ASM_APP_OFF);
1406: app_on = 0;
1407: }
1408:
1409: if (GET_CODE (body) == SEQUENCE)
1410: {
1411: /* A delayed-branch sequence */
1412: register int i;
1413: rtx next;
1414:
1415: if (prescan > 0)
1416: break;
1417: final_sequence = body;
1418:
1419: /* The first insn in this SEQUENCE might be a JUMP_INSN that will
1420: force the restoration of a comparison that was previously
1421: thought unnecessary. If that happens, cancel this sequence
1422: and cause that insn to be restored. */
1423:
1424: next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1);
1425: if (next != XVECEXP (body, 0, 1))
1426: {
1427: final_sequence = 0;
1428: return next;
1429: }
1430:
1431: for (i = 1; i < XVECLEN (body, 0); i++)
1432: final_scan_insn (XVECEXP (body, 0, i), file, 0, prescan, 1);
1433: #ifdef DBR_OUTPUT_SEQEND
1434: DBR_OUTPUT_SEQEND (file);
1435: #endif
1436: final_sequence = 0;
1437:
1438: /* If the insn requiring the delay slot was a CALL_INSN, the
1439: insns in the delay slot are actually executed before the
1440: called function. Hence we don't preserve any CC-setting
1441: actions in these insns and the CC must be marked as being
1442: clobbered by the function. */
1443: if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN)
1444: CC_STATUS_INIT;
1.1.1.3 root 1445:
1446: /* Following a conditional branch sequence, we have a new basic
1447: block. */
1448: if (profile_block_flag)
1449: {
1450: rtx insn = XVECEXP (body, 0, 0);
1451: rtx body = PATTERN (insn);
1452:
1453: if ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
1454: && GET_CODE (SET_SRC (body)) != LABEL_REF)
1455: || (GET_CODE (insn) == JUMP_INSN
1456: && GET_CODE (body) == PARALLEL
1457: && GET_CODE (XVECEXP (body, 0, 0)) == SET
1458: && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF))
1459: new_block = 1;
1460: }
1.1 root 1461: break;
1462: }
1463:
1464: /* We have a real machine instruction as rtl. */
1465:
1466: body = PATTERN (insn);
1467:
1468: #ifdef HAVE_cc0
1469: /* Check for redundant test and compare instructions
1470: (when the condition codes are already set up as desired).
1471: This is done only when optimizing; if not optimizing,
1472: it should be possible for the user to alter a variable
1473: with the debugger in between statements
1474: and the next statement should reexamine the variable
1475: to compute the condition codes. */
1476:
1477: if (optimize
1478: && GET_CODE (body) == SET
1479: && GET_CODE (SET_DEST (body)) == CC0
1480: && insn != last_ignored_compare)
1481: {
1482: if (GET_CODE (SET_SRC (body)) == SUBREG)
1483: SET_SRC (body) = alter_subreg (SET_SRC (body));
1484: else if (GET_CODE (SET_SRC (body)) == COMPARE)
1485: {
1486: if (GET_CODE (XEXP (SET_SRC (body), 0)) == SUBREG)
1487: XEXP (SET_SRC (body), 0)
1488: = alter_subreg (XEXP (SET_SRC (body), 0));
1489: if (GET_CODE (XEXP (SET_SRC (body), 1)) == SUBREG)
1490: XEXP (SET_SRC (body), 1)
1491: = alter_subreg (XEXP (SET_SRC (body), 1));
1492: }
1493: if ((cc_status.value1 != 0
1494: && rtx_equal_p (SET_SRC (body), cc_status.value1))
1495: || (cc_status.value2 != 0
1496: && rtx_equal_p (SET_SRC (body), cc_status.value2)))
1497: {
1498: /* Don't delete insn if it has an addressing side-effect. */
1499: if (! FIND_REG_INC_NOTE (insn, 0)
1500: /* or if anything in it is volatile. */
1501: && ! volatile_refs_p (PATTERN (insn)))
1502: {
1503: /* We don't really delete the insn; just ignore it. */
1504: last_ignored_compare = insn;
1505: break;
1506: }
1507: }
1508: }
1509: #endif
1510:
1.1.1.3 root 1511: /* Following a conditional branch, we have a new basic block.
1512: But if we are inside a sequence, the new block starts after the
1513: last insn of the sequence. */
1514: if (profile_block_flag && final_sequence == 0
1515: && ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
1516: && GET_CODE (SET_SRC (body)) != LABEL_REF)
1517: || (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == PARALLEL
1518: && GET_CODE (XVECEXP (body, 0, 0)) == SET
1519: && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF)))
1.1 root 1520: new_block = 1;
1521:
1522: #ifndef STACK_REGS
1523: /* Don't bother outputting obvious no-ops, even without -O.
1524: This optimization is fast and doesn't interfere with debugging.
1525: Don't do this if the insn is in a delay slot, since this
1526: will cause an improper number of delay insns to be written. */
1527: if (final_sequence == 0
1528: && prescan >= 0
1529: && GET_CODE (insn) == INSN && GET_CODE (body) == SET
1530: && GET_CODE (SET_SRC (body)) == REG
1531: && GET_CODE (SET_DEST (body)) == REG
1532: && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body)))
1533: break;
1534: #endif
1535:
1536: #ifdef HAVE_cc0
1537: /* If this is a conditional branch, maybe modify it
1538: if the cc's are in a nonstandard state
1539: so that it accomplishes the same thing that it would
1540: do straightforwardly if the cc's were set up normally. */
1541:
1542: if (cc_status.flags != 0
1543: && GET_CODE (insn) == JUMP_INSN
1544: && GET_CODE (body) == SET
1545: && SET_DEST (body) == pc_rtx
1546: && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
1547: /* This is done during prescan; it is not done again
1548: in final scan when prescan has been done. */
1549: && prescan >= 0)
1550: {
1551: /* This function may alter the contents of its argument
1552: and clear some of the cc_status.flags bits.
1553: It may also return 1 meaning condition now always true
1554: or -1 meaning condition now always false
1555: or 2 meaning condition nontrivial but altered. */
1556: register int result = alter_cond (XEXP (SET_SRC (body), 0));
1557: /* If condition now has fixed value, replace the IF_THEN_ELSE
1558: with its then-operand or its else-operand. */
1559: if (result == 1)
1560: SET_SRC (body) = XEXP (SET_SRC (body), 1);
1561: if (result == -1)
1562: SET_SRC (body) = XEXP (SET_SRC (body), 2);
1563:
1564: /* The jump is now either unconditional or a no-op.
1565: If it has become a no-op, don't try to output it.
1566: (It would not be recognized.) */
1567: if (SET_SRC (body) == pc_rtx)
1568: {
1569: PUT_CODE (insn, NOTE);
1570: NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
1571: NOTE_SOURCE_FILE (insn) = 0;
1572: break;
1573: }
1574: else if (GET_CODE (SET_SRC (body)) == RETURN)
1575: /* Replace (set (pc) (return)) with (return). */
1576: PATTERN (insn) = body = SET_SRC (body);
1577:
1578: /* Rerecognize the instruction if it has changed. */
1579: if (result != 0)
1580: INSN_CODE (insn) = -1;
1581: }
1582:
1583: /* Make same adjustments to instructions that examine the
1584: condition codes without jumping (if this machine has them). */
1585:
1586: if (cc_status.flags != 0
1587: && GET_CODE (body) == SET)
1588: {
1589: switch (GET_CODE (SET_SRC (body)))
1590: {
1591: case GTU:
1592: case GT:
1593: case LTU:
1594: case LT:
1595: case GEU:
1596: case GE:
1597: case LEU:
1598: case LE:
1599: case EQ:
1600: case NE:
1601: {
1602: register int result;
1603: if (XEXP (SET_SRC (body), 0) != cc0_rtx)
1604: break;
1605: result = alter_cond (SET_SRC (body));
1606: if (result == 1)
1607: validate_change (insn, &SET_SRC (body), const_true_rtx, 0);
1608: else if (result == -1)
1609: validate_change (insn, &SET_SRC (body), const0_rtx, 0);
1610: else if (result == 2)
1611: INSN_CODE (insn) = -1;
1612: }
1613: }
1614: }
1615: #endif
1616:
1617: /* Do machine-specific peephole optimizations if desired. */
1618:
1619: if (optimize && !flag_no_peephole && !nopeepholes)
1620: {
1621: rtx next = peephole (insn);
1622: /* When peepholing, if there were notes within the peephole,
1623: emit them before the peephole. */
1624: if (next != 0 && next != NEXT_INSN (insn))
1625: {
1626: rtx prev = PREV_INSN (insn);
1627: rtx note;
1628:
1629: for (note = NEXT_INSN (insn); note != next;
1630: note = NEXT_INSN (note))
1631: final_scan_insn (note, file, optimize, prescan, nopeepholes);
1632:
1633: /* In case this is prescan, put the notes
1634: in proper position for later rescan. */
1635: note = NEXT_INSN (insn);
1636: PREV_INSN (note) = prev;
1637: NEXT_INSN (prev) = note;
1638: NEXT_INSN (PREV_INSN (next)) = insn;
1639: PREV_INSN (insn) = PREV_INSN (next);
1640: NEXT_INSN (insn) = next;
1641: PREV_INSN (next) = insn;
1642: }
1643:
1644: /* PEEPHOLE might have changed this. */
1645: body = PATTERN (insn);
1646: }
1647:
1648: /* Try to recognize the instruction.
1649: If successful, verify that the operands satisfy the
1650: constraints for the instruction. Crash if they don't,
1651: since `reload' should have changed them so that they do. */
1652:
1653: insn_code_number = recog_memoized (insn);
1654: insn_extract (insn);
1655: for (i = 0; i < insn_n_operands[insn_code_number]; i++)
1656: {
1657: if (GET_CODE (recog_operand[i]) == SUBREG)
1658: recog_operand[i] = alter_subreg (recog_operand[i]);
1659: }
1660:
1661: #ifdef REGISTER_CONSTRAINTS
1662: if (! constrain_operands (insn_code_number, 1))
1663: fatal_insn_not_found (insn);
1664: #endif
1665:
1666: /* Some target machines need to prescan each insn before
1667: it is output. */
1668:
1669: #ifdef FINAL_PRESCAN_INSN
1670: FINAL_PRESCAN_INSN (insn, recog_operand,
1671: insn_n_operands[insn_code_number]);
1672: #endif
1673:
1674: #ifdef HAVE_cc0
1675: cc_prev_status = cc_status;
1676:
1677: /* Update `cc_status' for this instruction.
1678: The instruction's output routine may change it further.
1679: If the output routine for a jump insn needs to depend
1680: on the cc status, it should look at cc_prev_status. */
1681:
1682: NOTICE_UPDATE_CC (body, insn);
1683: #endif
1684:
1685: debug_insn = insn;
1686:
1687: /* If the proper template needs to be chosen by some C code,
1688: run that code and get the real template. */
1689:
1690: template = insn_template[insn_code_number];
1691: if (template == 0)
1692: {
1693: template = (*insn_outfun[insn_code_number]) (recog_operand, insn);
1694:
1695: /* If the C code returns 0, it means that it is a jump insn
1696: which follows a deleted test insn, and that test insn
1697: needs to be reinserted. */
1698: if (template == 0)
1699: {
1700: if (prev_nonnote_insn (insn) != last_ignored_compare)
1701: abort ();
1702: new_block = 0;
1703: return prev_nonnote_insn (insn);
1704: }
1705: }
1706:
1707: /* If the template is the string "#", it means that this insn must
1708: be split. */
1709: if (template[0] == '#' && template[1] == '\0')
1710: {
1711: rtx new = try_split (body, insn, 0);
1712:
1713: /* If we didn't split the insn, go away. */
1714: if (new == insn && PATTERN (new) == body)
1715: abort ();
1716:
1717: new_block = 0;
1718: return new;
1719: }
1720:
1721: if (prescan > 0)
1722: break;
1723:
1724: /* Output assembler code from the template. */
1725:
1726: output_asm_insn (template, recog_operand);
1727:
1728: #if 0
1729: /* It's not at all clear why we did this and doing so interferes
1730: with tests we'd like to do to use REG_WAS_0 notes, so let's try
1731: with this out. */
1732:
1733: /* Mark this insn as having been output. */
1734: INSN_DELETED_P (insn) = 1;
1735: #endif
1736:
1737: debug_insn = 0;
1738: }
1739: }
1740: return NEXT_INSN (insn);
1741: }
1742:
1743: /* Output debugging info to the assembler file FILE
1744: based on the NOTE-insn INSN, assumed to be a line number. */
1745:
1746: static void
1747: output_source_line (file, insn)
1748: FILE *file;
1749: rtx insn;
1750: {
1751: char ltext_label_name[100];
1752: register char *filename = NOTE_SOURCE_FILE (insn);
1753:
1754: last_linenum = NOTE_LINE_NUMBER (insn);
1755:
1756: if (write_symbols != NO_DEBUG)
1757: {
1758: #ifdef SDB_DEBUGGING_INFO
1759: if (write_symbols == SDB_DEBUG
1760: #if 0 /* People like having line numbers even in wrong file! */
1761: /* COFF can't handle multiple source files--lose, lose. */
1762: && !strcmp (filename, main_input_filename)
1763: #endif
1764: /* COFF relative line numbers must be positive. */
1765: && last_linenum > sdb_begin_function_line)
1766: {
1767: #ifdef ASM_OUTPUT_SOURCE_LINE
1768: ASM_OUTPUT_SOURCE_LINE (file, last_linenum);
1769: #else
1770: fprintf (file, "\t.ln\t%d\n",
1771: ((sdb_begin_function_line > -1)
1772: ? last_linenum - sdb_begin_function_line : 1));
1773: #endif
1774: }
1775: #endif
1776:
1.1.1.2 root 1777: #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
1778: if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
1.1.1.4 ! root 1779: dbxout_source_line (file, filename, NOTE_LINE_NUMBER (insn));
1.1.1.2 root 1780: #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
1.1 root 1781:
1782: #ifdef DWARF_DEBUGGING_INFO
1783: if (write_symbols == DWARF_DEBUG)
1784: dwarfout_line (filename, NOTE_LINE_NUMBER (insn));
1785: #endif
1786: }
1787: }
1788:
1789: /* If X is a SUBREG, replace it with a REG or a MEM,
1790: based on the thing it is a subreg of. */
1791:
1792: rtx
1793: alter_subreg (x)
1794: register rtx x;
1795: {
1796: register rtx y = SUBREG_REG (x);
1797: if (GET_CODE (y) == SUBREG)
1798: y = alter_subreg (y);
1799:
1800: if (GET_CODE (y) == REG)
1801: {
1802: /* If the containing reg really gets a hard reg, so do we. */
1803: PUT_CODE (x, REG);
1804: REGNO (x) = REGNO (y) + SUBREG_WORD (x);
1805: }
1806: else if (GET_CODE (y) == MEM)
1807: {
1808: register int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
1809: #if BYTES_BIG_ENDIAN
1810: offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))
1811: - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y))));
1812: #endif
1813: PUT_CODE (x, MEM);
1814: MEM_VOLATILE_P (x) = MEM_VOLATILE_P (y);
1815: XEXP (x, 0) = plus_constant (XEXP (y, 0), offset);
1816: }
1817:
1818: return x;
1819: }
1820:
1821: /* Do alter_subreg on all the SUBREGs contained in X. */
1822:
1823: static rtx
1824: walk_alter_subreg (x)
1825: rtx x;
1826: {
1827: switch (GET_CODE (x))
1828: {
1829: case PLUS:
1830: case MULT:
1831: XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0));
1832: XEXP (x, 1) = walk_alter_subreg (XEXP (x, 1));
1833: break;
1834:
1835: case MEM:
1836: XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0));
1837: break;
1838:
1839: case SUBREG:
1840: return alter_subreg (x);
1841: }
1842:
1843: return x;
1844: }
1845:
1846: #ifdef HAVE_cc0
1847:
1848: /* Given BODY, the body of a jump instruction, alter the jump condition
1849: as required by the bits that are set in cc_status.flags.
1850: Not all of the bits there can be handled at this level in all cases.
1851:
1852: The value is normally 0.
1853: 1 means that the condition has become always true.
1854: -1 means that the condition has become always false.
1855: 2 means that COND has been altered. */
1856:
1857: static int
1858: alter_cond (cond)
1859: register rtx cond;
1860: {
1861: int value = 0;
1862:
1863: if (cc_status.flags & CC_REVERSED)
1864: {
1865: value = 2;
1866: PUT_CODE (cond, swap_condition (GET_CODE (cond)));
1867: }
1868:
1869: if (cc_status.flags & CC_INVERTED)
1870: {
1871: value = 2;
1872: PUT_CODE (cond, reverse_condition (GET_CODE (cond)));
1873: }
1874:
1875: if (cc_status.flags & CC_NOT_POSITIVE)
1876: switch (GET_CODE (cond))
1877: {
1878: case LE:
1879: case LEU:
1880: case GEU:
1881: /* Jump becomes unconditional. */
1882: return 1;
1883:
1884: case GT:
1885: case GTU:
1886: case LTU:
1887: /* Jump becomes no-op. */
1888: return -1;
1889:
1890: case GE:
1891: PUT_CODE (cond, EQ);
1892: value = 2;
1893: break;
1894:
1895: case LT:
1896: PUT_CODE (cond, NE);
1897: value = 2;
1898: break;
1899: }
1900:
1901: if (cc_status.flags & CC_NOT_NEGATIVE)
1902: switch (GET_CODE (cond))
1903: {
1904: case GE:
1905: case GEU:
1906: /* Jump becomes unconditional. */
1907: return 1;
1908:
1909: case LT:
1910: case LTU:
1911: /* Jump becomes no-op. */
1912: return -1;
1913:
1914: case LE:
1915: case LEU:
1916: PUT_CODE (cond, EQ);
1917: value = 2;
1918: break;
1919:
1920: case GT:
1921: case GTU:
1922: PUT_CODE (cond, NE);
1923: value = 2;
1924: break;
1925: }
1926:
1927: if (cc_status.flags & CC_NO_OVERFLOW)
1928: switch (GET_CODE (cond))
1929: {
1930: case GEU:
1931: /* Jump becomes unconditional. */
1932: return 1;
1933:
1934: case LEU:
1935: PUT_CODE (cond, EQ);
1936: value = 2;
1937: break;
1938:
1939: case GTU:
1940: PUT_CODE (cond, NE);
1941: value = 2;
1942: break;
1943:
1944: case LTU:
1945: /* Jump becomes no-op. */
1946: return -1;
1947: }
1948:
1949: if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
1950: switch (GET_CODE (cond))
1951: {
1952: case LE:
1953: case LEU:
1954: case GE:
1955: case GEU:
1956: case LT:
1957: case LTU:
1958: case GT:
1959: case GTU:
1960: abort ();
1961:
1962: case NE:
1963: PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
1964: value = 2;
1965: break;
1966:
1967: case EQ:
1968: PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE);
1969: value = 2;
1970: break;
1971: }
1.1.1.4 ! root 1972:
! 1973: if (cc_status.flags & CC_NOT_SIGNED)
! 1974: /* The flags are valid if signed condition operators are converted
! 1975: to unsigned. */
! 1976: switch (GET_CODE (cond))
! 1977: {
! 1978: case LE:
! 1979: PUT_CODE (cond, LEU);
! 1980: value = 2;
! 1981: break;
! 1982:
! 1983: case LT:
! 1984: PUT_CODE (cond, LTU);
! 1985: value = 2;
! 1986: break;
! 1987:
! 1988: case GT:
! 1989: PUT_CODE (cond, GTU);
! 1990: value = 2;
! 1991: break;
! 1992:
! 1993: case GE:
! 1994: PUT_CODE (cond, GEU);
! 1995: value = 2;
! 1996: break;
! 1997: }
! 1998:
1.1 root 1999: return value;
2000: }
2001: #endif
2002:
2003: /* Report inconsistency between the assembler template and the operands.
2004: In an `asm', it's the user's fault; otherwise, the compiler's fault. */
2005:
2006: void
2007: output_operand_lossage (str)
2008: char *str;
2009: {
2010: if (this_is_asm_operands)
2011: error_for_asm (this_is_asm_operands, "invalid `asm': %s", str);
2012: else
2013: abort ();
2014: }
2015:
2016: /* Output of assembler code from a template, and its subroutines. */
2017:
2018: /* Output text from TEMPLATE to the assembler output file,
2019: obeying %-directions to substitute operands taken from
2020: the vector OPERANDS.
2021:
2022: %N (for N a digit) means print operand N in usual manner.
2023: %lN means require operand N to be a CODE_LABEL or LABEL_REF
2024: and print the label name with no punctuation.
2025: %cN means require operand N to be a constant
2026: and print the constant expression with no punctuation.
2027: %aN means expect operand N to be a memory address
2028: (not a memory reference!) and print a reference
2029: to that address.
2030: %nN means expect operand N to be a constant
2031: and print a constant expression for minus the value
2032: of the operand, with no other punctuation. */
2033:
2034: void
2035: output_asm_insn (template, operands)
2036: char *template;
2037: rtx *operands;
2038: {
2039: register char *p;
2040: register int c;
2041:
2042: /* An insn may return a null string template
2043: in a case where no assembler code is needed. */
2044: if (*template == 0)
2045: return;
2046:
2047: p = template;
2048: putc ('\t', asm_out_file);
2049:
2050: #ifdef ASM_OUTPUT_OPCODE
2051: ASM_OUTPUT_OPCODE (asm_out_file, p);
2052: #endif
2053:
2054: while (c = *p++)
2055: {
2056: #ifdef ASM_OUTPUT_OPCODE
2057: if (c == '\n')
2058: {
2059: putc (c, asm_out_file);
2060: while ((c = *p) == '\t')
2061: {
2062: putc (c, asm_out_file);
2063: p++;
2064: }
2065: ASM_OUTPUT_OPCODE (asm_out_file, p);
2066: }
2067: else
2068: #endif
2069: if (c != '%')
2070: putc (c, asm_out_file);
2071: else
2072: {
2073: /* %% outputs a single %. */
2074: if (*p == '%')
2075: {
2076: p++;
2077: putc (c, asm_out_file);
2078: }
2079: /* %= outputs a number which is unique to each insn in the entire
2080: compilation. This is useful for making local labels that are
2081: referred to more than once in a given insn. */
2082: else if (*p == '=')
1.1.1.4 ! root 2083: {
! 2084: p++;
! 2085: fprintf (asm_out_file, "%d", insn_counter);
! 2086: }
1.1 root 2087: /* % followed by a letter and some digits
2088: outputs an operand in a special way depending on the letter.
2089: Letters `acln' are implemented directly.
2090: Other letters are passed to `output_operand' so that
2091: the PRINT_OPERAND macro can define them. */
2092: else if ((*p >= 'a' && *p <= 'z')
2093: || (*p >= 'A' && *p <= 'Z'))
2094: {
2095: int letter = *p++;
2096: c = atoi (p);
2097:
2098: if (! (*p >= '0' && *p <= '9'))
2099: output_operand_lossage ("operand number missing after %-letter");
2100: else if (this_is_asm_operands && c >= (unsigned) insn_noperands)
2101: output_operand_lossage ("operand number out of range");
2102: else if (letter == 'l')
2103: output_asm_label (operands[c]);
2104: else if (letter == 'a')
2105: output_address (operands[c]);
2106: else if (letter == 'c')
2107: {
2108: if (CONSTANT_ADDRESS_P (operands[c]))
2109: output_addr_const (asm_out_file, operands[c]);
2110: else
2111: output_operand (operands[c], 'c');
2112: }
2113: else if (letter == 'n')
2114: {
2115: if (GET_CODE (operands[c]) == CONST_INT)
1.1.1.4 ! root 2116: fprintf (asm_out_file,
! 2117: #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
! 2118: "%d",
! 2119: #else
! 2120: "%ld",
! 2121: #endif
! 2122: - INTVAL (operands[c]));
1.1 root 2123: else
2124: {
2125: putc ('-', asm_out_file);
2126: output_addr_const (asm_out_file, operands[c]);
2127: }
2128: }
2129: else
2130: output_operand (operands[c], letter);
2131:
2132: while ((c = *p) >= '0' && c <= '9') p++;
2133: }
2134: /* % followed by a digit outputs an operand the default way. */
2135: else if (*p >= '0' && *p <= '9')
2136: {
2137: c = atoi (p);
2138: if (this_is_asm_operands && c >= (unsigned) insn_noperands)
2139: output_operand_lossage ("operand number out of range");
2140: else
2141: output_operand (operands[c], 0);
2142: while ((c = *p) >= '0' && c <= '9') p++;
2143: }
2144: /* % followed by punctuation: output something for that
2145: punctuation character alone, with no operand.
2146: The PRINT_OPERAND macro decides what is actually done. */
2147: #ifdef PRINT_OPERAND_PUNCT_VALID_P
2148: else if (PRINT_OPERAND_PUNCT_VALID_P (*p))
1.1.1.4 ! root 2149: output_operand (NULL_RTX, *p++);
1.1 root 2150: #endif
2151: else
2152: output_operand_lossage ("invalid %%-code");
2153: }
2154: }
2155:
2156: if (flag_print_asm_name)
2157: {
2158: /* Annotate the assembly with a comment describing the pattern and
2159: alternative used. */
2160: if (debug_insn)
2161: {
2162: register int num = INSN_CODE (debug_insn);
2163: fprintf (asm_out_file, " %s %d %s",
2164: ASM_COMMENT_START, INSN_UID (debug_insn), insn_name[num]);
2165: if (insn_n_alternatives[num] > 1)
2166: fprintf (asm_out_file, "/%d", which_alternative + 1);
2167:
2168: /* Clear this so only the first assembler insn
2169: of any rtl insn will get the special comment for -dp. */
2170: debug_insn = 0;
2171: }
2172: }
2173:
2174: putc ('\n', asm_out_file);
2175: }
2176:
2177: /* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */
2178:
2179: void
2180: output_asm_label (x)
2181: rtx x;
2182: {
2183: char buf[256];
2184:
2185: if (GET_CODE (x) == LABEL_REF)
2186: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
2187: else if (GET_CODE (x) == CODE_LABEL)
2188: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
2189: else
2190: output_operand_lossage ("`%l' operand isn't a label");
2191:
2192: assemble_name (asm_out_file, buf);
2193: }
2194:
2195: /* Print operand X using machine-dependent assembler syntax.
2196: The macro PRINT_OPERAND is defined just to control this function.
2197: CODE is a non-digit that preceded the operand-number in the % spec,
2198: such as 'z' if the spec was `%z3'. CODE is 0 if there was no char
2199: between the % and the digits.
2200: When CODE is a non-letter, X is 0.
2201:
2202: The meanings of the letters are machine-dependent and controlled
2203: by PRINT_OPERAND. */
2204:
2205: static void
2206: output_operand (x, code)
2207: rtx x;
2208: int code;
2209: {
2210: if (x && GET_CODE (x) == SUBREG)
2211: x = alter_subreg (x);
1.1.1.4 ! root 2212:
! 2213: /* If X is a pseudo-register, abort now rather than writing trash to the
! 2214: assembler file. */
! 2215:
! 2216: if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
! 2217: abort ();
! 2218:
1.1 root 2219: PRINT_OPERAND (asm_out_file, x, code);
2220: }
2221:
2222: /* Print a memory reference operand for address X
2223: using machine-dependent assembler syntax.
2224: The macro PRINT_OPERAND_ADDRESS exists just to control this function. */
2225:
2226: void
2227: output_address (x)
2228: rtx x;
2229: {
2230: walk_alter_subreg (x);
2231: PRINT_OPERAND_ADDRESS (asm_out_file, x);
2232: }
2233:
2234: /* Print an integer constant expression in assembler syntax.
2235: Addition and subtraction are the only arithmetic
2236: that may appear in these expressions. */
2237:
2238: void
2239: output_addr_const (file, x)
2240: FILE *file;
2241: rtx x;
2242: {
2243: char buf[256];
2244:
2245: restart:
2246: switch (GET_CODE (x))
2247: {
2248: case PC:
2249: if (flag_pic)
2250: putc ('.', file);
2251: else
2252: abort ();
2253: break;
2254:
2255: case SYMBOL_REF:
2256: assemble_name (file, XSTR (x, 0));
2257: break;
2258:
2259: case LABEL_REF:
2260: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
1.1.1.4 ! root 2261: assemble_name (file, buf);
1.1 root 2262: break;
2263:
2264: case CODE_LABEL:
2265: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
1.1.1.4 ! root 2266: assemble_name (file, buf);
1.1 root 2267: break;
2268:
2269: case CONST_INT:
1.1.1.4 ! root 2270: fprintf (file,
! 2271: #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
! 2272: "%d",
! 2273: #else
! 2274: "%ld",
! 2275: #endif
! 2276: INTVAL (x));
1.1 root 2277: break;
2278:
2279: case CONST:
2280: /* This used to output parentheses around the expression,
2281: but that does not work on the 386 (either ATT or BSD assembler). */
2282: output_addr_const (file, XEXP (x, 0));
2283: break;
2284:
2285: case CONST_DOUBLE:
2286: if (GET_MODE (x) == VOIDmode)
2287: {
1.1.1.4 ! root 2288: /* We can use %d if the number is one word and positive. */
1.1 root 2289: if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
1.1.1.4 ! root 2290: fprintf (file,
! 2291: #if HOST_BITS_PER_WIDE_INT == 64
! 2292: #if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
! 2293: " 0x%lx%016lx",
! 2294: #else
! 2295: " 0x%x%016x",
! 2296: #endif
! 2297: #else
! 2298: #if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
! 2299: " 0x%lx%08lx",
! 2300: #else
! 2301: " 0x%x%08x",
! 2302: #endif
! 2303: #endif
1.1 root 2304: CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
2305: else
1.1.1.4 ! root 2306: fprintf (file,
! 2307: #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
! 2308: "%d",
! 2309: #else
! 2310: "%ld",
! 2311: #endif
! 2312: CONST_DOUBLE_LOW (x));
1.1 root 2313: }
2314: else
2315: /* We can't handle floating point constants;
2316: PRINT_OPERAND must handle them. */
2317: output_operand_lossage ("floating constant misused");
2318: break;
2319:
2320: case PLUS:
2321: /* Some assemblers need integer constants to appear last (eg masm). */
2322: if (GET_CODE (XEXP (x, 0)) == CONST_INT)
2323: {
2324: output_addr_const (file, XEXP (x, 1));
2325: if (INTVAL (XEXP (x, 0)) >= 0)
2326: fprintf (file, "+");
2327: output_addr_const (file, XEXP (x, 0));
2328: }
2329: else
2330: {
2331: output_addr_const (file, XEXP (x, 0));
2332: if (INTVAL (XEXP (x, 1)) >= 0)
2333: fprintf (file, "+");
2334: output_addr_const (file, XEXP (x, 1));
2335: }
2336: break;
2337:
2338: case MINUS:
1.1.1.4 ! root 2339: /* Avoid outputting things like x-x or x+5-x,
! 2340: since some assemblers can't handle that. */
! 2341: x = simplify_subtraction (x);
! 2342: if (GET_CODE (x) != MINUS)
! 2343: goto restart;
! 2344:
1.1 root 2345: output_addr_const (file, XEXP (x, 0));
2346: fprintf (file, "-");
1.1.1.4 ! root 2347: if (GET_CODE (XEXP (x, 1)) == CONST_INT
! 2348: && INTVAL (XEXP (x, 1)) < 0)
! 2349: {
! 2350: fprintf (file, ASM_OPEN_PAREN);
! 2351: output_addr_const (file, XEXP (x, 1));
! 2352: fprintf (file, ASM_CLOSE_PAREN);
! 2353: }
! 2354: else
! 2355: output_addr_const (file, XEXP (x, 1));
! 2356: break;
! 2357:
! 2358: case ZERO_EXTEND:
! 2359: case SIGN_EXTEND:
! 2360: output_addr_const (file, XEXP (x, 0));
1.1 root 2361: break;
2362:
2363: default:
2364: output_operand_lossage ("invalid expression as operand");
2365: }
2366: }
2367:
2368: /* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
2369: %R prints the value of REGISTER_PREFIX.
2370: %L prints the value of LOCAL_LABEL_PREFIX.
2371: %U prints the value of USER_LABEL_PREFIX.
2372: %I prints the value of IMMEDIATE_PREFIX.
1.1.1.2 root 2373: %O runs ASM_OUTPUT_OPCODE to transform what follows in the string.
1.1 root 2374: Also supported are %d, %x, %s, %e, %f, %g and %%. */
2375:
2376: void
2377: asm_fprintf (va_alist)
2378: va_dcl
2379: {
2380: va_list argptr;
2381: FILE *file;
2382: char buf[10];
2383: char *p, *q, c;
2384:
2385: va_start (argptr);
2386:
2387: file = va_arg (argptr, FILE *);
2388: p = va_arg (argptr, char *);
2389: buf[0] = '%';
2390:
2391: while (c = *p++)
2392: switch (c)
2393: {
2394: case '%':
2395: c = *p++;
2396: q = &buf[1];
2397: while ((c >= '0' && c <= '9') || c == '.')
2398: {
2399: *q++ = c;
2400: c = *p++;
2401: }
2402: switch (c)
2403: {
2404: case '%':
2405: fprintf (file, "%%");
2406: break;
2407:
2408: case 'd': case 'i': case 'u':
2409: case 'x': case 'p': case 'X':
2410: case 'o':
2411: *q++ = c;
2412: *q = 0;
2413: fprintf (file, buf, va_arg (argptr, int));
2414: break;
2415:
2416: case 'e':
2417: case 'f':
2418: case 'g':
2419: *q++ = c;
2420: *q = 0;
2421: fprintf (file, buf, va_arg (argptr, double));
2422: break;
2423:
2424: case 's':
2425: *q++ = c;
2426: *q = 0;
2427: fprintf (file, buf, va_arg (argptr, char *));
2428: break;
2429:
1.1.1.2 root 2430: case 'O':
2431: #ifdef ASM_OUTPUT_OPCODE
2432: ASM_OUTPUT_OPCODE (asm_out_file, p);
2433: #endif
2434: break;
2435:
1.1 root 2436: case 'R':
2437: #ifdef REGISTER_PREFIX
2438: fprintf (file, "%s", REGISTER_PREFIX);
2439: #endif
2440: break;
2441:
2442: case 'I':
2443: #ifdef IMMEDIATE_PREFIX
2444: fprintf (file, "%s", IMMEDIATE_PREFIX);
2445: #endif
2446: break;
2447:
2448: case 'L':
2449: #ifdef LOCAL_LABEL_PREFIX
2450: fprintf (file, "%s", LOCAL_LABEL_PREFIX);
2451: #endif
2452: break;
2453:
2454: case 'U':
2455: #ifdef USER_LABEL_PREFIX
2456: fprintf (file, "%s", USER_LABEL_PREFIX);
2457: #endif
2458: break;
2459:
2460: default:
2461: abort ();
2462: }
2463: break;
2464:
2465: default:
2466: fputc (c, file);
2467: }
2468: }
2469:
2470: /* Split up a CONST_DOUBLE or integer constant rtx
2471: into two rtx's for single words,
2472: storing in *FIRST the word that comes first in memory in the target
2473: and in *SECOND the other. */
2474:
2475: void
2476: split_double (value, first, second)
2477: rtx value;
2478: rtx *first, *second;
2479: {
2480: if (GET_CODE (value) == CONST_INT)
2481: {
2482: /* The rule for using CONST_INT for a wider mode
2483: is that we regard the value as signed.
2484: So sign-extend it. */
2485: rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx);
2486: #if WORDS_BIG_ENDIAN
2487: *first = high;
2488: *second = value;
2489: #else
2490: *first = value;
2491: *second = high;
2492: #endif
2493: }
2494: else if (GET_CODE (value) != CONST_DOUBLE)
2495: {
2496: #if WORDS_BIG_ENDIAN
2497: *first = const0_rtx;
2498: *second = value;
2499: #else
2500: *first = value;
2501: *second = const0_rtx;
2502: #endif
2503: }
2504: else if (GET_MODE (value) == VOIDmode
2505: /* This is the old way we did CONST_DOUBLE integers. */
2506: || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT)
2507: {
2508: /* In an integer, the words are defined as most and least significant.
2509: So order them by the target's convention. */
2510: #if WORDS_BIG_ENDIAN
1.1.1.4 ! root 2511: *first = GEN_INT (CONST_DOUBLE_HIGH (value));
! 2512: *second = GEN_INT (CONST_DOUBLE_LOW (value));
1.1 root 2513: #else
1.1.1.4 ! root 2514: *first = GEN_INT (CONST_DOUBLE_LOW (value));
! 2515: *second = GEN_INT (CONST_DOUBLE_HIGH (value));
1.1 root 2516: #endif
2517: }
2518: else
2519: {
2520: if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
1.1.1.4 ! root 2521: || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
1.1 root 2522: && ! flag_pretend_float)
2523: abort ();
2524:
2525: #if defined (HOST_WORDS_BIG_ENDIAN) == WORDS_BIG_ENDIAN
2526: /* Host and target agree => no need to swap. */
1.1.1.4 ! root 2527: *first = GEN_INT (CONST_DOUBLE_LOW (value));
! 2528: *second = GEN_INT (CONST_DOUBLE_HIGH (value));
1.1 root 2529: #else
1.1.1.4 ! root 2530: *second = GEN_INT (CONST_DOUBLE_LOW (value));
! 2531: *first = GEN_INT (CONST_DOUBLE_HIGH (value));
1.1 root 2532: #endif
2533: }
2534: }
2535:
2536: /* Return nonzero if this function has no function calls. */
2537:
2538: int
2539: leaf_function_p ()
2540: {
2541: rtx insn;
2542:
2543: if (profile_flag || profile_block_flag)
2544: return 0;
2545:
2546: for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
2547: {
2548: if (GET_CODE (insn) == CALL_INSN)
2549: return 0;
2550: if (GET_CODE (insn) == INSN
2551: && GET_CODE (PATTERN (insn)) == SEQUENCE
2552: && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN)
2553: return 0;
2554: }
2555: for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1))
2556: {
2557: if (GET_CODE (XEXP (insn, 0)) == CALL_INSN)
2558: return 0;
2559: if (GET_CODE (XEXP (insn, 0)) == INSN
2560: && GET_CODE (PATTERN (XEXP (insn, 0))) == SEQUENCE
2561: && GET_CODE (XVECEXP (PATTERN (XEXP (insn, 0)), 0, 0)) == CALL_INSN)
2562: return 0;
2563: }
2564:
2565: return 1;
2566: }
2567:
2568: /* On some machines, a function with no call insns
2569: can run faster if it doesn't create its own register window.
2570: When output, the leaf function should use only the "output"
2571: registers. Ordinarily, the function would be compiled to use
2572: the "input" registers to find its arguments; it is a candidate
2573: for leaf treatment if it uses only the "input" registers.
2574: Leaf function treatment means renumbering so the function
2575: uses the "output" registers instead. */
2576:
2577: #ifdef LEAF_REGISTERS
2578:
2579: static char permitted_reg_in_leaf_functions[] = LEAF_REGISTERS;
2580:
2581: /* Return 1 if this function uses only the registers that can be
2582: safely renumbered. */
2583:
2584: int
2585: only_leaf_regs_used ()
2586: {
2587: int i;
2588:
2589: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2590: {
1.1.1.4 ! root 2591: if ((regs_ever_live[i] || global_regs[i])
! 2592: && ! permitted_reg_in_leaf_functions[i])
1.1 root 2593: return 0;
2594: }
2595: return 1;
2596: }
2597:
2598: /* Scan all instructions and renumber all registers into those
2599: available in leaf functions. */
2600:
2601: static void
2602: leaf_renumber_regs (first)
2603: rtx first;
2604: {
2605: rtx insn;
2606:
2607: /* Renumber only the actual patterns.
2608: The reg-notes can contain frame pointer refs,
2609: and renumbering them could crash, and should not be needed. */
2610: for (insn = first; insn; insn = NEXT_INSN (insn))
2611: if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
2612: leaf_renumber_regs_insn (PATTERN (insn));
2613: for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1))
2614: if (GET_RTX_CLASS (GET_CODE (XEXP (insn, 0))) == 'i')
2615: leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0)));
2616: }
2617:
2618: /* Scan IN_RTX and its subexpressions, and renumber all regs into those
2619: available in leaf functions. */
2620:
2621: void
2622: leaf_renumber_regs_insn (in_rtx)
2623: register rtx in_rtx;
2624: {
2625: register int i, j;
2626: register char *format_ptr;
2627:
2628: if (in_rtx == 0)
2629: return;
2630:
2631: /* Renumber all input-registers into output-registers.
2632: renumbered_regs would be 1 for an output-register;
2633: they */
2634:
2635: if (GET_CODE (in_rtx) == REG)
2636: {
2637: int newreg;
2638:
2639: /* Don't renumber the same reg twice. */
2640: if (in_rtx->used)
2641: return;
2642:
2643: newreg = REGNO (in_rtx);
1.1.1.2 root 2644: /* Don't try to renumber pseudo regs. It is possible for a pseudo reg
1.1 root 2645: to reach here as part of a REG_NOTE. */
2646: if (newreg >= FIRST_PSEUDO_REGISTER)
2647: {
2648: in_rtx->used = 1;
2649: return;
2650: }
2651: newreg = LEAF_REG_REMAP (newreg);
2652: if (newreg < 0)
2653: abort ();
2654: regs_ever_live[REGNO (in_rtx)] = 0;
2655: regs_ever_live[newreg] = 1;
2656: REGNO (in_rtx) = newreg;
2657: in_rtx->used = 1;
2658: }
2659:
2660: if (GET_RTX_CLASS (GET_CODE (in_rtx)) == 'i')
2661: {
2662: /* Inside a SEQUENCE, we find insns.
2663: Renumber just the patterns of these insns,
2664: just as we do for the top-level insns. */
2665: leaf_renumber_regs_insn (PATTERN (in_rtx));
2666: return;
2667: }
2668:
2669: format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
2670:
2671: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
2672: switch (*format_ptr++)
2673: {
2674: case 'e':
2675: leaf_renumber_regs_insn (XEXP (in_rtx, i));
2676: break;
2677:
2678: case 'E':
2679: if (NULL != XVEC (in_rtx, i))
2680: {
2681: for (j = 0; j < XVECLEN (in_rtx, i); j++)
2682: leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j));
2683: }
2684: break;
2685:
2686: case 'S':
2687: case 's':
2688: case '0':
2689: case 'i':
1.1.1.4 ! root 2690: case 'w':
1.1 root 2691: case 'n':
2692: case 'u':
2693: break;
2694:
2695: default:
2696: abort ();
2697: }
2698: }
2699: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.