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