[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