[llvm] [NVVM][NVPTX] Support spcompress and spdecompress intrinsics (PR #221751)
Rajat Bajpai via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 30 02:57:20 PDT 2026
================
@@ -0,0 +1,204 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains NVVM-specific IR verification logic. These checks are
+/// always compiled and linked as part of LLVMCore.
+///
+//===----------------------------------------------------------------------===//
+
+#include "VerifierInternal.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/IntrinsicsNVPTX.h"
+#include "llvm/Support/MathExtras.h"
+#include <optional>
+
+using namespace llvm;
+
+#define Check(C, ...) \
+ do { \
+ if (!(C)) { \
+ VS.CheckFailed(__VA_ARGS__); \
+ return; \
+ } \
+ } while (false)
+
+namespace {
+
+struct SPVectorInfo {
+ unsigned ElemSize;
+ unsigned NumElements;
+ unsigned NumRegisters;
+};
+
+// Register layout of the sparse intrinsic operands, used by the IR verifier.
+struct SPOperandLayout {
+ unsigned MetadataSize;
+ unsigned CompressedDataSize;
+ unsigned DataSize;
+};
+
+} // namespace
+
+// PTX limits the combined vector size of the mdata, cdata, and data operands
+// of spcompress and spdecompress to 253 32-bit registers.
+constexpr unsigned MaxSPOperandRegisters = 253;
+
+static bool isValidSPElemSize(unsigned ElemSize) {
+ return ElemSize == 8 || ElemSize == 16;
+}
+
+static bool isValidSPIdxSize(unsigned IdxSize) {
+ return IdxSize == 2 || IdxSize == 4;
+}
+
+static bool isValidSPRepeatFactor(unsigned RepeatFactor) {
+ return isPowerOf2_32(RepeatFactor) && RepeatFactor <= 64;
+}
+
+static bool isValidSPDecompressFactor(unsigned NumSrc, unsigned NumTgt) {
+ switch (NumSrc) {
+ case 1:
+ return NumTgt == 2 || NumTgt == 4 || NumTgt == 8 || NumTgt == 16;
+ case 2:
+ return NumTgt == 4 || NumTgt == 8 || NumTgt == 16;
+ case 4:
+ return NumTgt == 8 || NumTgt == 16;
+ default:
+ return false;
+ }
+}
+
+static std::optional<SPOperandLayout>
+getSPCompressLayout(unsigned ElemSize, unsigned IdxSize,
+ unsigned RepeatFactor) {
+ if (!isValidSPElemSize(ElemSize) || !isValidSPIdxSize(IdxSize) ||
+ !isValidSPRepeatFactor(RepeatFactor))
+ return std::nullopt;
+
+ SPOperandLayout Layout = {divideCeil(RepeatFactor * IdxSize, ElemSize),
+ RepeatFactor, RepeatFactor * 2};
+ if (Layout.MetadataSize + Layout.CompressedDataSize + Layout.DataSize >
+ MaxSPOperandRegisters)
+ return std::nullopt;
+ return Layout;
+}
+
+static std::optional<SPOperandLayout>
+getSPDecompressLayout(unsigned NumSrc, unsigned NumTgt, unsigned ElemSize,
+ unsigned IdxSize, unsigned RepeatFactor) {
+ if (!isValidSPDecompressFactor(NumSrc, NumTgt) ||
+ !isValidSPElemSize(ElemSize) || !isValidSPIdxSize(IdxSize) ||
+ !isValidSPRepeatFactor(RepeatFactor) || NumSrc * ElemSize > 32 ||
+ (IdxSize == 2 && NumTgt > 4))
+ return std::nullopt;
+
+ unsigned DataBits = NumTgt * ElemSize * RepeatFactor;
+ if (DataBits < 32 || DataBits > 4096)
+ return std::nullopt;
+
+ SPOperandLayout Layout = {divideCeil(NumSrc * IdxSize * RepeatFactor, 32),
+ divideCeil(NumSrc * ElemSize * RepeatFactor, 32),
+ divideCeil(DataBits, 32)};
+ if (Layout.MetadataSize + Layout.CompressedDataSize + Layout.DataSize >
+ MaxSPOperandRegisters)
+ return std::nullopt;
+ return Layout;
+}
+
+static std::optional<SPVectorInfo> getSPVectorInfo(Type *Ty) {
+ auto *VT = dyn_cast<FixedVectorType>(Ty);
+ if (!VT)
+ return std::nullopt;
+ auto *ElemTy = dyn_cast<IntegerType>(VT->getElementType());
+ if (!ElemTy)
+ return std::nullopt;
+ unsigned ElemSize = ElemTy->getBitWidth();
+ if (ElemSize != 8 && ElemSize != 16)
+ return std::nullopt;
+ unsigned NumElements = VT->getNumElements();
+ return SPVectorInfo{ElemSize, NumElements,
+ divideCeil(NumElements, 32 / ElemSize)};
+}
+
+static std::optional<unsigned> getSPMetadataRegisters(Type *Ty) {
+ if (Ty->isIntegerTy(32))
+ return 1;
+ auto *VT = dyn_cast<FixedVectorType>(Ty);
+ if (!VT || !VT->getElementType()->isIntegerTy(32))
+ return std::nullopt;
+ return VT->getNumElements();
----------------
rajatbajpai wrote:
It seems we are supporting <1 x i32> as well, is that intentional? I don't see any test case exercising that.
https://github.com/llvm/llvm-project/pull/221751
More information about the llvm-commits
mailing list