[llvm] [Target] Add target-independent TargetVerifier dispatcher (PR #205703)

Alexis Engelke via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 27 02:04:38 PDT 2026


================
@@ -0,0 +1,135 @@
+//===-- llvm/Target/TargetVerifier.h - Target IR 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 a target-dependent verification framework that can be
+// instantiated and run from target-independent locations.
+//
+// In contrast to the generic Verifier or Lint, a TargetVerify looks for
+// constructs that are invalid for a *particular* target machine. Each backend
+// provides its own TargetVerify and registers a factory for it (keyed by
+// Triple::ArchType) via registerTargetVerify(), typically from its
+// LLVMInitialize<Target>Target().
+//
+// TargetVerifierPass is the target-independent dispatcher: it reads the
+// module's target triple and runs whichever TargetVerify (if any) was
+// registered for that architecture. Because dispatch happens at run time by
+// triple, the pass can be scheduled from generic, target-independent pipelines
+// (e.g. `opt -passes=target-verifier`); it is simply a no-op for targets that
+// have not registered a verifier.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TARGET_TARGETVERIFIER_H
+#define LLVM_TARGET_TARGETVERIFIER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Triple.h"
+
+#include <functional>
+#include <memory>
+#include <string>
+
+namespace llvm {
+
+class Function;
+
+/// Base class for a single target's IR verification logic.
+///
+/// A backend subclasses this and implements run() to check a function for
+/// constructs that are invalid for that target. Failed checks are recorded in
+/// \p Messages (and clear \p IsValid) via checkFailed().
+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 print the condition's message.
+  ///
+  /// This is a convenient place to put a breakpoint to see why something is
+  /// considered invalid for the target.
+  void checkFailed(const Twine &Message) {
+    IsValid = false;
+    MessagesStr << Message << '\n';
+  }
+
+  /// A check failed (with values to print).
+  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;
+
+  /// Whether every function verified so far is valid for the target.
+  bool IsValid = true;
+
+  TargetVerify(Module *Mod)
+      : Mod(Mod), TT(Mod->getTargetTriple()), MessagesStr(Messages) {}
+  virtual ~TargetVerify() = default;
+
+  /// Run this target's checks on \p F. Returns true if \p F is valid.
+  virtual bool run(Function &F) = 0;
+};
+
+/// Factory that creates a target's TargetVerify for a given module.
+using TargetVerifyFactory = std::function<TargetVerify *(Module &)>;
----------------
aengelke wrote:

Can we avoid the use of std::function if at all possible?

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


More information about the llvm-commits mailing list