This RFC proposes the addition of an atomic pragma to Clang, designed to provide a more flexible mechanism for users to specify how atomic operations should be handled during the lowering process in LLVM IR. Currently, the atomicrmw instruction in LLVM IR can be lowered to either atomic instructions or CAS loops, depending on whether the target supports atomic instructions for a specific operation type or alignment. However, there are cases where the decision-making process for lowering an atomicrmw instruction cannot be fully expressed by the existing IR.
For instance, consider a scenario where a floating-point atomic add instruction does not conform to IEEE denormal mode requirements on a particular subtarget. Even though this non-conformance exists, users might still prefer the corresponding IR to be lowered to atomic instructions if they are unconcerned about denormal mode. This means that the backend needs to be informed through IR whether to ignore the floating-point denormal mode during the lowering process. Another example involves an atomic instruction that may not function correctly for specific memory types, such as memory accessed through PCIe, which only supports atomic integer add, exchange, or compare-and-swap operations. To ensure correct and efficient lowering of atomicrmw instructions, the backend must be aware of the memory type involved.
To convey this necessary information to the backend, we propose adding target-specific metadata to atomicrmw instructions in IR. Since this information is provided by users, a flexible mechanism is needed to allow them to specify these details in the source code. To achieve this, we introduce a pragma in the format of
#pragma clang atomic no_remote_memory(on|off) no_fine_grained_memory(on|off) ignore_denormal_mode(on|off)
This pragma allows users to specify one, two, or all three options and must be placed at the beginning of a compound statement. The pragma can also be nested, with inner pragmas overriding the options specified in outer compound statements 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 pragma, 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.
The design of this atomic pragma and the associated compiler options are intended to be target-neutral, enabling potential reuse across different targets. While a target might choose not to emit metadata for some or all of these options, or might add new options to the pragma, the overall design is inspired by Clang’s floating-point pragma, which conveys extra information to the backend about how floating-point instructions should be lowered. Importantly, the metadata introduced by this pragma in the IR can be dropped without affecting the correctness of the program, as it is primarily intended to improve performance.
In terms of implementation, the atomic pragma is represented in the AST by trailing data in CompoundStmt. The parser in Clang maintains an atomic options stack in Sema, which is updated whenever the atomic pragma is encountered. When a CompoundStmt is created, it includes the current atomic options. RAII is employed to save and restore atomic options when transitioning between outer and inner CompoundStmts.
During code generation in Clang, the CodeGenModule maintains the current atomic options, which are used to emit the relevant metadata for atomic instructions. As with the parsing phase, RAII is used to manage the saving and restoring of atomic options when entering and exiting nested CompoundStmts. This ensures that the correct metadata is generated in the IR, reflecting the user’s specified options accurately.
An initial implementation of this RFC can be found at
Your feedbacks are welcome. Thanks.