[clang] Add clang atomic control options and attribute (PR #114841)

via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 4 09:59:02 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-amdgpu

Author: Yaxun (Sam) Liu (yxsamliu)

<details>
<summary>Changes</summary>

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.

---

Patch is 140.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/114841.diff


26 Files Affected:

- (added) clang/include/clang/Basic/AtomicOptions.def (+19) 
- (modified) clang/include/clang/Basic/Attr.td (+56) 
- (modified) clang/include/clang/Basic/DiagnosticDriverKinds.td (+7) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2) 
- (modified) clang/include/clang/Basic/LangOptions.h (+167) 
- (modified) clang/include/clang/Basic/TargetInfo.h (+6) 
- (modified) clang/include/clang/Driver/Options.td (+8) 
- (modified) clang/include/clang/Parse/Parser.h (+5) 
- (modified) clang/lib/Basic/LangOptions.cpp (+52) 
- (modified) clang/lib/Basic/Targets/AMDGPU.cpp (+7) 
- (modified) clang/lib/CodeGen/CGStmt.cpp (+5) 
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+17) 
- (modified) clang/lib/CodeGen/CodeGenModule.cpp (+2-1) 
- (modified) clang/lib/CodeGen/CodeGenModule.h (+8) 
- (modified) clang/lib/CodeGen/Targets/AMDGPU.cpp (+12-10) 
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+26) 
- (modified) clang/lib/Parse/ParseDecl.cpp (+71) 
- (modified) clang/lib/Sema/SemaStmtAttr.cpp (+43) 
- (added) clang/test/AST/ast-dump-atomic-options.hip (+102) 
- (modified) clang/test/CodeGenCUDA/amdgpu-atomic-ops.cu (+95-100) 
- (modified) clang/test/CodeGenCUDA/atomic-ops.cu (+100-100) 
- (added) clang/test/CodeGenCUDA/atomic-options.hip (+456) 
- (added) clang/test/Driver/atomic-options.hip (+31) 
- (modified) clang/test/OpenMP/amdgpu-unsafe-fp-atomics.cpp (+6-4) 
- (added) clang/test/Parser/Inputs/cuda.h (+54) 
- (added) clang/test/Parser/atomic-options.hip (+30) 


``````````diff
diff --git a/clang/include/clang/Basic/AtomicOptions.def b/clang/include/clang/Basic/AtomicOptions.def
new file mode 100644
index 00000000000000..4cf2dab581c8b4
--- /dev/null
+++ b/clang/include/clang/Basic/AtomicOptions.def
@@ -0,0 +1,19 @@
+//===--- AtomicOptions.def - Atomic Options database -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This file defines the Atomic language options. Users of this file
+// must define the OPTION macro to make use of this information.
+#ifndef OPTION
+#  error Define the OPTION macro to handle atomic language options
+#endif
+
+// OPTION(name, type, width, previousName)
+OPTION(NoRemoteMemory, bool, 1, First)
+OPTION(NoFineGrainedMemory, bool, 1, NoRemoteMemory)
+OPTION(IgnoreDenormalMode, bool, 1, NoFineGrainedMemory)
+
+#undef OPTION
\ No newline at end of file
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 156fbd1c4442eb..6b5fea1965aec3 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4838,3 +4838,59 @@ def ClspvLibclcBuiltin: InheritableAttr {
   let Documentation = [ClspvLibclcBuiltinDoc];
   let SimpleHandler = 1;
 }
