[llvm] [TargetVerifier][AMDGPU] Add TargetVerifier. (PR #123609)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 2 05:36:39 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-amdgpu

Author: None (jofrn)

<details>
<summary>Changes</summary>

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.

---

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


22 Files Affected:

- (modified) llvm/include/llvm/IR/Module.h (+4) 
- (modified) llvm/include/llvm/Passes/StandardInstrumentations.h (+4-2) 
- (added) llvm/include/llvm/Target/TargetVerifier.h (+83) 
- (added) llvm/include/llvm/Target/TargetVerify/AMDGPUTargetVerifier.h (+54) 
- (modified) llvm/lib/Analysis/Lint.cpp (+6-3) 
- (modified) llvm/lib/IR/Verifier.cpp (+14-4) 
- (modified) llvm/lib/LTO/LTOBackend.cpp (+1-1) 
- (modified) llvm/lib/LTO/ThinLTOCodeGenerator.cpp (+1-1) 
- (modified) llvm/lib/Passes/CMakeLists.txt (+1) 
- (modified) llvm/lib/Passes/PassBuilderBindings.cpp (+1-1) 
- (modified) llvm/lib/Passes/StandardInstrumentations.cpp (+15-4) 
- (added) llvm/lib/Target/AMDGPU/AMDGPUTargetVerifier.cpp (+213) 
- (modified) llvm/lib/Target/AMDGPU/CMakeLists.txt (+1) 
- (modified) llvm/lib/Target/CMakeLists.txt (+2) 
- (added) llvm/test/CodeGen/AMDGPU/tgt-verify-llc-fail.ll (+6) 
- (added) llvm/test/CodeGen/AMDGPU/tgt-verify-llc-pass.ll (+6) 
- (added) llvm/test/CodeGen/AMDGPU/tgt-verify.ll (+62) 
- (modified) llvm/tools/llc/NewPMDriver.cpp (+1-1) 
- (added) llvm/tools/llvm-tgt-verify/CMakeLists.txt (+34) 
- (added) llvm/tools/llvm-tgt-verify/llvm-tgt-verify.cpp (+172) 
- (modified) llvm/tools/opt/NewPMDriver.cpp (+1-1) 
- (modified) llvm/unittests/IR/PassManagerTest.cpp (+3-3) 


``````````diff
diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h
index 12b50fc506516..7844cb216ed57 100644
--- a/llvm/include/llvm/IR/Module.h
+++ b/llvm/include/llvm/IR/Module.h
@@ -211,6 +211,10 @@ class LLVM_ABI Module {
 /// @name Constructors
 /// @{
 public:
+  /// Is this Module valid as determined by one of the verification passes
+  /// i.e. Lint, Verifier, TargetVerifier.
+  bool IsValid = true;
+
   /// Is this Module using intrinsics to record the position of debugging
   /// information, or non-intrinsic records? See IsNewDbgInfoFormat in
   /// \ref BasicBlock.
diff --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h
index 4e62ee9c00daf..f794555b7a96d 100644
--- a/llvm/include/llvm/Passes/StandardInstrumentations.h
+++ b/llvm/include/llvm/Passes/StandardInstrumentations.h
@@ -464,7 +464,8 @@ class VerifyInstrumentation {
 public:
   VerifyInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {}
   void registerCallbacks(PassInstrumentationCallbacks &PIC,
-                         ModuleAnalysisManager *MAM);
+                         ModuleAnalysisManager *MAM,
+			 FunctionAnalysisManager *FAM);
 };
 
 /// This class implements --time-trace functionality for new pass manager.
@@ -609,7 +610,8 @@ class StandardInstrumentations {
   // Register all the standard instrumentation callbacks. If \p FAM is nullptr
   // then PreservedCFGChecker is not enabled.
   void registerCallbacks(PassInstrumentationCallbacks &PIC,
-                         ModuleAnalysisManager *MAM = nullptr);
+                         ModuleAnalysisManager *MAM,
+			 FunctionAnalysisManager *FAM);
 
   TimePassesHandler &getTimePasses() { return TimePasses; }
 };
