cp-tree.h (struct language_function): Remove temp_name_counter.
* cp-tree.h (struct language_function): Remove temp_name_counter. (temp_name_counter): Remove. (get_temp_name): Change prototype. (get_guard): New function. (get_guard_cond): Likewise. (set_guard): Likewise. * cvt.c (build_up_reference): Adjust call to get_temp_name. * decl.c (expand_static_init): Use get_guard and friends to implement guard variables. * decl2.c (get_temp_name): Assume that the variables created are always static. (get_sentry): Rename to ... (get_guard): ... this. Implement new ABI guard variables. (get_guard_bits): New function. (get_guard_cond): Likewise. (set_guard): Likewise. (start_static_initialization_or_destruction): Use them. (do_static_initialization): Replace sentry with guard throughout. (do_static_destruction): Likewise. * init.c (create_temporary_var): Add comment. From-SVN: r34803
This commit is contained in:
parent
c1c8f8cc4f
commit
c395453cb6
@ -1,3 +1,26 @@
|
||||
2000-06-30 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
* cp-tree.h (struct language_function): Remove temp_name_counter.
|
||||
(temp_name_counter): Remove.
|
||||
(get_temp_name): Change prototype.
|
||||
(get_guard): New function.
|
||||
(get_guard_cond): Likewise.
|
||||
(set_guard): Likewise.
|
||||
* cvt.c (build_up_reference): Adjust call to get_temp_name.
|
||||
* decl.c (expand_static_init): Use get_guard and friends to
|
||||
implement guard variables.
|
||||
* decl2.c (get_temp_name): Assume that the variables created are
|
||||
always static.
|
||||
(get_sentry): Rename to ...
|
||||
(get_guard): ... this. Implement new ABI guard variables.
|
||||
(get_guard_bits): New function.
|
||||
(get_guard_cond): Likewise.
|
||||
(set_guard): Likewise.
|
||||
(start_static_initialization_or_destruction): Use them.
|
||||
(do_static_initialization): Replace sentry with guard throughout.
|
||||
(do_static_destruction): Likewise.
|
||||
* init.c (create_temporary_var): Add comment.
|
||||
|
||||
2000-06-29 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
* cp-tree.h (flag_const_strings): Remove.
|
||||
|
@ -900,7 +900,6 @@ struct language_function
|
||||
int returns_value;
|
||||
int returns_null;
|
||||
int parms_stored;
|
||||
int temp_name_counter;
|
||||
int in_function_try_handler;
|
||||
int x_expanding_p;
|
||||
int name_declared;
|
||||
@ -1004,11 +1003,6 @@ struct language_function
|
||||
|
||||
#define vtbls_set_up_p cp_function_chain->vtbls_set_up_p
|
||||
|
||||
/* Used to help generate temporary names which are unique within
|
||||
a function. Reset to 0 by start_function. */
|
||||
|
||||
#define temp_name_counter cp_function_chain->temp_name_counter
|
||||
|
||||
/* Non-zero if we should generate RTL for functions that we process.
|
||||
When this is zero, we just accumulate tree structure, without
|
||||
interacting with the back end. */
|
||||
@ -4075,7 +4069,7 @@ extern tree constructor_name_full PARAMS ((tree));
|
||||
extern tree constructor_name PARAMS ((tree));
|
||||
extern void setup_vtbl_ptr PARAMS ((tree, tree));
|
||||
extern void defer_fn PARAMS ((tree));
|
||||
extern tree get_temp_name PARAMS ((tree, int));
|
||||
extern tree get_temp_name PARAMS ((tree));
|
||||
extern void finish_anon_union PARAMS ((tree));
|
||||
extern tree finish_table PARAMS ((tree, tree, tree, int));
|
||||
extern void finish_builtin_type PARAMS ((tree, const char *,
|
||||
@ -4110,6 +4104,9 @@ extern tree handle_class_head PARAMS ((tree, tree, tree));
|
||||
extern tree lookup_arg_dependent PARAMS ((tree, tree, tree));
|
||||
extern void finish_static_data_member_decl PARAMS ((tree, tree, tree, int));
|
||||
extern tree build_artificial_parm PARAMS ((tree, tree));
|
||||
extern tree get_guard PARAMS ((tree));
|
||||
extern tree get_guard_cond PARAMS ((tree));
|
||||
extern tree set_guard PARAMS ((tree));
|
||||
|
||||
/* in parse.y */
|
||||
extern void cp_parse_init PARAMS ((void));
|
||||
|
@ -356,7 +356,7 @@ build_up_reference (type, arg, flags)
|
||||
/* Create a new temporary variable. */
|
||||
tree targ = arg;
|
||||
if (toplevel_bindings_p ())
|
||||
arg = get_temp_name (argtype, 1);
|
||||
arg = get_temp_name (argtype);
|
||||
else
|
||||
{
|
||||
arg = pushdecl (build_decl (VAR_DECL, NULL_TREE, argtype));
|
||||
|
@ -8572,19 +8572,19 @@ expand_static_init (decl, init)
|
||||
else if (! toplevel_bindings_p ())
|
||||
{
|
||||
/* Emit code to perform this initialization but once. */
|
||||
tree temp;
|
||||
tree if_stmt;
|
||||
tree then_clause;
|
||||
tree assignment;
|
||||
tree temp_init;
|
||||
tree guard;
|
||||
tree guard_init;
|
||||
|
||||
/* Emit code to perform this initialization but once. This code
|
||||
looks like:
|
||||
|
||||
static int temp = 0;
|
||||
if (!temp) {
|
||||
static int guard = 0;
|
||||
if (!guard) {
|
||||
// Do initialization.
|
||||
temp = 1;
|
||||
guard = 1;
|
||||
// Register variable for destruction at end of program.
|
||||
}
|
||||
|
||||
@ -8602,14 +8602,13 @@ expand_static_init (decl, init)
|
||||
In theory, this process should be thread-safe, too; multiple
|
||||
threads should not be able to initialize the variable more
|
||||
than once. We don't yet attempt to ensure thread-safety. */
|
||||
temp = get_temp_name (integer_type_node, 1);
|
||||
rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
|
||||
|
||||
/* Create the guard variable. */
|
||||
guard = get_guard (decl);
|
||||
|
||||
/* Begin the conditional initialization. */
|
||||
if_stmt = begin_if_stmt ();
|
||||
finish_if_stmt_cond (cp_build_binary_op (EQ_EXPR, temp,
|
||||
integer_zero_node),
|
||||
if_stmt);
|
||||
finish_if_stmt_cond (get_guard_cond (guard), if_stmt);
|
||||
then_clause = begin_compound_stmt (/*has_no_scope=*/0);
|
||||
|
||||
/* Do the initialization itself. */
|
||||
@ -8631,16 +8630,16 @@ expand_static_init (decl, init)
|
||||
the assignment to TEMP into a single expression, ensuring
|
||||
that when we call finish_expr_stmt the cleanups will not be
|
||||
run until after TEMP is set to 1. */
|
||||
temp_init = build_modify_expr (temp, NOP_EXPR, integer_one_node);
|
||||
guard_init = set_guard (guard);
|
||||
if (assignment)
|
||||
{
|
||||
assignment = tree_cons (NULL_TREE, assignment,
|
||||
build_tree_list (NULL_TREE,
|
||||
temp_init));
|
||||
guard_init));
|
||||
assignment = build_compound_expr (assignment);
|
||||
}
|
||||
else
|
||||
assignment = temp_init;
|
||||
assignment = guard_init;
|
||||
finish_expr_stmt (assignment);
|
||||
|
||||
/* Use atexit to register a function for destroying this static
|
||||
|
216
gcc/cp/decl2.c
216
gcc/cp/decl2.c
@ -62,7 +62,6 @@ typedef struct priority_info_s {
|
||||
int destructions_p;
|
||||
} *priority_info;
|
||||
|
||||
static tree get_sentry PARAMS ((tree));
|
||||
static void mark_vtable_entries PARAMS ((tree));
|
||||
static void grok_function_init PARAMS ((tree, tree));
|
||||
static int finish_vtable_vardecl PARAMS ((tree *, void *));
|
||||
@ -95,6 +94,7 @@ static void write_out_vars PARAMS ((tree));
|
||||
static void import_export_class PARAMS ((tree));
|
||||
static tree key_method PARAMS ((tree));
|
||||
static int compare_options PARAMS ((const PTR, const PTR));
|
||||
static tree get_guard_bits PARAMS ((tree));
|
||||
|
||||
extern int current_class_depth;
|
||||
|
||||
@ -2098,32 +2098,24 @@ defer_fn (fn)
|
||||
/* Hand off a unique name which can be used for variable we don't really
|
||||
want to know about anyway, for example, the anonymous variables which
|
||||
are needed to make references work. Declare this thing so we can use it.
|
||||
The variable created will be of type TYPE.
|
||||
|
||||
STATICP is nonzero if this variable should be static. */
|
||||
The variable created will be of type TYPE, and will have internal
|
||||
linkage. */
|
||||
|
||||
tree
|
||||
get_temp_name (type, staticp)
|
||||
get_temp_name (type)
|
||||
tree type;
|
||||
int staticp;
|
||||
{
|
||||
char buf[sizeof (AUTO_TEMP_FORMAT) + 20];
|
||||
tree decl;
|
||||
int toplev = toplevel_bindings_p ();
|
||||
|
||||
if (toplev || staticp)
|
||||
{
|
||||
sprintf (buf, AUTO_TEMP_FORMAT, global_temp_name_counter++);
|
||||
decl = pushdecl_top_level (build_decl (VAR_DECL, get_identifier (buf), type));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (buf, AUTO_TEMP_FORMAT, temp_name_counter++);
|
||||
decl = pushdecl (build_decl (VAR_DECL, get_identifier (buf), type));
|
||||
}
|
||||
TREE_USED (decl) = 1;
|
||||
TREE_STATIC (decl) = staticp;
|
||||
sprintf (buf, AUTO_TEMP_FORMAT, global_temp_name_counter++);
|
||||
decl = build_decl (VAR_DECL, get_identifier (buf), type);
|
||||
DECL_ARTIFICIAL (decl) = 1;
|
||||
TREE_USED (decl) = 1;
|
||||
TREE_STATIC (decl) = 1;
|
||||
|
||||
decl = pushdecl_top_level (decl);
|
||||
|
||||
/* If this is a local variable, then lay out its rtl now.
|
||||
Otherwise, callers of this function are responsible for dealing
|
||||
@ -2866,37 +2858,111 @@ build_cleanup (decl)
|
||||
return temp;
|
||||
}
|
||||
|
||||
/* Returns the initialization guard variable for the non-local
|
||||
variable DECL. */
|
||||
/* Returns the initialization guard variable for the variable DECL,
|
||||
which has static storage duration. */
|
||||
|
||||
static tree
|
||||
get_sentry (decl)
|
||||
tree
|
||||
get_guard (decl)
|
||||
tree decl;
|
||||
{
|
||||
tree sname;
|
||||
tree sentry;
|
||||
tree guard;
|
||||
|
||||
/* For a local variable, under the old ABI, we do not try to get a
|
||||
unique mangled name for the DECL. */
|
||||
if (!flag_new_abi && !DECL_NAMESPACE_SCOPE_P (decl))
|
||||
{
|
||||
guard = get_temp_name (integer_type_node);
|
||||
rest_of_decl_compilation (guard, NULL_PTR, 0, 0);
|
||||
}
|
||||
|
||||
if (!flag_new_abi)
|
||||
/* For struct X foo __attribute__((weak)), there is a counter
|
||||
__snfoo. Since base is already an assembler name, sname should
|
||||
be globally unique */
|
||||
sname = get_id_2 ("__sn", DECL_ASSEMBLER_NAME (decl));
|
||||
else
|
||||
sname = mangle_guard_variable (decl);
|
||||
|
||||
/* For struct X foo __attribute__((weak)), there is a counter
|
||||
__snfoo. Since base is already an assembler name, sname should
|
||||
be globally unique */
|
||||
sentry = IDENTIFIER_GLOBAL_VALUE (sname);
|
||||
if (! sentry)
|
||||
guard = IDENTIFIER_GLOBAL_VALUE (sname);
|
||||
if (! guard)
|
||||
{
|
||||
sentry = build_decl (VAR_DECL, sname, integer_type_node);
|
||||
TREE_PUBLIC (sentry) = 1;
|
||||
DECL_ARTIFICIAL (sentry) = 1;
|
||||
TREE_STATIC (sentry) = 1;
|
||||
TREE_USED (sentry) = 1;
|
||||
DECL_COMMON (sentry) = 1;
|
||||
pushdecl_top_level (sentry);
|
||||
cp_finish_decl (sentry, NULL_TREE, NULL_TREE, 0);
|
||||
tree guard_type;
|
||||
|
||||
/* Under the new ABI, we use a type that is big enough to
|
||||
contain a mutex as well as an integer counter. */
|
||||
if (flag_new_abi)
|
||||
guard_type = long_long_integer_type_node;
|
||||
else
|
||||
guard_type = integer_type_node;
|
||||
|
||||
guard = build_decl (VAR_DECL, sname, guard_type);
|
||||
TREE_PUBLIC (guard) = 1;
|
||||
DECL_ARTIFICIAL (guard) = 1;
|
||||
TREE_STATIC (guard) = 1;
|
||||
TREE_USED (guard) = 1;
|
||||
DECL_COMMON (guard) = 1;
|
||||
pushdecl_top_level (guard);
|
||||
cp_finish_decl (guard, NULL_TREE, NULL_TREE, 0);
|
||||
}
|
||||
return sentry;
|
||||
return guard;
|
||||
}
|
||||
|
||||
/* Return those bits of the GUARD variable that should be set when the
|
||||
guarded entity is actually initialized. */
|
||||
|
||||
static tree
|
||||
get_guard_bits (guard)
|
||||
tree guard;
|
||||
{
|
||||
if (!flag_new_abi)
|
||||
return guard;
|
||||
|
||||
/* Under the new ABI, we only set the first byte of the guard,
|
||||
in order to leave room for a mutex in the high-order bits. */
|
||||
guard = build1 (ADDR_EXPR,
|
||||
build_pointer_type (TREE_TYPE (guard)),
|
||||
guard);
|
||||
guard = build1 (NOP_EXPR,
|
||||
build_pointer_type (char_type_node),
|
||||
guard);
|
||||
guard = build1 (INDIRECT_REF, char_type_node, guard);
|
||||
|
||||
return guard;
|
||||
}
|
||||
|
||||
/* Return an expression which determines whether or not the GUARD
|
||||
variable has already been initialized. */
|
||||
|
||||
tree
|
||||
get_guard_cond (guard)
|
||||
tree guard;
|
||||
{
|
||||
tree guard_value;
|
||||
|
||||
/* Check to see if the GUARD is zero. */
|
||||
guard = get_guard_bits (guard);
|
||||
guard_value = integer_zero_node;
|
||||
if (!same_type_p (TREE_TYPE (guard_value), TREE_TYPE (guard)))
|
||||
guard_value = convert (TREE_TYPE (guard), guard_value);
|
||||
return cp_build_binary_op (EQ_EXPR, guard, guard_value);
|
||||
}
|
||||
|
||||
/* Return an expression which sets the GUARD variable, indicating that
|
||||
the variable being guarded has been initialized. */
|
||||
|
||||
tree
|
||||
set_guard (guard)
|
||||
tree guard;
|
||||
{
|
||||
tree guard_init;
|
||||
|
||||
/* Set the GUARD to one. */
|
||||
guard = get_guard_bits (guard);
|
||||
guard_init = integer_one_node;
|
||||
if (!same_type_p (TREE_TYPE (guard_init), TREE_TYPE (guard)))
|
||||
guard_init = convert (TREE_TYPE (guard), guard_init);
|
||||
return build_modify_expr (guard, NOP_EXPR, guard_init);
|
||||
}
|
||||
|
||||
/* Start the process of running a particular set of global constructors
|
||||
@ -3201,9 +3267,10 @@ start_static_initialization_or_destruction (decl, initp)
|
||||
tree decl;
|
||||
int initp;
|
||||
{
|
||||
tree sentry_if_stmt = NULL_TREE;
|
||||
tree guard_if_stmt = NULL_TREE;
|
||||
int priority;
|
||||
tree cond;
|
||||
tree guard;
|
||||
tree init_cond;
|
||||
priority_info pi;
|
||||
|
||||
@ -3247,7 +3314,7 @@ start_static_initialization_or_destruction (decl, initp)
|
||||
|
||||
/* Conditionalize this initialization on being in the right priority
|
||||
and being initializing/finalizing appropriately. */
|
||||
sentry_if_stmt = begin_if_stmt ();
|
||||
guard_if_stmt = begin_if_stmt ();
|
||||
cond = cp_build_binary_op (EQ_EXPR,
|
||||
priority_decl,
|
||||
build_int_2 (priority, 0));
|
||||
@ -3257,7 +3324,9 @@ start_static_initialization_or_destruction (decl, initp)
|
||||
init_cond);
|
||||
cond = cp_build_binary_op (TRUTH_ANDIF_EXPR, cond, init_cond);
|
||||
|
||||
/* We need a sentry if this is an object with external linkage that
|
||||
/* Assume we don't need a guard. */
|
||||
guard = NULL_TREE;
|
||||
/* We need a guard if this is an object with external linkage that
|
||||
might be initialized in more than one place. (For example, a
|
||||
static data member of a template, when the data member requires
|
||||
construction.) */
|
||||
@ -3265,47 +3334,60 @@ start_static_initialization_or_destruction (decl, initp)
|
||||
|| DECL_ONE_ONLY (decl)
|
||||
|| DECL_WEAK (decl)))
|
||||
{
|
||||
tree sentry;
|
||||
tree sentry_cond;
|
||||
tree guard_cond;
|
||||
|
||||
sentry = get_sentry (decl);
|
||||
guard = get_guard (decl);
|
||||
|
||||
/* We do initializations only if the SENTRY is zero, i.e., if we
|
||||
are the first to initialize the variable. We do destructions
|
||||
only if the SENTRY is one, i.e., if we are the last to
|
||||
destroy the variable. */
|
||||
if (initp)
|
||||
sentry_cond
|
||||
/* When using __cxa_atexit, we just check the GUARD as we would
|
||||
for a local static. */
|
||||
if (flag_use_cxa_atexit)
|
||||
{
|
||||
/* When using __cxa_atexit, we never try to destroy
|
||||
anything from a static destructor. */
|
||||
my_friendly_assert (initp, 20000629);
|
||||
guard_cond = get_guard_cond (guard);
|
||||
}
|
||||
/* Under the old ABI, e do initializations only if the GUARD is
|
||||
zero, i.e., if we are the first to initialize the variable.
|
||||
We do destructions only if the GUARD is one, i.e., if we are
|
||||
the last to destroy the variable. */
|
||||
else if (initp)
|
||||
guard_cond
|
||||
= cp_build_binary_op (EQ_EXPR,
|
||||
build_unary_op (PREINCREMENT_EXPR,
|
||||
sentry,
|
||||
guard,
|
||||
/*noconvert=*/1),
|
||||
integer_one_node);
|
||||
else
|
||||
sentry_cond
|
||||
guard_cond
|
||||
= cp_build_binary_op (EQ_EXPR,
|
||||
build_unary_op (PREDECREMENT_EXPR,
|
||||
sentry,
|
||||
guard,
|
||||
/*noconvert=*/1),
|
||||
integer_zero_node);
|
||||
|
||||
cond = cp_build_binary_op (TRUTH_ANDIF_EXPR, cond, sentry_cond);
|
||||
cond = cp_build_binary_op (TRUTH_ANDIF_EXPR, cond, guard_cond);
|
||||
}
|
||||
|
||||
finish_if_stmt_cond (cond, sentry_if_stmt);
|
||||
finish_if_stmt_cond (cond, guard_if_stmt);
|
||||
|
||||
return sentry_if_stmt;
|
||||
/* Under the new ABI, we have not already set the GUARD, so we must
|
||||
do so now. */
|
||||
if (guard && initp && flag_new_abi)
|
||||
finish_expr_stmt (set_guard (guard));
|
||||
|
||||
return guard_if_stmt;
|
||||
}
|
||||
|
||||
/* We've just finished generating code to do an initialization or
|
||||
finalization. SENTRY_IF_STMT is the if-statement we used to guard
|
||||
finalization. GUARD_IF_STMT is the if-statement we used to guard
|
||||
the initialization. */
|
||||
|
||||
static void
|
||||
finish_static_initialization_or_destruction (sentry_if_stmt)
|
||||
tree sentry_if_stmt;
|
||||
finish_static_initialization_or_destruction (guard_if_stmt)
|
||||
tree guard_if_stmt;
|
||||
{
|
||||
finish_then_clause (sentry_if_stmt);
|
||||
finish_then_clause (guard_if_stmt);
|
||||
finish_if_stmt ();
|
||||
|
||||
/* Now that we're done with DECL we don't need to pretend to be a
|
||||
@ -3316,7 +3398,7 @@ finish_static_initialization_or_destruction (sentry_if_stmt)
|
||||
|
||||
/* Generate code to do the static initialization of DECL. The
|
||||
initialization is INIT. If DECL may be initialized more than once
|
||||
in different object files, SENTRY is the guard variable to
|
||||
in different object files, GUARD is the guard variable to
|
||||
check. PRIORITY is the priority for the initialization. */
|
||||
|
||||
static void
|
||||
@ -3325,10 +3407,10 @@ do_static_initialization (decl, init)
|
||||
tree init;
|
||||
{
|
||||
tree expr;
|
||||
tree sentry_if_stmt;
|
||||
tree guard_if_stmt;
|
||||
|
||||
/* Set up for the initialization. */
|
||||
sentry_if_stmt
|
||||
guard_if_stmt
|
||||
= start_static_initialization_or_destruction (decl,
|
||||
/*initp=*/1);
|
||||
|
||||
@ -3353,11 +3435,11 @@ do_static_initialization (decl, init)
|
||||
register_dtor_fn (decl);
|
||||
|
||||
/* Finsh up. */
|
||||
finish_static_initialization_or_destruction (sentry_if_stmt);
|
||||
finish_static_initialization_or_destruction (guard_if_stmt);
|
||||
}
|
||||
|
||||
/* Generate code to do the static destruction of DECL. If DECL may be
|
||||
initialized more than once in different object files, SENTRY is the
|
||||
initialized more than once in different object files, GUARD is the
|
||||
guard variable to check. PRIORITY is the priority for the
|
||||
destruction. */
|
||||
|
||||
@ -3365,7 +3447,7 @@ static void
|
||||
do_static_destruction (decl)
|
||||
tree decl;
|
||||
{
|
||||
tree sentry_if_stmt;
|
||||
tree guard_if_stmt;
|
||||
|
||||
/* If we're using __cxa_atexit, then destructors are registered
|
||||
immediately after objects are initialized. */
|
||||
@ -3376,10 +3458,10 @@ do_static_destruction (decl)
|
||||
return;
|
||||
|
||||
/* Actually do the destruction. */
|
||||
sentry_if_stmt = start_static_initialization_or_destruction (decl,
|
||||
guard_if_stmt = start_static_initialization_or_destruction (decl,
|
||||
/*initp=*/0);
|
||||
finish_expr_stmt (build_cleanup (decl));
|
||||
finish_static_initialization_or_destruction (sentry_if_stmt);
|
||||
finish_static_initialization_or_destruction (guard_if_stmt);
|
||||
}
|
||||
|
||||
/* VARS is a list of variables with static storage duration which may
|
||||
|
@ -2729,6 +2729,8 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
|
||||
return cp_convert (void_type_node, body);
|
||||
}
|
||||
|
||||
/* Create an unnamed variable of the indicated TYPE. */
|
||||
|
||||
tree
|
||||
create_temporary_var (type)
|
||||
tree type;
|
||||
|
Loading…
Reference in New Issue
Block a user