[llvm] f0655b0 - [llvm-exegesis] Add memory annotation parsing

Aiden Grossman via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 26 22:31:45 PDT 2023


Author: Aiden Grossman
Date: 2023-06-27T05:30:54Z
New Revision: f0655b0d06129330f710b3cb9955cec7e778bfd0

URL: https://github.com/llvm/llvm-project/commit/f0655b0d06129330f710b3cb9955cec7e778bfd0
DIFF: https://github.com/llvm/llvm-project/commit/f0655b0d06129330f710b3cb9955cec7e778bfd0.diff

LOG: [llvm-exegesis] Add memory annotation parsing

This patch adds memory annotation parsing to llvm-exegesis. The memory
annotations cannot be used currently, but this allows for using parsed
memory annotations within a FunctionExecutorImpl to set up a specified
execution environment.

Added: 
    llvm/test/tools/llvm-exegesis/X86/latency/memory-annotations-unsupported.s

Modified: 
    llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
    llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
    llvm/tools/llvm-exegesis/lib/SnippetFile.h
    llvm/tools/llvm-exegesis/llvm-exegesis.cpp
    llvm/unittests/tools/llvm-exegesis/X86/SnippetFileTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-exegesis/X86/latency/memory-annotations-unsupported.s b/llvm/test/tools/llvm-exegesis/X86/latency/memory-annotations-unsupported.s
new file mode 100644
index 0000000000000..5d06a0ceff5c7
--- /dev/null
+++ b/llvm/test/tools/llvm-exegesis/X86/latency/memory-annotations-unsupported.s
@@ -0,0 +1,9 @@
+# REQUIRES: exegesis-can-measure-latency, x86_64-linux
+
+# RUN: not llvm-exegesis -mtriple=x86_64-unknown-unknown -snippets-file=%s -mode=latency 2>&1 | FileCheck %s
+
+# CHECK: llvm-exegesis error: Memory annotations are only supported in subprocess execution mode
+
+# LLVM-EXEGESIS-MEM-DEF test1 4096 ff
+
+movq $0, %rax

diff  --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
index eb3b839ea09fb..77e0994fe0208 100644
--- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
+++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
@@ -64,6 +64,11 @@ struct BenchmarkKey {
   std::vector<MCInst> Instructions;
   // The initial values of the registers.
   std::vector<RegisterValue> RegisterInitialValues;
+  // The memory values that can be mapped into the execution context of the
+  // snippet.
+  std::unordered_map<std::string, MemoryValue> MemoryValues;
+  // The memory mappings that the snippet can access.
+  std::vector<MemoryMapping> MemoryMappings;
   // An opaque configuration, that can be used to separate several benchmarks of
   // the same instruction under 
diff erent configurations.
   std::string Config;

diff  --git a/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp b/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
index 0b69a79b02cc7..d85a9f190655a 100644
--- a/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "SnippetFile.h"
+#include "BenchmarkRunner.h"
 #include "Error.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCInstPrinter.h"
@@ -82,6 +83,54 @@ class BenchmarkCodeStreamer : public MCStreamer, public AsmCommentConsumer {
       }
       return;
     }
+    if (CommentText.consume_front("MEM-DEF")) {
+      // LLVM-EXEGESIS-MEM-DEF <name> <size> <value>
+      SmallVector<StringRef, 3> Parts;
+      CommentText.split(Parts, ' ', -1, false);
+      if (Parts.size() != 3) {
+        errs() << "invalid comment 'LLVM-EXEGESIS-MEM-DEF " << CommentText
+               << "', expected three parameters <NAME> <SIZE> <VALUE>";
+        ++InvalidComments;
+        return;
+      }
+      const StringRef HexValue = Parts[2].trim();
+      MemoryValue MemVal;
+      MemVal.SizeBytes = std::stol(Parts[1].trim().str());
+      if (HexValue.size() % 2 != 0) {
+        errs() << "invalid comment 'LLVM-EXEGESIS-MEM-DEF " << CommentText
+               << "', expected <VALUE> to contain a whole number of bytes";
+      }
+      MemVal.Value = APInt(HexValue.size() * 4, HexValue, 16);
+      MemVal.Index = Result->Key.MemoryValues.size();
+      Result->Key.MemoryValues[Parts[0].trim().str()] = MemVal;
+      return;
+    }
+    if (CommentText.consume_front("MEM-MAP")) {
+      // LLVM-EXEGESIS-MEM-MAP <value name> <address>
+      SmallVector<StringRef, 2> Parts;
+      CommentText.split(Parts, ' ', -1, false);
+      if (Parts.size() != 2) {
+        errs() << "invalid comment 'LLVM-EXEGESIS-MEM-MAP " << CommentText
+               << "', expected two parameters <VALUE NAME> <ADDRESS>";
+        ++InvalidComments;
+        return;
+      }
+      MemoryMapping MemMap;
+      MemMap.MemoryValueName = Parts[0].trim().str();
+      MemMap.Address = std::stol(Parts[1].trim().str());
+      // validate that the annotation refers to an already existing memory
+      // definition
+      auto MemValIT = Result->Key.MemoryValues.find(Parts[0].trim().str());
+      if (MemValIT == Result->Key.MemoryValues.end()) {
+        errs() << "invalid comment 'LLVM-EXEGESIS-MEM-MAP " << CommentText
+               << "', expected <VALUE NAME> to contain the name of an already "
+                  "specified memory definition";
+        ++InvalidComments;
+        return;
+      }
+      Result->Key.MemoryMappings.push_back(std::move(MemMap));
+      return;
+    }
   }
 
   unsigned numInvalidComments() const { return InvalidComments; }

