[llvm] [AutoUpgrade] Restrict NVVM bf16 intrinsic upgrades to integer storage types (PR #197387)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 4 03:43:54 PDT 2026
https://github.com/woruyu updated https://github.com/llvm/llvm-project/pull/197387
>From 3f7f0fa4ef0e21e35cc0f8cf4dce41cf465160bd Mon Sep 17 00:00:00 2001
From: woruyu <1214539920 at qq.com>
Date: Wed, 13 May 2026 16:33:04 +0800
Subject: [PATCH 1/4] [AutoUpgrade] Restrict NVVM bf16 intrinsic upgrades to
integer storage types
NVVM bf16 intrinsics used to be represented with integer storage types
before switching to bfloat signatures. AutoUpgrade currently upgrades any
matching NVVM bf16 intrinsic whose return type is not already bfloat.
That is too broad: invalid declarations such as a half-returning
llvm.nvvm.neg.bf16 are treated as old intrinsics and later crash when the
upgraded bfloat call is RAUW'ed with the original half-typed call.
Only perform this upgrade when the old signature uses integer storage
types with the same primitive bit widths as the new bf16 signature.
Otherwise leave the invalid intrinsic for the verifier to diagnose.
Add coverage for invalid half and mismatched integer signatures.
---
llvm/lib/IR/AutoUpgrade.cpp | 29 +++++++++++++++++--
.../nvvm-bf16-invalid-autoupgrade.ll | 9 ++++++
2 files changed, 35 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/Assembler/nvvm-bf16-invalid-autoupgrade.ll
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 88d0885d18da3..64694fff76a7a 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -1252,6 +1252,28 @@ static Intrinsic::ID shouldUpgradeNVPTXBF16Intrinsic(StringRef Name) {
return Intrinsic::not_intrinsic;
}
+static bool shouldUpgradeNVPTXBF16IntrinsicSignature(Function *F,
+ Intrinsic::ID IID) {
+ FunctionType *NewFnTy = Intrinsic::getType(F->getContext(), IID);
+ FunctionType *OldFnTy = F->getFunctionType();
+ auto IsOldBF16StorageTy = [](Type *OldTy, Type *NewTy) {
+ return OldTy->getScalarType()->isIntegerTy() &&
+ OldTy->getPrimitiveSizeInBits() == NewTy->getPrimitiveSizeInBits();
+ };
+
+ if (!IsOldBF16StorageTy(OldFnTy->getReturnType(), NewFnTy->getReturnType()))
+ return false;
+
+ if (OldFnTy->getNumParams() != NewFnTy->getNumParams())
+ return false;
+
+ for (unsigned I = 0, E = OldFnTy->getNumParams(); I != E; ++I)
+ if (!IsOldBF16StorageTy(OldFnTy->getParamType(I), NewFnTy->getParamType(I)))
+ return false;
+
+ return true;
+}
+
static bool consumeNVVMPtrAddrSpace(StringRef &Name) {
return Name.consume_front("local") || Name.consume_front("shared") ||
Name.consume_front("global") || Name.consume_front("constant") ||
@@ -1620,9 +1642,10 @@ static bool upgradeIntrinsicFunction1(Function *F, Function *&NewFn,
}
// Check for nvvm intrinsics that need a return type adjustment.
- if (!F->getReturnType()->getScalarType()->isBFloatTy()) {
+ {
Intrinsic::ID IID = shouldUpgradeNVPTXBF16Intrinsic(Name);
- if (IID != Intrinsic::not_intrinsic) {
+ if (IID != Intrinsic::not_intrinsic &&
+ shouldUpgradeNVPTXBF16IntrinsicSignature(F, IID)) {
NewFn = nullptr;
return true;
}
@@ -2886,7 +2909,7 @@ static Value *upgradeNVVMIntrinsicCall(StringRef Name, CallBase *CI,
} else {
Intrinsic::ID IID = shouldUpgradeNVPTXBF16Intrinsic(Name);
if (IID != Intrinsic::not_intrinsic &&
- !F->getReturnType()->getScalarType()->isBFloatTy()) {
+ shouldUpgradeNVPTXBF16IntrinsicSignature(F, IID)) {
rename(F);
Function *NewFn = Intrinsic::getOrInsertDeclaration(F->getParent(), IID);
SmallVector<Value *, 2> Args;
diff --git a/llvm/test/Assembler/nvvm-bf16-invalid-autoupgrade.ll b/llvm/test/Assembler/nvvm-bf16-invalid-autoupgrade.ll
new file mode 100644
index 0000000000000..4ae90fa392205
--- /dev/null
+++ b/llvm/test/Assembler/nvvm-bf16-invalid-autoupgrade.ll
@@ -0,0 +1,9 @@
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+
+; CHECK: intrinsic has incorrect return type!
+declare half @llvm.nvvm.neg.bf16(bfloat)
+
+define void @test() {
+ %t = call half @llvm.nvvm.neg.bf16(bfloat 1.0)
+ ret void
+}
>From 07c720b7768163ead027d2fde5e3f7f03c368126 Mon Sep 17 00:00:00 2001
From: woruyu <1214539920 at qq.com>
Date: Thu, 14 May 2026 15:44:06 +0800
Subject: [PATCH 2/4] fix: review
---
.../nvvm-bf16-invalid-autoupgrade.ll | 20 ++++++++++++++--
.../Assembler/nvvm-bf16-valid-autoupgrade.ll | 24 +++++++++++++++++++
2 files changed, 42 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/Assembler/nvvm-bf16-valid-autoupgrade.ll
diff --git a/llvm/test/Assembler/nvvm-bf16-invalid-autoupgrade.ll b/llvm/test/Assembler/nvvm-bf16-invalid-autoupgrade.ll
index 4ae90fa392205..b5a974c43e288 100644
--- a/llvm/test/Assembler/nvvm-bf16-invalid-autoupgrade.ll
+++ b/llvm/test/Assembler/nvvm-bf16-invalid-autoupgrade.ll
@@ -1,9 +1,25 @@
-; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+; RUN: not llvm-as -disable-output < %s 2>&1 | FileCheck %s
-; CHECK: intrinsic has incorrect return type!
+; CHECK-DAG: intrinsic has incorrect return type!
declare half @llvm.nvvm.neg.bf16(bfloat)
define void @test() {
%t = call half @llvm.nvvm.neg.bf16(bfloat 1.0)
ret void
}
+
+; CHECK-DAG: intrinsic has incorrect argument type!
+declare bfloat @llvm.nvvm.fmax.bf16(bfloat, half)
+
+define void @wrong_argument(bfloat %x, half %y) {
+ %t = call bfloat @llvm.nvvm.fmax.bf16(bfloat %x, half %y)
+ ret void
+}
+
+; CHECK-DAG: intrinsic has incorrect number of args. Expected 2, but got 1
+declare bfloat @llvm.nvvm.fmin.bf16(bfloat)
+
+define void @wrong_num_arguments(bfloat %x) {
+ %t = call bfloat @llvm.nvvm.fmin.bf16(bfloat %x)
+ ret void
+}
diff --git a/llvm/test/Assembler/nvvm-bf16-valid-autoupgrade.ll b/llvm/test/Assembler/nvvm-bf16-valid-autoupgrade.ll
new file mode 100644
index 0000000000000..dc75433680214
--- /dev/null
+++ b/llvm/test/Assembler/nvvm-bf16-valid-autoupgrade.ll
@@ -0,0 +1,24 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+
+declare i16 @llvm.nvvm.neg.bf16(i16)
+declare i32 @llvm.nvvm.neg.bf16x2(i32)
+
+define i16 @upgrade_neg_bf16(i16 %x) {
+; CHECK-LABEL: define i16 @upgrade_neg_bf16(
+; CHECK: [[ARG:%.*]] = bitcast i16 %x to bfloat
+; CHECK: [[CALL:%.*]] = call bfloat @llvm.nvvm.neg.bf16(bfloat [[ARG]])
+; CHECK: [[RET:%.*]] = bitcast bfloat [[CALL]] to i16
+; CHECK: ret i16 [[RET]]
+ %t = call i16 @llvm.nvvm.neg.bf16(i16 %x)
+ ret i16 %t
+}
+
+define i32 @upgrade_neg_bf16x2(i32 %x) {
+; CHECK-LABEL: define i32 @upgrade_neg_bf16x2(
+; CHECK: [[ARG:%.*]] = bitcast i32 %x to <2 x bfloat>
+; CHECK: [[CALL:%.*]] = call <2 x bfloat> @llvm.nvvm.neg.bf16x2(<2 x bfloat> [[ARG]])
+; CHECK: [[RET:%.*]] = bitcast <2 x bfloat> [[CALL]] to i32
+; CHECK: ret i32 [[RET]]
+ %t = call i32 @llvm.nvvm.neg.bf16x2(i32 %x)
+ ret i32 %t
+}
>From 1174bd02f4ec3194ded8ee244b802b28c604b24a Mon Sep 17 00:00:00 2001
From: woruyu <1214539920 at qq.com>
Date: Wed, 20 May 2026 20:08:35 +0800
Subject: [PATCH 3/4] fix: review
---
llvm/lib/IR/AutoUpgrade.cpp | 7 +++----
.../nvvm-bf16-invalid-autoupgrade.ll | 6 +++---
2 files changed, 6 insertions(+), 7 deletions(-)
rename llvm/test/{Assembler => Bitcode}/nvvm-bf16-invalid-autoupgrade.ll (74%)
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 64694fff76a7a..ae4d71f2c4d71 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -1252,8 +1252,7 @@ static Intrinsic::ID shouldUpgradeNVPTXBF16Intrinsic(StringRef Name) {
return Intrinsic::not_intrinsic;
}
-static bool shouldUpgradeNVPTXBF16IntrinsicSignature(Function *F,
- Intrinsic::ID IID) {
+static bool isLegacyNVPTXBF16IntSignature(Function *F, Intrinsic::ID IID) {
FunctionType *NewFnTy = Intrinsic::getType(F->getContext(), IID);
FunctionType *OldFnTy = F->getFunctionType();
auto IsOldBF16StorageTy = [](Type *OldTy, Type *NewTy) {
@@ -1645,7 +1644,7 @@ static bool upgradeIntrinsicFunction1(Function *F, Function *&NewFn,
{
Intrinsic::ID IID = shouldUpgradeNVPTXBF16Intrinsic(Name);
if (IID != Intrinsic::not_intrinsic &&
- shouldUpgradeNVPTXBF16IntrinsicSignature(F, IID)) {
+ isLegacyNVPTXBF16IntSignature(F, IID)) {
NewFn = nullptr;
return true;
}
@@ -2909,7 +2908,7 @@ static Value *upgradeNVVMIntrinsicCall(StringRef Name, CallBase *CI,
} else {
Intrinsic::ID IID = shouldUpgradeNVPTXBF16Intrinsic(Name);
if (IID != Intrinsic::not_intrinsic &&
- shouldUpgradeNVPTXBF16IntrinsicSignature(F, IID)) {
+ isLegacyNVPTXBF16IntSignature(F, IID)) {
rename(F);
Function *NewFn = Intrinsic::getOrInsertDeclaration(F->getParent(), IID);
SmallVector<Value *, 2> Args;
diff --git a/llvm/test/Assembler/nvvm-bf16-invalid-autoupgrade.ll b/llvm/test/Bitcode/nvvm-bf16-invalid-autoupgrade.ll
similarity index 74%
rename from llvm/test/Assembler/nvvm-bf16-invalid-autoupgrade.ll
rename to llvm/test/Bitcode/nvvm-bf16-invalid-autoupgrade.ll
index b5a974c43e288..6328a7430cf93 100644
--- a/llvm/test/Assembler/nvvm-bf16-invalid-autoupgrade.ll
+++ b/llvm/test/Bitcode/nvvm-bf16-invalid-autoupgrade.ll
@@ -1,6 +1,6 @@
; RUN: not llvm-as -disable-output < %s 2>&1 | FileCheck %s
-; CHECK-DAG: intrinsic has incorrect return type!
+; CHECK: intrinsic has incorrect return type!
declare half @llvm.nvvm.neg.bf16(bfloat)
define void @test() {
@@ -8,7 +8,7 @@ define void @test() {
ret void
}
-; CHECK-DAG: intrinsic has incorrect argument type!
+; CHECK: intrinsic has incorrect argument type!
declare bfloat @llvm.nvvm.fmax.bf16(bfloat, half)
define void @wrong_argument(bfloat %x, half %y) {
@@ -16,7 +16,7 @@ define void @wrong_argument(bfloat %x, half %y) {
ret void
}
-; CHECK-DAG: intrinsic has incorrect number of args. Expected 2, but got 1
+; CHECK: intrinsic has incorrect number of args. Expected 2, but got 1
declare bfloat @llvm.nvvm.fmin.bf16(bfloat)
define void @wrong_num_arguments(bfloat %x) {
>From e6042528cc15d1f0702927f660cd990f2ac16c47 Mon Sep 17 00:00:00 2001
From: woruyu <1214539920 at qq.com>
Date: Thu, 4 Jun 2026 18:43:31 +0800
Subject: [PATCH 4/4] fix: test
---
llvm/test/Bitcode/nvvm-bf16-invalid-autoupgrade.ll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/test/Bitcode/nvvm-bf16-invalid-autoupgrade.ll b/llvm/test/Bitcode/nvvm-bf16-invalid-autoupgrade.ll
index 6328a7430cf93..24b52d33be145 100644
--- a/llvm/test/Bitcode/nvvm-bf16-invalid-autoupgrade.ll
+++ b/llvm/test/Bitcode/nvvm-bf16-invalid-autoupgrade.ll
@@ -1,6 +1,6 @@
; RUN: not llvm-as -disable-output < %s 2>&1 | FileCheck %s
-; CHECK: intrinsic has incorrect return type!
+; CHECK: intrinsic return type expected bfloat, but got half
declare half @llvm.nvvm.neg.bf16(bfloat)
define void @test() {
@@ -8,7 +8,7 @@ define void @test() {
ret void
}
-; CHECK: intrinsic has incorrect argument type!
+; CHECK: intrinsic argument 1 type expected bfloat, but got half
declare bfloat @llvm.nvvm.fmax.bf16(bfloat, half)
define void @wrong_argument(bfloat %x, half %y) {
More information about the llvm-commits
mailing list