|
|
1.1 root 1: /* Procedure integration for GNU CC.
2: Copyright (C) 1988 Free Software Foundation, Inc.
3: Contributed by Michael Tiemann ([email protected])
4:
5: This file is part of GNU CC.
6:
1.1.1.12! root 7: GNU CC is free software; you can redistribute it and/or modify
! 8: it under the terms of the GNU General Public License as published by
! 9: the Free Software Foundation; either version 1, or (at your option)
! 10: any later version.
! 11:
1.1 root 12: GNU CC is distributed in the hope that it will be useful,
1.1.1.12! root 13: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 15: GNU General Public License for more details.
! 16:
! 17: You should have received a copy of the GNU General Public License
! 18: along with GNU CC; see the file COPYING. If not, write to
! 19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
1.1 root 20:
21:
22: #include <stdio.h>
23:
24: #include "config.h"
25: #include "rtl.h"
26: #include "tree.h"
27: #include "flags.h"
28: #include "insn-flags.h"
29: #include "expr.h"
30:
31: #include "obstack.h"
32: #define obstack_chunk_alloc xmalloc
33: #define obstack_chunk_free free
34: extern int xmalloc ();
35: extern void free ();
36:
37: extern struct obstack permanent_obstack, maybepermanent_obstack;
38: extern struct obstack *rtl_obstack, *saveable_obstack, *current_obstack;
39:
40: #define MIN(x,y) ((x < y) ? x : y)
41:
42: extern tree pushdecl ();
1.1.1.5 root 43:
44: /* Default max number of insns a function can have and still be inline.
45: This is overridden on RISC machines. */
46: #ifndef INTEGRATE_THRESHOLD
47: #define INTEGRATE_THRESHOLD(DECL) \
48: (8 * (8 + list_length (DECL_ARGUMENTS (DECL)) + 16*TREE_INLINE (DECL)))
49: #endif
1.1 root 50:
51: /* This is the target of the inline function being expanded,
52: or NULL if there is none. */
53: static rtx inline_target;
54:
55: /* We must take special care not to disrupt life too severely
56: when performing procedure integration. One thing that that
57: involves is not creating illegitimate address which reload
58: cannot fix. Since we don't know what the frame pointer is
59: not capable of (in a machine independent way), we create
60: a pseudo-frame pointer which will have to do for now. */
61: static rtx inline_fp_rtx;
62:
63: /* Convert old frame-pointer offsets to new. Parameters which only
64: produce values (no addresses, and are never assigned), map directly
65: to the pseudo-reg of the incoming value. Parameters that are
66: assigned to but do not have their address taken are given a fresh
67: pseudo-register. Parameters that have their address take are
68: given a fresh stack-slot. */
69: static rtx *parm_map;
70:
71: /* ?? Should this be done here?? It is not right now.
72: Keep track of whether a given pseudo-register is the sum
73: of the frame pointer and a const_int (or zero). */
74: static char *fp_addr_p;
75:
76: /* For the local variables of the procdure being integrated that live
77: on the frame, FRAME_POINTER_DELTA says how much to change their
78: offsets by, so that they now live in the correct place on the
79: frame of the function being compiled. */
80: static int fp_delta;
81:
1.1.1.11 root 82: /* When an insn is being copied by copy_rtx_and_substitute,
83: this is nonzero if we have copied an ASM_OPERANDS.
84: In that case, it is the original input-operand vector.
85: Likewise in copy_for_inline. */
86: static rtvec orig_asm_operands_vector;
87:
88: /* When an insn is being copied by copy_rtx_and_substitute,
89: this is nonzero if we have copied an ASM_OPERANDS.
90: In that case, it is the copied input-operand vector.
91: Likewise in copy_for_inline. */
92: static rtvec copy_asm_operands_vector;
93:
1.1 root 94: /* Return a copy of an rtx (as needed), substituting pseudo-register,
95: labels, and frame-pointer offsets as necessary. */
96: static rtx copy_rtx_and_substitute ();
1.1.1.7 root 97: /* Variant, used for memory addresses that are not memory_address_p. */
98: static rtx copy_address ();
1.1 root 99:
100: static void copy_parm_decls ();
101: static void copy_decl_tree ();
102:
103: static rtx try_fold_cc0 ();
104:
105: /* We do some simple constant folding optimization. This optimization
106: really exists primarily to save time inlining a function. It
1.1.1.5 root 107: also helps users who ask for inline functions without -O. */
1.1 root 108: static rtx fold_out_const_cc0 ();
109:
110: /* Zero if the current function (whose FUNCTION_DECL is FNDECL)
111: is safe and reasonable to integrate into other functions.
112: Nonzero means value is a warning message with a single %s
113: for the function's name. */
114:
115: char *
116: function_cannot_inline_p (fndecl)
117: register tree fndecl;
118: {
119: register rtx insn;
120: tree last = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
1.1.1.5 root 121: int max_insns = INTEGRATE_THRESHOLD (fndecl);
1.1 root 122: register int ninsns = 0;
123: register tree parms;
124:
125: /* No inlines with varargs. `grokdeclarator' gives a warning
126: message about that if `inline' is specified. This code
127: it put in to catch the volunteers. */
128: if (last && TREE_VALUE (last) != void_type_node)
1.1.1.7 root 129: return "varargs function cannot be inline";
1.1 root 130:
131: /* If its not even close, don't even look. */
132: if (get_max_uid () > 2 * max_insns)
1.1.1.7 root 133: return "function too large to be inline";
1.1 root 134:
1.1.1.11 root 135: /* If the structure value address comes in the stack,
136: we can't handle it. */
137: #if defined (STRUCT_VALUE) || defined (STRUCT_VALUE_INCOMING)
138: if (TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode)
139: return "function returning large aggregate cannot be inline";
140: #endif
141:
1.1 root 142: /* Don't inline functions which have BLKmode arguments.
143: Don't inline functions that take the address of
144: a parameter and do not specify a function prototype. */
145: for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
146: {
147: if (TYPE_MODE (TREE_TYPE (parms)) == BLKmode)
1.1.1.7 root 148: return "function with large aggregate parameter cannot be inline";
1.1 root 149: if (last == NULL_TREE && TREE_ADDRESSABLE (parms))
1.1.1.7 root 150: return "no prototype, and parameter address used; cannot be inline";
1.1.1.11 root 151: /* If an aggregate is thought of as "in memory"
152: then its components are referred to by narrower memory refs.
153: If the actual parameter is a reg, these refs can't be translated,
154: esp. since copy_rtx_and_substitute doesn't know whether it is
155: reading or writing. */
156: if ((TREE_CODE (TREE_TYPE (parms)) == RECORD_TYPE
157: || TREE_CODE (TREE_TYPE (parms)) == UNION_TYPE)
158: && GET_CODE (DECL_RTL (parms)) == MEM)
159: return "address of an aggregate parameter is used; cannot be inline";
1.1 root 160: }
161:
162: if (get_max_uid () > max_insns)
163: {
164: for (ninsns = 0, insn = get_first_nonparm_insn (); insn && ninsns < max_insns;
165: insn = NEXT_INSN (insn))
166: {
167: if (GET_CODE (insn) == INSN
168: || GET_CODE (insn) == JUMP_INSN
169: || GET_CODE (insn) == CALL_INSN)
170: ninsns++;
171: }
172:
173: if (ninsns >= max_insns)
1.1.1.7 root 174: return "function too large to be inline";
1.1 root 175: }
176:
177: return 0;
178: }
179:
180: /* Variables used within save_for_inline. */
181:
182: /* Mapping from old pesudo-register to new pseudo-registers.
183: The first element of this map is reg_map[FIRST_PSEUDO_REGISTER].
1.1.1.6 root 184: It is allocated in `save_for_inline' and `expand_inline_function',
1.1 root 185: and deallocated on exit from each of those routines. */
186: static rtx *reg_map;
187:
188: /* Mapping from old code-labels to new code-labels.
189: The first element of this map is label_map[min_labelno].
1.1.1.6 root 190: It is allocated in `save_for_inline' and `expand_inline_function',
1.1 root 191: and deallocated on exit from each of those routines. */
192: static rtx *label_map;
193:
1.1.1.6 root 194: /* Mapping from old insn uid's to copied insns.
195: It is allocated in `save_for_inline' and `expand_inline_function',
196: and deallocated on exit from each of those routines. */
197: static rtx *insn_map;
198:
1.1 root 199: /* Map pseudo reg number into the PARM_DECL for the parm living in the reg.
200: Zero for a reg that isn't a parm's home.
201: Only reg numbers less than max_parm_reg are mapped here. */
202: static tree *parmdecl_map;
203:
204: /* Keep track of first pseudo-register beyond those that are parms. */
205: static int max_parm_reg;
206:
1.1.1.7 root 207: /* Offset from arg ptr to the first parm of this inline function. */
208: static int first_parm_offset;
209:
1.1 root 210: /* On machines that perform a function return with a single
211: instruction, such as the VAX, these return insns must be
212: mapped into branch statements. */
213: extern rtx return_label;
214:
215: /* Copy an rtx for save_for_inline. */
216: static rtx copy_for_inline ();
217:
218: /* Make the insns and PARM_DECLs of the current function permanent
219: and record other information in DECL_SAVED_INSNS to allow inlining
220: of this function in subsequent calls. */
221:
222: void
223: save_for_inline (fndecl)
224: tree fndecl;
225: {
226: extern rtx *regno_reg_rtx; /* in emit-rtl.c. */
227: extern current_function_args_size;
228:
229: rtx first_insn, last_insn, insn;
230: rtx head, copy;
231: tree parms;
232: int max_labelno, min_labelno, i, len;
233: int max_reg;
1.1.1.6 root 234: int max_uid;
1.1 root 235:
236: /* Make and emit a return-label if we have not already done so. */
237:
238: if (return_label == 0)
239: {
240: return_label = gen_label_rtx ();
241: emit_label (return_label);
242: }
243:
244: /* Get some bounds on the labels and registers used. */
245:
246: max_labelno = max_label_num ();
247: min_labelno = get_first_label_num ();
248: max_parm_reg = max_parm_reg_num ();
249: max_reg = max_reg_num ();
250:
251: /* Set up PARMDECL_MAP which maps pseudo-reg number to its PARM_DECL.
252:
253: Set TREE_VOLATILE to 0 if the parm is in a register, otherwise 1.
254: Later we set TREE_READONLY to 0 if the parm is modified inside the fn. */
255:
256: parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree));
1.1.1.3 root 257: bzero (parmdecl_map, max_parm_reg * sizeof (tree));
1.1 root 258:
259: for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
260: {
261: rtx p = DECL_RTL (parms);
262:
263: if (GET_CODE (p) == REG)
264: {
265: parmdecl_map[REGNO (p)] = parms;
266: TREE_VOLATILE (parms) = 0;
267: }
268: else
269: TREE_VOLATILE (parms) = 1;
270: TREE_READONLY (parms) = 1;
271: }
272:
273: /* The list of DECL_SAVES_INSNS, starts off with a header which
274: contains the following information:
275:
276: the first insn of the function (not including the insns that copy
277: parameters into registers).
278: the first label used by that function,
279: the last label used by that function,
280: and the total number of registers used. */
281:
282: head = gen_inline_header_rtx (NULL, NULL, min_labelno, max_labelno,
283: max_parm_reg, max_reg,
284: current_function_args_size);
1.1.1.6 root 285: max_uid = INSN_UID (head);
1.1 root 286:
287: /* We have now allocated all that needs to be allocated permanently
288: on the rtx obstack. Set our high-water mark, so that we
289: can free the rest of this when the time comes. */
290:
291: preserve_data ();
292:
293: /* Copy the chain insns of this function.
294: Install the copied chain as the insns of this function,
295: for continued compilation;
296: the original chain is recorded as the DECL_SAVED_INSNS
297: for inlining future calls. */
298:
299: /* If there are insns that copy parms from the stack into pseudo registers,
300: those insns are not copied. `expand_inline_function' must
301: emit the correct code to handle such things. */
302:
303: insn = get_insns ();
304: if (GET_CODE (insn) != NOTE)
305: abort ();
306: first_insn = rtx_alloc (NOTE);
307: NOTE_SOURCE_FILE (first_insn) = NOTE_SOURCE_FILE (insn);
308: NOTE_LINE_NUMBER (first_insn) = NOTE_LINE_NUMBER (insn);
309: INSN_UID (first_insn) = INSN_UID (insn);
310: PREV_INSN (first_insn) = NULL;
311: NEXT_INSN (first_insn) = NULL;
312: last_insn = first_insn;
313:
314: /* Each pseudo-reg in the old insn chain must have a unique rtx in the copy.
315: Make these new rtx's now, and install them in regno_reg_rtx, so they
316: will be the official pseudo-reg rtx's for the rest of compilation. */
317:
318: reg_map = (rtx *) alloca ((max_reg + 1) * sizeof (rtx));
319:
320: len = sizeof (struct rtx_def) + (GET_RTX_LENGTH (REG) - 1) * sizeof (rtunion);
321: for (i = max_reg - 1; i >= FIRST_PSEUDO_REGISTER; i--)
322: reg_map[i] = (rtx)obstack_copy (&maybepermanent_obstack, regno_reg_rtx[i], len);
323: bcopy (reg_map + FIRST_PSEUDO_REGISTER,
324: regno_reg_rtx + FIRST_PSEUDO_REGISTER,
1.1.1.7 root 325: (max_reg - FIRST_PSEUDO_REGISTER) * sizeof (rtx));
1.1 root 326:
327: /* Likewise each label rtx must have a unique rtx as its copy. */
328:
329: label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));
330: label_map -= min_labelno;
331:
332: for (i = min_labelno; i < max_labelno; i++)
333: label_map[i] = gen_label_rtx ();
334:
1.1.1.6 root 335: /* Record the mapping of old insns to copied insns. */
336:
337: insn_map = (rtx *) alloca (max_uid * sizeof (rtx));
338: bzero (insn_map, max_uid * sizeof (rtx));
339:
1.1 root 340: /* Now copy the chain of insns. */
341:
342: for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
343: {
1.1.1.11 root 344: orig_asm_operands_vector = 0;
345: copy_asm_operands_vector = 0;
346:
1.1 root 347: switch (GET_CODE (insn))
348: {
349: case NOTE:
1.1.1.7 root 350: if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END)
351: continue;
352:
1.1 root 353: copy = rtx_alloc (NOTE);
354: NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);
355: NOTE_LINE_NUMBER (copy) = NOTE_LINE_NUMBER (insn);
356: break;
357:
358: case INSN:
359: case CALL_INSN:
360: case JUMP_INSN:
361: copy = rtx_alloc (GET_CODE (insn));
362: PATTERN (copy) = copy_for_inline (PATTERN (insn));
363: INSN_CODE (copy) = -1;
364: LOG_LINKS (copy) = NULL;
365: REG_NOTES (copy) = copy_for_inline (REG_NOTES (insn));
366: break;
367:
368: case CODE_LABEL:
369: copy = label_map[CODE_LABEL_NUMBER (insn)];
370: break;
371:
372: case BARRIER:
373: copy = rtx_alloc (BARRIER);
374: break;
375:
376: default:
377: abort ();
378: }
379: INSN_UID (copy) = INSN_UID (insn);
1.1.1.6 root 380: insn_map[INSN_UID (insn)] = copy;
1.1 root 381: NEXT_INSN (last_insn) = copy;
382: PREV_INSN (copy) = last_insn;
383: last_insn = copy;
384: }
385:
386: NEXT_INSN (last_insn) = NULL;
387:
388: NEXT_INSN (head) = get_first_nonparm_insn ();
389: FIRST_PARM_INSN (head) = get_insns ();
390: DECL_SAVED_INSNS (fndecl) = head;
391: DECL_FRAME_SIZE (fndecl) = get_frame_size ();
392: TREE_INLINE (fndecl) = 1;
393:
394: parmdecl_map = 0;
395: label_map = 0;
396: reg_map = 0;
397: return_label = 0;
398:
399: set_new_first_and_last_insn (first_insn, last_insn);
400: }
401:
402: /* Copy the rtx ORIG recursively, replacing pseudo-regs and labels
403: according to `reg_map' and `label_map'.
404: All other kinds of rtx are copied except those that can never be
405: changed during compilation. */
406:
407: static rtx
408: copy_for_inline (orig)
409: rtx orig;
410: {
411: register rtx x = orig;
412: register int i;
413: register enum rtx_code code;
414: register char *format_ptr;
415:
416: if (x == 0)
417: return x;
418:
419: code = GET_CODE (x);
420:
421: /* These types may be freely shared. */
422:
423: switch (code)
424: {
425: case QUEUED:
426: case CONST_INT:
427: case CONST_DOUBLE:
428: case SYMBOL_REF:
429: case PC:
430: case CC0:
431: return x;
432:
1.1.1.11 root 433: case ASM_OPERANDS:
434: /* If a single asm insn contains multiple output operands
435: then it contains multiple ASM_OPERANDS rtx's that share operand 3.
436: We must make sure that the copied insn continues to share it. */
437: if (orig_asm_operands_vector == XVEC (orig, 3))
438: {
439: x = rtx_alloc (ASM_OPERANDS);
440: XSTR (x, 0) = XSTR (orig, 0);
441: XSTR (x, 1) = XSTR (orig, 1);
442: XINT (x, 2) = XINT (orig, 2);
443: XVEC (x, 3) = copy_asm_operands_vector;
444: XVEC (x, 4) = XVEC (orig, 4);
445: return x;
446: }
447: break;
448:
1.1 root 449: case MEM:
450: /* A MEM is allowed to be shared if its address is constant
451: or is a constant plus one of the special registers. */
452: if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
453: return x;
454: if (GET_CODE (XEXP (x, 0)) == PLUS
455: && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
456: && (REGNO (XEXP (XEXP (x, 0), 0)) == FRAME_POINTER_REGNUM
457: || REGNO (XEXP (XEXP (x, 0), 0)) == ARG_POINTER_REGNUM)
458: && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1)))
459: if (GET_CODE (XEXP (x, 0)) == REG
460: && (REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
461: || REGNO (XEXP (x, 0)) == ARG_POINTER_REGNUM)
462: && CONSTANT_ADDRESS_P (XEXP (x, 1)))
463: return x;
464: break;
465:
466: case LABEL_REF:
467: {
468: /* Must point to the new insn. */
469: return gen_rtx (LABEL_REF, GET_MODE (orig),
470: label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]);
471: }
472:
473: case REG:
474: if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
475: return reg_map [REGNO (x)];
476: else
477: return x;
478:
479: /* If a parm that gets modified lives in a pseudo-reg,
480: set its TREE_VOLATILE to prevent certain optimizations. */
481: case SET:
482: {
483: rtx dest = SET_DEST (x);
484:
485: if (GET_CODE (dest) == REG
486: && REGNO (dest) < max_parm_reg
1.1.1.3 root 487: && REGNO (dest) >= FIRST_PSEUDO_REGISTER
488: && parmdecl_map[REGNO (dest)] != 0)
1.1 root 489: TREE_READONLY (parmdecl_map[REGNO (dest)]) = 0;
490: }
491: break;
492: }
493:
494: /* Replace this rtx with a copy of itself. */
495:
496: x = rtx_alloc (code);
497: bcopy (orig, x, sizeof (int) * (GET_RTX_LENGTH (code) + 1));
498:
499: /* Now scan the subexpressions recursively.
500: We can store any replaced subexpressions directly into X
501: since we know X is not shared! Any vectors in X
502: must be copied if X was copied. */
503:
504: format_ptr = GET_RTX_FORMAT (code);
505:
506: for (i = 0; i < GET_RTX_LENGTH (code); i++)
507: {
508: switch (*format_ptr++)
509: {
510: case 'e':
511: XEXP (x, i) = copy_for_inline (XEXP (x, i));
512: break;
513:
1.1.1.6 root 514: case 'u':
515: /* Change any references to old-insns to point to the
516: corresponding copied insns. */
517: return insn_map[INSN_UID (XEXP (x, i))];
518:
1.1 root 519: case 'E':
1.1.1.6 root 520: if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0)
1.1 root 521: {
522: register int j;
523:
524: XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0));
525: for (j = 0; j < XVECLEN (x, i); j++)
526: XVECEXP (x, i, j)
527: = copy_for_inline (XVECEXP (x, i, j));
528: }
529: break;
530: }
531: }
1.1.1.11 root 532:
533: if (code == ASM_OPERANDS && orig_asm_operands_vector == 0)
534: {
535: orig_asm_operands_vector = XVEC (orig, 3);
536: copy_asm_operands_vector = XVEC (x, 3);
537: }
538:
1.1 root 539: return x;
540: }
541:
542: /* Integrate the procedure defined by FNDECL. Note that this function
543: may wind up calling itself. Since the static variables are not
544: reentrant, we do not assign them until after the possibility
545: or recursion is eliminated.
546:
547: If IGNORE is nonzero, do not produce a value.
548: Otherwise store the value in TARGET if it is nonzero and that is convenient.
549:
550: Value is:
551: (rtx)-1 if we could not substitute the function
552: 0 if we substituted it and it does not produce a value
553: else an rtx for where the value is stored. */
554:
555: rtx
556: expand_inline_function (fndecl, parms, target, ignore, type, structure_value_addr)
557: tree fndecl, parms;
558: rtx target;
559: int ignore;
560: tree type;
561: rtx structure_value_addr;
562: {
563: tree formal, actual;
564: rtx header = DECL_SAVED_INSNS (fndecl);
565: rtx insns = FIRST_FUNCTION_INSN (header);
1.1.1.9 root 566: rtx insn;
1.1 root 567: int max_regno = MAX_REGNUM (header) + 1;
568: register int i;
569: int min_labelno = FIRST_LABELNO (header);
570: int max_labelno = LAST_LABELNO (header);
571: int nargs;
572: rtx *arg_vec;
1.1.1.9 root 573: rtx local_return_label = 0;
1.1 root 574: rtx follows_call = 0;
1.1.1.7 root 575: rtx this_struct_value_rtx = 0;
1.1 root 576:
577: if (max_regno < FIRST_PSEUDO_REGISTER)
1.1.1.3 root 578: abort ();
1.1 root 579:
580: nargs = list_length (DECL_ARGUMENTS (fndecl));
581:
1.1.1.7 root 582: first_parm_offset = FIRST_PARM_OFFSET (fndecl);
583:
1.1 root 584: /* We expect PARMS to have the right length; don't crash if not. */
585: if (list_length (parms) != nargs)
586: return (rtx)-1;
587:
588: /* Make a fresh binding contour that we can easily remove. */
589: pushlevel (0);
590: expand_start_bindings (0);
591:
592: /* Get all the actual args as RTL, and store them in ARG_VEC. */
593:
594: arg_vec = (rtx *)alloca (nargs * sizeof (rtx));
595:
596: for (formal = DECL_ARGUMENTS (fndecl),
597: actual = parms,
598: i = 0;
599: formal;
600: formal = TREE_CHAIN (formal),
601: actual = TREE_CHAIN (actual),
602: i++)
603: {
604: tree arg = TREE_VALUE (actual); /* this has already been converted */
605: enum machine_mode tmode = TYPE_MODE (TREE_TYPE (formal));
606: rtx copy;
607:
1.1.1.7 root 608: emit_note (DECL_SOURCE_FILE (formal), DECL_SOURCE_LINE (formal));
1.1 root 609:
610: if (TREE_ADDRESSABLE (formal))
611: {
612: int size = int_size_in_bytes (TREE_TYPE (formal));
613: copy = assign_stack_local (tmode, size);
1.1.1.12! root 614: if (!memory_address_p (DECL_MODE (formal), XEXP (copy, 0)))
! 615: copy = change_address (copy, VOIDmode, copy_rtx (XEXP (copy, 0)));
1.1 root 616: store_expr (arg, copy, 0);
617: }
618: else if (! TREE_READONLY (formal)
619: || TREE_VOLATILE (formal))
620: {
621: /* If parm is modified or if it hasn't a pseudo reg,
622: we may not simply substitute the actual value;
623: copy it through a register. */
624: copy = gen_reg_rtx (tmode);
625: store_expr (arg, copy, 0);
626: }
627: else
628: {
629: copy = expand_expr (arg, 0, tmode, 0);
630:
631: /* We do not use CONSTANT_ADDRESS_P here because
632: the set of cases where that might make a difference
633: are a subset of the cases that arise even when
634: it is a CONSTANT_ADDRESS_P (i.e., fp_delta
635: gets into the act. */
636: if (GET_CODE (copy) != REG && ! CONSTANT_P (copy))
637: copy = copy_to_reg (copy);
638: }
639: arg_vec[i] = copy;
640: }
641:
642: copy_parm_decls (DECL_ARGUMENTS (fndecl), arg_vec);
643:
644: /* Perform postincrements before actually calling the function. */
645: emit_queue ();
646:
647: /* clean up stack so that variables might have smaller offsets. */
648: do_pending_stack_adjust ();
649:
650: /* Pass the function the address in which to return a structure value. */
651: if (structure_value_addr)
1.1.1.7 root 652: {
653: if (GET_CODE (struct_value_rtx) == MEM)
654: {
655: this_struct_value_rtx = force_reg (Pmode, structure_value_addr);
656: }
657: else
658: {
659: this_struct_value_rtx = struct_value_rtx;
660: emit_move_insn (this_struct_value_rtx, structure_value_addr);
661: }
662: }
1.1 root 663:
664: /* Now prepare for copying the insns.
665: Set up reg_map, parm_map and label_map saying how to translate
666: the pseudo-registers, stack-parm references and labels when copying. */
667:
668: reg_map = (rtx *) alloca (max_regno * sizeof (rtx));
669: bzero (reg_map, max_regno * sizeof (rtx));
670:
671: if (DECL_ARGUMENTS (fndecl))
672: {
673: tree decl = DECL_ARGUMENTS (fndecl);
674: int offset = FUNCTION_ARGS_SIZE (header);
1.1.1.7 root 675:
1.1 root 676: parm_map =
677: (rtx *)alloca ((offset / UNITS_PER_WORD) * sizeof (rtx));
678: bzero (parm_map, (offset / UNITS_PER_WORD) * sizeof (rtx));
1.1.1.7 root 679: parm_map -= first_parm_offset / UNITS_PER_WORD;
1.1 root 680:
681: for (formal = decl, i = 0; formal; formal = TREE_CHAIN (formal), i++)
682: {
683: /* Create an entry in PARM_MAP that says what pseudo register
684: is associated with an address we might compute. */
1.1.1.7 root 685: if (DECL_OFFSET (formal) >= 0)
686: {
687: /* This parameter has a home in the stack. */
688: parm_map[DECL_OFFSET (formal) / BITS_PER_WORD] = arg_vec[i];
689: }
690: else
691: {
692: /* Parameter that was passed in a register;
693: does it have a home on the stack (as a local)? */
694: rtx frtx = DECL_RTL (formal);
695: rtx offset = 0;
696: if (GET_CODE (frtx) == MEM)
697: {
698: frtx = XEXP (frtx, 0);
699: if (GET_CODE (frtx) == PLUS)
700: {
701: if (XEXP (frtx, 0) == frame_pointer_rtx
702: && GET_CODE (XEXP (frtx, 1)) == CONST_INT)
703: offset = XEXP (frtx, 1);
704: else if (XEXP (frtx, 1) == frame_pointer_rtx
705: && GET_CODE (XEXP (frtx, 0)) == CONST_INT)
706: offset = XEXP (frtx, 0);
707: }
708: if (offset)
709: parm_map[INTVAL (offset) / UNITS_PER_WORD] = arg_vec[i];
710: else abort ();
711: }
712: else if (GET_CODE (frtx) != REG)
713: abort ();
714: }
1.1 root 715: /* Create an entry in REG_MAP that says what rtx is associated
716: with a pseudo register from the function being inlined. */
717: if (GET_CODE (DECL_RTL (formal)) == REG)
718: reg_map[REGNO (DECL_RTL (formal))] = arg_vec[i];
719: }
1.1.1.7 root 720:
1.1.1.8 root 721: /* Make certain that we can accept struct_value_{incoming_rtx,rtx},
1.1.1.7 root 722: and map it. If it is a hard register, it is mapped automagically. */
1.1.1.12! root 723: if (this_struct_value_rtx == 0
! 724: || GET_CODE (struct_value_incoming_rtx) == REG)
1.1.1.7 root 725: ;
726: else if (GET_CODE (struct_value_incoming_rtx) == MEM
727: && XEXP (XEXP (struct_value_incoming_rtx, 0), 0) == frame_pointer_rtx
728: && GET_CODE (XEXP (XEXP (struct_value_incoming_rtx, 0), 1)) == CONST_INT)
729: parm_map[INTVAL (XEXP (XEXP (struct_value_incoming_rtx, 0), 1)) / UNITS_PER_WORD]
730: = this_struct_value_rtx;
731: else
732: abort ();
1.1 root 733: }
734: else
735: {
736: parm_map = NULL;
737: }
738:
739: label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));
740: label_map -= min_labelno;
741:
742: for (i = min_labelno; i < max_labelno; i++)
743: label_map[i] = gen_label_rtx ();
744:
1.1.1.6 root 745: /* As we copy insns, record the correspondence, so that inter-insn
746: references can be copied into isomorphic structure. */
747:
748: insn_map = (rtx *) alloca (INSN_UID (header) * sizeof (rtx));
749: bzero (insn_map, INSN_UID (header) * sizeof (rtx));
750:
1.1 root 751: /* Set up a target to translate the inline function's value-register. */
752:
753: if (structure_value_addr != 0 || TYPE_MODE (type) == VOIDmode)
754: inline_target = 0;
755: else
1.1.1.3 root 756: {
757: /* Machine mode function was declared to return. */
758: enum machine_mode departing_mode = TYPE_MODE (type);
759: /* (Possibly wider) machine mode it actually computes
760: (for the sake of callers that fail to declare it right). */
761: enum machine_mode arriving_mode
1.1.1.10 root 762: = TYPE_MODE (DECL_RESULT_TYPE (fndecl));
1.1.1.3 root 763:
1.1.1.5 root 764: /* Don't use MEMs as direct targets because on some machines
765: substituting a MEM for a REG makes invalid insns.
766: Let the combiner substitute the MEM if that is valid. */
767: if (target && GET_CODE (target) == REG
768: && GET_MODE (target) == departing_mode)
1.1.1.3 root 769: inline_target = target;
770: else
771: inline_target = target = gen_reg_rtx (departing_mode);
772:
773: /* If function's value was promoted before return,
774: avoid machine mode mismatch when we substitute INLINE_TARGET.
775: But TARGET is what we will return to the caller. */
776: if (arriving_mode != departing_mode)
777: inline_target = gen_rtx (SUBREG, arriving_mode, target, 0);
778: }
1.1 root 779:
780: /* We are about to make space in this function's stack frame
781: for a copy of the stack frame of the inline function.
782: First, create an RTX that points to that stack frame
783: with the same offset usually used for the frame pointer.
784: This will be substituted for all frame-pointer references. */
785:
786: fp_delta = get_frame_size ();
787: #ifdef FRAME_GROWS_DOWNWARD
788: fp_delta = - fp_delta;
789: #endif
790: fp_delta -= STARTING_FRAME_OFFSET;
791:
792: inline_fp_rtx
793: = copy_to_mode_reg (Pmode,
794: plus_constant (frame_pointer_rtx, fp_delta));
795:
796: /* Now allocate the space for that to point at. */
797:
798: assign_stack_local (VOIDmode, DECL_FRAME_SIZE (fndecl));
799:
800: /* Now copy the insns one by one. */
801:
802: for (insn = insns; insn; insn = NEXT_INSN (insn))
803: {
804: rtx copy, pattern, next = 0;
805:
1.1.1.11 root 806: orig_asm_operands_vector = 0;
807: copy_asm_operands_vector = 0;
808:
1.1 root 809: switch (GET_CODE (insn))
810: {
811: case INSN:
812: pattern = PATTERN (insn);
813:
814: /* Special handling for the insn immediately after a CALL_INSN
815: that returned a value:
816: If it does copy the value, we must avoid the usual translation
817: of the return-register into INLINE_TARGET.
818: If it just USEs the value, the inline function expects it to
819: stay in the return-register and be returned,
820: so copy it into INLINE_TARGET. */
821:
822: if (follows_call
823: /* Allow a stack-adjust, handled normally, to come in between
824: the call and the value-copying insn. */
825: && ! (GET_CODE (pattern) == SET
826: && SET_DEST (pattern) == stack_pointer_rtx))
827: {
828: if (GET_CODE (pattern) == SET
829: && rtx_equal_p (SET_SRC (pattern), follows_call))
830: /* This insn copies the value: take special care to copy
831: that value to this insn's destination. */
832: {
833: copy = emit_insn (gen_rtx (SET, VOIDmode,
834: copy_rtx_and_substitute (SET_DEST (pattern)),
835: follows_call));
1.1.1.9 root 836: RTX_INTEGRATED_P (copy) = 1;
1.1 root 837: follows_call = 0;
838: break;
839: }
840: else if (GET_CODE (pattern) == USE
841: && rtx_equal_p (XEXP (pattern, 0), follows_call))
842: /* This insn does nothing but says the value is expected
843: to flow through to the inline function's return-value.
844: Make that happen, then ignore this insn. */
845: {
846: copy = emit_insn (gen_rtx (SET, VOIDmode, inline_target,
847: follows_call));
1.1.1.9 root 848: RTX_INTEGRATED_P (copy) = 1;
1.1 root 849: follows_call = 0;
850: break;
851: }
852: /* If it does neither, this value must be ignored. */
853: follows_call = 0;
854: }
855:
856: /* The (USE (REG n)) at return from the function should be ignored
857: since we are changing (REG n) into inline_target. */
1.1.1.6 root 858: copy = 0;
1.1 root 859: if (GET_CODE (pattern) == USE
860: && GET_CODE (XEXP (pattern, 0)) == REG
1.1.1.5 root 861: && REG_FUNCTION_VALUE_P (XEXP (pattern, 0)))
1.1 root 862: break;
863:
864: /* Try to do some quick constant folding here.
865: This will save save execution time of the compiler,
866: as well time and space of the program if done here. */
867: if (GET_CODE (pattern) == SET
868: && SET_DEST (pattern) == cc0_rtx)
869: next = try_fold_cc0 (insn);
870:
871: if (next != 0)
872: {
873: insn = next;
874: }
875: else
876: {
877: copy = emit_insn (copy_rtx_and_substitute (pattern));
1.1.1.9 root 878: RTX_INTEGRATED_P (copy) = 1;
1.1 root 879: }
880: break;
881:
882: case JUMP_INSN:
883: follows_call = 0;
884: if (GET_CODE (PATTERN (insn)) == RETURN)
885: {
1.1.1.9 root 886: if (local_return_label == 0)
887: local_return_label = gen_label_rtx ();
888: emit_jump (local_return_label);
1.1 root 889: break;
890: }
891: copy = emit_jump_insn (copy_rtx_and_substitute (PATTERN (insn)));
1.1.1.9 root 892: RTX_INTEGRATED_P (copy) = 1;
1.1 root 893: break;
894:
895: case CALL_INSN:
1.1.1.6 root 896: #if 0
897: /* This should no longer be necessary now that references
898: to this function's return value are flagged to distinguish
899: them from other references to the same hard register. */
1.1 root 900: {
901: rtx newbod;
902: /* If the call's body is (set (reg...) (call...)),
903: the register is a function return register, but DON'T
904: translate it into INLINE_TARGET because it describes the
905: called function, not the caller's return value. */
906: if (GET_CODE (PATTERN (insn)) == SET)
907: newbod = gen_rtx (SET, VOIDmode, SET_DEST (PATTERN (insn)),
908: copy_rtx_and_substitute (SET_SRC (PATTERN (insn))));
1.1.1.6 root 909: else if (GET_CODE (PATTERN (insn)) == PARALLEL
910: && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
911: {
912: register int j;
913: rtx newelem;
914: newbod = gen_rtx (PARALLEL, VOIDmode,
915: rtvec_alloc (XVECLEN (PATTERN (insn), 0)));
916: newelem = gen_rtx (SET, VOIDmode,
917: SET_DEST (XVECEXP (PATTERN (insn), 0, 0)),
918: copy_rtx_and_substitute (SET_SRC (XVECEXP (PATTERN (insn), 0, 0))));
919: XVECEXP (newbod, 0, 0) = newelem;
920: for (j = 1; j < XVECLEN (newbod, 0); j++)
921: XVECEXP (newbod, 0, j)
922: = copy_rtx_and_substitute (XVECEXP (PATTERN (insn), 0, j));
923: }
1.1 root 924: else
925: newbod = copy_rtx_and_substitute (PATTERN (insn));
926: copy = emit_call_insn (newbod);
927: }
1.1.1.6 root 928: #else /* 1 */
929: copy = emit_call_insn (copy_rtx_and_substitute (PATTERN (insn)));
930: #endif /* 1 */
1.1.1.9 root 931: RTX_INTEGRATED_P (copy) = 1;
1.1 root 932: /* Special handling needed for the following INSN depending on
933: whether it copies the value from the fcn return reg. */
934: if (GET_CODE (PATTERN (insn)) == SET)
935: follows_call = SET_DEST (PATTERN (insn));
936: break;
937:
938: case CODE_LABEL:
1.1.1.6 root 939: copy = emit_label (label_map[CODE_LABEL_NUMBER (insn)]);
1.1 root 940: follows_call = 0;
941: break;
942:
943: case BARRIER:
1.1.1.6 root 944: copy = emit_barrier ();
1.1 root 945: break;
946:
947: case NOTE:
1.1.1.7 root 948: if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
949: copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
950: else
951: copy = 0;
1.1 root 952: break;
953:
954: default:
955: abort ();
956: break;
957: }
1.1.1.6 root 958:
959: insn_map[INSN_UID (insn)] = copy;
1.1 root 960: }
961:
1.1.1.9 root 962: if (local_return_label)
963: emit_label (local_return_label);
1.1 root 964:
965: /* Make copies of the decls of the symbols in the inline function, so that
966: the copies of the variables get declared in the current function. */
967: copy_decl_tree (DECL_INITIAL (fndecl), 0);
968:
969: /* End the scope containing the copied formal parameter variables. */
970:
1.1.1.10 root 971: expand_end_bindings (getdecls (), 1, 1);
1.1 root 972: poplevel (1, 1, 0);
973:
974: reg_map = NULL;
975: label_map = NULL;
976:
977: if (ignore || TYPE_MODE (type) == VOIDmode)
978: return 0;
979:
980: if (structure_value_addr)
981: {
982: if (target)
983: return target;
984: return gen_rtx (MEM, BLKmode,
985: memory_address (BLKmode, structure_value_addr));
986: }
987:
1.1.1.3 root 988: return target;
1.1 root 989: }
990:
991: /* Given a chain of PARM_DECLs, ARGS, and a vector of RTL homes VEC,
992: copy each decl into a VAR_DECL, push all of those decls
993: and give each one the corresponding home. */
994:
995: static void
996: copy_parm_decls (args, vec)
997: tree args;
998: rtx *vec;
999: {
1000: register tree tail;
1001: register int i;
1002:
1003: for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++)
1004: {
1005: register tree decl = pushdecl (build_decl (VAR_DECL, DECL_NAME (tail),
1006: TREE_TYPE (tail)));
1.1.1.9 root 1007: /* These args would always appear unused, if not for this. */
1008: TREE_USED (decl) = 1;
1.1 root 1009: DECL_RTL (decl) = vec[i];
1010: }
1011: }
1012:
1013: /* Given a LET_STMT node, push decls and levels
1014: so as to construct in the current function a tree of contexts
1015: isomorphic to the one that is given. */
1016:
1017: static void
1018: copy_decl_tree (let, level)
1019: tree let;
1020: int level;
1021: {
1022: tree t;
1023:
1024: pushlevel (0);
1025:
1026: for (t = STMT_VARS (let); t; t = TREE_CHAIN (t))
1027: {
1028: tree d = build_decl (TREE_CODE (t), DECL_NAME (t), TREE_TYPE (t));
1029: DECL_SOURCE_LINE (d) = DECL_SOURCE_LINE (t);
1030: DECL_SOURCE_FILE (d) = DECL_SOURCE_FILE (t);
1031: if (DECL_RTL (t) != 0)
1.1.1.8 root 1032: {
1033: if (GET_CODE (DECL_RTL (t)) == MEM
1034: && CONSTANT_ADDRESS_P (XEXP (DECL_RTL (t), 0)))
1035: /* copy_rtx_and_substitute would call memory_address
1036: which would copy the address into a register.
1037: Then debugging-output wouldn't know how to handle it. */
1038: DECL_RTL (d) = DECL_RTL (t);
1039: else
1040: DECL_RTL (d) = copy_rtx_and_substitute (DECL_RTL (t));
1041: }
1.1 root 1042: TREE_EXTERNAL (d) = TREE_EXTERNAL (t);
1043: TREE_STATIC (d) = TREE_STATIC (t);
1044: TREE_PUBLIC (d) = TREE_PUBLIC (t);
1045: TREE_LITERAL (d) = TREE_LITERAL (t);
1046: TREE_ADDRESSABLE (d) = TREE_ADDRESSABLE (t);
1047: TREE_READONLY (d) = TREE_READONLY (t);
1048: TREE_VOLATILE (d) = TREE_VOLATILE (t);
1.1.1.9 root 1049: /* These args would always appear unused, if not for this. */
1050: TREE_USED (d) = 1;
1.1 root 1051: pushdecl (d);
1052: }
1053:
1054: for (t = STMT_BODY (let); t; t = TREE_CHAIN (t))
1055: copy_decl_tree (t, level + 1);
1056:
1057: poplevel (level > 0, 0, 0);
1058: }
1059:
1060: /* Create a new copy of an rtx.
1061: Recursively copies the operands of the rtx,
1062: except for those few rtx codes that are sharable. */
1063:
1064: static rtx
1065: copy_rtx_and_substitute (orig)
1066: register rtx orig;
1067: {
1068: register rtx copy, temp;
1069: register int i, j;
1070: register RTX_CODE code;
1071: register enum machine_mode mode;
1072: register char *format_ptr;
1073: int regno;
1074:
1075: if (orig == 0)
1076: return 0;
1077:
1078: code = GET_CODE (orig);
1079: mode = GET_MODE (orig);
1080:
1081: switch (code)
1082: {
1083: case REG:
1084: /* If a frame-pointer register shows up, then we
1085: must `fix' the reference. If the stack pointer
1086: register shows up, it must be part of stack-adjustments
1087: (*not* because we eliminated the frame pointer!).
1088: Small hard registers are returned as-is. Pseudo-registers
1089: go through their `reg_map'. */
1090: regno = REGNO (orig);
1091: if (regno < FIRST_PSEUDO_REGISTER)
1092: {
1.1.1.5 root 1093: if (REG_FUNCTION_VALUE_P (orig))
1.1.1.9 root 1094: {
1095: /* This is a reference to the function return value. If
1096: the function doesn't have a return value, error.
1097: If it does, it may not be the same mode as `inline_target'
1098: because SUBREG is not required for hard regs.
1099: If not, adjust mode of inline_target to fit the context. */
1100: if (inline_target == 0)
1101: abort ();
1102: if (mode == GET_MODE (inline_target))
1103: return inline_target;
1104: return gen_rtx (SUBREG, mode, inline_target, 0);
1105: }
1.1 root 1106: if (regno == FRAME_POINTER_REGNUM)
1107: return plus_constant (orig, fp_delta);
1108: return orig;
1109: }
1110: if (reg_map[regno] == NULL)
1111: reg_map[regno] = gen_reg_rtx (mode);
1112: return reg_map[regno];
1113:
1114: case CODE_LABEL:
1115: return label_map[CODE_LABEL_NUMBER (orig)];
1116:
1117: case LABEL_REF:
1118: copy = rtx_alloc (LABEL_REF);
1119: PUT_MODE (copy, mode);
1120: XEXP (copy, 0) = label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))];
1121: return copy;
1122:
1123: case PC:
1124: case CC0:
1125: case CONST_INT:
1126: case CONST_DOUBLE:
1127: case SYMBOL_REF:
1128: return orig;
1129:
1.1.1.11 root 1130: case ASM_OPERANDS:
1131: /* If a single asm insn contains multiple output operands
1132: then it contains multiple ASM_OPERANDS rtx's that share operand 3.
1133: We must make sure that the copied insn continues to share it. */
1134: if (orig_asm_operands_vector == XVEC (orig, 3))
1135: {
1136: copy = rtx_alloc (ASM_OPERANDS);
1137: XSTR (copy, 0) = XSTR (orig, 0);
1138: XSTR (copy, 1) = XSTR (orig, 1);
1139: XINT (copy, 2) = XINT (orig, 2);
1140: XVEC (copy, 3) = copy_asm_operands_vector;
1141: XVEC (copy, 4) = XVEC (orig, 4);
1142: return copy;
1143: }
1144: break;
1145:
1.1.1.5 root 1146: case CALL:
1147: /* This is given special treatment because the first
1148: operand of a CALL is a (MEM ...) which may get
1149: forced into a register for cse. This is undesirable
1150: if function-address cse isn't wanted or if we won't do cse. */
1151: #ifndef NO_FUNCTION_CSE
1152: if (! (optimize && ! flag_no_function_cse))
1153: #endif
1154: return gen_rtx (CALL, GET_MODE (orig),
1155: gen_rtx (MEM, GET_MODE (XEXP (orig, 0)),
1156: copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0))),
1157: copy_rtx_and_substitute (XEXP (orig, 1)));
1158: break;
1159:
1.1 root 1160: case PLUS:
1161: /* Note: the PLUS case is not nearly as careful as the MEM
1162: case in terms of preserving addresses. The reason for this
1163: is that it is expected that if a PLUS_EXPR turns out not
1164: to be a legitimate address, reload can fix that up, without
1165: doing major damage. However, a MEM rtx must preside
1166: over a legitimate address. The MEM case has lots of hair
1167: to deal with what happens when it sits on a PLUS... */
1168: /* Take care of the easy case quickly. */
1169: if (XEXP (orig, 0) == frame_pointer_rtx
1170: || XEXP (orig, 1) == frame_pointer_rtx
1171: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
1172: && (XEXP (orig, 0) == arg_pointer_rtx
1173: || XEXP (orig, 1) == arg_pointer_rtx)))
1174: {
1175: if (XEXP (orig, 0) == frame_pointer_rtx
1176: || XEXP (orig, 0) == arg_pointer_rtx)
1177: copy = XEXP (orig, 1);
1178: else
1179: copy = XEXP (orig, 0);
1180:
1181: if (GET_CODE (copy) == CONST_INT)
1182: {
1183: int c = INTVAL (copy);
1184:
1185: if (c > 0)
1186: {
1187: copy = parm_map[c / UNITS_PER_WORD];
1188: return XEXP (copy, 0);
1189: }
1190: return gen_rtx (PLUS, mode,
1191: frame_pointer_rtx,
1192: gen_rtx (CONST_INT, SImode,
1193: c + fp_delta));
1194: }
1195: copy = copy_rtx_and_substitute (copy);
1.1.1.6 root 1196: temp = force_reg (mode, gen_rtx (PLUS, mode, frame_pointer_rtx, copy));
1.1 root 1197: return plus_constant (temp, fp_delta);
1198: }
1199: else if (reg_mentioned_p (frame_pointer_rtx, orig)
1200: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
1201: && reg_mentioned_p (arg_pointer_rtx, orig)))
1202: {
1203: /* If we have a complex sum which has a frame pointer
1204: in it, and it was a legitimate address, then
1205: keep it that way. */
1206: if (memory_address_p (mode, orig))
1207: {
1208: if (GET_CODE (XEXP (orig, 0)) == CONST_INT)
1209: {
1210: copy = copy_rtx_and_substitute (XEXP (orig, 1));
1211: temp = plus_constant (copy, INTVAL (XEXP (orig, 0)));
1212: }
1213: else if (GET_CODE (XEXP (orig, 1)) == CONST_INT)
1214: {
1215: copy = copy_rtx_and_substitute (XEXP (orig, 0));
1216: temp = plus_constant (copy, INTVAL (XEXP (orig, 1)));
1217: }
1218: else
1219: {
1220: temp = gen_rtx (PLUS, GET_MODE (orig),
1221: copy_rtx_and_substitute (XEXP (orig, 0)),
1222: copy_rtx_and_substitute (XEXP (orig, 1)));
1223: }
1224: temp = memory_address (mode, temp);
1225: }
1226: else
1227: temp = gen_rtx (PLUS, GET_MODE (orig),
1228: copy_rtx_and_substitute (XEXP (orig, 0)),
1229: copy_rtx_and_substitute (XEXP (orig, 1)));
1230: }
1231: else
1232: temp = gen_rtx (PLUS, GET_MODE (orig),
1233: copy_rtx_and_substitute (XEXP (orig, 0)),
1234: copy_rtx_and_substitute (XEXP (orig, 1)));
1235:
1236: return temp;
1.1.1.7 root 1237:
1.1 root 1238: case MEM:
1239: /* Take care of easiest case here. */
1240: copy = XEXP (orig, 0);
1241: if (copy == frame_pointer_rtx || copy == arg_pointer_rtx)
1242: return gen_rtx (MEM, mode,
1243: plus_constant (frame_pointer_rtx, fp_delta));
1.1.1.6 root 1244:
1245: /* Allow a pushing-address even if that is not valid as an
1246: ordinary memory address. It indicates we are inlining a special
1.1.1.9 root 1247: push-insn. These must be copied; otherwise unshare_all_rtl
1248: might clobber them to point at temporary rtl of this function. */
1.1.1.6 root 1249: #ifdef STACK_GROWS_DOWNWARD
1250: if (GET_CODE (copy) == PRE_DEC && XEXP (copy, 0) == stack_pointer_rtx)
1.1.1.9 root 1251: return gen_rtx (MEM, mode, copy_rtx_and_substitute (copy));
1.1.1.6 root 1252: #else
1253: if (GET_CODE (copy) == PRE_INC && XEXP (copy, 0) == stack_pointer_rtx)
1.1.1.9 root 1254: return gen_rtx (MEM, mode, copy_rtx_and_substitute (copy));
1.1.1.6 root 1255: #endif
1256:
1.1.1.7 root 1257: /* If this is some other sort of address that isn't generally valid,
1258: break out all the registers referred to. */
1259: if (! memory_address_p (mode, copy))
1260: return gen_rtx (MEM, mode, copy_address (copy));
1261:
1.1 root 1262: if (GET_CODE (copy) == PLUS)
1263: {
1264: if (XEXP (copy, 0) == frame_pointer_rtx
1265: || XEXP (copy, 1) == frame_pointer_rtx
1266: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
1267: && (XEXP (copy, 0) == arg_pointer_rtx
1268: || XEXP (copy, 1) == arg_pointer_rtx)))
1269: {
1270: rtx reg;
1271: if (XEXP (copy, 0) == frame_pointer_rtx
1272: || XEXP (copy, 0) == arg_pointer_rtx)
1273: reg = XEXP (copy, 0), copy = XEXP (copy, 1);
1274: else
1275: reg = XEXP (copy, 1), copy = XEXP (copy, 0);
1276:
1277: if (GET_CODE (copy) == CONST_INT)
1278: {
1279: int c = INTVAL (copy);
1280:
1.1.1.7 root 1281: if (reg == arg_pointer_rtx && c >= first_parm_offset)
1.1 root 1282: {
1.1.1.10 root 1283: int index = c / UNITS_PER_WORD;
1284: int offset = c % UNITS_PER_WORD;
1285:
1286: /* If we are referring to the middle of a multiword parm,
1287: find the beginning of that parm.
1288: OFFSET gets the offset of the reference from
1289: the beginning of the parm. */
1290:
1291: while (parm_map[index] == 0)
1292: {
1293: index--;
1294: if (index < first_parm_offset / UNITS_PER_WORD)
1295: /* If this abort happens, it means we need
1296: to handle "decrementing" INDEX back far
1297: enough to start looking among the reg parms
1298: instead of the stack parms. What a mess! */
1299: abort ();
1300: offset += UNITS_PER_WORD;
1301: }
1302:
1303: copy = parm_map[index];
1304:
1.1.1.11 root 1305: #ifdef BYTES_BIG_ENDIAN
1.1.1.10 root 1306: /* Subtract from OFFSET the offset of where
1307: the actual parm value would start. */
1308: if (GET_MODE_SIZE (GET_MODE (copy)) < UNITS_PER_WORD)
1309: offset
1310: -= (UNITS_PER_WORD
1311: - GET_MODE_SIZE (GET_MODE (copy)));
1312: #endif
1.1 root 1313:
1314: /* If the MEM is only some of the bytes in the parm,
1.1.1.10 root 1315: effectively perform a SUBREG of the actual parm. */
1316: if ((GET_MODE (copy) != mode
1317: && GET_MODE (copy) != VOIDmode))
1318: {
1.1.1.11 root 1319: if (GET_CODE (copy) == MEM)
1320: return change_address (copy, mode,
1321: plus_constant (XEXP (copy, 0),
1322: offset));
1323: if (GET_CODE (copy) == REG)
1324: {
1325: /* Crash if the portion of the arg wanted
1326: is not the least significant.
1327: Functions with refs to other parts of a
1328: parameter should not be inline--
1329: see function_cannot_inline_p. */
1330: #ifdef BYTES_BIG_ENDIAN
1331: if (offset + GET_MODE_SIZE (mode)
1332: != GET_MODE_SIZE (GET_MODE (copy)))
1333: abort ();
1334: #else
1335: if (offset != 0)
1336: abort ();
1337: #endif
1338: return gen_rtx (SUBREG, mode, copy, 0);
1339: }
1340:
1341: abort ();
1.1.1.10 root 1342: }
1.1 root 1343: return copy;
1344: }
1345: temp = gen_rtx (PLUS, Pmode,
1346: frame_pointer_rtx,
1347: gen_rtx (CONST_INT, SImode,
1348: c + fp_delta));
1349: if (! memory_address_p (Pmode, temp))
1350: return gen_rtx (MEM, mode, plus_constant (inline_fp_rtx, c));
1351: }
1352: copy = copy_rtx_and_substitute (copy);
1353: temp = gen_rtx (PLUS, Pmode, frame_pointer_rtx, copy);
1354: temp = plus_constant (temp, fp_delta);
1355: temp = memory_address (Pmode, temp);
1356: }
1357: else if (reg_mentioned_p (frame_pointer_rtx, copy)
1358: || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
1359: && reg_mentioned_p (arg_pointer_rtx, copy)))
1360: {
1361: if (GET_CODE (XEXP (copy, 0)) == CONST_INT)
1362: {
1363: temp = copy_rtx_and_substitute (XEXP (copy, 1));
1364: temp = plus_constant (temp, INTVAL (XEXP (copy, 0)));
1365: }
1366: else if (GET_CODE (XEXP (copy, 1)) == CONST_INT)
1367: {
1368: temp = copy_rtx_and_substitute (XEXP (copy, 0));
1369: temp = plus_constant (temp, INTVAL (XEXP (copy, 1)));
1370: }
1371: else
1372: {
1373: temp = gen_rtx (PLUS, GET_MODE (copy),
1374: copy_rtx_and_substitute (XEXP (copy, 0)),
1375: copy_rtx_and_substitute (XEXP (copy, 1)));
1376: }
1377: }
1378: else
1379: {
1380: if (GET_CODE (XEXP (copy, 1)) == CONST_INT)
1381: temp = plus_constant (copy_rtx_and_substitute (XEXP (copy, 0)),
1382: INTVAL (XEXP (copy, 1)));
1383: else if (GET_CODE (XEXP (copy, 0)) == CONST_INT)
1384: temp = plus_constant (copy_rtx_and_substitute (XEXP (copy, 1)),
1385: INTVAL (XEXP (copy, 0)));
1386: else
1387: {
1388: rtx left = copy_rtx_and_substitute (XEXP (copy, 0));
1389: rtx right = copy_rtx_and_substitute (XEXP (copy, 1));
1390:
1391: temp = gen_rtx (PLUS, GET_MODE (copy), left, right);
1392: }
1393: }
1394: }
1395: else
1396: temp = copy_rtx_and_substitute (copy);
1397:
1398: return change_address (orig, mode, temp);
1399:
1400: case RETURN:
1401: abort ();
1402: }
1403:
1404: copy = rtx_alloc (code);
1405: PUT_MODE (copy, mode);
1406: copy->in_struct = orig->in_struct;
1407: copy->volatil = orig->volatil;
1408: copy->unchanging = orig->unchanging;
1409:
1410: format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
1411:
1412: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
1413: {
1414: switch (*format_ptr++)
1415: {
1416: case '0':
1417: break;
1418:
1419: case 'e':
1420: XEXP (copy, i) = copy_rtx_and_substitute (XEXP (orig, i));
1421: break;
1422:
1.1.1.6 root 1423: case 'u':
1424: /* Change any references to old-insns to point to the
1425: corresponding copied insns. */
1.1.1.9 root 1426: XEXP (copy, i) = insn_map[INSN_UID (XEXP (orig, i))];
1427: break;
1.1.1.6 root 1428:
1.1 root 1429: case 'E':
1430: XVEC (copy, i) = XVEC (orig, i);
1.1.1.6 root 1431: if (XVEC (orig, i) != NULL && XVECLEN (orig, i) != 0)
1.1 root 1432: {
1433: XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
1434: for (j = 0; j < XVECLEN (copy, i); j++)
1435: XVECEXP (copy, i, j) = copy_rtx_and_substitute (XVECEXP (orig, i, j));
1436: }
1437: break;
1438:
1439: case 'i':
1440: XINT (copy, i) = XINT (orig, i);
1441: break;
1442:
1443: case 's':
1444: XSTR (copy, i) = XSTR (orig, i);
1445: break;
1446:
1447: default:
1448: abort ();
1449: }
1450: }
1.1.1.11 root 1451:
1452: if (code == ASM_OPERANDS && orig_asm_operands_vector == 0)
1453: {
1454: orig_asm_operands_vector = XVEC (orig, 3);
1455: copy_asm_operands_vector = XVEC (copy, 3);
1456: }
1457:
1.1 root 1458: return copy;
1459: }
1460:
1.1.1.7 root 1461: /* Like copy_rtx_and_substitute but produces different output, suitable
1462: for an ideosyncractic address that isn't memory_address_p.
1463: The output resembles the input except that REGs and MEMs are replaced
1464: with new psuedo registers. All the "real work" is done in separate
1465: insns which set up the values of these new registers. */
1466:
1467: static rtx
1468: copy_address (orig)
1469: register rtx orig;
1470: {
1.1.1.9 root 1471: register rtx copy;
1.1.1.7 root 1472: register int i, j;
1473: register RTX_CODE code;
1474: register enum machine_mode mode;
1475: register char *format_ptr;
1476:
1477: if (orig == 0)
1478: return 0;
1479:
1480: code = GET_CODE (orig);
1481: mode = GET_MODE (orig);
1482:
1483: switch (code)
1484: {
1485: case REG:
1.1.1.9 root 1486: if (REGNO (orig) != FRAME_POINTER_REGNUM)
1487: return copy_rtx_and_substitute (orig);
1488: return plus_constant (frame_pointer_rtx, fp_delta);
1489:
1490: case PLUS:
1491: if (GET_CODE (XEXP (orig, 0)) == REG
1492: && REGNO (XEXP (orig, 0)) == FRAME_POINTER_REGNUM)
1493: return plus_constant (orig, fp_delta);
1494: break;
1495:
1.1.1.7 root 1496: case MEM:
1.1.1.9 root 1497: return copy_to_reg (copy_rtx_and_substitute (orig));
1.1.1.7 root 1498:
1499: case CODE_LABEL:
1500: case LABEL_REF:
1.1.1.9 root 1501: return copy_rtx_and_substitute (orig);
1.1.1.7 root 1502:
1503: case PC:
1504: case CC0:
1505: case CONST_INT:
1506: case CONST_DOUBLE:
1507: case SYMBOL_REF:
1508: return orig;
1509: }
1510:
1511: copy = rtx_alloc (code);
1512: PUT_MODE (copy, mode);
1513: copy->in_struct = orig->in_struct;
1514: copy->volatil = orig->volatil;
1515: copy->unchanging = orig->unchanging;
1516:
1517: format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
1518:
1519: for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
1520: {
1521: switch (*format_ptr++)
1522: {
1523: case '0':
1524: break;
1525:
1526: case 'e':
1527: XEXP (copy, i) = copy_rtx_and_substitute (XEXP (orig, i));
1528: break;
1529:
1530: case 'u':
1531: /* Change any references to old-insns to point to the
1532: corresponding copied insns. */
1.1.1.9 root 1533: XEXP (copy, i) = insn_map[INSN_UID (XEXP (orig, i))];
1534: break;
1.1.1.7 root 1535:
1536: case 'E':
1537: XVEC (copy, i) = XVEC (orig, i);
1538: if (XVEC (orig, i) != NULL && XVECLEN (orig, i) != 0)
1539: {
1540: XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
1541: for (j = 0; j < XVECLEN (copy, i); j++)
1542: XVECEXP (copy, i, j) = copy_rtx_and_substitute (XVECEXP (orig, i, j));
1543: }
1544: break;
1545:
1546: case 'i':
1547: XINT (copy, i) = XINT (orig, i);
1548: break;
1549:
1550: case 's':
1551: XSTR (copy, i) = XSTR (orig, i);
1552: break;
1553:
1554: default:
1555: abort ();
1556: }
1557: }
1558: return copy;
1559: }
1560:
1.1 root 1561: /* Attempt to simplify INSN while copying it from an inline fn,
1562: assuming it is a SET that sets CC0.
1563:
1564: If we simplify it, we emit the appropriate insns and return
1565: the last insn that we have handled (since we may handle the insn
1566: that follows INSN as well as INSN itself).
1567:
1568: Otherwise we do nothing and return zero. */
1569:
1570: static rtx
1571: try_fold_cc0 (insn)
1572: rtx insn;
1573: {
1574: rtx cnst = copy_rtx_and_substitute (SET_SRC (PATTERN (insn)));
1575: rtx pat, copy;
1576:
1577: if (CONSTANT_P (cnst)
1578: /* @@ Cautious: Don't know how many of these tests we need. */
1579: && NEXT_INSN (insn)
1580: && GET_CODE (pat = PATTERN (NEXT_INSN (insn))) == SET
1581: && SET_DEST (pat) == pc_rtx
1582: && GET_CODE (pat = SET_SRC (pat)) == IF_THEN_ELSE
1583: && GET_RTX_LENGTH (GET_CODE (XEXP (pat, 0))) == 2)
1584: {
1585: rtx cnst2;
1586: rtx cond = XEXP (pat, 0);
1587:
1588: if ((XEXP (cond, 0) == cc0_rtx
1589: && CONSTANT_P (XEXP (cond, 1))
1590: && (cnst2 = XEXP (cond, 1)))
1591: || (XEXP (cond, 1) == cc0_rtx
1592: && CONSTANT_P (XEXP (cond, 0))
1593: && (cnst2 = XEXP (cond, 0))))
1594: {
1595: copy = fold_out_const_cc0 (cond, XEXP (pat, 1), XEXP (pat, 2),
1596: cnst, cnst2);
1597: if (copy)
1598: {
1599: if (GET_CODE (copy) == LABEL_REF)
1600: {
1601: /* We will branch unconditionally to
1602: the label specified by COPY.
1603: Eliminate dead code by running down the
1604: list of insn until we see a CODE_LABEL.
1605: If the CODE_LABEL is the one specified
1606: by COPY, we win, and can delete all code
1607: up to (but not necessarily including)
1608: that label. Otherwise only win a little:
1609: emit the branch insn, and continue expanding. */
1610: rtx tmp = NEXT_INSN (insn);
1611: while (tmp && GET_CODE (tmp) != CODE_LABEL)
1612: tmp = NEXT_INSN (tmp);
1613: if (! tmp)
1614: abort ();
1615: if (label_map[CODE_LABEL_NUMBER (tmp)] == XEXP (copy, 0))
1616: {
1617: /* Big win. */
1618: return PREV_INSN (tmp);
1619: }
1620: else
1621: {
1622: /* Small win. Emit the unconditional branch,
1623: followed by a BARRIER, so that jump optimization
1624: will know what to do. */
1625: emit_jump (copy);
1626: return NEXT_INSN (insn);
1627: }
1628: }
1629: else if (copy == pc_rtx)
1630: {
1631: /* Do not take the branch, just fall through.
1632: Jump optimize should handle the elimination of
1633: dead code if appropriate. */
1634: return NEXT_INSN (insn);
1635: }
1636: else
1637: abort ();
1638: }
1639: }
1640: }
1641: return 0;
1642: }
1643:
1644: /* If (COND_RTX CNST1 CNST2) yield a result we can treat
1645: as being constant, return THEN_RTX if the result is always
1646: non-zero, and return ELSE_RTX otherwise. */
1647: static rtx
1648: fold_out_const_cc0 (cond_rtx, then_rtx, else_rtx, cnst1, cnst2)
1649: rtx cond_rtx, then_rtx, else_rtx;
1650: rtx cnst1, cnst2;
1651: {
1652: int value1, value2;
1653: int int1 = GET_CODE (cnst1) == CONST_INT;
1654: int int2 = GET_CODE (cnst2) == CONST_INT;
1655: if (int1)
1656: value1 = INTVAL (cnst1);
1657: else
1658: value1 = 1;
1659: if (int2)
1660: value2 = INTVAL (cnst2);
1661: else
1662: value2 = 1;
1663:
1664: switch (GET_CODE (cond_rtx))
1665: {
1666: case NE:
1667: if (int1 && int2)
1668: if (value1 != value2)
1669: return copy_rtx_and_substitute (then_rtx);
1670: else
1671: return copy_rtx_and_substitute (else_rtx);
1672: if (value1 == 0 || value2 == 0)
1673: return copy_rtx_and_substitute (then_rtx);
1674: if (int1 == 0 && int2 == 0)
1675: if (rtx_equal_p (cnst1, cnst2))
1676: return copy_rtx_and_substitute (else_rtx);
1677: break;
1678: case EQ:
1679: if (int1 && int2)
1680: if (value1 == value2)
1681: return copy_rtx_and_substitute (then_rtx);
1682: else
1683: return copy_rtx_and_substitute (else_rtx);
1684: if (value1 == 0 || value2 == 0)
1685: return copy_rtx_and_substitute (else_rtx);
1686: if (int1 == 0 && int2 == 0)
1687: if (rtx_equal_p (cnst1, cnst2))
1688: return copy_rtx_and_substitute (then_rtx);
1689: break;
1690: case GE:
1691: if (int1 && int2)
1692: if (value1 >= value2)
1693: return copy_rtx_and_substitute (then_rtx);
1694: else
1695: return copy_rtx_and_substitute (else_rtx);
1696: if (value1 == 0)
1697: return copy_rtx_and_substitute (else_rtx);
1698: if (value2 == 0)
1699: return copy_rtx_and_substitute (then_rtx);
1700: break;
1701: case GT:
1702: if (int1 && int2)
1703: if (value1 > value2)
1704: return copy_rtx_and_substitute (then_rtx);
1705: else
1706: return copy_rtx_and_substitute (else_rtx);
1707: if (value1 == 0)
1708: return copy_rtx_and_substitute (else_rtx);
1709: if (value2 == 0)
1710: return copy_rtx_and_substitute (then_rtx);
1711: break;
1712: case LE:
1713: if (int1 && int2)
1714: if (value1 <= value2)
1715: return copy_rtx_and_substitute (then_rtx);
1716: else
1717: return copy_rtx_and_substitute (else_rtx);
1718: if (value1 == 0)
1719: return copy_rtx_and_substitute (then_rtx);
1720: if (value2 == 0)
1721: return copy_rtx_and_substitute (else_rtx);
1722: break;
1723: case LT:
1724: if (int1 && int2)
1725: if (value1 < value2)
1726: return copy_rtx_and_substitute (then_rtx);
1727: else
1728: return copy_rtx_and_substitute (else_rtx);
1729: if (value1 == 0)
1730: return copy_rtx_and_substitute (then_rtx);
1731: if (value2 == 0)
1732: return copy_rtx_and_substitute (else_rtx);
1733: break;
1734: case GEU:
1735: if (int1 && int2)
1736: if ((unsigned)value1 >= (unsigned)value2)
1737: return copy_rtx_and_substitute (then_rtx);
1738: else
1739: return copy_rtx_and_substitute (else_rtx);
1740: if (value1 == 0)
1741: return copy_rtx_and_substitute (else_rtx);
1742: if (value2 == 0)
1743: return copy_rtx_and_substitute (then_rtx);
1744: break;
1745: case GTU:
1746: if (int1 && int2)
1747: if ((unsigned)value1 > (unsigned)value2)
1748: return copy_rtx_and_substitute (then_rtx);
1749: else
1750: return copy_rtx_and_substitute (else_rtx);
1751: if (value1 == 0)
1752: return copy_rtx_and_substitute (else_rtx);
1753: if (value2 == 0)
1754: return copy_rtx_and_substitute (then_rtx);
1755: break;
1756: case LEU:
1757: if (int1 && int2)
1758: if ((unsigned)value1 <= (unsigned)value2)
1759: return copy_rtx_and_substitute (then_rtx);
1760: else
1761: return copy_rtx_and_substitute (else_rtx);
1762: if (value1 == 0)
1763: return copy_rtx_and_substitute (then_rtx);
1764: if (value2 == 0)
1765: return copy_rtx_and_substitute (else_rtx);
1766: break;
1767: case LTU:
1768: if (int1 && int2)
1769: if ((unsigned)value1 < (unsigned)value2)
1770: return copy_rtx_and_substitute (then_rtx);
1771: else
1772: return copy_rtx_and_substitute (else_rtx);
1773: if (value1 == 0)
1774: return copy_rtx_and_substitute (then_rtx);
1775: if (value2 == 0)
1776: return copy_rtx_and_substitute (else_rtx);
1777: break;
1778: }
1779: /* Could not hack it. */
1780: return 0;
1781: }
1782:
1783: /* Output the assembly language code for the function FNDECL
1784: from its DECL_SAVED_INSNS. Used for inline functions that are output
1785: at end of compilation instead of where they came in the source. */
1786:
1787: void
1788: output_inline_function (fndecl)
1789: tree fndecl;
1790: {
1791: rtx head = DECL_SAVED_INSNS (fndecl);
1792: rtx last;
1793:
1794: temporary_allocation ();
1795:
1.1.1.4 root 1796: current_function_decl = fndecl;
1797:
1.1 root 1798: /* This call is only used to initialize global variables.
1799: The rtl code it emits will be discarded below. */
1800: expand_function_start (fndecl);
1801:
1802: /* Set stack frame size. */
1803: assign_stack_local (BLKmode, DECL_FRAME_SIZE (fndecl));
1804:
1805: restore_reg_data (FIRST_PARM_INSN (head));
1806:
1.1.1.10 root 1807: expand_function_end (DECL_SOURCE_FILE (fndecl), DECL_SOURCE_LINE (fndecl));
1.1 root 1808:
1809: for (last = head; NEXT_INSN (last); last = NEXT_INSN (last))
1810: ;
1811:
1812: set_new_first_and_last_insn (FIRST_PARM_INSN (head), last);
1813:
1814: /* Compile this function all the way down to assembly code. */
1815: rest_of_compilation (fndecl);
1816:
1.1.1.4 root 1817: current_function_decl = 0;
1818:
1.1 root 1819: permanent_allocation ();
1820: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.