aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.cc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2022-10-06 08:56:48 +0200
committerJakub Jelinek <jakub@redhat.com>2022-10-06 08:56:48 +0200
commit08b51baddc53d64aa4c5e7a81ef3c4bf320293be (patch)
treef6bdda9f6abdade347d75edeb8c2c5f8075f9cce /gcc/fold-const.cc
parent5fc4d3e1837ea4850aac6460f563913f1d3fc5b8 (diff)
downloadgcc-08b51baddc53d64aa4c5e7a81ef3c4bf320293be.zip
gcc-08b51baddc53d64aa4c5e7a81ef3c4bf320293be.tar.gz
gcc-08b51baddc53d64aa4c5e7a81ef3c4bf320293be.tar.bz2
c++, c: Implement C++23 P1774R8 - Portable assumptions [PR106654]
The following patch implements C++23 P1774R8 - Portable assumptions paper, by introducing support for [[assume (cond)]]; attribute for C++. In addition to that the patch adds [[gnu::assume (cond)]]; and __attribute__((assume (cond))); support to both C and C++. As described in C++23, the attribute argument is conditional-expression rather than the usual assignment-expression for attribute arguments, the condition is contextually converted to bool (for C truthvalue conversion is done on it) and is never evaluated at runtime. For C++ constant expression evaluation, I only check the simplest conditions for undefined behavior, because otherwise I'd need to undo changes to *ctx->global which happened during the evaluation (but I believe the spec allows that and we can further improve later). The patch uses a new internal function, .ASSUME, to hold the condition in the FEs. At gimplification time, if the condition is simple/without side-effects, it is gimplified as if (cond) ; else __builtin_unreachable (); and otherwise for now dropped on the floor. The intent is to incrementally outline the conditions into separate artificial functions and use .ASSUME further to tell the ranger and perhaps other optimization passes about the assumptions, as detailed in the PR. When implementing it, I found that assume entry hasn't been added to https://eel.is/c++draft/cpp.cond#6 Jonathan said he'll file a NB comment about it, this patch assumes it has been added into the table as 202207L when the paper has been voted in. With the attributes for both C/C++, I'd say we don't need to add __builtin_assume with similar purpose, especially when __builtin_assume in LLVM is just weird. It is strange for side-effects in function call's argument not to be evaluated, and LLVM in that case (annoyingly) warns and ignores the side-effects (but doesn't do then anything with it), if there are no side-effects, it will work like our if (!cond) __builtin_unreachable (); 2022-10-06 Jakub Jelinek <jakub@redhat.com> PR c++/106654 gcc/ * internal-fn.def (ASSUME): New internal function. * internal-fn.h (expand_ASSUME): Declare. * internal-fn.cc (expand_ASSUME): Define. * gimplify.cc (gimplify_call_expr): Gimplify IFN_ASSUME. * fold-const.h (simple_condition_p): Declare. * fold-const.cc (simple_operand_p_2): Rename to ... (simple_condition_p): ... this. Remove forward declaration. No longer static. Adjust function comment and fix a typo in it. Adjust recursive call. (simple_operand_p): Adjust function comment. (fold_truth_andor): Adjust simple_operand_p_2 callers to call simple_condition_p. * doc/extend.texi: Document assume attribute. Move fallthrough attribute example to its section. gcc/c-family/ * c-attribs.cc (handle_assume_attribute): New function. (c_common_attribute_table): Add entry for assume attribute. * c-lex.cc (c_common_has_attribute): Handle __have_cpp_attribute (assume). gcc/c/ * c-parser.cc (handle_assume_attribute): New function. (c_parser_declaration_or_fndef): Handle assume attribute. (c_parser_attribute_arguments): Add assume_attr argument, if true, parse first argument as conditional expression. (c_parser_gnu_attribute, c_parser_std_attribute): Adjust c_parser_attribute_arguments callers. (c_parser_statement_after_labels) <case RID_ATTRIBUTE>: Handle assume attribute. gcc/cp/ * cp-tree.h (process_stmt_assume_attribute): Implement C++23 P1774R8 - Portable assumptions. Declare. (diagnose_failing_condition): Declare. (find_failing_clause): Likewise. * parser.cc (assume_attr): New enumerator. (cp_parser_parenthesized_expression_list): Handle assume_attr. Remove identifier variable, for id_attr push the identifier into expression_list right away instead of inserting it before all the others at the end. (cp_parser_conditional_expression): New function. (cp_parser_constant_expression): Use it. (cp_parser_statement): Handle assume attribute. (cp_parser_expression_statement): Likewise. (cp_parser_gnu_attribute_list): Use assume_attr for assume attribute. (cp_parser_std_attribute): Likewise. Handle standard assume attribute like gnu::assume. * cp-gimplify.cc (process_stmt_assume_attribute): New function. * constexpr.cc: Include fold-const.h. (find_failing_clause_r, find_failing_clause): New functions, moved from semantics.cc with ctx argument added and if non-NULL, call cxx_eval_constant_expression rather than fold_non_dependent_expr. (cxx_eval_internal_function): Handle IFN_ASSUME. (potential_constant_expression_1): Likewise. * pt.cc (tsubst_copy_and_build): Likewise. * semantics.cc (diagnose_failing_condition): New function. (find_failing_clause_r, find_failing_clause): Moved to constexpr.cc. (finish_static_assert): Use it. Add auto_diagnostic_group. gcc/testsuite/ * gcc.dg/attr-assume-1.c: New test. * gcc.dg/attr-assume-2.c: New test. * gcc.dg/attr-assume-3.c: New test. * g++.dg/cpp2a/feat-cxx2a.C: Add colon to C++20 features comment, add C++20 attributes comment and move C++20 new features after the attributes before them. * g++.dg/cpp23/feat-cxx2b.C: Likewise. Test __has_cpp_attribute(assume). * g++.dg/cpp23/attr-assume1.C: New test. * g++.dg/cpp23/attr-assume2.C: New test. * g++.dg/cpp23/attr-assume3.C: New test. * g++.dg/cpp23/attr-assume4.C: New test.
Diffstat (limited to 'gcc/fold-const.cc')
-rw-r--r--gcc/fold-const.cc28
1 files changed, 13 insertions, 15 deletions
diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 4f4ec81..9f7beae 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -130,7 +130,6 @@ static tree eval_subst (location_t, tree, tree, tree, tree, tree);
static tree optimize_bit_field_compare (location_t, enum tree_code,
tree, tree, tree);
static bool simple_operand_p (const_tree);
-static bool simple_operand_p_2 (tree);
static tree range_binop (enum tree_code, tree, tree, int, tree, int);
static tree range_predecessor (tree);
static tree range_successor (tree);
@@ -4868,8 +4867,8 @@ sign_bit_p (tree exp, const_tree val)
return NULL_TREE;
}
-/* Subroutine for fold_truth_andor_1: determine if an operand is simple enough
- to be evaluated unconditionally. */
+/* Subroutine for fold_truth_andor_1 and simple_condition_p: determine if an
+ operand is simple enough to be evaluated unconditionally. */
static bool
simple_operand_p (const_tree exp)
@@ -4897,13 +4896,12 @@ simple_operand_p (const_tree exp)
&& (! TREE_STATIC (exp) || DECL_REGISTER (exp))));
}
-/* Subroutine for fold_truth_andor: determine if an operand is simple enough
- to be evaluated unconditionally.
- I addition to simple_operand_p, we assume that comparisons, conversions,
+/* Determine if an operand is simple enough to be evaluated unconditionally.
+ In addition to simple_operand_p, we assume that comparisons, conversions,
and logic-not operations are simple, if their operands are simple, too. */
-static bool
-simple_operand_p_2 (tree exp)
+bool
+simple_condition_p (tree exp)
{
enum tree_code code;
@@ -4920,7 +4918,7 @@ simple_operand_p_2 (tree exp)
&& simple_operand_p (TREE_OPERAND (exp, 1)));
if (code == TRUTH_NOT_EXPR)
- return simple_operand_p_2 (TREE_OPERAND (exp, 0));
+ return simple_condition_p (TREE_OPERAND (exp, 0));
return simple_operand_p (exp);
}
@@ -9787,10 +9785,10 @@ fold_truth_andor (location_t loc, enum tree_code code, tree type,
side-effects, or isn't simple, then we can't add to it,
as otherwise we might destroy if-sequence. */
if (TREE_CODE (arg0) == icode
- && simple_operand_p_2 (arg1)
+ && simple_condition_p (arg1)
/* Needed for sequence points to handle trappings, and
side-effects. */
- && simple_operand_p_2 (TREE_OPERAND (arg0, 1)))
+ && simple_condition_p (TREE_OPERAND (arg0, 1)))
{
tem = fold_build2_loc (loc, ncode, type, TREE_OPERAND (arg0, 1),
arg1);
@@ -9800,10 +9798,10 @@ fold_truth_andor (location_t loc, enum tree_code code, tree type,
/* Same as above but for (A AND[-IF] (B AND-IF C)) -> ((A AND B) AND-IF C),
or (A OR[-IF] (B OR-IF C) -> ((A OR B) OR-IF C). */
else if (TREE_CODE (arg1) == icode
- && simple_operand_p_2 (arg0)
+ && simple_condition_p (arg0)
/* Needed for sequence points to handle trappings, and
side-effects. */
- && simple_operand_p_2 (TREE_OPERAND (arg1, 0)))
+ && simple_condition_p (TREE_OPERAND (arg1, 0)))
{
tem = fold_build2_loc (loc, ncode, type,
arg0, TREE_OPERAND (arg1, 0));
@@ -9814,8 +9812,8 @@ fold_truth_andor (location_t loc, enum tree_code code, tree type,
into (A OR B).
For sequence point consistancy, we need to check for trapping,
and side-effects. */
- else if (code == icode && simple_operand_p_2 (arg0)
- && simple_operand_p_2 (arg1))
+ else if (code == icode && simple_condition_p (arg0)
+ && simple_condition_p (arg1))
return fold_build2_loc (loc, ncode, type, arg0, arg1);
}