[llvm] [NVPTX] Add range attributes for cluster rank intrinsics to preserve signed non-negativity (PR #224727)
Daniel Donenfeld via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 10:54:32 PDT 2026
https://github.com/daniel-donenfeld updated https://github.com/llvm/llvm-project/pull/224727
>From 140af05faa24eda3761469e0dca7a81c0d62409d Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Fri, 18 Sep 2026 19:50:52 +0000
Subject: [PATCH 1/3] [NVPTX] Add InstCombine tests for cluster rank ranges
---
.../InstCombine/NVPTX/intrinsic-range.ll | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/NVPTX/intrinsic-range.ll
diff --git a/llvm/test/Transforms/InstCombine/NVPTX/intrinsic-range.ll b/llvm/test/Transforms/InstCombine/NVPTX/intrinsic-range.ll
new file mode 100644
index 0000000000000..4a086946cca3f
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/NVPTX/intrinsic-range.ll
@@ -0,0 +1,38 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -S -passes=instcombine -mtriple=nvptx64-nvidia-cuda | FileCheck %s
+
+declare i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
+declare i32 @llvm.nvvm.read.ptx.sreg.cluster.nctarank()
+
+define i1 @ctarank_is_nonnegative() {
+; CHECK-LABEL: define i1 @ctarank_is_nonnegative() {
+; CHECK-NEXT: [[RANK:%.*]] = call i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[RANK]], -1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %rank = call i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
+ %cmp = icmp sge i32 %rank, 0
+ ret i1 %cmp
+}
+
+define i1 @nctarank_is_positive() {
+; CHECK-LABEL: define i1 @nctarank_is_positive() {
+; CHECK-NEXT: [[RANK:%.*]] = call i32 @llvm.nvvm.read.ptx.sreg.cluster.nctarank()
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[RANK]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %rank = call i32 @llvm.nvvm.read.ptx.sreg.cluster.nctarank()
+ %cmp = icmp sgt i32 %rank, 0
+ ret i1 %cmp
+}
+
+define i32 @ctarank_sdiv_16() {
+; CHECK-LABEL: define i32 @ctarank_sdiv_16() {
+; CHECK-NEXT: [[RANK:%.*]] = call i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
+; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[RANK]], 16
+; CHECK-NEXT: ret i32 [[DIV]]
+;
+ %rank = call i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
+ %div = sdiv i32 %rank, 16
+ ret i32 %div
+}
>From 784d2ac4e1e8a6a434f7bb427e2299132a6572da Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Fri, 11 Sep 2026 20:18:17 +0000
Subject: [PATCH 2/3] Upstream cluster cta metadata
---
llvm/include/llvm/IR/IntrinsicsNVVM.td | 8 ++++++--
llvm/test/CodeGen/NVPTX/intr-range.ll | 5 +++++
.../Transforms/InstCombine/NVPTX/intrinsic-range.ll | 10 +++-------
3 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/llvm/include/llvm/IR/IntrinsicsNVVM.td b/llvm/include/llvm/IR/IntrinsicsNVVM.td
index 4fb9aef1596e0..2ca9bea8b719b 100644
--- a/llvm/include/llvm/IR/IntrinsicsNVVM.td
+++ b/llvm/include/llvm/IR/IntrinsicsNVVM.td
@@ -2758,8 +2758,12 @@ defm int_nvvm_read_ptx_sreg_nclusterid : PTXReadSRegIntrinsicNB_v4i32<MAX_GRID_N
defm int_nvvm_read_ptx_sreg_cluster_ctaid : PTXReadSRegIntrinsicNB_v4i32<MAX_GRID_ID_RANGE>;
defm int_nvvm_read_ptx_sreg_cluster_nctaid : PTXReadSRegIntrinsicNB_v4i32<MAX_GRID_NID_RANGE>;
-def int_nvvm_read_ptx_sreg_cluster_ctarank : PTXReadSRegIntrinsicNB_r32;
-def int_nvvm_read_ptx_sreg_cluster_nctarank : PTXReadSRegIntrinsicNB_r32;
+// ctarank is an index within cluster CTA ranks (non-negative).
+// nctarank is the number of CTA ranks in cluster (positive).
+def int_nvvm_read_ptx_sreg_cluster_ctarank
+ : PTXReadSRegIntrinsicNB_r32<[Range<RetIndex, 0, !add(MAX_GRID_SIZE_X, 1)>]>;
+def int_nvvm_read_ptx_sreg_cluster_nctarank
+ : PTXReadSRegIntrinsicNB_r32<[Range<RetIndex, 1, !add(MAX_GRID_SIZE_X, 1)>]>;
//
// Reserved Shared Memory Intrinsics
diff --git a/llvm/test/CodeGen/NVPTX/intr-range.ll b/llvm/test/CodeGen/NVPTX/intr-range.ll
index 1fb43dc038f25..b82704aefab1a 100644
--- a/llvm/test/CodeGen/NVPTX/intr-range.ll
+++ b/llvm/test/CodeGen/NVPTX/intr-range.ll
@@ -178,6 +178,8 @@ define ptx_kernel i32 @test_cluster_dim() "nvvm.cluster_dim"="4,4,1" {
; DEFAULT-DAG: declare noundef range(i32 1, 65536) i32 @llvm.nvvm.read.ptx.sreg.cluster.nctaid.y()
; DEFAULT-DAG: declare noundef range(i32 1, 65536) i32 @llvm.nvvm.read.ptx.sreg.cluster.nctaid.z()
; DEFAULT-DAG: declare noundef range(i32 0, 1) i32 @llvm.nvvm.read.ptx.sreg.cluster.nctaid.w()
+; DEFAULT-DAG: declare noundef range(i32 0, -2147483648) i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
+; DEFAULT-DAG: declare noundef range(i32 1, -2147483648) i32 @llvm.nvvm.read.ptx.sreg.cluster.nctarank()
declare i32 @llvm.nvvm.read.ptx.sreg.tid.x()
declare i32 @llvm.nvvm.read.ptx.sreg.tid.y()
@@ -222,6 +224,9 @@ declare i32 @llvm.nvvm.read.ptx.sreg.cluster.nctaid.y()
declare i32 @llvm.nvvm.read.ptx.sreg.cluster.nctaid.z()
declare i32 @llvm.nvvm.read.ptx.sreg.cluster.nctaid.w()
+declare i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
+declare i32 @llvm.nvvm.read.ptx.sreg.cluster.nctarank()
+
; The product of all maxntid dims can exceed INT32_MAX. Make sure we still get
; correct ranges on (n)tid.(x|y).
diff --git a/llvm/test/Transforms/InstCombine/NVPTX/intrinsic-range.ll b/llvm/test/Transforms/InstCombine/NVPTX/intrinsic-range.ll
index 4a086946cca3f..f25408cde3692 100644
--- a/llvm/test/Transforms/InstCombine/NVPTX/intrinsic-range.ll
+++ b/llvm/test/Transforms/InstCombine/NVPTX/intrinsic-range.ll
@@ -6,9 +6,7 @@ declare i32 @llvm.nvvm.read.ptx.sreg.cluster.nctarank()
define i1 @ctarank_is_nonnegative() {
; CHECK-LABEL: define i1 @ctarank_is_nonnegative() {
-; CHECK-NEXT: [[RANK:%.*]] = call i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[RANK]], -1
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%rank = call i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
%cmp = icmp sge i32 %rank, 0
@@ -17,9 +15,7 @@ define i1 @ctarank_is_nonnegative() {
define i1 @nctarank_is_positive() {
; CHECK-LABEL: define i1 @nctarank_is_positive() {
-; CHECK-NEXT: [[RANK:%.*]] = call i32 @llvm.nvvm.read.ptx.sreg.cluster.nctarank()
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[RANK]], 0
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%rank = call i32 @llvm.nvvm.read.ptx.sreg.cluster.nctarank()
%cmp = icmp sgt i32 %rank, 0
@@ -29,7 +25,7 @@ define i1 @nctarank_is_positive() {
define i32 @ctarank_sdiv_16() {
; CHECK-LABEL: define i32 @ctarank_sdiv_16() {
; CHECK-NEXT: [[RANK:%.*]] = call i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
-; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[RANK]], 16
+; CHECK-NEXT: [[DIV:%.*]] = lshr i32 [[RANK]], 4
; CHECK-NEXT: ret i32 [[DIV]]
;
%rank = call i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
>From 366520a984a6e293b58aa0ac29cf25a40d46892e Mon Sep 17 00:00:00 2001
From: Daniel Donenfeld <ddonenfeld at nvidia.com>
Date: Mon, 21 Sep 2026 17:54:08 +0000
Subject: [PATCH 3/3] Update maximum to byte size for ctarank
---
llvm/include/llvm/IR/IntrinsicsNVVM.td | 8 ++++++--
llvm/test/CodeGen/NVPTX/intr-range.ll | 4 ++--
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/llvm/include/llvm/IR/IntrinsicsNVVM.td b/llvm/include/llvm/IR/IntrinsicsNVVM.td
index 2ca9bea8b719b..9dbab5783167a 100644
--- a/llvm/include/llvm/IR/IntrinsicsNVVM.td
+++ b/llvm/include/llvm/IR/IntrinsicsNVVM.td
@@ -158,6 +158,8 @@ defvar MAX_GRID_SIZE_X = 0x7fffffff;
defvar MAX_GRID_SIZE_Y = 0xffff;
defvar MAX_GRID_SIZE_Z = 0xffff;
+defvar MAX_CLUSTER_RANK = 0x100;
+
defvar MAX_BLOCK_SIZE_X = 1024;
defvar MAX_BLOCK_SIZE_Y = 1024;
defvar MAX_BLOCK_SIZE_Z = 64;
@@ -2761,9 +2763,11 @@ defm int_nvvm_read_ptx_sreg_cluster_nctaid : PTXReadSRegIntrinsicNB_v4i32<MAX_GR
// ctarank is an index within cluster CTA ranks (non-negative).
// nctarank is the number of CTA ranks in cluster (positive).
def int_nvvm_read_ptx_sreg_cluster_ctarank
- : PTXReadSRegIntrinsicNB_r32<[Range<RetIndex, 0, !add(MAX_GRID_SIZE_X, 1)>]>;
+ : PTXReadSRegIntrinsicNB_r32<
+ [Range<RetIndex, 0, MAX_CLUSTER_RANK>]>;
def int_nvvm_read_ptx_sreg_cluster_nctarank
- : PTXReadSRegIntrinsicNB_r32<[Range<RetIndex, 1, !add(MAX_GRID_SIZE_X, 1)>]>;
+ : PTXReadSRegIntrinsicNB_r32<
+ [Range<RetIndex, 1, !add(MAX_CLUSTER_RANK, 1)>]>;
//
// Reserved Shared Memory Intrinsics
diff --git a/llvm/test/CodeGen/NVPTX/intr-range.ll b/llvm/test/CodeGen/NVPTX/intr-range.ll
index b82704aefab1a..741808acbbdaf 100644
--- a/llvm/test/CodeGen/NVPTX/intr-range.ll
+++ b/llvm/test/CodeGen/NVPTX/intr-range.ll
@@ -178,8 +178,8 @@ define ptx_kernel i32 @test_cluster_dim() "nvvm.cluster_dim"="4,4,1" {
; DEFAULT-DAG: declare noundef range(i32 1, 65536) i32 @llvm.nvvm.read.ptx.sreg.cluster.nctaid.y()
; DEFAULT-DAG: declare noundef range(i32 1, 65536) i32 @llvm.nvvm.read.ptx.sreg.cluster.nctaid.z()
; DEFAULT-DAG: declare noundef range(i32 0, 1) i32 @llvm.nvvm.read.ptx.sreg.cluster.nctaid.w()
-; DEFAULT-DAG: declare noundef range(i32 0, -2147483648) i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
-; DEFAULT-DAG: declare noundef range(i32 1, -2147483648) i32 @llvm.nvvm.read.ptx.sreg.cluster.nctarank()
+; DEFAULT-DAG: declare noundef range(i32 0, 256) i32 @llvm.nvvm.read.ptx.sreg.cluster.ctarank()
+; DEFAULT-DAG: declare noundef range(i32 1, 257) i32 @llvm.nvvm.read.ptx.sreg.cluster.nctarank()
declare i32 @llvm.nvvm.read.ptx.sreg.tid.x()
declare i32 @llvm.nvvm.read.ptx.sreg.tid.y()
More information about the llvm-commits
mailing list