diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ef878797494..46544015e80 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +2000-06-30 Mark Mitchell + + * 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 * cp-tree.h (flag_const_strings): Remove. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f98c5ea225e..fb37a3d39ca 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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)); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index e3e86923875..2cbbd59d476 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -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)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index dea99029b09..ae933abfc44 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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 diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index f21187e92c9..c172d50dd22 100644 --- a/gcc/cp/decl2.c +++ b/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 diff --git a/gcc/cp/init.c b/gcc/cp/init.c index a78da11eca3..089559f1f86 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -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;