[llvm] [TargetVerifier][AMDGPU] Add TargetVerifier. (PR #123609)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 20 06:19:36 PST 2025
https://github.com/jofrn updated https://github.com/llvm/llvm-project/pull/123609
>From 053aac8113194cda51fbbafe98e38c6c54521134 Mon Sep 17 00:00:00 2001
From: jofernau <Joe.Fernau at amd.com>
Date: Mon, 20 Jan 2025 04:51:26 -0800
Subject: [PATCH] [TargetVerifier][AMDGPU] Add TargetVerifier.
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.
---
llvm/include/llvm/IR/Module.h | 4 +
llvm/include/llvm/Target/TargetVerifier.h | 82 +++++++
.../TargetVerify/AMDGPUTargetVerifier.h | 36 +++
llvm/lib/Analysis/Lint.cpp | 9 +-
llvm/lib/IR/Verifier.cpp | 18 +-
.../Target/AMDGPU/AMDGPUTargetVerifier.cpp | 220 ++++++++++++++++++
llvm/lib/Target/AMDGPU/CMakeLists.txt | 1 +
llvm/test/CodeGen/AMDGPU/tgt-verify.ll | 62 +++++
llvm/tools/llvm-tgt-verify/CMakeLists.txt | 34 +++
.../tools/llvm-tgt-verify/llvm-tgt-verify.cpp | 172 ++++++++++++++
10 files changed, 631 insertions(+), 7 deletions(-)
create mode 100644 llvm/include/llvm/Target/TargetVerifier.h
create mode 100644 llvm/include/llvm/Target/TargetVerify/AMDGPUTargetVerifier.h
create mode 100644 llvm/lib/Target/AMDGPU/AMDGPUTargetVerifier.cpp
create mode 100644 llvm/test/CodeGen/AMDGPU/tgt-verify.ll
create mode 100644 llvm/tools/llvm-tgt-verify/CMakeLists.txt
create mode 100644 llvm/tools/llvm-tgt-verify/llvm-tgt-verify.cpp
diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h
index 12b50fc506516e..7844cb216ed571 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/Target/TargetVerifier.h b/llvm/include/llvm/Target/TargetVerifier.h
new file mode 100644
index 00000000000000..e00c6a7b260c98
--- /dev/null
+++ b/llvm/include/llvm/Target/TargetVerifier.h
@@ -0,0 +1,82 @@
+//===-- 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) {};
+};
+
+} // 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 00000000000000..e6ff57629b1413
--- /dev/null
+++ b/llvm/include/llvm/Target/TargetVerify/AMDGPUTargetVerifier.h
@@ -0,0 +1,36 @@
+//===-- 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"
+
+namespace llvm {
+
+class Function;
+
+class AMDGPUTargetVerifierPass : public TargetVerifierPass {
+public:
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_AMDGPU_TARGET_VERIFIER_H
diff --git a/llvm/lib/Analysis/Lint.cpp b/llvm/lib/Analysis/Lint.cpp
index e9d96a0c2972ad..1a42131b8ed1f1 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 7b6f7b5aa6171a..26616c4de59d2a 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/Target/AMDGPU/AMDGPUTargetVerifier.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetVerifier.cpp
new file mode 100644
index 00000000000000..4e12145d0b45d7
--- /dev/null
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetVerifier.cpp
@@ -0,0 +1,220 @@
+#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 alloca array size is constant
+ 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))
+ {
+ 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)) {
+ InControlFlow = true;
+ break;
+ }
+ if (InControlFlow) {
+ // 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))) {
+ dbgs() << "Not uniform: " << *II->getOperand(i) << '\n';
+ hasUniformOperands = false;
+ }
+ }
+ 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);
+ }
+ }
+ }
+ }
+}
+
+PreservedAnalyses AMDGPUTargetVerifierPass::run(Function &F, FunctionAnalysisManager &AM) {
+
+ auto *Mod = F.getParent();
+
+ auto UA = &AM.getResult<UniformityInfoAnalysis>(F);
+ auto *DT = &AM.getResult<DominatorTreeAnalysis>(F);
+ auto *PDT = &AM.getResult<PostDominatorTreeAnalysis>(F);
+
+ AMDGPUTargetVerify TV(Mod, DT, PDT, UA);
+ TV.run(F);
+
+ dbgs() << TV.MessagesStr.str();
+ if (!TV.MessagesStr.str().empty()) {
+ F.getParent()->IsValid = false;
+ }
+
+ return PreservedAnalyses::all();
+}
+} // namespace llvm
diff --git a/llvm/lib/Target/AMDGPU/CMakeLists.txt b/llvm/lib/Target/AMDGPU/CMakeLists.txt
index 97a0d59cfeeda3..a7cbc0415fb3e4 100644
--- a/llvm/lib/Target/AMDGPU/CMakeLists.txt
+++ b/llvm/lib/Target/AMDGPU/CMakeLists.txt
@@ -108,6 +108,7 @@ add_llvm_target(AMDGPUCodeGen
AMDGPUTargetMachine.cpp
AMDGPUTargetObjectFile.cpp
AMDGPUTargetTransformInfo.cpp
+ AMDGPUTargetVerifier.cpp
AMDGPUUnifyDivergentExitNodes.cpp
AMDGPUUnifyMetadata.cpp
R600MachineCFGStructurizer.cpp
diff --git a/llvm/test/CodeGen/AMDGPU/tgt-verify.ll b/llvm/test/CodeGen/AMDGPU/tgt-verify.ll
new file mode 100644
index 00000000000000..f56ff992a56c2f
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/tgt-verify.ll
@@ -0,0 +1,62 @@
+; RUN: not llvm-tgt-verify %s -mtriple=amdgcn |& FileCheck %s
+
+define amdgpu_kernel void @test_mfma_f32_32x32x1f32_vecarg(ptr addrspace(1) %arg) #0 {
+; CHECK: Not uniform: %in.f32 = load <32 x float>, ptr addrspace(1) %gep, align 128
+; CHECK-NEXT: MFMA in control flow
+; CHECK-NEXT: %mfma = tail call <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.000000e+00, float 2.000000e+00, <32 x float> %in.f32, i32 1, i32 2, i32 3)
+s:
+ %tid = call i32 @llvm.amdgcn.workitem.id.x()
+ %gep = getelementptr inbounds <32 x float>, ptr addrspace(1) %arg, i32 %tid
+ %in.i32 = load <32 x i32>, ptr addrspace(1) %gep
+ %in.f32 = load <32 x float>, ptr addrspace(1) %gep
+
+ %0 = icmp eq <32 x i32> %in.i32, zeroinitializer
+ %div.br = extractelement <32 x i1> %0, i32 0
+ br i1 %div.br, label %if.3, label %else.0
+
+if.3:
+ br label %join
+
+else.0:
+ %mfma = tail call <32 x float> @llvm.amdgcn.mfma.f32.32x32x1f32(float 1.000000e+00, float 2.000000e+00, <32 x float> %in.f32, i32 1, i32 2, i32 3)
+ br label %join
+
+join:
+ ret void
+}
+
+define amdgpu_cs i32 @shader() {
+; CHECK: Shaders must return void
+ ret i32 0
+}
+
+define amdgpu_kernel void @store_const(ptr addrspace(4) %out, i32 %a, i32 %b) {
+; CHECK: Undefined behavior: Write to memory in const addrspace
+; CHECK-NEXT: store i32 %r, ptr addrspace(4) %out, align 4
+; CHECK-NEXT: Write to const memory
+; CHECK-NEXT: store i32 %r, ptr addrspace(4) %out, align 4
+ %r = add i32 %a, %b
+ store i32 %r, ptr addrspace(4) %out
+ ret void
+}
+
+define amdgpu_kernel void @kernel_callee(ptr %x) {
+ ret void
+}
+
+define amdgpu_kernel void @kernel_caller(ptr %x) {
+; CHECK: A kernel may not call a kernel
+; CHECK-NEXT: ptr @kernel_caller
+ call amdgpu_kernel void @kernel_callee(ptr %x)
+ ret void
+}
+
+
+; Function Attrs: nounwind
+define i65 @invalid_type(i65 %x) #0 {
+; CHECK: Int type is invalid.
+; CHECK-NEXT: %tmp2 = ashr i65 %x, 64
+entry:
+ %tmp2 = ashr i65 %x, 64
+ ret i65 %tmp2
+}
diff --git a/llvm/tools/llvm-tgt-verify/CMakeLists.txt b/llvm/tools/llvm-tgt-verify/CMakeLists.txt
new file mode 100644
index 00000000000000..fe47c85e6cdce7
--- /dev/null
+++ b/llvm/tools/llvm-tgt-verify/CMakeLists.txt
@@ -0,0 +1,34 @@
+set(LLVM_LINK_COMPONENTS
+ AllTargetsAsmParsers
+ AllTargetsCodeGens
+ AllTargetsDescs
+ AllTargetsInfos
+ Analysis
+ AsmPrinter
+ CodeGen
+ CodeGenTypes
+ Core
+ IRPrinter
+ IRReader
+ MC
+ MIRParser
+ Passes
+ Remarks
+ ScalarOpts
+ SelectionDAG
+ Support
+ Target
+ TargetParser
+ TransformUtils
+ Vectorize
+ )
+
+add_llvm_tool(llvm-tgt-verify
+ llvm-tgt-verify.cpp
+
+ DEPENDS
+ intrinsics_gen
+ SUPPORT_PLUGINS
+ )
+
+export_executable_symbols_for_plugins(llc)
diff --git a/llvm/tools/llvm-tgt-verify/llvm-tgt-verify.cpp b/llvm/tools/llvm-tgt-verify/llvm-tgt-verify.cpp
new file mode 100644
index 00000000000000..68422abd6f4cc0
--- /dev/null
+++ b/llvm/tools/llvm-tgt-verify/llvm-tgt-verify.cpp
@@ -0,0 +1,172 @@
+//===--- llvm-isel-fuzzer.cpp - Fuzzer for instruction selection ----------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Tool to fuzz instruction selection using libFuzzer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/InitializePasses.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Analysis/Lint.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IRReader/IRReader.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"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetVerifier.h"
+
+#include "llvm/Target/TargetVerify/AMDGPUTargetVerifier.h"
+
+#define DEBUG_TYPE "isel-fuzzer"
+
+using namespace llvm;
+
+static codegen::RegisterCodeGenFlags CGF;
+
+static cl::opt<std::string>
+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>
+ 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<char>
+ OptLevel("O",
+ cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
+ "(default = '-O2')"),
+ cl::Prefix, cl::init('2'));
+
+static cl::opt<std::string>
+ TargetTriple("mtriple", cl::desc("Override target triple for module"));
+
+static std::unique_ptr<TargetMachine> TM;
+
+static void handleLLVMFatalError(void *, const char *Message, bool) {
+ if (StacktraceAbort) {
+ dbgs() << "LLVM ERROR: " << Message << "\n"
+ << "Aborting.\n";
+ abort();
+ }
+}
+
+int main(int argc, char **argv) {
+ StringRef ExecName = argv[0];
+ InitLLVM X(argc, argv);
+
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+
+ PassRegistry *Registry = PassRegistry::getPassRegistry();
+ initializeCore(*Registry);
+ initializeCodeGen(*Registry);
+ initializeAnalysis(*Registry);
+ initializeTarget(*Registry);
+
+ cl::ParseCommandLineOptions(argc, argv);
+
+ if (TargetTriple.empty()) {
+ errs() << ExecName << ": -mtriple must be specified\n";
+ exit(1);
+ }
+
+ CodeGenOptLevel OLvl;
+ if (auto Level = CodeGenOpt::parseLevel(OptLevel)) {
+ OLvl = *Level;
+ } else {
+ errs() << ExecName << ": invalid optimization level.\n";
+ return 1;
+ }
+ ExitOnError ExitOnErr(std::string(ExecName) + ": error:");
+ TM = ExitOnErr(codegen::createTargetMachineForTriple(
+ Triple::normalize(TargetTriple), OLvl));
+ assert(TM && "Could not allocate target machine!");
+
+ // Make sure we print the summary and the current unit when LLVM errors out.
+ install_fatal_error_handler(handleLLVMFatalError, nullptr);
+
+ LLVMContext Context;
+ SMDiagnostic Err;
+ std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context);
+ if (!M) {
+ errs() << "Invalid mod\n";
+ return 1;
+ }
+ auto S = Triple::normalize(TargetTriple);
+ M->setTargetTriple(S);
+
+ PassInstrumentationCallbacks PIC;
+ StandardInstrumentations SI(Context, false/*debug PM*/,
+ false);
+ registerCodeGenCallback(PIC, *TM);
+
+ ModulePassManager MPM;
+ FunctionPassManager FPM;
+ //TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple()));
+
+ MachineFunctionAnalysisManager MFAM;
+ LoopAnalysisManager LAM;
+ FunctionAnalysisManager FAM;
+ CGSCCAnalysisManager CGAM;
+ ModuleAnalysisManager MAM;
+ PassBuilder PB(TM.get(), PipelineTuningOptions(), std::nullopt, &PIC);
+ PB.registerModuleAnalyses(MAM);
+ PB.registerCGSCCAnalyses(CGAM);
+ PB.registerFunctionAnalyses(FAM);
+ PB.registerLoopAnalyses(LAM);
+ PB.registerMachineFunctionAnalyses(MFAM);
+ PB.crossRegisterProxies(LAM, FAM, CGAM, MAM, &MFAM);
+
+ SI.registerCallbacks(PIC, &MAM);
+
+ //FAM.registerPass([&] { return TargetLibraryAnalysis(TLII); });
+
+ Triple TT(M->getTargetTriple());
+ if (!NoLint)
+ FPM.addPass(LintPass());
+ if (!NoVerify)
+ MPM.addPass(VerifierPass());
+ if (TT.isAMDGPU())
+ FPM.addPass(AMDGPUTargetVerifierPass());
+ else if (false) {} // ...
+ else
+ FPM.addPass(TargetVerifierPass());
+ MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
+
+ MPM.run(*M, MAM);
+
+ if (!M->IsValid)
+ return 1;
+
+ return 0;
+}
More information about the llvm-commits
mailing list