[llvm] [Instrumentor] A configurable instrumentation pass (PR #119038)

via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 6 14:48:01 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Johannes Doerfert (jdoerfert)

<details>
<summary>Changes</summary>

Both internally and externally we instrument code all the time. Usually, those are hand written traversals that look for some specific instructions or program points and then provide information to a runtime. Since the real difference is in the runtime, and the instrumentation is basically always the same, people can use this Instrumentor pass and configure it to their needs.

Initial implementation only instruments alloca instructions but shows the setup, and configurability via a JSON file.

---

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


11 Files Affected:

- (added) llvm/include/llvm/Transforms/Instrumentation/Instrumentor.h (+56) 
- (added) llvm/include/llvm/Transforms/Instrumentation/InstrumentorConfig.def (+56) 
- (modified) llvm/lib/Passes/PassBuilder.cpp (+1) 
- (modified) llvm/lib/Passes/PassRegistry.def (+1) 
- (modified) llvm/lib/Transforms/Instrumentation/CMakeLists.txt (+1) 
- (added) llvm/lib/Transforms/Instrumentation/Instrumentor.cpp (+343) 
- (added) llvm/test/Instrumentation/Instrumentor/alloca.ll (+62) 
- (added) llvm/test/Instrumentation/Instrumentor/default_config.json (+13) 
- (added) llvm/test/Instrumentation/Instrumentor/just_calls_config.json (+14) 
- (added) llvm/test/Instrumentation/Instrumentor/read_config.ll (+22) 
- (added) llvm/test/Instrumentation/Instrumentor/write_config.ll (+3) 


``````````diff
diff --git a/llvm/include/llvm/Transforms/Instrumentation/Instrumentor.h b/llvm/include/llvm/Transforms/Instrumentation/Instrumentor.h
new file mode 100644
index 00000000000000..0da4562be6a7a7
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Instrumentation/Instrumentor.h
@@ -0,0 +1,56 @@
+//===- Transforms/Instrumentation/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_INSTRUMENTATION_INSTRUMENTOR_H
+#define LLVM_TRANSFORMS_INSTRUMENTATION_INSTRUMENTOR_H
+
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/PassManager.h"
+
+#include <functional>
+
+namespace llvm {
+
+/// Configuration for the Instrumentor. First generic configuration, followed by
+/// the selection of what instruction classes and instructions should be
+/// instrumented and how.
+struct InstrumentorConfig {
+
+  /// An optional callback that takes the instruction that is about to be
+  /// instrumented and can return false if it should be skipped.
+  using CallbackTy = std::function<bool(Instruction &)>;
+
+#define SECTION_START(SECTION, CLASS) struct {
+
+#define CONFIG_INTERNAL(SECTION, TYPE, NAME, DEFAULT_VALUE)                    \
+  TYPE NAME = DEFAULT_VALUE;
+
+#define CONFIG(SECTION, TYPE, NAME, DEFAULT_VALUE) TYPE NAME = DEFAULT_VALUE;
+
+#define SECTION_END(SECTION)                                                   \
+  }                                                                            \
+  SECTION;
+
+#include "llvm/Transforms/Instrumentation/InstrumentorConfig.def"
+};
+
+class InstrumentorPass : public PassInfoMixin<InstrumentorPass> {
+  InstrumentorConfig IC;
+
+public:
+  InstrumentorPass(InstrumentorConfig IC = InstrumentorConfig{}) : IC(IC) {}
+
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+};
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_INSTRUMENTATION_INSTRUMENTOR_H
diff --git a/llvm/include/llvm/Transforms/Instrumentation/InstrumentorConfig.def b/llvm/include/llvm/Transforms/Instrumentation/InstrumentorConfig.def
new file mode 100644
index 00000000000000..1d45919608b322
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Instrumentation/InstrumentorConfig.def
@@ -0,0 +1,56 @@
+//===- Transforms/Instrumentation/InstrumentorConfig.def ------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+// No include guards
+
+/// Base configuration
+///{
+SECTION_START(Base, )
+
+/// The base name which defines the runtime call names, i.a.,
+/// <BaseName><instruction/location>(...)
+CONFIG(Base, std::string, RuntimeName, "__instrumentor_")
+
+/// Print the signatures of all used runtime functions.
+CONFIG(Base, bool, PrintRuntimeSignatures, true)
+
+SECTION_END(Base)
+///}
+
+/// AllocaInst
+///{
+SECTION_START(Alloca, AllocaInst)
+
+/// Should allocas be instrumented.
+CONFIG(Alloca, bool, Instrument, true)
+
+/// Selection of information passed to the runtime.
+///{
+/// The actual allocated pointer.
+CONFIG(Alloca, bool, Value, /*        PtrTy */ true)
+/// The size of the entire allocation.
+CONFIG(Alloca, bool, AllocationSize, /* I64 */ true)
+/// The minimal alignment requested statically.
+CONFIG(Alloca, bool, Alignment, /*      I64 */ true)
+///}
+
+/// Should the value be replaced by the runtime call result.
+CONFIG(Alloca, bool, ReplaceValue, true)
+
+/// Optional callback, see CallbackTy.
+CONFIG_INTERNAL(Alloca, CallbackTy, CB, nullptr)
+
+SECTION_END(Alloca)
+///}
+
+#undef SECTION_START
+#undef CONFIG
+#undef CONFIG_INTERNAL
+#undef SECTION_END
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 260a34f2e060d6..3997275075e87e 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -211,6 +211,7 @@
 #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
 #include "llvm/Transforms/Instrumentation/InstrOrderFile.h"
 #include "llvm/Transforms/Instrumentation/InstrProfiling.h"
+#include "llvm/Transforms/Instrumentation/Instrumentor.h"
 #include "llvm/Transforms/Instrumentation/KCFI.h"
 #include "llvm/Transforms/Instrumentation/LowerAllowCheckPass.h"
 #include "llvm/Transforms/Instrumentation/MemProfiler.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 772ec5fd10e633..268fe1f7c0ab32 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -91,6 +91,7 @@ MODULE_PASS("instrprof", InstrProfilingLoweringPass())
 MODULE_PASS("ctx-instr-lower", PGOCtxProfLoweringPass())
 MODULE_PASS("print<ctx-prof-analysis>", CtxProfAnalysisPrinterPass(errs()))
 MODULE_PASS("invalidate<all>", InvalidateAllAnalysesPass())
+MODULE_PASS("instrumentor", InstrumentorPass())
 MODULE_PASS("iroutliner", IROutlinerPass())
 MODULE_PASS("jmc-instrumenter", JMCInstrumenterPass())
 MODULE_PASS("lower-emutls", LowerEmuTLSPass())
diff --git a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
index 3e3c3eced4bb9c..279aff368d0712 100644
--- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
+++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
@@ -12,6 +12,7 @@ add_llvm_component_library(LLVMInstrumentation
   IndirectCallPromotion.cpp
   InstrOrderFile.cpp
   InstrProfiling.cpp
+  Instrumentor.cpp
   KCFI.cpp
   LowerAllowCheckPass.cpp
   PGOCtxProfFlattening.cpp
diff --git a/llvm/lib/Transforms/Instrumentation/Instrumentor.cpp b/llvm/lib/Transforms/Instrumentation/Instrumentor.cpp
new file mode 100644
index 00000000000000..2bdeb2d7dcd79c
--- /dev/null
+++ b/llvm/lib/Transforms/Instrumentation/Instrumentor.cpp
@@ -0,0 +1,343 @@
+//===-- Instrumentor.cpp - Highly configurable instrumentation pass -------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Instrumentation/Instrumentor.h"
+
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/ConstantFolder.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <type_traits>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "instrumentor"
+
+cl::opt<std::string> WriteJSONConfig(
+    "instrumentor-write-config-file",
+    cl::desc(
+        "Write the instrumentor configuration into the specified JSON file"),
+    cl::init(""));
+cl::opt<std::string> ReadJSONConfig(
+    "instrumentor-read-config-file",
+    cl::desc(
+        "Read the instrumentor configuration from the specified JSON file"),
+    cl::init(""));
+
+namespace {
+
+template <typename... Targs>
+void dumpObject(json::OStream &J, Targs... Fargs) {}
+
+void writeInstrumentorConfig(InstrumentorConfig &IC) {
+  if (WriteJSONConfig.empty())
+    return;
+
+  std::error_code EC;
+  raw_fd_stream OS(WriteJSONConfig, EC);
+  if (EC) {
+    errs() << "WARNING: Failed to open instrumentor configuration file for "
+              "writing: "
+           << EC.message() << "\n";
+    return;
+  }
+
+  json::OStream J(OS, 2);
+  J.objectBegin();
+
+#define SECTION_START(SECTION, CLASS)                                          \
+  J.attributeBegin(#SECTION);                                                  \
+  J.objectBegin();
+#define CONFIG_INTERNAL(SECTION, TYPE, NAME, DEFAULT_VALUE)
+#define CONFIG(SECTION, TYPE, NAME, DEFAULT_VALUE)                             \
+  J.attribute(#NAME, IC.SECTION.NAME);
+#define SECTION_END(SECTION)                                                   \
+  J.objectEnd();                                                               \
+  J.attributeEnd();
+
+#include "llvm/Transforms/Instrumentation/InstrumentorConfig.def"
+
+  J.objectEnd();
+}
+
+bool readInstrumentorConfigFromJSON(InstrumentorConfig &IC) {
+  if (ReadJSONConfig.empty())
+    return true;
+
+  std::error_code EC;
+  auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(ReadJSONConfig);
+  if (std::error_code EC = BufferOrErr.getError()) {
+    errs() << "WARNING: Failed to open instrumentor configuration file for "
+              "reading: "
+           << EC.message() << "\n";
+    return false;
+  }
+  auto Buffer = std::move(BufferOrErr.get());
+  json::Path::Root NullRoot;
+  auto Parsed = json::parse(Buffer->getBuffer());
+  if (!Parsed) {
+    errs() << "WARNING: Failed to parse the instrumentor configuration file: "
+           << Parsed.takeError() << "\n";
+    return false;
+  }
+  auto *Config = Parsed->getAsObject();
+  if (!Config) {
+    errs() << "WARNING: Failed to parse the instrumentor configuration file: "
+              "Expected "
+              "an object '{ ... }'\n";
+    return false;
+  }
+
+  auto End = Config->end(), It = Config->begin();
+
+#define CONFIG(SECTION, TYPE, NAME, DEFAULT_VALUE)                             \
+  It = Config->find(#SECTION);                                                 \
+  if (It != End) {                                                             \
+    if (auto *InstObj = It->second.getAsObject()) {                            \
+      if (auto *Val = InstObj->get(#NAME)) {                                   \
+        if (!json::fromJSON(*Val, IC.SECTION.NAME, NullRoot))                  \
+          errs() << "WARNING: Failed to read " #SECTION "." #NAME " as " #TYPE \
+                 << "\n";                                                      \
+      }                                                                        \
+    }                                                                          \
+  }
+
+#define SECTION_START(SECTION, CLASS)
+#define CONFIG_INTERNAL(SECTION, TYPE, NAME, DEFAULT_VALUE)
+#define SECTION_END(SECTION)
+
+#include "llvm/Transforms/Instrumentation/InstrumentorConfig.def"
+
+  return true;
+}
+
+raw_ostream &printAsCType(raw_ostream &OS, Type *T) {
+  if (T->isPointerTy())
+    return OS << "void* ";
+  if (T->isIntegerTy())
+    return OS << "int" << T->getIntegerBitWidth() << "_t ";
+  return OS << *T << " ";
+}
+
+class InstrumentorImpl final {
+public:
+  InstrumentorImpl(const InstrumentorConfig &IC, Module &M)
+      : IC(IC), M(M), Ctx(M.getContext()),
+        IRB(Ctx, ConstantFolder(),
+            IRBuilderCallbackInserter(
+                [&](Instruction *I) { NewInst[I] = Epoche; })) {}
+
+  /// Instrument the module, public entry point.
+  bool instrument();
+
+private:
+  bool shouldInstrumentFunction(Function *Fn);
+  bool instrumentFunction(Function &Fn);
+  bool instrument(AllocaInst &I);
+
+  template <typename Ty> Constant *getCI(Type *IT, Ty Val) {
+    return ConstantInt::get(IT, Val);
+  }
+
+  std::string getRTName(StringRef Suffix) {
+    return (IC.Base.RuntimeName + Suffix).str();
+  }
+
+  DenseMap<unsigned, FunctionCallee> InstrumentationFunctions;
+  FunctionCallee getCallee(Instruction &I, SmallVectorImpl<Type *> &RTArgTypes,
+                           SmallVectorImpl<std::string> &RTArgNames,
+                           Type *RT = nullptr) {
+    FunctionCallee &FC = InstrumentationFunctions[I.getOpcode()];
+    if (!FC.getFunctionType()) {
+      FC = M.getOrInsertFunction(
+          getRTName(I.getOpcodeName()),
+          FunctionType::get(RT ? RT : VoidTy, RTArgTypes, /*IsVarArgs*/ false));
+
+      if (IC.Base.PrintRuntimeSignatures) {
+        printAsCType(outs(), FC.getFunctionType()->getReturnType());
+        outs() << FC.getCallee()->getName() << "(";
+        auto *FT = FC.getFunctionType();
+        for (int I = 0, E = RTArgNames.size(); I != E; ++I) {
+          if (I != 0)
+            outs() << ", ";
+          printAsCType(outs(), FT->getParamType(I)) << RTArgNames[I];
+        }
+        outs() << ");\n";
+      }
+    }
+    return FC;
+  }
+
+  /// 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> NewInst;
+
+  /// The instrumentor configuration.
+  const InstrumentorConfig &IC;
+
+  /// The module and the LLVM context.
+  Module &M;
+  LLVMContext &Ctx;
+
+  /// A special IR builder that keeps track of the inserted instructions.
+  IRBuilder<ConstantFolder, IRBuilderCallbackInserter> IRB;
+
+  /// Commonly used values for IR inspection and creation.
+  ///{
+
+  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);
+  ///}
+};
+
+} // end anonymous namespace
+
+bool InstrumentorImpl::shouldInstrumentFunction(Function *Fn) {
+  if (!Fn || Fn->isDeclaration())
+    return false;
+  return true;
+}
+
+bool InstrumentorImpl::instrument(AllocaInst &I) {
+  if (IC.Alloca.CB && !IC.Alloca.CB(I))
+    return false;
+
+  Instruction *IP = I.getNextNonDebugInstruction();
+  while (isa<AllocaInst>(IP))
+    IP = IP->getNextNonDebugInstruction();
+  IRB.SetInsertPoint(IP);
+
+  SmallVector<Type *> RTArgTypes;
+  SmallVector<Value *> RTArgs;
+  SmallVector<std::string> RTArgNames;
+
+  if (IC.Alloca.Value) {
+    auto *ArgTy = PtrTy;
+    RTArgTypes.push_back(ArgTy);
+    RTArgs.push_back(IRB.CreatePointerBitCastOrAddrSpaceCast(&I, ArgTy));
+    RTArgNames.push_back("Value");
+  }
+
+  if (IC.Alloca.AllocationSize) {
+    auto *ArgTy = Int64Ty;
+    RTArgTypes.push_back(ArgTy);
+    Value *SizeValue = nullptr;
+    TypeSize TypeSize = DL.getTypeAllocSize(I.getAllocatedType());
+    if (TypeSize.isFixed())
+      SizeValue = getCI(ArgTy, TypeSize.getFixedValue());
+    if (!SizeValue) {
+      SizeValue = IRB.CreateSub(
+          IRB.CreatePtrToInt(
+              IRB.CreateGEP(I.getAllocatedType(), &I, {getCI(Int32Ty, 1)}),
+              ArgTy),
+          IRB.CreatePtrToInt(&I, ArgTy));
+    }
+    if (I.isArrayAllocation())
+      SizeValue = IRB.CreateMul(
+          SizeValue, IRB.CreateZExtOrBitCast(I.getArraySize(), ArgTy));
+    RTArgs.push_back(SizeValue);
+    RTArgNames.push_back("AllocationSize");
+  }
+
+  if (IC.Alloca.Alignment) {
+    auto *ArgTy = Int64Ty;
+    RTArgTypes.push_back(ArgTy);
+    RTArgs.push_back(getCI(ArgTy, I.getAlign().value()));
+    RTArgNames.push_back("Alignment");
+  }
+
+  Type *RetTy = IC.Alloca.ReplaceValue ? PtrTy : nullptr;
+  FunctionCallee FC = getCallee(I, RTArgTypes, RTArgNames, RetTy);
+  auto *CI = IRB.CreateCall(FC, RTArgs);
+  if (IC.Alloca.ReplaceValue)
+    I.replaceUsesWithIf(
+        IRB.CreatePointerBitCastOrAddrSpaceCast(CI, I.getType()), [&](Use &U) {
+          return NewInst.lookup(cast<Instruction>(U.getUser())) != Epoche;
+        });
+
+  return true;
+}
+
+bool InstrumentorImpl::instrumentFunction(Function &Fn) {
+  bool Changed = false;
+  if (!shouldInstrumentFunction(&Fn))
+    return Changed;
+
+  ReversePostOrderTraversal<Function *> RPOT(&Fn);
+  for (auto &It : RPOT) {
+    for (auto &I : *It) {
+      // Skip instrumentation instructions.
+      if (NewInst.contains(&I))
+        continue;
+
+      // Count epochs eagerly.
+      ++Epoche;
+
+      switch (I.getOpcode()) {
+      case Instruction::Alloca:
+        if (IC.Alloca.Instrument)
+          instrument(cast<AllocaInst>(I));
+        break;
+      default:
+        break;
+      }
+    }
+  }
+
+  return Changed;
+}
+
+bool InstrumentorImpl::instrument() {
+  bool Changed = false;
+
+  for (Function &Fn : M)
+    Changed |= instrumentFunction(Fn);
+
+  return Changed;
+}
+
+PreservedAnalyses InstrumentorPass::run(Module &M, ModuleAnalysisManager &MAM) {
+  InstrumentorImpl Impl(IC, M);
+  if (!readInstrumentorConfigFromJSON(IC))
+    return PreservedAnalyses::all();
+  writeInstrumentorConfig(IC);
+  if (!Impl.instrument())
+    return PreservedAnalyses::all();
+  assert(!verifyModule(M, &errs()));
+  return PreservedAnalyses::none();
+}
diff --git a/llvm/test/Instrumentation/Instrumentor/alloca.ll b/llvm/test/Instrumentation/Instrumentor/alloca.ll
new file mode 100644
index 00000000000000..aa337b189aaf97
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/alloca.ll
@@ -0,0 +1,62 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instrumentor -S | FileCheck %s
+
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+define ptr @foo() {
+; CHECK-LABEL: define ptr @foo() {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[A:%.*]] = alloca ptr, align 8
+; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__instrumentor_alloca(ptr [[A]], i64 8, i64 8)
+; CHECK-NEXT:    ret ptr [[TMP0]]
+;
+entry:
+  %a = alloca ptr
+  ret ptr %a
+}
+define ptr @bar(i1 %c) {
+; CHECK-LABEL: define ptr @bar(
+; CHECK-SAME: i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, i32 5, align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__instrumentor_alloca(ptr [[B]], i64 20, i64 4)
+; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @__instrumentor_alloca(ptr [[A]], i64 4, i64 4)
+; CHECK-NEXT:    [[S:%.*]] = select i1 [[C]], ptr [[TMP1]], ptr [[TMP0]]
+; CHECK-NEXT:    ret ptr [[S]]
+;
+entry:
+  %a = alloca i32
+  %b = alloca i32, i32 5
+  %s = select i1 %c, ptr %a, ptr %b
+  ret ptr %s
+}
+define ptr @baz(i32 %v) {
+; CHECK-LABEL: define ptr @baz(
+; CHECK-SAME: i32 [[V:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[A:%.*]] = alloca ptr, i32 [[V]], align 8
+; CHECK-NEXT:    [[TMP0:%.*]] = zext i32 [[V]] to i64
+; CHECK-NEXT:    [[TMP2:%.*]] = mul i64 8, [[TMP0]]
+; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @__instrumentor_alloca(ptr [[A]], i64 [[TMP2]], i64 8)
+; CHECK-NEXT:    ret ptr [[TMP1]]
+;
+entry:
+  %a = alloca ptr, i32 %v
+  ret ptr %a
+}
+define ptr @fizz() {
+; CHECK-LABEL: define ptr @fizz() {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[A:%.*]] = alloca <vscale x 2 x i32>, align 8
+; CHECK-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[A]] to i64
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr <vscale x 2 x i32>, ptr [[A]], i32 1
+; CHECK-NEXT:    [[TMP2:%.*]] = ptrtoint ptr [[TMP1]] to i64
+; CHECK-NEXT:    [[TMP3:%.*]] = sub i64 [[TMP2]], [[TMP0]]
+; CHECK-NEXT:    [[TMP4:%.*]] = call ptr @__instrumentor_alloca(ptr [[A]], i64 [[TMP3]], i64 8)
+; CHECK-NEXT:    ret ptr [[TMP4]]
+;
+entry:
+  %a = alloca <vscale x 2 x i32>
+  ret ptr %a
+}
diff --git a/llvm/test/Instrumentation/Instrumentor/default_config.json b/llvm/test/Instrumentation/Instrumentor/default_config.json
new file mode 100644
index 00000000000000..587931254a0496
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/default_config.json
@@ -0,0 +1,13 @@
+{
+  "Base": {
+    "RuntimeNam...
[truncated]

``````````

</details>


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


More information about the llvm-commits mailing list