+
+def Atomic : StmtAttr {
+  let Spellings = [Clang<"atomic">];
+  let Args = [
+    EnumArgument<"NoRemoteMemory", "NoRemoteMemoryTy", /*IsString*/ false,
+      ["no_remote_memory", "!no_remote_memory", ""],
+      ["NoRemoteMemoryOn", "NoRemoteMemoryOff", "NoRemoteMemoryUnset"]>,
+    EnumArgument<"NoFineGrainedMemory", "NoFineGrainedMemoryTy", /*IsString*/ false,
+      ["no_fine_grained_memory", "!no_fine_grained_memory", ""],
+      ["NoFineGrainedMemoryOn", "NoFineGrainedMemoryOff", "NoFineGrainedMemoryUnset"]>,
+    EnumArgument<"IgnoreDenormalMode", "IgnoreDenormalModeTy", /*IsString*/ false,
+      ["ignore_denormal_mode", "!ignore_denormal_mode", ""],
+      ["IgnoreDenormalModeOn", "IgnoreDenormalModeOff", "IgnoreDenormalModeUnset"]>
+  ];
+  let Subjects = SubjectList<[CompoundStmt], ErrorDiag, "compound statements">;
+  let HasCustomParsing = 1;
+  let Documentation = [Undocumented];
+  let AdditionalMembers = [{
+    AtomicOptionsOverride AOO;
+    AtomicOptionsOverride getAtomicOptionsOverride() const { return AOO; }
+    void updateAtomicOptionsOverride() {
+      switch (getNoRemoteMemory()) {
+      case NoRemoteMemoryOn:
+        AOO.setNoRemoteMemoryOverride(true);
+        break;
+      case NoRemoteMemoryOff:
+        AOO.setNoRemoteMemoryOverride(false);
+        break;
+      case NoRemoteMemoryUnset:
+        AOO.clearNoRemoteMemoryOverride();
+      }
+
+      switch (getNoFineGrainedMemory()) {
+      case NoFineGrainedMemoryOn:
+        AOO.setNoFineGrainedMemoryOverride(true);
+        break;
+      case NoFineGrainedMemoryOff:
+        AOO.setNoFineGrainedMemoryOverride(false);
+        break;
+      case NoFineGrainedMemoryUnset:
+        AOO.clearNoFineGrainedMemoryOverride();
+      }
+
+      switch (getIgnoreDenormalMode()) {
+      case IgnoreDenormalModeOn:
+        AOO.setIgnoreDenormalModeOverride(true);
+        break;
+      case IgnoreDenormalModeOff:
+        AOO.setIgnoreDenormalModeOverride(false);
+        break;
+      case IgnoreDenormalModeUnset:
+        AOO.clearIgnoreDenormalModeOverride();
+      }
+    }
+  }];
+}
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index cdfdaa01fb121d..d72d661281d112 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -305,6 +305,13 @@ def err_drv_invalid_int_value : Error<"invalid integral value '%1' in '%0'">;
 def err_drv_invalid_value_with_suggestion : Error<
     "invalid value '%1' in '%0', expected one of: %2">;
 def err_drv_alignment_not_power_of_two : Error<"alignment is not a power of 2 in '%0'">;
+
+def err_drv_invalid_atomic_option : Error<
+  "invalid argument '%0' to -fatomic=; must be a "
+  "comma-separated list of key:value pairs, where allowed keys are "
+  "'no_fine_grained_memory', 'no_remote_memory', 'ignore_denormal_mode', "
+  "and values are 'on' or 'off', and each key must be unique">;
+
 def err_drv_invalid_remap_file : Error<
     "invalid option '%0' not of the form <from-file>;<to-file>">;
 def err_drv_invalid_gcc_install_dir : Error<"'%0' does not contain a GCC installation">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d697e6d61afa9a..98d65d83513025 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3275,6 +3275,8 @@ def err_invalid_branch_protection_spec : Error<
   "invalid or misplaced branch protection specification '%0'">;
 def warn_unsupported_branch_protection_spec : Warning<
   "unsupported branch protection specification '%0'">, InGroup<BranchProtection>;
