[llvm] [Instrumentor] Add atomicrmw instrumentation opportunity (PR #229369)

Ethan Luis McDonough via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 6 03:17:54 PDT 2026


https://github.com/EthanLuisMcDonough updated https://github.com/llvm/llvm-project/pull/229369

>From a5801be4d964976f83c5376f1fcfe9072d56f362 Mon Sep 17 00:00:00 2001
From: Ethan Luis McDonough <ethanluismcdonough at gmail.com>
Date: Tue, 6 Oct 2026 03:17:33 -0700
Subject: [PATCH] Add atomicrmw IO

---
 .../llvm/Transforms/IPO/Instrumentor.h        | 100 ++++++++++
 llvm/lib/Transforms/IPO/Instrumentor.cpp      | 185 ++++++++++++++++++
 .../Instrumentation/Instrumentor/atomicrmw.ll |  40 ++++
 .../Instrumentor/atomicrmw_config.json        |  54 +++++
 .../Instrumentor/atomicrmw_simple_config.json |  41 ++++
 .../Instrumentor/default_config.json          |  66 +++++++
 .../Instrumentation/Instrumentor/default_rt.c |  19 ++
 .../Instrumentor/rt_config.json               |  66 +++++++
 8 files changed, 571 insertions(+)
 create mode 100644 llvm/test/Instrumentation/Instrumentor/atomicrmw.ll
 create mode 100644 llvm/test/Instrumentation/Instrumentor/atomicrmw_config.json
 create mode 100644 llvm/test/Instrumentation/Instrumentor/atomicrmw_simple_config.json

diff --git a/llvm/include/llvm/Transforms/IPO/Instrumentor.h b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
index 5da53ac0ada15b8..7a2d3f19cd43806 100644
--- a/llvm/include/llvm/Transforms/IPO/Instrumentor.h
+++ b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
@@ -1119,6 +1119,106 @@ struct LoadIO : public InstructionIO<Instruction::Load> {
   }
 };
 
