0c144b406ec3 — Leonard Ritter 28 days ago
* new native `matrix` storage type to represent matrices in SPIR-V
* `glm`: use native matrix storage type for `mat-type` instances
M external/glslang/SpvBuilder.cpp +4 -2
@@ 313,9 313,11 @@ Id Builder::makeVectorType(Id component,
 Id Builder::makeMatrixType(Id component, int cols, int rows)
 {
     assert(cols <= maxMatrixSize && rows <= maxMatrixSize);
+    return makeMatrixType(makeVectorType(component, rows), cols);
+}
 
-    Id column = makeVectorType(component, rows);
-
+Id Builder::makeMatrixType(Id column, int cols)
+{
     // try to find it
     Instruction* type;
     for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) {

          
M external/glslang/SpvBuilder.h +1 -0
@@ 125,6 125,7 @@ public:
     Id makeStructResultType(Id type0, Id type1);
     Id makeVectorType(Id component, int size);
     Id makeMatrixType(Id component, int cols, int rows);
+    Id makeMatrixType(Id column, int cols);
     Id makeArrayType(Id element, Id sizeId, int stride);  // 0 stride means no stride decoration
     Id makeRuntimeArray(Id element);
     Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);

          
M genie.lua +1 -0
@@ 148,6 148,7 @@ project "scopesrt"
         "src/type/sized_storage_type.cpp",
         "src/type/array_type.cpp",
         "src/type/vector_type.cpp",
+        "src/type/matrix_type.cpp",
         "src/type/tuple_type.cpp",
         "src/type/qualify_type.cpp",
         "src/type/arguments_type.cpp",

          
M include/scopes/scopes.h +4 -0
@@ 464,6 464,10 @@ SCOPES_LIBEXPORT sc_type_raises_t sc_arr
 
 SCOPES_LIBEXPORT sc_type_raises_t sc_vector_type(const sc_type_t *element_type, size_t count);
 
+// matrix types
+
+SCOPES_LIBEXPORT sc_type_raises_t sc_matrix_type(const sc_type_t *element_type, size_t count);
+
 // tuple types
 
 SCOPES_LIBEXPORT sc_type_raises_t sc_tuple_type(int numtypes, const sc_type_t **types);

          
M lib/scopes/core.sc +38 -3
@@ 4908,9 4908,7 @@ inline vector-binary-op-dispatch (symbol
                 `(shufflevector self self mask)
     __unpack = `[(make-unpack-function extractelement)]
     __countof = __countof-aggregate
-    __@ =
-        inline (self index)
-            extractelement self index
+    __@ = extractelement
     # dynamic vector type constructor
     type =
         inline "vector.type" (element-type size)

          
@@ 4959,6 4957,43 @@ inline clamp (x mn mx)
         ? (< x mn) mn x
 
 #-------------------------------------------------------------------------------
+# matrices
+#-------------------------------------------------------------------------------
+
+'set-symbols matrix
+    __unpack = `[(make-unpack-function extractvalue)]
+    __countof = __countof-aggregate
+    __@ = extractvalue
+    # dynamic matrix type constructor
+    type =
+        inline "matrix.type" (element-type size)
+            sc_matrix_type element-type (size as usize)
+    # static matrix type constructor
+    __typecall =
+        spice-macro
+            fn "matrix.__typecall" (args)
+                let argc = ('argcount args)
+                verify-count argc 1 4
+                raising Error
+                let cls = (('getarg args 0) as type)
+                if (cls == matrix)
+                    verify-count argc 3 4
+                    let element-type = (('getarg args 1) as type)
+                    let columns = ((extract-integer ('getarg args 2)) as usize)
+                    let T =
+                        if (argc == 4)
+                            let rows = ((extract-integer ('getarg args 3)) as usize)
+                            sc_matrix_type
+                                sc_vector_type element-type rows
+                                columns
+                        else
+                            sc_matrix_type element-type columns
+                    `T
+                else
+                    verify-count argc 1 1
+                    `(nullof cls)
+
+#-------------------------------------------------------------------------------
 # various C related sugar
 #-------------------------------------------------------------------------------
 

          
M lib/scopes/glm.sc +1 -1
@@ 76,7 76,7 @@ inline construct-mat-type (element-type 
     let prefix = (element-prefix element-type)
     let vecT =
         construct-vec-type element-type rows
-    let MT = (array vecT cols)
+    let MT = (matrix vecT cols)
     typedef (.. prefix "mat" (tostring cols) "x" (tostring rows))
         \ < mat-type : MT
         let

          
M src/error.hpp +6 -1
@@ 292,6 292,8 @@ formatters:
     T(VectorSizeMismatch, \
         "arguments of type %0 and %1 must be of scalar type or vector type of equal size", \
         PType, PType) \
+    T(InvalidMatrixSize, \
+        "matrix type must at least have two columns") \
     T(ConditionNotBool, \
         "branching condition must be of boolean type, but is of type %0", \
         PType) \

          
@@ 423,7 425,10 @@ formatters:
         "codegen: entry function must have type %0 but has type %1", \
         PType, PType) \
     T(CGenUnsupportedVectorSize, \
-        "codegen: a vector of type %0 and size %1 is unsupported", \
+        "codegen: vector of type %0 and size %1 is unsupported", \
+        PType, int) \
+    T(CGenUnsupportedMatrixSize, \
+        "codegen: matrix of type %0 and size %1 is unsupported", \
         PType, int) \
 
 // runtime

          
M src/gen_llvm.cpp +5 -4
@@ 775,12 775,13 @@ struct LLVMIRGenerator {
         case TK_Pointer:
             return LLVMPointerType(
                 SCOPES_GET_RESULT(_type_to_llvm_type(cast<PointerType>(type)->element_type)), 0);
-        case TK_Array: {
-            auto ai = cast<ArrayType>(type);
+        case TK_Array:
+        case TK_Matrix: {
+            auto ai = cast<ArrayLikeType>(type);
             return LLVMArrayType(SCOPES_GET_RESULT(_type_to_llvm_type(ai->element_type)), ai->count());
         } break;
         case TK_Vector: {
-            auto vi = cast<VectorType>(type);
+            auto vi = cast<ArrayLikeType>(type);
             return LLVMVectorType(SCOPES_GET_RESULT(_type_to_llvm_type(vi->element_type)), vi->count());
         } break;
         case TK_Arguments: {

          
@@ 2256,7 2257,7 @@ struct LLVMIRGenerator {
             }
         } break;
         case LLVMArrayTypeKind: {
-            auto ai = cast<ArrayType>(SCOPES_GET_RESULT(storage_type(node->get_type())));
+            auto ai = cast<ArrayLikeType>(SCOPES_GET_RESULT(storage_type(node->get_type())));
             return LLVMConstArray(SCOPES_GET_RESULT(type_to_llvm_type(ai->element_type)),
                 values, count);
         } break;

          
M src/gen_spirv.cpp +12 -0
@@ 543,6 543,18 @@ struct SPIRVGenerator {
                 SCOPES_GET_RESULT(size_of(ai->element_type)));
             return ty;
         } break;
+        case TK_Matrix: {
+            auto mi = cast<MatrixType>(type);
+
+            auto etype = SCOPES_GET_RESULT(type_to_spirv_type(mi->element_type));
+
+            spv::Id ty = builder.makeMatrixType(etype, mi->count());
+            builder.addDecoration(ty,
+                spv::DecorationMatrixStride,
+                SCOPES_GET_RESULT(size_of(mi->element_type)));
+            builder.addDecoration(ty, spv::DecorationColMajor);
+            return ty;
+        } break;
         case TK_Vector: {
             auto vi = cast<VectorType>(type);
 

          
M src/globals.cpp +13 -0
@@ 1708,6 1708,7 @@ sc_size_raises_t sc_type_offsetof(const 
     switch(T->kind()) {
     case TK_Pointer: result = SCOPES_C_GET_RESULT(cast<PointerType>(T)->getelementptr(nullptr, (size_t)index)); break;
     case TK_Array: result = SCOPES_C_GET_RESULT(cast<ArrayType>(T)->getelementptr(nullptr, (size_t)index)); break;
+    case TK_Matrix: result = SCOPES_C_GET_RESULT(cast<MatrixType>(T)->getelementptr(nullptr, (size_t)index)); break;
     case TK_Vector: result = SCOPES_C_GET_RESULT(cast<VectorType>(T)->getelementptr(nullptr, (size_t)index)); break;
     case TK_Tuple: result = SCOPES_C_GET_RESULT(cast<TupleType>(T)->getelementptr(nullptr, (size_t)index)); break;
     default: {

          
@@ 1728,6 1729,7 @@ sc_int_raises_t sc_type_countof(const sc
     case TK_SampledImage:
         return { true, nullptr, 1 };
     case TK_Array: return { true, nullptr, (int)cast<ArrayType>(T)->count() };
+    case TK_Matrix: return { true, nullptr, (int)cast<MatrixType>(T)->count() };
     case TK_Vector: return { true, nullptr, (int)cast<VectorType>(T)->count() };
     case TK_Tuple: return { true, nullptr, (int)cast<TupleType>(T)->values.size() };
     case TK_Function:  return { true, nullptr, (int)(cast<FunctionType>(T)->argument_types.size()) };

          
@@ 1756,6 1758,7 @@ sc_type_raises_t sc_type_element_at(cons
     switch(T->kind()) {
     case TK_Pointer: result = cast<PointerType>(T)->element_type; break;
     case TK_Array: result = cast<ArrayType>(T)->element_type; break;
+    case TK_Matrix: result = cast<MatrixType>(T)->element_type; break;
     case TK_Vector: result = cast<VectorType>(T)->element_type; break;
     case TK_Tuple: result = SCOPES_C_GET_RESULT(cast<TupleType>(T)->type_at_index(i)); break;
     case TK_Function: result = SCOPES_C_GET_RESULT(cast<FunctionType>(T)->type_at_index(i)); break;

          
@@ 2049,6 2052,14 @@ sc_type_raises_t sc_vector_type(const sc
     return convert_result(vector_type(element_type, count));
 }
 
+// Matrix Type
+////////////////////////////////////////////////////////////////////////////////
+
+sc_type_raises_t sc_matrix_type(const sc_type_t *element_type, size_t count) {
+    using namespace scopes;
+    return convert_result(matrix_type(element_type, count));
+}
+
 // Tuple Type
 ////////////////////////////////////////////////////////////////////////////////
 

          
@@ 2516,6 2527,8 @@ void init_globals(int argc, char *argv[]
 
     DEFINE_RAISING_EXTERN_C_FUNCTION(sc_vector_type, TYPE_Type, TYPE_Type, TYPE_USize);
 
+    DEFINE_RAISING_EXTERN_C_FUNCTION(sc_matrix_type, TYPE_Type, TYPE_Type, TYPE_USize);
+
     DEFINE_RAISING_EXTERN_C_FUNCTION(sc_tuple_type, TYPE_Type, TYPE_I32, native_ro_pointer_type(TYPE_Type));
     DEFINE_RAISING_EXTERN_C_FUNCTION(sc_packed_tuple_type, TYPE_Type, TYPE_I32, native_ro_pointer_type(TYPE_Type));
     DEFINE_RAISING_EXTERN_C_FUNCTION(sc_union_storage_type, TYPE_Type, TYPE_I32, native_ro_pointer_type(TYPE_Type));

          
M src/prover.cpp +13 -8
@@ 196,8 196,9 @@ SCOPES_RESULT(ConstRef) nullof(const Typ
     case TK_Integer: return ConstRef(ConstInt::from(T, 0));
     case TK_Real: return ConstRef(ConstReal::from(T, 0.0));
     case TK_Pointer: return ConstRef(ConstPointer::from(T, nullptr));
-    case TK_Array: {
-        auto at = cast<ArrayType>(ST);
+    case TK_Array:
+    case TK_Matrix: {
+        auto at = cast<ArrayLikeType>(ST);
         ConstantPtrs fields;
         if (at->count()) {
             auto elem = SCOPES_GET_RESULT(nullof(at->element_type));

          
@@ 2489,6 2490,7 @@ repeat:
                 if (SSrcT != SDestT) {
                     switch (SSrcT->kind()) {
                     case TK_Array:
+                    case TK_Matrix:
                     //case TK_Vector:
                     case TK_Tuple: {
                         SCOPES_ERROR(CastIncompatibleAggregateType, SSrcT);

          
@@ 2722,8 2724,9 @@ repeat:
             READ_STORAGETYPEOF(idx);
             uint64_t iidx = -1ull;
             switch(T->kind()) {
-            case TK_Array: {
-                auto ai = cast<ArrayType>(T);
+            case TK_Array:
+            case TK_Matrix: {
+                auto ai = cast<ArrayLikeType>(T);
                 auto rq = try_qualifier<ReferQualifier>(typeof_T);
                 if (rq) {
                     SCOPES_CHECK_RESULT(verify_integer(idx));

          
@@ 2770,8 2773,9 @@ repeat:
             }
             auto T = SCOPES_GET_RESULT(storage_type(AT));
             switch(T->kind()) {
-            case TK_Array: {
-                auto ai = cast<ArrayType>(T);
+            case TK_Array:
+            case TK_Matrix: {
+                auto ai = cast<ArrayLikeType>(T);
                 SCOPES_CHECK_RESULT(verify(SCOPES_GET_RESULT(storage_type(SCOPES_GET_RESULT(ai->type_at_index(idx)))), ET));
             } break;
             case TK_Tuple: {

          
@@ 2825,8 2829,9 @@ repeat:
             while (argn < argcount) {
                 const Type *ST = SCOPES_GET_RESULT(storage_type(T));
                 switch(ST->kind()) {
-                case TK_Array: {
-                    auto ai = cast<ArrayType>(ST);
+                case TK_Array:
+                case TK_Matrix: {
+                    auto ai = cast<ArrayLikeType>(ST);
                     T = ai->element_type;
                     READ_STORAGETYPEOF(arg);
                     SCOPES_CHECK_RESULT(verify_integer(arg));

          
M src/quote.cpp +6 -4
@@ 517,8 517,9 @@ ValueRef unwrap_value(const Type *T, con
         }
         return result;
     } break;
-    case TK_Array: {
-        auto at = cast<ArrayType>(ST);
+    case TK_Array:
+    case TK_Matrix: {
+        auto at = cast<ArrayLikeType>(ST);
         auto argT = at->element_type;
         auto numvals = (int)at->count();
         //auto numelems = ConstInt::from(anchor, TYPE_I32, numvals);

          
@@ 634,8 635,9 @@ ValueRef wrap_value(const Type *T, const
                 { REF(ConstPointer::type_from(T)), numelems, buf })));
             return result;
         } break;
-        case TK_Array: {
-            auto at = cast<ArrayType>(ST);
+        case TK_Array:
+        case TK_Matrix: {
+            auto at = cast<ArrayLikeType>(ST);
             auto result = REF(Expression::unscoped_from());
             auto ET = at->element_type;
             auto numvals = (int)at->count();

          
M src/type.cpp +5 -0
@@ 210,6 210,7 @@ repeat:
         return true;
     case TK_Array:
     case TK_Vector:
+    case TK_Matrix:
         T = cast<ArrayLikeType>(T)->element_type;
         goto repeat;
     case TK_Tuple:

          
@@ 266,6 267,7 @@ SCOPES_RESULT(size_t) size_of(const Type
     case TK_Pointer: return PointerType::size();
     case TK_Array: return cast<ArrayType>(T)->size;
     case TK_Vector: return cast<VectorType>(T)->size;
+    case TK_Matrix: return cast<MatrixType>(T)->size;
     case TK_Tuple: return cast<TupleType>(T)->size;
     case TK_Typename: return size_of(SCOPES_GET_RESULT(storage_type(T)));
     default: break;

          
@@ 297,6 299,7 @@ SCOPES_RESULT(size_t) align_of(const Typ
     case TK_Pointer: return PointerType::size();
     case TK_Array: return cast<ArrayType>(T)->align;
     case TK_Vector: return cast<VectorType>(T)->align;
+    case TK_Matrix: return cast<MatrixType>(T)->align;
     case TK_Tuple: return cast<TupleType>(T)->align;
     case TK_Typename: return align_of(SCOPES_GET_RESULT(storage_type(T)));
     default: break;

          
@@ 314,6 317,7 @@ const Type *superof(const Type *T) {
     case TK_Pointer: return TYPE_Pointer;
     case TK_Array: return TYPE_Array;
     case TK_Vector: return TYPE_Vector;
+    case TK_Matrix: return TYPE_Matrix;
     case TK_Tuple: return TYPE_Tuple;
     case TK_Typename: return cast<TypenameType>(T)->super();
     case TK_Function: return TYPE_Function;

          
@@ 429,6 433,7 @@ void init_types() {
     DEFINE_OPAQUE_TYPENAME("integer", TYPE_Integer, TYPE_Immutable);
     DEFINE_OPAQUE_TYPENAME("real", TYPE_Real, TYPE_Immutable);
     DEFINE_OPAQUE_TYPENAME("vector", TYPE_Vector, TYPE_Immutable);
+    DEFINE_OPAQUE_TYPENAME("matrix", TYPE_Matrix, TYPE_Immutable);
     DEFINE_OPAQUE_TYPENAME("CEnum", TYPE_CEnum, TYPE_Immutable);
 
     DEFINE_OPAQUE_TYPENAME("array", TYPE_Array, TYPE_Aggregate);

          
M src/type.hpp +2 -0
@@ 41,6 41,7 @@ struct TypedValue;
     T(TK_Pointer, "type-kind-pointer", PointerType) \
     T(TK_Array, "type-kind-array", ArrayType) \
     T(TK_Vector, "type-kind-vector", VectorType) \
+    T(TK_Matrix, "type-kind-matrix", MatrixType) \
     T(TK_Tuple, "type-kind-tuple", TupleType) \
     T(TK_Function, "type-kind-function", FunctionType) \
     /* additional GPU machine types */ \

          
@@ 157,6 158,7 @@ typedef std::vector<const Type *> Types;
     T(TYPE_Pointer, "pointer") \
     T(TYPE_Array, "array") \
     T(TYPE_Vector, "vector") \
+    T(TYPE_Matrix, "matrix") \
     T(TYPE_Tuple, "tuple") \
     T(TYPE_Union, "union") \
     T(TYPE_Qualify, "Qualify") \

          
A => src/type/matrix_type.cpp +84 -0
@@ 0,0 1,84 @@ 
+/*
+    The Scopes Compiler Infrastructure
+    This file is distributed under the MIT License.
+    See LICENSE.md for details.
+*/
+
+#include "matrix_type.hpp"
+#include "vector_type.hpp"
+#include "typename_type.hpp"
+#include "../error.hpp"
+#include "../dyn_cast.inc"
+#include "../hash.hpp"
+#include "../utils.hpp"
+
+#include <unordered_set>
+
+namespace scopes {
+
+namespace MatrixSet {
+struct Hash {
+    std::size_t operator()(const MatrixType *s) const {
+        return
+            hash2(
+                std::hash<const Type *>{}(s->element_type),
+                std::hash<size_t>{}(s->_count));
+    }
+};
+
+struct KeyEqual {
+    bool operator()( const MatrixType *lhs, const MatrixType *rhs ) const {
+        return lhs->element_type == rhs->element_type
+            && lhs->_count == rhs->_count;
+    }
+};
+} // namespace MatrixSet
+
+static std::unordered_set<const MatrixType *, MatrixSet::Hash, MatrixSet::KeyEqual> matrices;
+
+//------------------------------------------------------------------------------
+// MATRIX TYPE
+//------------------------------------------------------------------------------
+
+void MatrixType::stream_name(StyledStream &ss) const {
+    ss << "<";
+    stream_type_name(ss, element_type);
+    ss << " * ";
+    ss << _count;
+    ss << ">";
+}
+
+const VectorType *MatrixType::column_type() const {
+    return cast<VectorType>(storage_type(element_type).assert_ok());
+}
+
+MatrixType::MatrixType(const Type *_element_type, size_t _count)
+    : ArrayLikeType(TK_Matrix, _element_type, _count) {
+    auto ST = column_type();
+    column_element_type = ST->element_type;
+    row_count = ST->count();
+
+    size = stride * count();
+    align = align_of(element_type).assert_ok();
+}
+
+SCOPES_RESULT(const Type *) matrix_type(const Type *element_type, size_t count) {
+    SCOPES_RESULT_TYPE(const Type *);
+    SCOPES_TYPE_KEY(MatrixType, key);
+    key->element_type = element_type;
+    key->_count = count;
+    auto it = matrices.find(key);
+    if (it != matrices.end())
+        return *it;
+    if (storage_kind(element_type) != TK_Vector) {
+        SCOPES_ERROR(TypeKindMismatch, TK_Vector, element_type);
+    }
+    if (count < 2) {
+        SCOPES_ERROR(InvalidMatrixSize);
+    }
+    auto result = new MatrixType(element_type, count);
+    matrices.insert(result);
+    return result;
+}
+
+} // namespace scopes

          
A => src/type/matrix_type.hpp +36 -0
@@ 0,0 1,36 @@ 
+/*
+    The Scopes Compiler Infrastructure
+    This file is distributed under the MIT License.
+    See LICENSE.md for details.
+*/
+
+#ifndef SCOPES_MATRIX_HPP
+#define SCOPES_MATRIX_HPP
+
+#include "sized_storage_type.hpp"
+
+namespace scopes {
+
+struct VectorType;
+
+//------------------------------------------------------------------------------
+// MATRIX TYPE
+//------------------------------------------------------------------------------
+
+struct MatrixType : ArrayLikeType {
+    static bool classof(const Type *T);
+
+    void stream_name(StyledStream &ss) const;
+    MatrixType(const Type *_element_type, size_t _count);
+
+    const VectorType *column_type() const;
+
+    const Type *column_element_type;
+    size_t row_count;
+};
+
+SCOPES_RESULT(const Type *) matrix_type(const Type *element_type, size_t count);
+
+} // namespace scopes
+
+#endif // SCOPES_MATRIX_HPP
  No newline at end of file

          
M src/type/sized_storage_type.cpp +1 -0
@@ 16,6 16,7 @@ bool ArrayLikeType::classof(const Type *
     switch(T->kind()) {
     case TK_Array:
     case TK_Vector:
+    case TK_Matrix:
         return true;
     default: break;
     }

          
M src/types.hpp +1 -0
@@ 11,6 11,7 @@ 
 #include "type/pointer_type.hpp"
 #include "type/array_type.hpp"
 #include "type/vector_type.hpp"
+#include "type/matrix_type.hpp"
 #include "type/tuple_type.hpp"
 #include "type/arguments_type.hpp"
 #include "type/function_type.hpp"

          
M src/value.cpp +6 -3
@@ 1341,8 1341,9 @@ static const Type *get_element_pointer_t
     for (int i = 1; i < count; ++i) {
         const Type *ST = storage_type(T).assert_ok();
         switch(ST->kind()) {
-        case TK_Array: {
-            auto ai = cast<ArrayType>(ST);
+        case TK_Array:
+        case TK_Matrix: {
+            auto ai = cast<ArrayLikeType>(ST);
             T = ai->element_type;
         } break;
         case TK_Vector: {

          
@@ 1377,7 1378,9 @@ static const Type *value_type_at_index(c
     T = storage_type(T).assert_ok();
     switch(T->kind()) {
     case TK_Pointer: return cast<PointerType>(T)->element_type;
-    case TK_Array: return cast<ArrayType>(T)->element_type;
+    case TK_Array:
+    case TK_Matrix:
+        return cast<ArrayLikeType>(T)->element_type;
     case TK_Vector: return cast<VectorType>(T)->element_type;
     case TK_Tuple: return type_key(cast<TupleType>(T)->type_at_index(index).assert_ok())._1;
     default: {

          
M testing/test_glsl.sc +3 -1
@@ 11,6 11,8 @@ run-stage;
 
 inout uv : vec2
     location = 0
+in transform : mat4x3
+    location = 1
 
 fn multiple-return-values ()
     if true

          
@@ 22,7 24,7 @@ fn set-vertex-position ()
     local screen-tri-vertices = screen-tri-vertices
     let pos = (screen-tri-vertices @ gl_VertexID)
     multiple-return-values;
-    gl_Position = (vec4 pos.x pos.y 0 1)
+    gl_Position = (vec4 (transform * (vec4 pos.x pos.y 0 1)) 1)
     deref pos
 
 fn vertex-shader ()