google / amber

Amber is a multi-API shader test framework
Apache License 2.0
188 stars 63 forks source link

SPIRV-ASM Compilation Failed #982

Closed rayanht closed 2 years ago

rayanht commented 2 years ago

Hi I'm trying to use Amber to run spirv compute shaders but I am running into compilation errors.

#!amber
SHADER compute shader SPIRV-ASM TARGET_ENV spv1.3
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %119 "main" %114 %116 %118
OpExecutionMode %119 LocalSize 1 1 1
%1 = OpTypeVoid
%2 = OpTypeFunction %1
%3 = OpTypeBool
%4 = OpTypeVector %3 3
%5 = OpTypePointer Input %4
%6 = OpTypeFloat 32
%7 = OpTypeInt 32 0
%8 = OpTypeFunction %1 %5 %6 %7 %6
%9 = OpTypePointer Output %3
%10 = OpTypeStruct %3 %3 %9 %3
%11 = OpTypeInt 32 1
%12 = OpTypeRuntimeArray %11
%13 = OpTypeStruct %3
%14 = OpTypeVector %11 3
%15 = OpTypeStruct %14 %3 %12
%16 = OpTypeStruct %12 %3 %3 %13 %15
%17 = OpTypePointer Function %16
%18 = OpConstant %7 31
%19 = OpTypeArray %3 %18
%20 = OpConstant %7 6
%21 = OpTypeArray %11 %20
%22 = OpTypeStruct %10 %6 %17 %19 %21
%23 = OpConstant %7 16
%24 = OpTypeArray %6 %23
%25 = OpTypeVector %7 3
%26 = OpTypeStruct %3 %25 %6
%27 = OpTypeStruct %26 %11
%28 = OpTypeVector %7 2
%29 = OpTypeStruct
%30 = OpConstant %7 7
%31 = OpTypeArray %11 %30
%32 = OpTypeStruct %29 %11 %31 %3
%33 = OpTypeRuntimeArray %6
%34 = OpTypeFunction %1 %33
%35 = OpTypeFunction %1 %29
%36 = OpTypeFunction %1 %14 %4
%37 = OpTypeFunction %1 %11
%38 = OpConstant %7 12
%39 = OpTypeArray %7 %38
%40 = OpTypeStruct %19 %39 %6
%41 = OpTypeStruct %40 %11 %11
%42 = OpTypePointer Input %12
%43 = OpConstant %7 4
%44 = OpTypeArray %6 %43
%45 = OpTypeStruct %7 %3 %33 %44 %3
%46 = OpTypeStruct %7 %45 %29
%47 = OpTypeStruct %6 %6
%48 = OpTypeStruct %47 %11 %9 %6
%49 = OpTypeStruct %46 %6 %48 %11
%50 = OpTypeStruct %42 %49
%51 = OpTypeVector %6 4
%52 = OpTypeStruct %6 %33 %29 %50 %51
%53 = OpTypeStruct %52
%54 = OpTypeVector %3 2
%55 = OpTypeStruct %54 %3 %6
%56 = OpTypePointer Function %55
%57 = OpTypeStruct %33 %56
%58 = OpConstant %7 29
%59 = OpTypeArray %3 %58
%60 = OpTypePointer Input %59
%61 = OpConstant %7 8
%62 = OpTypeArray %6 %61
%63 = OpTypePointer Output %62
%64 = OpConstant %7 28
%65 = OpTypeArray %3 %64
%66 = OpTypePointer Uniform %65
%67 = OpTypePointer Input %66
%68 = OpTypeStruct %25 %67
%69 = OpTypeRuntimeArray %7
%70 = OpTypeStruct %68 %6 %69
%71 = OpConstant %7 18
%72 = OpTypeArray %3 %71
%73 = OpTypeStruct %63 %70 %72 %6 %6
%74 = OpTypeStruct %73
%75 = OpTypeStruct %74
%76 = OpTypeStruct %11 %75
%77 = OpTypePointer Output %76
%78 = OpConstant %7 15
%79 = OpTypeArray %6 %78
%80 = OpTypeVector %6 2
%81 = OpTypeStruct %77 %79 %6 %80
%82 = OpTypeRuntimeArray %3
%83 = OpTypeStruct %82 %54
%84 = OpTypePointer Uniform %28
%85 = OpTypeStruct %60 %3 %81 %83 %84
%86 = OpTypeStruct %6 %57 %3 %85 %7
%87 = OpTypeStruct %6 %86
%88 = OpTypeFunction %1 %41 %53 %6 %87 %3
%89 = OpTypeFunction %1 %6 %6
%90 = OpTypeVector %3 4
%91 = OpTypeStruct %3 %12 %11
%92 = OpConstant %7 11
%93 = OpTypeArray %6 %92
%94 = OpTypeStruct %91 %6 %33 %93 %3
%95 = OpTypeFunction %1 %90 %94
%96 = OpTypeFunction %1 %6
%97 = OpConstant %7 5
%98 = OpTypeArray %6 %97
%99 = OpTypePointer Function %6
%100 = OpTypeStruct %69 %6 %29 %33 %99
%101 = OpTypeStruct %3 %11 %28 %100
%102 = OpTypeVector %6 3
%103 = OpTypePointer UniformConstant %3
%104 = OpTypeFunction %1 %103 %33 %3 %11 %3
%105 = OpTypePointer UniformConstant %80
%106 = OpConstant %6 1150871570.5568037
%107 = OpConstantTrue %3
%108 = OpConstantFalse %3
%109 = OpConstant %7 3326166830
%110 = OpConstant %6 181730082.29375458
%111 = OpConstant %11 315431628
%112 = OpConstant %7 316193280
%113 = OpTypePointer Input %7
%114 = OpVariable %113 Input
%115 = OpTypePointer Input %11
%116 = OpVariable %115 Input
%117 = OpTypePointer Output %7
%118 = OpVariable %117 Output
%119 = OpFunction %1 None %2
%120 = OpLabel
OpReturn
OpFunctionEnd
END

