2e6df9acee35 — Leonard Ritter a month ago
* SPIR-V: report invalid reference storage classes at function boundaries
* prover: dereference return or call arguments for shader storage classes that can not be passed directly
5 files changed, 106 insertions(+), 5 deletions(-)

M lib/scopes/glsl.sc
M src/error.hpp
M src/gen_spirv.cpp
M src/prover.cpp
M testing/test_glsl.sc
M lib/scopes/glsl.sc +2 -1
@@ 285,7 285,8 @@ inline gen-xvar-sugar (name f)
             let expr = (qq [local-new] '[name] [T]
                 (unquote-splice (parse-layout layout...)))
             let expr = ('tag `expr ('anchor expression))
-            qq [let] [name] = [expr]
+            let _let = ('tag `let ('anchor expression))
+            qq [_let] [name] = [expr]
         default
             error
                 .. "syntax: " name " <name> [: <type>] [location = i] [binding = j]"

          
M src/error.hpp +6 -1
@@ 416,8 416,13 @@ formatters:
         "codegen: unsupported execution mode: %0", \
         Symbol) \
     T(CGenUnsupportedPointerStorageClass, \
-        "codegen: unsupported pointer storage class: %0", \
+        "codegen: unsupported pointer or reference storage class: %0", \
         Symbol) \
+    T(CGenUnsupportedArgumentPointerStorageClass, \
+        "codegen: unsupported storage class for reference or pointer: %0. Try dereferencing the argument before passing it.", \
+        Symbol) \
+    T(CGenUnsupportedReturnArgument, \
+        "codegen: Attempting to return a reference or pointer. Try dereferencing the return argument.") \
     T(CGenUnsupportedIntrinsic, \
         "codegen: unspported intrinsic function: '%0'", \
         Symbol) \

          
M src/gen_spirv.cpp +18 -0
@@ 717,6 717,11 @@ struct SPIRVGenerator {
         SCOPES_RESULT_TYPE(void);
         Ids refs;
         for (auto val : values) {
+            auto rq = try_qualifier<ReferQualifier>(val->get_type());
+            if (rq) {
+                SCOPES_TRACE_CODEGEN(val);
+                SCOPES_ERROR(CGenUnsupportedReturnArgument);
+            }
             refs.push_back(SCOPES_GET_RESULT(ref_to_value(val)));
         }
         return write_return(refs, is_except);

          
@@ 2195,6 2200,19 @@ struct SPIRVGenerator {
         //auto retT = SCOPES_GET_RESULT(type_to_spirv_type(rtype));
 
         for (size_t i = 0; i < argcount; ++i) {
+            auto AT = args[i]->get_type();
+            auto rq = try_qualifier<ReferQualifier>(AT);
+            if (rq) {
+                auto sc = rq->storage_class;
+                switch(sc.value()) {
+                case SYM_SPIRV_StorageClassFunction: break;
+                //case SYM_SPIRV_StorageClassImage: break;
+                default: {
+                    SCOPES_TRACE_CODEGEN(args[i]);
+                    SCOPES_ERROR(CGenUnsupportedArgumentPointerStorageClass, sc);
+                } break;
+                }
+            }
             values.push_back(SCOPES_GET_RESULT(ref_to_value(args[i])));
         }
 

          
M src/prover.cpp +42 -3
@@ 890,8 890,27 @@ static SCOPES_RESULT(TypedValueRef) make
     for (size_t i = 0; i < values.size(); ++i) {
         auto T = values[i]->get_type();
         auto rq = try_qualifier<ReferQualifier>(T);
-        if (rq && (rq->storage_class == SYM_SPIRV_StorageClassFunction)) {
-            SCOPES_CHECK_RESULT(build_deref_automove(ctx, mover, values[i]));
+        if (rq) {
+            switch(rq->storage_class.value()) {
+            case SYM_SPIRV_StorageClassUniformConstant:
+            case SYM_SPIRV_StorageClassUniform:
+            case SYM_SPIRV_StorageClassInput:
+            case SYM_SPIRV_StorageClassFunction:
+            //case SYM_SPIRV_StorageClassWorkgroup:
+            //case SYM_SPIRV_StorageClassCrossWorkgroup:
+            //case SYM_SPIRV_StorageClassPushConstant:
+            //case SYM_SPIRV_StorageClassAtomicCounter:
+            //case SYM_SPIRV_StorageClassStorageBuffer:
+            {
+                SCOPES_CHECK_RESULT(build_deref_automove(ctx, mover, values[i]));
+            } break;
+            //case SYM_SPIRV_StorageClassImage: break;
+            //case SYM_SPIRV_StorageClassPrivate: break;
+            //case SYM_SPIRV_StorageClassFunction: break;
+            //case SYM_SPIRV_StorageClassGeneric: break;
+            default: break;
+            }
+
         }
     }
 

          
@@ 2064,7 2083,27 @@ repeat:
                     SCOPES_TRACE_PROVE_ARG(arg);
                     SCOPES_ERROR(OpaqueType, AT);
                 }
-                types.push_back(arg->get_type());
+                // FIX: auto-dereference certain arguments that can not be
+                // passed as pointers.
+                switch(refer_storage_class(AT).value()) {
+                case SYM_SPIRV_StorageClassUniformConstant:
+                case SYM_SPIRV_StorageClassUniform:
+                case SYM_SPIRV_StorageClassInput:
+                //case SYM_SPIRV_StorageClassWorkgroup:
+                //case SYM_SPIRV_StorageClassCrossWorkgroup:
+                //case SYM_SPIRV_StorageClassPushConstant:
+                //case SYM_SPIRV_StorageClassAtomicCounter:
+                //case SYM_SPIRV_StorageClassStorageBuffer:
+                {
+                    AT = strip_qualifier<ReferQualifier>(AT);
+                } break;
+                //case SYM_SPIRV_StorageClassImage: break;
+                //case SYM_SPIRV_StorageClassPrivate: break;
+                //case SYM_SPIRV_StorageClassFunction: break;
+                //case SYM_SPIRV_StorageClassGeneric: break;
+                default: break;
+                }
+                types.push_back(AT);
             }
             callee = SCOPES_GET_RESULT(prove(
                 ref(callee.anchor(), cl->frame),

          
M testing/test_glsl.sc +38 -0
@@ 204,6 204,44 @@ do
     #test ((cttz 6) == 1)
     #test ((bitreverse 0b10010110:i8) == 0b01101001:i8)
 
+# passing pointers to shader functions
+do
+    using import struct
+    using import glm
+    using import glsl
 
+    fn t (v)
+        v
+
+    fn vertex ()
+        in x : i32
+        buffer v1 :
+            struct T
+                member : vec4
+        uniform v2 : vec4
+
+        fn t1 () v1
+        fn t2 () v2
+
+        switch x
+        case 0
+            gl_Position = (t v1.member)
+        case 1
+            gl_Position = (t v2)
+        #case 2
+            gl_Position = (t1)
+        case 3
+            gl_Position = (t2)
+        case 4
+            # this works:
+            gl_Position = (t (deref v1.member))
+        case 5
+            # or
+            gl_Position = (t (deref v2))
+        default
+            ;
+
+    print (compile-glsl 450 'vertex (static-typify vertex))
+    none
 
 ;