[llvm] [LLVM][Verifier] Improve diagnostic messages for Intrinsics in Verifier (PR #185641)

Kirill Vedernikov via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 10 06:02:13 PDT 2026


https://github.com/kvederni created https://github.com/llvm/llvm-project/pull/185641

Introduce IntrinsicDiagnosticsProvider, a base class that allows to append detailed information to the standard LLVM error messages emitted when an intrinsic is called or declared with an incorrect signature.

The original messages are preserved unchanged. The NVVM detail is only appended when the intrinsic name starts with "llvm.nvvm.". Non-NVVM intrinsics produce the standard messages and all existing LLVM tests pass unmodified.

---

## Case 1: Wrong return type (with explicit declaration)

Input: `declare i16 @llvm.nvvm.sad.i(i32, i32, i32)` — return type `i16` instead of `i32`.

**Before:**
```
Intrinsic has incorrect return type!
ptr @llvm.nvvm.sad.i
```

**After:**
```
Intrinsic has incorrect return type!
declared return type is 'i16', expected 'i32' in canonical signature 'i32 (i32, i32, i32)'
ptr @llvm.nvvm.sad.i
```

---

## Case 2: Wrong argument type at call site (with correct declaration)

Input: `declare i32 @llvm.nvvm.sad.ui(i32, i32, i32)` + `call i32 @llvm.nvvm.sad.ui(i32 %x, i32 %y, i16 %z)` — third arg `i16` instead of `i32`.

**Before:**
```
Intrinsic called with incompatible signature
  %1 = call i32 @llvm.nvvm.sad.ui(i32 %x, i32 %y, i16 %z)
```

**After:**
```
Intrinsic called with incompatible signature
argument 3 type mismatch (expected i32, got i16)
  %1 = call i32 @llvm.nvvm.sad.ui(i32 %x, i32 %y, i16 %z)
```

---

## Case 2b: Wrong argument type in declaration

Input: `declare i32 @llvm.nvvm.sad.ui(i32, i32, i16)` — third param `i16` instead of `i32`.

**Before:**
```
Intrinsic has incorrect argument type!
ptr @llvm.nvvm.sad.ui
```

**After:**
```
Intrinsic has incorrect argument type!
declared signature is 'i32 (i32, i32, i16)', canonical signature is 'i32 (i32, i32, i32)'
ptr @llvm.nvvm.sad.ui
```

---

## Case 3: Wrong argument count (with explicit declaration)

Input: `call i64 @llvm.nvvm.sad.ull(i64 %x, i64 %y, i64 %z, i64 %w)` — 4 args instead of 3.

**Before:**
```
Intrinsic called with incompatible signature
  %1 = call i64 @llvm.nvvm.sad.ull(i64 %x, i64 %y, i64 %z, i64 %w)
```

**After:**
```
Intrinsic called with incompatible signature
wrong number of arguments (expected 3, got 4), expected signature: i64 (i64, i64, i64), got signature: i64 (i64, i64, i64, i64)
  %1 = call i64 @llvm.nvvm.sad.ull(i64 %x, i64 %y, i64 %z, i64 %w)
```

---

## Case 4: Wrong return type (no declaration)

Input: `call i16 @llvm.nvvm.sad.i(...)` with no `declare` — parser auto-resolves the forward
reference and rejects the mismatched signature.

**Before:**
```
<stdin>:1:65: error: invalid intrinsic signature
define i16 @test(...) { ... }
                ^
```

**After:**
```
<stdin>:1:65: error: invalid intrinsic signature
for 'llvm.nvvm.sad.i': got i16 (i32, i32, i32), expected i32 (i32, i32, i32)
define i16 @test(...) { ... }
                ^
```

---

## Case 5: Wrong argument type (no declaration)

Input: `call i32 @llvm.nvvm.sad.ui(i32 %x, i32 %y, i16 %z)` with no `declare`.

**Before:**
```
<stdin>:1:65: error: invalid intrinsic signature
define i32 @test(...) { ... }
                ^
```

**After:**
```
<stdin>:1:65: error: invalid intrinsic signature
for 'llvm.nvvm.sad.ui': got i32 (i32, i32, i16), expected i32 (i32, i32, i32)
define i32 @test(...) { ... }
                ^
```

---

## Case 6: Wrong argument count (no declaration)

Input: `call i64 @llvm.nvvm.sad.ull(i64 %x, i64 %y, i64 %z, i64 %w)` with no `declare`.

**Before:**
```
<stdin>:1:65: error: invalid intrinsic signature
define i64 @test(...) { ... }
                ^
```

**After:**
```
<stdin>:1:65: error: invalid intrinsic signature
for 'llvm.nvvm.sad.ull': got i64 (i64, i64, i64, i64), expected i64 (i64, i64, i64)
define i64 @test(...) { ... }
                ^
```

>From 5829d48d6950cc6868bcd32e44e21de01aff590c Mon Sep 17 00:00:00 2001
From: Kirill Vedernikov <kvedernikov at nvidia.com>
Date: Tue, 10 Mar 2026 12:53:28 +0100
Subject: [PATCH] [LLVM][Verifier] Improve diagnostic messages for Intrinsics
 in Verifier

Introduce IntrinsicDiagnosticsProvider, a base class that allows
to append detailed information to the standard LLVM error messages
emitted when an intrinsic is called or declared with an incorrect
signature.

The original messages are preserved unchanged. The NVVM detail is only
appended when the intrinsic name starts with "llvm.nvvm.". Non-NVVM
intrinsics produce the standard messages and all existing LLVM tests
pass unmodified.
---
 llvm/include/llvm/IR/IntrinsicDiagnostics.h   |  72 ++++++++++
 llvm/lib/AsmParser/LLParser.cpp               |  13 +-
 llvm/lib/IR/CMakeLists.txt                    |   2 +
 llvm/lib/IR/IntrinsicDiagnostics.cpp          |  51 ++++++++
 llvm/lib/IR/NVVMIntrinsicDiagnostics.cpp      | 123 ++++++++++++++++++
 llvm/lib/IR/Verifier.cpp                      |  35 ++++-
 .../test/CodeGen/NVPTX/sad-intrins-invalid.ll |  69 ++++++++++
 7 files changed, 357 insertions(+), 8 deletions(-)
 create mode 100644 llvm/include/llvm/IR/IntrinsicDiagnostics.h
 create mode 100644 llvm/lib/IR/IntrinsicDiagnostics.cpp
 create mode 100644 llvm/lib/IR/NVVMIntrinsicDiagnostics.cpp
 create mode 100644 llvm/test/CodeGen/NVPTX/sad-intrins-invalid.ll

diff --git a/llvm/include/llvm/IR/IntrinsicDiagnostics.h b/llvm/include/llvm/IR/IntrinsicDiagnostics.h
new file mode 100644
index 0000000000000..31fd31818bcee
--- /dev/null
+++ b/llvm/include/llvm/IR/IntrinsicDiagnostics.h
@@ -0,0 +1,72 @@
+//===- IntrinsicDiagnostics.h - Intrinsic diagnostic hooks ------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines IntrinsicDiagnosticsProvider, a virtual base class that targets
+// can subclass to append extra detail lines to intrinsic signature mismatch
+// diagnostics.  The default implementations are no-ops, leaving the standard
+// upstream message unchanged.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_IR_INTRINSICDIAGNOSTICS_H
+#define LLVM_IR_INTRINSICDIAGNOSTICS_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+class FunctionType;
+class raw_ostream;
+
+/// Interface for appending target-specific detail lines to diagnostics emitted
+/// when an intrinsic is called or declared with an incorrect signature.
+///
+/// Subclasses are registered via \c registerProvider.  At diagnostic emission
+/// time each registered provider may write additional lines to the output
+/// stream; the standard upstream message is always emitted first by the caller.
+class IntrinsicDiagnosticsProvider {
+public:
+  virtual ~IntrinsicDiagnosticsProvider() = default;
+
+  /// Optionally appends detail for a call-site signature mismatch.
+  virtual void getSignatureMismatch(StringRef IntrName, FunctionType *DeclFTy,
+                                    FunctionType *CallFTy,
+                                    raw_ostream &OS) const {}
+
+  /// Optionally appends detail for a verifier return-type mismatch.
+  virtual void getReturnTypeMismatch(StringRef IntrName, FunctionType *IFTy,
+                                     raw_ostream &OS) const {}
+
+  /// Optionally appends detail for a verifier argument-type mismatch.
+  virtual void getArgTypeMismatch(StringRef IntrName, FunctionType *IFTy,
+                                  raw_ostream &OS) const {}
+
+  /// Optionally appends detail for a parser-level signature mismatch.
+  /// \p ExpectedFTy is the canonical intrinsic type, or null for overloaded
+  /// intrinsics.
+  virtual void getParserMismatch(StringRef IntrName, FunctionType *CallFTy,
+                                 FunctionType *ExpectedFTy,
+                                 raw_ostream &OS) const {}
+
+  /// Registers \p P as a diagnostics provider.  Does not take ownership;
+  /// \p P must outlive all diagnostic queries.
+  static void registerProvider(IntrinsicDiagnosticsProvider *P);
+
+  /// Asks all registered providers to append detail to \p OS.
+  static void querySignatureMismatch(StringRef IntrName, FunctionType *DeclFTy,
+                                     FunctionType *CallFTy, raw_ostream &OS);
+  static void queryReturnTypeMismatch(StringRef IntrName, FunctionType *IFTy,
+                                      raw_ostream &OS);
+  static void queryArgTypeMismatch(StringRef IntrName, FunctionType *IFTy,
+                                   raw_ostream &OS);
+  static void queryParserMismatch(StringRef IntrName, FunctionType *CallFTy,
+                                  FunctionType *ExpectedFTy, raw_ostream &OS);
+};
+
+} // namespace llvm
+
+#endif // LLVM_IR_INTRINSICDIAGNOSTICS_H
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 551b88d8b435b..aa735abc48639 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -36,6 +36,7 @@
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/InstIterator.h"
 #include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicDiagnostics.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/LLVMContext.h"
