[llvm] 917117c - [SPIR-V] Add vector type support for non-standard integers in G_TRUNC op (#198213)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 01:03:24 PDT 2026


Author: Arseniy Obolenskiy
Date: 2026-06-08T10:03:20+02:00
New Revision: 917117ceeebf004dff4b0b430de133c354f236ba

URL: https://github.com/llvm/llvm-project/commit/917117ceeebf004dff4b0b430de133c354f236ba
DIFF: https://github.com/llvm/llvm-project/commit/917117ceeebf004dff4b0b430de133c354f236ba.diff

LOG: [SPIR-V] Add vector type support for non-standard integers in G_TRUNC op (#198213)

Added: 
    

Modified: 
    llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
    llvm/test/CodeGen/SPIRV/trunc-nonstd-bitwidth.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index 3fa9f27d5d601..de454228f8602 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -514,30 +514,44 @@ generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
         Register DstReg = MI.getOperand(0).getReg();
         Register SrcReg = MI.getOperand(1).getReg();
 
-        // TODO: handle vector types.
-        if (!MRI.getType(DstReg).isScalar()) {
-          assert(!MRI.getType(SrcReg).isScalar());
-          continue;
-        }
-
-        unsigned OriginalDstWidth = MRI.getType(DstReg).getScalarSizeInBits();
-        unsigned OriginalSrcWidth = MRI.getType(SrcReg).getScalarSizeInBits();
+        LLT DstTy = MRI.getType(DstReg);
+        LLT SrcTy = MRI.getType(SrcReg);
+        assert((DstTy.isScalar() || DstTy.isVector()) &&
+               (SrcTy.isScalar() || SrcTy.isVector()) &&
+               "Expected scalar or vector G_TRUNC types");
+        assert(DstTy.isVector() == SrcTy.isVector() &&
+               "Expected matching scalar/vector G_TRUNC types");
+        assert((!DstTy.isVector() ||
+                DstTy.getElementCount() == SrcTy.getElementCount()) &&
+               "Expected equal vector element counts");
+
+        unsigned OriginalDstWidth = DstTy.getScalarSizeInBits();
+        unsigned OriginalSrcWidth = SrcTy.getScalarSizeInBits();
 
         unsigned NewDstWidth = widenBitWidthToNextPow2(OriginalDstWidth);
         unsigned NewSrcWidth = widenBitWidthToNextPow2(OriginalSrcWidth);
+        LLT NewDstTy = DstTy.changeElementSize(NewDstWidth);
+        LLT NewSrcTy = SrcTy.changeElementSize(NewSrcWidth);
 
-        // No Dst width change means no truncation semantics change.
-        if (OriginalDstWidth == NewDstWidth)
+        // No Dst width change means no truncation semantics change, but the
+        // source still needs a legal type.
+        if (OriginalDstWidth == NewDstWidth) {
+          MRI.setType(SrcReg, NewSrcTy);
           continue;
+        }
 
-        MRI.setType(SrcReg, LLT::scalar(NewSrcWidth));
-        MRI.setType(DstReg, LLT::scalar(NewDstWidth));
+        MRI.setType(SrcReg, NewSrcTy);
+        MRI.setType(DstReg, NewDstTy);
 
         MIB.setInsertPt(MBB, MI.getIterator());
         APInt Mask = APInt::getLowBitsSet(NewSrcWidth, OriginalDstWidth);
-        auto MaskReg = MIB.buildConstant(LLT::scalar(NewSrcWidth), Mask);
-        Register MaskedReg =
-            MRI.createGenericVirtualRegister(LLT::scalar(NewSrcWidth));
+        MachineInstrBuilder MaskReg =
+            DstTy.isVector()
+                ? MIB.buildBuildVectorConstant(
+                      NewSrcTy,
+                      SmallVector<APInt, 4>(DstTy.getNumElements(), Mask))
+                : MIB.buildConstant(NewSrcTy, Mask);
+        Register MaskedReg = MRI.createGenericVirtualRegister(NewSrcTy);
         MIB.buildAnd(MaskedReg, SrcReg, MaskReg);
 
         if (NewSrcWidth == NewDstWidth) {

diff  --git a/llvm/test/CodeGen/SPIRV/trunc-nonstd-bitwidth.ll b/llvm/test/CodeGen/SPIRV/trunc-nonstd-bitwidth.ll
index 22af0c3b81ee0..e3b2f48ceead3 100644
--- a/llvm/test/CodeGen/SPIRV/trunc-nonstd-bitwidth.ll
+++ b/llvm/test/CodeGen/SPIRV/trunc-nonstd-bitwidth.ll
@@ -13,8 +13,26 @@
 ; CHECK-EXT-DAG: %[[#Int40:]] = OpTypeInt 40 0
 ; CHECK-EXT-DAG: %[[#Int50:]] = OpTypeInt 50 0
 ; CHECK-EXT-DAG: %[[#Int24:]] = OpTypeInt 24 0
+; CHECK-EXT-DAG: %[[#ExtInt32:]] = OpTypeInt 32 0
 ; CHECK-NOEXT-DAG: %[[#Int64:]] = OpTypeInt 64 0
 ; CHECK-NOEXT-DAG: %[[#Int32:]] = OpTypeInt 32 0
+; CHECK-EXT-DAG: %[[#Vec2Int40:]] = OpTypeVector %[[#Int40]] 2
+; CHECK-EXT-DAG: %[[#Vec2Int50:]] = OpTypeVector %[[#Int50]] 2
+; CHECK-EXT-DAG: %[[#Vec2ExtInt32:]] = OpTypeVector %[[#ExtInt32]] 2
+; CHECK-EXT-DAG: %[[#Vec3Int50:]] = OpTypeVector %[[#Int50]] 3
+; CHECK-EXT-DAG: %[[#Vec3Int24:]] = OpTypeVector %[[#Int24]] 3
+; CHECK-EXT-DAG: %[[#Vec4Int24:]] = OpTypeVector %[[#Int24]] 4
+; CHECK-NOEXT-DAG: %[[#Vec2Int64:]] = OpTypeVector %[[#Int64]] 2
+; CHECK-NOEXT-DAG: %[[#Vec2Int32:]] = OpTypeVector %[[#Int32]] 2
+; CHECK-NOEXT-DAG: %[[#Vec3Int64:]] = OpTypeVector %[[#Int64]] 3
+; CHECK-NOEXT-DAG: %[[#Vec4Int64:]] = OpTypeVector %[[#Int64]] 4
+; CHECK-NOEXT-DAG: %[[#Vec3Int32:]] = OpTypeVector %[[#Int32]] 3
+; CHECK-NOEXT-DAG: %[[#Vec4Int32:]] = OpTypeVector %[[#Int32]] 4
+; CHECK-NOEXT-DAG: %[[#Mask40:]] = OpConstant %[[#Int64]] 1099511627775
+; CHECK-NOEXT-DAG: %[[#Mask24:]] = OpConstant %[[#Int64]] 16777215
+; CHECK-NOEXT-DAG: %[[#Mask40Vec2:]] = OpConstantComposite %[[#Vec2Int64]] %[[#Mask40]] %[[#Mask40]]
+; CHECK-NOEXT-DAG: %[[#Mask24Vec3:]] = OpConstantComposite %[[#Vec3Int64]] %[[#Mask24]] %[[#Mask24]] %[[#Mask24]]
+; CHECK-NOEXT-DAG: %[[#Mask24Vec4:]] = OpConstantComposite %[[#Vec4Int64]] %[[#Mask24]] %[[#Mask24]] %[[#Mask24]] %[[#Mask24]]
 
 
 ; Test i64 -> i40: both widen to i64
@@ -60,3 +78,62 @@ define spir_kernel void @trunc_i64_to_i24(ptr addrspace(1) %arg, i64 %val) {
   store i24 %tr, ptr addrspace(1) %arg
   ret void
 }
+
+; Test <2 x i64> -> <2 x i40>: both widen to <2 x i64>
+; CHECK: OpFunction
+; CHECK: %[[#T4Arg:]] = OpFunctionParameter
+; CHECK: %[[#T4Val:]] = OpFunctionParameter
+; CHECK-EXT: %[[#T4Tr:]] = OpUConvert %[[#Vec2Int40]] %[[#T4Val]]
+; CHECK-EXT: OpStore %[[#T4Arg]] %[[#T4Tr]]
+; CHECK-NOEXT: %[[#T4And:]] = OpBitwiseAnd %[[#Vec2Int64]] %[[#T4Val]] %[[#Mask40Vec2]]
+; CHECK-NOEXT: OpStore %[[#T4Arg]] %[[#T4And]]
+define spir_kernel void @trunc_v2i64_to_v2i40(ptr addrspace(1) %arg, <2 x i64> %val) {
+  %tr = trunc <2 x i64> %val to <2 x i40>
+  store <2 x i40> %tr, ptr addrspace(1) %arg
+  ret void
+}
+
+; Test <3 x i50> -> <3 x i24>: src widens to <3 x i64>, dst widens to <3 x i32>
+; CHECK: OpFunction
+; CHECK: %[[#T5Arg:]] = OpFunctionParameter
+; CHECK: %[[#T5Val:]] = OpFunctionParameter
+; CHECK-EXT: %[[#T5Tr:]] = OpUConvert %[[#Vec3Int24]] %[[#T5Val]]
+; CHECK-EXT: OpStore %[[#T5Arg]] %[[#T5Tr]]
+; CHECK-NOEXT: %[[#T5And:]] = OpBitwiseAnd %[[#Vec3Int64]] %[[#T5Val]] %[[#Mask24Vec3]]
+; CHECK-NOEXT: %[[#T5Conv:]] = OpUConvert %[[#Vec3Int32]] %[[#T5And]]
+; CHECK-NOEXT: OpStore %[[#T5Arg]] %[[#T5Conv]]
+define spir_kernel void @trunc_v3i50_to_v3i24(ptr addrspace(1) %arg, <3 x i50> %val) {
+  %tr = trunc <3 x i50> %val to <3 x i24>
+  store <3 x i24> %tr, ptr addrspace(1) %arg
+  ret void
+}
+
+; Test <4 x i64> -> <4 x i24>: src stays <4 x i64>, dst widens to <4 x i32>
+; CHECK: OpFunction
+; CHECK: %[[#T6Arg:]] = OpFunctionParameter
+; CHECK: %[[#T6Val:]] = OpFunctionParameter
+; CHECK-EXT: %[[#T6Tr:]] = OpUConvert %[[#Vec4Int24]] %[[#T6Val]]
+; CHECK-EXT: OpStore %[[#T6Arg]] %[[#T6Tr]]
+; CHECK-NOEXT: %[[#T6And:]] = OpBitwiseAnd %[[#Vec4Int64]] %[[#T6Val]] %[[#Mask24Vec4]]
+; CHECK-NOEXT: %[[#T6Conv:]] = OpUConvert %[[#Vec4Int32]] %[[#T6And]]
+; CHECK-NOEXT: OpStore %[[#T6Arg]] %[[#T6Conv]]
+define spir_kernel void @trunc_v4i64_to_v4i24(ptr addrspace(1) %arg, <4 x i64> %val) {
+  %tr = trunc <4 x i64> %val to <4 x i24>
+  store <4 x i24> %tr, ptr addrspace(1) %arg
+  ret void
+}
+
+; Test <2 x i50> -> <2 x i32>: dst width is already legal, no mask needed
+; CHECK: OpFunction
+; CHECK: %[[#T7Arg:]] = OpFunctionParameter
+; CHECK: %[[#T7Val:]] = OpFunctionParameter
+; CHECK-EXT: %[[#T7Tr:]] = OpUConvert %[[#Vec2ExtInt32]] %[[#T7Val]]
+; CHECK-EXT: OpStore %[[#T7Arg]] %[[#T7Tr]]
+; CHECK-NOEXT-NOT: OpBitwiseAnd
+; CHECK-NOEXT: %[[#T7Conv:]] = OpUConvert %[[#Vec2Int32]] %[[#T7Val]]
+; CHECK-NOEXT: OpStore %[[#T7Arg]] %[[#T7Conv]]
+define spir_kernel void @trunc_v2i50_to_v2i32(ptr addrspace(1) %arg, <2 x i50> %val) {
+  %tr = trunc <2 x i50> %val to <2 x i32>
+  store <2 x i32> %tr, ptr addrspace(1) %arg
+  ret void
+}


        


More information about the llvm-commits mailing list