intel / intel/intel-graphics-compiler

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

Open
#432 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
718
Forks
191
PR merge metrics
No merged PRs in 30d

Description

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:

```llvm
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.

Contributor guide

Open the contributing guide

Research direction

Reproduce the failure with the listed ocloc command and inspect external/llvm/llvm_preferred_version.cmake to confirm the translator branch IGC uses. Compare the SPIR-V reader handling of OpUMulExtended with KhronosGroup/SPIRV-LLVM-Translator#3963, and review IGC/BiFModule/Implementation/arithmetic.cl for the available overloads. Done means the supplied SPIR-V and affected device-code paths build without the unresolved signed-mangled symbol.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.