-/* A subroutine of nonlocal_mentioned_p, returns 1 if *LOC mentions
- something which is not local to the function and is not constant. */
-
-static int
-nonlocal_mentioned_p_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
-{
- rtx x = *loc;
- rtx base;
- int regno;
-
- if (! x)
- return 0;
-
- switch (GET_CODE (x))
- {
- case SUBREG:
- if (REG_P (SUBREG_REG (x)))
- {
- /* Global registers are not local. */
- if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
- && global_regs[subreg_regno (x)])
- return 1;
- return 0;
- }
- break;
-
- case REG:
- regno = REGNO (x);
- /* Global registers are not local. */
- if (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
- return 1;
- return 0;
-
- case SCRATCH:
- case PC:
- case CC0:
- case CONST_INT:
- case CONST_DOUBLE:
- case CONST_VECTOR:
- case CONST:
- case LABEL_REF:
- return 0;
-
- case SYMBOL_REF:
- /* Constants in the function's constants pool are constant. */
- if (CONSTANT_POOL_ADDRESS_P (x))
- return 0;
- return 1;
-
- case CALL:
- /* Non-constant calls and recursion are not local. */
- return 1;
-
- case MEM:
- /* Be overly conservative and consider any volatile memory
- reference as not local. */
- if (MEM_VOLATILE_P (x))
- return 1;
- base = find_base_term (XEXP (x, 0));
- if (base)
- {
- /* A Pmode ADDRESS could be a reference via the structure value
- address or static chain. Such memory references are nonlocal.
-
- Thus, we have to examine the contents of the ADDRESS to find
- out if this is a local reference or not. */
- if (GET_CODE (base) == ADDRESS
- && GET_MODE (base) == Pmode
- && (XEXP (base, 0) == stack_pointer_rtx
- || XEXP (base, 0) == arg_pointer_rtx
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
- || XEXP (base, 0) == hard_frame_pointer_rtx
-#endif
- || XEXP (base, 0) == frame_pointer_rtx))
- return 0;
- /* Constants in the function's constant pool are constant. */
- if (GET_CODE (base) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (base))
- return 0;
- }
- return 1;
-
- case UNSPEC_VOLATILE:
- case ASM_INPUT:
- return 1;
-
- case ASM_OPERANDS:
- if (MEM_VOLATILE_P (x))
- return 1;
-
- /* Fall through. */
-
- default:
- break;
- }
-
- return 0;
-}
-
-/* Returns nonzero if X might mention something which is not
- local to the function and is not constant. */
-
-static int
-nonlocal_mentioned_p (rtx x)
-{
- if (INSN_P (x))
- {
- if (CALL_P (x))
- {
- if (! CONST_OR_PURE_CALL_P (x))
- return 1;
- x = CALL_INSN_FUNCTION_USAGE (x);
- if (x == 0)
- return 0;
- }
- else
- x = PATTERN (x);
- }
-
- return for_each_rtx (&x, nonlocal_mentioned_p_1, NULL);
-}
-
-/* A subroutine of nonlocal_referenced_p, returns 1 if *LOC references
- something which is not local to the function and is not constant. */
-
-static int
-nonlocal_referenced_p_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
-{
- rtx x = *loc;
-
- if (! x)
- return 0;
-
- switch (GET_CODE (x))
- {
- case MEM:
- case REG:
- case SYMBOL_REF:
- case SUBREG:
- return nonlocal_mentioned_p (x);
-
- case CALL:
- /* Non-constant calls and recursion are not local. */
- return 1;
-
- case SET:
- if (nonlocal_mentioned_p (SET_SRC (x)))
- return 1;
-
- if (MEM_P (SET_DEST (x)))
- return nonlocal_mentioned_p (XEXP (SET_DEST (x), 0));
-
- /* If the destination is anything other than a CC0, PC,
- MEM, REG, or a SUBREG of a REG that occupies all of
- the REG, then X references nonlocal memory if it is
- mentioned in the destination. */
- if (GET_CODE (SET_DEST (x)) != CC0
- && GET_CODE (SET_DEST (x)) != PC
- && !REG_P (SET_DEST (x))
- && ! (GET_CODE (SET_DEST (x)) == SUBREG
- && REG_P (SUBREG_REG (SET_DEST (x)))
- && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
- + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
- == ((GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
- + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))))
- return nonlocal_mentioned_p (SET_DEST (x));
- return 0;
-
- case CLOBBER:
- if (MEM_P (XEXP (x, 0)))
- return nonlocal_mentioned_p (XEXP (XEXP (x, 0), 0));
- return 0;
-
- case USE:
- return nonlocal_mentioned_p (XEXP (x, 0));
-
- case ASM_INPUT:
- case UNSPEC_VOLATILE:
- return 1;
-
- case ASM_OPERANDS:
- if (MEM_VOLATILE_P (x))
- return 1;
-
- /* Fall through. */
-
- default:
- break;
- }
-
- return 0;
-}
-
-/* Returns nonzero if X might reference something which is not
- local to the function and is not constant. */
-
-static int
-nonlocal_referenced_p (rtx x)
-{
- if (INSN_P (x))
- {
- if (CALL_P (x))
- {
- if (! CONST_OR_PURE_CALL_P (x))
- return 1;
- x = CALL_INSN_FUNCTION_USAGE (x);
- if (x == 0)
- return 0;
- }
- else
- x = PATTERN (x);
- }
-
- return for_each_rtx (&x, nonlocal_referenced_p_1, NULL);
-}
-
-/* A subroutine of nonlocal_set_p, returns 1 if *LOC sets
- something which is not local to the function and is not constant. */
-
-static int
-nonlocal_set_p_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
-{
- rtx x = *loc;
-
- if (! x)
- return 0;
-
- switch (GET_CODE (x))
- {
- case CALL:
- /* Non-constant calls and recursion are not local. */
- return 1;
-
- case PRE_INC:
- case PRE_DEC:
- case POST_INC:
- case POST_DEC:
- case PRE_MODIFY:
- case POST_MODIFY:
- return nonlocal_mentioned_p (XEXP (x, 0));
-
- case SET:
- if (nonlocal_mentioned_p (SET_DEST (x)))
- return 1;
- return nonlocal_set_p (SET_SRC (x));
-
- case CLOBBER:
- return nonlocal_mentioned_p (XEXP (x, 0));
-
- case USE:
- return 0;
-
- case ASM_INPUT:
- case UNSPEC_VOLATILE:
- return 1;
-
- case ASM_OPERANDS:
- if (MEM_VOLATILE_P (x))
- return 1;
-
- /* Fall through. */
-
- default:
- break;
- }
-
- return 0;
-}
-
-/* Returns nonzero if X might set something which is not
- local to the function and is not constant. */
-
-static int
-nonlocal_set_p (rtx x)
-{
- if (INSN_P (x))
- {
- if (CALL_P (x))
- {
- if (! CONST_OR_PURE_CALL_P (x))
- return 1;
- x = CALL_INSN_FUNCTION_USAGE (x);
- if (x == 0)
- return 0;
- }
- else
- x = PATTERN (x);
- }
-
- return for_each_rtx (&x, nonlocal_set_p_1, NULL);
-}
-
-/* Mark the function if it is pure or constant. */
-
-void
-mark_constant_function (void)
-{
- rtx insn;
- int nonlocal_memory_referenced;
-
- if (TREE_READONLY (current_function_decl)
- || DECL_IS_PURE (current_function_decl)
- || TREE_THIS_VOLATILE (current_function_decl)
- || current_function_has_nonlocal_goto
- || !targetm.binds_local_p (current_function_decl))
- return;
-
- /* A loop might not return which counts as a side effect. */
- if (mark_dfs_back_edges ())
- return;
-
- nonlocal_memory_referenced = 0;
-
- init_alias_analysis ();
-
- /* Determine if this is a constant or pure function. */
-
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- if (! INSN_P (insn))
- continue;
-
- if (nonlocal_set_p (insn) || global_reg_mentioned_p (insn)
- || volatile_refs_p (PATTERN (insn)))
- break;
-
- if (! nonlocal_memory_referenced)
- nonlocal_memory_referenced = nonlocal_referenced_p (insn);
- }
-
- end_alias_analysis ();
-
- /* Mark the function. */
-
- if (insn)
- ;
- else if (nonlocal_memory_referenced)
- {
- cgraph_rtl_info (current_function_decl)->pure_function = 1;
- DECL_IS_PURE (current_function_decl) = 1;
- }
- else
- {
- cgraph_rtl_info (current_function_decl)->const_function = 1;
- TREE_READONLY (current_function_decl) = 1;
- }
-}
-\f