diff options
Diffstat (limited to 'gcc/cp/semantics.c')
-rw-r--r-- | gcc/cp/semantics.c | 1330 |
1 files changed, 1223 insertions, 107 deletions
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index c1f4330..8796b17 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -63,6 +63,12 @@ static tree maybe_convert_cond (tree); static tree finalize_nrv_r (tree *, int *, void *); static tree capture_decltype (tree); +/* Used for OpenMP non-static data member privatization. */ + +static hash_map<tree, tree> *omp_private_member_map; +static vec<tree> omp_private_member_vec; +static bool omp_private_member_ignore_next; + /* Deferred Access Checking Overview --------------------------------- @@ -1704,6 +1710,8 @@ tree finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) { gcc_assert (TREE_CODE (decl) == FIELD_DECL); + bool try_omp_private = !object && omp_private_member_map; + tree ret; if (!object) { @@ -1755,17 +1763,17 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) type = cp_build_qualified_type (type, quals); } - return (convert_from_reference + ret = (convert_from_reference (build_min (COMPONENT_REF, type, object, decl, NULL_TREE))); } /* If PROCESSING_TEMPLATE_DECL is nonzero here, then QUALIFYING_SCOPE is also non-null. Wrap this in a SCOPE_REF for now. */ else if (processing_template_decl) - return build_qualified_name (TREE_TYPE (decl), - qualifying_scope, - decl, - /*template_p=*/false); + ret = build_qualified_name (TREE_TYPE (decl), + qualifying_scope, + decl, + /*template_p=*/false); else { tree access_type = TREE_TYPE (object); @@ -1782,11 +1790,18 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) &binfo); } - return build_class_member_access_expr (object, decl, - /*access_path=*/NULL_TREE, - /*preserve_reference=*/false, - tf_warning_or_error); + ret = build_class_member_access_expr (object, decl, + /*access_path=*/NULL_TREE, + /*preserve_reference=*/false, + tf_warning_or_error); } + if (try_omp_private) + { + tree *v = omp_private_member_map->get (decl); + if (v) + ret = convert_from_reference (*v); + } + return ret; } /* If we are currently parsing a template and we encountered a typedef @@ -4252,6 +4267,91 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, return errorcount != save_errorcount; } +/* If DECL is DECL_OMP_PRIVATIZED_MEMBER, return corresponding + FIELD_DECL, otherwise return DECL itself. */ + +static tree +omp_clause_decl_field (tree decl) +{ + if (VAR_P (decl) + && DECL_HAS_VALUE_EXPR_P (decl) + && DECL_ARTIFICIAL (decl) + && DECL_LANG_SPECIFIC (decl) + && DECL_OMP_PRIVATIZED_MEMBER (decl)) + { + tree f = DECL_VALUE_EXPR (decl); + if (TREE_CODE (f) == INDIRECT_REF) + f = TREE_OPERAND (f, 0); + if (TREE_CODE (f) == COMPONENT_REF) + { + f = TREE_OPERAND (f, 1); + gcc_assert (TREE_CODE (f) == FIELD_DECL); + return f; + } + } + return NULL_TREE; +} + +/* Adjust DECL if needed for printing using %qE. */ + +static tree +omp_clause_printable_decl (tree decl) +{ + tree t = omp_clause_decl_field (decl); + if (t) + return t; + return decl; +} + +/* For a FIELD_DECL F and corresponding DECL_OMP_PRIVATIZED_MEMBER + VAR_DECL T that doesn't need a DECL_EXPR added, record it for + privatization. */ + +static void +omp_note_field_privatization (tree f, tree t) +{ + if (!omp_private_member_map) + omp_private_member_map = new hash_map<tree, tree>; + tree &v = omp_private_member_map->get_or_insert (f); + if (v == NULL_TREE) + { + v = t; + omp_private_member_vec.safe_push (f); + /* Signal that we don't want to create DECL_EXPR for this dummy var. */ + omp_private_member_vec.safe_push (integer_zero_node); + } +} + +/* Privatize FIELD_DECL T, return corresponding DECL_OMP_PRIVATIZED_MEMBER + dummy VAR_DECL. */ + +tree +omp_privatize_field (tree t) +{ + tree m = finish_non_static_data_member (t, NULL_TREE, NULL_TREE); + if (m == error_mark_node) + return error_mark_node; + if (!omp_private_member_map) + omp_private_member_map = new hash_map<tree, tree>; + if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) + { + gcc_assert (TREE_CODE (m) == INDIRECT_REF); + m = TREE_OPERAND (m, 0); + } + tree &v = omp_private_member_map->get_or_insert (t); + if (v == NULL_TREE) + { + v = create_temporary_var (TREE_TYPE (m)); + if (!DECL_LANG_SPECIFIC (v)) + retrofit_lang_decl (v); + DECL_OMP_PRIVATIZED_MEMBER (v) = 1; + SET_DECL_VALUE_EXPR (v, m); + DECL_HAS_VALUE_EXPR_P (v) = 1; + omp_private_member_vec.safe_push (t); + } + return v; +} + /* Helper function for handle_omp_array_sections. Called recursively to handle multiple array-section-subscripts. C is the clause, T current expression (initially OMP_CLAUSE_DECL), which is either @@ -4266,7 +4366,7 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, map(a[:b][2:1][:c][:2][:d][e:f][2:5]) FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c] all are or may have length of 1, array-section-subscript [:2] is the - first one knonwn not to have length 1. For array-section-subscript + first one known not to have length 1. For array-section-subscript <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above @@ -4274,13 +4374,43 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, static tree handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, - bool &maybe_zero_len, unsigned int &first_non_one) + bool &maybe_zero_len, unsigned int &first_non_one, + bool is_omp) { tree ret, low_bound, length, type; if (TREE_CODE (t) != TREE_LIST) { if (error_operand_p (t)) return error_mark_node; + if (REFERENCE_REF_P (t) + && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF) + t = TREE_OPERAND (t, 0); + ret = t; + if (TREE_CODE (t) == COMPONENT_REF + && is_omp + && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM) + && !type_dependent_expression_p (t)) + { + if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "bit-field %qE in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + while (TREE_CODE (t) == COMPONENT_REF) + { + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is a member of a union", t); + return error_mark_node; + } + t = TREE_OPERAND (t, 0); + } + } if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { if (processing_template_decl) @@ -4295,6 +4425,15 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); return error_mark_node; } + else if (TREE_CODE (t) == PARM_DECL + && DECL_ARTIFICIAL (t) + && DECL_NAME (t) == this_identifier) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + return error_mark_node; + } else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && VAR_P (t) && CP_DECL_THREAD_LOCAL_P (t)) { @@ -4303,14 +4442,17 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); return error_mark_node; } - if (type_dependent_expression_p (t)) + if (type_dependent_expression_p (ret)) return NULL_TREE; - t = convert_from_reference (t); - return t; + ret = convert_from_reference (ret); + return ret; } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && TREE_CODE (TREE_CHAIN (t)) == FIELD_DECL) + TREE_CHAIN (t) = omp_privatize_field (TREE_CHAIN (t)); ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types, - maybe_zero_len, first_non_one); + maybe_zero_len, first_non_one, is_omp); if (ret == error_mark_node || ret == NULL_TREE) return ret; @@ -4358,11 +4500,32 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, if (length != NULL_TREE) { if (!integer_nonzerop (length)) - maybe_zero_len = true; + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + if (integer_zerop (length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + else + maybe_zero_len = true; + } if (first_non_one == types.length () && (TREE_CODE (length) != INTEGER_CST || integer_onep (length))) first_non_one++; } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && !integer_zerop (low_bound)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<reduction%> array section has to be zero-based"); + return error_mark_node; + } if (TREE_CODE (type) == ARRAY_TYPE) { if (length == NULL_TREE @@ -4410,7 +4573,17 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, return error_mark_node; } if (tree_int_cst_equal (size, low_bound)) - maybe_zero_len = true; + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + maybe_zero_len = true; + } else if (length == NULL_TREE && first_non_one == types.length () && tree_int_cst_equal @@ -4420,7 +4593,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, } else if (length == NULL_TREE) { - maybe_zero_len = true; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + maybe_zero_len = true; if (first_non_one == types.length ()) first_non_one++; } @@ -4454,7 +4629,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, } else if (length == NULL_TREE) { - maybe_zero_len = true; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + maybe_zero_len = true; if (first_non_one == types.length ()) first_non_one++; } @@ -4478,6 +4655,15 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, "for pointer type length expression must be specified"); return error_mark_node; } + if (length != NULL_TREE + && TREE_CODE (length) == INTEGER_CST + && tree_int_cst_sgn (length) == -1) + { + error_at (OMP_CLAUSE_LOCATION (c), + "negative length in array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } /* If there is a pointer type anywhere but in the very first array-section-subscript, the array section can't be contiguous. */ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND @@ -4511,13 +4697,14 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, /* Handle array sections for clause C. */ static bool -handle_omp_array_sections (tree c) +handle_omp_array_sections (tree c, bool is_omp) { bool maybe_zero_len = false; unsigned int first_non_one = 0; - auto_vec<tree> types; + auto_vec<tree, 10> types; tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, - maybe_zero_len, first_non_one); + maybe_zero_len, first_non_one, + is_omp); if (first == error_mark_node) return true; if (first == NULL_TREE) @@ -4619,7 +4806,9 @@ handle_omp_array_sections (tree c) { tree l; - if (i > first_non_one && length && integer_nonzerop (length)) + if (i > first_non_one + && ((length && integer_nonzerop (length)) + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)) continue; if (length) l = fold_convert (sizetype, length); @@ -4644,6 +4833,12 @@ handle_omp_array_sections (tree c) else if (size == NULL_TREE) { size = size_in_bytes (TREE_TYPE (types[i])); + tree eltype = TREE_TYPE (types[num - 1]); + while (TREE_CODE (eltype) == ARRAY_TYPE) + eltype = TREE_TYPE (eltype); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + size = size_binop (EXACT_DIV_EXPR, size, + size_in_bytes (eltype)); size = size_binop (MULT_EXPR, size, l); if (condition) size = fold_build3 (COND_EXPR, sizetype, condition, @@ -4657,14 +4852,52 @@ handle_omp_array_sections (tree c) { if (side_effects) size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + size = size_binop (MINUS_EXPR, size, size_one_node); + tree index_type = build_index_type (size); + tree eltype = TREE_TYPE (first); + while (TREE_CODE (eltype) == ARRAY_TYPE) + eltype = TREE_TYPE (eltype); + tree type = build_array_type (eltype, index_type); + tree ptype = build_pointer_type (eltype); + if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE + && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (t)))) + t = convert_from_reference (t); + else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + t = build_fold_addr_expr (t); + t = build2 (MEM_REF, type, t, build_int_cst (ptype, 0)); + OMP_CLAUSE_DECL (c) = t; + return false; + } OMP_CLAUSE_DECL (c) = first; OMP_CLAUSE_SIZE (c) = size; - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP + || (TREE_CODE (t) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)) return false; + if (is_omp) + switch (OMP_CLAUSE_MAP_KIND (c)) + { + case GOMP_MAP_ALLOC: + case GOMP_MAP_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1; + break; + default: + break; + } tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER); - if (!cxx_mark_addressable (t)) + OMP_CLAUSE_SET_MAP_KIND (c2, is_omp ? GOMP_MAP_FIRSTPRIVATE_POINTER + : GOMP_MAP_POINTER); + if (!is_omp && !cxx_mark_addressable (t)) return false; OMP_CLAUSE_DECL (c2) = t; t = build_fold_addr_expr (first); @@ -4682,7 +4915,8 @@ handle_omp_array_sections (tree c) OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); OMP_CLAUSE_CHAIN (c) = c2; ptr = OMP_CLAUSE_DECL (c2); - if (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE + if (!is_omp + && TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (ptr)))) { tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), @@ -5091,9 +5325,45 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) { tree t = OMP_CLAUSE_DECL (c); bool predefined = false; + if (TREE_CODE (t) == TREE_LIST) + { + gcc_assert (processing_template_decl); + return false; + } tree type = TREE_TYPE (t); + if (TREE_CODE (t) == MEM_REF) + type = TREE_TYPE (type); if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree oatype = type; + gcc_assert (TREE_CODE (t) != MEM_REF); + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + if (!processing_template_decl) + { + t = require_complete_type (t); + if (t == error_mark_node) + return true; + tree size = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (oatype), + TYPE_SIZE_UNIT (type)); + if (integer_zerop (size)) + { + error ("%qE in %<reduction%> clause is a zero size array", + omp_clause_printable_decl (t)); + return true; + } + size = size_binop (MINUS_EXPR, size, size_one_node); + tree index_type = build_index_type (size); + tree atype = build_array_type (type, index_type); + tree ptype = build_pointer_type (type); + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + t = build_fold_addr_expr (t); + t = build2 (MEM_REF, atype, t, build_int_cst (ptype, 0)); + OMP_CLAUSE_DECL (c) = t; + } + } if (type == error_mark_node) return true; else if (ARITHMETIC_TYPE_P (type)) @@ -5126,9 +5396,10 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) default: break; } - else if (TREE_CODE (type) == ARRAY_TYPE || TYPE_READONLY (type)) + else if (TYPE_READONLY (type)) { - error ("%qE has invalid type for %<reduction%>", t); + error ("%qE has const type for %<reduction%>", + omp_clause_printable_decl (t)); return true; } else if (!processing_template_decl) @@ -5149,9 +5420,7 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) tree id = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); - type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); - if (TREE_CODE (type) == REFERENCE_TYPE) - type = TREE_TYPE (type); + type = TYPE_MAIN_VARIANT (type); OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE; if (id == NULL_TREE) id = omp_reduction_id (OMP_CLAUSE_REDUCTION_CODE (c), @@ -5169,7 +5438,7 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) if (TREE_CODE (body) == STATEMENT_LIST) { tree_stmt_iterator tsi; - tree placeholder = NULL_TREE; + tree placeholder = NULL_TREE, decl_placeholder = NULL_TREE; int i; tree stmts[7]; tree atype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (id))); @@ -5190,14 +5459,24 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) DECL_ARTIFICIAL (placeholder) = 1; DECL_IGNORED_P (placeholder) = 1; OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder; + if (TREE_CODE (t) == MEM_REF) + { + decl_placeholder = build_lang_decl (VAR_DECL, NULL_TREE, + type); + DECL_ARTIFICIAL (decl_placeholder) = 1; + DECL_IGNORED_P (decl_placeholder) = 1; + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) = decl_placeholder; + } if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[0]))) cxx_mark_addressable (placeholder); if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[1])) && TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) != REFERENCE_TYPE) - cxx_mark_addressable (OMP_CLAUSE_DECL (c)); + cxx_mark_addressable (decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c)); tree omp_out = placeholder; - tree omp_in = convert_from_reference (OMP_CLAUSE_DECL (c)); + tree omp_in = decl_placeholder ? decl_placeholder + : convert_from_reference (OMP_CLAUSE_DECL (c)); if (need_static_cast) { tree rtype = build_reference_type (atype); @@ -5219,10 +5498,12 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) gcc_assert (TREE_CODE (stmts[3]) == DECL_EXPR && TREE_CODE (stmts[4]) == DECL_EXPR); if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[3]))) - cxx_mark_addressable (OMP_CLAUSE_DECL (c)); + cxx_mark_addressable (decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c)); if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[4]))) cxx_mark_addressable (placeholder); - tree omp_priv = convert_from_reference (OMP_CLAUSE_DECL (c)); + tree omp_priv = decl_placeholder ? decl_placeholder + : convert_from_reference (OMP_CLAUSE_DECL (c)); tree omp_orig = placeholder; if (need_static_cast) { @@ -5261,7 +5542,8 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) else { tree init; - tree v = convert_from_reference (t); + tree v = decl_placeholder ? decl_placeholder + : convert_from_reference (t); if (AGGREGATE_TYPE_P (TREE_TYPE (v))) init = build_constructor (TREE_TYPE (v), NULL); else @@ -5276,9 +5558,85 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) *need_dtor = true; else { - error ("user defined reduction not found for %qD", t); + error ("user defined reduction not found for %qE", + omp_clause_printable_decl (t)); return true; } + if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF) + gcc_assert (TYPE_SIZE_UNIT (type) + && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST); + return false; +} + +/* Called from finish_struct_1. linear(this) or linear(this:step) + clauses might not be finalized yet because the class has been incomplete + when parsing #pragma omp declare simd methods. Fix those up now. */ + +void +finish_omp_declare_simd_methods (tree t) +{ + if (processing_template_decl) + return; + + for (tree x = TYPE_METHODS (t); x; x = DECL_CHAIN (x)) + { + if (TREE_CODE (TREE_TYPE (x)) != METHOD_TYPE) + continue; + tree ods = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (x)); + if (!ods || !TREE_VALUE (ods)) + continue; + for (tree c = TREE_VALUE (TREE_VALUE (ods)); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && integer_zerop (OMP_CLAUSE_DECL (c)) + && OMP_CLAUSE_LINEAR_STEP (c) + && TREE_CODE (TREE_TYPE (OMP_CLAUSE_LINEAR_STEP (c))) + == POINTER_TYPE) + { + tree s = OMP_CLAUSE_LINEAR_STEP (c); + s = fold_convert_loc (OMP_CLAUSE_LOCATION (c), sizetype, s); + s = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MULT_EXPR, + sizetype, s, TYPE_SIZE_UNIT (t)); + OMP_CLAUSE_LINEAR_STEP (c) = s; + } + } +} + +/* Adjust sink depend clause to take into account pointer offsets. + + Return TRUE if there was a problem processing the offset, and the + whole clause should be removed. */ + +static bool +cp_finish_omp_clause_depend_sink (tree sink_clause) +{ + tree t = OMP_CLAUSE_DECL (sink_clause); + gcc_assert (TREE_CODE (t) == TREE_LIST); + + /* Make sure we don't adjust things twice for templates. */ + if (processing_template_decl) + return false; + + for (; t; t = TREE_CHAIN (t)) + { + tree decl = TREE_VALUE (t); + if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE) + { + tree offset = TREE_PURPOSE (t); + bool neg = wi::neg_p ((wide_int) offset); + offset = fold_unary (ABS_EXPR, TREE_TYPE (offset), offset); + decl = mark_rvalue_use (decl); + decl = convert_from_reference (decl); + tree t2 = pointer_int_sum (OMP_CLAUSE_LOCATION (sink_clause), + neg ? MINUS_EXPR : PLUS_EXPR, + decl, offset); + t2 = fold_build2_loc (OMP_CLAUSE_LOCATION (sink_clause), + MINUS_EXPR, sizetype, t2, + decl); + if (t2 == error_mark_node) + return true; + TREE_PURPOSE (t) = t2; + } + } return false; } @@ -5286,11 +5644,12 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor) Remove any elements from the list that are invalid. */ tree -finish_omp_clauses (tree clauses) +finish_omp_clauses (tree clauses, bool allow_fields, bool declare_simd) { bitmap_head generic_head, firstprivate_head, lastprivate_head; - bitmap_head aligned_head; + bitmap_head aligned_head, map_head, map_field_head, generic_field_head; tree c, t, *pc; + tree safelen = NULL_TREE; bool branch_seen = false; bool copyprivate_seen = false; @@ -5299,35 +5658,93 @@ finish_omp_clauses (tree clauses) bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); bitmap_initialize (&aligned_head, &bitmap_default_obstack); + bitmap_initialize (&map_head, &bitmap_default_obstack); + bitmap_initialize (&map_field_head, &bitmap_default_obstack); + bitmap_initialize (&generic_field_head, &bitmap_default_obstack); for (pc = &clauses, c = clauses; c ; c = *pc) { bool remove = false; + bool field_ok = false; switch (OMP_CLAUSE_CODE (c)) { case OMP_CLAUSE_SHARED: goto check_dup_generic; case OMP_CLAUSE_PRIVATE: + field_ok = allow_fields; goto check_dup_generic; case OMP_CLAUSE_REDUCTION: + field_ok = allow_fields; + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c, allow_fields)) + { + remove = true; + break; + } + if (TREE_CODE (t) == TREE_LIST) + { + while (TREE_CODE (t) == TREE_LIST) + t = TREE_CHAIN (t); + } + else + { + gcc_assert (TREE_CODE (t) == MEM_REF); + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == ADDR_EXPR + || TREE_CODE (t) == INDIRECT_REF) + t = TREE_OPERAND (t, 0); + } + tree n = omp_clause_decl_field (t); + if (n) + t = n; + goto check_dup_generic_t; + } goto check_dup_generic; case OMP_CLAUSE_COPYPRIVATE: copyprivate_seen = true; + field_ok = allow_fields; goto check_dup_generic; case OMP_CLAUSE_COPYIN: goto check_dup_generic; case OMP_CLAUSE_LINEAR: + field_ok = allow_fields; t = OMP_CLAUSE_DECL (c); + if (!declare_simd + && OMP_CLAUSE_LINEAR_KIND (c) != OMP_CLAUSE_LINEAR_DEFAULT) + { + error_at (OMP_CLAUSE_LOCATION (c), + "modifier should not be specified in %<linear%> " + "clause on %<simd%> or %<for%> constructs"); + OMP_CLAUSE_LINEAR_KIND (c) = OMP_CLAUSE_LINEAR_DEFAULT; + } if ((VAR_P (t) || TREE_CODE (t) == PARM_DECL) - && !type_dependent_expression_p (t) - && !INTEGRAL_TYPE_P (TREE_TYPE (t)) - && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + && !type_dependent_expression_p (t)) { - error ("linear clause applied to non-integral non-pointer " - "variable with %qT type", TREE_TYPE (t)); - remove = true; - break; + tree type = TREE_TYPE (t); + if ((OMP_CLAUSE_LINEAR_KIND (c) == OMP_CLAUSE_LINEAR_REF + || OMP_CLAUSE_LINEAR_KIND (c) == OMP_CLAUSE_LINEAR_UVAL) + && TREE_CODE (type) != REFERENCE_TYPE) + { + error ("linear clause with %qs modifier applied to " + "non-reference variable with %qT type", + OMP_CLAUSE_LINEAR_KIND (c) == OMP_CLAUSE_LINEAR_REF + ? "ref" : "uval", TREE_TYPE (t)); + remove = true; + break; + } + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + if (!INTEGRAL_TYPE_P (type) + && TREE_CODE (type) != POINTER_TYPE) + { + error ("linear clause applied to non-integral non-pointer " + "variable with %qT type", TREE_TYPE (t)); + remove = true; + break; + } } t = OMP_CLAUSE_LINEAR_STEP (c); if (t == NULL_TREE) @@ -5354,14 +5771,38 @@ finish_omp_clauses (tree clauses) if (TREE_CODE (OMP_CLAUSE_DECL (c)) == PARM_DECL) t = maybe_constant_value (t); t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); - if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) - == POINTER_TYPE) + tree type = TREE_TYPE (OMP_CLAUSE_DECL (c)); + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + if (OMP_CLAUSE_LINEAR_KIND (c) == OMP_CLAUSE_LINEAR_REF) + { + type = build_pointer_type (type); + tree d = fold_convert (type, OMP_CLAUSE_DECL (c)); + t = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, + d, t); + t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), + MINUS_EXPR, sizetype, t, d); + if (t == error_mark_node) + { + remove = true; + break; + } + } + else if (TREE_CODE (type) == POINTER_TYPE + /* Can't multiply the step yet if *this + is still incomplete type. */ + && (!declare_simd + || TREE_CODE (OMP_CLAUSE_DECL (c)) != PARM_DECL + || !DECL_ARTIFICIAL (OMP_CLAUSE_DECL (c)) + || DECL_NAME (OMP_CLAUSE_DECL (c)) + != this_identifier + || !TYPE_BEING_DEFINED (TREE_TYPE (type)))) { + tree d = convert_from_reference (OMP_CLAUSE_DECL (c)); t = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, - OMP_CLAUSE_DECL (c), t); + d, t); t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), - MINUS_EXPR, sizetype, t, - OMP_CLAUSE_DECL (c)); + MINUS_EXPR, sizetype, t, d); if (t == error_mark_node) { remove = true; @@ -5369,14 +5810,33 @@ finish_omp_clauses (tree clauses) } } else - t = fold_convert (TREE_TYPE (OMP_CLAUSE_DECL (c)), t); + t = fold_convert (type, t); } OMP_CLAUSE_LINEAR_STEP (c) = t; } goto check_dup_generic; check_dup_generic: - t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + t = omp_clause_decl_field (OMP_CLAUSE_DECL (c)); + if (t) + { + if (!remove) + omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); + } + else + t = OMP_CLAUSE_DECL (c); + check_dup_generic_t: + if (t == current_class_ptr + && (!declare_simd + || (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LINEAR + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_UNIFORM))) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + remove = true; + break; + } + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL + && (!field_ok || TREE_CODE (t) != FIELD_DECL)) { if (processing_template_decl) break; @@ -5397,11 +5857,34 @@ finish_omp_clauses (tree clauses) } else bitmap_set_bit (&generic_head, DECL_UID (t)); + if (!field_ok) + break; + handle_field_decl: + if (!remove + && TREE_CODE (t) == FIELD_DECL + && t == OMP_CLAUSE_DECL (c)) + { + OMP_CLAUSE_DECL (c) = omp_privatize_field (t); + if (OMP_CLAUSE_DECL (c) == error_mark_node) + remove = true; + } break; case OMP_CLAUSE_FIRSTPRIVATE: - t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + t = omp_clause_decl_field (OMP_CLAUSE_DECL (c)); + if (t) + omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); + else + t = OMP_CLAUSE_DECL (c); + if (t == current_class_ptr) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + remove = true; + break; + } + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL + && (!allow_fields || TREE_CODE (t) != FIELD_DECL)) { if (processing_template_decl) break; @@ -5419,11 +5902,23 @@ finish_omp_clauses (tree clauses) } else bitmap_set_bit (&firstprivate_head, DECL_UID (t)); - break; + goto handle_field_decl; case OMP_CLAUSE_LASTPRIVATE: - t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + t = omp_clause_decl_field (OMP_CLAUSE_DECL (c)); + if (t) + omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); + else + t = OMP_CLAUSE_DECL (c); + if (t == current_class_ptr) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + remove = true; + break; + } + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL + && (!allow_fields || TREE_CODE (t) != FIELD_DECL)) { if (processing_template_decl) break; @@ -5441,7 +5936,7 @@ finish_omp_clauses (tree clauses) } else bitmap_set_bit (&lastprivate_head, DECL_UID (t)); - break; + goto handle_field_decl; case OMP_CLAUSE_IF: t = OMP_CLAUSE_IF_EXPR (c); @@ -5477,7 +5972,17 @@ finish_omp_clauses (tree clauses) { t = mark_rvalue_use (t); if (!processing_template_decl) - t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + { + t = maybe_constant_value (t); + if (TREE_CODE (t) == INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "%<num_threads%> value must be positive"); + t = integer_one_node; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; } break; @@ -5545,6 +6050,8 @@ finish_omp_clauses (tree clauses) } } OMP_CLAUSE_OPERAND (c, 0) = t; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SAFELEN) + safelen = c; } break; @@ -5562,7 +6069,17 @@ finish_omp_clauses (tree clauses) { t = mark_rvalue_use (t); if (!processing_template_decl) - t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + { + t = maybe_constant_value (t); + if (TREE_CODE (t) == INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "%<num_teams%> value must be positive"); + t = integer_one_node; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } OMP_CLAUSE_NUM_TEAMS_EXPR (c) = t; } break; @@ -5619,7 +6136,17 @@ finish_omp_clauses (tree clauses) { t = mark_rvalue_use (t); if (!processing_template_decl) - t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + { + t = maybe_constant_value (t); + if (TREE_CODE (t) == INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "%<thread_limit%> value must be positive"); + t = integer_one_node; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t; } break; @@ -5667,6 +6194,13 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_ALIGNED: t = OMP_CLAUSE_DECL (c); + if (t == current_class_ptr && !declare_simd) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + remove = true; + break; + } if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { if (processing_template_decl) @@ -5729,9 +6263,21 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_DEPEND: t = OMP_CLAUSE_DECL (c); + if (t == NULL_TREE) + { + gcc_assert (OMP_CLAUSE_DEPEND_KIND (c) + == OMP_CLAUSE_DEPEND_SOURCE); + break; + } + if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + { + if (cp_finish_omp_clause_depend_sink (c)) + remove = true; + break; + } if (TREE_CODE (t) == TREE_LIST) { - if (handle_omp_array_sections (c)) + if (handle_omp_array_sections (c, allow_fields)) remove = true; break; } @@ -5747,6 +6293,12 @@ finish_omp_clauses (tree clauses) error ("%qE is not a variable in %<depend%> clause", t); remove = true; } + else if (t == current_class_ptr) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + remove = true; + } else if (!processing_template_decl && !cxx_mark_addressable (t)) remove = true; @@ -5759,7 +6311,7 @@ finish_omp_clauses (tree clauses) t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) == TREE_LIST) { - if (handle_omp_array_sections (c)) + if (handle_omp_array_sections (c, allow_fields)) remove = true; else { @@ -5774,12 +6326,90 @@ finish_omp_clauses (tree clauses) omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } + while (TREE_CODE (t) == ARRAY_REF) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + { + while (TREE_CODE (t) == COMPONENT_REF) + t = TREE_OPERAND (t, 0); + if (bitmap_bit_p (&map_field_head, DECL_UID (t))) + break; + if (bitmap_bit_p (&map_head, DECL_UID (t))) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + error ("%qD appears more than once in motion" + " clauses", t); + else + error ("%qD appears more than once in map" + " clauses", t); + remove = true; + } + else + { + bitmap_set_bit (&map_head, DECL_UID (t)); + bitmap_set_bit (&map_field_head, DECL_UID (t)); + } + } } break; } if (t == error_mark_node) - remove = true; - else if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + { + remove = true; + break; + } + if (REFERENCE_REF_P (t) + && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == COMPONENT_REF + && allow_fields + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_) + { + if (type_dependent_expression_p (t)) + break; + if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "bit-field %qE in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!cp_omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have a mappable type in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + while (TREE_CODE (t) == COMPONENT_REF) + { + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) + == UNION_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is a member of a union", t); + remove = true; + break; + } + t = TREE_OPERAND (t, 0); + } + if (remove) + break; + if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FIRSTPRIVATE_POINTER)) + { + if (bitmap_bit_p (&generic_field_head, DECL_UID (t))) + break; + } + else if (bitmap_bit_p (&map_field_head, DECL_UID (t))) + break; + } + } + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { if (processing_template_decl) break; @@ -5800,12 +6430,22 @@ finish_omp_clauses (tree clauses) omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } + else if (t == current_class_ptr) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + remove = true; + break; + } else if (!processing_template_decl && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE && !cxx_mark_addressable (t)) remove = true; else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER) + && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER + || (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FIRSTPRIVATE_POINTER))) + && t == OMP_CLAUSE_DECL (c) && !type_dependent_expression_p (t) && !cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) @@ -5817,7 +6457,28 @@ finish_omp_clauses (tree clauses) omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } - else if (bitmap_bit_p (&generic_head, DECL_UID (t))) + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) + { + if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + { + error ("%qD appears more than once in data clauses", t); + remove = true; + } + else + { + bitmap_set_bit (&generic_head, DECL_UID (t)); + if (t != OMP_CLAUSE_DECL (c) + && (TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPONENT_REF + || (REFERENCE_REF_P (OMP_CLAUSE_DECL (c)) + && (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (c), + 0)) + == COMPONENT_REF)))) + bitmap_set_bit (&generic_field_head, DECL_UID (t)); + } + } + else if (bitmap_bit_p (&map_head, DECL_UID (t))) { if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) error ("%qD appears more than once in motion clauses", t); @@ -5826,7 +6487,42 @@ finish_omp_clauses (tree clauses) remove = true; } else - bitmap_set_bit (&generic_head, DECL_UID (t)); + { + bitmap_set_bit (&map_head, DECL_UID (t)); + if (t != OMP_CLAUSE_DECL (c) + && TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPONENT_REF) + bitmap_set_bit (&map_field_head, DECL_UID (t)); + } + break; + + case OMP_CLAUSE_TO_DECLARE: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == FUNCTION_DECL) + break; + /* FALLTHRU */ + case OMP_CLAUSE_LINK: + t = OMP_CLAUSE_DECL (c); + if (!VAR_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!cp_omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD does not have a mappable type in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } break; case OMP_CLAUSE_UNIFORM: @@ -5844,6 +6540,137 @@ finish_omp_clauses (tree clauses) } goto check_dup_generic; + case OMP_CLAUSE_NUM_TASKS: + t = OMP_CLAUSE_NUM_TASKS_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%<num_tasks%> expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + if (TREE_CODE (t) == INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "%<num_tasks%> value must be positive"); + t = integer_one_node; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + OMP_CLAUSE_NUM_TASKS_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_GRAINSIZE: + t = OMP_CLAUSE_GRAINSIZE_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%<grainsize%> expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + if (TREE_CODE (t) == INTEGER_CST + && tree_int_cst_sgn (t) != 1) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "%<grainsize%> value must be positive"); + t = integer_one_node; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + OMP_CLAUSE_GRAINSIZE_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_PRIORITY: + t = OMP_CLAUSE_PRIORITY_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%<priority%> expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + if (TREE_CODE (t) == INTEGER_CST + && tree_int_cst_sgn (t) == -1) + { + warning_at (OMP_CLAUSE_LOCATION (c), 0, + "%<priority%> value must be non-negative"); + t = integer_one_node; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + OMP_CLAUSE_PRIORITY_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_HINT: + t = OMP_CLAUSE_HINT_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%<num_tasks%> expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + OMP_CLAUSE_HINT_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_IS_DEVICE_PTR: + case OMP_CLAUSE_USE_DEVICE_PTR: + field_ok = allow_fields; + t = OMP_CLAUSE_DECL (c); + if (!type_dependent_expression_p (t)) + { + tree type = TREE_TYPE (t); + if (TREE_CODE (type) != POINTER_TYPE + && TREE_CODE (type) != ARRAY_TYPE + && (TREE_CODE (type) != REFERENCE_TYPE + || (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qs variable is neither a pointer, nor an array" + "nor reference to pointer or array", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + } + goto check_dup_generic; + case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: @@ -5855,6 +6682,10 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_SECTIONS: case OMP_CLAUSE_TASKGROUP: case OMP_CLAUSE_PROC_BIND: + case OMP_CLAUSE_NOGROUP: + case OMP_CLAUSE_THREADS: + case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_DEFAULTMAP: case OMP_CLAUSE__CILK_FOR_COUNT_: break; @@ -5883,7 +6714,7 @@ finish_omp_clauses (tree clauses) { enum omp_clause_code c_kind = OMP_CLAUSE_CODE (c); bool remove = false; - bool need_complete_non_reference = false; + bool need_complete_type = false; bool need_default_ctor = false; bool need_copy_ctor = false; bool need_copy_assignment = false; @@ -5897,31 +6728,49 @@ finish_omp_clauses (tree clauses) need_implicitly_determined = true; break; case OMP_CLAUSE_PRIVATE: - need_complete_non_reference = true; + need_complete_type = true; need_default_ctor = true; need_dtor = true; need_implicitly_determined = true; break; case OMP_CLAUSE_FIRSTPRIVATE: - need_complete_non_reference = true; + need_complete_type = true; need_copy_ctor = true; need_dtor = true; need_implicitly_determined = true; break; case OMP_CLAUSE_LASTPRIVATE: - need_complete_non_reference = true; + need_complete_type = true; need_copy_assignment = true; need_implicitly_determined = true; break; case OMP_CLAUSE_REDUCTION: need_implicitly_determined = true; break; + case OMP_CLAUSE_LINEAR: + if (!declare_simd) + need_implicitly_determined = true; + break; case OMP_CLAUSE_COPYPRIVATE: need_copy_assignment = true; break; case OMP_CLAUSE_COPYIN: need_copy_assignment = true; break; + case OMP_CLAUSE_SIMDLEN: + if (safelen + && !processing_template_decl + && tree_int_cst_lt (OMP_CLAUSE_SAFELEN_EXPR (safelen), + OMP_CLAUSE_SIMDLEN_EXPR (c))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<simdlen%> clause value is bigger than " + "%<safelen%> clause value"); + OMP_CLAUSE_SIMDLEN_EXPR (c) + = OMP_CLAUSE_SAFELEN_EXPR (safelen); + } + pc = &OMP_CLAUSE_CHAIN (c); + continue; case OMP_CLAUSE_NOWAIT: if (copyprivate_seen) { @@ -5975,18 +6824,14 @@ finish_omp_clauses (tree clauses) break; } - if (need_complete_non_reference || need_copy_assignment) + if (need_complete_type || need_copy_assignment) { t = require_complete_type (t); if (t == error_mark_node) remove = true; else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE - && need_complete_non_reference) - { - error ("%qE has reference type for %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } + && !complete_type_or_else (TREE_TYPE (TREE_TYPE (t)), t)) + remove = true; } if (need_implicitly_determined) { @@ -6014,19 +6859,21 @@ finish_omp_clauses (tree clauses) if (share_name) { error ("%qE is predetermined %qs for %qs", - t, share_name, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + omp_clause_printable_decl (t), share_name, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } } /* We're interested in the base element, not arrays. */ inner_type = type = TREE_TYPE (t); - while (TREE_CODE (inner_type) == ARRAY_TYPE) - inner_type = TREE_TYPE (inner_type); - - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + if ((need_complete_type + || need_copy_assignment + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) && TREE_CODE (inner_type) == REFERENCE_TYPE) inner_type = TREE_TYPE (inner_type); + while (TREE_CODE (inner_type) == ARRAY_TYPE) + inner_type = TREE_TYPE (inner_type); /* Check for special function availability by building a call to one. Save the results, because later we won't be in the right context @@ -6051,6 +6898,134 @@ finish_omp_clauses (tree clauses) return clauses; } +/* Start processing OpenMP clauses that can include any + privatization clauses for non-static data members. */ + +tree +push_omp_privatization_clauses (bool ignore_next) +{ + if (omp_private_member_ignore_next) + { + omp_private_member_ignore_next = ignore_next; + return NULL_TREE; + } + omp_private_member_ignore_next = ignore_next; + if (omp_private_member_map) + omp_private_member_vec.safe_push (error_mark_node); + return push_stmt_list (); +} + +/* Revert remapping of any non-static data members since + the last push_omp_privatization_clauses () call. */ + +void +pop_omp_privatization_clauses (tree stmt) +{ + if (stmt == NULL_TREE) + return; + stmt = pop_stmt_list (stmt); + if (omp_private_member_map) + { + while (!omp_private_member_vec.is_empty ()) + { + tree t = omp_private_member_vec.pop (); + if (t == error_mark_node) + { + add_stmt (stmt); + return; + } + bool no_decl_expr = t == integer_zero_node; + if (no_decl_expr) + t = omp_private_member_vec.pop (); + tree *v = omp_private_member_map->get (t); + gcc_assert (v); + if (!no_decl_expr) + add_decl_expr (*v); + omp_private_member_map->remove (t); + } + delete omp_private_member_map; + omp_private_member_map = NULL; + } + add_stmt (stmt); +} + +/* Remember OpenMP privatization clauses mapping and clear it. + Used for lambdas. */ + +void +save_omp_privatization_clauses (vec<tree> &save) +{ + save = vNULL; + if (omp_private_member_ignore_next) + save.safe_push (integer_one_node); + omp_private_member_ignore_next = false; + if (!omp_private_member_map) + return; + + while (!omp_private_member_vec.is_empty ()) + { + tree t = omp_private_member_vec.pop (); + if (t == error_mark_node) + { + save.safe_push (t); + continue; + } + tree n = t; + if (t == integer_zero_node) + t = omp_private_member_vec.pop (); + tree *v = omp_private_member_map->get (t); + gcc_assert (v); + save.safe_push (*v); + save.safe_push (t); + if (n != t) + save.safe_push (n); + } + delete omp_private_member_map; + omp_private_member_map = NULL; +} + +/* Restore OpenMP privatization clauses mapping saved by the + above function. */ + +void +restore_omp_privatization_clauses (vec<tree> &save) +{ + gcc_assert (omp_private_member_vec.is_empty ()); + omp_private_member_ignore_next = false; + if (save.is_empty ()) + return; + if (save.length () == 1 && save[0] == integer_one_node) + { + omp_private_member_ignore_next = true; + save.release (); + return; + } + + omp_private_member_map = new hash_map <tree, tree>; + while (!save.is_empty ()) + { + tree t = save.pop (); + tree n = t; + if (t != error_mark_node) + { + if (t == integer_one_node) + { + omp_private_member_ignore_next = true; + gcc_assert (save.is_empty ()); + break; + } + if (t == integer_zero_node) + t = save.pop (); + tree &v = omp_private_member_map->get_or_insert (t); + v = save.pop (); + } + omp_private_member_vec.safe_push (t); + if (n != t) + omp_private_member_vec.safe_push (n); + } + save.release (); +} + /* For all variables in the tree_list VARS, mark them as thread local. */ void @@ -6228,9 +7203,10 @@ finish_omp_task (tree clauses, tree body) into integral iterator. Return FALSE if successful. */ static bool -handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, - tree condv, tree incrv, tree *body, - tree *pre_body, tree clauses, tree *lastp) +handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, + tree declv, tree initv, tree condv, tree incrv, + tree *body, tree *pre_body, tree &clauses, + tree *lastp, int collapse, int ordered) { tree diff, iter_init, iter_incr = NULL, last; tree incr_var = NULL, orig_pre_body, orig_body, c; @@ -6388,10 +7364,25 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, } incr = cp_convert (TREE_TYPE (diff), incr, tf_warning_or_error); + bool taskloop_iv_seen = false; for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE && OMP_CLAUSE_DECL (c) == iter) - break; + { + if (code == OMP_TASKLOOP) + { + taskloop_iv_seen = true; + OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV (c) = 1; + } + break; + } + else if (code == OMP_TASKLOOP + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE + && OMP_CLAUSE_DECL (c) == iter) + { + taskloop_iv_seen = true; + OMP_CLAUSE_PRIVATE_TASKLOOP_IV (c) = 1; + } decl = create_temporary_var (TREE_TYPE (diff)); pushdecl (decl); @@ -6399,13 +7390,33 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, last = create_temporary_var (TREE_TYPE (diff)); pushdecl (last); add_decl_expr (last); - if (c && iter_incr == NULL) + if (c && iter_incr == NULL && TREE_CODE (incr) != INTEGER_CST + && (!ordered || (i < collapse && collapse > 1))) { incr_var = create_temporary_var (TREE_TYPE (diff)); pushdecl (incr_var); add_decl_expr (incr_var); } gcc_assert (stmts_are_full_exprs_p ()); + tree diffvar = NULL_TREE; + if (code == OMP_TASKLOOP) + { + if (!taskloop_iv_seen) + { + tree ivc = build_omp_clause (locus, OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (ivc) = iter; + cxx_omp_finish_clause (ivc, NULL); + OMP_CLAUSE_CHAIN (ivc) = clauses; + clauses = ivc; + } + tree lvc = build_omp_clause (locus, OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (lvc) = last; + OMP_CLAUSE_CHAIN (lvc) = clauses; + clauses = lvc; + diffvar = create_temporary_var (TREE_TYPE (diff)); + pushdecl (diffvar); + add_decl_expr (diffvar); + } orig_pre_body = *pre_body; *pre_body = push_stmt_list (); @@ -6416,19 +7427,32 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, iter, NOP_EXPR, init, tf_warning_or_error)); init = build_int_cst (TREE_TYPE (diff), 0); - if (c && iter_incr == NULL) + if (c && iter_incr == NULL + && (!ordered || (i < collapse && collapse > 1))) { - finish_expr_stmt (build_x_modify_expr (elocus, - incr_var, NOP_EXPR, - incr, tf_warning_or_error)); - incr = incr_var; + if (incr_var) + { + finish_expr_stmt (build_x_modify_expr (elocus, + incr_var, NOP_EXPR, + incr, tf_warning_or_error)); + incr = incr_var; + } iter_incr = build_x_modify_expr (elocus, iter, PLUS_EXPR, incr, tf_warning_or_error); } + if (c && ordered && i < collapse && collapse > 1) + iter_incr = incr; finish_expr_stmt (build_x_modify_expr (elocus, last, NOP_EXPR, init, tf_warning_or_error)); + if (diffvar) + { + finish_expr_stmt (build_x_modify_expr (elocus, + diffvar, NOP_EXPR, + diff, tf_warning_or_error)); + diff = diffvar; + } *pre_body = pop_stmt_list (*pre_body); cond = cp_build_binary_op (elocus, @@ -6455,7 +7479,22 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, if (c) { OMP_CLAUSE_LASTPRIVATE_STMT (c) = push_stmt_list (); - finish_expr_stmt (iter_incr); + if (!ordered) + finish_expr_stmt (iter_incr); + else + { + iter_init = decl; + if (i < collapse && collapse > 1 && !error_operand_p (iter_incr)) + iter_init = build2 (PLUS_EXPR, TREE_TYPE (diff), + iter_init, iter_incr); + iter_init = build2 (MINUS_EXPR, TREE_TYPE (diff), iter_init, last); + iter_init = build_x_modify_expr (elocus, + iter, PLUS_EXPR, iter_init, + tf_warning_or_error); + if (iter_init != error_mark_node) + iter_init = build1 (NOP_EXPR, void_type_node, iter_init); + finish_expr_stmt (iter_init); + } OMP_CLAUSE_LASTPRIVATE_STMT (c) = pop_stmt_list (OMP_CLAUSE_LASTPRIVATE_STMT (c)); } @@ -6477,18 +7516,29 @@ handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, sk_omp scope. */ tree -finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, - tree condv, tree incrv, tree body, tree pre_body, tree clauses) +finish_omp_for (location_t locus, enum tree_code code, tree declv, + tree orig_declv, tree initv, tree condv, tree incrv, + tree body, tree pre_body, tree clauses) { tree omp_for = NULL, orig_incr = NULL; tree decl = NULL, init, cond, incr, orig_decl = NULL_TREE, block = NULL_TREE; tree last = NULL_TREE; location_t elocus; int i; + int collapse = 1; + int ordered = 0; gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (initv)); gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (condv)); gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (incrv)); + if (TREE_VEC_LENGTH (declv) > 1) + { + tree c = find_omp_clause (clauses, OMP_CLAUSE_COLLAPSE); + if (c) + collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (c)); + if (collapse != TREE_VEC_LENGTH (declv)) + ordered = TREE_VEC_LENGTH (declv); + } for (i = 0; i < TREE_VEC_LENGTH (declv); i++) { decl = TREE_VEC_ELT (declv, i); @@ -6572,6 +7622,9 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, return add_stmt (stmt); } + if (!orig_declv) + orig_declv = copy_node (declv); + if (processing_template_decl) orig_incr = make_tree_vec (TREE_VEC_LENGTH (incrv)); @@ -6614,9 +7667,10 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, } if (code == CILK_FOR && i == 0) orig_decl = decl; - if (handle_omp_for_class_iterator (i, locus, declv, initv, condv, - incrv, &body, &pre_body, - clauses, &last)) + if (handle_omp_for_class_iterator (i, locus, code, declv, initv, + condv, incrv, &body, &pre_body, + clauses, &last, collapse, + ordered)) return NULL; continue; } @@ -6672,8 +7726,8 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, if (code == CILK_FOR && !processing_template_decl) block = push_stmt_list (); - omp_for = c_finish_omp_for (locus, code, declv, initv, condv, incrv, - body, pre_body); + omp_for = c_finish_omp_for (locus, code, declv, orig_declv, initv, condv, + incrv, body, pre_body); if (omp_for == NULL) { @@ -6716,6 +7770,68 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, } OMP_FOR_CLAUSES (omp_for) = clauses; + /* For simd loops with non-static data member iterators, we could have added + OMP_CLAUSE_LINEAR clauses without OMP_CLAUSE_LINEAR_STEP. As we know the + step at this point, fill it in. */ + if (code == OMP_SIMD && !processing_template_decl + && TREE_VEC_LENGTH (OMP_FOR_INCR (omp_for)) == 1) + for (tree c = find_omp_clause (clauses, OMP_CLAUSE_LINEAR); c; + c = find_omp_clause (OMP_CLAUSE_CHAIN (c), OMP_CLAUSE_LINEAR)) + if (OMP_CLAUSE_LINEAR_STEP (c) == NULL_TREE) + { + decl = TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (omp_for), 0), 0); + gcc_assert (decl == OMP_CLAUSE_DECL (c)); + incr = TREE_VEC_ELT (OMP_FOR_INCR (omp_for), 0); + tree step, stept; + switch (TREE_CODE (incr)) + { + case PREINCREMENT_EXPR: + case POSTINCREMENT_EXPR: + /* c_omp_for_incr_canonicalize_ptr() should have been + called to massage things appropriately. */ + gcc_assert (!POINTER_TYPE_P (TREE_TYPE (decl))); + OMP_CLAUSE_LINEAR_STEP (c) = build_int_cst (TREE_TYPE (decl), 1); + break; + case PREDECREMENT_EXPR: + case POSTDECREMENT_EXPR: + /* c_omp_for_incr_canonicalize_ptr() should have been + called to massage things appropriately. */ + gcc_assert (!POINTER_TYPE_P (TREE_TYPE (decl))); + OMP_CLAUSE_LINEAR_STEP (c) + = build_int_cst (TREE_TYPE (decl), -1); + break; + case MODIFY_EXPR: + gcc_assert (TREE_OPERAND (incr, 0) == decl); + incr = TREE_OPERAND (incr, 1); + switch (TREE_CODE (incr)) + { + case PLUS_EXPR: + if (TREE_OPERAND (incr, 1) == decl) + step = TREE_OPERAND (incr, 0); + else + step = TREE_OPERAND (incr, 1); + break; + case MINUS_EXPR: + case POINTER_PLUS_EXPR: + gcc_assert (TREE_OPERAND (incr, 0) == decl); + step = TREE_OPERAND (incr, 1); + break; + default: + gcc_unreachable (); + } + stept = TREE_TYPE (decl); + if (POINTER_TYPE_P (stept)) + stept = sizetype; + step = fold_convert (stept, step); + if (TREE_CODE (incr) == MINUS_EXPR) + step = fold_build1 (NEGATE_EXPR, stept, step); + OMP_CLAUSE_LINEAR_STEP (c) = step; + break; + default: + gcc_unreachable (); + } + } + if (block) { tree omp_par = make_node (OMP_PARALLEL); @@ -6802,7 +7918,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, tree initv, OMP_CLAUSE_OPERAND (c, 0) = cilk_for_number_of_iterations (omp_for); OMP_CLAUSE_CHAIN (c) = clauses; - OMP_PARALLEL_CLAUSES (omp_par) = finish_omp_clauses (c); + OMP_PARALLEL_CLAUSES (omp_par) = finish_omp_clauses (c, false); add_stmt (omp_par); return omp_par; } |