[llvm] [Instrumentor] Add Instrumentor pass (PR #138958)

via llvm-commits llvm-commits at lists.llvm.org
Wed May 7 13:48:41 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Kevin Sala Penades (kevinsala)

<details>
<summary>Changes</summary>

This PR adds the basic infrastructure for the Instrumentor pass, which allows instrumenting code in a simple and customizable way. This commit adds support for instrumenting load and store instructions. The Instrumentor can be configured with a JSON file that describes what should be instrumented, or can be used programmatically from another pass.

The default JSON config file can be found in: `llvm/test/Instrumentation/Instrumentor/default_config.json`. More information about Instrumentor in the [RFC](https://discourse.llvm.org/t/rfc-introducing-instrumentor-easily-customizable-code-instrumentation/86020).

This is only a squash commit of several contributions to the Instrumentor. The following are the authors and contributors of this pass:

- Johannes Doerfert @<!-- -->jdoerfert
- Kevin Sala @<!-- -->kevinsala
- Ivan Radanov Ivanov @<!-- -->ivanradanov
- Ethan Luis McDonough @<!-- -->EthanLuisMcDonough

---

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


19 Files Affected:

- (added) llvm/include/llvm/Transforms/IPO/Instrumentor.h (+739) 
- (added) llvm/include/llvm/Transforms/IPO/InstrumentorConfigFile.h (+29) 
- (modified) llvm/lib/Passes/PassBuilder.cpp (+1) 
- (modified) llvm/lib/Passes/PassBuilderPipelines.cpp (+12) 
- (modified) llvm/lib/Passes/PassRegistry.def (+1) 
- (modified) llvm/lib/Transforms/IPO/CMakeLists.txt (+3) 
- (added) llvm/lib/Transforms/IPO/Instrumentor.cpp (+645) 
- (added) llvm/lib/Transforms/IPO/InstrumentorConfigFile.cpp (+203) 
- (added) llvm/test/Instrumentation/Instrumentor/counters.ll (+23) 
- (added) llvm/test/Instrumentation/Instrumentor/counters_config.json (+25) 
- (added) llvm/test/Instrumentation/Instrumentor/custom_config.json (+14) 
- (added) llvm/test/Instrumentation/Instrumentor/default_config.json (+109) 
- (added) llvm/test/Instrumentation/Instrumentor/load_store.ll (+217) 
- (added) llvm/test/Instrumentation/Instrumentor/load_store_args.ll (+226) 
- (added) llvm/test/Instrumentation/Instrumentor/load_store_config.json (+107) 
- (added) llvm/test/Instrumentation/Instrumentor/load_store_noreplace.ll (+208) 
- (added) llvm/test/Instrumentation/Instrumentor/load_store_noreplace_config.json (+107) 
- (added) llvm/test/Instrumentation/Instrumentor/read_config.ll (+26) 
- (added) llvm/test/Instrumentation/Instrumentor/write_config.ll (+3) 


``````````diff
diff --git a/llvm/include/llvm/Transforms/IPO/Instrumentor.h b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
new file mode 100644
index 0000000000000..6fb5a06305096
--- /dev/null
+++ b/llvm/include/llvm/Transforms/IPO/Instrumentor.h
@@ -0,0 +1,739 @@
+//===- Transforms/IPO/Instrumentor.h --------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// A highly configurable instrumentation pass.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_IPO_INSTRUMENTOR_H
+#define LLVM_TRANSFORMS_IPO_INSTRUMENTOR_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/EnumeratedArray.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Transforms/Utils/Instrumentation.h"
+
+#include <bitset>
+#include <cstdint>
+#include <functional>
+#include <string>
+#include <tuple>
+
+namespace llvm {
+namespace instrumentor {
+
+struct InstrumentationConfig;
+struct InstrumentationOpportunity;
+
+struct InstrumentorIRBuilderTy {
+  InstrumentorIRBuilderTy(Module &M, FunctionAnalysisManager &FAM)
+      : M(M), Ctx(M.getContext()), FAM(FAM),
+        IRB(Ctx, ConstantFolder(),
+            IRBuilderCallbackInserter(
+                [&](Instruction *I) { NewInsts[I] = Epoche; })) {}
+
+  ~InstrumentorIRBuilderTy() {
+    for (auto *I : ToBeErased) {
+      if (!I->getType()->isVoidTy())
+        I->replaceAllUsesWith(PoisonValue::get(I->getType()));
+      I->eraseFromParent();
+    }
+  }
+
+  /// Get a temporary alloca to communicate (large) values with the runtime.
+  AllocaInst *getAlloca(Function *Fn, Type *Ty, bool MatchType = false) {
+    const DataLayout &DL = Fn->getDataLayout();
+    auto *&AllocaList = AllocaMap[{Fn, DL.getTypeAllocSize(Ty)}];
+    if (!AllocaList)
+      AllocaList = new AllocaListTy;
+    AllocaInst *AI = nullptr;
+    for (auto *&ListAI : *AllocaList) {
+      if (MatchType && ListAI->getAllocatedType() != Ty)
+        continue;
+      AI = ListAI;
+      ListAI = *AllocaList->rbegin();
+      break;
+    }
+    if (AI)
+      AllocaList->pop_back();
+    else
+      AI = new AllocaInst(Ty, DL.getAllocaAddrSpace(), "",
+                          Fn->getEntryBlock().begin());
+    UsedAllocas[AI] = AllocaList;
+    return AI;
+  }
+
+  /// Return the temporary allocas.
+  void returnAllocas() {
+    for (auto [AI, List] : UsedAllocas)
+      List->push_back(AI);
+    UsedAllocas.clear();
+  }
+
+  /// Commonly used values for IR inspection and creation.
+  ///{
+
+  Module &M;
+
+  /// The underying LLVM context.
+  LLVMContext &Ctx;
+
+  const DataLayout &DL = M.getDataLayout();
+
+  Type *VoidTy = Type::getVoidTy(Ctx);
+  Type *IntptrTy = M.getDataLayout().getIntPtrType(Ctx);
+  PointerType *PtrTy = PointerType::getUnqual(Ctx);
+  IntegerType *Int8Ty = Type::getInt8Ty(Ctx);
+  IntegerType *Int32Ty = Type::getInt32Ty(Ctx);
+  IntegerType *Int64Ty = Type::getInt64Ty(Ctx);
+  Constant *NullPtrVal = Constant::getNullValue(PtrTy);
+  ///}
+
+  /// Mapping to remember temporary allocas for reuse.
+  using AllocaListTy = SmallVector<AllocaInst *>;
+  DenseMap<std::pair<Function *, unsigned>, AllocaListTy *> AllocaMap;
+  DenseMap<AllocaInst *, SmallVector<AllocaInst *> *> UsedAllocas;
+
+  void eraseLater(Instruction *I) { ToBeErased.insert(I); }
+  SmallPtrSet<Instruction *, 32> ToBeErased;
+
+  FunctionAnalysisManager &FAM;
+
+  IRBuilder<ConstantFolder, IRBuilderCallbackInserter> IRB;
+
+  /// Each instrumentation, i.a., of an instruction, is happening in a dedicated
+  /// epoche. The epoche allows to determine if instrumentation instructions
+  /// were already around, due to prior instrumentations, or have been
+  /// introduced to support the current instrumentation, i.a., compute
+  /// information about the current instruction.
+  unsigned Epoche = 0;
+
+  /// A mapping from instrumentation instructions to the epoche they have been
+  /// created.
+  DenseMap<Instruction *, unsigned> NewInsts;
+};
+
+using GetterCallbackTy = std::function<Value *(
+    Value &, Type &, InstrumentationConfig &, InstrumentorIRBuilderTy &)>;
+using SetterCallbackTy = std::function<Value *(
+    Value &, Value &, InstrumentationConfig &, InstrumentorIRBuilderTy &)>;
+
+struct IRTArg {
+  enum IRArgFlagTy {
+    NONE = 0,
+    STRING = 1 << 0,
+    REPLACABLE = 1 << 1,
+    REPLACABLE_CUSTOM = 1 << 2,
+    POTENTIALLY_INDIRECT = 1 << 3,
+    INDIRECT_HAS_SIZE = 1 << 4,
+
+    LAST,
+  };
+
+  IRTArg(Type *Ty, StringRef Name, StringRef Description, unsigned Flags,
+         GetterCallbackTy GetterCB, SetterCallbackTy SetterCB = nullptr,
+         bool Enabled = true, bool NoCache = false)
+      : Enabled(Enabled), Ty(Ty), Name(Name), Description(Description),
+        Flags(Flags), GetterCB(std::move(GetterCB)),
+        SetterCB(std::move(SetterCB)), NoCache(NoCache) {}
+
+  bool Enabled;
+  Type *Ty;
+  StringRef Name;
+  StringRef Description;
+  unsigned Flags;
+  GetterCallbackTy GetterCB;
+  SetterCallbackTy SetterCB;
+  bool NoCache;
+};
+
+struct InstrumentationCaches {
+  DenseMap<std::tuple<unsigned, StringRef, StringRef>, Value *> DirectArgCache;
+  DenseMap<std::tuple<unsigned, StringRef, StringRef>, Value *>
+      IndirectArgCache;
+};
+
+struct IRTCallDescription {
+  IRTCallDescription(InstrumentationOpportunity &IConf, Type *RetTy = nullptr);
+
+  FunctionType *createLLVMSignature(InstrumentationConfig &IConf,
+                                    LLVMContext &Ctx, const DataLayout &DL,
+                                    bool ForceIndirection);
+  CallInst *createLLVMCall(Value *&V, InstrumentationConfig &IConf,
+                           InstrumentorIRBuilderTy &IIRB, const DataLayout &DL,
+                           InstrumentationCaches &ICaches);
+
+  bool isReplacable(IRTArg &IRTA) const {
+    return (IRTA.Flags & (IRTArg::REPLACABLE | IRTArg::REPLACABLE_CUSTOM));
+  }
+
+  bool isPotentiallyIndirect(IRTArg &IRTA) const {
+    return ((IRTA.Flags & IRTArg::POTENTIALLY_INDIRECT) ||
+            ((IRTA.Flags & IRTArg::REPLACABLE) && NumReplaceableArgs > 1));
+  }
+
+  bool RequiresIndirection = false;
+  bool MightRequireIndirection = false;
+  unsigned NumReplaceableArgs = 0;
+  InstrumentationOpportunity &IO;
+  Type *RetTy = nullptr;
+};
+
+struct InstrumentationLocation {
+  enum KindTy {
+    MODULE_PRE,
+    MODULE_POST,
+    GLOBAL_PRE,
+    GLOBAL_POST,
+    FUNCTION_PRE,
+    FUNCTION_POST,
+    BASIC_BLOCK_PRE,
+    BASIC_BLOCK_POST,
+    INSTRUCTION_PRE,
+    INSTRUCTION_POST,
+    SPECIAL_VALUE,
+    Last = SPECIAL_VALUE,
+  };
+
+  InstrumentationLocation(KindTy Kind) : Kind(Kind) {
+    assert(Kind != INSTRUCTION_PRE && Kind != INSTRUCTION_POST &&
+           "Opcode required!");
+  }
+
+  InstrumentationLocation(unsigned Opcode, bool IsPRE)
+      : Kind(IsPRE ? INSTRUCTION_PRE : INSTRUCTION_POST), Opcode(Opcode) {}
+
+  KindTy getKind() const { return Kind; }
+
+  static StringRef getKindStr(KindTy Kind) {
+    switch (Kind) {
+    case MODULE_PRE:
+      return "module_pre";
+    case MODULE_POST:
+      return "module_post";
+    case GLOBAL_PRE:
+      return "global_pre";
+    case GLOBAL_POST:
+      return "global_post";
+    case FUNCTION_PRE:
+      return "function_pre";
+    case FUNCTION_POST:
+      return "function_post";
+    case BASIC_BLOCK_PRE:
+      return "basic_block_pre";
+    case BASIC_BLOCK_POST:
+      return "basic_block_post";
+    case INSTRUCTION_PRE:
+      return "instruction_pre";
+    case INSTRUCTION_POST:
+      return "instruction_post";
+    case SPECIAL_VALUE:
+      return "special_value";
+    }
+    llvm_unreachable("Invalid kind!");
+  }
+  static KindTy getKindFromStr(StringRef S) {
+    return StringSwitch<KindTy>(S)
+        .Case("module_pre", MODULE_PRE)
+        .Case("module_post", MODULE_POST)
+        .Case("global_pre", GLOBAL_PRE)
+        .Case("global_post", GLOBAL_POST)
+        .Case("function_pre", FUNCTION_PRE)
+        .Case("function_post", FUNCTION_POST)
+        .Case("basic_block_pre", BASIC_BLOCK_PRE)
+        .Case("basic_block_post", BASIC_BLOCK_POST)
+        .Case("instruction_pre", INSTRUCTION_PRE)
+        .Case("instruction_post", INSTRUCTION_POST)
+        .Case("special_value", SPECIAL_VALUE)
+        .Default(Last);
+  }
+
+  static bool isPRE(KindTy Kind) {
+    switch (Kind) {
+    case MODULE_PRE:
+    case GLOBAL_PRE:
+    case FUNCTION_PRE:
+    case BASIC_BLOCK_PRE:
+    case INSTRUCTION_PRE:
+      return true;
+    case MODULE_POST:
+    case GLOBAL_POST:
+    case FUNCTION_POST:
+    case BASIC_BLOCK_POST:
+    case INSTRUCTION_POST:
+    case SPECIAL_VALUE:
+      return false;
+    }
+    llvm_unreachable("Invalid kind!");
+  }
+  bool isPRE() const { return isPRE(Kind); }
+
+  unsigned getOpcode() const {
+    assert((Kind == INSTRUCTION_PRE || Kind == INSTRUCTION_POST) &&
+           "Expected instruction!");
+    return Opcode;
+  }
+
+private:
+  const KindTy Kind;
+  const unsigned Opcode = -1;
+};
+
+struct BaseConfigurationOpportunity {
+  enum KindTy {
+    STRING,
+    BOOLEAN,
+  };
+
+  static BaseConfigurationOpportunity *getBoolOption(InstrumentationConfig &IC,
+                                                     StringRef Name,
+                                                     StringRef Description,
+                                                     bool B);
+  static BaseConfigurationOpportunity *
+  getStringOption(InstrumentationConfig &IC, StringRef Name,
+                  StringRef Description, StringRef Value);
+  union ValueTy {
+    bool B;
+    int64_t I;
+    StringRef S;
+  };
+
+  void setBool(bool B) {
+    assert(Kind == BOOLEAN && "Not a boolean!");
+    V.B = B;
+  }
+  bool getBool() const {
+    assert(Kind == BOOLEAN && "Not a boolean!");
+    return V.B;
+  }
+  void setString(StringRef S) {
+    assert(Kind == STRING && "Not a string!");
+    V.S = S;
+  }
+  StringRef getString() const {
+    assert(Kind == STRING && "Not a string!");
+    return V.S;
+  }
+
+  StringRef Name;
+  StringRef Description;
+  KindTy Kind;
+  ValueTy V = {0};
+};
+
+struct InstrumentorIRBuilderTy;
+struct InstrumentationConfig {
+  virtual ~InstrumentationConfig() {}
+
+  InstrumentationConfig() : SS(StringAllocator) {
+    RuntimePrefix = BaseConfigurationOpportunity::getStringOption(
+        *this, "runtime_prefix", "The runtime API prefix.", "__instrumentor_");
+    TargetRegex = BaseConfigurationOpportunity::getStringOption(
+        *this, "target_regex",
+        "Regular expression to be matched against the module target. "
+        "Only targets that match this regex will be instrumented",
+        "");
+    HostEnabled = BaseConfigurationOpportunity::getBoolOption(
+        *this, "host_enabled", "Instrument non-GPU targets", true);
+    GPUEnabled = BaseConfigurationOpportunity::getBoolOption(
+        *this, "gpu_enabled", "Instrument GPU targets", true);
+  }
+
+  bool ReadConfig = true;
+
+  virtual void populate(InstrumentorIRBuilderTy &IIRB);
+  StringRef getRTName() const { return RuntimePrefix->getString(); }
+
+  std::string getRTName(StringRef Prefix, StringRef Name,
+                        StringRef Suffix1 = "", StringRef Suffix2 = "") const {
+    return (getRTName() + Prefix + Name + Suffix1 + Suffix2).str();
+  }
+
+  void addBaseChoice(BaseConfigurationOpportunity *BCO) {
+    BaseConfigurationOpportunities.push_back(BCO);
+  }
+  SmallVector<BaseConfigurationOpportunity *> BaseConfigurationOpportunities;
+
+  BaseConfigurationOpportunity *RuntimePrefix;
+  BaseConfigurationOpportunity *TargetRegex;
+  BaseConfigurationOpportunity *HostEnabled;
+  BaseConfigurationOpportunity *GPUEnabled;
+
+  EnumeratedArray<StringMap<InstrumentationOpportunity *>,
+                  InstrumentationLocation::KindTy>
+      IChoices;
+  void addChoice(InstrumentationOpportunity &IO);
+
+  template <typename Ty, typename... ArgsTy>
+  static Ty *allocate(ArgsTy &&...Args) {
+    static SpecificBumpPtrAllocator<Ty> Allocator;
+    Ty *Obj = Allocator.Allocate();
+    new (Obj) Ty(std::forward<ArgsTy>(Args)...);
+    return Obj;
+  }
+
+  BumpPtrAllocator StringAllocator;
+  StringSaver SS;
+};
+
+template <typename EnumTy> struct BaseConfigTy {
+  std::bitset<static_cast<int>(EnumTy::NumConfig)> Options;
+
+  BaseConfigTy(bool Enable = true) {
+    if (Enable)
+      Options.set();
+  }
+
+  bool has(EnumTy Opt) const { return Options.test(static_cast<int>(Opt)); }
+  void set(EnumTy Opt, bool Value = true) {
+    Options.set(static_cast<int>(Opt), Value);
+  }
+};
+
+struct InstrumentationOpportunity {
+  InstrumentationOpportunity(const InstrumentationLocation IP) : IP(IP) {}
+  virtual ~InstrumentationOpportunity() {}
+
+  InstrumentationLocation IP;
+
+  SmallVector<IRTArg> IRTArgs;
+  bool Enabled = true;
+
+  /// Helpers to cast values, pass them to the runtime, and replace them. To be
+  /// used as part of the getter/setter of a InstrumentationOpportunity.
+  ///{
+  static Value *forceCast(Value &V, Type &Ty, InstrumentorIRBuilderTy &IIRB);
+  static Value *getValue(Value &V, Type &Ty, InstrumentationConfig &IConf,
+                         InstrumentorIRBuilderTy &IIRB) {
+    return forceCast(V, Ty, IIRB);
+  }
+
+  static Value *replaceValue(Value &V, Value &NewV,
+                             InstrumentationConfig &IConf,
+                             InstrumentorIRBuilderTy &IIRB);
+  ///}
+
+  virtual Value *instrument(Value *&V, InstrumentationConfig &IConf,
+                            InstrumentorIRBuilderTy &IIRB,
+                            InstrumentationCaches &ICaches) {
+    if (CB && !CB(*V))
+      return nullptr;
+
+    const DataLayout &DL = IIRB.IRB.GetInsertBlock()->getDataLayout();
+    IRTCallDescription IRTCallDesc(*this, getRetTy(V->getContext()));
+    auto *CI = IRTCallDesc.createLLVMCall(V, IConf, IIRB, DL, ICaches);
+    return CI;
+  }
+
+  virtual Type *getRetTy(LLVMContext &Ctx) const { return nullptr; }
+  virtual StringRef getName() const = 0;
+
+  unsigned getOpcode() const { return IP.getOpcode(); }
+  InstrumentationLocation::KindTy getLocationKind() const {
+    return IP.getKind();
+  }
+
+  /// An optional callback that takes the value that is about to be
+  /// instrumented and can return false if it should be skipped.
+  using CallbackTy = std::function<bool(Value &)>;
+
+  CallbackTy CB = nullptr;
+
+  static Value *getIdPre(Value &V, Type &Ty, InstrumentationConfig &IConf,
+                         InstrumentorIRBuilderTy &IIRB);
+  static Value *getIdPost(Value &V, Type &Ty, InstrumentationConfig &IConf,
+                          InstrumentorIRBuilderTy &IIRB);
+
+  void addCommonArgs(InstrumentationConfig &IConf, LLVMContext &Ctx,
+                     bool PassId) {
+    const auto CB = IP.isPRE() ? getIdPre : getIdPost;
+    if (PassId)
+      IRTArgs.push_back(
+          IRTArg(IntegerType::getInt32Ty(Ctx), "id",
+                 "A unique ID associated with the given instrumentor call",
+                 IRTArg::NONE, CB, nullptr, true, true));
+  }
+
+  static int32_t getIdFromEpoche(uint32_t Epoche) {
+    static DenseMap<uint32_t, int32_t> EpocheIdMap;
+    static int32_t GlobalId = 0;
+    int32_t &EpochId = EpocheIdMap[Epoche];
+    if (EpochId == 0)
+      EpochId = ++GlobalId;
+    return EpochId;
+  }
+};
+
+template <unsigned Opcode>
+struct InstructionIO : public InstrumentationOpportunity {
+  InstructionIO(bool IsPRE)
+      : InstrumentationOpportunity(InstrumentationLocation(Opcode, IsPRE)) {}
+  virtual ~InstructionIO() {}
+
+  unsigned getOpcode() const { return Opcode; }
+
+  StringRef getName() const override {
+    return Instruction::getOpcodeName(Opcode);
+  }
+};
+
+struct StoreIO : public InstructionIO<Instruction::Store> {
+  StoreIO(bool IsPRE) : InstructionIO(IsPRE) {}
+  virtual ~StoreIO() {};
+
+  enum ConfigKind {
+    PassPointer = 0,
+    ReplacePointer,
+    PassPointerAS,
+    PassStoredValue,
+    PassStoredValueSize,
+    PassAlignment,
+    PassValueTypeId,
+    PassAtomicityOrdering,
+    PassSyncScopeId,
+    PassIsVolatile,
+    PassId,
+    NumConfig,
+  };
+
+  virtual Type *getValueType(LLVMContext &Ctx) const {
+    return IntegerType::getInt64Ty(Ctx);
+  }
+
+  using ConfigTy = BaseConfigTy<ConfigKind>;
+  ConfigTy Config;
+
+  void init(InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB,
+            ConfigTy *UserConfig = nullptr) {
+    if (UserConfig)
+      Config = *UserConfig;
+
+    bool IsPRE = getLocationKind() == InstrumentationLocation::INSTRUCTION_PRE;
+    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(PassStoredValue))
+      IRTArgs.push_back(
+          IRTArg(getValueType(IIRB.Ctx), "value", "The stored value.",
+                 IRTArg::POTENTIALLY_INDIRECT | (Config.has(PassStoredValueSize)
+                                                     ? IRTArg::INDIRECT_HAS_SIZE
+                                                     : IRTArg::NONE),
+                 getValue));
+    if (Config.has(PassStoredValueSize))
+      IRTArgs.push_back(IRTArg(IIRB.Int64Ty, "value_size",
+                               "The size of the stored 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 stored value.", IRTArg::NONE,
+                               getValueTypeId));
+    if (Config.has(PassAtomicityOrdering))
+      IRTArgs.push_back(IRTArg(IIRB.Int32Ty, "atomicity_ordering",
+                               "The atomicity ordering of the store.",
+                               IRTArg::NONE, getAtomicityOrdering));
+    if (Config.has(PassSyncScopeId))
+      IRTArgs.push_back(IRTArg(IIRB.Int8Ty, "sync_scope_id",
+                               "The sync scope id of the store.", IRTArg::NONE,
+                               getSyncScopeId));
+    if (Config.has(PassIsVolatile))
+      IRTArgs.push_back(IRTArg(IIRB.Int8Ty, "is_volatile",
+                               "Flag indicating a volatile store.",
+                               IRTArg::NONE, isVolatile));
+
+    addCommonArgs(IConf, IIRB.Ctx, Config.has(PassId));
+    IConf.addChoice(*this);
+  }
+
+  static Value *getPointer(Value &V, Type &Ty, InstrumentationConfig &IConf,
+                           InstrumentorIRBuilderTy &IIRB);
+  static Value *setPointer(Value &V, Value &NewV, InstrumentationConfig &IConf,
+                           InstrumentorIRBuilderTy &IIRB);
+  static Value *getPointerAS(Value &V, Type &Ty, InstrumentationConfig &IConf,
+                             InstrumentorIRBuilderTy &IIRB);
+  static Value *getValue(Value &V, Type &Ty, InstrumentationConfig &IConf,
+                         InstrumentorIRBuilderTy &IIRB);
+  static Value *getValueSize(Value &V, Type &Ty, InstrumentationConfig &IConf,
+                             InstrumentorIRBuilderTy &IIRB);
+  static Value *getAlignment(Value &V, Type &Ty, InstrumentationConfig &IConf,
+                             In...
[truncated]

``````````

</details>


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


More information about the llvm-commits mailing list