-/* Copy the rtx ORIG recursively, replacing pseudo-regs and labels
- according to `reg_map' and `label_map'. The original rtl insns
- will be saved for inlining; this is used to make a copy
- which is used to finish compiling the inline function itself.
-
- If we find a "saved" constant pool entry, one which was replaced with
- the value of the constant, convert it back to a constant pool entry.
- Since the pool wasn't touched, this should simply restore the old
- address.
-
- All other kinds of rtx are copied except those that can never be
- changed during compilation. */
-
-static rtx
-copy_for_inline (orig)
- rtx orig;
-{
- register rtx x = orig;
- register rtx new;
- register int i;
- register enum rtx_code code;
- register char *format_ptr;
-
- if (x == 0)
- return x;
-
- code = GET_CODE (x);
-
- /* These types may be freely shared. */
-
- switch (code)
- {
- case QUEUED:
- case CONST_INT:
- case PC:
- case CC0:
- return x;
-
- case SYMBOL_REF:
- if (! SYMBOL_REF_NEED_ADJUST (x))
- return x;
- return rethrow_symbol_map (x, save_for_inline_eh_labelmap);
-
- case CONST_DOUBLE:
- /* We have to make a new CONST_DOUBLE to ensure that we account for
- it correctly. Using the old CONST_DOUBLE_MEM data is wrong. */
- if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
- {
- REAL_VALUE_TYPE d;
-
- REAL_VALUE_FROM_CONST_DOUBLE (d, x);
- return CONST_DOUBLE_FROM_REAL_VALUE (d, GET_MODE (x));
- }
- else
- return immed_double_const (CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x),
- VOIDmode);
-
- case CONST:
- /* Get constant pool entry for constant in the pool. */
- if (RTX_INTEGRATED_P (x))
- return validize_mem (force_const_mem (GET_MODE (x),
- copy_for_inline (XEXP (x, 0))));
- break;
-
- case SUBREG:
- /* Get constant pool entry, but access in different mode. */
- if (RTX_INTEGRATED_P (x))
- {
- new = force_const_mem (GET_MODE (SUBREG_REG (x)),
- copy_for_inline (XEXP (SUBREG_REG (x), 0)));
-
- PUT_MODE (new, GET_MODE (x));
- return validize_mem (new);
- }
- break;
-
- case ADDRESS:
- /* If not special for constant pool error. Else get constant pool
- address. */
- if (! RTX_INTEGRATED_P (x))
- abort ();
-
- new = force_const_mem (GET_MODE (XEXP (x, 0)),
- copy_for_inline (XEXP (XEXP (x, 0), 0)));
- new = XEXP (new, 0);
-
-#ifdef POINTERS_EXTEND_UNSIGNED
- if (GET_MODE (new) != GET_MODE (x))
- new = convert_memory_address (GET_MODE (x), new);
-#endif
-
- return new;
-
- case ASM_OPERANDS:
- /* If a single asm insn contains multiple output operands
- then it contains multiple ASM_OPERANDS rtx's that share operand 3.
- We must make sure that the copied insn continues to share it. */
- if (orig_asm_operands_vector == XVEC (orig, 3))
- {
- x = rtx_alloc (ASM_OPERANDS);
- x->volatil = orig->volatil;
- XSTR (x, 0) = XSTR (orig, 0);
- XSTR (x, 1) = XSTR (orig, 1);
- XINT (x, 2) = XINT (orig, 2);
- XVEC (x, 3) = copy_asm_operands_vector;
- XVEC (x, 4) = copy_asm_constraints_vector;
- XSTR (x, 5) = XSTR (orig, 5);
- XINT (x, 6) = XINT (orig, 6);
- return x;
- }
- break;
-
- case MEM:
- /* A MEM is usually allowed to be shared if its address is constant
- or is a constant plus one of the special registers.
-
- We do not allow sharing of addresses that are either a special
- register or the sum of a constant and a special register because
- it is possible for unshare_all_rtl to copy the address, into memory
- that won't be saved. Although the MEM can safely be shared, and
- won't be copied there, the address itself cannot be shared, and may
- need to be copied.
-
- There are also two exceptions with constants: The first is if the
- constant is a LABEL_REF or the sum of the LABEL_REF
- and an integer. This case can happen if we have an inline
- function that supplies a constant operand to the call of another
- inline function that uses it in a switch statement. In this case,
- we will be replacing the LABEL_REF, so we have to replace this MEM
- as well.
-
- The second case is if we have a (const (plus (address ..) ...)).
- In that case we need to put back the address of the constant pool
- entry. */
-
- if (CONSTANT_ADDRESS_P (XEXP (x, 0))
- && GET_CODE (XEXP (x, 0)) != LABEL_REF
- && ! (GET_CODE (XEXP (x, 0)) == CONST
- && (GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
- && ((GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
- == LABEL_REF)
- || (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
- == ADDRESS)))))
- return x;
- break;
-
- case LABEL_REF:
- /* If this is a non-local label, just make a new LABEL_REF.
- Otherwise, use the new label as well. */
- x = gen_rtx_LABEL_REF (GET_MODE (orig),
- LABEL_REF_NONLOCAL_P (orig) ? XEXP (orig, 0)
- : label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]);
- LABEL_REF_NONLOCAL_P (x) = LABEL_REF_NONLOCAL_P (orig);
- LABEL_OUTSIDE_LOOP_P (x) = LABEL_OUTSIDE_LOOP_P (orig);
- return x;
-
- case REG:
- if (REGNO (x) > LAST_VIRTUAL_REGISTER)
- return reg_map [REGNO (x)];
- else
- return x;
-
- case SET:
- /* If a parm that gets modified lives in a pseudo-reg,
- clear its TREE_READONLY to prevent certain optimizations. */
- {
- rtx dest = SET_DEST (x);
-
- while (GET_CODE (dest) == STRICT_LOW_PART
- || GET_CODE (dest) == ZERO_EXTRACT
- || GET_CODE (dest) == SUBREG)
- dest = XEXP (dest, 0);
-
- if (GET_CODE (dest) == REG
- && REGNO (dest) < max_parm_reg
- && REGNO (dest) >= FIRST_PSEUDO_REGISTER
- && parmdecl_map[REGNO (dest)] != 0
- /* The insn to load an arg pseudo from a stack slot
- does not count as modifying it. */
- && in_nonparm_insns)
- TREE_READONLY (parmdecl_map[REGNO (dest)]) = 0;
- }
- break;
-
-#if 0 /* This is a good idea, but here is the wrong place for it. */
- /* Arrange that CONST_INTs always appear as the second operand
- if they appear, and that `frame_pointer_rtx' or `arg_pointer_rtx'
- always appear as the first. */
- case PLUS:
- if (GET_CODE (XEXP (x, 0)) == CONST_INT
- || (XEXP (x, 1) == frame_pointer_rtx
- || (ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
- && XEXP (x, 1) == arg_pointer_rtx)))
- {
- rtx t = XEXP (x, 0);
- XEXP (x, 0) = XEXP (x, 1);
- XEXP (x, 1) = t;
- }
- break;
-#endif
- default:
- break;
- }
-
- /* Replace this rtx with a copy of itself. */
-
- x = rtx_alloc (code);
- bcopy ((char *) orig, (char *) x,
- (sizeof (*x) - sizeof (x->fld)
- + sizeof (x->fld[0]) * GET_RTX_LENGTH (code)));
-
- /* Now scan the subexpressions recursively.
- We can store any replaced subexpressions directly into X
- since we know X is not shared! Any vectors in X
- must be copied if X was copied. */
-
- format_ptr = GET_RTX_FORMAT (code);
-
- for (i = 0; i < GET_RTX_LENGTH (code); i++)
- {
- switch (*format_ptr++)
- {
- case 'e':
- XEXP (x, i) = copy_for_inline (XEXP (x, i));
- break;
-
- case 'u':
- /* Change any references to old-insns to point to the
- corresponding copied insns. */
- XEXP (x, i) = insn_map[INSN_UID (XEXP (x, i))];
- break;
-
- case 'E':
- if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0)
- {
- register int j;
-
- XVEC (x, i) = gen_rtvec_vv (XVECLEN (x, i), XVEC (x, i)->elem);
- for (j = 0; j < XVECLEN (x, i); j++)
- XVECEXP (x, i, j)
- = copy_for_inline (XVECEXP (x, i, j));
- }
- break;
- }
- }
-
- if (code == ASM_OPERANDS && orig_asm_operands_vector == 0)
- {
- orig_asm_operands_vector = XVEC (orig, 3);
- copy_asm_operands_vector = XVEC (x, 3);
- copy_asm_constraints_vector = XVEC (x, 4);
- }
-
- return x;
-}
-