https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118068
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jason at gcc dot gnu.org --- Comment #7 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Marek/Jason, what do you think about doing cp_walk_tree with cp_fold_immediate_r callback from cp_fold_function and cp_fully_fold_init? Though, tried --- gcc/cp/cp-gimplify.cc.jj 2025-02-01 00:47:07.881079292 +0100 +++ gcc/cp/cp-gimplify.cc 2025-03-06 15:31:11.713951494 +0100 @@ -1204,7 +1204,8 @@ cp_build_init_expr_for_ctor (tree call, return init; } -/* A subroutine of cp_fold_r to handle immediate functions. */ +/* A walk_tree callback for cp_fold_function and cp_fully_fold_init to handle + immediate functions. */ static tree cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_) @@ -1370,45 +1371,8 @@ cp_fold_r (tree *stmt_p, int *walk_subtr tree stmt = *stmt_p; enum tree_code code = TREE_CODE (stmt); - if (cxx_dialect >= cxx20) - { - /* Unfortunately we must handle code like - false ? bar () : 42 - where we have to check bar too. The cp_fold call below could - fold the ?: into a constant before we've checked it. */ - if (code == COND_EXPR) - { - auto then_fn = cp_fold_r, else_fn = cp_fold_r; - /* See if we can figure out if either of the branches is dead. If it - is, we don't need to do everything that cp_fold_r does. */ - cp_walk_tree (&TREE_OPERAND (stmt, 0), cp_fold_r, data, nullptr); - if (integer_zerop (TREE_OPERAND (stmt, 0))) - then_fn = cp_fold_immediate_r; - else if (integer_nonzerop (TREE_OPERAND (stmt, 0))) - else_fn = cp_fold_immediate_r; - - if (TREE_OPERAND (stmt, 1)) - cp_walk_tree (&TREE_OPERAND (stmt, 1), then_fn, data, - nullptr); - if (TREE_OPERAND (stmt, 2)) - cp_walk_tree (&TREE_OPERAND (stmt, 2), else_fn, data, - nullptr); - *walk_subtrees = 0; - /* Don't return yet, still need the cp_fold below. */ - } - else - cp_fold_immediate_r (stmt_p, walk_subtrees, data); - } - *stmt_p = stmt = cp_fold (*stmt_p, data->flags); - /* For certain trees, like +foo(), the cp_fold above will remove the +, - and the subsequent tree walk would go straight down to the CALL_EXPR's - operands, meaning that cp_fold_immediate_r would never see the - CALL_EXPR. Ew :(. */ - if (TREE_CODE (stmt) == CALL_EXPR && code != CALL_EXPR) - cp_fold_immediate_r (stmt_p, walk_subtrees, data); - if (data->pset.add (stmt)) { /* Don't walk subtrees of stmts we've already walked once, otherwise @@ -1537,6 +1501,13 @@ cp_fold_function (tree fndecl) been constant-evaluated already if possible, so we can safely pass ff_mce_false. */ cp_fold_data data (ff_genericize | ff_mce_false); + /* Do cp_fold_immediate_r in separate whole IL walk instead of during + cp_fold_r, as otherwise expressions using results of immediate functions + might not be folded as cp_fold is called on those before cp_fold_r is + called on their argument. And calling cp_fold_immediate_r during + cp_fold can mean evaluation of the immediate functions many times. */ + if (cxx_dialect >= cxx20) + cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_immediate_r, &data, NULL); cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_r, &data, NULL); /* This is merely an optimization: if FNDECL has no i-e expressions, @@ -2910,6 +2881,8 @@ cp_fully_fold_init (tree x) return x; x = cp_fully_fold (x, mce_false); cp_fold_data data (ff_mce_false); + if (cxx_dialect >= cxx20) + cp_walk_tree (&x, cp_fold_immediate_r, &data, NULL); cp_walk_tree (&x, cp_fold_r, &data, NULL); return x; } --- gcc/testsuite/g++.target/i386/pr118068.C.jj 2025-03-06 15:25:59.849944651 +0100 +++ gcc/testsuite/g++.target/i386/pr118068.C 2025-03-06 15:25:51.152064565 +0100 @@ -0,0 +1,17 @@ +// PR target/118068 +// { dg-do compile { target c++20 } } +// { dg-options "-O0 -mavx" } + +typedef float V __attribute__((vector_size (32))); + +consteval unsigned char +foo (int x) +{ + return x; +} + +V +bar (V x, V y) +{ + return __builtin_ia32_blendps256 (x, y, (int) foo (0x23)); +} and so far saw FAIL: g++.dg/cpp23/consteval-if1.C -std=gnu++20 (test for excess errors) FAIL: g++.dg/cpp23/consteval-if1.C -std=gnu++23 (test for excess errors) FAIL: g++.dg/cpp23/consteval-if1.C -std=gnu++26 (test for excess errors) FAIL: g++.dg/cpp23/consteval-if10.C -std=gnu++20 (test for excess errors) FAIL: g++.dg/cpp23/consteval-if10.C -std=gnu++23 (test for excess errors) FAIL: g++.dg/cpp23/consteval-if10.C -std=gnu++26 (test for excess errors) FAIL: g++.dg/cpp23/consteval-if11.C -std=gnu++20 (test for excess errors) FAIL: g++.dg/cpp23/consteval-if11.C -std=gnu++23 (test for excess errors) FAIL: g++.dg/cpp23/consteval-if11.C -std=gnu++26 (test for excess errors) FAIL: g++.dg/cpp23/consteval-if13.C -std=c++23 (test for excess errors) FAIL: g++.dg/cpp23/consteval-if13.C -std=c++26 (test for excess errors) FAIL: g++.dg/cpp2a/consteval-prop15.C -std=gnu++20 (test for excess errors) FAIL: g++.dg/cpp2a/consteval-prop15.C -std=gnu++23 (test for excess errors) FAIL: g++.dg/cpp2a/consteval-prop15.C -std=gnu++26 (test for excess errors) FAIL: g++.dg/cpp2a/consteval-prop8.C -std=gnu++20 (test for excess errors) FAIL: g++.dg/cpp2a/consteval-prop17.C -std=gnu++20 (test for excess errors) FAIL: g++.dg/cpp2a/consteval-prop8.C -std=gnu++23 (test for excess errors) FAIL: g++.dg/cpp2a/consteval-prop1.C -std=c++20 (test for excess errors) FAIL: g++.dg/cpp2a/consteval-prop17.C -std=gnu++23 (test for excess errors) FAIL: g++.dg/cpp2a/consteval-prop8.C -std=gnu++26 (test for excess errors) FAIL: g++.dg/cpp2a/consteval-prop17.C -std=gnu++26 (test for excess errors) FAIL: g++.dg/cpp2a/consteval-prop1.C -std=c++23 (test for excess errors) FAIL: g++.dg/cpp2a/consteval-prop1.C -std=c++26 (test for excess errors) regressions.