@@ -354,7 +355,17 @@ bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
           if (!UpgradeIntrinsicFunction(TmpF, NewF)) {
             if (IID == Intrinsic::not_intrinsic)
               return error(Info.second, "unknown intrinsic '" + Name + "'");
-            return error(Info.second, "invalid intrinsic signature");
+            FunctionType *ExpFTy = nullptr;
+            if (!Intrinsic::isOverloaded(IID)) {
+              SmallVector<Type *, 4> OverloadTys;
+              ExpFTy =
+                  Intrinsic::getType(M->getContext(), IID, OverloadTys);
+            }
+            std::string Msg = "invalid intrinsic signature";
+            raw_string_ostream SS(Msg);
+            IntrinsicDiagnosticsProvider::queryParserMismatch(
+                Name, CB->getFunctionType(), ExpFTy, SS);
+            return error(Info.second, Msg);
           }
 
           U.set(TmpF);
diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt
index 08bac979d4c90..393ed97357b8b 100644
--- a/llvm/lib/IR/CMakeLists.txt
+++ b/llvm/lib/IR/CMakeLists.txt
@@ -35,6 +35,8 @@ add_llvm_component_library(LLVMCore
   GVMaterializer.cpp
   Globals.cpp
   Intrinsics.cpp
+  IntrinsicDiagnostics.cpp
+  NVVMIntrinsicDiagnostics.cpp
   NVVMIntrinsicUtils.cpp
   IRBuilder.cpp
   IRPrintingPasses.cpp
diff --git a/llvm/lib/IR/IntrinsicDiagnostics.cpp b/llvm/lib/IR/IntrinsicDiagnostics.cpp
new file mode 100644
index 0000000000000..1d374dd4ebfe5
--- /dev/null
+++ b/llvm/lib/IR/IntrinsicDiagnostics.cpp
@@ -0,0 +1,51 @@
+//===-- IntrinsicDiagnostics.cpp - Intrinsic diagnostic hooks -------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/IntrinsicDiagnostics.h"
+#include "llvm/ADT/SmallVector.h"
+
+using namespace llvm;
+
+static SmallVector<IntrinsicDiagnosticsProvider *, 4> &getProviders() {
+  static SmallVector<IntrinsicDiagnosticsProvider *, 4> Providers;
+  return Providers;
+}
+
+void IntrinsicDiagnosticsProvider::registerProvider(
+    IntrinsicDiagnosticsProvider *P) {
+  getProviders().push_back(P);
+}
+
+void IntrinsicDiagnosticsProvider::querySignatureMismatch(
+    StringRef IntrName, FunctionType *DeclFTy, FunctionType *CallFTy,
+    raw_ostream &OS) {
+  for (auto *P : getProviders())
+    P->getSignatureMismatch(IntrName, DeclFTy, CallFTy, OS);
+}
+
+void IntrinsicDiagnosticsProvider::queryReturnTypeMismatch(StringRef IntrName,
+                                                           FunctionType *IFTy,
+                                                           raw_ostream &OS) {
+  for (auto *P : getProviders())
+    P->getReturnTypeMismatch(IntrName, IFTy, OS);
+}
+
+void IntrinsicDiagnosticsProvider::queryArgTypeMismatch(StringRef IntrName,
+                                                        FunctionType *IFTy,
+                                                        raw_ostream &OS) {
+  for (auto *P : getProviders())
+    P->getArgTypeMismatch(IntrName, IFTy, OS);
+}
+
+void IntrinsicDiagnosticsProvider::queryParserMismatch(StringRef IntrName,
+                                                       FunctionType *CallFTy,
+                                                       FunctionType *ExpectedFTy,
+                                                       raw_ostream &OS) {
+  for (auto *P : getProviders())
+    P->getParserMismatch(IntrName, CallFTy, ExpectedFTy, OS);
+}
diff --git a/llvm/lib/IR/NVVMIntrinsicDiagnostics.cpp b/llvm/lib/IR/NVVMIntrinsicDiagnostics.cpp
new file mode 100644
index 0000000000000..6b68cb889b8e4
--- /dev/null
+++ b/llvm/lib/IR/NVVMIntrinsicDiagnostics.cpp
@@ -0,0 +1,123 @@
+//===-- NVVMIntrinsicDiagnostics.cpp - Detailed NVVM diags ----------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Registers a diagnostics provider that appends detailed information to error
+// messages for NVVM intrinsic signature mismatches.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/IntrinsicDiagnostics.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+static bool isNVVMIntrinsic(StringRef Name) {
+  return Name.starts_with("llvm.nvvm.");
+}
+
+/// Returns the canonical FunctionType for a non-overloaded intrinsic, or null.
+static FunctionType *getCanonicalType(StringRef Name, LLVMContext &Ctx) {
+  Intrinsic::ID ID = Intrinsic::lookupIntrinsicID(Name);
+  if (ID == Intrinsic::not_intrinsic || Intrinsic::isOverloaded(ID))
+    return nullptr;
+  SmallVector<Type *, 4> OverloadTys;
+  return Intrinsic::getType(Ctx, ID, OverloadTys);
+}
+
+namespace {
+
+class NVVMIntrinsicDiagnosticsProvider : public IntrinsicDiagnosticsProvider {
+public:
+  void getSignatureMismatch(StringRef Name, FunctionType *DeclFTy,
+                            FunctionType *CallFTy,
+                            raw_ostream &OS) const override {
+    if (!isNVVMIntrinsic(Name))
+      return;
+    if (DeclFTy->getReturnType() != CallFTy->getReturnType()) {
+      OS << "\nreturn type mismatch (expected ";
+      DeclFTy->getReturnType()->print(OS);
+      OS << ", got ";
+      CallFTy->getReturnType()->print(OS);
+      OS << ")";
+    } else if (DeclFTy->getNumParams() != CallFTy->getNumParams()) {
+      OS << "\nwrong number of arguments (expected " << DeclFTy->getNumParams()
+         << ", got " << CallFTy->getNumParams()
+         << "), expected signature: ";
+      DeclFTy->print(OS);
+      OS << ", got signature: ";
+      CallFTy->print(OS);
+    } else {
+      for (unsigned I = 0, E = DeclFTy->getNumParams(); I < E; ++I) {
+        if (DeclFTy->getParamType(I) != CallFTy->getParamType(I)) {
+          OS << "\nargument " << (I + 1) << " type mismatch (expected ";
+          DeclFTy->getParamType(I)->print(OS);
+          OS << ", got ";
+          CallFTy->getParamType(I)->print(OS);
+          OS << ")";
+          break;
+        }
+      }
+    }
+  }
+
+  void getReturnTypeMismatch(StringRef Name, FunctionType *IFTy,
+                             raw_ostream &OS) const override {
+    if (!isNVVMIntrinsic(Name))
+      return;
+    OS << "\ndeclared return type is '";
+    IFTy->getReturnType()->print(OS);
+    OS << "'";
+    if (FunctionType *ExpFTy = getCanonicalType(Name, IFTy->getContext())) {
+      OS << ", expected '";
+      ExpFTy->getReturnType()->print(OS);
+      OS << "' in canonical signature '";
+      ExpFTy->print(OS);
+      OS << "'";
+    }
+  }
+
+  void getArgTypeMismatch(StringRef Name, FunctionType *IFTy,
+                          raw_ostream &OS) const override {
+    if (!isNVVMIntrinsic(Name))
+      return;
+    OS << "\ndeclared signature is '";
+    IFTy->print(OS);
+    OS << "'";
+    if (FunctionType *ExpFTy = getCanonicalType(Name, IFTy->getContext())) {
+      OS << ", canonical signature is '";
+      ExpFTy->print(OS);
+      OS << "'";
+    }
+  }
+
+  void getParserMismatch(StringRef Name, FunctionType *CallFTy,
+                         FunctionType *ExpectedFTy,
+                         raw_ostream &OS) const override {
+    if (!isNVVMIntrinsic(Name))
+      return;
+    OS << "\nfor '" << Name << "': got ";
+    CallFTy->print(OS);
+    if (ExpectedFTy) {
+      OS << ", expected ";
+      ExpectedFTy->print(OS);
+    }
+  }
+};
+
+NVVMIntrinsicDiagnosticsProvider TheProvider;
+
+struct ProviderRegistrar {
+  ProviderRegistrar() {
+    IntrinsicDiagnosticsProvider::registerProvider(&TheProvider);
+  }
+};
+static ProviderRegistrar TheRegistrar;
+
+} // anonymous namespace
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 3784ee00811f8..ef6a129ad5c2f 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -91,6 +91,7 @@
 #include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicDiagnostics.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicsAArch64.h"
