#define ECF_SP_DEPRESSED 1024
/* Nonzero if this call is known to always return. */
#define ECF_ALWAYS_RETURN 2048
+/* Create libcall block around the call. */
+#define ECF_LIBCALL_BLOCK 4096
static void emit_call_1 PARAMS ((rtx, tree, tree, HOST_WIDE_INT,
HOST_WIDE_INT, HOST_WIDE_INT, rtx,
/* The function exp may have the `pure' attribute. */
if (DECL_P (exp) && DECL_IS_PURE (exp))
- flags |= ECF_PURE;
+ flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
if (TREE_NOTHROW (exp))
flags |= ECF_NOTHROW;
}
if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
- flags |= ECF_CONST;
+ flags |= ECF_CONST | ECF_LIBCALL_BLOCK;
if (TREE_THIS_VOLATILE (exp))
flags |= ECF_NORETURN;
if (TREE_CODE (type) == FUNCTION_TYPE && TYPE_RETURNS_STACK_DEPRESSED (type))
{
flags |= ECF_SP_DEPRESSED;
- flags &= ~(ECF_PURE | ECF_CONST);
+ flags &= ~(ECF_PURE | ECF_CONST | ECF_LIBCALL_BLOCK);
}
return flags;
copy = assign_temp (type, 0, 1, 0);
store_expr (args[i].tree_value, copy, 0);
- *ecf_flags &= ~(ECF_CONST | ECF_PURE);
+ *ecf_flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
args[i].tree_value = build1 (ADDR_EXPR,
build_pointer_type (type),
/* If this is an addressable type, we cannot pre-evaluate it. Thus,
we cannot consider this function call constant. */
if (TREE_ADDRESSABLE (type))
- *ecf_flags &= ~(ECF_CONST | ECF_PURE);
+ *ecf_flags &= ~ECF_LIBCALL_BLOCK;
/* Compute the stack-size of this argument. */
if (args[i].reg == 0 || args[i].partial != 0
worse code) */
for (i = 0; i < num_actuals; i++)
- if ((flags & (ECF_CONST | ECF_PURE))
+ if ((flags & ECF_LIBCALL_BLOCK)
|| calls_function (args[i].tree_value, !ACCUMULATE_OUTGOING_ARGS))
{
enum machine_mode mode;
if (aggregate_value_p (exp))
{
/* This call returns a big structure. */
- flags &= ~(ECF_CONST | ECF_PURE);
+ flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
#ifdef PCC_STATIC_STRUCT_RETURN
{
do this eventually, but it is too complicated to keep track of
what insns go in the cse'able block and which don't. */
- flags &= ~(ECF_CONST | ECF_PURE);
+ flags &= ~ECF_LIBCALL_BLOCK;
must_preallocate = 1;
}
/* When calling a const function, we must pop the stack args right away,
so that the pop is deleted or moved with the call. */
- if (flags & (ECF_CONST | ECF_PURE))
+ if (pass && (flags & ECF_LIBCALL_BLOCK))
NO_DEFER_POP;
/* Push the temporary stack slot level so that we can free any
/* Now we are about to start emitting insns that can be deleted
if a libcall is deleted. */
- if (flags & (ECF_CONST | ECF_PURE | ECF_MALLOC))
+ if (pass && (flags & (ECF_LIBCALL_BLOCK | ECF_MALLOC)))
start_sequence ();
adjusted_args_size = args_size;
/* When the stack adjustment is pending, we get better code
by combining the adjustments. */
if (pending_stack_adjust
- && ! (flags & (ECF_CONST | ECF_PURE))
+ && ! (flags & ECF_LIBCALL_BLOCK)
&& ! inhibit_defer_pop)
{
pending_stack_adjust
valreg = hard_function_value (TREE_TYPE (exp), fndecl, (pass == 0));
}
+ if (valreg == 0 || GET_CODE (valreg) == PARALLEL)
+ flags &= ~ECF_LIBCALL_BLOCK;
+
/* Precompute all register parameters. It isn't safe to compute anything
once we have started filling any specific hard regs. */
precompute_register_parameters (num_actuals, args, ®_parm_seen);
Test valreg so we don't crash; may safely ignore `const'
if return type is void. Disable for PARALLEL return values, because
we have no way to move such values into a pseudo register. */
- if (pass
- && (flags & (ECF_CONST | ECF_PURE))
- && valreg != 0 && GET_CODE (valreg) != PARALLEL)
+ if (pass && (flags & ECF_LIBCALL_BLOCK))
{
rtx note = 0;
rtx temp = gen_reg_rtx (GET_MODE (valreg));
valreg = temp;
}
- else if (flags & (ECF_CONST | ECF_PURE))
- {
- /* Otherwise, just write out the sequence without a note. */
- rtx insns = get_insns ();
-
- end_sequence ();
- emit_insns (insns);
- }
- else if (flags & ECF_MALLOC)
+ else if (pass && (flags & ECF_MALLOC))
{
rtx temp = gen_reg_rtx (GET_MODE (valreg));
rtx last, insns;
switch (fn_type)
{
case LCT_NORMAL:
+ break;
case LCT_CONST:
+ flags |= ECF_CONST;
+ break;
case LCT_PURE:
- /* Nothing to do here. */
+ flags |= ECF_PURE;
break;
case LCT_CONST_MAKE_BLOCK:
- flags |= ECF_CONST;
+ flags |= ECF_CONST | ECF_LIBCALL_BLOCK;
break;
case LCT_PURE_MAKE_BLOCK:
- flags |= ECF_PURE;
+ flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
break;
case LCT_NORETURN:
flags |= ECF_NORETURN;
#endif
/* This call returns a big structure. */
- flags &= ~(ECF_CONST | ECF_PURE);
+ flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
}
/* ??? Unfinished: must pass the memory address as an argument. */
/* Now we are about to start emitting insns that can be deleted
if a libcall is deleted. */
- if (flags & (ECF_CONST | ECF_PURE))
+ if (flags & ECF_LIBCALL_BLOCK)
start_sequence ();
push_temp_slots ();
NO_DEFER_POP;
valreg = (mem_value == 0 && outmode != VOIDmode
? hard_libcall_value (outmode) : NULL_RTX);
+ if (valreg == 0 || GET_CODE (valreg) == PARALLEL)
+ flags &= ~ECF_LIBCALL_BLOCK;
/* Stack must be properly aligned now. */
if (stack_pointer_delta & (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT - 1))
Test valreg so we don't crash; may safely ignore `const'
if return type is void. Disable for PARALLEL return values, because
we have no way to move such values into a pseudo register. */
- if ((flags & (ECF_CONST | ECF_PURE))
- && valreg != 0 && GET_CODE (valreg) != PARALLEL)
+ if (flags & ECF_LIBCALL_BLOCK)
{
rtx note = 0;
rtx temp = gen_reg_rtx (GET_MODE (valreg));
valreg = temp;
}
- else if (flags & (ECF_CONST | ECF_PURE))
- {
- /* Otherwise, just write out the sequence without a note. */
- rtx insns = get_insns ();
-
- end_sequence ();
- emit_insns (insns);
- }
pop_temp_slots ();
/* Copy the value to the right place. */