> On 8 Oct 2025, at 16:04, Jason Merrill <[email protected]> wrote:
> 
> On 10/8/25 3:08 PM, Iain Sandoe wrote:
>>>> Otherwise, I’m looking for guidance on what’s needed to land this.
>>> IIRC the paper talks about a call to an unknown function having the desired 
>>> semantics.  I’ll go with that, making it not throwing, const but looping 
>>> and leaf.  We can make it stronger if necessary, weakening it after people 
>>> rely on semantics is less useful IMO.  On RTL we have nothing at all, I’ve 
>>> heard ,volatile‘ asm is only about missing outputs, not side effects in 
>>> general.  So I’d expand to nothing on RTL, watching what breaks.
>> with a follow up to a query
>>> I suggest to remove the assert or replace it with one that checks that if 
>>> ECF_LOOPING_CONST_OR_PURE is set the function is either ECF_CONST or 
>>> ECF_PURE.
>> Done and re-tested on x86_64-darwin24 and powerpc64le-linux, OK for trunk 
>> now?
>> thanks
>> Iain
>> --- 8< ---
>> P1494 provides a mechanism that serves to demarc epochs within the code
>> preventing UB-based optimisations from 'time traveling' across such
>> boundaries.  The additional paper, P3641, alters the name of the function
>> to 'observable_checkpoint' which is the name used here.
>> This implementation  maintains the observable function call through to
>> expand, where it produces no code.
>> PR c++/119060
>> gcc/ChangeLog:
>> * builtins.cc (expand_builtin): Handle BUILT_IN_OBSERVABLE_CHKPT.
>> * builtins.def (BUILT_IN_OBSERVABLE_CHKPT): New.
>> * tree.cc (build_common_builtin_nodes): Build observable
>> checkpoint builtin.
>> gcc/cp/ChangeLog:
>> * cp-gimplify.cc (cp_fold): Handle std::observable_checkpoint
>> specially, lowering it to the builtin.
>> * cxxapi-data.csv: Add observable_checkpoint to <utility>.
>> * std-name-hint.gperf: Add observable_checkpoint to <utility>.
>> * std-name-hint.h: Regenerate.
>> gcc/testsuite/ChangeLog:
>> * g++.dg/cpp26/observable-checkpoint.C: New test.
>> Signed-off-by: Iain Sandoe <[email protected]>
>> ---
>>  gcc/builtins.cc                               |   4 +
>>  gcc/builtins.def                              |   1 +
>>  gcc/cp/cp-gimplify.cc                         |  16 ++
>>  gcc/cp/cxxapi-data.csv                        |   1 +
>>  gcc/cp/std-name-hint.gperf                    |   1 +
>>  gcc/cp/std-name-hint.h                        | 142 +++++++++---------
>>  .../g++.dg/cpp26/observable-checkpoint.C      |  25 +++
>>  gcc/tree.cc                                   |   9 +-
>>  8 files changed, 128 insertions(+), 71 deletions(-)
>>  create mode 100644 gcc/testsuite/g++.dg/cpp26/observable-checkpoint.C
>> diff --git a/gcc/builtins.cc b/gcc/builtins.cc
>> index 78b561529f5..fb294ce58cd 100644
>> --- a/gcc/builtins.cc
>> +++ b/gcc/builtins.cc
>> @@ -8427,6 +8427,10 @@ expand_builtin (tree exp, rtx target, rtx subtarget, 
>> machine_mode mode,
>>        expand_builtin_unreachable ();
>>        return const0_rtx;
>>  +    case BUILT_IN_OBSERVABLE_CHKPT:
>> +      /* Generate no code.  */
>> +      return const0_rtx;
>> +
>>      CASE_FLT_FN (BUILT_IN_SIGNBIT):
>>      case BUILT_IN_SIGNBITD32:
>>      case BUILT_IN_SIGNBITD64:
>> diff --git a/gcc/builtins.def b/gcc/builtins.def
>> index 3dc2333c6f2..7cd5353bcb1 100644
>> --- a/gcc/builtins.def
>> +++ b/gcc/builtins.def
>> @@ -1142,6 +1142,7 @@ DEF_C2Y_BUILTIN        (BUILT_IN_ULABS, "ulabs", 
>> BT_FN_ULONG_LONG, ATTR_CONST_NO
>>  DEF_C2Y_BUILTIN        (BUILT_IN_ULLABS, "ullabs", 
>> BT_FN_ULONGLONG_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
>>  DEF_GCC_BUILTIN        (BUILT_IN_UNREACHABLE_TRAP, "unreachable trap", 
>> BT_FN_VOID, ATTR_CONST_NORETURN_NOTHROW_LEAF_COLD_LIST)
>>  DEF_GCC_BUILTIN        (BUILT_IN_UNREACHABLE, "unreachable", BT_FN_VOID, 
>> ATTR_CONST_NORETURN_NOTHROW_LEAF_COLD_LIST)
>> +DEF_GCC_BUILTIN        (BUILT_IN_OBSERVABLE_CHKPT, "observable_checkpoint", 
>> BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
>>  DEF_GCC_BUILTIN        (BUILT_IN_UNWIND_INIT, "unwind_init", BT_FN_VOID, 
>> ATTR_NULL)
>>  DEF_GCC_BUILTIN        (BUILT_IN_UPDATE_SETJMP_BUF, "update_setjmp_buf", 
>> BT_FN_VOID_PTR, ATTR_NULL)
>>  DEF_GCC_BUILTIN        (BUILT_IN_VA_COPY, "va_copy", 
>> BT_FN_VOID_VALIST_REF_VALIST_ARG, ATTR_NOTHROW_LEAF_LIST)
>> diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
>> index 1662336e165..483d964bd62 100644
>> --- a/gcc/cp/cp-gimplify.cc
>> +++ b/gcc/cp/cp-gimplify.cc
>> @@ -3452,6 +3452,22 @@ cp_fold (tree x, fold_flags_t flags)
>>       break;
>>     }
>>  + /* We need to convert std::observable_checkpoint () into its equivalent
>> +    builtin for correctness, but must not rely on middle-end inlining
>> +    to do this; special-case it here.  */
> 
> Why is this necessary?  If it isn't inlined, it's still a call, and we talked 
> about an unknown call having the desired semantics.

As I understand the intention of the paper, the function is not supposed to 
generate any code - if, for some reason, it was not inlined then it would 
generate a call.

> There doesn't seem to be a testcase for std::observable_checkpoint to test 
> whether this change is needed.

I’d suppose we could just generate a case with -fno-inline and that would then 
produce a call that survives optimisation.

The std library function should just resolve to the builtin.

Iain

>> +
>> + if (call_expr_nargs (x) == 0
>> +     && decl_in_std_namespace_p (callee)
>> +     && DECL_NAME (callee) != NULL_TREE
>> +     && id_equal (DECL_NAME (callee), "observable_checkpoint"))
>> +   {
>> +     r = builtin_decl_explicit (BUILT_IN_OBSERVABLE_CHKPT);
>> +     releasing_vec vec;
>> +     r = finish_call_expr (r, &vec, false, false, tf_warning_or_error);
>> +     x = cp_fold (r, flags);
>> +     break;
>> +   }
>> +


Reply via email to