+/* Arguments to the call. */
+static rtx call_arguments;
+
+/* Compute call_arguments. */
+
+static void
+prepare_call_arguments (basic_block bb, rtx insn)
+{
+ rtx link, x;
+ rtx prev, cur, next;
+ rtx call = PATTERN (insn);
+ tree type = NULL_TREE, t;
+ CUMULATIVE_ARGS args_so_far;
+
+ memset (&args_so_far, 0, sizeof (args_so_far));
+ if (GET_CODE (call) == PARALLEL)
+ call = XVECEXP (call, 0, 0);
+ if (GET_CODE (call) == SET)
+ call = SET_SRC (call);
+ if (GET_CODE (call) == CALL
+ && MEM_P (XEXP (call, 0))
+ && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
+ {
+ rtx symbol = XEXP (XEXP (call, 0), 0);
+ if (SYMBOL_REF_DECL (symbol)
+ && TREE_CODE (SYMBOL_REF_DECL (symbol)) == FUNCTION_DECL
+ && TYPE_ARG_TYPES (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
+ {
+ type = TREE_TYPE (SYMBOL_REF_DECL (symbol));
+ for (t = TYPE_ARG_TYPES (type); t && t != void_list_node;
+ t = TREE_CHAIN (t))
+ if (TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_VALUE (t))))
+ break;
+ if (t == NULL || t == void_list_node)
+ type = NULL;
+ else
+ INIT_CUMULATIVE_ARGS (args_so_far, type, NULL_RTX,
+ SYMBOL_REF_DECL (symbol),
+ list_length (TYPE_ARG_TYPES (type)));
+ }
+ }
+ t = type ? TYPE_ARG_TYPES (type) : NULL_TREE;
+
+ for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+ if (GET_CODE (XEXP (link, 0)) == USE)
+ {
+ rtx item = NULL_RTX;
+ x = XEXP (XEXP (link, 0), 0);
+ if (REG_P (x))
+ {
+ cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
+ if (val && cselib_preserved_value_p (val))
+ item = gen_rtx_CONCAT (GET_MODE (x), x, val->val_rtx);
+ else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
+ {
+ enum machine_mode mode = GET_MODE (x);
+
+ while ((mode = GET_MODE_WIDER_MODE (mode)) != VOIDmode
+ && GET_MODE_BITSIZE (mode) <= BITS_PER_WORD)
+ {
+ rtx reg = simplify_subreg (mode, x, GET_MODE (x), 0);
+
+ if (reg == NULL_RTX || !REG_P (reg))
+ continue;
+ val = cselib_lookup (reg, mode, 0, VOIDmode);
+ if (val && cselib_preserved_value_p (val))
+ {
+ item = gen_rtx_CONCAT (GET_MODE (x), x,
+ lowpart_subreg (GET_MODE (x),
+ val->val_rtx,
+ mode));
+ break;
+ }
+ }
+ }
+ }
+ else if (MEM_P (x))
+ {
+ rtx mem = x;
+ cselib_val *val;
+
+ if (!frame_pointer_needed)
+ {
+ struct adjust_mem_data amd;
+ amd.mem_mode = VOIDmode;
+ amd.stack_adjust = -VTI (bb)->out.stack_adjust;
+ amd.side_effects = NULL_RTX;
+ amd.store = true;
+ mem = simplify_replace_fn_rtx (mem, NULL_RTX, adjust_mems,
+ &amd);
+ gcc_assert (amd.side_effects == NULL_RTX);
+ }
+ val = cselib_lookup (mem, GET_MODE (mem), 0, VOIDmode);
+ if (val && cselib_preserved_value_p (val))
+ item = gen_rtx_CONCAT (GET_MODE (x), copy_rtx (x), val->val_rtx);
+ }
+ if (item)
+ call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item, call_arguments);
+ if (t && t != void_list_node)
+ {
+ enum machine_mode mode = TYPE_MODE (TREE_VALUE (t));
+ rtx reg = targetm.calls.function_arg (&args_so_far, mode,
+ TREE_VALUE (t), true);
+ if (TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_VALUE (t)))
+ && reg
+ && REG_P (reg)
+ && GET_MODE (reg) == mode
+ && GET_MODE_CLASS (mode) == MODE_INT
+ && REG_P (x)
+ && REGNO (x) == REGNO (reg)
+ && GET_MODE (x) == mode
+ && item)
+ {
+ enum machine_mode indmode
+ = TYPE_MODE (TREE_TYPE (TREE_VALUE (t)));
+ rtx mem = gen_rtx_MEM (indmode, x);
+ cselib_val *val = cselib_lookup (mem, indmode, 0, VOIDmode);
+ if (val && cselib_preserved_value_p (val))
+ {
+ item = gen_rtx_CONCAT (indmode, mem, val->val_rtx);
+ call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item,
+ call_arguments);
+ }
+ else
+ {
+ struct elt_loc_list *l;
+ tree initial;
+
+ /* Try harder, when passing address of a constant
+ pool integer it can be easily read back. */
+ val = CSELIB_VAL_PTR (XEXP (item, 1));
+ for (l = val->locs; l; l = l->next)
+ if (GET_CODE (l->loc) == SYMBOL_REF
+ && TREE_CONSTANT_POOL_ADDRESS_P (l->loc)
+ && SYMBOL_REF_DECL (l->loc)
+ && DECL_INITIAL (SYMBOL_REF_DECL (l->loc)))
+ {
+ initial = DECL_INITIAL (SYMBOL_REF_DECL (l->loc));
+ if (host_integerp (initial, 0))
+ {
+ item = GEN_INT (tree_low_cst (initial, 0));
+ item = gen_rtx_CONCAT (indmode, mem, item);
+ call_arguments
+ = gen_rtx_EXPR_LIST (VOIDmode, item,
+ call_arguments);
+ }
+ break;
+ }
+ }
+ }
+ targetm.calls.function_arg_advance (&args_so_far, mode,
+ TREE_VALUE (t), true);
+ t = TREE_CHAIN (t);
+ }
+ }
+
+ /* Reverse call_arguments chain. */
+ prev = NULL_RTX;
+ for (cur = call_arguments; cur; cur = next)
+ {
+ next = XEXP (cur, 1);
+ XEXP (cur, 1) = prev;
+ prev = cur;
+ }
+ call_arguments = prev;
+
+ x = PATTERN (insn);
+ if (GET_CODE (x) == PARALLEL)
+ x = XVECEXP (x, 0, 0);
+ if (GET_CODE (x) == SET)
+ x = SET_SRC (x);
+ if (GET_CODE (x) == CALL && MEM_P (XEXP (x, 0)))
+ {
+ x = XEXP (XEXP (x, 0), 0);
+ if (GET_CODE (x) != SYMBOL_REF)
+ {
+ cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
+ if (val && cselib_preserved_value_p (val))
+ {
+ x = gen_rtx_CONCAT (GET_MODE (x), pc_rtx, val->val_rtx);
+ call_arguments
+ = gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments);
+ }
+ }
+ }
+}
+