stride3d/stride · error · NotImplementedException

64bit integers

Error message

64bit integers

What it means

FindCommonBaseTypeForBinaryOperation computes the common scalar base type for binary operands. 64-bit integers (Scalar.Int64) are not yet supported by the SPIR-V binary-op type promotion, so the builder throws NotImplementedException with the message '64bit integers'.

Solutions

  1. Change shader variables/constants from long/ulong (int64) to int/uint
  2. Cast 64-bit operands down to 32-bit types before the binary operation
  3. Split 64-bit math into emulated 32-bit operations if full range is needed
  4. Check whether a Stride update adds Int64 support for binary operations

Example fix

// before (HLSL)
long a = ...;
long c = a + 2;
// after
int a = ...;
int c = a + 2;
Defensive patterns

Strategy: validation

Validate before calling

// Reject int64 operands in shader binary expressions before compilation
if (leftType is ScalarType { Type: Scalar.Int64 } || rightType is ScalarType { Type: Scalar.Int64 })
    throw new ShaderSemanticException("64-bit integers are not supported in shader binary operations");

Type guard

bool IsInt64(SymbolType t) => t is ScalarType { Type: Scalar.Int64 };

Try / catch

try { var r = AnalyzeBinaryOperation(table, l, op, r, loc); }
catch (NotImplementedException ex) when (ex.Message == "64bit integers") { throw new ShaderSemanticException("Use 32-bit integer types in shaders", ex); }

Prevention

When it happens

Trigger: Any binary expression (e.g. a + b, a << b) where either operand's scalar type is Scalar.Int64, via AnalyzeBinaryOperation/desiredElementType.

Common situations: Using long/int64_t variables in shader arithmetic; porting C# code with long constants into shaders; HLSL 64-bit integer math unsupported by this compiler path.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/4b9de71861179ce7. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Builder.Expressions.cs:108

        for (var swizzleIndex = 0; swizzleIndex < swizzles.Length; swizzleIndex++)
        {
            var swizzle = swizzles[swizzleIndex];
            elements[swizzleIndex] = Insert(new OpCompositeExtract(context.GetOrRegister(m.BaseType), context.Bound++, value.Id, [swizzle.Column, swizzle.Row])).ResultId;
        }

        var resultType = m.BaseType.GetVectorOrScalar(swizzles.Length);
        value = swizzles.Length > 1
            ? new(InsertData(new OpCompositeConstruct(context.GetOrRegister(resultType), context.Bound++, [.. elements])))
            : new(elements[0], context.GetOrRegister(resultType));

        return (value, resultType);
    }

    public static ScalarType FindCommonBaseTypeForBinaryOperation(SymbolType leftElementType, SymbolType rightElementType)
    {
        return (leftElementType, rightElementType) switch
        {
            (ScalarType { Type: Scalar.Int64 }, _) or (_, ScalarType { Type: Scalar.Int64 }) => throw new NotImplementedException("64bit integers"),
            // Matching types
            (ScalarType { Type: Scalar.Int or Scalar.UInt or Scalar.Half or Scalar.Float or Scalar.Double or Scalar.Boolean } l, ScalarType r) when l == r => l,
            // If one side is float/double and other is integer, promote to floating
            (ScalarType { Type: Scalar.Int or Scalar.UInt } l, ScalarType { Type: Scalar.Float or Scalar.Double } r) => r,
            (ScalarType { Type: Scalar.Float or Scalar.Double } l, ScalarType { Type: Scalar.Int or Scalar.UInt } r) => l,
            // Half mixed with float/double: HLSL narrows to half
            (ScalarType { Type: Scalar.Half } l, ScalarType { Type: Scalar.Float or Scalar.Double }) => l,
            (ScalarType { Type: Scalar.Float or Scalar.Double }, ScalarType { Type: Scalar.Half } r) => r,
            // Half mixed with integer promotes to half
            (ScalarType { Type: Scalar.Int or Scalar.UInt } l, ScalarType { Type: Scalar.Half } r) => r,
            (ScalarType { Type: Scalar.Half } l, ScalarType { Type: Scalar.Int or Scalar.UInt } r) => l,
            // If one side is unsigned, promote to unsigned (bitcast)
            (ScalarType { Type: Scalar.Int } l, ScalarType { Type: Scalar.UInt } r) => r,
            (ScalarType { Type: Scalar.UInt } l, ScalarType { Type: Scalar.Int } r) => l,
            // Bool promotes to int/uint/float in arithmetic contexts (HLSL implicit conversion)
            (ScalarType { Type: Scalar.Boolean }, ScalarType { Type: Scalar.Int or Scalar.UInt or Scalar.Half or Scalar.Float or Scalar.Double } r) => r,
            (ScalarType { Type: Scalar.Int or Scalar.UInt or Scalar.Half or Scalar.Float or Scalar.Double } l, ScalarType { Type: Scalar.Boolean }) => l,
            _ => throw new NotImplementedException($"Couldn't figure out element type for binary operation between {leftElementType} and {rightElementType}"),

View on GitHub (pinned to 96fad776d2)