+def err_attribute_invalid_atomic_argument : Error<
+  "invalid argument '%0' to atomic attribute; valid options are: 'no_remote_memory', 'no_fine_grained_memory', 'ignore_denormal_mode' (optionally prefixed with '!')">;
 
 def warn_unsupported_target_attribute
     : Warning<"%select{unsupported|duplicate|unknown}0%select{| CPU|"
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 949c8f5d448bcf..79862993575fcf 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -622,6 +622,10 @@ class LangOptions : public LangOptionsBase {
   // WebAssembly target.
   bool NoWasmOpt = false;
 
+  /// The default atomic codegen options specified by command line in the
+  /// format of key:{on|off}.
+  std::vector<std::string> AtomicOptionsAsWritten;
+
   LangOptions();
 
   /// Set language defaults for the given input language and
@@ -1093,6 +1097,169 @@ inline void FPOptions::applyChanges(FPOptionsOverride FPO) {
   *this = FPO.applyOverrides(*this);
 }
 
+/// Atomic control options
+class AtomicOptionsOverride;
+class AtomicOptions {
+public:
+  using storage_type = uint16_t;
+
+  static constexpr unsigned StorageBitSize = 8 * sizeof(storage_type);
+
+  static constexpr storage_type FirstShift = 0, FirstWidth = 0;
+#define OPTION(NAME, TYPE, WIDTH, PREVIOUS)                                    \
+  static constexpr storage_type NAME##Shift =                                  \
+      PREVIOUS##Shift + PREVIOUS##Width;                                       \
+  static constexpr storage_type NAME##Width = WIDTH;                           \
+  static constexpr storage_type NAME##Mask = ((1 << NAME##Width) - 1)          \
+                                             << NAME##Shift;
+#include "clang/Basic/AtomicOptions.def"
+
+  static constexpr storage_type TotalWidth = 0
+#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) +WIDTH
+#include "clang/Basic/AtomicOptions.def"
+      ;
+  static_assert(TotalWidth <= StorageBitSize,
+                "Too short type for AtomicOptions");
+
+private:
+  storage_type Value;
+
+  AtomicOptionsOverride getChangesSlow(const AtomicOptions &Base) const;
+
+public:
+  AtomicOptions() : Value(0) {
+    setNoRemoteMemory(false);
+    setNoFineGrainedMemory(false);
+    setIgnoreDenormalMode(false);
+  }
+  explicit AtomicOptions(const LangOptions &LO) {
+    Value = 0;
+#if 0
+    setNoRemoteMemory(LO.NoRemoteMemoryAccess);
+    setNoFineGrainedMemory(LO.NoFineGrainedMemoryAccess);
+    setIgnoreDenormalMode(LO.IgnoreDenormals);
+#endif
+  }
+
+  bool operator==(AtomicOptions other) const { return Value == other.Value; }
+
+  /// Return the default value of AtomicOptions that's used when trailing
+  /// storage isn't required.
+  static AtomicOptions defaultWithoutTrailingStorage(const LangOptions &LO);
+
+  storage_type getAsOpaqueInt() const { return Value; }
+  static AtomicOptions getFromOpaqueInt(storage_type Value) {
+    AtomicOptions Opts;
+    Opts.Value = Value;
+    return Opts;
+  }
+
+  /// Return difference with the given option set.
+  AtomicOptionsOverride getChangesFrom(const AtomicOptions &Base) const;
+
+  void applyChanges(AtomicOptionsOverride AO);
+
+#define OPTION(NAME, TYPE, WIDTH, PREVIOUS)                                    \
+  TYPE get##NAME() const {                                                     \
+    return static_cast<TYPE>((Value & NAME##Mask) >> NAME##Shift);             \
+  }                                                                            \
+  void set##NAME(TYPE value) {                                                 \
+    Value = (Value & ~NAME##Mask) | (storage_type(value) << NAME##Shift);      \
+  }
+#include "clang/Basic/AtomicOptions.def"
+  LLVM_DUMP_METHOD void dump();
+};
+
+/// Represents difference between two AtomicOptions values.
+class AtomicOptionsOverride {
+  AtomicOptions Options = AtomicOptions::getFromOpaqueInt(0);
+  AtomicOptions::storage_type OverrideMask = 0;
+
+public:
+  /// The type suitable for storing values of AtomicOptionsOverride. Must be
+  /// twice as wide as bit size of AtomicOption.
+  using storage_type = uint32_t;
+  static_assert(sizeof(storage_type) >= 2 * sizeof(AtomicOptions::storage_type),
+                "Too short type for AtomicOptionsOverride");
+
+  /// Bit mask selecting bits of OverrideMask in serialized representation of
+  /// AtomicOptionsOverride.
+  static constexpr storage_type OverrideMaskBits =
+      (static_cast<storage_type>(1) << AtomicOptions::StorageBitSize) - 1;
+
+  AtomicOptionsOverride() {}
+  AtomicOptionsOverride(const LangOptions &LO);
+  AtomicOptionsOverride(AtomicOptions AO)
+      : Options(AO), OverrideMask(OverrideMaskBits) {}
+  AtomicOptionsOverride(AtomicOptions AO, AtomicOptions::storage_type Mask)
+      : Options(AO), OverrideMask(Mask) {}
+
+  bool requiresTrailingStorage() const { return OverrideMask != 0; }
+
+  storage_type getAsOpaqueInt() const {
+    return (static_cast<storage_type>(Options.getAsOpaqueInt())
+            << AtomicOptions::StorageBitSize) |
+           OverrideMask;
+  }
+
+  static AtomicOptionsOverride getFromOpaqueInt(storage_type I) {
+    AtomicOptionsOverride Opts;
+    Opts.OverrideMask = I & OverrideMaskBits;
+    Opts.Options =
+        AtomicOptions::getFromOpaqueInt(I >> AtomicOptions::StorageBitSize);
+    return Opts;
+  }
+
+  AtomicOptions applyOverrides(AtomicOptions Base) {
+    AtomicOptions Result = AtomicOptions::getFromOpaqueInt(
+        (Base.getAsOpaqueInt() & ~OverrideMask) |
+        (Options.getAsOpaqueInt() & OverrideMask));
+    return Result;
+  }
+
+  AtomicOptions applyOverrides(const LangOptions &LO) {
+    return applyOverrides(AtomicOptions(LO));
+  }
+
+  bool operator==(AtomicOptionsOverride other) const {
+    return Options == other.Options && OverrideMask == other.OverrideMask;
+  }
+  bool operator!=(AtomicOptionsOverride other) const {
+    return !(*this == other);
+  }
+
+#define OPTION(NAME, TYPE, WIDTH, PREVIOUS)                                    \
+  bool has##NAME##Override() const {                                           \
+    return OverrideMask & AtomicOptions::NAME##Mask;                           \
+  }                                                                            \
+  TYPE get##NAME##Override() const {                                           \
+    assert(has##NAME##Override());                                             \
+    return Options.get##NAME();                                                \
+  }                                                                            \
+  void clear##NAME##Override() {                                               \
+    Options.set##NAME(TYPE(0));                                                \
+    OverrideMask &= ~AtomicOptions::NAME##Mask;                                \
+  }                                                                            \
+  void set##NAME##Override(TYPE value) {                                       \
+    Options.set##NAME(value);                                                  \
+    OverrideMask |= AtomicOptions::NAME##Mask;                                 \
+  }
+#include "clang/Basic/AtomicOptions.def"
+
+  LLVM_DUMP_METHOD void dump();
+};
+
+inline AtomicOptionsOverride
+AtomicOptions::getChangesFrom(const AtomicOptions &Base) const {
+  if (Value == Base.Value)
+    return AtomicOptionsOverride();
+  return getChangesSlow(Base);
+}
+
+inline void AtomicOptions::applyChanges(AtomicOptionsOverride AO) {
+  *this = AO.applyOverrides(*this);
+}
+
 /// Describes the kind of translation unit being processed.
 enum TranslationUnitKind {
   /// The translation unit is a complete translation unit.
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 25eda907d20a7b..c23ce5d9418f46 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -295,6 +295,9 @@ class TargetInfo : public TransferrableTargetInfo,
   // in function attributes in IR.
   llvm::StringSet<> ReadOnlyFeatures;
 
+  // Default atomic options
+  AtomicOptions AtomicOpts;
+
 public:
   /// Construct a target for the given options.
   ///
@@ -1674,6 +1677,9 @@ class TargetInfo : public TransferrableTargetInfo,
     return CC_C;
   }
 