BUFFER buf0 DATA_TYPE uint32 DATA
4
END
BUFFER buf1 DATA_TYPE int32 DATA
46
END
BUFFER buf2 DATA_TYPE uint32 DATA
46
END

PIPELINE compute pipeline
ATTACH shader
BIND BUFFER buf0 AS storage DESCRIPTOR_SET 0 BINDING 0
BIND BUFFER buf1 AS storage DESCRIPTOR_SET 0 BINDING 1
BIND BUFFER buf2 AS storage DESCRIPTOR_SET 0 BINDING 2
END
RUN pipeline 1 1 1

Running this code with amber -d out.amber, fails with the following error:

[mvk-error] VK_ERROR_INITIALIZATION_FAILED: Shader library compile failed (Error code 3):
Compilation failed: 

program_source:116:8: error: invalid return type 'main0_out' for kernel function
kernel main0_out main0()
       ^
.
[mvk-error] VK_ERROR_INVALID_SHADER_NV: Compute shader function could not be compiled into pipeline. See previous logged error.
out.amber: Vulkan::Calling vkCreateComputePipelines Fail

Summary of Failures:
  out.amber

Summary: 0 pass, 1 fail
afd commented 2 years ago

I wonder if this is a spirv-cross issue.

"mvk-error" means that MoltenVk - an implementation of Vulkan on top of Apple's Metal, is going wrong.

I believe MoltenVk uses spirv-cross to compile SPIR-V into the Metal shading language (msl).

It looks to me like perhaps spirv-cross has generated:

kernel main0_out main0()

and that the Metal compiler isn't happy with this. (I don't know msl syntax.)

I suggest you try the following:

If this indeed turns out to look like a spirv-cross problem then find a minimal example that exposes the problem (you could use spirv-reduce to help you), and report it to spirv-cross (but always make sure the SPIR-V is definitely valid before reporting any SPIR-V-related bug!)

rayanht commented 2 years ago

Thanks @afd, this seems to be a spirv-cross error indeed. spirv-cross generates correct-ish GLSL which can be run with Amber but seems to have issues translating to MSL. The generated MSL is as follows:

#pragma clang diagnostic ignored "-Wmissing-prototypes"
#pragma clang diagnostic ignored "-Wmissing-braces"

#include <metal_stdlib>
#include <simd/simd.h>

using namespace metal;

template<typename T, size_t Num>
struct spvUnsafeArray
{
    T elements[Num ? Num : 1];

    thread T& operator [] (size_t pos) thread
    {
        return elements[pos];
    }
    constexpr const thread T& operator [] (size_t pos) const thread
    {
        return elements[pos];
    }

    device T& operator [] (size_t pos) device
    {
        return elements[pos];
    }
    constexpr const device T& operator [] (size_t pos) const device
    {
        return elements[pos];
    }

    constexpr const constant T& operator [] (size_t pos) const constant
    {
        return elements[pos];
    }

    threadgroup T& operator [] (size_t pos) threadgroup
    {
        return elements[pos];
    }
    constexpr const threadgroup T& operator [] (size_t pos) const threadgroup
    {
        return elements[pos];
    }
};

struct _13
{
    int _m0;
    float _m1;
    spvUnsafeArray<uint, 1> _m2;
    uint _m3;
};

struct _16
{
    float3 _m0;
    float _m1;
    spvUnsafeArray<bool, 1> _m2;
    bool _m3;
};

struct _20
{
    bool _m0;
    bool _m1;
};

struct _23
{
    float _m0;
    thread bool* _m1;
    _20 _m2;
    spvUnsafeArray<float, 25> _m3;
};

struct _24
{
    float _m0;
    uint _m1;
    _23 _m2;
};

struct _29
{
    int _m0;
    uint _m1;
    float _m2;
};

struct _30
{
    _29 _m0;
};

struct _31
{
    spvUnsafeArray<uint, 1> _m0;
    int _m1;
    spvUnsafeArray<float, 1> _m2;
    bool _m3;
    _30 _m4;
};

struct _34
{
    bool _m0;
    uint _m1;
};

struct main0_out
{
    float m_3;
};

kernel main0_out main0()
{
    main0_out out = {};
    return out;
}

The MSL spec Section 5.1.3. states that kernel functions should return void in MSL but here the return type is a struct containing a float, even though the original spirv assembly specifies a void return type on the function.

The output buffer in that spirv program is however a float so I'm guessing spirv-cross thinks that it should be the return type of the kernel in MSL.

Closing this as it is not an issue in Amber per se.