diff  --git a/llvm/tools/llvm-exegesis/lib/SnippetFile.h b/llvm/tools/llvm-exegesis/lib/SnippetFile.h
index c346a047bf41f..74f918d0e60f4 100644
--- a/llvm/tools/llvm-exegesis/lib/SnippetFile.h
+++ b/llvm/tools/llvm-exegesis/lib/SnippetFile.h
@@ -17,6 +17,7 @@
 #define LLVM_TOOLS_LLVM_EXEGESIS_SNIPPETFILE_H
 
 #include "BenchmarkCode.h"
+#include "BenchmarkRunner.h"
 #include "LlvmState.h"
 #include "llvm/Support/Error.h"
 

diff  --git a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
index 82df07c6a83bb..ff868e756338a 100644
--- a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
+++ b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp
@@ -15,6 +15,7 @@
 #include "lib/BenchmarkResult.h"
 #include "lib/BenchmarkRunner.h"
 #include "lib/Clustering.h"
+#include "lib/CodeTemplate.h"
 #include "lib/Error.h"
 #include "lib/LlvmState.h"
 #include "lib/PerfHelper.h"
@@ -521,6 +522,13 @@ void benchmarkMain() {
     }
   } else {
     Configurations = ExitOnErr(readSnippets(State, SnippetsFile));
+    for (const auto &Configuration : Configurations) {
+      if (ExecutionMode != BenchmarkRunner::ExecutionModeE::SubProcess &&
+          (Configuration.Key.MemoryMappings.size() != 0 ||
+           Configuration.Key.MemoryValues.size() != 0))
+        ExitWithError("Memory annotations are only supported in subprocess "
+                      "execution mode");
+    }
   }
 
   if (NumRepetitions == 0) {

diff  --git a/llvm/unittests/tools/llvm-exegesis/X86/SnippetFileTest.cpp b/llvm/unittests/tools/llvm-exegesis/X86/SnippetFileTest.cpp
index b868b696c0114..c754d60de3dda 100644
--- a/llvm/unittests/tools/llvm-exegesis/X86/SnippetFileTest.cpp
+++ b/llvm/unittests/tools/llvm-exegesis/X86/SnippetFileTest.cpp
@@ -34,6 +34,7 @@ using testing::Eq;
 using testing::Field;
 using testing::Property;
 using testing::SizeIs;
+using testing::UnorderedElementsAre;
 
 using llvm::unittest::TempDir;
 
@@ -69,6 +70,27 @@ MATCHER_P2(RegisterInitialValueIs, Reg, Val, "") {
   return false;
 }
 
+MATCHER_P3(MemoryDefinitionIs, Name, Value, Size, "") {
+  if (arg.second.Value.getLimitedValue() == static_cast<uint64_t>(Value) &&
+      arg.second.SizeBytes == static_cast<size_t>(Size) && arg.first == Name)
+    return true;
+  *result_listener << "expected: {" << Name << ", " << Value << ", " << Size
+                   << "} ";
+  *result_listener << "actual: {" << arg.first << ", "
+                   << arg.second.Value.getLimitedValue() << ", "
+                   << arg.second.SizeBytes << "}";
+  return false;
+}
+
+MATCHER_P2(MemoryMappingIs, Address, Name, "") {
+  if (arg.Address == Address && arg.MemoryValueName == Name)
+    return true;
+  *result_listener << "expected: {" << Address << ", " << Name << "} ";
+  *result_listener << "actual: {" << arg.Address << ", " << arg.MemoryValueName
+                   << "}";
+  return false;
+}
+
 TEST_F(X86SnippetFileTest, Works) {
   auto Snippets = TestCommon(R"(
     # LLVM-EXEGESIS-DEFREG RAX 0f
@@ -124,6 +146,80 @@ TEST_F(X86SnippetFileTest, NoAsmStreamer) {
   EXPECT_FALSE((bool)Snippets.takeError());
 }
 
+TEST_F(X86SnippetFileTest, MemoryDefinitionTestSingleDef) {
+  auto Snippets = TestCommon(R"(
+    # LLVM-EXEGESIS-MEM-DEF test1 4096 ff
+    # LLVM-EXEGESIS-MEM-MAP test1 8192
+    # LLVM-EXEGESIS-MEM-MAP test1 16384
+    movq $8192, %r10
+    movq (%r10), %r11
+  )");
+  EXPECT_FALSE((bool)Snippets.takeError());
+  ASSERT_THAT(*Snippets, SizeIs(1));
+  const auto &Snippet = (*Snippets)[0];
+  ASSERT_THAT(Snippet.Key.MemoryValues,
+              UnorderedElementsAre(MemoryDefinitionIs("test1", 255, 4096)));
+  ASSERT_THAT(Snippet.Key.MemoryMappings,
+              ElementsAre(MemoryMappingIs(8192, "test1"),
+                          MemoryMappingIs(16384, "test1")));
+}
+
+TEST_F(X86SnippetFileTest, MemoryDefinitionsTestTwoDef) {
+  auto Snippets = TestCommon(R"(
+    # LLVM-EXEGESIS-MEM-DEF test1 4096 ff
+    # LLVM-EXEGESIS-MEM-DEF test2 4096 100
+    # LLVM-EXEGESIS-MEM-MAP test1 8192
+    # LLVM-EXEGESIS-MEM-MAP test2 16384
+    movq $8192, %r10
+    movq (%r10), %r11
+  )");
+  EXPECT_FALSE((bool)Snippets.takeError());
+  ASSERT_THAT(*Snippets, SizeIs(1));
+  const auto &Snippet = (*Snippets)[0];
+  ASSERT_THAT(Snippet.Key.MemoryValues,
+              UnorderedElementsAre(MemoryDefinitionIs("test1", 255, 4096),
+                                   MemoryDefinitionIs("test2", 256, 4096)));
+  ASSERT_THAT(Snippet.Key.MemoryMappings,
+              ElementsAre(MemoryMappingIs(8192, "test1"),
+                          MemoryMappingIs(16384, "test2")));
+}
+
+TEST_F(X86SnippetFileTest, MemoryDefinitionMissingParameter) {
+  auto Error = TestCommon(R"(
+    # LLVM-EXEGESIS-MEM-DEF test1 4096
+  )")
+                   .takeError();
+  EXPECT_TRUE((bool)Error);
+  consumeError(std::move(Error));
+}
+
+TEST_F(X86SnippetFileTest, MemoryMappingMissingParameters) {
+  auto Error = TestCommon(R"(
+    # LLVM-EXEGESIS-MEM-MAP test1
+  )")
+                   .takeError();
+  EXPECT_TRUE((bool)Error);
+  consumeError(std::move(Error));
+}
+
+TEST_F(X86SnippetFileTest, MemoryMappingNoDefinition) {
+  auto Error = TestCommon(R"(
+    # LLVM-EXEGESIS-MEM-MAP test1 4096
+  )")
+                   .takeError();
+  EXPECT_TRUE((bool)Error);
+  consumeError(std::move(Error));
+}
+
+TEST_F(X86SnippetFileTest, IncompatibleExecutorMode) {
+  auto Error = TestCommon(R"(
+    # LLVM-EXEGESIS-MEM-MAP test1 4096
+  )")
+                   .takeError();
+  EXPECT_TRUE((bool)Error);
+  consumeError(std::move(Error));
+}
+
 } // namespace
 } // namespace exegesis
 } // namespace llvm


        


More information about the llvm-commits mailing list