alias.c (nonlocal_reference_p): Take a care for CALL_INSNS's fusage field.
* alias.c (nonlocal_reference_p): Take a care for CALL_INSNS's fusage field. * calls.c (ECF_PURE): New flag. (emit_call_1): Handle ECF_PURE calls. (initialize_argument_information): Unset ECF_PURE flag too. (precompute_arguments): Precompute for ECF_PURE too. (expand_call): Handle ECF_PURE calls too. (emit_library_call_value_1): Rename no_queue argument to fn_type, accept value of 2 as pure function. (emit_library_call_value, emit_library_call): Rename no_queue argument to fn_type. * optabs.c (prepare_cmp_insn): Pass fn_type 2 to memcmp call. * tree.h (DECL_IS_PURE): New macro. (struct tree_decl): Add pure_flag. * c-common.c (enum attrs): Add attribute "pure". (init_attributes): Initialize attribute "pure" (decl_attributes): Handle attribute "pure". * extend.texi (Attribute "pure"): Document. * calls.c (expand_call): Add (mem:BLK (scratch)) to "equal from" in pure function. (flags_from_decl_or_type): Support attribute "pure". From-SVN: r33138
This commit is contained in:
parent
c966901c24
commit
2a8f6b90c1
|
@ -1,3 +1,28 @@
|
|||
Thu Apr 13 15:55:08 MET DST 2000 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* alias.c (nonlocal_reference_p): Take a care for
|
||||
CALL_INSNS's fusage field.
|
||||
* calls.c (ECF_PURE): New flag.
|
||||
(emit_call_1): Handle ECF_PURE calls.
|
||||
(initialize_argument_information): Unset ECF_PURE flag too.
|
||||
(precompute_arguments): Precompute for ECF_PURE too.
|
||||
(expand_call): Handle ECF_PURE calls too.
|
||||
(emit_library_call_value_1): Rename no_queue argument to
|
||||
fn_type, accept value of 2 as pure function.
|
||||
(emit_library_call_value, emit_library_call): Rename no_queue argument
|
||||
to fn_type.
|
||||
* optabs.c (prepare_cmp_insn): Pass fn_type 2 to memcmp call.
|
||||
|
||||
* tree.h (DECL_IS_PURE): New macro.
|
||||
(struct tree_decl): Add pure_flag.
|
||||
* c-common.c (enum attrs): Add attribute "pure".
|
||||
(init_attributes): Initialize attribute "pure"
|
||||
(decl_attributes): Handle attribute "pure".
|
||||
* extend.texi (Attribute "pure"): Document.
|
||||
* calls.c (expand_call): Add (mem:BLK (scratch)) to "equal from"
|
||||
in pure function.
|
||||
(flags_from_decl_or_type): Support attribute "pure".
|
||||
|
||||
2000-04-13 Jason Merrill <jason@casey.cygnus.com>
|
||||
|
||||
* cpplex.c (_cpp_lex_token): Handle digraphs. Don't null-terminate
|
||||
|
|
13
gcc/alias.c
13
gcc/alias.c
|
@ -1424,10 +1424,15 @@ nonlocal_reference_p (x)
|
|||
|
||||
if (GET_RTX_CLASS (code) == 'i')
|
||||
{
|
||||
/* Constant functions are constant. */
|
||||
/* Constant functions can be constant if they don't use
|
||||
scratch memory used to mark function w/o side effects. */
|
||||
if (code == CALL_INSN && CONST_CALL_P (x))
|
||||
return 0;
|
||||
x = PATTERN (x);
|
||||
{
|
||||
x = CALL_INSN_FUNCTION_USAGE (x);
|
||||
if (!x) return 0;
|
||||
}
|
||||
else
|
||||
x = PATTERN (x);
|
||||
code = GET_CODE (x);
|
||||
}
|
||||
|
||||
|
@ -1520,7 +1525,7 @@ nonlocal_reference_p (x)
|
|||
|
||||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||||
{
|
||||
if (fmt[i] == 'e')
|
||||
if (fmt[i] == 'e' && XEXP (x, i))
|
||||
{
|
||||
if (nonlocal_reference_p (XEXP (x, i)))
|
||||
return 1;
|
||||
|
|
|
@ -145,7 +145,7 @@ enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
|
|||
A_NO_CHECK_MEMORY_USAGE, A_NO_INSTRUMENT_FUNCTION,
|
||||
A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
|
||||
A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS, A_MALLOC,
|
||||
A_NO_LIMIT_STACK};
|
||||
A_NO_LIMIT_STACK, A_PURE};
|
||||
|
||||
enum format_type { printf_format_type, scanf_format_type,
|
||||
strftime_format_type };
|
||||
|
@ -457,6 +457,7 @@ init_attributes ()
|
|||
add_attribute (A_NO_CHECK_MEMORY_USAGE, "no_check_memory_usage", 0, 0, 1);
|
||||
add_attribute (A_MALLOC, "malloc", 0, 0, 1);
|
||||
add_attribute (A_NO_LIMIT_STACK, "no_stack_limit", 0, 0, 1);
|
||||
add_attribute (A_PURE, "pure", 0, 0, 1);
|
||||
}
|
||||
|
||||
/* Default implementation of valid_lang_attribute, below. By default, there
|
||||
|
@ -596,6 +597,7 @@ decl_attributes (node, attributes, prefix_attributes)
|
|||
case A_MALLOC:
|
||||
if (TREE_CODE (decl) == FUNCTION_DECL)
|
||||
DECL_IS_MALLOC (decl) = 1;
|
||||
/* ??? TODO: Support types. */
|
||||
else
|
||||
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
|
||||
break;
|
||||
|
@ -625,6 +627,15 @@ decl_attributes (node, attributes, prefix_attributes)
|
|||
warning ( "`%s' attribute ignored", IDENTIFIER_POINTER (name));
|
||||
break;
|
||||
|
||||
case A_PURE:
|
||||
if (TREE_CODE (decl) == FUNCTION_DECL)
|
||||
DECL_IS_PURE (decl) = 1;
|
||||
/* ??? TODO: Support types. */
|
||||
else
|
||||
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
|
||||
break;
|
||||
|
||||
|
||||
case A_T_UNION:
|
||||
if (is_type
|
||||
&& TREE_CODE (type) == UNION_TYPE
|
||||
|
|
101
gcc/calls.c
101
gcc/calls.c
|
@ -168,6 +168,9 @@ static int calls_function_1 PARAMS ((tree, int));
|
|||
the current one. */
|
||||
#define ECF_FORK_OR_EXEC 128
|
||||
#define ECF_SIBCALL 256
|
||||
/* Nonzero if this is a call to "pure" function (like const function,
|
||||
but may read memory. */
|
||||
#define ECF_PURE 512
|
||||
|
||||
static void emit_call_1 PARAMS ((rtx, tree, tree, HOST_WIDE_INT,
|
||||
HOST_WIDE_INT, HOST_WIDE_INT, rtx,
|
||||
|
@ -555,6 +558,15 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
|
|||
if (! call_insn)
|
||||
abort ();
|
||||
|
||||
/* Mark memory as used for "pure" function call. */
|
||||
if (ecf_flags & ECF_PURE)
|
||||
{
|
||||
call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_USE (VOIDmode,
|
||||
gen_rtx_MEM (BLKmode,
|
||||
gen_rtx_SCRATCH (VOIDmode))), call_fusage);
|
||||
}
|
||||
|
||||
/* Put the register usage information on the CALL. If there is already
|
||||
some usage information, put ours at the end. */
|
||||
if (CALL_INSN_FUNCTION_USAGE (call_insn))
|
||||
|
@ -571,7 +583,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
|
|||
CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage;
|
||||
|
||||
/* If this is a const call, then set the insn's unchanging bit. */
|
||||
if (ecf_flags & ECF_CONST)
|
||||
if (ecf_flags & (ECF_CONST | ECF_PURE))
|
||||
CONST_CALL_P (call_insn) = 1;
|
||||
|
||||
/* If this call can't throw, attach a REG_EH_REGION reg note to that
|
||||
|
@ -610,7 +622,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
|
|||
if (rounded_stack_size != 0)
|
||||
{
|
||||
if (flag_defer_pop && inhibit_defer_pop == 0
|
||||
&& !(ecf_flags & ECF_CONST))
|
||||
&& !(ecf_flags & (ECF_CONST | ECF_PURE)))
|
||||
pending_stack_adjust += rounded_stack_size;
|
||||
else
|
||||
adjust_stack (rounded_stack_size_rtx);
|
||||
|
@ -759,6 +771,10 @@ flags_from_decl_or_type (exp)
|
|||
if (DECL_P (exp) && DECL_IS_MALLOC (exp))
|
||||
flags |= ECF_MALLOC;
|
||||
|
||||
/* The function exp may have the `pure' attribute. */
|
||||
if (DECL_P (exp) && DECL_IS_PURE (exp))
|
||||
flags |= ECF_PURE;
|
||||
|
||||
if (TREE_NOTHROW (exp))
|
||||
flags |= ECF_NOTHROW;
|
||||
}
|
||||
|
@ -1195,7 +1211,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
|
|||
MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
|
||||
|
||||
store_expr (args[i].tree_value, copy, 0);
|
||||
*ecf_flags &= ~ECF_CONST;
|
||||
*ecf_flags &= ~(ECF_CONST | ECF_PURE);
|
||||
|
||||
args[i].tree_value = build1 (ADDR_EXPR,
|
||||
build_pointer_type (type),
|
||||
|
@ -1254,7 +1270,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
|
|||
/* 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_flags &= ~(ECF_CONST | ECF_PURE);
|
||||
|
||||
/* Compute the stack-size of this argument. */
|
||||
if (args[i].reg == 0 || args[i].partial != 0
|
||||
|
@ -1435,7 +1451,7 @@ precompute_arguments (flags, must_preallocate, num_actuals, args, args_size)
|
|||
which have already been stored into the stack. */
|
||||
|
||||
for (i = 0; i < num_actuals; i++)
|
||||
if ((flags & ECF_CONST)
|
||||
if ((flags & (ECF_CONST | ECF_PURE))
|
||||
|| ((args_size->var != 0 || args_size->constant != 0)
|
||||
&& calls_function (args[i].tree_value, 1))
|
||||
|| (must_preallocate
|
||||
|
@ -2038,7 +2054,7 @@ expand_call (exp, target, ignore)
|
|||
if (aggregate_value_p (exp))
|
||||
{
|
||||
/* This call returns a big structure. */
|
||||
flags &= ~ECF_CONST;
|
||||
flags &= ~(ECF_CONST | ECF_PURE);
|
||||
|
||||
#ifdef PCC_STATIC_STRUCT_RETURN
|
||||
{
|
||||
|
@ -2295,7 +2311,7 @@ expand_call (exp, target, ignore)
|
|||
|
||||
/* 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)
|
||||
if (flags & (ECF_CONST | ECF_PURE))
|
||||
NO_DEFER_POP;
|
||||
|
||||
/* Don't let pending stack adjusts add up to too much.
|
||||
|
@ -2416,7 +2432,7 @@ expand_call (exp, target, ignore)
|
|||
|
||||
Also do not make a sibling call. */
|
||||
|
||||
flags &= ~ECF_CONST;
|
||||
flags &= ~(ECF_CONST | ECF_PURE);
|
||||
must_preallocate = 1;
|
||||
sibcall_failure = 1;
|
||||
}
|
||||
|
@ -2470,7 +2486,7 @@ expand_call (exp, target, ignore)
|
|||
|
||||
/* Now we are about to start emitting insns that can be deleted
|
||||
if a libcall is deleted. */
|
||||
if (flags & (ECF_CONST | ECF_MALLOC))
|
||||
if (flags & (ECF_CONST | ECF_PURE | ECF_MALLOC))
|
||||
start_sequence ();
|
||||
|
||||
old_stack_allocated = stack_pointer_delta - pending_stack_adjust;
|
||||
|
@ -2653,7 +2669,7 @@ expand_call (exp, target, ignore)
|
|||
{
|
||||
/* When the stack adjustment is pending, we get better code
|
||||
by combining the adjustments. */
|
||||
if (pending_stack_adjust && ! (flags & ECF_CONST)
|
||||
if (pending_stack_adjust && ! (flags & (ECF_CONST | ECF_PURE))
|
||||
&& ! inhibit_defer_pop)
|
||||
{
|
||||
int adjust;
|
||||
|
@ -2821,7 +2837,8 @@ expand_call (exp, target, ignore)
|
|||
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) && valreg != 0 && GET_CODE (valreg) != PARALLEL)
|
||||
if ((flags & (ECF_CONST | ECF_PURE))
|
||||
&& valreg != 0 && GET_CODE (valreg) != PARALLEL)
|
||||
{
|
||||
rtx note = 0;
|
||||
rtx temp = gen_reg_rtx (GET_MODE (valreg));
|
||||
|
@ -2840,11 +2857,17 @@ expand_call (exp, target, ignore)
|
|||
insns = get_insns ();
|
||||
end_sequence ();
|
||||
|
||||
if (flags & ECF_PURE)
|
||||
note = gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_USE (VOIDmode,
|
||||
gen_rtx_MEM (BLKmode,
|
||||
gen_rtx_SCRATCH (VOIDmode))), note);
|
||||
|
||||
emit_libcall_block (insns, temp, valreg, note);
|
||||
|
||||
valreg = temp;
|
||||
}
|
||||
else if (flags & ECF_CONST)
|
||||
else if (flags & (ECF_CONST | ECF_PURE))
|
||||
{
|
||||
/* Otherwise, just write out the sequence without a note. */
|
||||
rtx insns = get_insns ();
|
||||
|
@ -3171,11 +3194,11 @@ libfunc_nothrow (fun)
|
|||
The RETVAL parameter specifies whether return value needs to be saved, other
|
||||
parameters are documented in the emit_library_call function bellow. */
|
||||
static rtx
|
||||
emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
|
||||
emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
|
||||
int retval;
|
||||
rtx orgfun;
|
||||
rtx value;
|
||||
int no_queue;
|
||||
int fn_type;
|
||||
enum machine_mode outmode;
|
||||
int nargs;
|
||||
va_list p;
|
||||
|
@ -3223,8 +3246,10 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
if (no_queue)
|
||||
if (fn_type == 1)
|
||||
flags |= ECF_CONST;
|
||||
else if (fn_type == 2)
|
||||
flags |= ECF_PURE;
|
||||
fun = orgfun;
|
||||
|
||||
if (libfunc_nothrow (fun))
|
||||
|
@ -3258,7 +3283,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
|
|||
#endif
|
||||
|
||||
/* This call returns a big structure. */
|
||||
flags &= ~ECF_CONST;
|
||||
flags &= ~(ECF_CONST | ECF_PURE);
|
||||
}
|
||||
|
||||
/* ??? Unfinished: must pass the memory address as an argument. */
|
||||
|
@ -3282,7 +3307,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
|
|||
|
||||
/* Now we are about to start emitting insns that can be deleted
|
||||
if a libcall is deleted. */
|
||||
if (flags & ECF_CONST)
|
||||
if (flags & (ECF_CONST | ECF_PURE))
|
||||
start_sequence ();
|
||||
|
||||
push_temp_slots ();
|
||||
|
@ -3726,7 +3751,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
|
|||
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)
|
||||
if ((flags & (ECF_CONST | ECF_PURE))
|
||||
&& valreg != 0 && GET_CODE (valreg) != PARALLEL)
|
||||
{
|
||||
rtx note = 0;
|
||||
|
@ -3743,11 +3768,17 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
|
|||
insns = get_insns ();
|
||||
end_sequence ();
|
||||
|
||||
if (flags & ECF_PURE)
|
||||
note = gen_rtx_EXPR_LIST (VOIDmode,
|
||||
gen_rtx_USE (VOIDmode,
|
||||
gen_rtx_MEM (BLKmode,
|
||||
gen_rtx_SCRATCH (VOIDmode))), note);
|
||||
|
||||
emit_libcall_block (insns, temp, valreg, note);
|
||||
|
||||
valreg = temp;
|
||||
}
|
||||
else if (flags & ECF_CONST)
|
||||
else if (flags & (ECF_CONST | ECF_PURE))
|
||||
{
|
||||
/* Otherwise, just write out the sequence without a note. */
|
||||
rtx insns = get_insns ();
|
||||
|
@ -3830,26 +3861,18 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
|
|||
and machine_modes to convert them to.
|
||||
The rtx values should have been passed through protect_from_queue already.
|
||||
|
||||
NO_QUEUE will be true if and only if the library call is a `const' call
|
||||
which will be enclosed in REG_LIBCALL/REG_RETVAL notes; it is equivalent
|
||||
to the flag ECF_CONST in expand_call.
|
||||
|
||||
NO_QUEUE must be true for const calls, because if it isn't, then
|
||||
any pending increment will be emitted between REG_LIBCALL/REG_RETVAL notes,
|
||||
and will be lost if the libcall sequence is optimized away.
|
||||
|
||||
NO_QUEUE must be false for non-const calls, because if it isn't, the
|
||||
call insn will have its CONST_CALL_P bit set, and it will be incorrectly
|
||||
optimized. For instance, the instruction scheduler may incorrectly
|
||||
move memory references across the non-const call. */
|
||||
FN_TYPE will is zero for `normal' calls, one for `const' calls, wich
|
||||
which will be enclosed in REG_LIBCALL/REG_RETVAL notes and two for `pure'
|
||||
calls, that are handled like `const' calls with extra
|
||||
(use (memory (scratch)). */
|
||||
|
||||
void
|
||||
emit_library_call VPARAMS((rtx orgfun, int no_queue, enum machine_mode outmode,
|
||||
emit_library_call VPARAMS((rtx orgfun, int fn_type, enum machine_mode outmode,
|
||||
int nargs, ...))
|
||||
{
|
||||
#ifndef ANSI_PROTOTYPES
|
||||
rtx orgfun;
|
||||
int no_queue;
|
||||
int fn_type;
|
||||
enum machine_mode outmode;
|
||||
int nargs;
|
||||
#endif
|
||||
|
@ -3859,12 +3882,12 @@ emit_library_call VPARAMS((rtx orgfun, int no_queue, enum machine_mode outmode,
|
|||
|
||||
#ifndef ANSI_PROTOTYPES
|
||||
orgfun = va_arg (p, rtx);
|
||||
no_queue = va_arg (p, int);
|
||||
fn_type = va_arg (p, int);
|
||||
outmode = va_arg (p, enum machine_mode);
|
||||
nargs = va_arg (p, int);
|
||||
#endif
|
||||
|
||||
emit_library_call_value_1 (0, orgfun, NULL_RTX, no_queue, outmode, nargs, p);
|
||||
emit_library_call_value_1 (0, orgfun, NULL_RTX, fn_type, outmode, nargs, p);
|
||||
|
||||
va_end (p);
|
||||
}
|
||||
|
@ -3878,13 +3901,13 @@ emit_library_call VPARAMS((rtx orgfun, int no_queue, enum machine_mode outmode,
|
|||
If VALUE is nonzero, VALUE is returned. */
|
||||
|
||||
rtx
|
||||
emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
|
||||
emit_library_call_value VPARAMS((rtx orgfun, rtx value, int fn_type,
|
||||
enum machine_mode outmode, int nargs, ...))
|
||||
{
|
||||
#ifndef ANSI_PROTOTYPES
|
||||
rtx orgfun;
|
||||
rtx value;
|
||||
int no_queue;
|
||||
int fn_type;
|
||||
enum machine_mode outmode;
|
||||
int nargs;
|
||||
#endif
|
||||
|
@ -3895,12 +3918,12 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
|
|||
#ifndef ANSI_PROTOTYPES
|
||||
orgfun = va_arg (p, rtx);
|
||||
value = va_arg (p, rtx);
|
||||
no_queue = va_arg (p, int);
|
||||
fn_type = va_arg (p, int);
|
||||
outmode = va_arg (p, enum machine_mode);
|
||||
nargs = va_arg (p, int);
|
||||
#endif
|
||||
|
||||
value = emit_library_call_value_1 (1, orgfun, value, no_queue, outmode, nargs, p);
|
||||
value = emit_library_call_value_1 (1, orgfun, value, fn_type, outmode, nargs, p);
|
||||
|
||||
va_end (p);
|
||||
|
||||
|
|
|
@ -1379,22 +1379,44 @@ typedef void voidfn ();
|
|||
volatile voidfn fatal;
|
||||
@end smallexample
|
||||
|
||||
@cindex @code{const} function attribute
|
||||
@item const
|
||||
Many functions do not examine any values except their arguments, and
|
||||
have no effects except the return value. Such a function can be subject
|
||||
@cindex @code{pure} function attribute
|
||||
@item pure
|
||||
Many functions have no effects except the return value and their
|
||||
return value and depends only on the parameters and/or global variables.
|
||||
Such a function can be subject
|
||||
to common subexpression elimination and loop optimization just as an
|
||||
arithmetic operator would be. These functions should be declared
|
||||
with the attribute @code{const}. For example,
|
||||
with the attribute @code{pure}. For example,
|
||||
|
||||
@smallexample
|
||||
int square (int) __attribute__ ((const));
|
||||
int square (int) __attribute__ ((pure));
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
says that the hypothetical function @code{square} is safe to call
|
||||
fewer times than the program says.
|
||||
|
||||
Some of common examples of pure functions are @code{strlen} or @code{memcmp}.
|
||||
Interesting non-pure functions are functions with infinite loops or those
|
||||
depending on volatile memory or other system resource, that may change between
|
||||
two consetuctive calls (such as @code{feof} in multithreding environment).
|
||||
|
||||
The attribute @code{pure} is not implemented in GNU C versions earlier
|
||||
than 2.96.
|
||||
@cindex @code{const} function attribute
|
||||
@item const
|
||||
Many functions do not examine any values except their arguments, and
|
||||
have no effects except the return value. Basically this is just slightly
|
||||
more strict class than the "pure" attribute above, since function is not
|
||||
alloved to read global memory.
|
||||
|
||||
@cindex pointer arguments
|
||||
Note that a function that has pointer arguments and examines the data
|
||||
pointed to must @emph{not} be declared @code{const}. Likewise, a
|
||||
function that calls a non-@code{const} function usually must not be
|
||||
@code{const}. It does not make sense for a @code{const} function to
|
||||
return @code{void}.
|
||||
|
||||
The attribute @code{const} is not implemented in GNU C versions earlier
|
||||
than 2.5. An alternative way to declare that a function has no side
|
||||
effects, which works in the current version and in some older versions,
|
||||
|
@ -1409,12 +1431,6 @@ extern const intfn square;
|
|||
This approach does not work in GNU C++ from 2.6.0 on, since the language
|
||||
specifies that the @samp{const} must be attached to the return value.
|
||||
|
||||
@cindex pointer arguments
|
||||
Note that a function that has pointer arguments and examines the data
|
||||
pointed to must @emph{not} be declared @code{const}. Likewise, a
|
||||
function that calls a non-@code{const} function usually must not be
|
||||
@code{const}. It does not make sense for a @code{const} function to
|
||||
return @code{void}.
|
||||
|
||||
@item format (@var{archetype}, @var{string-index}, @var{first-to-check})
|
||||
@cindex @code{format} function attribute
|
||||
|
|
|
@ -3020,14 +3020,14 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align,
|
|||
#endif
|
||||
{
|
||||
#ifdef TARGET_MEM_FUNCTIONS
|
||||
emit_library_call (memcmp_libfunc, 0,
|
||||
emit_library_call (memcmp_libfunc, 2,
|
||||
TYPE_MODE (integer_type_node), 3,
|
||||
XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
|
||||
convert_to_mode (TYPE_MODE (sizetype), size,
|
||||
TREE_UNSIGNED (sizetype)),
|
||||
TYPE_MODE (sizetype));
|
||||
#else
|
||||
emit_library_call (bcmp_libfunc, 0,
|
||||
emit_library_call (bcmp_libfunc, 2,
|
||||
TYPE_MODE (integer_type_node), 3,
|
||||
XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
|
||||
convert_to_mode (TYPE_MODE (integer_type_node),
|
||||
|
|
|
@ -1253,6 +1253,10 @@ struct tree_type
|
|||
not an alias. */
|
||||
#define DECL_IS_MALLOC(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.malloc_flag)
|
||||
|
||||
/* Nonzero in a FUNCTION_DECL means this function should be treated
|
||||
as "pure" function (like const function, but may read global memory). */
|
||||
#define DECL_IS_PURE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.pure_flag)
|
||||
|
||||
/* Nonzero in a FIELD_DECL means it is a bit field, and must be accessed
|
||||
specially. */
|
||||
#define DECL_BIT_FIELD(NODE) (FIELD_DECL_CHECK (NODE)->decl.bit_field_flag)
|
||||
|
@ -1392,6 +1396,7 @@ struct tree_decl
|
|||
unsigned comdat_flag : 1;
|
||||
unsigned malloc_flag : 1;
|
||||
unsigned no_limit_stack : 1;
|
||||
unsigned pure_flag : 1;
|
||||
#ifdef ONLY_INT_FIELDS
|
||||
unsigned int built_in_class : 2;
|
||||
#else
|
||||
|
|
Loading…
Reference in New Issue