diff options
Diffstat (limited to 'gcc/gimplify.c')
-rw-r--r-- | gcc/gimplify.c | 181 |
1 files changed, 169 insertions, 12 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c index d461d776ee8..34ffaf18974 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -619,6 +619,25 @@ mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data) return NULL_TREE; } +/* APPLE LOCAL begin PR 14498, etc --bowdidge */ +/* This routine was deleted from FSF mainline and lno-branch; however, + we're still using it in the next routine. Keep a local copy until + we can rewrite that other stuff. The FIXME on this worries me. */ + +/* Mark all the _DECL nodes under *TP as volatile. FIXME: This must die + after VA_ARG_EXPRs are properly lowered. */ + +static tree +mark_decls_volatile_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + if (SSA_VAR_P (*tp)) + TREE_THIS_VOLATILE (*tp) = 1; + + return NULL_TREE; +} +/* APPLE LOCAL end PR 14498, etc --bowdidge */ + /* Callback for walk_tree to unshare most of the shared trees rooted at *TP. If *TP has been visited already (i.e., TREE_VISITED (*TP) == 1), then *TP is deep copied by calling copy_tree_r. @@ -659,7 +678,24 @@ copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, /* Otherwise, mark the tree as visited and keep looking. */ else - TREE_VISITED (t) = 1; + /* APPLE LOCAL begin PR 14498 etc. --dbj */ + /* History is complicated, this was in mainline prior to merge, + temporarily and erroneously removed at merge snapshot, + later put back, still later replaced by different mechanism. */ + { + TREE_VISITED (t) = 1; + if (TREE_CODE (*tp) == VA_ARG_EXPR) + { + /* Mark any _DECL inside the operand as volatile to avoid + the optimizers messing around with it. We have to do this + early, otherwise we might mark a variable as volatile + after we gimplify other statements that use the variable + assuming it's not volatile. */ + walk_tree (&TREE_OPERAND (*tp, 0), mark_decls_volatile_r, + NULL, NULL); + } + } + /* APPLE LOCAL end PR 14498 etc. */ return NULL_TREE; } @@ -2123,7 +2159,8 @@ gimple_boolify (tree expr) *EXPR_P should be stored. */ static enum gimplify_status -gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target) +gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target, + fallback_t fallback) { tree expr = *expr_p; tree tmp, tmp2, type; @@ -2137,18 +2174,40 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target) the arms. */ else if (! VOID_TYPE_P (type)) { + tree result; + if (target) { ret = gimplify_expr (&target, pre_p, post_p, is_gimple_min_lval, fb_lvalue); if (ret != GS_ERROR) ret = GS_OK; - tmp = target; + result = tmp = target; tmp2 = unshare_expr (target); } + else if ((fallback & fb_lvalue) == 0) + { + result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp"); + ret = GS_ALL_DONE; + } else { - tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp"); + tree type = build_pointer_type (TREE_TYPE (expr)); + + if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node) + TREE_OPERAND (expr, 1) = + build_fold_addr_expr (TREE_OPERAND (expr, 1)); + + if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node) + TREE_OPERAND (expr, 2) = + build_fold_addr_expr (TREE_OPERAND (expr, 2)); + + tmp2 = tmp = create_tmp_var (type, "iftmp"); + + expr = build (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0), + TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 2)); + + result = build_fold_indirect_ref (tmp); ret = GS_ALL_DONE; } @@ -2169,7 +2228,7 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target) /* Move the COND_EXPR to the prequeue. */ gimplify_and_add (expr, pre_p); - *expr_p = tmp; + *expr_p = result; return ret; } @@ -2907,7 +2966,8 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p, if (!is_gimple_reg_type (TREE_TYPE (*from_p))) { *expr_p = *from_p; - return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p); + return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p, + fb_rvalue); } else ret = GS_UNHANDLED; @@ -3207,6 +3267,9 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p) builtins like __builtin_va_end). */ /* Caution: the silent array decomposition semantics we allow for ADDR_EXPR means we can't always discard the pair. */ + /* Gimplification of the ADDR_EXPR operand may drop + cv-qualification conversions, so make sure we add them if + needed. */ { tree op00 = TREE_OPERAND (op0, 0); tree t_expr = TREE_TYPE (expr); @@ -3216,9 +3279,9 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p) { #ifdef ENABLE_CHECKING tree t_op0 = TREE_TYPE (op0); - gcc_assert (TREE_CODE (t_op0) == ARRAY_TYPE - && POINTER_TYPE_P (t_expr) - && cpt_same_type (TREE_TYPE (t_op0), + gcc_assert (POINTER_TYPE_P (t_expr) + && cpt_same_type (TREE_CODE (t_op0) == ARRAY_TYPE + ? TREE_TYPE (t_op0) : t_op0, TREE_TYPE (t_expr)) && POINTER_TYPE_P (t_op00) && cpt_same_type (t_op0, TREE_TYPE (t_op00))); @@ -3330,16 +3393,81 @@ gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p) char *p = xstrdup (constraint); p[0] = '='; TREE_VALUE (TREE_PURPOSE (link)) = build_string (constraint_len, p); - free (p); /* And add a matching input constraint. */ if (allows_reg) { sprintf (buf, "%d", i); - input = build_string (strlen (buf), buf); + + /* If there are multiple alternatives in the constraint, + handle each of them individually. Those that allow register + will be replaced with operand number, the others will stay + unchanged. */ + if (strchr (p, ',') != NULL) + { + size_t len = 0, buflen = strlen (buf); + char *beg, *end, *str, *dst; + + for (beg = p + 1;;) + { + end = strchr (beg, ','); + if (end == NULL) + end = strchr (beg, '\0'); + if ((size_t) (end - beg) < buflen) + len += buflen + 1; + else + len += end - beg + 1; + if (*end) + beg = end + 1; + else + break; + } + + str = alloca (len); + for (beg = p + 1, dst = str;;) + { + const char *tem; + bool mem_p, reg_p, inout_p; + + end = strchr (beg, ','); + if (end) + *end = '\0'; + beg[-1] = '='; + tem = beg - 1; + parse_output_constraint (&tem, i, 0, 0, + &mem_p, ®_p, &inout_p); + if (dst != str) + *dst++ = ','; + if (reg_p) + { + memcpy (dst, buf, buflen); + dst += buflen; + } + else + { + if (end) + len = end - beg; + else + len = strlen (beg); + memcpy (dst, beg, len); + dst += len; + } + if (end) + beg = end + 1; + else + break; + } + *dst = '\0'; + input = build_string (dst - str, str); + } + else + input = build_string (strlen (buf), buf); } else input = build_string (constraint_len - 1, constraint + 1); + + free (p); + input = build_tree_list (build_tree_list (NULL_TREE, input), unshare_expr (TREE_VALUE (link))); ASM_INPUTS (expr) = chainon (ASM_INPUTS (expr), input); @@ -3721,11 +3849,30 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, break; case COND_EXPR: - ret = gimplify_cond_expr (expr_p, pre_p, post_p, NULL_TREE); + ret = gimplify_cond_expr (expr_p, pre_p, post_p, NULL_TREE, + fallback); + /* C99 code may assign to an array in a structure value of a + conditional expression, and this has undefined behavior + only on execution, so create a temporary if an lvalue is + required. */ + if (fallback == fb_lvalue) + { + *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p); + lang_hooks.mark_addressable (*expr_p); + } break; case CALL_EXPR: ret = gimplify_call_expr (expr_p, pre_p, fallback != fb_none); + /* C99 code may assign to an array in a structure returned + from a function, and this has undefined behavior only on + execution, so create a temporary if an lvalue is + required. */ + if (fallback == fb_lvalue) + { + *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p); + lang_hooks.mark_addressable (*expr_p); + } break; case TREE_LIST: @@ -3805,6 +3952,16 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, case MISALIGNED_INDIRECT_REF: ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_gimple_reg, fb_rvalue); + + /* APPLE LOCAL begin Radar 4124724 */ + /* Useless type conversions may have been discarded, so ensure + that the INDIRECT_REF has a type corresponding to the pointee + type of its operand. */ + if (TREE_CODE (*expr_p) == INDIRECT_REF) + TREE_TYPE (*expr_p) + = TREE_TYPE (TREE_TYPE (TREE_OPERAND (*expr_p, 0))); + /* APPLE LOCAL end Radar 4124724 */ + recalculate_side_effects (*expr_p); break; |