+/// The instrumentation opportunity for atomic RMW instructions.
+struct AtomicRMWIO final : public InstructionIO<Instruction::AtomicRMW> {
+  AtomicRMWIO(InstrumentationLocation::KindTy Kind) : InstructionIO(Kind) {}
+
+  /// The selector of arguments for atomic RMW opportunities.
+  ///{
+  enum ConfigKind {
+    PassPointer = 0,
+    ReplacePointer,
+    PassPointerAS,
+    PassBasePointerInfo,
+    PassValOperand,
+    PassPrevValue,
+    ReplacePrevValue,
+    PassValueSize,
+    PassAlignment,
+    PassValueTypeId,
+    PassValueSubTypeId,
+    PassAtomicityOrdering,
+    PassSyncScopeId,
+    PassIsVolatile,
+    PassOperation,
+    PassId,
+    NumConfig,
+  };
+
+  using ConfigTy = BaseConfigTy<ConfigKind>;
+  ConfigTy Config;
+  ///}
+
+  /// Get the type of the modified value.
+  Type *getValueType(InstrumentorIRBuilderTy &IIRB) const {
+    return IIRB.Int64Ty;
+  }
+
+  /// Initialize the atomic RMW opportunity using the instrumentation config \p
+  /// IConf and the user config \p UserConfig.
+  LLVM_ABI void init(InstrumentationConfig &IConf,
+                     InstrumentorIRBuilderTy &IIRB,
+                     ConfigTy *UserConfig = nullptr);
+
+  /// Getters and setters for the arguments of the instrumentation function for
+  /// the atomic RMW opportunity.
+  ///{
+  LLVM_ABI static Value *getPointer(Value &V, Type &Ty,
+                                    InstrumentationConfig &IConf,
+                                    InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *setPointer(Value &V, Value &NewV,
+                                    InstrumentationConfig &IConf,
+                                    InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *getPointerAS(Value &V, Type &Ty,
+                                      InstrumentationConfig &IConf,
+                                      InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *getBasePointerInfo(Value &V, Type &Ty,
+                                            InstrumentationConfig &IConf,
+                                            InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *getValue(Value &V, Type &Ty,
+                                  InstrumentationConfig &IConf,
+                                  InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *getValueSize(Value &V, Type &Ty,
+                                      InstrumentationConfig &IConf,
+                                      InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *getAlignment(Value &V, Type &Ty,
+                                      InstrumentationConfig &IConf,
+                                      InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *getValueTypeId(Value &V, Type &Ty,
+                                        InstrumentationConfig &IConf,
+                                        InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *getValueSubTypeId(Value &V, Type &Ty,
+                                           InstrumentationConfig &IConf,
+                                           InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *getAtomicityOrdering(Value &V, Type &Ty,
+                                              InstrumentationConfig &IConf,
+                                              InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *getSyncScopeId(Value &V, Type &Ty,
+                                        InstrumentationConfig &IConf,
+                                        InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *getValOperand(Value &V, Type &Ty,
+                                       InstrumentationConfig &IConf,
+                                       InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *getOperation(Value &V, Type &Ty,
+                                      InstrumentationConfig &IConf,
+                                      InstrumentorIRBuilderTy &IIRB);
+  LLVM_ABI static Value *isVolatile(Value &V, Type &Ty,
+                                    InstrumentationConfig &IConf,
+                                    InstrumentorIRBuilderTy &IIRB);
+  ///}
+
+  /// Create the atomic RMW opportunities for PRE and POST positions.
+  static void populate(InstrumentationConfig &IConf,
+                       InstrumentorIRBuilderTy &IIRB) {
+    auto *PreIO =
+        IConf.allocate<AtomicRMWIO>(InstrumentationLocation::INSTRUCTION_PRE);
+    PreIO->init(IConf, IIRB);
+    auto *PostIO =
+        IConf.allocate<AtomicRMWIO>(InstrumentationLocation::INSTRUCTION_POST);
+    PostIO->init(IConf, IIRB);
+  }
+};
+
 /// The instrumentation opportunity for type cast instructions.
 /// This includes PtrToInt, IntToPtr, Trunc, ZExt, SExt, FPToUI, FPToSI,
 /// UIToFP, SIToFP, FPTrunc, FPExt, AddrSpaceCast, and BitCast.
diff --git a/llvm/lib/Transforms/IPO/Instrumentor.cpp b/llvm/lib/Transforms/IPO/Instrumentor.cpp
index 393e90fdf7d0273..27b730f6be664f2 100644
--- a/llvm/lib/Transforms/IPO/Instrumentor.cpp
+++ b/llvm/lib/Transforms/IPO/Instrumentor.cpp
@@ -638,6 +638,7 @@ void InstrumentationConfig::populate(InstrumentorIRBuilderTy &IIRB) {
   UnreachableIO::populate(*this, IIRB);
   LoadIO::populate(*this, IIRB);
   StoreIO::populate(*this, IIRB);
+  AtomicRMWIO::populate(*this, IIRB);
   CastIO::populate(*this, IIRB);
   NumericIO::populate(*this, IIRB);
   CompareIO::populate(*this, IIRB);
@@ -1505,6 +1506,190 @@ Value *LoadIO::isVolatile(Value &V, Type &Ty, InstrumentationConfig &IConf,
   return getCI(&Ty, LI.isVolatile());
 }
 
+void AtomicRMWIO::init(InstrumentationConfig &IConf,
+                       InstrumentorIRBuilderTy &IIRB, ConfigTy *UserConfig) {
+  bool IsPRE = getLocationKind() == InstrumentationLocation::INSTRUCTION_PRE;
+  if (UserConfig)
+    Config = *UserConfig;
+  if (Config.has(PassPointer)) {
+    IRTArgs.push_back(
+        IRTArg(IIRB.PtrTy, "pointer", "The accessed pointer.",
+               ((IsPRE && Config.has(ReplacePointer)) ? IRTArg::REPLACABLE
+                                                      : IRTArg::NONE),
+               getPointer, setPointer));
+  }
+  if (Config.has(PassPointerAS)) {
+    IRTArgs.push_back(IRTArg(IIRB.Int32Ty, "pointer_as",
+                             "The address space of the accessed pointer.",
+                             IRTArg::NONE, getPointerAS));
+  }
+  if (Config.has(PassBasePointerInfo)) {
+    IRTArgs.push_back(IRTArg(IIRB.PtrTy, "base_pointer_info",
+                             "The runtime provided base pointer info.",
+                             IRTArg::NONE, getBasePointerInfo));
+  }
+  if (Config.has(PassValOperand)) {
+    IRTArgs.push_back(
+        IRTArg(IIRB.Int64Ty, "val_operand",
+               "The operand being atomically applied to the stored value.",
+               IRTArg::POTENTIALLY_INDIRECT |
+                   (Config.has(PassValueSize) ? IRTArg::INDIRECT_HAS_SIZE
+                                              : IRTArg::NONE),
+               getValOperand));
+  }
+  if (!IsPRE && Config.has(PassPrevValue)) {
+    IRTArgs.push_back(IRTArg(
+        getValueType(IIRB), "prev_value", "The unmodified old value.",
+        Config.has(ReplacePrevValue)
+            ? IRTArg::REPLACABLE | IRTArg::POTENTIALLY_INDIRECT |
+                  (Config.has(PassValueSize) ? IRTArg::INDIRECT_HAS_SIZE
+                                             : IRTArg::NONE)
+            : IRTArg::NONE,
+        getValue, Config.has(ReplacePrevValue) ? replaceValue : nullptr));
+  }
+  if (Config.has(PassValueSize)) {
+    IRTArgs.push_back(IRTArg(IIRB.Int64Ty, "value_size",
+                             "The size of the modified value.", IRTArg::NONE,
+                             getValueSize));
+  }
+  if (Config.has(PassAlignment)) {
+    IRTArgs.push_back(IRTArg(IIRB.Int64Ty, "alignment",
+                             "The known access alignment.", IRTArg::NONE,
+                             getAlignment));
+  }
+  if (Config.has(PassValueTypeId)) {
+    IRTArgs.push_back(IRTArg(IIRB.Int32Ty, "value_type_id",
+                             "The type id of the modified value.",
+                             IRTArg::TYPEID, getValueTypeId));
+  }
+  if (Config.has(PassValueSubTypeId)) {
+    IRTArgs.push_back(IRTArg(IIRB.Int32Ty, "value_sub_type_id",
+                             "The sub type id of the modified value (for "
+                             "arrays and vectors, or -1).",
+                             IRTArg::TYPEID, getValueSubTypeId));
+  }
+  if (Config.has(PassAtomicityOrdering)) {
+    IRTArgs.push_back(
+        IRTArg(IIRB.Int32Ty, "atomicity_ordering",
+               "The atomicity ordering of the atomic RMW instruction.",
+               IRTArg::NONE, getAtomicityOrdering));
+  }
+  if (Config.has(PassSyncScopeId)) {
+    IRTArgs.push_back(IRTArg(IIRB.Int8Ty, "sync_scope_id",
+                             "The sync scope id of the operation.",
+                             IRTArg::NONE, getSyncScopeId));
+  }
+  if (Config.has(PassOperation)) {
+    IRTArgs.push_back(IRTArg(IIRB.Int32Ty, "operation",
+                             "The atomic RMW instruction's operation id.",
+                             IRTArg::NONE, getOperation));
+  }
+  if (Config.has(PassIsVolatile)) {
+    IRTArgs.push_back(IRTArg(IIRB.Int8Ty, "is_volatile",
+                             "Flag indicating a volatile operation.",
+                             IRTArg::NONE, isVolatile));
+  }
+
+  addCommonArgs(IConf, IIRB.Ctx, Config.has(PassId));
+  IConf.addChoice(*this, IIRB.Ctx);
+}
+
+Value *AtomicRMWIO::getPointer(Value &V, Type &Ty, InstrumentationConfig &IConf,
+                               InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  return AI.getPointerOperand();
+}
+
+Value *AtomicRMWIO::setPointer(Value &V, Value &NewV,
+                               InstrumentationConfig &IConf,
+                               InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  AI.setOperand(AI.getPointerOperandIndex(), &NewV);
+  return &AI;
+}
+
+Value *AtomicRMWIO::getPointerAS(Value &V, Type &Ty,
+                                 InstrumentationConfig &IConf,
+                                 InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  return getCI(&Ty, AI.getPointerAddressSpace());
+}
+
+Value *AtomicRMWIO::getBasePointerInfo(Value &V, Type &Ty,
+                                       InstrumentationConfig &IConf,
+                                       InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  return IConf.getBasePointerInfo(*AI.getPointerOperand(), IIRB);
+}
+
+Value *AtomicRMWIO::getValue(Value &V, Type &Ty, InstrumentationConfig &IConf,
+                             InstrumentorIRBuilderTy &IIRB) {
+  return &V;
+}
+
+Value *AtomicRMWIO::getValueSize(Value &V, Type &Ty,
+                                 InstrumentationConfig &IConf,
+                                 InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  auto &DL = AI.getDataLayout();
+  return getCI(&Ty, DL.getTypeStoreSize(AI.getType()));
+}
+
+Value *AtomicRMWIO::getAlignment(Value &V, Type &Ty,
+                                 InstrumentationConfig &IConf,
+                                 InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  return getCI(&Ty, AI.getAlign().value());
+}
+
+Value *AtomicRMWIO::getValueTypeId(Value &V, Type &Ty,
+                                   InstrumentationConfig &IConf,
+                                   InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  return getCI(&Ty, AI.getType()->getTypeID());
+}
+
+Value *AtomicRMWIO::getValueSubTypeId(Value &V, Type &Ty,
+                                      InstrumentationConfig &IConf,
+                                      InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  return getSubTypeID(*AI.getType(), Ty);
+}
+
+Value *AtomicRMWIO::getAtomicityOrdering(Value &V, Type &Ty,
+                                         InstrumentationConfig &IConf,
+                                         InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  return getCI(&Ty, uint64_t(AI.getOrdering()));
+}
+
+Value *AtomicRMWIO::getSyncScopeId(Value &V, Type &Ty,
+                                   InstrumentationConfig &IConf,
+                                   InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  return getCI(&Ty, uint64_t(AI.getSyncScopeID()));
+}
+
+Value *AtomicRMWIO::getValOperand(Value &V, Type &Ty,
+                                  InstrumentationConfig &IConf,
+                                  InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  return AI.getValOperand();
+}
+
+Value *AtomicRMWIO::getOperation(Value &V, Type &Ty,
+                                 InstrumentationConfig &IConf,
+                                 InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  return getCI(&Ty, AI.getOperation());
+}
+
+Value *AtomicRMWIO::isVolatile(Value &V, Type &Ty, InstrumentationConfig &IConf,
+                               InstrumentorIRBuilderTy &IIRB) {
+  auto &AI = cast<AtomicRMWInst>(V);
+  return getCI(&Ty, AI.isVolatile());
+}
+
 void BasePointerIO::init(InstrumentationConfig &IConf,
                          InstrumentorIRBuilderTy &IIRB, ConfigTy *UserConfig) {
   if (UserConfig)
diff --git a/llvm/test/Instrumentation/Instrumentor/atomicrmw.ll b/llvm/test/Instrumentation/Instrumentor/atomicrmw.ll
new file mode 100644
index 000000000000000..a74ca2b7c40762f
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/atomicrmw.ll
@@ -0,0 +1,40 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=instrumentor -instrumentor-read-config-files=%S/atomicrmw_config.json -S 2>&1 | FileCheck %s
+; RUN: opt < %s -passes=instrumentor -instrumentor-read-config-files=%S/atomicrmw_simple_config.json -S 2>&1 | FileCheck %s --check-prefix=SIMPLE
+
+define i64 @foo(ptr %p, i64 %val) {
+; CHECK-LABEL: define i64 @foo(
+; CHECK-SAME: ptr [[P:%.*]], i64 [[VAL:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__instrumentor_post_base_pointer_info(ptr [[P]], i32 0, i32 -1) #[[ATTR0:[0-9]+]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @__instrumentor_pre_atomicrmw(ptr [[P]], i32 0, ptr [[TMP0]], i64 [[VAL]], i64 8, i64 8, i32 12, i32 -1, i32 2, i8 1, i32 3, i8 0, i32 1) #[[ATTR0]]
+; CHECK-NEXT:    [[RMW_OLD1:%.*]] = atomicrmw and ptr [[TMP1]], i64 [[VAL]] monotonic, align 8
+; CHECK-NEXT:    [[TMP2:%.*]] = call i64 @__instrumentor_post_atomicrmw(ptr [[P]], i32 0, ptr [[TMP0]], i64 [[VAL]], i64 [[RMW_OLD1]], i64 8, i64 8, i32 12, i32 -1, i32 2, i8 1, i32 3, i8 0, i32 -1) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP3:%.*]] = call ptr @__instrumentor_pre_atomicrmw(ptr [[P]], i32 0, ptr [[TMP0]], i64 [[TMP2]], i64 8, i64 8, i32 12, i32 -1, i32 7, i8 1, i32 1, i8 1, i32 2) #[[ATTR0]]
+; CHECK-NEXT:    [[RMW_OLD2:%.*]] = atomicrmw volatile add ptr [[TMP3]], i64 [[TMP2]] seq_cst, align 8
+; CHECK-NEXT:    [[TMP4:%.*]] = call i64 @__instrumentor_post_atomicrmw(ptr [[P]], i32 0, ptr [[TMP0]], i64 [[TMP2]], i64 [[RMW_OLD2]], i64 8, i64 8, i32 12, i32 -1, i32 7, i8 1, i32 1, i8 1, i32 -2) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = call ptr @__instrumentor_pre_atomicrmw(ptr [[P]], i32 0, ptr [[TMP0]], i64 [[TMP4]], i64 8, i64 8, i32 12, i32 -1, i32 4, i8 1, i32 5, i8 0, i32 3) #[[ATTR0]]
+; CHECK-NEXT:    [[RMW_OLD3:%.*]] = atomicrmw or ptr [[TMP5]], i64 [[TMP4]] acquire, align 8
+; CHECK-NEXT:    [[TMP6:%.*]] = call i64 @__instrumentor_post_atomicrmw(ptr [[P]], i32 0, ptr [[TMP0]], i64 [[TMP4]], i64 [[RMW_OLD3]], i64 8, i64 8, i32 12, i32 -1, i32 4, i8 1, i32 5, i8 0, i32 -3) #[[ATTR0]]
+; CHECK-NEXT:    ret i64 [[TMP6]]
+;
+; SIMPLE-LABEL: define i64 @foo(
+; SIMPLE-SAME: ptr [[P:%.*]], i64 [[VAL:%.*]]) {
+; SIMPLE-NEXT:  [[ENTRY:.*:]]
+; SIMPLE-NEXT:    call void @__instrumentor_pre_atomicrmw(ptr [[P]], i32 0, i64 [[VAL]], i64 8, i64 8, i32 12, i32 -1, i32 2, i8 1, i32 3, i8 0, i32 1) #[[ATTR0:[0-9]+]]
+; SIMPLE-NEXT:    [[RMW_OLD1:%.*]] = atomicrmw and ptr [[P]], i64 [[VAL]] monotonic, align 8
+; SIMPLE-NEXT:    call void @__instrumentor_post_atomicrmw(ptr [[P]], i32 0, i64 [[VAL]], i64 8, i64 8, i32 12, i32 -1, i32 2, i8 1, i32 3, i8 0, i32 -1) #[[ATTR0]]
+; SIMPLE-NEXT:    call void @__instrumentor_pre_atomicrmw(ptr [[P]], i32 0, i64 [[RMW_OLD1]], i64 8, i64 8, i32 12, i32 -1, i32 7, i8 1, i32 1, i8 1, i32 2) #[[ATTR0]]
+; SIMPLE-NEXT:    [[RMW_OLD2:%.*]] = atomicrmw volatile add ptr [[P]], i64 [[RMW_OLD1]] seq_cst, align 8
+; SIMPLE-NEXT:    call void @__instrumentor_post_atomicrmw(ptr [[P]], i32 0, i64 [[RMW_OLD1]], i64 8, i64 8, i32 12, i32 -1, i32 7, i8 1, i32 1, i8 1, i32 -2) #[[ATTR0]]
+; SIMPLE-NEXT:    call void @__instrumentor_pre_atomicrmw(ptr [[P]], i32 0, i64 [[RMW_OLD2]], i64 8, i64 8, i32 12, i32 -1, i32 4, i8 1, i32 5, i8 0, i32 3) #[[ATTR0]]
+; SIMPLE-NEXT:    [[RMW_OLD3:%.*]] = atomicrmw or ptr [[P]], i64 [[RMW_OLD2]] acquire, align 8
+; SIMPLE-NEXT:    call void @__instrumentor_post_atomicrmw(ptr [[P]], i32 0, i64 [[RMW_OLD2]], i64 8, i64 8, i32 12, i32 -1, i32 4, i8 1, i32 5, i8 0, i32 -3) #[[ATTR0]]
+; SIMPLE-NEXT:    ret i64 [[RMW_OLD3]]
+;
+entry:
+  %rmw.old1 = atomicrmw and ptr %p, i64 %val monotonic, align 8
+  %rmw.old2 = atomicrmw volatile add ptr %p, i64 %rmw.old1 seq_cst
+  %rmw.old3 = atomicrmw or ptr %p, i64 %rmw.old2 acquire
+  ret i64 %rmw.old3
+}
diff --git a/llvm/test/Instrumentation/Instrumentor/atomicrmw_config.json b/llvm/test/Instrumentation/Instrumentor/atomicrmw_config.json
new file mode 100644
index 000000000000000..b1c6fb9e632ec2b
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/atomicrmw_config.json
@@ -0,0 +1,54 @@
+{
+  "configuration": {
+    "runtime_prefix": "__instrumentor_",
+    "demangle_function_names": true
+  },
+  "instruction_pre": {
+    "atomicrmw": {
+      "enabled": true,
+      "pointer": true,
+      "pointer.replace": true,
+      "pointer_as": true,
+      "base_pointer_info": true,
+      "val_operand": true,
+      "value_size": true,
+      "alignment": true,
+      "value_type_id": true,
+      "value_sub_type_id": true,
+      "atomicity_ordering": true,
+      "sync_scope_id": true,
+      "operation": true,
+      "is_volatile": true,
+      "id": true
+    }
+  },
+  "instruction_post": {
+    "atomicrmw": {
+      "enabled": true,
+      "pointer": true,
+      "pointer_as": true,
+      "base_pointer_info": true,
+      "val_operand": true,
+      "prev_value": true,
+      "prev_value.replace": true,
+      "value_size": true,
+      "alignment": true,
+      "value_type_id": true,
+      "value_sub_type_id": true,
+      "atomicity_ordering": true,
+      "sync_scope_id": true,
+      "operation": true,
+      "is_volatile": true,
+      "id": true
+    }
+  },
+  "special_value": {
+    "base_pointer_info": {
+      "enabled": true,
+      "base_pointer": true,
+      "base_pointer.replace": true,
+      "base_pointer_kind": true,
+      "id": true
+    }
+  }
+}
diff --git a/llvm/test/Instrumentation/Instrumentor/atomicrmw_simple_config.json b/llvm/test/Instrumentation/Instrumentor/atomicrmw_simple_config.json
new file mode 100644
index 000000000000000..65e9cd451246da4
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/atomicrmw_simple_config.json
@@ -0,0 +1,41 @@
+{
+  "configuration": {
+    "runtime_prefix": "__instrumentor_",
+    "demangle_function_names": true
+  },
+  "instruction_pre": {
+    "atomicrmw": {
+      "enabled": true,
+      "pointer": true,
+      "pointer_as": true,
+      "val_operand": true,
+      "value_size": true,
+      "alignment": true,
+      "value_type_id": true,
+      "value_sub_type_id": true,
+      "atomicity_ordering": true,
+      "sync_scope_id": true,
+      "operation": true,
+      "is_volatile": true,
+      "id": true
+    }
+  },
+  "instruction_post": {
+    "atomicrmw": {
+      "enabled": true,
+      "pointer": true,
+      "pointer_as": true,
+      "val_operand": true,
+      "value": true,
+      "value_size": true,
+      "alignment": true,
+      "value_type_id": true,
+      "value_sub_type_id": true,
+      "atomicity_ordering": true,
+      "sync_scope_id": true,
+      "operation": true,
+      "is_volatile": true,
+      "id": true
+    }
+  }
+}
diff --git a/llvm/test/Instrumentation/Instrumentor/default_config.json b/llvm/test/Instrumentation/Instrumentor/default_config.json
index fc712537e5e224c..220f67c15836c01 100644
--- a/llvm/test/Instrumentation/Instrumentor/default_config.json
+++ b/llvm/test/Instrumentation/Instrumentor/default_config.json
@@ -213,6 +213,38 @@
       "id": true,
       "id.description": "A unique ID associated with the given instrumentor call"
     },
+    "atomicrmw": {
+      "enabled": true,
+      "filter": "",
+      "filter.description": "Static property filter to exclude instrumentation.",
+      "pointer": true,
+      "pointer.replace": true,
+      "pointer.description": "The accessed pointer.",
+      "pointer_as": true,
+      "pointer_as.description": "The address space of the accessed pointer.",
+      "base_pointer_info": true,
+      "base_pointer_info.description": "The runtime provided base pointer info.",
+      "val_operand": true,
+      "val_operand.description": "The operand being atomically applied to the stored value.",
+      "value_size": true,
+      "value_size.description": "The size of the modified value.",
+      "alignment": true,
+      "alignment.description": "The known access alignment.",
+      "value_type_id": true,
+      "value_type_id.description": "The type id of the modified value.",
+      "value_sub_type_id": true,
+      "value_sub_type_id.description": "The sub type id of the modified value (for arrays and vectors, or -1).",
+      "atomicity_ordering": true,
+      "atomicity_ordering.description": "The atomicity ordering of the atomic RMW instruction.",
+      "sync_scope_id": true,
+      "sync_scope_id.description": "The sync scope id of the operation.",
+      "operation": true,
+      "operation.description": "The atomic RMW instruction's operation id.",
+      "is_volatile": true,
+      "is_volatile.description": "Flag indicating a volatile operation.",
+      "id": true,
+      "id.description": "A unique ID associated with the given instrumentor call"
+    },
     "cast": {
       "enabled": true,
       "filter": "",
@@ -353,6 +385,40 @@
       "id": true,
       "id.description": "A unique ID associated with the given instrumentor call"
     },
+    "atomicrmw": {
+      "enabled": true,
+      "filter": "",
+      "filter.description": "Static property filter to exclude instrumentation.",
+      "pointer": true,
+      "pointer.description": "The accessed pointer.",
+      "pointer_as": true,
+      "pointer_as.description": "The address space of the accessed pointer.",
+      "base_pointer_info": true,
+      "base_pointer_info.description": "The runtime provided base pointer info.",
+      "val_operand": true,
+      "val_operand.description": "The operand being atomically applied to the stored value.",
+      "prev_value": true,
+      "prev_value.replace": true,
+      "prev_value.description": "The unmodified old value.",
+      "value_size": true,
+      "value_size.description": "The size of the modified value.",
+      "alignment": true,
+      "alignment.description": "The known access alignment.",
+      "value_type_id": true,
+      "value_type_id.description": "The type id of the modified value.",
+      "value_sub_type_id": true,
+      "value_sub_type_id.description": "The sub type id of the modified value (for arrays and vectors, or -1).",
+      "atomicity_ordering": true,
+      "atomicity_ordering.description": "The atomicity ordering of the atomic RMW instruction.",
+      "sync_scope_id": true,
+      "sync_scope_id.description": "The sync scope id of the operation.",
+      "operation": true,
+      "operation.description": "The atomic RMW instruction's operation id.",
+      "is_volatile": true,
+      "is_volatile.description": "Flag indicating a volatile operation.",
+      "id": true,
+      "id.description": "A unique ID associated with the given instrumentor call"
+    },
     "cast": {
       "enabled": true,
       "filter": "",
diff --git a/llvm/test/Instrumentation/Instrumentor/default_rt.c b/llvm/test/Instrumentation/Instrumentor/default_rt.c
index bce5fa9c63a1e18..3d3caf28f815b77 100644
--- a/llvm/test/Instrumentation/Instrumentor/default_rt.c
+++ b/llvm/test/Instrumentation/Instrumentor/default_rt.c
@@ -97,6 +97,16 @@ void *__instrumentor_pre_store_ind(void *pointer, int32_t pointer_as, void *base
   return pointer;
 }
 
+void *__instrumentor_pre_atomicrmw(void *pointer, int32_t pointer_as, void *base_pointer_info, int64_t val_operand, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t value_sub_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int32_t operation, int8_t is_volatile, int32_t id) {
+  printf("atomicrmw pre -- pointer: %p, pointer_as: %" PRId32 ", base_pointer_info: %p, val_operand: %" PRId64 ", value_size: %" PRId64 ", alignment: %" PRId64 ", value_type_id: %s, value_sub_type_id: %s, atomicity_ordering: %" PRId32 ", sync_scope_id: %" PRId32 ", operation: %" PRId32 ", is_volatile: %" PRId32 ", id: %" PRId32 "\n", pointer, pointer_as, base_pointer_info, val_operand, value_size, alignment, getLLVMTypeIDName(value_type_id), getLLVMTypeIDName(value_sub_type_id), atomicity_ordering, sync_scope_id, operation, is_volatile, id);
+  return pointer;
+}
+
+void *__instrumentor_pre_atomicrmw_ind(void *pointer, int32_t pointer_as, void *base_pointer_info, int64_t *val_operand_ptr, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t value_sub_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int32_t operation, int8_t is_volatile, int32_t id) {
+  printf("atomicrmw pre -- pointer: %p, pointer_as: %" PRId32 ", base_pointer_info: %p, val_operand: %p, value_size: %" PRId64 ", alignment: %" PRId64 ", value_type_id: %s, value_sub_type_id: %s, atomicity_ordering: %" PRId32 ", sync_scope_id: %" PRId32 ", operation: %" PRId32 ", is_volatile: %" PRId32 ", id: %" PRId32 "\n", pointer, pointer_as, base_pointer_info, val_operand_ptr, value_size, alignment, getLLVMTypeIDName(value_type_id), getLLVMTypeIDName(value_sub_type_id), atomicity_ordering, sync_scope_id, operation, is_volatile, id);
+  return pointer;
+}
+
 void __instrumentor_pre_cast(int64_t input, int32_t input_type_id, int32_t input_sub_type_id, int32_t input_size, int32_t result_type_id, int32_t result_sub_type_id, int32_t result_size, int32_t opcode, int32_t id) {
   printf("cast pre -- input: %" PRId64 ", input_type_id: %s, input_sub_type_id: %s, input_size: %" PRId32 ", result_type_id: %s, result_sub_type_id: %s, result_size: %" PRId32 ", opcode: %" PRId32 ", id: %" PRId32 "\n", input, getLLVMTypeIDName(input_type_id), getLLVMTypeIDName(input_sub_type_id), input_size, getLLVMTypeIDName(result_type_id), getLLVMTypeIDName(result_sub_type_id), result_size, opcode, id);
 }
@@ -127,6 +137,15 @@ void __instrumentor_post_store_ind(void *pointer, int32_t pointer_as, void *base
   printf("store post -- pointer: %p, pointer_as: %" PRId32 ", base_pointer_info: %p, value: %p, value_size: %" PRId64 ", alignment: %" PRId64 ", value_type_id: %s, value_sub_type_id: %s, atomicity_ordering: %" PRId32 ", sync_scope_id: %" PRId32 ", is_volatile: %" PRId32 ", id: %" PRId32 "\n", pointer, pointer_as, base_pointer_info, value_ptr, value_size, alignment, getLLVMTypeIDName(value_type_id), getLLVMTypeIDName(value_sub_type_id), atomicity_ordering, sync_scope_id, is_volatile, id);
 }
 
+int64_t __instrumentor_post_atomicrmw(void *pointer, int32_t pointer_as, void *base_pointer_info, int64_t val_operand, int64_t prev_value, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t value_sub_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int32_t operation, int8_t is_volatile, int32_t id) {
+  printf("atomicrmw post -- pointer: %p, pointer_as: %" PRId32 ", base_pointer_info: %p, val_operand: %" PRId64 ", prev_value: %" PRId64 ", value_size: %" PRId64 ", alignment: %" PRId64 ", value_type_id: %s, value_sub_type_id: %s, atomicity_ordering: %" PRId32 ", sync_scope_id: %" PRId32 ", operation: %" PRId32 ", is_volatile: %" PRId32 ", id: %" PRId32 "\n", pointer, pointer_as, base_pointer_info, val_operand, prev_value, value_size, alignment, getLLVMTypeIDName(value_type_id), getLLVMTypeIDName(value_sub_type_id), atomicity_ordering, sync_scope_id, operation, is_volatile, id);
+  return prev_value;
+}
+
+void __instrumentor_post_atomicrmw_ind(void *pointer, int32_t pointer_as, void *base_pointer_info, int64_t *val_operand_ptr, int64_t *prev_value_ptr, int64_t value_size, int64_t alignment, int32_t value_type_id, int32_t value_sub_type_id, int32_t atomicity_ordering, int8_t sync_scope_id, int32_t operation, int8_t is_volatile, int32_t id) {
+  printf("atomicrmw post -- pointer: %p, pointer_as: %" PRId32 ", base_pointer_info: %p, val_operand: %p, prev_value: %p, value_size: %" PRId64 ", alignment: %" PRId64 ", value_type_id: %s, value_sub_type_id: %s, atomicity_ordering: %" PRId32 ", sync_scope_id: %" PRId32 ", operation: %" PRId32 ", is_volatile: %" PRId32 ", id: %" PRId32 "\n", pointer, pointer_as, base_pointer_info, val_operand_ptr, prev_value_ptr, value_size, alignment, getLLVMTypeIDName(value_type_id), getLLVMTypeIDName(value_sub_type_id), atomicity_ordering, sync_scope_id, operation, is_volatile, id);
+}
+
 int64_t __instrumentor_post_cast(int64_t input, int32_t input_type_id, int32_t input_sub_type_id, int32_t input_size, int64_t result, int32_t result_type_id, int32_t result_sub_type_id, int32_t result_size, int32_t opcode, int32_t id) {
   printf("cast post -- input: %" PRId64 ", input_type_id: %s, input_sub_type_id: %s, input_size: %" PRId32 ", result: %" PRId64 ", result_type_id: %s, result_sub_type_id: %s, result_size: %" PRId32 ", opcode: %" PRId32 ", id: %" PRId32 "\n", input, getLLVMTypeIDName(input_type_id), getLLVMTypeIDName(input_sub_type_id), input_size, result, getLLVMTypeIDName(result_type_id), getLLVMTypeIDName(result_sub_type_id), result_size, opcode, id);
   return result;
diff --git a/llvm/test/Instrumentation/Instrumentor/rt_config.json b/llvm/test/Instrumentation/Instrumentor/rt_config.json
index 42d0f0b047309fa..563e1754834cd84 100644
--- a/llvm/test/Instrumentation/Instrumentor/rt_config.json
+++ b/llvm/test/Instrumentation/Instrumentor/rt_config.json
@@ -209,6 +209,38 @@
       "id": true,
       "id.description": "A unique ID associated with the given instrumentor call"
     },
+    "atomicrmw": {
+      "enabled": true,
+      "filter": "",
+      "filter.description": "Static property filter to exclude instrumentation.",
+      "pointer": true,
+      "pointer.replace": true,
+      "pointer.description": "The accessed pointer.",
+      "pointer_as": true,
+      "pointer_as.description": "The address space of the accessed pointer.",
+      "base_pointer_info": true,
+      "base_pointer_info.description": "The runtime provided base pointer info.",
+      "val_operand": true,
+      "val_operand.description": "The operand being atomically applied to the stored value.",
+      "value_size": true,
+      "value_size.description": "The size of the modified value.",
+      "alignment": true,
+      "alignment.description": "The known access alignment.",
+      "value_type_id": true,
+      "value_type_id.description": "The type id of the modified value.",
+      "value_sub_type_id": true,
+      "value_sub_type_id.description": "The sub type id of the modified value (for arrays and vectors, or -1).",
+      "atomicity_ordering": true,
+      "atomicity_ordering.description": "The atomicity ordering of the atomic RMW instruction.",
+      "sync_scope_id": true,
+      "sync_scope_id.description": "The sync scope id of the operation.",
+      "operation": true,
+      "operation.description": "The atomic RMW instruction's operation id.",
+      "is_volatile": true,
+      "is_volatile.description": "Flag indicating a volatile operation.",
+      "id": true,
+      "id.description": "A unique ID associated with the given instrumentor call"
+    },
     "cast": {
       "enabled": true,
       "filter": "",
@@ -307,6 +339,40 @@
       "id": true,
       "id.description": "A unique ID associated with the given instrumentor call"
     },
+    "atomicrmw": {
+      "enabled": true,
+      "filter": "",
+      "filter.description": "Static property filter to exclude instrumentation.",
+      "pointer": true,
+      "pointer.description": "The accessed pointer.",
+      "pointer_as": true,
+      "pointer_as.description": "The address space of the accessed pointer.",
+      "base_pointer_info": true,
+      "base_pointer_info.description": "The runtime provided base pointer info.",
+      "val_operand": true,
+      "val_operand.description": "The operand being atomically applied to the stored value.",
+      "prev_value": true,
+      "prev_value.replace": true,
+      "prev_value.description": "The unmodified old value.",
+      "value_size": true,
+      "value_size.description": "The size of the modified value.",
+      "alignment": true,
+      "alignment.description": "The known access alignment.",
+      "value_type_id": true,
+      "value_type_id.description": "The type id of the modified value.",
+      "value_sub_type_id": true,
+      "value_sub_type_id.description": "The sub type id of the modified value (for arrays and vectors, or -1).",
+      "atomicity_ordering": true,
+      "atomicity_ordering.description": "The atomicity ordering of the atomic RMW instruction.",
+      "sync_scope_id": true,
+      "sync_scope_id.description": "The sync scope id of the operation.",
+      "operation": true,
+      "operation.description": "The atomic RMW instruction's operation id.",
+      "is_volatile": true,
+      "is_volatile.description": "Flag indicating a volatile operation.",
+      "id": true,
+      "id.description": "A unique ID associated with the given instrumentor call"
+    },
     "cast": {
       "enabled": true,
       "filter": "",



More information about the llvm-commits mailing list