Skip to content
Open
12 changes: 12 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4340,6 +4340,18 @@ whole system, the current device, an OpenCL workgroup, wavefront, or just a
single thread. If these are used on a target that does not support atomic
scopes, then they will behave exactly as the standard GNU atomic builtins.

Constant evaluatable atomic builtins
------------------------------------

Clang supports constant evaluation of all ``__c11_atomic_*`` and GCC-compatible
``__atomic_*`` builtins. Behaviour of identical as if evaluating these builtins
in a single-threaded environment.
Comment on lines +4347 to +4348
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
``__atomic_*`` builtins. Behaviour of identical as if evaluating these builtins
in a single-threaded environment.
``__atomic_*`` builtins. The behavior is identical to evaluating these builtins
in a single-threaded environment.


(Note the GCC-compatible ``__atomic_fetch_OP`` and ``__atomic_OP_fetch``
builtins with a pointer argument operates as if pointer was pointing to bytes.
Evaluating these builtins which would result in a non-aligned pointer to pointee
Comment on lines +4351 to +4352
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
builtins with a pointer argument operates as if pointer was pointing to bytes.
Evaluating these builtins which would result in a non-aligned pointer to pointee
builtins with a pointer argument operates as if the pointer was pointing to bytes.
Evaluating these builtins in a way which would result in a non-aligned pointer to pointee

type is unsupported.)

Low-level ARM exclusive memory builtins
---------------------------------------

Expand Down
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,9 @@ C++2c Feature Support

- Implemented `P3176R1 The Oxford variadic comma <https://wg21.link/P3176R1>`_

- Making GCC and C11 atomic intrinsics evaluatable during constant evaluation,
which supports `P3309R3 constexpr atomic and atomic_ref <https://wg21.link/P3309R3>`_

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Removed the restriction to literal types in constexpr functions in C++23 mode.
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -6830,6 +6830,9 @@ class AtomicExpr : public Expr {
std::unique_ptr<AtomicScopeModel> getScopeModel() const {
return getScopeModel(getOp());
}

/// Helper function to check valid ordering for specified Op.
static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op);
};

/// TypoExpr - Internal placeholder for expressions where typo correction
Expand Down
80 changes: 40 additions & 40 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -1744,97 +1744,97 @@ def SyncSwapN : Builtin, SyncBuiltinsTemplate {
// C11 _Atomic operations for <stdatomic.h>.
def C11AtomicInit : AtomicBuiltin {
let Spellings = ["__c11_atomic_init"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicLoad : AtomicBuiltin {
let Spellings = ["__c11_atomic_load"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm worried about changing the C11 atomic builtins for a C++26 feature; I think there are more changes needed as a result. For example, changing this to be constexpr means we now run the risk of accepting this code in C: https://godbolt.org/z/hc3oqYx6b

We likely are missing test coverage for this kind of thing in C, so I would recommend 1) add test coverage to this PR and if it breaks as a result of these changes, then 2) I would probably add some getLangOpts().CPlusPlus checks in the constant expression evaluator. We could invent new tablegen to say "this is constexpr only in C++", but it's not clear to me whether there will be enough builtins that need such functionality or not, but that's another (cleaner, but a heavier lift for a new contributor) option.

Hmm, but I just remembered that __has_constexpr_builtin (https://clang.llvm.org/docs/LanguageExtensions.html#has-constexpr-builtin) is a thing, so we may need that tablegen solution after all because otherwise we change the behavior here in confusing ways: https://godbolt.org/z/qGY575MGr FWIW, here's an example of some recent changes to tablegen that you could model your changes after: https://github.com/llvm/llvm-project/pull/91894/files

let Prototype = "void(...)";
}

def C11AtomicStore : AtomicBuiltin {
let Spellings = ["__c11_atomic_store"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicExchange : AtomicBuiltin {
let Spellings = ["__c11_atomic_exchange"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicCompareExchangeStrong : AtomicBuiltin {
let Spellings = ["__c11_atomic_compare_exchange_strong"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicCompareExchangeWeak : AtomicBuiltin {
let Spellings = ["__c11_atomic_compare_exchange_weak"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicFetchAdd : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_add"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicFetchSub : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_sub"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicFetchAnd : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_and"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicFetchOr : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_or"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicFetchXor : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_xor"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicFetchNand : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_nand"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicFetchMax : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_max"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicFetchMin : AtomicBuiltin {
let Spellings = ["__c11_atomic_fetch_min"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def C11AtomicThreadFence : Builtin {
let Spellings = ["__c11_atomic_thread_fence"];
let Attributes = [NoThrow];
let Attributes = [NoThrow, Constexpr];
let Prototype = "void(int)";
}

def C11AtomicSignalFence : Builtin {
let Spellings = ["__c11_atomic_signal_fence"];
let Attributes = [NoThrow];
let Attributes = [NoThrow, Constexpr];
let Prototype = "void(int)";
}

Expand All @@ -1847,133 +1847,133 @@ def C11AtomicIsLockFree : Builtin {
// GNU atomic builtins.
def AtomicLoad : AtomicBuiltin {
let Spellings = ["__atomic_load"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When removing the constexpr-ness from these functions in C, please also make sure __c11_atomic_is_lock_free is tested as well; that was already marked constexpr and that might be a bug.

let Prototype = "void(...)";
}

def AtomicLoadN : AtomicBuiltin {
let Spellings = ["__atomic_load_n"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicStore : AtomicBuiltin {
let Spellings = ["__atomic_store"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicStoreN : AtomicBuiltin {
let Spellings = ["__atomic_store_n"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicExchange : AtomicBuiltin {
let Spellings = ["__atomic_exchange"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicExchangeN : AtomicBuiltin {
let Spellings = ["__atomic_exchange_n"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicCompareExchange : AtomicBuiltin {
let Spellings = ["__atomic_compare_exchange"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicCompareExchangeN : AtomicBuiltin {
let Spellings = ["__atomic_compare_exchange_n"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicFetchAdd : AtomicBuiltin {
let Spellings = ["__atomic_fetch_add"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicFetchSub : AtomicBuiltin {
let Spellings = ["__atomic_fetch_sub"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicFetchAnd : AtomicBuiltin {
let Spellings = ["__atomic_fetch_and"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicFetchOr : AtomicBuiltin {
let Spellings = ["__atomic_fetch_or"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicFetchXor : AtomicBuiltin {
let Spellings = ["__atomic_fetch_xor"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicFetchNand : AtomicBuiltin {
let Spellings = ["__atomic_fetch_nand"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicAddFetch : AtomicBuiltin {
let Spellings = ["__atomic_add_fetch"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicSubFetch : AtomicBuiltin {
let Spellings = ["__atomic_sub_fetch"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicAndFetch : AtomicBuiltin {
let Spellings = ["__atomic_and_fetch"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicOrFetch : AtomicBuiltin {
let Spellings = ["__atomic_or_fetch"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicXorFetch : AtomicBuiltin {
let Spellings = ["__atomic_xor_fetch"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicMaxFetch : AtomicBuiltin {
let Spellings = ["__atomic_max_fetch"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicMinFetch : AtomicBuiltin {
let Spellings = ["__atomic_min_fetch"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def AtomicNandFetch : AtomicBuiltin {
let Spellings = ["__atomic_nand_fetch"];
let Attributes = [CustomTypeChecking];
let Attributes = [CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

Expand All @@ -1991,7 +1991,7 @@ def AtomicClear : Builtin {

def AtomicThreadFence : Builtin {
let Spellings = ["__atomic_thread_fence"];
let Attributes = [NoThrow];
let Attributes = [NoThrow, Constexpr];
let Prototype = "void(int)";
}

Expand All @@ -2003,7 +2003,7 @@ def ScopedAtomicThreadFence : Builtin {

def AtomicSignalFence : Builtin {
let Spellings = ["__atomic_signal_fence"];
let Attributes = [NoThrow];
let Attributes = [NoThrow, Constexpr];
let Prototype = "void(int)";
}

Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticASTKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,12 @@ def note_constexpr_assumption_failed : Note<
"assumption evaluated to false">;
def err_experimental_clang_interp_failed : Error<
"the experimental clang interpreter failed to evaluate an expression">;
def note_unaligned_atomic_pointer_op : Note<
"atomic pointer operation with argument %0 not aligned to size of pointee type (sizeof %1 is %2)">;
def note_constexpr_atomic_ops_only_in_cpp : Note<
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This note is not emitted anywhere, but also, I don't think a note's the correct way to go because that will fail at constant expression time but __has_constexpr_builtin will still return true.

"constant evaluated atomic operations are supported only in C++ mode">;
def note_atomic_op_with_invalid_memory_order : Note<
"evaluated %select{|success |failure }0memory order argument to atomic operation is not allowed">;

def warn_integer_constant_overflow : Warning<
"overflow in expression; result is %0 with type %1">,
Expand Down
Loading
Loading