Skip to content

OpUMulExtended: SPIR-V reader mangles operands as signed, BiFModule only defines the unsigned overloads #432

Description

@pvelesko

A module using OpUMulExtended fails to build on every IGC I have tested:

$ ocloc compile -file umulo.spv -spirv_input -device pvc

error: undefined reference to `_Z20__spirv_UMulExtendedll'
in function: '__spirv_UMulExtended(long, long)' called by kernel: 'k'

error: backend compiler failed build.

The module is spirv-val clean and OpUMulExtended is core SPIR-V 1.0, no extension involved.

The SPIR-V reader mangles the operands as signed, _Z20__spirv_UMulExtendedll, but IGC/BiFModule/Implementation/arithmetic.cl defines only the unsigned overloads, __spirv_UMulExtended(ulong Operand1, ulong Operand2) and friends, which mangle to _Z20__spirv_UMulExtendedmm. There is no signed-typed __spirv_UMulExtended in that file. The same module with OpSMulExtended instead builds fine, because there the signed mangling matches __spirv_SMulExtended(long, long).

Tested:

Intel Data Center GPU Max 1550, IGC 2.11.29 (agama 25.18), ocloc -device pvc : fails
Intel Arc B570, IGC 2.38.2, ocloc -device bmg                                : fails

This looks fixed upstream by KhronosGroup/SPIRV-LLVM-Translator#3963 (merged 2026-08-18), which adds OpUMulExtended to the opcodes whose builtin arguments are mangled unsigned. That commit is on main only; it is not on llvm_release_170, which is what external/llvm/llvm_preferred_version.cmake points IGC at today, so no released IGC picks it up. Would you take a backport of that into the translator release branch IGC builds against, or alternatively add the signed overloads to the BiF module?

Reproducer, as SPIR-V assembly for spirv-as:

OpCapability Kernel
OpCapability Addresses
OpCapability Int64
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %15 "k"
OpName %11 "lo"
OpName %12 "ov"
%3 = OpTypeInt 64 0
%4 = OpTypePointer CrossWorkgroup %3
%5 = OpTypeVoid
%6 = OpTypeFunction %5 %4 %4 %3 %3
%7 = OpTypeBool
%8 = OpConstantNull %3
%9 = OpConstant %3 1
%10 = OpTypeStruct %3 %3
%15 = OpFunction %5 None %6
%11 = OpFunctionParameter %4
%12 = OpFunctionParameter %4
%13 = OpFunctionParameter %3
%14 = OpFunctionParameter %3
%2 = OpLabel
%16 = OpUMulExtended %10 %13 %14
%17 = OpCompositeExtract %3 %16 0
%18 = OpCompositeExtract %3 %16 1
%19 = OpINotEqual %7 %18 %8
%20 = OpSelect %3 %19 %9 %8
OpStore %11 %17 Aligned 8
OpStore %12 %20 Aligned 8
OpReturn
OpFunctionEnd

The same SPIR-V comes out of the in-tree LLVM SPIR-V backend for this input, so any language frontend that emits llvm.umul.with.overflow hits it:

define spir_kernel void @k(ptr addrspace(1) %lo, ptr addrspace(1) %ov, i64 %a, i64 %b) {
entry:
  %r = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
  %v = extractvalue { i64, i1 } %r, 0
  %o = extractvalue { i64, i1 } %r, 1
  %oz = zext i1 %o to i64
  store i64 %v, ptr addrspace(1) %lo
  store i64 %oz, ptr addrspace(1) %ov
  ret void
}
llc -mtriple=spirv64-unknown-unknown umulo.ll -filetype=obj -o umulo.spv

Impact for us: clang emits llvm.umul.with.overflow.i64 for a C++ new T[n] in device code, so any HIP or SYCL kernel that news an array fails to build. In chipStar all device code of a binary lands in one module, so the one unresolved symbol fails every kernel in the program.

Update: this is about to matter on a second path as well. KhronosGroup/SPIRV-LLVM-Translator#3977 changes llvm-spirv to lower llvm.umul.with.overflow to OpUMulExtended directly, instead of the spirv.llvm_umul_with_overflow_* helper function it emits today. That helper is the only reason SPIR-V produced by the translator still builds on a released IGC. If #3977 lands before IGC picks up #3963, modules coming from the translator will carry OpUMulExtended too, and hit the same undefined reference.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions