Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TargetVerifier][AMDGPU] Add TargetVerifier. #123609

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jofrn
Copy link
Contributor

@jofrn jofrn commented Jan 20, 2025

This pass verifies the IR for an individual backend. This is different than Lint because it consolidates all checks for a given backend in a single pass. A check for Lint may be undefined behavior across all targets, whereas a check in TargetVerifier would only pertain to the specified target but can check more than just undefined behavior such are IR validity. A use case of this would be to reject programs with invalid IR while fuzzing.

Copy link

github-actions bot commented Jan 20, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff 1c5b12257d19681d72a52e39eb2247dc6ab6af3b 053aac8113194cda51fbbafe98e38c6c54521134 --extensions h,cpp -- llvm/include/llvm/Target/TargetVerifier.h llvm/include/llvm/Target/TargetVerify/AMDGPUTargetVerifier.h llvm/lib/Target/AMDGPU/AMDGPUTargetVerifier.cpp llvm/tools/llvm-tgt-verify/llvm-tgt-verify.cpp llvm/include/llvm/IR/Module.h llvm/lib/Analysis/Lint.cpp llvm/lib/IR/Verifier.cpp
View the diff from clang-format here.
diff --git a/llvm/include/llvm/Target/TargetVerifier.h b/llvm/include/llvm/Target/TargetVerifier.h
index e00c6a7b26..400282d0a7 100644
--- a/llvm/include/llvm/Target/TargetVerifier.h
+++ b/llvm/include/llvm/Target/TargetVerifier.h
@@ -1,4 +1,5 @@
-//===-- llvm/Target/TargetVerifier.h - LLVM IR Target Verifier ---*- C++ -*-===//
+//===-- llvm/Target/TargetVerifier.h - LLVM IR Target Verifier ---*- C++
+//-*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -20,8 +21,8 @@
 #ifndef LLVM_TARGET_VERIFIER_H
 #define LLVM_TARGET_VERIFIER_H
 
-#include "llvm/IR/PassManager.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
 #include "llvm/TargetParser/Triple.h"
 
 namespace llvm {
@@ -59,10 +60,11 @@ protected:
   /// This calls the Message-only version so that the above is easier to set
   /// a breakpoint on.
   template <typename T1, typename... Ts>
-  void CheckFailed(const Twine &Message, const T1 &V1, const Ts &... Vs) {
+  void CheckFailed(const Twine &Message, const T1 &V1, const Ts &...Vs) {
     CheckFailed(Message);
     WriteValues({V1, Vs...});
   }
+
 public:
   Module *Mod;
   Triple TT;
diff --git a/llvm/include/llvm/Target/TargetVerify/AMDGPUTargetVerifier.h b/llvm/include/llvm/Target/TargetVerify/AMDGPUTargetVerifier.h
index e6ff57629b..207ff2d07d 100644
--- a/llvm/include/llvm/Target/TargetVerify/AMDGPUTargetVerifier.h
+++ b/llvm/include/llvm/Target/TargetVerify/AMDGPUTargetVerifier.h
@@ -1,8 +1,9 @@
-//===-- llvm/Target/TargetVerify/AMDGPUTargetVerifier.h - AMDGPU ---*- C++ -*-===//
+//===-- llvm/Target/TargetVerify/AMDGPUTargetVerifier.h - AMDGPU ---*- C++
+//-*-===//
 ////
-//// 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
+//// 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
 ////
 ////===----------------------------------------------------------------------===//
 ////
diff --git a/llvm/lib/Analysis/Lint.cpp b/llvm/lib/Analysis/Lint.cpp
index 1a42131b8e..9c314b80c7 100644
--- a/llvm/lib/Analysis/Lint.cpp
+++ b/llvm/lib/Analysis/Lint.cpp
@@ -750,9 +750,10 @@ PreservedAnalyses LintPass::run(Function &F, FunctionAnalysisManager &AM) {
   if (!L.MessagesStr.str().empty()) {
     F.getParent()->IsValid = false;
     if (LintAbortOnError)
-      report_fatal_error(Twine("Linter found errors, aborting. (enabled by --") +
-                           LintAbortOnErrorArgName + ")",
-                         false);
+      report_fatal_error(
+          Twine("Linter found errors, aborting. (enabled by --") +
+              LintAbortOnErrorArgName + ")",
+          false);
   }
   return PreservedAnalyses::all();
 }
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetVerifier.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetVerifier.cpp
index 4e12145d0b..ee6fbe771c 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetVerifier.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetVerifier.cpp
@@ -1,21 +1,22 @@
 #include "llvm/Target/TargetVerify/AMDGPUTargetVerifier.h"
 
-#include "llvm/Analysis/UniformityAnalysis.h"
 #include "llvm/Analysis/PostDominators.h"
-#include "llvm/Support/Debug.h"
+#include "llvm/Analysis/UniformityAnalysis.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/IntrinsicsAMDGPU.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/Value.h"
+#include "llvm/Support/Debug.h"
 
 #include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 
-static cl::opt<bool>
-MarkUniform("mark-uniform", cl::desc("Mark instructions as uniform"), cl::init(false));
+static cl::opt<bool> MarkUniform("mark-uniform",
+                                 cl::desc("Mark instructions as uniform"),
+                                 cl::init(false));
 
 // Check - We know that cond should be true, if not print an error message.
 #define Check(C, ...)                                                          \
@@ -28,55 +29,55 @@ MarkUniform("mark-uniform", cl::desc("Mark instructions as uniform"), cl::init(f
 
 static bool isMFMA(unsigned IID) {
   switch (IID) {
-    case Intrinsic::amdgcn_mfma_f32_4x4x1f32:
-    case Intrinsic::amdgcn_mfma_f32_4x4x4f16:
-    case Intrinsic::amdgcn_mfma_i32_4x4x4i8:
-    case Intrinsic::amdgcn_mfma_f32_4x4x2bf16:
-
-    case Intrinsic::amdgcn_mfma_f32_16x16x1f32:
-    case Intrinsic::amdgcn_mfma_f32_16x16x4f32:
-    case Intrinsic::amdgcn_mfma_f32_16x16x4f16:
-    case Intrinsic::amdgcn_mfma_f32_16x16x16f16:
-    case Intrinsic::amdgcn_mfma_i32_16x16x4i8:
-    case Intrinsic::amdgcn_mfma_i32_16x16x16i8:
-    case Intrinsic::amdgcn_mfma_f32_16x16x2bf16:
-    case Intrinsic::amdgcn_mfma_f32_16x16x8bf16:
-
-    case Intrinsic::amdgcn_mfma_f32_32x32x1f32:
-    case Intrinsic::amdgcn_mfma_f32_32x32x2f32:
-    case Intrinsic::amdgcn_mfma_f32_32x32x4f16:
-    case Intrinsic::amdgcn_mfma_f32_32x32x8f16:
-    case Intrinsic::amdgcn_mfma_i32_32x32x4i8:
-    case Intrinsic::amdgcn_mfma_i32_32x32x8i8:
-    case Intrinsic::amdgcn_mfma_f32_32x32x2bf16:
-    case Intrinsic::amdgcn_mfma_f32_32x32x4bf16:
-
-    case Intrinsic::amdgcn_mfma_f32_4x4x4bf16_1k:
-    case Intrinsic::amdgcn_mfma_f32_16x16x4bf16_1k:
-    case Intrinsic::amdgcn_mfma_f32_16x16x16bf16_1k:
-    case Intrinsic::amdgcn_mfma_f32_32x32x4bf16_1k:
-    case Intrinsic::amdgcn_mfma_f32_32x32x8bf16_1k:
-
-    case Intrinsic::amdgcn_mfma_f64_16x16x4f64:
-    case Intrinsic::amdgcn_mfma_f64_4x4x4f64:
-
-    case Intrinsic::amdgcn_mfma_i32_16x16x32_i8:
-    case Intrinsic::amdgcn_mfma_i32_32x32x16_i8:
-    case Intrinsic::amdgcn_mfma_f32_16x16x8_xf32:
-    case Intrinsic::amdgcn_mfma_f32_32x32x4_xf32:
-
-    case Intrinsic::amdgcn_mfma_f32_16x16x32_bf8_bf8:
-    case Intrinsic::amdgcn_mfma_f32_16x16x32_bf8_fp8:
-    case Intrinsic::amdgcn_mfma_f32_16x16x32_fp8_bf8:
-    case Intrinsic::amdgcn_mfma_f32_16x16x32_fp8_fp8:
-
-    case Intrinsic::amdgcn_mfma_f32_32x32x16_bf8_bf8:
-    case Intrinsic::amdgcn_mfma_f32_32x32x16_bf8_fp8:
-    case Intrinsic::amdgcn_mfma_f32_32x32x16_fp8_bf8:
-    case Intrinsic::amdgcn_mfma_f32_32x32x16_fp8_fp8:
-      return true;
-    default:
-      return false;
+  case Intrinsic::amdgcn_mfma_f32_4x4x1f32:
+  case Intrinsic::amdgcn_mfma_f32_4x4x4f16:
+  case Intrinsic::amdgcn_mfma_i32_4x4x4i8:
+  case Intrinsic::amdgcn_mfma_f32_4x4x2bf16:
+
+  case Intrinsic::amdgcn_mfma_f32_16x16x1f32:
+  case Intrinsic::amdgcn_mfma_f32_16x16x4f32:
+  case Intrinsic::amdgcn_mfma_f32_16x16x4f16:
+  case Intrinsic::amdgcn_mfma_f32_16x16x16f16:
+  case Intrinsic::amdgcn_mfma_i32_16x16x4i8:
+  case Intrinsic::amdgcn_mfma_i32_16x16x16i8:
+  case Intrinsic::amdgcn_mfma_f32_16x16x2bf16:
+  case Intrinsic::amdgcn_mfma_f32_16x16x8bf16:
+
+  case Intrinsic::amdgcn_mfma_f32_32x32x1f32:
+  case Intrinsic::amdgcn_mfma_f32_32x32x2f32:
+  case Intrinsic::amdgcn_mfma_f32_32x32x4f16:
+  case Intrinsic::amdgcn_mfma_f32_32x32x8f16:
+  case Intrinsic::amdgcn_mfma_i32_32x32x4i8:
+  case Intrinsic::amdgcn_mfma_i32_32x32x8i8:
+  case Intrinsic::amdgcn_mfma_f32_32x32x2bf16:
+  case Intrinsic::amdgcn_mfma_f32_32x32x4bf16:
+
+  case Intrinsic::amdgcn_mfma_f32_4x4x4bf16_1k:
+  case Intrinsic::amdgcn_mfma_f32_16x16x4bf16_1k:
+  case Intrinsic::amdgcn_mfma_f32_16x16x16bf16_1k:
+  case Intrinsic::amdgcn_mfma_f32_32x32x4bf16_1k:
+  case Intrinsic::amdgcn_mfma_f32_32x32x8bf16_1k:
+
+  case Intrinsic::amdgcn_mfma_f64_16x16x4f64:
+  case Intrinsic::amdgcn_mfma_f64_4x4x4f64:
+
+  case Intrinsic::amdgcn_mfma_i32_16x16x32_i8:
+  case Intrinsic::amdgcn_mfma_i32_32x32x16_i8:
+  case Intrinsic::amdgcn_mfma_f32_16x16x8_xf32:
+  case Intrinsic::amdgcn_mfma_f32_32x32x4_xf32:
+
+  case Intrinsic::amdgcn_mfma_f32_16x16x32_bf8_bf8:
+  case Intrinsic::amdgcn_mfma_f32_16x16x32_bf8_fp8:
+  case Intrinsic::amdgcn_mfma_f32_16x16x32_fp8_bf8:
+  case Intrinsic::amdgcn_mfma_f32_16x16x32_fp8_fp8:
+
+  case Intrinsic::amdgcn_mfma_f32_32x32x16_bf8_bf8:
+  case Intrinsic::amdgcn_mfma_f32_32x32x16_bf8_fp8:
+  case Intrinsic::amdgcn_mfma_f32_32x32x16_fp8_bf8:
+  case Intrinsic::amdgcn_mfma_f32_32x32x16_fp8_fp8:
+    return true;
+  default:
+    return false;
   }
 }
 
@@ -89,42 +90,40 @@ public:
   PostDominatorTree *PDT;
   UniformityInfo *UA;
 
-  AMDGPUTargetVerify(Module *Mod, DominatorTree *DT, PostDominatorTree *PDT, UniformityInfo *UA)
-    : TargetVerify(Mod), Mod(Mod), DT(DT), PDT(PDT), UA(UA) {}
+  AMDGPUTargetVerify(Module *Mod, DominatorTree *DT, PostDominatorTree *PDT,
+                     UniformityInfo *UA)
+      : TargetVerify(Mod), Mod(Mod), DT(DT), PDT(PDT), UA(UA) {}
 
   void run(Function &F);
 };
 
 static bool IsValidInt(const Type *Ty) {
-  return Ty->isIntegerTy(1) ||
-         Ty->isIntegerTy(8) ||
-         Ty->isIntegerTy(16) ||
-         Ty->isIntegerTy(32) ||
-         Ty->isIntegerTy(64) ||
-         Ty->isIntegerTy(128);
+  return Ty->isIntegerTy(1) || Ty->isIntegerTy(8) || Ty->isIntegerTy(16) ||
+         Ty->isIntegerTy(32) || Ty->isIntegerTy(64) || Ty->isIntegerTy(128);
 }
 
 static bool isShader(CallingConv::ID CC) {
-  switch(CC) {
-    case CallingConv::AMDGPU_VS:
-    case CallingConv::AMDGPU_LS:
-    case CallingConv::AMDGPU_HS:
-    case CallingConv::AMDGPU_ES:
-    case CallingConv::AMDGPU_GS:
-    case CallingConv::AMDGPU_PS:
-    case CallingConv::AMDGPU_CS_Chain:
-    case CallingConv::AMDGPU_CS_ChainPreserve:
-    case CallingConv::AMDGPU_CS:
-      return true;
-    default:
-      return false;
+  switch (CC) {
+  case CallingConv::AMDGPU_VS:
+  case CallingConv::AMDGPU_LS:
+  case CallingConv::AMDGPU_HS:
+  case CallingConv::AMDGPU_ES:
+  case CallingConv::AMDGPU_GS:
+  case CallingConv::AMDGPU_PS:
+  case CallingConv::AMDGPU_CS_Chain:
+  case CallingConv::AMDGPU_CS_ChainPreserve:
+  case CallingConv::AMDGPU_CS:
+    return true;
+  default:
+    return false;
   }
 }
 
 void AMDGPUTargetVerify::run(Function &F) {
   // Ensure shader calling convention returns void
   if (isShader(F.getCallingConv()))
-    Check(F.getReturnType() == Type::getVoidTy(F.getContext()), "Shaders must return void");
+    Check(F.getReturnType() == Type::getVoidTy(F.getContext()),
+          "Shaders must return void");
 
   for (auto &BB : F) {
 
@@ -137,32 +136,29 @@ void AMDGPUTargetVerify::run(Function &F) {
         Check(IsValidInt(I.getType()), "Int type is invalid.", &I);
       for (unsigned i = 0; i < I.getNumOperands(); ++i)
         if (I.getOperand(i)->getType()->isIntegerTy())
-          Check(IsValidInt(I.getOperand(i)->getType()),
-                "Int type is invalid.", I.getOperand(i));
+          Check(IsValidInt(I.getOperand(i)->getType()), "Int type is invalid.",
+                I.getOperand(i));
 
       // Ensure alloca array size is constant
-      if (auto *AI = dyn_cast<AllocaInst>(&I))
-      {
+      if (auto *AI = dyn_cast<AllocaInst>(&I)) {
         auto *AS = AI->getArraySize();
         Check(!isa<Constant>(AS), "Dynamically-sized alloca disallowed");
       }
 
       // Ensure no store to const memory
-      if (auto *SI = dyn_cast<StoreInst>(&I))
-      {
+      if (auto *SI = dyn_cast<StoreInst>(&I)) {
         unsigned AS = SI->getPointerAddressSpace();
         Check(AS != 4, "Write to const memory", SI);
       }
 
       // Ensure no kernel to kernel calls.
-      if (auto *CI = dyn_cast<CallInst>(&I))
-      {
+      if (auto *CI = dyn_cast<CallInst>(&I)) {
         CallingConv::ID CalleeCC = CI->getCallingConv();
-        if (CalleeCC == CallingConv::AMDGPU_KERNEL)
-        {
-          CallingConv::ID CallerCC = CI->getParent()->getParent()->getCallingConv();
+        if (CalleeCC == CallingConv::AMDGPU_KERNEL) {
+          CallingConv::ID CallerCC =
+              CI->getParent()->getParent()->getCallingConv();
           Check(CallerCC != CallingConv::AMDGPU_KERNEL,
-            "A kernel may not call a kernel", CI->getParent()->getParent());
+                "A kernel may not call a kernel", CI->getParent()->getParent());
         }
       }
 
@@ -181,7 +177,8 @@ void AMDGPUTargetVerify::run(Function &F) {
               break;
             }
           if (InControlFlow) {
-            // If operands to MFMA are not uniform, MFMA cannot be in control flow
+            // If operands to MFMA are not uniform, MFMA cannot be in control
+            // flow
             bool hasUniformOperands = true;
             for (unsigned i = 0; i < II->getNumOperands(); i++) {
               if (!UA->isUniform(II->getOperand(i))) {
@@ -189,17 +186,19 @@ void AMDGPUTargetVerify::run(Function &F) {
                 hasUniformOperands = false;
               }
             }
-            if (!hasUniformOperands) Check(false, "MFMA in control flow", II);
-            //else Check(false, "MFMA in control flow (uniform operands)", II);
+            if (!hasUniformOperands)
+              Check(false, "MFMA in control flow", II);
+            // else Check(false, "MFMA in control flow (uniform operands)", II);
           }
-          //else Check(false, "MFMA not in control flow", II);
+          // else Check(false, "MFMA not in control flow", II);
         }
       }
     }
   }
 }
 
-PreservedAnalyses AMDGPUTargetVerifierPass::run(Function &F, FunctionAnalysisManager &AM) {
+PreservedAnalyses AMDGPUTargetVerifierPass::run(Function &F,
+                                                FunctionAnalysisManager &AM) {
 
   auto *Mod = F.getParent();
 
diff --git a/llvm/tools/llvm-tgt-verify/llvm-tgt-verify.cpp b/llvm/tools/llvm-tgt-verify/llvm-tgt-verify.cpp
index 68422abd6f..404f76caf5 100644
--- a/llvm/tools/llvm-tgt-verify/llvm-tgt-verify.cpp
+++ b/llvm/tools/llvm-tgt-verify/llvm-tgt-verify.cpp
@@ -10,7 +10,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/InitializePasses.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Analysis/Lint.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
@@ -24,9 +23,10 @@
 #include "llvm/IR/Module.h"
 #include "llvm/IR/Verifier.h"
 #include "llvm/IRReader/IRReader.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/MC/TargetRegistry.h"
 #include "llvm/Passes/PassBuilder.h"
 #include "llvm/Passes/StandardInstrumentations.h"
-#include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/DataTypes.h"
 #include "llvm/Support/Debug.h"
@@ -45,19 +45,17 @@ using namespace llvm;
 static codegen::RegisterCodeGenFlags CGF;
 
 static cl::opt<std::string>
-InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
+    InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
 
-static cl::opt<bool>
-    StacktraceAbort("stacktrace-abort",
-        cl::desc("Turn on stacktrace"), cl::init(false));
+static cl::opt<bool> StacktraceAbort("stacktrace-abort",
+                                     cl::desc("Turn on stacktrace"),
+                                     cl::init(false));
 
-static cl::opt<bool>
-    NoLint("no-lint",
-        cl::desc("Turn off Lint"), cl::init(false));
+static cl::opt<bool> NoLint("no-lint", cl::desc("Turn off Lint"),
+                            cl::init(false));
 
-static cl::opt<bool>
-    NoVerify("no-verifier",
-        cl::desc("Turn off Verifier"), cl::init(false));
+static cl::opt<bool> NoVerify("no-verifier", cl::desc("Turn off Verifier"),
+                              cl::init(false));
 
 static cl::opt<char>
     OptLevel("O",
@@ -126,13 +124,12 @@ int main(int argc, char **argv) {
   M->setTargetTriple(S);
 
   PassInstrumentationCallbacks PIC;
-  StandardInstrumentations SI(Context, false/*debug PM*/,
-                              false);
+  StandardInstrumentations SI(Context, false /*debug PM*/, false);
   registerCodeGenCallback(PIC, *TM);
 
   ModulePassManager MPM;
   FunctionPassManager FPM;
-  //TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple()));
+  // TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple()));
 
   MachineFunctionAnalysisManager MFAM;
   LoopAnalysisManager LAM;
@@ -149,7 +146,7 @@ int main(int argc, char **argv) {
 
   SI.registerCallbacks(PIC, &MAM);
 
-  //FAM.registerPass([&] { return TargetLibraryAnalysis(TLII); });
+  // FAM.registerPass([&] { return TargetLibraryAnalysis(TLII); });
 
   Triple TT(M->getTargetTriple());
   if (!NoLint)
@@ -158,7 +155,8 @@ int main(int argc, char **argv) {
     MPM.addPass(VerifierPass());
   if (TT.isAMDGPU())
     FPM.addPass(AMDGPUTargetVerifierPass());
-  else if (false) {} // ...
+  else if (false) {
+  } // ...
   else
     FPM.addPass(TargetVerifierPass());
   MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));

This pass verifies the IR for an individual backend. This is
different than Lint because it consolidates all checks for a
given backend in a single pass. A check for Lint may be
undefined behavior across all targets, whereas a check in
TargetVerifier would only pertain to the specified target
but can check more than just undefined behavior such are IR
validity. A use case of this would be to reject programs
with invalid IR while fuzzing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant