{"record":{"id":"63a5a133700a272f","repo":"stride3d/stride","slug":"opbitcast-result-type-reversetypes-resulttype-is-not-a","errorCode":null,"errorMessage":"OpBitcast result type {ReverseTypes[resultType]} is not a scalar","messagePattern":"OpBitcast result type (.+?) is not a scalar","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Context.Constants.cs","lineNumber":113,"sourceCode":"                case Specification.Op.OpConvertUToF:\n                    if (!TryGetConstantValue(i.Data.Memory.Span[4], out var convertOperand, out var convertOperandTypeId))\n                        return false;\n                    value = op switch\n                    {\n                        // Note: first cast to object is important, otherwise int/float will be cast as float\n                        Specification.Op.OpConvertFToS => (object)(int)(float)convertOperand,\n                        Specification.Op.OpConvertFToU => (uint)(float)convertOperand,\n                        Specification.Op.OpConvertSToF => (float)(int)convertOperand,\n                        Specification.Op.OpConvertUToF => (float)(uint)convertOperand,\n                        _ => throw new NotSupportedException($\"Unsupported conversion op: {op}\"),\n                    };\n                    break;\n                // Bitcast: reinterpret the operand's bits as the target scalar type.\n                case Specification.Op.OpBitcast:\n                    if (!TryGetConstantValue(i.Data.Memory.Span[4], out var bitcastOperand, out _))\n                        return false;\n                    if (ReverseTypes[resultType] is not ScalarType { Type: var bitcastTargetScalar })\n                        throw new NotSupportedException($\"OpBitcast result type {ReverseTypes[resultType]} is not a scalar\");\n                    var bitcastBits = bitcastOperand switch\n                    {\n                        int v => (uint)v,\n                        uint v => v,\n                        float v => BitConverter.SingleToUInt32Bits(v),\n                        _ => throw new NotSupportedException($\"OpBitcast operand type {bitcastOperand.GetType()} is not supported\"),\n                    };\n                    value = bitcastTargetScalar switch\n                    {\n                        Scalar.Int => (object)(int)bitcastBits,\n                        Scalar.UInt => bitcastBits,\n                        Scalar.Float => BitConverter.UInt32BitsToSingle(bitcastBits),\n                        _ => throw new NotSupportedException($\"OpBitcast target scalar {bitcastTargetScalar} is not supported\"),\n                    };\n                    break;\n                // Unary operations\n                case Specification.Op.OpSNegate:\n                case Specification.Op.OpFNegate:","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/shaders/Stride.Shaders.Parsers/Spirv/Building/Context.Constants.cs#L95-L131","documentation":"OpBitcast constant folding requires the bitcast's result type to be a scalar (int, uint, or float 32-bit); if ReverseTypes[resultType] is a vector, matrix, or any non-scalar type, the code throws NotSupportedException 'OpBitcast result type ... is not a scalar'. Bitcasting aggregate or non-32-bit types is not supported at compile-time fold.","triggerScenarios":"Constant-folding an OpBitcast whose result type id maps to a non-scalar type — e.g. bitcasting to vec2/vec4/ivec, a struct, or a 64-bit type — in the TryGetConstantValue bitcast case.","commonSituations":"Shaders bitcasting float4 to uint4 or double to uint2 on constant expressions, a common pattern for float bit inspection or hashing; generated code that moves bit tricks into constant subexpressions.","solutions":["Bitcast scalar components individually instead of the whole vector/composite constant.","Keep the bitcast as a runtime instruction (avoid constant folding) so it executes per-component on the GPU.","Extend the folding code to handle vector bitcasts component-wise if needed."],"exampleFix":"// before\nvar bits = context.GetConstantValue(context.Bitcast(f4Const, uint4Type)); // throws\n// after\nvar bits = new uint4(context.GetConstantValue(Bitcast(f4.x, uintType)), ...); // per-component","handlingStrategy":"validation","validationCode":"if (context.ReverseTypes[resultType] is not ScalarType) EmitRuntimeInstruction(Specification.Op.OpBitcast); // defer vector/composite bitcasts","typeGuard":"bool IsScalarBitcast(Context ctx, int resultTypeId) => ctx.ReverseTypes[resultTypeId] is ScalarType;","tryCatchPattern":"try { folded = context.GetConstantValue(bitcastId); } catch (NotSupportedException ex) when (ex.Message.Contains(\"is not a scalar\")) { EmitRuntimeInstruction(Specification.Op.OpBitcast); }","preventionTips":["Bitcast scalar components individually rather than whole vectors","Keep bit tricks out of constant-folded subexpressions","Check the result type's kind before requesting constant folding"],"tags":["spirv","bitcast","constant-folding","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}