[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