slang icon indicating copy to clipboard operation
slang copied to clipboard

Interface with 2 implementations from separate compiled slang-modules -> crash

Open fknfilewalker opened this issue 1 year ago • 1 comments

So I have this simple interface and the following simple shader:

// emitter.slang
public interface IEmitter<Real : __BuiltinFloatingPointType> {
    [Differentiable] vector<Real, 3> illuminate(vector<Real, 3>, vector<Real, 3>);
    [Differentiable] vector<Real, 3> sample();
} 
import emitter;
StructuredBuffer<IEmitter<float>> emitters;
RWStructuredBuffer<float> outputBuffer;

[shader("compute")]
[numthreads(1, 1, 1)]
void main(uint3 dispatchThreadID: SV_DispatchThreadID)
{
    vector<float, 3> P = { 0.0, 0.0, 0.0 };
    vector<float, 3> N = { 0.0, 1.0, 0.0 };
    outputBuffer[0] = emitters[0].illuminate(P, N).x;
}

I compile two different implementations (PointLight and SpotLight) of this interface to two slang-modules, which then get added when compiling the main shader above. If I only use one implementation it compiles but when using two, it results in a crash.

Directly compiling to spirv gives me "Unhandled global inst in spirv-emit: witness_table %1 : %2(%PointLight);" Compiling to glsl gives me an internal error 99999

So the problem comes from the last line where the compiler has an kIROp_swizzle with kIROp_WitnessTable as operand0, which then in the func defaultEmitInstExpr can not be handled and results in the error.

https://github.com/fknfilewalker/dyslang contains the code tests/load_plugins_one works but tests/load_plugins_two crashes (only tried it on windows) DYSLANG_SLANG_FROM_SUBMODULE TRUE uses the latest github code.

fknfilewalker avatar Oct 25 '24 08:10 fknfilewalker

Seems to be a problem with generics in interfaces. Removing them fixes the problem.

fknfilewalker avatar Nov 16 '24 18:11 fknfilewalker

I got this error as well. But I can trigger it without a generic interface and without using multiple modules. This is as close to a minimal example as I could get.

RWStructuredBuffer<float> buffer;

void doSomethingToBuffer() {
    buffer[0] += 0.0;
}

interface Processor {
    void process();
}

struct Layer<let SIZE : uint> : Processor {
    void process() {
        doSomethingToBuffer();
    }
}

struct Wrapper {
    Processor inner;

    void run() {
        inner.process();
    }
}

void eval() {
    Wrapper(Layer<1>()).run();
}

[shader("compute")]
[numthreads(64, 1, 1)]
void computeMain()
{
    eval();
}

Has this error when compiling:

(0): error 99999: Slang compilation aborted due to an exception of class Slang::InternalError: unimplemented: Unhandled global inst in spirv-emit:
witness_table %1        : %2(%Layer);

Devon7925 avatar Jan 15 '25 06:01 Devon7925

I think I've ran into the same problem as well, on the CPU target as well as SPIR-V, with a slightly different approach.

interface IThingy
{
    void message();
}

struct SpecificThingy: IThingy
{
    void message() { printf("Specific\n"); }
};

struct GenericThingy<T>: IThingy
{
    void message() { printf("Generic\n"); }
};

// For CPU
export __extern_cpp int main()
{
    IThingy thingies[1];

    thingies[0] = GenericThingy<int>();
    //thingies[0] = SpecificThingy();
    thingies[0].message();
    return 0;
}

// For SPIR-V
[shader("fragment")]
float4 fragMain(float4 fragCoord : SV_Position) : SV_Target
{
    IThingy thingies[1];

    thingies[0] = GenericThingy<int>(10);
    //thingies[0] = SpecificThingy();
    thingies[0].message();
    return float4(0, 0, 0, 1);
}

If thingies is not an array or SpecificThingy is used instead of GenericThingy, this compiles just fine on both the CPU and SPIR-V targets. The SPIR-V error is the same as the ones posted before on this issue:

(0): error 99999: Slang compilation aborted due to an exception of N5Slang13InternalErrorE: unimplemented: Unhandled global inst in spirv-emit:
witness_table %1        : %2(%GenericThingy);

The CPU one is interesting too:

gcc 13.3: test.slang(16): error :  ‘_S4’ was not declared in this scope; did you mean ‘_S3’?
   16 | export __extern_cpp int main()
      |                                                     ^  
      |                                                     _S3

The part of the intermediate C++ that causes this is:

int32_t main()
{

#line 16
    Tuple_0 _S3 = { Vector<uint32_t, 2> (0U, 0U), (&_S4) };

#line 22
    _S1(_S3);
    return int(0);
}

There indeed is no _S4.

EDIT: Debug notes in case I don't end up having the time to fix this myself.

  • IR in BEFORE-LOWER-GENERICS is identical (bar some [export()] lines) between SpecificThingy & GenericThingy
  • IR in AFTER-LOWER-GENERICS has differences. A WitnessTable is left in the output for GenericThingy, but not for SpecificThingy. It probably shouldn't be there anymore.
  • IR starts to differ in specializeRTTIObjects (slang-ir-lower-generics.cpp), SequentialIDDecoration not set on witness table of GenericThingy
  • SequentialIDDecoration is not added for GenericThingy's witness table because LinkageDecoration is missing in ensureWitnessTableSequentialIDs
  • I see two ways to fix this:
    1. Add another special case to ensureWitnessTableSequentialIDs to add the ID in these cases
    2. Make addLinkageDecoration not look for the outermost generic or make it possible to optionally skip that.

juliusikkala avatar Jan 18 '25 17:01 juliusikkala

Fixed by https://github.com/shader-slang/slang/pull/6129

expipiplus1 avatar Feb 04 '25 15:02 expipiplus1