diff --git a/llvm/include/llvm/Target/TargetVerifier.h b/llvm/include/llvm/Target/TargetVerifier.h
new file mode 100644
index 0000000000000..ad5aeb895953d
--- /dev/null
+++ b/llvm/include/llvm/Target/TargetVerifier.h
@@ -0,0 +1,83 @@
+//===-- 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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines target verifier interfaces that can be used for some
+// validation of input to the system, and for checking that transformations
+// haven't done something bad. In contrast to the Verifier or Lint, the
+// TargetVerifier looks for constructions invalid to a particular target
+// machine.
+//
+// To see what specifically is checked, look at TargetVerifier.cpp or an
+// individual backend's TargetVerifier.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TARGET_VERIFIER_H
+#define LLVM_TARGET_VERIFIER_H
+
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/TargetParser/Triple.h"
+
+namespace llvm {
+
+class Function;
+
+class TargetVerifierPass : public PassInfoMixin<TargetVerifierPass> {
+public:
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {}
+};
+
+class TargetVerify {
+protected:
+  void WriteValues(ArrayRef<const Value *> Vs) {
+    for (const Value *V : Vs) {
+      if (!V)
+        continue;
+      if (isa<Instruction>(V)) {
+        MessagesStr << *V << '\n';
+      } else {
+        V->printAsOperand(MessagesStr, true, Mod);
+        MessagesStr << '\n';
+      }
+    }
+  }
+
+  /// A check failed, so printout out the condition and the message.
+  ///
+  /// This provides a nice place to put a breakpoint if you want to see why
+  /// something is not correct.
+  void CheckFailed(const Twine &Message) { MessagesStr << Message << '\n'; }
+
+  /// A check failed (with values to print).
+  ///
+  /// 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) {
+    CheckFailed(Message);
+    WriteValues({V1, Vs...});
+  }
+public:
+  Module *Mod;
+  Triple TT;
+
+  std::string Messages;
+  raw_string_ostream MessagesStr;
+
+  TargetVerify(Module *Mod)
+      : Mod(Mod), TT(Triple::normalize(Mod->getTargetTriple())),
+        MessagesStr(Messages) {}
+
+  void run(Function &F) {};
+  void run(Function &F, FunctionAnalysisManager &AM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_TARGET_VERIFIER_H
diff --git a/llvm/include/llvm/Target/TargetVerify/AMDGPUTargetVerifier.h b/llvm/include/llvm/Target/TargetVerify/AMDGPUTargetVerifier.h
new file mode 100644
index 0000000000000..d8a3fda4f87dc
--- /dev/null
+++ b/llvm/include/llvm/Target/TargetVerify/AMDGPUTargetVerifier.h
@@ -0,0 +1,54 @@
+//===-- 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
+////
+////===----------------------------------------------------------------------===//
+////
+//// This file defines target verifier interfaces that can be used for some
+//// validation of input to the system, and for checking that transformations
+//// haven't done something bad. In contrast to the Verifier or Lint, the
+//// TargetVerifier looks for constructions invalid to a particular target
+//// machine.
+////
+//// To see what specifically is checked, look at an individual backend's
+//// TargetVerifier.
+////
+////===----------------------------------------------------------------------===//
+
+#ifndef LLVM_AMDGPU_TARGET_VERIFIER_H
+#define LLVM_AMDGPU_TARGET_VERIFIER_H
+
+#include "llvm/Target/TargetVerifier.h"
+
+#include "llvm/Analysis/UniformityAnalysis.h"
+#include "llvm/Analysis/PostDominators.h"
+#include "llvm/IR/Dominators.h"
+
+namespace llvm {
+
+class Function;
+
+class AMDGPUTargetVerifierPass : public TargetVerifierPass {
+public:
+  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+};
+
+class AMDGPUTargetVerify : public TargetVerify {
+public:
+  Module *Mod;
+
+  DominatorTree *DT;
+  PostDominatorTree *PDT;
+  UniformityInfo *UA;
+
+  AMDGPUTargetVerify(Module *Mod, DominatorTree *DT, PostDominatorTree *PDT, UniformityInfo *UA)
+    : TargetVerify(Mod), Mod(Mod), DT(DT), PDT(PDT), UA(UA) {}
+
+  void run(Function &F);
+};
+
+} // namespace llvm
+
+#endif // LLVM_AMDGPU_TARGET_VERIFIER_H
diff --git a/llvm/lib/Analysis/Lint.cpp b/llvm/lib/Analysis/Lint.cpp
index e9d96a0c2972a..1a42131b8ed1f 100644
--- a/llvm/lib/Analysis/Lint.cpp
+++ b/llvm/lib/Analysis/Lint.cpp
@@ -747,10 +747,13 @@ PreservedAnalyses LintPass::run(Function &F, FunctionAnalysisManager &AM) {
   Lint L(Mod, DL, AA, AC, DT, TLI);
   L.visit(F);
   dbgs() << L.MessagesStr.str();
-  if (LintAbortOnError && !L.MessagesStr.str().empty())
-    report_fatal_error(Twine("Linter found errors, aborting. (enabled by --") +
+  if (!L.MessagesStr.str().empty()) {
+    F.getParent()->IsValid = false;
+    if (LintAbortOnError)
+      report_fatal_error(Twine("Linter found errors, aborting. (enabled by --") +
                            LintAbortOnErrorArgName + ")",
-                       false);
+                         false);
+  }
   return PreservedAnalyses::all();
 }
 
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 7b6f7b5aa6171..26616c4de59d2 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -135,6 +135,10 @@ static cl::opt<bool> VerifyNoAliasScopeDomination(
     cl::desc("Ensure that llvm.experimental.noalias.scope.decl for identical "
              "scopes are not dominating"));
 
+static cl::opt<bool>
+    VerifyAbortOnError("verifier-abort-on-error", cl::init(false),
+                       cl::desc("In the Verifier pass, abort on errors."));
+
 namespace llvm {
 
 struct VerifierSupport {
@@ -7739,16 +7743,22 @@ VerifierAnalysis::Result VerifierAnalysis::run(Function &F,
 
 PreservedAnalyses VerifierPass::run(Module &M, ModuleAnalysisManager &AM) {
   auto Res = AM.getResult<VerifierAnalysis>(M);
-  if (FatalErrors && (Res.IRBroken || Res.DebugInfoBroken))
-    report_fatal_error("Broken module found, compilation aborted!");
+  if (Res.IRBroken || Res.DebugInfoBroken) {
+    M.IsValid = false;
+    if (VerifyAbortOnError && FatalErrors)
+      report_fatal_error("Broken module found, compilation aborted!");
+  }
 
   return PreservedAnalyses::all();
 }
 
 PreservedAnalyses VerifierPass::run(Function &F, FunctionAnalysisManager &AM) {
   auto res = AM.getResult<VerifierAnalysis>(F);
-  if (res.IRBroken && FatalErrors)
-    report_fatal_error("Broken function found, compilation aborted!");
+  if (res.IRBroken) {
+    F.getParent()->IsValid = false;
+    if (VerifyAbortOnError && FatalErrors)
+      report_fatal_error("Broken function found, compilation aborted!");
+  }
 
   return PreservedAnalyses::all();
 }
diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp
index 8a2dddce4892c..2d2f16005bd40 100644
--- a/llvm/lib/LTO/LTOBackend.cpp
+++ b/llvm/lib/LTO/LTOBackend.cpp
@@ -270,7 +270,7 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,
   PassInstrumentationCallbacks PIC;
   StandardInstrumentations SI(Mod.getContext(), Conf.DebugPassManager,
                               Conf.VerifyEach);
-  SI.registerCallbacks(PIC, &MAM);
+  SI.registerCallbacks(PIC, &MAM, &FAM);
   PassBuilder PB(TM, Conf.PTO, PGOOpt, &PIC);
 
   RegisterPassPlugins(Conf.PassPlugins, PB);
diff --git a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
index 189f2876b61c0..84df56948a5a7 100644
--- a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
+++ b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
@@ -245,7 +245,7 @@ static void optimizeModule(Module &TheModule, TargetMachine &TM,
 
   PassInstrumentationCallbacks PIC;
   StandardInstrumentations SI(TheModule.getContext(), DebugPassManager);
-  SI.registerCallbacks(PIC, &MAM);
+  SI.registerCallbacks(PIC, &MAM, &FAM);
   PipelineTuningOptions PTO;
   PTO.LoopVectorization = true;
   PTO.SLPVectorization = true;
diff --git a/llvm/lib/Passes/CMakeLists.txt b/llvm/lib/Passes/CMakeLists.txt
index 23799ac4f98f7..4b643837722ad 100644
--- a/llvm/lib/Passes/CMakeLists.txt
+++ b/llvm/lib/Passes/CMakeLists.txt
@@ -30,6 +30,7 @@ add_llvm_component_library(LLVMPasses
   Scalar
   Support
   Target
+  TargetParser
   TransformUtils
   Vectorize
   Instrumentation
diff --git a/llvm/lib/Passes/PassBuilderBindings.cpp b/llvm/lib/Passes/PassBuilderBindings.cpp
index 933fe89e53a94..f0e1abb8cebc4 100644
--- a/llvm/lib/Passes/PassBuilderBindings.cpp
+++ b/llvm/lib/Passes/PassBuilderBindings.cpp
@@ -76,7 +76,7 @@ static LLVMErrorRef runPasses(Module *Mod, Function *Fun, const char *Passes,
   PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
 
   StandardInstrumentations SI(Mod->getContext(), Debug, VerifyEach);
-  SI.registerCallbacks(PIC, &MAM);
+  SI.registerCallbacks(PIC, &MAM, &FAM);
 
   // Run the pipeline.
   if (Fun) {
diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index b766517e68eba..27ea19302d8d8 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -45,6 +45,7 @@
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/xxhash.h"
+#include "llvm/Target/TargetVerifier.h"
 #include <unordered_map>
 #include <unordered_set>
 #include <utility>
@@ -1461,9 +1462,10 @@ void PreservedCFGCheckerInstrumentation::registerCallbacks(
 }
 
 void VerifyInstrumentation::registerCallbacks(PassInstrumentationCallbacks &PIC,
-                                              ModuleAnalysisManager *MAM) {
+                                              ModuleAnalysisManager *MAM,
+					      FunctionAnalysisManager *FAM) {
   PIC.registerAfterPassCallback(
-      [this, MAM](StringRef P, Any IR, const PreservedAnalyses &PassPA) {
+      [this, MAM, FAM](StringRef P, Any IR, const PreservedAnalyses &PassPA) {
         if (isIgnored(P) || P == "VerifierPass")
           return;
         const auto *F = unwrapIR<Function>(IR);
@@ -1480,6 +1482,15 @@ void VerifyInstrumentation::registerCallbacks(PassInstrumentationCallbacks &PIC,
             report_fatal_error(formatv("Broken function found after pass "
                                        "\"{0}\", compilation aborted!",
                                        P));
+
+          if (FAM) {
+            TargetVerify TV(const_cast<Module*>(F->getParent()));
+            TV.run(*const_cast<Function*>(F), *FAM);
+	    if (!F->getParent()->IsValid)
+              report_fatal_error(formatv("Broken function found after pass "
+                                         "\"{0}\", compilation aborted!",
+                                         P));
+          }
         } else {
           const auto *M = unwrapIR<Module>(IR);
           if (!M) {
@@ -2524,7 +2535,7 @@ void PrintCrashIRInstrumentation::registerCallbacks(
 }
 
 void StandardInstrumentations::registerCallbacks(
-    PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM) {
+    PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM, FunctionAnalysisManager *FAM) {
   PrintIR.registerCallbacks(PIC);
   PrintPass.registerCallbacks(PIC);
   TimePasses.registerCallbacks(PIC);
@@ -2533,7 +2544,7 @@ void StandardInstrumentations::registerCallbacks(
   PrintChangedIR.registerCallbacks(PIC);
   PseudoProbeVerification.registerCallbacks(PIC);
   if (VerifyEach)
-    Verify.registerCallbacks(PIC, MAM);
+    Verify.registerCallbacks(PIC, MAM, FAM);
   PrintChangedDiff.registerCallbacks(PIC);
   WebsiteChangeReporter.registerCallbacks(PIC);
   ChangeTester.registerCallbacks(PIC);
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetVerifier.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetVerifier.cpp
new file mode 100644
index 0000000000000..e6cdec7160229
--- /dev/null
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetVerifier.cpp
@@ -0,0 +1,213 @@
+#include "llvm/Target/TargetVerify/AMDGPUTargetVerifier.h"
+
+#include "llvm/Analysis/UniformityAnalysis.h"
+#include "llvm/Analysis/PostDominators.h"
+#include "llvm/Support/Debug.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/raw_ostream.h"
+
+using namespace llvm;
+
+//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, ...)                                                          \
+  do {                                                                         \
+    if (!(C)) {                                                                \
+      TargetVerify::CheckFailed(__VA_ARGS__);                                  \
+      return;                                                                  \
+    }                                                                          \
+  } while (false)
+
+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;
+  }
+}
+
+namespace llvm {
+/*class AMDGPUTargetVerify : public TargetVerify {
+public:
+  Module *Mod;
+
+  DominatorTree *DT;
+  PostDominatorTree *PDT;
+  UniformityInfo *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);
+}
+
+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;
+  }
+}
+
+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");
+
+  for (auto &BB : F) {
+
+    for (auto &I : BB) {
+      //if (MarkUniform)
+        //outs() << UA->isUniform(&I) << ' ' << I << '\n';
+
+      // Ensure integral types are valid: i8, i16, i32, i64, i128
+      if (I.getType()->isIntegerTy())
+        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));
+
+      // Ensure no store to const memory
+      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))
+      {
+        CallingConv::ID CalleeCC = CI->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());
+        }
+      }
+
+      // Ensure MFMA is not in control flow with diverging operands
+      if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
+        if (isMFMA(II->getIntrinsicID())) {
+          bool InControlFlow = false;
+          for (const auto &P : predecessors(&BB))
+            if (!PDT->dominates(&BB, P)) {
+              InControlFlow = true;
+              break;
+            }
+          for (const auto &S : successors(&BB))
+            if (!DT->dominates(&BB, S)) {
+ ...
[truncated]

``````````

</details>


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


More information about the llvm-commits mailing list