Skip to content

Commit 5d4b96b

Browse files
committed
Add clang atomic control options and attribute
Add option and statement attribute for controlling emitting of target-specific metadata to atomicrmw instructions in IR. The RFC for this attribute and option is https://discourse.llvm.org/t/rfc-add-clang-atomic-control-options-and-pragmas/80641, Originally a pragma was proposed, then it was changed to clang attribute. This attribute allows users to specify one, two, or all three options and must be applied to a compound statement. The attribute can also be nested, with inner attributes overriding the options specified by outer attributes or the target's default options. These options will then determine the target-specific metadata added to atomic instructions in the IR. In addition to the attribute, a new compiler option is introduced: -fatomic=no_remote_memory:{on|off},no_fine_grained_memory:{on|off},ignore_denormal_mode{on|off}. This compiler option allows users to override the target's default options through the Clang driver and front end. In terms of implementation, the atomic attribute is represented in the AST by the existing AttributedStmt, with minimal changes to AST and Sema. During code generation in Clang, the CodeGenModule maintains the current atomic options, which are used to emit the relevant metadata for atomic instructions. RAII is used to manage the saving and restoring of atomic options when entering and exiting nested AttributedStmt.
1 parent 2b04291 commit 5d4b96b

32 files changed

+1613
-390
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5404,6 +5404,115 @@ third argument, can only occur at file scope.
54045404
a = b[i] * c[i] + e;
54055405
}
54065406
5407+
Extensions for controlling atomic code generation
5408+
=================================================
5409+
5410+
The ``[[clang::atomic]]`` statement attribute enables users to control how
5411+
atomic operations are lowered in LLVM IR by conveying additional metadata to
5412+
the backend. The primary goal is to allow users to specify certain options,
5413+
like ignoring floating-point denormal modes, or restricting which memory
5414+
regions can be used, without affecting the correctness of code that does not
5415+
rely on these behaviors.
5416+
5417+
In LLVM, lowering of atomic operations (e.g., ``atomicrmw``) can differ based on
5418+
the target's capabilities. Some backends support native atomic instructions
5419+
only for certain operation types or alignments, or only in specific memory
5420+
regions. Likewise, floating-point atomic instructions may or may not respect
5421+
IEEE denormal requirements. When the user is unconcerned about denormal-mode
5422+
compliance (for performance reasons) or knows that certain atomic operations
5423+
will not function in a particular memory space, extra hints are needed to
5424+
tell the backend how to proceed.
5425+
5426+
A classic example is an architecture where floating-point atomic add does not
5427+
fully conform to IEEE denormal-mode handling. If the user does not mind ignoring
5428+
that aspect, they would prefer to still emit a faster hardware atomic
5429+
instruction, rather than a fallback or CAS loop. Conversely, on certain GPUs
5430+
(e.g., AMDGPU), memory accessed via PCIe may only support a subset of atomic
5431+
operations (e.g., integer add, exchange, or compare-and-swap). To ensure correct
5432+
and efficient lowering, the compiler must know whether the user wants to prevent
5433+
the use of these instructions.
5434+
5435+
Because this is metadata for atomic instructions and can be dropped if the
5436+
backend does not support it, it does not affect correctness (the program's
5437+
behavior remains correct if the metadata is ignored), but it can significantly
5438+
improve performance or guide code generation in the cases that matter.
5439+
5440+
The attribute may be applied only to a compound statement and looks like:
5441+
5442+
.. code-block:: c++
5443+
5444+
[[clang::atomic(no_remote_memory, !no_fine_grained_memory, ignore_denormal_mode)]]
5445+
{
5446+
// Atomic instructions in this block carry extra metadata reflecting
5447+
// these user-specified options.
5448+
}
5449+
5450+
You can provide one or more of these options, each optionally prefixed with
5451+
``!`` to negate that option. The currently supported options are:
5452+
5453+
``no_remote_memory``
5454+
Indicates that atomic operations in this block can assume the accessed memory
5455+
is not remote memory (relevant for certain GPU memory spaces, like those
5456+
accessed via PCIe). The prefix ``!`` disables this if a broader scope or
5457+
command-line had it on.
5458+
5459+
``no_fine_grained_memory``
5460+
Suggests that no fine-grained memory regions are accessed by atomic
5461+
operations. On some GPUs, this can assure certain atomic instructions
5462+
to work, instead of falling back to CAS loops.
5463+
5464+
``ignore_denormal_mode``
5465+
Allows the backend to ignore floating-point denormals for atomic instructions
5466+
(like 32-bit ``fadd``). This often improves performance on architectures that
5467+
do not handle denormals efficiently.
5468+
5469+
Any unspecified option is inherited from the global defaults, which can be set
5470+
by a compiler flag (described below) or the target's built-in defaults.
5471+
5472+
.. code-block:: c++
5473+
5474+
// Suppose we globally set: -fatomic=no_remote_memory:on,no_fine_grained_memory:off
5475+
// (meaning we do not allow remote memory usage but do allow fine-grained memory)
5476+
5477+
void example() {
5478+
// Locally override the "no_remote_memory" setting to *off* for this block,
5479+
// but turn on "no_fine_grained_memory".
5480+
[[clang::atomic(!no_remote_memory, no_fine_grained_memory)]] {
5481+
// This compound statement's atomic ops behave differently than outside:
5482+
// - no_remote_memory is disabled here
5483+
// - no_fine_grained_memory is enabled
5484+
// - ignore_denormal_mode remains unchanged from global default
5485+
// ...
5486+
}
5487+
}
5488+
5489+
A new compiler option, ``-fatomic=<key>:<value>[,<key2>:<value2>...]``, can
5490+
globally override the target's defaults for these atomic-lowering options.
5491+
For instance:
5492+
5493+
.. code-block:: console
5494+
5495+
$ clang -fatomic=no_remote_memory:on,ignore_denormal_mode:on file.cpp
5496+
5497+
Each key can be one of:
5498+
``no_remote_memory``, ``no_fine_grained_memory``, or ``ignore_denormal_mode``.
5499+
Each value can be ``on``, ``off``, ``yes``, ``no``, ``true``, ``false``, ``1``,
5500+
or ``0`` (case-insensitive). Unrecognized options or invalid formats produce an
5501+
error. Code using the ``[[clang::atomic]]`` attribute then selectively overrides
5502+
the command-line defaults on a per-block basis.
5503+
5504+
Internally, this attribute attaches "atomic options" information to the compound
5505+
statement in the AST, using an approach analogous to how Clang tracks
5506+
floating-point pragmas. During IR emission, Clang checks these options and
5507+
attaches target-specific metadata (e.g., ``amdgpu.no.remote.memory``) to atomic
5508+
instructions, guiding the backend's lowering process.
5509+
5510+
Although current usage focuses on AMDGPU, the mechanism is general. Other
5511+
backends can ignore or implement their own responses to these flags if desired.
5512+
If a target does not understand or enforce these hints, the IR remains valid,
5513+
and the resulting program is still correct (although potentially less optimized
5514+
for that user's needs).
5515+
54075516
Specifying an attribute for multiple declarations (#pragma clang attribute)
54085517
===========================================================================
54095518

clang/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ Removed Compiler Flags
110110
Attribute Changes in Clang
111111
--------------------------
112112

113+
- Introduced a new statement attribute ``[[clang::atomic]]`` that enables
114+
fine-grained control over atomic code generation on a per-statement basis.
115+
Supported options include ``no_remote_memory``, ``no_fine_grained_memory``,
116+
and ``ignore_denormal_mode``, particularly relevant for AMDGPU targets,
117+
where they map to corresponding IR metadata.
118+
113119
Improvements to Clang's diagnostics
114120
-----------------------------------
115121

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===--- AtomicOptions.def - Atomic Options database -------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// This file defines the Atomic language options. Users of this file
9+
// must define the OPTION macro to make use of this information.
10+
#ifndef OPTION
11+
# error Define the OPTION macro to handle atomic language options
12+
#endif
13+
14+
// Format: OPTION(NAME, STR, TYPE, WIDTH, PREVIOUS)
15+
OPTION(NoRemoteMemory, "no_remote_memory", bool, 1, First)
16+
OPTION(NoFineGrainedMemory, "no_fine_grained_memory", bool, 1, NoRemoteMemory)
17+
OPTION(IgnoreDenormalMode, "ignore_denormal_mode", bool, 1, NoFineGrainedMemory)
18+
19+
#undef OPTION

clang/include/clang/Basic/Attr.td

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4972,3 +4972,16 @@ def NoTrivialAutoVarInit: InheritableAttr {
49724972
let Documentation = [NoTrivialAutoVarInitDocs];
49734973
let SimpleHandler = 1;
49744974
}
4975+
4976+
def Atomic : StmtAttr {
4977+
let Spellings = [Clang<"atomic">];
4978+
let Args = [VariadicStringArgument<"Options">];
4979+
let Subjects = SubjectList<[CompoundStmt], ErrorDiag, "compound statements">;
4980+
let HasCustomParsing = 1;
4981+
let Documentation = [AtomicDocs];
4982+
let AdditionalMembers = [{
4983+
AtomicOptionsOverride AOO;
4984+
AtomicOptionsOverride getAtomicOptionsOverride() const { return AOO; }
4985+
void setAtomicOptionsOverride(AtomicOptionsOverride A) { AOO = A; }
4986+
}];
4987+
}

clang/include/clang/Basic/AttrDocs.td

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8068,6 +8068,21 @@ for details.
80688068
}];
80698069
}
80708070

8071+
def AtomicDocs : Documentation {
8072+
let Category = DocCatStmt;
8073+
let Content = [{
8074+
The ``atomic`` attribute can be applied to *compound statements* to override or
8075+
further specify the default atomic code-generation behavior, especially on
8076+
targets such as AMDGPU. You can annotate compound statements with options
8077+
to modify how atomic instructions inside that statement are emitted at the IR
8078+
level.
8079+
8080+
For details, see the documentation for `@available
8081+
<http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-controlling-atomic-code-generation>`_
8082+
8083+
}];
8084+
}
8085+
80718086
def ClangRandomizeLayoutDocs : Documentation {
80728087
let Category = DocCatDecl;
80738088
let Heading = "randomize_layout, no_randomize_layout";

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,16 @@ def err_drv_invalid_int_value : Error<"invalid integral value '%1' in '%0'">;
305305
def err_drv_invalid_value_with_suggestion : Error<
306306
"invalid value '%1' in '%0', expected one of: %2">;
307307
def err_drv_alignment_not_power_of_two : Error<"alignment is not a power of 2 in '%0'">;
308+
309+
def err_drv_invalid_atomic_option : Error<
310+
"invalid argument '%0' to '-fatomic='; %select{"
311+
"must be a comma-separated list of key:value pairs|"
312+
"key '%2' is not allowed; allowed keys are 'no_fine_grained_memory', "
313+
"'no_remote_memory', 'ignore_denormal_mode'|"
314+
"value '%3' is invalid; must be boolean (true/false, 1/0, yes/no, on/off)|"
315+
"duplicate key '%2'"
316+
"}1">;
317+
308318
def err_drv_invalid_remap_file : Error<
309319
"invalid option '%0' not of the form <from-file>;<to-file>">;
310320
def err_drv_invalid_gcc_install_dir : Error<"'%0' does not contain a GCC installation">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3294,6 +3294,8 @@ def err_invalid_branch_protection_spec : Error<
32943294
"invalid or misplaced branch protection specification '%0'">;
32953295
def warn_unsupported_branch_protection_spec : Warning<
32963296
"unsupported branch protection specification '%0'">, InGroup<BranchProtection>;
3297+
def err_attribute_invalid_atomic_argument : Error<
3298+
"invalid argument '%0' to atomic attribute; valid options are: 'no_remote_memory', 'no_fine_grained_memory', 'ignore_denormal_mode' (optionally prefixed with '!')">;
32973299

32983300
def warn_unsupported_target_attribute
32993301
: Warning<"%select{unsupported|duplicate|unknown}0%select{| CPU|"

clang/include/clang/Basic/Features.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ EXTENSION(datasizeof, LangOpts.CPlusPlus)
312312

313313
FEATURE(cxx_abi_relative_vtable, LangOpts.CPlusPlus && LangOpts.RelativeCXXABIVTables)
314314

315+
FEATURE(atomic_attributes, true)
316+
315317
// CUDA/HIP Features
316318
FEATURE(cuda_noinline_keyword, LangOpts.CUDA)
317319
EXTENSION(cuda_implicit_host_device_templates, LangOpts.CUDA && LangOpts.OffloadImplicitHostDeviceTemplates)

0 commit comments

Comments
 (0)