@@ -3865,9 +3866,17 @@ void Verifier::visitCallBase(CallBase &Call) {
   Function *Callee =
       dyn_cast<Function>(Call.getCalledOperand()->stripPointerCasts());
   bool IsIntrinsic = Callee && Callee->isIntrinsic();
-  if (IsIntrinsic)
-    Check(Callee->getFunctionType() == FTy,
-          "Intrinsic called with incompatible signature", Call);
+  if (IsIntrinsic) {
+    FunctionType *DeclFTy = cast<FunctionType>(Callee->getValueType());
+    if (DeclFTy != FTy) {
+      std::string Msg = "Intrinsic called with incompatible signature";
+      raw_string_ostream SS(Msg);
+      IntrinsicDiagnosticsProvider::querySignatureMismatch(
+          Callee->getName(), DeclFTy, FTy, SS);
+      CheckFailed(Msg, Call);
+      return;
+    }
+  }
 
   // Verify if the calling convention of the callee is callable.
   Check(isCallableCC(Call.getCallingConv()),
@@ -5855,10 +5864,22 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
   SmallVector<Type *, 4> ArgTys;
   Intrinsic::MatchIntrinsicTypesResult Res =
       Intrinsic::matchIntrinsicSignature(IFTy, TableRef, ArgTys);
-  Check(Res != Intrinsic::MatchIntrinsicTypes_NoMatchRet,
-        "Intrinsic has incorrect return type!", IF);
-  Check(Res != Intrinsic::MatchIntrinsicTypes_NoMatchArg,
-        "Intrinsic has incorrect argument type!", IF);
+  if (Res == Intrinsic::MatchIntrinsicTypes_NoMatchRet) {
+    std::string Msg = "Intrinsic has incorrect return type!";
+    raw_string_ostream SS(Msg);
+    IntrinsicDiagnosticsProvider::queryReturnTypeMismatch(
+        IF->getName(), IFTy, SS);
+    CheckFailed(Msg, IF);
+    return;
+  }
+  if (Res == Intrinsic::MatchIntrinsicTypes_NoMatchArg) {
+    std::string Msg = "Intrinsic has incorrect argument type!";
+    raw_string_ostream SS(Msg);
+    IntrinsicDiagnosticsProvider::queryArgTypeMismatch(
+        IF->getName(), IFTy, SS);
+    CheckFailed(Msg, IF);
+    return;
+  }
 
   // Verify if the intrinsic call matches the vararg property.
   if (IsVarArg)
diff --git a/llvm/test/CodeGen/NVPTX/sad-intrins-invalid.ll b/llvm/test/CodeGen/NVPTX/sad-intrins-invalid.ll
new file mode 100644
index 0000000000000..f91e51beb4bf3
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/sad-intrins-invalid.ll
@@ -0,0 +1,69 @@
+; RUN: split-file %s %t
+; RUN: not llc -mtriple=nvptx64 -mcpu=sm_50 < %t/main.ll 2>&1 | FileCheck %s
+; RUN: not llc -mtriple=nvptx64 -mcpu=sm_50 < %t/parser-bad-ret.ll 2>&1 | FileCheck %s --check-prefix=PARSER-RET
+; RUN: not llc -mtriple=nvptx64 -mcpu=sm_50 < %t/parser-bad-arg.ll 2>&1 | FileCheck %s --check-prefix=PARSER-ARG
+; RUN: not llc -mtriple=nvptx64 -mcpu=sm_50 < %t/parser-bad-count.ll 2>&1 | FileCheck %s --check-prefix=PARSER-COUNT
+
+; CHECK: Intrinsic has incorrect return type!
+; CHECK-NEXT: declared return type is 'i16', expected 'i32' in canonical signature 'i32 (i32, i32, i32)'
+; CHECK: Intrinsic called with incompatible signature
+; CHECK-NEXT: argument 3 type mismatch (expected i32, got i16)
+; CHECK: Intrinsic called with incompatible signature
+; CHECK-NEXT: wrong number of arguments (expected 3, got 4), expected signature: i64 (i64, i64, i64), got signature: i64 (i64, i64, i64, i64)
+
+; PARSER-RET: invalid intrinsic signature
+; PARSER-RET-NEXT: for 'llvm.nvvm.sad.i': got i16 (i32, i32, i32), expected i32 (i32, i32, i32)
+
+; PARSER-ARG: invalid intrinsic signature
+; PARSER-ARG-NEXT: for 'llvm.nvvm.sad.ui': got i32 (i32, i32, i16), expected i32 (i32, i32, i32)
+
+; PARSER-COUNT: invalid intrinsic signature
+; PARSER-COUNT-NEXT: for 'llvm.nvvm.sad.ull': got i64 (i64, i64, i64, i64), expected i64 (i64, i64, i64)
+
+;--- main.ll
+
+; Invalid return type: @llvm.nvvm.sad.i declared with i16 return instead of i32.
+define i16 @test_bad_ret(i32 %x, i32 %y, i32 %z) {
+  %1 = call i16 @llvm.nvvm.sad.i(i32 %x, i32 %y, i32 %z)
+  ret i16 %1
+}
+
+; Invalid argument type: @llvm.nvvm.sad.ui called with i16 third arg instead of i32.
+define i32 @test_bad_arg(i32 %x, i32 %y, i16 %z) {
+  %1 = call i32 @llvm.nvvm.sad.ui(i32 %x, i32 %y, i16 %z)
+  ret i32 %1
+}
+
+; Invalid argument count: @llvm.nvvm.sad.ull called with 4 args instead of 3.
+define i64 @test_bad_arg_count(i64 %x, i64 %y, i64 %z, i64 %w) {
+  %1 = call i64 @llvm.nvvm.sad.ull(i64 %x, i64 %y, i64 %z, i64 %w)
+  ret i64 %1
+}
+
+declare i16 @llvm.nvvm.sad.i(i32, i32, i32)
+declare i32 @llvm.nvvm.sad.ui(i32, i32, i32)
+declare i64 @llvm.nvvm.sad.ull(i64, i64, i64)
+
+;--- parser-bad-ret.ll
+
+; Parser error: no declaration, intrinsic called with wrong return type.
+define i16 @test_parser_bad_ret(i32 %x, i32 %y, i32 %z) {
+  %1 = call i16 @llvm.nvvm.sad.i(i32 %x, i32 %y, i32 %z)
+  ret i16 %1
+}
+
+;--- parser-bad-arg.ll
+
+; Parser error: no declaration, intrinsic called with wrong argument type.
+define i32 @test_parser_bad_arg(i32 %x, i32 %y, i16 %z) {
+  %1 = call i32 @llvm.nvvm.sad.ui(i32 %x, i32 %y, i16 %z)
+  ret i32 %1
+}
+
+;--- parser-bad-count.ll
+
+; Parser error: no declaration, intrinsic called with wrong argument count.
+define i64 @test_parser_bad_count(i64 %x, i64 %y, i64 %z, i64 %w) {
+  %1 = call i64 @llvm.nvvm.sad.ull(i64 %x, i64 %y, i64 %z, i64 %w)
+  ret i64 %1
+}



More information about the llvm-commits mailing list