[llvm] [SPIR-V] Fix sub-byte argument type mismatch in call lowering (PR #189893)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 1 05:22:40 PDT 2026


https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/189893

>From ea334acefb1a014b46f74b72df6691e2eb41b565 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 1 Apr 2026 09:01:20 +0200
Subject: [PATCH 1/3] [SPIR-V] Fix sub-byte argument type mismatch in call
 lowering

Remove the `MRI->setType()` call in lowerFormalArguments that was overriding the vreg LLT with the SPIR-V type's LLT, causing a type mismatch when sub-byte integer arguments (e.g. i2, i4) were preliminary widened to i8
---
 llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp      |  1 -
 .../SPIRV/transcoding/OpBitReverse-subbyte.ll    | 11 ++++-------
 .../CodeGen/SPIRV/transcoding/OpBitReverse_i2.ll | 11 ++++-------
 .../transcoding/subbyte-arg-type-mismatch.ll     | 16 ++++++++++++++++
 4 files changed, 24 insertions(+), 15 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/transcoding/subbyte-arg-type-mismatch.ll

diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
index bc6418f2ceceb..1defbc5fabb72 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
@@ -395,7 +395,6 @@ bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
     assert(VRegs[i].size() == 1 && "Formal arg has multiple vregs");
     Register ArgReg = VRegs[i][0];
     MRI->setRegClass(ArgReg, GR->getRegClass(ArgTypeVRegs[i]));
-    MRI->setType(ArgReg, GR->getRegType(ArgTypeVRegs[i]));
     auto MIB = MIRBuilder.buildInstr(SPIRV::OpFunctionParameter)
                    .addDef(ArgReg)
                    .addUse(GR->getSPIRVTypeID(ArgTypeVRegs[i]));
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse-subbyte.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse-subbyte.ll
index 280f586891717..5d3f77cc9075a 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse-subbyte.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse-subbyte.ll
@@ -1,14 +1,11 @@
 ; The goal of the test case is to ensure valid SPIR-V code emision
 ; on translation of integers with bit width less than 8.
 
-; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - -filetype=obj | spirv-val %}
 
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - -filetype=obj | spirv-val %}
-
-; TODO: This test currently fails with LLVM_ENABLE_EXPENSIVE_CHECKS enabled
-; XFAIL: expensive_checks
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV: OpCapability BitInstructions
 ; CHECK-SPIRV: OpExtension "SPV_KHR_bit_instructions"
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse_i2.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse_i2.ll
index 9d6a5e0dc0d32..200355ec0326f 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse_i2.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse_i2.ll
@@ -1,14 +1,11 @@
 ; The goal of the test case is to ensure that there's no crash
 ; on translation of integers with bit width less than 8.
 
-; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - -filetype=obj | spirv-val %}
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - -filetype=obj | spirv-val %}
 
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - -filetype=obj | spirv-val %}
-
-; TODO: This test currently fails with LLVM_ENABLE_EXPENSIVE_CHECKS enabled
-; XFAIL: expensive_checks
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - -filetype=obj | spirv-val %}
 
 ; CHECK-SPIRV: OpCapability BitInstructions
 ; CHECK-SPIRV: OpExtension "SPV_KHR_bit_instructions"
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/subbyte-arg-type-mismatch.ll b/llvm/test/CodeGen/SPIRV/transcoding/subbyte-arg-type-mismatch.ll
new file mode 100644
index 0000000000000..0f1b364524a7f
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/subbyte-arg-type-mismatch.ll
@@ -0,0 +1,16 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK: %[[#CharTy:]] = OpTypeInt 8 0
+; CHECK: %[[#FnTy:]] = OpTypeFunction %[[#CharTy]] %[[#CharTy]] %[[#CharTy]]
+; CHECK: %[[#Fn:]] = OpFunction %[[#CharTy]] None %[[#FnTy]]
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#CharTy]]
+; CHECK: %[[#B:]] = OpFunctionParameter %[[#CharTy]]
+; CHECK: %[[#Res:]] = OpIAdd %[[#CharTy]] %[[#A]] %[[#B]]
+; CHECK: OpReturnValue %[[#Res]]
+
+define spir_func i2 @add_i2(i2 %a, i2 %b) {
+entry:
+  %r = add i2 %a, %b
+  ret i2 %r
+}

>From 5cda77805fbe16e754e9f0918bb284b29eb43260 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 1 Apr 2026 10:44:15 +0200
Subject: [PATCH 2/3] Address review comments

---
 .../llvm-intrinsics/bitreverse_small_type.ll  | 37 +++++++++++++++++--
 .../SPIRV/transcoding/OpBitReverse-subbyte.ll | 32 ----------------
 .../SPIRV/transcoding/OpBitReverse_i2.ll      | 27 --------------
 3 files changed, 33 insertions(+), 63 deletions(-)
 delete mode 100644 llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse-subbyte.ll
 delete mode 100644 llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse_i2.ll

diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/bitreverse_small_type.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/bitreverse_small_type.ll
index 44ea765a93d4a..4d95fc7d09043 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/bitreverse_small_type.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/bitreverse_small_type.ll
@@ -1,11 +1,36 @@
-;; Check that llvm.bitreverse.* intrinsics are lowered for
-;; 2/4-bit scalar and vector types.
-
+;; Check that llvm.bitreverse.* intrinsics are lowered correctly for
+;; 2/4-bit scalar and vector types under different extension combinations.
+;;
+;; Without SPV_ALTERA_arbitrary_precision_integers, sub-byte types are
+;; widened to i8 and OpBitReverse operates on the widened type.
+;; With SPV_ALTERA, native sub-byte types are preserved:
+;;   - Without SPV_KHR_bit_instructions: bitreverse is emulated.
+;;   - With SPV_KHR_bit_instructions: native OpBitReverse is used.
+
+;; Widen-to-i8 case (no ALTERA, sub-byte types widened):
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_bit_instructions %s -o - | FileCheck %s --check-prefix=CHECK-WIDEN
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_bit_instructions %s -o - | FileCheck %s --check-prefix=CHECK-WIDEN
+; RUN: %if spirv-tools %{ llc -O0 -verify-machineinstrs -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_bit_instructions %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -verify-machineinstrs -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_KHR_bit_instructions %s -o - -filetype=obj | spirv-val %}
+
+;; Native sub-byte types with emulated bitreverse (ALTERA only):
 ; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers %s -o - | FileCheck %s --check-prefix=CHECK-EMULATION
-; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers,+SPV_KHR_bit_instructions %s -o - | FileCheck %s --check-prefix=CHECK-NATIVE
 ; RUN: %if spirv-tools %{ llc -O0 -verify-machineinstrs -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers %s -o - -filetype=obj | spirv-val %}
+
+;; Native sub-byte types with native OpBitReverse (ALTERA + KHR):
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers,+SPV_KHR_bit_instructions %s -o - | FileCheck %s --check-prefix=CHECK-NATIVE
 ; RUN: %if spirv-tools %{ llc -O0 -verify-machineinstrs -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers,+SPV_KHR_bit_instructions %s -o - -filetype=obj | spirv-val %}
 
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Capability and type declarations
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Widen case: sub-byte types become i8
+; CHECK-WIDEN: OpCapability BitInstructions
+; CHECK-WIDEN: OpExtension "SPV_KHR_bit_instructions"
+; CHECK-WIDEN-DAG: %[[#I8:]] = OpTypeInt 8 0
+
 ; CHECK-EMULATION-DAG: OpCapability ArbitraryPrecisionIntegersALTERA
 ; CHECK-EMULATION-DAG: OpExtension "SPV_ALTERA_arbitrary_precision_integers"
 
@@ -54,6 +79,7 @@
 
 define spir_kernel void @test_scalar(i8 %a8, i2 %a2, i4 %a4, ptr addrspace(1) %res) #0 {
 entry:
+  ; CHECK-WIDEN-LABEL: Begin function test_scalar
   ; CHECK-NATIVE-LABEL: Begin function test_scalar
   ; CHECK-EMULATION-LABEL: Begin function test_scalar
   ; CHECK-EMULATION-NOT: OpBitReverse
@@ -64,6 +90,7 @@ entry:
   ; CHECK-EMULATION-DAG: %[[#I2_Arg:]] = OpFunctionParameter %[[#I2]]
   ; CHECK-EMULATION-DAG: %[[#I4_Arg:]] = OpFunctionParameter %[[#I4]]
 
+  ; CHECK-WIDEN: OpBitReverse %[[#I8]] %[[#]]
   ; CHECK-NATIVE: OpBitReverse  %[[#I2]] %[[#I2_Arg]]
   ; CHECK-EMULATION: OpShiftRightLogical %[[#I2]] %[[#I2_Arg]] %[[#]]
   ; CHECK-EMULATION: OpBitwiseAnd %[[#I2:]] %[[#]] %[[#]]
@@ -74,6 +101,7 @@ entry:
   %call2 = call i2 @llvm.bitreverse.i2(i2 %a2)
   store i2 %call2, ptr addrspace(1) %res, align 2
 
+  ; CHECK-WIDEN: OpBitReverse %[[#I8]] %[[#]]
   ; CHECK-NATIVE: OpBitReverse  %[[#I4]] %[[#I4_Arg]]
   ; CHECK-EMULATION: OpShiftRightLogical %[[#I4]] %[[#I4_Arg]] %[[#]]
   ; CHECK-EMULATION: OpBitwiseAnd %[[#I4:]] %[[#]] %[[#]]
@@ -84,6 +112,7 @@ entry:
   %call4 = call i4 @llvm.bitreverse.i4(i4 %a4)
   store i4 %call4, ptr addrspace(1) %res, align 4
 
+  ; CHECK-WIDEN-LABEL: OpFunctionEnd
   ; CHECK-NATIVE-LABEL: OpFunctionEnd
   ; CHECK-EMULATION-LABEL: OpFunctionEnd
   ret void
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse-subbyte.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse-subbyte.ll
deleted file mode 100644
index 5d3f77cc9075a..0000000000000
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse-subbyte.ll
+++ /dev/null
@@ -1,32 +0,0 @@
-; The goal of the test case is to ensure valid SPIR-V code emision
-; on translation of integers with bit width less than 8.
-
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - -filetype=obj | spirv-val %}
-
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - -filetype=obj | spirv-val %}
-
-; CHECK-SPIRV: OpCapability BitInstructions
-; CHECK-SPIRV: OpExtension "SPV_KHR_bit_instructions"
-; CHECK-SPIRV: %[[#CharTy:]] = OpTypeInt 8 0
-; CHECK-SPIRV-NO: %[[#CharTy:]] = OpTypeInt 8 0
-; CHECK-SPIRV-COUNT-2: %[[#]] = OpBitReverse %[[#CharTy]] %[[#]]
-
-; TODO: Add a check to ensure that there's no behavior change of bitreverse operation
-;       between the LLVM-IR and SPIR-V for i2 and i4
-
- at G_res2 = global i2 0
- at G_res4 = global i4 0
-
-define spir_func void @foo(i2 %a, i4 %b) {
-entry:
-  %res2 = tail call i2 @llvm.bitreverse.i2(i2 %a)
-  store i2 %res2, ptr @G_res2
-  %res4 = tail call i4 @llvm.bitreverse.i4(i4 %b)
-  store i4 %res4, ptr @G_res4
-  ret void
-}
-
-declare i2 @llvm.bitreverse.i2(i2)
-declare i4 @llvm.bitreverse.i4(i4)
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse_i2.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse_i2.ll
deleted file mode 100644
index 200355ec0326f..0000000000000
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpBitReverse_i2.ll
+++ /dev/null
@@ -1,27 +0,0 @@
-; The goal of the test case is to ensure that there's no crash
-; on translation of integers with bit width less than 8.
-
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - -filetype=obj | spirv-val %}
-
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s --spirv-ext=+SPV_KHR_bit_instructions -o - -filetype=obj | spirv-val %}
-
-; CHECK-SPIRV: OpCapability BitInstructions
-; CHECK-SPIRV: OpExtension "SPV_KHR_bit_instructions"
-; CHECK-SPIRV: %[[#CharTy:]] = OpTypeInt 8 0
-; CHECK-SPIRV-NO: %[[#CharTy:]] = OpTypeInt 8 0
-; CHECK-SPIRV: %[[#Arg:]] = OpFunctionParameter %[[#CharTy]]
-; CHECK-SPIRV: %[[#Res:]] = OpBitReverse %[[#CharTy]] %[[#Arg]]
-; CHECK-SPIRV: OpReturnValue %[[#Res]]
-
-; TODO: Add a check to ensure that there's no behavior change of bitreverse operation
-;       between the LLVM-IR and SPIR-V for i2
-
-define spir_func signext i2 @foo(i2 noundef signext %a) {
-entry:
-  %b = tail call i2 @llvm.bitreverse.i2(i2 %a)
-  ret i2 %b
-}
-
-declare i2 @llvm.bitreverse.i2(i2)

>From 8a5fdd9c4bb0e82b6ac7a2c8bc05b39c7bc91792 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 1 Apr 2026 14:22:26 +0200
Subject: [PATCH 3/3] Add comment for the test

---
 .../CodeGen/SPIRV/transcoding/subbyte-arg-type-mismatch.ll  | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/llvm/test/CodeGen/SPIRV/transcoding/subbyte-arg-type-mismatch.ll b/llvm/test/CodeGen/SPIRV/transcoding/subbyte-arg-type-mismatch.ll
index 0f1b364524a7f..a66d1da607bb6 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/subbyte-arg-type-mismatch.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/subbyte-arg-type-mismatch.ll
@@ -1,6 +1,12 @@
 ; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
 ; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
 
+; This test verifies that sub-byte integer arguments (e.g. i2) don't cause a
+; type mismatch during call lowering.
+;
+; Sub-byte types like i2 are widened to i8 early on, so the vreg gets LLT s8.
+;   %vreg = G_ANYEXT s8, ...   ; vreg is s8 after widening
+
 ; CHECK: %[[#CharTy:]] = OpTypeInt 8 0
 ; CHECK: %[[#FnTy:]] = OpTypeFunction %[[#CharTy]] %[[#CharTy]] %[[#CharTy]]
 ; CHECK: %[[#Fn:]] = OpFunction %[[#CharTy]] None %[[#FnTy]]



More information about the llvm-commits mailing list