[llvm] [SPIR-V] Support i64 smul.fix/umul.fix via SPV_ALTERA_arbitrary_precision_integers (PR #207405)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 3 07:51:42 PDT 2026


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

>From 290bd9a619364fae2a9cc0cfb777239b2db96e6f Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Fri, 3 Jul 2026 16:34:24 +0200
Subject: [PATCH] [SPIR-V] Support i64 smul.fix/umul.fix via
 SPV_ALTERA_arbitrary_precision_integers

---
 llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp  | 16 +++----
 .../llvm-intrinsics/fixed-point-math-i64.ll   | 42 +++++++++++++++++--
 2 files changed, 47 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index e2e4a4a6ae799..d452c9815a86a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -159,9 +159,10 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
 
   auto &allowedVectorTypes = ST.isShader() ? allShaderVectors : allVectors;
 
+  bool HasArbitraryPrecisionInts = ST.canUseExtension(
+      SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers);
   bool IsExtendedInts =
-      ST.canUseExtension(
-          SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers) ||
+      HasArbitraryPrecisionInts ||
       ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
       ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
   auto extendedScalarsAndVectors =
@@ -460,11 +461,12 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
 
   getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).lower();
 
-  // s64 is unsupported because lowering widens to s128, which SPIR-V does not
-  // have.
-  getActionDefinitionsBuilder({G_SMULFIX, G_UMULFIX})
-      .unsupportedFor({s64})
-      .lower();
+  // Lowering widens s64 to s128, which needs
+  // SPV_ALTERA_arbitrary_precision_integers. Mark s64 unsupported otherwise.
+  auto &MulFix = getActionDefinitionsBuilder({G_SMULFIX, G_UMULFIX});
+  if (!HasArbitraryPrecisionInts)
+    MulFix.unsupportedFor({s64});
+  MulFix.lower();
 
   getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
       .legalForCartesianProduct(allFloatScalarsAndVectors,
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fixed-point-math-i64.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fixed-point-math-i64.ll
index 2e2f45c31365b..a3b731e342016 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fixed-point-math-i64.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fixed-point-math-i64.ll
@@ -1,10 +1,44 @@
-; i64 is unsupported for smul.fix/umul.fix because lowering widens to i128,
-; which SPIR-V does not have.
+; i64 smul.fix/umul.fix lowering widens to i128, which SPIR-V only has via
+; SPV_ALTERA_arbitrary_precision_integers. Without the extension s64 is marked
+; unsupported so the diagnostic comes from the legalizer.
 
-; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o -
-; XFAIL: *
+; RUN: not llc -O0 -mtriple=spirv64-unknown-unknown %s -o %t.spvt 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
 
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_ALTERA_arbitrary_precision_integers %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-ERROR: LLVM ERROR: unable to legalize instruction: {{.*}} = G_SMULFIX
+
+; CHECK: OpCapability ArbitraryPrecisionIntegersALTERA
+; CHECK: OpExtension "SPV_ALTERA_arbitrary_precision_integers"
+; CHECK-DAG: %[[#I64:]] = OpTypeInt 64 0
+; CHECK-DAG: %[[#I128:]] = OpTypeInt 128 0
+; CHECK-DAG: %[[#Scale:]] = OpConstant %[[#I128]] 3
+
+; CHECK: OpFunction
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#I64]]
+; CHECK: %[[#B:]] = OpFunctionParameter %[[#I64]]
+; CHECK: %[[#WideA:]] = OpSConvert %[[#I128]] %[[#A]]
+; CHECK: %[[#WideB:]] = OpSConvert %[[#I128]] %[[#B]]
+; CHECK: %[[#Mul:]] = OpIMul %[[#I128]] %[[#WideA]] %[[#WideB]]
+; CHECK: %[[#Shift:]] = OpShiftRightArithmetic %[[#I128]] %[[#Mul]] %[[#Scale]]
+; CHECK: %[[#Res:]] = OpUConvert %[[#I64]] %[[#Shift]]
+; CHECK: OpReturnValue %[[#Res]]
 define i64 @smulfix_i64(i64 %a, i64 %b) {
   %r = call i64 @llvm.smul.fix.i64(i64 %a, i64 %b, i32 3)
   ret i64 %r
 }
+
+; CHECK: OpFunction
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#I64]]
+; CHECK: %[[#B:]] = OpFunctionParameter %[[#I64]]
+; CHECK: %[[#WideA:]] = OpUConvert %[[#I128]] %[[#A]]
+; CHECK: %[[#WideB:]] = OpUConvert %[[#I128]] %[[#B]]
+; CHECK: %[[#Mul:]] = OpIMul %[[#I128]] %[[#WideA]] %[[#WideB]]
+; CHECK: %[[#Shift:]] = OpShiftRightLogical %[[#I128]] %[[#Mul]] %[[#Scale]]
+; CHECK: %[[#Res:]] = OpUConvert %[[#I64]] %[[#Shift]]
+; CHECK: OpReturnValue %[[#Res]]
+define i64 @umulfix_i64(i64 %a, i64 %b) {
+  %r = call i64 @llvm.umul.fix.i64(i64 %a, i64 %b, i32 3)
+  ret i64 %r
+}



More information about the llvm-commits mailing list