+  /// Get the default atomic options.
+  AtomicOptions getAtomicOpts() const { return AtomicOpts; }
+
   enum CallingConvCheckResult {
     CCCR_OK,
     CCCR_Warning,
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 805b79491e6ea4..737514724545ae 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2346,6 +2346,14 @@ def fsymbol_partition_EQ : Joined<["-"], "fsymbol-partition=">, Group<f_Group>,
   Visibility<[ClangOption, CC1Option]>,
   MarshallingInfoString<CodeGenOpts<"SymbolPartition">>;
 
+def fatomic_EQ : CommaJoined<["-"], "fatomic=">, Group<f_Group>,
+  Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Specify atomic codegen options as a comma-separated list of "
+           "key:value pairs, allowed keys and values are "
+           "no_fine_grained_memory:on|off, no_remote_memory:on|off, "
+           "ignore_denormal_mode:on|off">,
+  MarshallingInfoStringVector<LangOpts<"AtomicOptionsAsWritten">>;
+
 defm memory_profile : OptInCC1FFlag<"memory-profile", "Enable", "Disable", " heap memory profiling">;
 def fmemory_profile_EQ : Joined<["-"], "fmemory-profile=">,
     Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 045ee754a242b3..08bab6104be04d 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -3100,6 +3100,11 @@ class Parser : public CodeCompletionHandler {
   std::optional<AvailabilitySpec> ParseAvailabilitySpec();
   ExprResult ParseAvailabilityCheckExpr(SourceLocation StartLoc);
 
+  void ParseAtomicAttribute(IdentifierInfo &AttrName,
+                            SourceLocation AttrNameLoc, ParsedAttributes &Attrs,
+                            SourceLocation *EndLoc, IdentifierInfo *ScopeName,
+                            SourceLocation ScopeLoc, ParsedAttr::Form Form);
+
   void ParseExternalSourceSymbolAttribute(IdentifierInfo &ExternalSourceSymbol,
                                           SourceLocation Loc,
                                           ParsedAttributes &Attrs,
diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp
index 94caf6a3897bc1..29afcdf03486d2 100644
--- a/clang/lib/Basic/LangOptions.cpp
+++ b/clang/lib/Basic/LangOptions.cpp
@@ -238,3 +238,55 @@ LLVM_DUMP_METHOD void FPOptionsOverride::dump() {
 #include "clang/Basic/FPOptions.def"
   llvm::errs() << "\n";
 }
+
+AtomicOptions
+AtomicOptions::defaultWithoutTrailingStorage(const LangOptions &LO) {
+  AtomicOptions result(LO);
+  return result;
+}
+
+AtomicOptionsOverride
+AtomicOptions::getChangesSlow(const AtomicOptions &Base) const {
+  AtomicOptions::storage_type OverrideMask = 0;
+#define OPTION(NAME, TYPE, WIDTH, PREVIOUS)                                    \
+  if (get##NAME() != Base.get##NAME())                                         \
+    OverrideMask |= NAME##Mask;
+#include "clang/Basic/AtomicOptions.def"
+  return AtomicOptionsOverride(*this, OverrideMask);
+}
+
+LLVM_DUMP_METHOD void AtomicOptions::dump() {
+#define OPTION(NAME, TYPE, WIDTH, PREVIOUS)                                    \
+  llvm::errs() << "\n " #NAME " " << get##NAME();
+#include "clang/Basic/AtomicOptions.def"
+  llvm::errs() << "\n";
+}
+
+LLVM_DUMP_METHOD void AtomicOptionsOverride::dump() {
+#define OPTION(NAME, TYPE, WIDTH, PREVIOUS)                                    \
+  if (has##NAME##Override())                                                   \
+    llvm::errs() << "\n " #NAME " Override is " << get##NAME##Override();
+#include "clang/Basic/AtomicOptions.def"
+  llvm::errs() << "\n";
+}
+
+AtomicOptionsOverride::AtomicOptionsOverride(const LangOptions &LO) {
+  for (const auto &Setting : LO.AtomicOptionsAsWritten) {
+    SmallVector<StringRef, 2> KeyValue;
+    StringRef(Setting).split(KeyValue, ":");
+    // Assuming option string has been checked elsewhere and is valid.
+    assert(KeyValue.size() == 2 && "Invalid atomic option format");
+    StringRef Key = KeyValue[0];
+    StringRef Val = KeyValue[1];
+    bool IsEnabled = (Val == "on");
+
+    if (Key == "no_fine_grained_memory")
+      setNoFineGrainedMemoryOverride(IsEnabled);
+    else if (Key == "no_remote_memory")
+      setNoRemoteMemoryOverride(IsEnabled);
+    else if (Key == "ignore_denormal_mode")
+      setIgnoreDenormalModeOverride(IsEnabled);
+    else
+      assert(false && "Unknown atomic option key");
+  }
+}
diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp
index 078819183afdac..3a5e9f3ec0851d 100644
--- a/clang/lib/Basic/Targets/AMDGPU.cpp
+++ b/clang/lib/Basic/Targets/AMDGPU.cpp
@@ -241,6 +241,11 @@ AMDGPUTargetInfo::AMDGPUTargetInfo(const llvm::Triple &Triple,
   WavefrontSize = (GPUFeatures & llvm::AMDGPU::FEATURE_WAVE32) ? 32 : 64;
   AllowAMDGPUUnsafeFPAtomics = Opts.AllowAMDGPUUnsafeFPAtomics;
 
+  // Set the default atomic options
+  AtomicOpts.setNoRemoteMemory(true);
+  AtomicOpts.setNoFineGrainedMemory(true);
+  AtomicOpts.setIgnoreDenormalMode(Opts.AllowAMDGPUUnsafeFPAtomics);
+
   // Set pointer width and alignment for the generic address space.
   PointerWidth = PointerAlign = getPointerWidthV(LangAS::Default);
   if (getMaxPointerWidth() == 64) {
@@ -264,6 +269,8 @@ void AMDGPUTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
   // to OpenCL can be removed from the following line.
   setAddressSpaceMap((Opts.OpenCL && !Opts.OpenCLGenericAddressSpace) ||
                      !isAMDGCN(getTriple()));
+
+  AtomicOpts.applyChanges(AtomicOptionsOverride(Opts));
 }
 
 ArrayRef<Builtin::Info> AMDGPUTargetInfo::getTargetBuiltins() const {
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 41dc91c578c800..fee336097ec4dd 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -728,6 +728,7 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
   bool alwaysinline = false;
   bool noconvergent = false;
   const CallExpr *musttail = nullptr;
+  AtomicOptionsOverride AOO;
 
   for (const auto *A : S.getAttrs()) {
     switch (A->getKind()) {
@@ -758,6 +759,9 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
         Builder.CreateAssumption(AssumptionVal);
       }
     } break;
+    case attr::Atomic: {
+      AOO = cast<AtomicAttr>(A)->getAtomicOptionsOverride();
+    } break;
     }
   }
   SaveAndRestore save_nomerge(InNoMergeAttributedStmt, nomerge);
@@ -765,6 +769,7 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
   SaveAndRestore save_alwaysinline(InAlwaysInlineAttributedStmt, alwaysinline);
   SaveAndRestore save_noconvergent(InNoConvergentAttributedStmt, noconvergent);
   SaveAndRestore save_musttail(MustTailCall, musttail);
+  CGAtomicOptionsRAII AORAII(CGM, AOO);
   EmitStmt(S.getSubStmt(), S.getAttrs());
 }
 
diff --git a/clang/...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/114841


More information about the cfe-commits mailing list