[Bug libstdc++/86590] Codegen is poor when passing std::string by value with _GLIBCXX_EXTERN_TEMPLATE undefined
jakub at gcc dot gnu.org
gcc-bugzilla@gcc.gnu.org
Fri Jul 20 11:53:00 GMT 2018
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86590
Jakub Jelinek <jakub at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |jason at gcc dot gnu.org,
| |nathan at gcc dot gnu.org
--- Comment #23 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
So, I've tried to implement this, but so far failed:
--- gcc/builtins.def.jj 2018-06-20 08:15:34.179862153 +0200
+++ gcc/builtins.def 2018-07-20 12:03:10.254453811 +0200
@@ -974,6 +974,11 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_PRINTF_
DEF_EXT_LIB_BUILTIN (BUILT_IN_VFPRINTF_CHK, "__vfprintf_chk",
BT_FN_INT_FILEPTR_INT_CONST_STRING_VALIST_ARG,
ATTR_NONNULL_1_FORMAT_PRINTF_3_0)
DEF_EXT_LIB_BUILTIN (BUILT_IN_VPRINTF_CHK, "__vprintf_chk",
BT_FN_INT_INT_CONST_STRING_VALIST_ARG, ATTR_FORMAT_PRINTF_2_0)
+/* C++ __builtin_is_constant_evaluated. */
+DEF_BUILTIN (BUILT_IN_IS_CONSTANT_EVALUATED,
"__builtin_is_constant_evaluated",
+ BUILT_IN_NORMAL, BT_FN_BOOL, BT_LAST, false, false, false,
+ ATTR_CONST_NOTHROW_LEAF_LIST, true, c_dialect_cxx ())
+
/* Profiling hooks. */
DEF_BUILTIN (BUILT_IN_PROFILE_FUNC_ENTER, "__cyg_profile_func_enter",
BUILT_IN_NORMAL, BT_FN_VOID_PTR_PTR, BT_LAST,
false, false, false, ATTR_NULL, true, true)
--- gcc/builtins.c.jj 2018-07-16 23:24:51.306429546 +0200
+++ gcc/builtins.c 2018-07-20 12:09:13.278818768 +0200
@@ -9104,6 +9104,10 @@ fold_builtin_0 (location_t loc, tree fnd
case BUILT_IN_CLASSIFY_TYPE:
return fold_builtin_classify_type (NULL_TREE);
+ case BUILT_IN_IS_CONSTANT_EVALUATED:
+ /* The C++ FE can evaluate this to something other than false. */
+ return boolean_false_node;
+
default:
break;
}
--- gcc/cp/constexpr.c.jj 2018-06-25 14:51:23.094989194 +0200
+++ gcc/cp/constexpr.c 2018-07-20 12:54:35.781999003 +0200
@@ -1184,6 +1184,18 @@ cxx_eval_builtin_function_call (const co
return t;
}
+ /* For __builtin_is_constant_evaluated, defer it if ctx->quiet, otherwise
+ fold it to true. */
+ if (DECL_FUNCTION_CODE (fun) == BUILT_IN_IS_CONSTANT_EVALUATED)
+ {
+ if (0 && ctx->quiet)
+ {
+ *non_constant_p = true;
+ return t;
+ }
+ return boolean_true_node;
+ }
+
/* Be permissive for arguments to built-ins; __builtin_constant_p should
return constant false for a non-constant argument. */
constexpr_ctx new_ctx = *ctx;
--- gcc/cp/cp-gimplify.c.jj 2018-07-20 11:39:15.543037497 +0200
+++ gcc/cp/cp-gimplify.c 2018-07-20 12:21:29.869568404 +0200
@@ -2478,6 +2478,12 @@ cp_fold (tree x)
&& DECL_DECLARED_CONSTEXPR_P (current_function_decl))
nw = 1;
+ /* Defer folding __builtin_is_constant_evaluated. */
+ if (callee
+ && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (callee) == BUILT_IN_IS_CONSTANT_EVALUATED)
+ break;
+
x = copy_node (x);
m = call_expr_nargs (x);
--- gcc/lto/lto-lang.c.jj 2018-06-13 10:05:49.991124932 +0200
+++ gcc/lto/lto-lang.c 2018-07-20 12:29:28.087207392 +0200
@@ -246,6 +246,7 @@ static GTY(()) tree signed_size_type_nod
int flag_isoc94;
int flag_isoc99;
int flag_isoc11;
+#define c_dialect_cxx() 0
/* Attribute handlers. */
Given the fixed up testcase from p0595r1 with
s/std::is_constant_evaluated()/__builtin_is_constant_evaluated ()/:
template<int> struct X {};
X<__builtin_is_constant_evaluated ()> x; // type X<true>
int y = 4;
int a = __builtin_is_constant_evaluated () ? y : 1; // initializes a to 1
int b = __builtin_is_constant_evaluated () ? 2 : y; // initializes b to 2
int c = y + (__builtin_is_constant_evaluated () ? 2 : y); // initializes c to
2*y
constexpr int
f ()
{
const int n = __builtin_is_constant_evaluated () ? 13 : 17; // n == 13
int m = __builtin_is_constant_evaluated () ? 13 : 17; // m might be 13 or 17
(see below)
char arr[n] = {}; // char[13]
return m + sizeof (arr);
}
int p = f (); // m == 13; initialized to 26
int q = p + f (); // m == 17 for this call; initialized to 56
struct false_type { static constexpr bool value = false; };
struct true_type { static constexpr bool value = true; };
template<class T, class U>
struct is_same : false_type {};
template<class T>
struct is_same<T, T> : true_type {};
static_assert (is_same<decltype (x), X<true> >::value, "x's type");
int
main ()
{
if (a != 1 || b != 2 || c != 8 || p != 26 || q != 56)
__builtin_abort ();
}
a, b, c, x, p are correct. In the out-of-line copy of f (if I force it), both
n and m are actually 13 and q is 52 rather than 56.
If I remove the 0 && part from the patch, so that
__builtin_is_constant_evaluated () is evaluated to true only if ctx->quiet is
false and otherwise deferred,
then a, c and x are correct, b is though 4 (i.e. y), p is 34, q is 68 and in f
arr is a VLA.
The description doesn't seem to be unambiguous:
"An expression e is required to be constant-evaluated if:
it is a constant-expression (_expr.const_), or"
and later it says that std::is_constant_evaluated () is a core-constant
expression. From the example it seems they really want
to talk about outermost expression that needs to be evaluated, but the wording
to me sounds like std::is_constant_evaluated () should always return true,
because std::is_constant_evaluated () itself is an expression e that is a
constant expression, similarly for
int z;
int b = z + (std::is_constant_evaluated () + 2);
one could argue that e being std::is_constant_evaluated () + 2 is a
constant-expression (but e being z + (std::is_constant_evaluated () + 2)
already is not a constant expression).
Now, even if we consider that it means only outermost constant expression,
isn't in
int m = __builtin_is_constant_evaluated () ? 13 : 17;
__builtin_is_constant_evaluated () ? 13 : 17 the outermost expression which is
a constant expression and thus in there should the magic builtin evaluate to
true?
Or is there the intent that inside of constexpr functions the "it is a
constant-expression (_expr.const_)" doesn't hold, unless it is one of the other
cases?
More information about the Gcc-bugs
mailing list