diff options
Diffstat (limited to 'gcc/c/c-decl.c')
-rw-r--r-- | gcc/c/c-decl.c | 176 |
1 files changed, 174 insertions, 2 deletions
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index f263348..0554e72 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -147,6 +147,9 @@ static bool undef_nested_function; enum machine_mode c_default_pointer_mode = VOIDmode; +/* If non-zero, implicit "omp declare target" attribute is added into the + attribute lists. */ +int current_omp_declare_target_attribute; /* Each c_binding structure describes one binding of an identifier to a decl. All the decls in a scope - irrespective of namespace - are @@ -3971,6 +3974,35 @@ groktypename (struct c_type_name *type_name, tree *expr, return type; } +/* Wrapper for decl_attributes that adds some implicit attributes + to VAR_DECLs or FUNCTION_DECLs. */ + +static tree +c_decl_attributes (tree *node, tree attributes, int flags) +{ + /* Add implicit "omp declare target" attribute if requested. */ + if (current_omp_declare_target_attribute + && ((TREE_CODE (*node) == VAR_DECL && TREE_STATIC (*node)) + || TREE_CODE (*node) == FUNCTION_DECL)) + { + if (TREE_CODE (*node) == VAR_DECL + && ((DECL_CONTEXT (*node) + && TREE_CODE (DECL_CONTEXT (*node)) == FUNCTION_DECL) + || (current_function_decl && !DECL_EXTERNAL (*node)))) + error ("%q+D in block scope inside of declare target directive", + *node); + else if (TREE_CODE (*node) == VAR_DECL + && !COMPLETE_TYPE_P (TREE_TYPE (*node))) + error ("%q+D in declare target directive does not have mappable type", + *node); + else + attributes = tree_cons (get_identifier ("omp declare target"), + NULL_TREE, attributes); + } + return decl_attributes (node, attributes, flags); +} + + /* Decode a declarator in an ordinary declaration or data definition. This is called as soon as the type information and variable name have been parsed, before parsing the initializer if any. @@ -4105,7 +4137,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, DECL_COMMON (decl) = 1; /* Set attributes here so if duplicate decl, will have proper attributes. */ - decl_attributes (&decl, attributes, 0); + c_decl_attributes (&decl, attributes, 0); /* Handle gnu_inline attribute. */ if (declspecs->inline_p @@ -7727,7 +7759,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, loc = DECL_SOURCE_LOCATION (decl1); - decl_attributes (&decl1, attributes, 0); + c_decl_attributes (&decl1, attributes, 0); if (DECL_DECLARED_INLINE_P (decl1) && DECL_UNINLINABLE (decl1) @@ -8324,6 +8356,44 @@ store_parm_decls (void) if (arg_info->pending_sizes) add_stmt (arg_info->pending_sizes); } + +/* Store PARM_DECLs in PARMS into scope temporarily. Used for + c_finish_omp_declare_simd for function prototypes. No diagnostics + should be done. */ + +void +temp_store_parm_decls (tree fndecl, tree parms) +{ + push_scope (); + for (tree p = parms; p; p = DECL_CHAIN (p)) + { + DECL_CONTEXT (p) = fndecl; + if (DECL_NAME (p)) + bind (DECL_NAME (p), p, current_scope, + /*invisible=*/false, /*nested=*/false, + UNKNOWN_LOCATION); + } +} + +/* Undo what temp_store_parm_decls did. */ + +void +temp_pop_parm_decls (void) +{ + /* Clear all bindings in this temporary scope, so that + pop_scope doesn't create a BLOCK. */ + struct c_binding *b = current_scope->bindings; + current_scope->bindings = NULL; + for (; b; b = free_binding_and_advance (b)) + { + gcc_assert (TREE_CODE (b->decl) == PARM_DECL); + gcc_assert (I_SYMBOL_BINDING (b->id) == b); + I_SYMBOL_BINDING (b->id) = b->shadowed; + if (b->shadowed && b->shadowed->u.type) + TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type; + } + pop_scope (); +} /* Finish up a function declaration and compile that function @@ -10158,4 +10228,106 @@ c_register_addr_space (const char *word, addr_space_t as) ridpointers [rid] = id; } +/* Return identifier to look up for omp declare reduction. */ + +tree +c_omp_reduction_id (enum tree_code reduction_code, tree reduction_id) +{ + const char *p = NULL; + switch (reduction_code) + { + case PLUS_EXPR: p = "+"; break; + case MULT_EXPR: p = "*"; break; + case MINUS_EXPR: p = "-"; break; + case BIT_AND_EXPR: p = "&"; break; + case BIT_XOR_EXPR: p = "^"; break; + case BIT_IOR_EXPR: p = "|"; break; + case TRUTH_ANDIF_EXPR: p = "&&"; break; + case TRUTH_ORIF_EXPR: p = "||"; break; + case MIN_EXPR: p = "min"; break; + case MAX_EXPR: p = "max"; break; + default: + break; + } + + if (p == NULL) + { + if (TREE_CODE (reduction_id) != IDENTIFIER_NODE) + return error_mark_node; + p = IDENTIFIER_POINTER (reduction_id); + } + + const char prefix[] = "omp declare reduction "; + size_t lenp = sizeof (prefix); + size_t len = strlen (p); + char *name = XALLOCAVEC (char, lenp + len); + memcpy (name, prefix, lenp - 1); + memcpy (name + lenp - 1, p, len + 1); + return get_identifier (name); +} + +/* Lookup REDUCTION_ID in the current scope, or create an artificial + VAR_DECL, bind it into the current scope and return it. */ + +tree +c_omp_reduction_decl (tree reduction_id) +{ + struct c_binding *b = I_SYMBOL_BINDING (reduction_id); + if (b != NULL && B_IN_CURRENT_SCOPE (b)) + return b->decl; + + tree decl = build_decl (BUILTINS_LOCATION, VAR_DECL, + reduction_id, integer_type_node); + DECL_ARTIFICIAL (decl) = 1; + DECL_EXTERNAL (decl) = 1; + TREE_STATIC (decl) = 1; + TREE_PUBLIC (decl) = 0; + bind (reduction_id, decl, current_scope, true, false, BUILTINS_LOCATION); + return decl; +} + +/* Lookup REDUCTION_ID in the first scope where it has entry for TYPE. */ + +tree +c_omp_reduction_lookup (tree reduction_id, tree type) +{ + struct c_binding *b = I_SYMBOL_BINDING (reduction_id); + while (b) + { + tree t; + for (t = DECL_INITIAL (b->decl); t; t = TREE_CHAIN (t)) + if (comptypes (TREE_PURPOSE (t), type)) + return TREE_VALUE (t); + b = b->shadowed; + } + return error_mark_node; +} + +/* Helper function called via walk_tree, to diagnose invalid + #pragma omp declare reduction combiners or initializers. */ + +tree +c_check_omp_declare_reduction_r (tree *tp, int *, void *data) +{ + tree *vars = (tree *) data; + if (SSA_VAR_P (*tp) + && !DECL_ARTIFICIAL (*tp) + && *tp != vars[0] + && *tp != vars[1]) + { + location_t loc = DECL_SOURCE_LOCATION (vars[0]); + if (strcmp (IDENTIFIER_POINTER (DECL_NAME (vars[0])), "omp_out") == 0) + error_at (loc, "%<#pragma omp declare reduction%> combiner refers to " + "variable %qD which is not %<omp_out%> nor %<omp_in%>", + *tp); + else + error_at (loc, "%<#pragma omp declare reduction%> initializer refers " + "to variable %qD which is not %<omp_priv%> nor " + "%<omp_orig%>", + *tp); + return *tp; + } + return NULL_TREE; +} + #include "gt-c-c-decl.h" |