[llvm] [msan] Add debugging for handleUnknownIntrinsic (PR #123381)

Thurston Dang via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 17 10:06:23 PST 2025


https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/123381

>From f3a6f2f2e8306ce97d836a88e8981eb1c8b46c7c Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Fri, 17 Jan 2025 04:51:07 +0000
Subject: [PATCH 1/2] [msan] Add debugging for handleUnknownIntrinsic

This adds an experimental flag, msan-dump-strict-intrinsics (modeled
after msan-dump-strict-instructions), which prints out any intrinsics
that are heuristically handled. Additionally, MSan will print out heuristically
handled intrinsics when -debug is passed as a flag in debug builds.

MSan's intrinsic handling can be broken down into:
1) special cases (usually highly accurate)
2) heuristic handling (sometimes erroneous)
3) not handled

This patch's -msan-dump-strict-intrinsics can help debug Case 2.
Case 3) (which includes all the heuristics that are not handled by
special cases nor heuristics) can be debugged using the existing -msan-dump-strict-instructions.
---
 .../Instrumentation/MemorySanitizer.cpp       | 36 ++++++++++++-------
 1 file changed, 23 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
index 429e323b6b7c24..1564f4c9ebd428 100644
--- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
@@ -318,6 +318,13 @@ static cl::opt<bool> ClDumpStrictInstructions(
     cl::desc("print out instructions with default strict semantics"),
     cl::Hidden, cl::init(false));
 
+static cl::opt<bool> ClDumpStrictIntrinsics(
+    "msan-dump-strict-intrinsics",
+    cl::desc("Prints 'unknown' intrinsics that were handled heuristically. "
+             "Use -msan-dump-strict-instructions to print intrinsics that "
+             "could not be handled exactly nor heuristically."),
+    cl::Hidden, cl::init(false));
+
 static cl::opt<int> ClInstrumentationWithCallThreshold(
     "msan-instrumentation-with-call-threshold",
     cl::desc(
@@ -3016,28 +3023,29 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
   /// handling as an example of that.
   bool handleUnknownIntrinsic(IntrinsicInst &I) {
     unsigned NumArgOperands = I.arg_size();
-    if (NumArgOperands == 0)
-      return false;
 
-    if (NumArgOperands == 2 && I.getArgOperand(0)->getType()->isPointerTy() &&
+    bool success = false;
+    if (NumArgOperands == 0) {
+      // No-op
+    } else if (NumArgOperands == 2 && I.getArgOperand(0)->getType()->isPointerTy() &&
         I.getArgOperand(1)->getType()->isVectorTy() &&
         I.getType()->isVoidTy() && !I.onlyReadsMemory()) {
       // This looks like a vector store.
-      return handleVectorStoreIntrinsic(I);
-    }
-
-    if (NumArgOperands == 1 && I.getArgOperand(0)->getType()->isPointerTy() &&
+      success = handleVectorStoreIntrinsic(I);
+    } else if (NumArgOperands == 1 && I.getArgOperand(0)->getType()->isPointerTy() &&
         I.getType()->isVectorTy() && I.onlyReadsMemory()) {
       // This looks like a vector load.
-      return handleVectorLoadIntrinsic(I);
-    }
+      success = handleVectorLoadIntrinsic(I);
+    } else if (I.doesNotAccessMemory())
+      success = maybeHandleSimpleNomemIntrinsic(I);
+
+    if (success && ClDumpStrictIntrinsics)
+      dumpInst(I);
 
-    if (I.doesNotAccessMemory())
-      if (maybeHandleSimpleNomemIntrinsic(I))
-        return true;
+    LLVM_DEBUG(dbgs() << "UNKNOWN INTRINSIC HANDLED HEURISTICALLY: " << I << "\n");
 
     // FIXME: detect and handle SSE maskstore/maskload
-    return false;
+    return success;
   }
 
   void handleInvariantGroup(IntrinsicInst &I) {
@@ -4033,6 +4041,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
 
   void visitIntrinsicInst(IntrinsicInst &I) {
     switch (I.getIntrinsicID()) {
+#if 0
     case Intrinsic::uadd_with_overflow:
     case Intrinsic::sadd_with_overflow:
     case Intrinsic::usub_with_overflow:
@@ -4445,6 +4454,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
       handleNEONVectorMultiplyIntrinsic(I);
       break;
     }
+#endif
 
     default:
       if (!handleUnknownIntrinsic(I))

>From 44c620cbf6a781b47ae32bca43999bde60564890 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Fri, 17 Jan 2025 18:05:48 +0000
Subject: [PATCH 2/2] Remove testing change + format

---
 .../Instrumentation/MemorySanitizer.cpp         | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
index 1564f4c9ebd428..ddbe8db408b615 100644
--- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
@@ -3027,13 +3027,15 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
     bool success = false;
     if (NumArgOperands == 0) {
       // No-op
-    } else if (NumArgOperands == 2 && I.getArgOperand(0)->getType()->isPointerTy() &&
-        I.getArgOperand(1)->getType()->isVectorTy() &&
-        I.getType()->isVoidTy() && !I.onlyReadsMemory()) {
+    } else if (NumArgOperands == 2 &&
+               I.getArgOperand(0)->getType()->isPointerTy() &&
+               I.getArgOperand(1)->getType()->isVectorTy() &&
+               I.getType()->isVoidTy() && !I.onlyReadsMemory()) {
       // This looks like a vector store.
       success = handleVectorStoreIntrinsic(I);
-    } else if (NumArgOperands == 1 && I.getArgOperand(0)->getType()->isPointerTy() &&
-        I.getType()->isVectorTy() && I.onlyReadsMemory()) {
+    } else if (NumArgOperands == 1 &&
+               I.getArgOperand(0)->getType()->isPointerTy() &&
+               I.getType()->isVectorTy() && I.onlyReadsMemory()) {
       // This looks like a vector load.
       success = handleVectorLoadIntrinsic(I);
     } else if (I.doesNotAccessMemory())
@@ -3042,7 +3044,8 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
     if (success && ClDumpStrictIntrinsics)
       dumpInst(I);
 
-    LLVM_DEBUG(dbgs() << "UNKNOWN INTRINSIC HANDLED HEURISTICALLY: " << I << "\n");
+    LLVM_DEBUG(dbgs() << "UNKNOWN INTRINSIC HANDLED HEURISTICALLY: " << I
+                      << "\n");
 
     // FIXME: detect and handle SSE maskstore/maskload
     return success;
@@ -4041,7 +4044,6 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
 
   void visitIntrinsicInst(IntrinsicInst &I) {
     switch (I.getIntrinsicID()) {
-#if 0
     case Intrinsic::uadd_with_overflow:
     case Intrinsic::sadd_with_overflow:
     case Intrinsic::usub_with_overflow:
@@ -4454,7 +4456,6 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
       handleNEONVectorMultiplyIntrinsic(I);
       break;
     }
-#endif
 
     default:
       if (!handleUnknownIntrinsic(I))



More information about the llvm-commits mailing list