diff options
Diffstat (limited to 'gcc/gimplify.cc')
-rw-r--r-- | gcc/gimplify.cc | 464 |
1 files changed, 284 insertions, 180 deletions
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 9f9ff92..fbf47dd 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -71,6 +71,10 @@ along with GCC; see the file COPYING3. If not see #include "context.h" #include "tree-nested.h" #include "gcc-urlifier.h" +#include "insn-config.h" +#include "recog.h" +#include "output.h" +#include "gimplify_reg_info.h" /* Identifier for a basic condition, mapping it to other basic conditions of its Boolean expression. Basic conditions given the same uid (in the same @@ -7305,6 +7309,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, && !(TREE_ADDRESSABLE (TREE_TYPE (*from_p)) && TREE_CODE (*from_p) == CALL_EXPR)) { + suppress_warning (*from_p, OPT_Wunused_result); gimplify_stmt (from_p, pre_p); gimplify_stmt (to_p, pre_p); *expr_p = NULL_TREE; @@ -7822,6 +7827,42 @@ gimplify_addr_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) return ret; } +/* Return the number of times character C occurs in string S. */ + +static int +num_occurrences (int c, const char *s) +{ + int n = 0; + while (*s) + n += (*s++ == c); + return n; +} + +/* A subroutine of gimplify_asm_expr. Check that all operands have + the same number of alternatives. Return -1 if this is violated. Otherwise + return the number of alternatives. */ + +static int +num_alternatives (const_tree link) +{ + if (link == nullptr) + return 0; + + const char *constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); + int num = num_occurrences (',', constraint); + + if (num + 1 > MAX_RECOG_ALTERNATIVES) + return -1; + + for (link = TREE_CHAIN (link); link; link = TREE_CHAIN (link)) + { + constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); + if (num_occurrences (',', constraint) != num) + return -1; + } + return num + 1; +} + /* Gimplify the operands of an ASM_EXPR. Input operands should be a gimple value; output operands should be a gimple lvalue. */ @@ -7852,6 +7893,36 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) clobbers = NULL; labels = NULL; + int num_alternatives_out = num_alternatives (ASM_OUTPUTS (expr)); + int num_alternatives_in = num_alternatives (ASM_INPUTS (expr)); + if (num_alternatives_out == -1 || num_alternatives_in == -1 + || (num_alternatives_out > 0 && num_alternatives_in > 0 + && num_alternatives_out != num_alternatives_in)) + { + error ("operand constraints for %<asm%> differ " + "in number of alternatives"); + return GS_ERROR; + } + int num_alternatives = MAX (num_alternatives_out, num_alternatives_in); + + gimplify_reg_info reg_info (num_alternatives, noutputs); + + link_next = NULL_TREE; + for (link = ASM_CLOBBERS (expr); link; link = link_next) + { + /* The clobber entry could also be an error marker. */ + if (TREE_CODE (TREE_VALUE (link)) == STRING_CST) + { + const char *regname= TREE_STRING_POINTER (TREE_VALUE (link)); + int regno = decode_reg_name (regname); + if (regno >= 0) + reg_info.set_clobbered (regno); + } + link_next = TREE_CHAIN (link); + TREE_CHAIN (link) = NULL_TREE; + vec_safe_push (clobbers, link); + } + ret = GS_ALL_DONE; link_next = NULL_TREE; for (i = 0, link = ASM_OUTPUTS (expr); link; ++i, link = link_next) @@ -7868,8 +7939,9 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) if (constraint_len == 0) continue; - ok = parse_output_constraint (&constraint, i, 0, 0, - &allows_mem, &allows_reg, &is_inout); + reg_info.operand = TREE_VALUE (link); + ok = parse_output_constraint (&constraint, i, 0, 0, &allows_mem, + &allows_reg, &is_inout, ®_info); if (!ok) { ret = GS_ERROR; @@ -8000,8 +8072,8 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) *end = '\0'; beg[-1] = '='; tem = beg - 1; - parse_output_constraint (&tem, i, 0, 0, - &mem_p, ®_p, &inout_p); + parse_output_constraint (&tem, i, 0, 0, &mem_p, ®_p, + &inout_p, nullptr); if (dst != str) *dst++ = ','; if (reg_p) @@ -8040,13 +8112,60 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) } } + /* After all output operands have been gimplified, verify that each output + operand is used at most once in case of hard register constraints. Thus, + error out in cases like + asm ("" : "={0}" (x), "={1}" (x)); + or even for + asm ("" : "=r" (x), "={1}" (x)); + + FIXME: Ideally we would also error out for cases like + int x; + asm ("" : "=r" (x), "=r" (x)); + However, since code like that was previously accepted, erroring out now might + break existing code. On the other hand, we already error out for register + asm like + register int x asm ("0"); + asm ("" : "=r" (x), "=r" (x)); + Thus, maybe it wouldn't be too bad to also error out in the former + non-register-asm case. + */ + for (unsigned i = 0; i < vec_safe_length (outputs); ++i) + { + tree link = (*outputs)[i]; + tree op1 = TREE_VALUE (link); + const char *constraint + = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); + if (strchr (constraint, '{') != nullptr) + for (unsigned j = 0; j < vec_safe_length (outputs); ++j) + { + if (i == j) + continue; + tree link2 = (*outputs)[j]; + tree op2 = TREE_VALUE (link2); + if (op1 == op2) + { + error ("multiple outputs to lvalue %qE", op2); + return GS_ERROR; + } + } + } + link_next = NULL_TREE; - for (link = ASM_INPUTS (expr); link; ++i, link = link_next) + int input_num = 0; + for (link = ASM_INPUTS (expr); link; ++input_num, ++i, link = link_next) { link_next = TREE_CHAIN (link); constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); - parse_input_constraint (&constraint, 0, 0, noutputs, 0, - oconstraints, &allows_mem, &allows_reg); + reg_info.operand = TREE_VALUE (link); + bool ok = parse_input_constraint (&constraint, input_num, 0, noutputs, 0, + oconstraints, &allows_mem, &allows_reg, + ®_info); + if (!ok) + { + ret = GS_ERROR; + is_inout = false; + } /* If we can't make copies, we can only accept memory. */ tree intype = TREE_TYPE (TREE_VALUE (link)); @@ -8128,15 +8247,7 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) } link_next = NULL_TREE; - for (link = ASM_CLOBBERS (expr); link; ++i, link = link_next) - { - link_next = TREE_CHAIN (link); - TREE_CHAIN (link) = NULL_TREE; - vec_safe_push (clobbers, link); - } - - link_next = NULL_TREE; - for (link = ASM_LABELS (expr); link; ++i, link = link_next) + for (link = ASM_LABELS (expr); link; link = link_next) { link_next = TREE_CHAIN (link); TREE_CHAIN (link) = NULL_TREE; @@ -9526,9 +9637,7 @@ gimplify_omp_affinity (tree *list_p, gimple_seq *pre_p) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_AFFINITY) { tree t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == TREE_LIST - && TREE_PURPOSE (t) - && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + if (OMP_ITERATOR_DECL_P (t)) { if (TREE_VALUE (t) == null_pointer_node) continue; @@ -9633,6 +9742,155 @@ gimplify_omp_affinity (tree *list_p, gimple_seq *pre_p) return; } +/* Returns a tree expression containing the total iteration count of the + OpenMP iterator IT. */ + +static tree +compute_omp_iterator_count (tree it, gimple_seq *pre_p) +{ + tree tcnt = size_one_node; + for (; it; it = TREE_CHAIN (it)) + { + if (gimplify_expr (&TREE_VEC_ELT (it, 1), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR + || gimplify_expr (&TREE_VEC_ELT (it, 2), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR + || gimplify_expr (&TREE_VEC_ELT (it, 3), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR + || (gimplify_expr (&TREE_VEC_ELT (it, 4), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR)) + return NULL_TREE; + tree var = TREE_VEC_ELT (it, 0); + tree begin = TREE_VEC_ELT (it, 1); + tree end = TREE_VEC_ELT (it, 2); + tree step = TREE_VEC_ELT (it, 3); + tree orig_step = TREE_VEC_ELT (it, 4); + tree type = TREE_TYPE (var); + tree stype = TREE_TYPE (step); + location_t loc = DECL_SOURCE_LOCATION (var); + tree endmbegin; + /* Compute count for this iterator as + orig_step > 0 + ? (begin < end ? (end - begin + (step - 1)) / step : 0) + : (begin > end ? (end - begin + (step + 1)) / step : 0) + and compute product of those for the entire clause. */ + if (POINTER_TYPE_P (type)) + endmbegin = fold_build2_loc (loc, POINTER_DIFF_EXPR, stype, end, begin); + else + endmbegin = fold_build2_loc (loc, MINUS_EXPR, type, end, begin); + tree stepm1 = fold_build2_loc (loc, MINUS_EXPR, stype, step, + build_int_cst (stype, 1)); + tree stepp1 = fold_build2_loc (loc, PLUS_EXPR, stype, step, + build_int_cst (stype, 1)); + tree pos = fold_build2_loc (loc, PLUS_EXPR, stype, + unshare_expr (endmbegin), stepm1); + pos = fold_build2_loc (loc, TRUNC_DIV_EXPR, stype, pos, step); + tree neg = fold_build2_loc (loc, PLUS_EXPR, stype, endmbegin, stepp1); + if (TYPE_UNSIGNED (stype)) + { + neg = fold_build1_loc (loc, NEGATE_EXPR, stype, neg); + step = fold_build1_loc (loc, NEGATE_EXPR, stype, step); + } + neg = fold_build2_loc (loc, TRUNC_DIV_EXPR, stype, neg, step); + step = NULL_TREE; + tree cond = fold_build2_loc (loc, LT_EXPR, boolean_type_node, begin, end); + pos = fold_build3_loc (loc, COND_EXPR, stype, cond, pos, + build_int_cst (stype, 0)); + cond = fold_build2_loc (loc, LT_EXPR, boolean_type_node, end, begin); + neg = fold_build3_loc (loc, COND_EXPR, stype, cond, neg, + build_int_cst (stype, 0)); + tree osteptype = TREE_TYPE (orig_step); + cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, orig_step, + build_int_cst (osteptype, 0)); + tree cnt = fold_build3_loc (loc, COND_EXPR, stype, cond, pos, neg); + cnt = fold_convert_loc (loc, sizetype, cnt); + if (gimplify_expr (&cnt, pre_p, NULL, is_gimple_val, + fb_rvalue) == GS_ERROR) + return NULL_TREE; + tcnt = size_binop_loc (loc, MULT_EXPR, tcnt, cnt); + } + if (gimplify_expr (&tcnt, pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR) + return NULL_TREE; + + return tcnt; +} + +/* Build loops iterating over the space defined by the OpenMP iterator IT. + Returns a pointer to the BIND_EXPR_BODY in the innermost loop body. + LAST_BIND is set to point to the BIND_EXPR containing the whole loop. */ + +static tree * +build_omp_iterator_loop (tree it, gimple_seq *pre_p, tree *last_bind) +{ + if (*last_bind) + gimplify_and_add (*last_bind, pre_p); + tree block = TREE_VEC_ELT (it, 5); + *last_bind = build3 (BIND_EXPR, void_type_node, + BLOCK_VARS (block), NULL, block); + TREE_SIDE_EFFECTS (*last_bind) = 1; + tree *p = &BIND_EXPR_BODY (*last_bind); + for (; it; it = TREE_CHAIN (it)) + { + tree var = TREE_VEC_ELT (it, 0); + tree begin = TREE_VEC_ELT (it, 1); + tree end = TREE_VEC_ELT (it, 2); + tree step = TREE_VEC_ELT (it, 3); + tree orig_step = TREE_VEC_ELT (it, 4); + tree type = TREE_TYPE (var); + location_t loc = DECL_SOURCE_LOCATION (var); + /* Emit: + var = begin; + goto cond_label; + beg_label: + ... + var = var + step; + cond_label: + if (orig_step > 0) { + if (var < end) goto beg_label; + } else { + if (var > end) goto beg_label; + } + for each iterator, with inner iterators added to + the ... above. */ + tree beg_label = create_artificial_label (loc); + tree cond_label = NULL_TREE; + tree tem = build2_loc (loc, MODIFY_EXPR, void_type_node, var, begin); + append_to_statement_list_force (tem, p); + tem = build_and_jump (&cond_label); + append_to_statement_list_force (tem, p); + tem = build1 (LABEL_EXPR, void_type_node, beg_label); + append_to_statement_list (tem, p); + tree bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, + NULL_TREE, NULL_TREE); + TREE_SIDE_EFFECTS (bind) = 1; + SET_EXPR_LOCATION (bind, loc); + append_to_statement_list_force (bind, p); + if (POINTER_TYPE_P (type)) + tem = build2_loc (loc, POINTER_PLUS_EXPR, type, + var, fold_convert_loc (loc, sizetype, step)); + else + tem = build2_loc (loc, PLUS_EXPR, type, var, step); + tem = build2_loc (loc, MODIFY_EXPR, void_type_node, var, tem); + append_to_statement_list_force (tem, p); + tem = build1 (LABEL_EXPR, void_type_node, cond_label); + append_to_statement_list (tem, p); + tree cond = fold_build2_loc (loc, LT_EXPR, boolean_type_node, var, end); + tree pos = fold_build3_loc (loc, COND_EXPR, void_type_node, cond, + build_and_jump (&beg_label), void_node); + cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, var, end); + tree neg = fold_build3_loc (loc, COND_EXPR, void_type_node, cond, + build_and_jump (&beg_label), void_node); + tree osteptype = TREE_TYPE (orig_step); + cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, orig_step, + build_int_cst (osteptype, 0)); + tem = fold_build3_loc (loc, COND_EXPR, void_type_node, cond, pos, neg); + append_to_statement_list_force (tem, p); + p = &BIND_EXPR_BODY (bind); + } + + return p; +} + /* If *LIST_P contains any OpenMP depend clauses with iterators, lower all the depend clauses by populating corresponding depend array. Returns 0 if there are no such depend clauses, or @@ -9677,89 +9935,13 @@ gimplify_omp_depend (tree *list_p, gimple_seq *pre_p) tree t = OMP_CLAUSE_DECL (c); if (first_loc == UNKNOWN_LOCATION) first_loc = OMP_CLAUSE_LOCATION (c); - if (TREE_CODE (t) == TREE_LIST - && TREE_PURPOSE (t) - && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + if (OMP_ITERATOR_DECL_P (t)) { if (TREE_PURPOSE (t) != last_iter) { - tree tcnt = size_one_node; - for (tree it = TREE_PURPOSE (t); it; it = TREE_CHAIN (it)) - { - if (gimplify_expr (&TREE_VEC_ELT (it, 1), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR - || gimplify_expr (&TREE_VEC_ELT (it, 2), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR - || gimplify_expr (&TREE_VEC_ELT (it, 3), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR - || (gimplify_expr (&TREE_VEC_ELT (it, 4), pre_p, NULL, - is_gimple_val, fb_rvalue) - == GS_ERROR)) - return 2; - tree var = TREE_VEC_ELT (it, 0); - tree begin = TREE_VEC_ELT (it, 1); - tree end = TREE_VEC_ELT (it, 2); - tree step = TREE_VEC_ELT (it, 3); - tree orig_step = TREE_VEC_ELT (it, 4); - tree type = TREE_TYPE (var); - tree stype = TREE_TYPE (step); - location_t loc = DECL_SOURCE_LOCATION (var); - tree endmbegin; - /* Compute count for this iterator as - orig_step > 0 - ? (begin < end ? (end - begin + (step - 1)) / step : 0) - : (begin > end ? (end - begin + (step + 1)) / step : 0) - and compute product of those for the entire depend - clause. */ - if (POINTER_TYPE_P (type)) - endmbegin = fold_build2_loc (loc, POINTER_DIFF_EXPR, - stype, end, begin); - else - endmbegin = fold_build2_loc (loc, MINUS_EXPR, type, - end, begin); - tree stepm1 = fold_build2_loc (loc, MINUS_EXPR, stype, - step, - build_int_cst (stype, 1)); - tree stepp1 = fold_build2_loc (loc, PLUS_EXPR, stype, step, - build_int_cst (stype, 1)); - tree pos = fold_build2_loc (loc, PLUS_EXPR, stype, - unshare_expr (endmbegin), - stepm1); - pos = fold_build2_loc (loc, TRUNC_DIV_EXPR, stype, - pos, step); - tree neg = fold_build2_loc (loc, PLUS_EXPR, stype, - endmbegin, stepp1); - if (TYPE_UNSIGNED (stype)) - { - neg = fold_build1_loc (loc, NEGATE_EXPR, stype, neg); - step = fold_build1_loc (loc, NEGATE_EXPR, stype, step); - } - neg = fold_build2_loc (loc, TRUNC_DIV_EXPR, stype, - neg, step); - step = NULL_TREE; - tree cond = fold_build2_loc (loc, LT_EXPR, - boolean_type_node, - begin, end); - pos = fold_build3_loc (loc, COND_EXPR, stype, cond, pos, - build_int_cst (stype, 0)); - cond = fold_build2_loc (loc, LT_EXPR, boolean_type_node, - end, begin); - neg = fold_build3_loc (loc, COND_EXPR, stype, cond, neg, - build_int_cst (stype, 0)); - tree osteptype = TREE_TYPE (orig_step); - cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, - orig_step, - build_int_cst (osteptype, 0)); - tree cnt = fold_build3_loc (loc, COND_EXPR, stype, - cond, pos, neg); - cnt = fold_convert_loc (loc, sizetype, cnt); - if (gimplify_expr (&cnt, pre_p, NULL, is_gimple_val, - fb_rvalue) == GS_ERROR) - return 2; - tcnt = size_binop_loc (loc, MULT_EXPR, tcnt, cnt); - } - if (gimplify_expr (&tcnt, pre_p, NULL, is_gimple_val, - fb_rvalue) == GS_ERROR) + tree tcnt = compute_omp_iterator_count (TREE_PURPOSE (t), + pre_p); + if (!tcnt) return 2; last_iter = TREE_PURPOSE (t); last_count = tcnt; @@ -9913,91 +10095,13 @@ gimplify_omp_depend (tree *list_p, gimple_seq *pre_p) gcc_unreachable (); } tree t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == TREE_LIST - && TREE_PURPOSE (t) - && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + if (OMP_ITERATOR_DECL_P (t)) { if (TREE_PURPOSE (t) != last_iter) { - if (last_bind) - gimplify_and_add (last_bind, pre_p); - tree block = TREE_VEC_ELT (TREE_PURPOSE (t), 5); - last_bind = build3 (BIND_EXPR, void_type_node, - BLOCK_VARS (block), NULL, block); - TREE_SIDE_EFFECTS (last_bind) = 1; + last_body = build_omp_iterator_loop (TREE_PURPOSE (t), pre_p, + &last_bind); SET_EXPR_LOCATION (last_bind, OMP_CLAUSE_LOCATION (c)); - tree *p = &BIND_EXPR_BODY (last_bind); - for (tree it = TREE_PURPOSE (t); it; it = TREE_CHAIN (it)) - { - tree var = TREE_VEC_ELT (it, 0); - tree begin = TREE_VEC_ELT (it, 1); - tree end = TREE_VEC_ELT (it, 2); - tree step = TREE_VEC_ELT (it, 3); - tree orig_step = TREE_VEC_ELT (it, 4); - tree type = TREE_TYPE (var); - location_t loc = DECL_SOURCE_LOCATION (var); - /* Emit: - var = begin; - goto cond_label; - beg_label: - ... - var = var + step; - cond_label: - if (orig_step > 0) { - if (var < end) goto beg_label; - } else { - if (var > end) goto beg_label; - } - for each iterator, with inner iterators added to - the ... above. */ - tree beg_label = create_artificial_label (loc); - tree cond_label = NULL_TREE; - tem = build2_loc (loc, MODIFY_EXPR, void_type_node, - var, begin); - append_to_statement_list_force (tem, p); - tem = build_and_jump (&cond_label); - append_to_statement_list_force (tem, p); - tem = build1 (LABEL_EXPR, void_type_node, beg_label); - append_to_statement_list (tem, p); - tree bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, - NULL_TREE, NULL_TREE); - TREE_SIDE_EFFECTS (bind) = 1; - SET_EXPR_LOCATION (bind, loc); - append_to_statement_list_force (bind, p); - if (POINTER_TYPE_P (type)) - tem = build2_loc (loc, POINTER_PLUS_EXPR, type, - var, fold_convert_loc (loc, sizetype, - step)); - else - tem = build2_loc (loc, PLUS_EXPR, type, var, step); - tem = build2_loc (loc, MODIFY_EXPR, void_type_node, - var, tem); - append_to_statement_list_force (tem, p); - tem = build1 (LABEL_EXPR, void_type_node, cond_label); - append_to_statement_list (tem, p); - tree cond = fold_build2_loc (loc, LT_EXPR, - boolean_type_node, - var, end); - tree pos - = fold_build3_loc (loc, COND_EXPR, void_type_node, - cond, build_and_jump (&beg_label), - void_node); - cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, - var, end); - tree neg - = fold_build3_loc (loc, COND_EXPR, void_type_node, - cond, build_and_jump (&beg_label), - void_node); - tree osteptype = TREE_TYPE (orig_step); - cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, - orig_step, - build_int_cst (osteptype, 0)); - tem = fold_build3_loc (loc, COND_EXPR, void_type_node, - cond, pos, neg); - append_to_statement_list_force (tem, p); - p = &BIND_EXPR_BODY (bind); - } - last_body = p; } last_iter = TREE_PURPOSE (t); if (TREE_CODE (TREE_VALUE (t)) == COMPOUND_EXPR) |