Add type determination for GLSL determinant.

This CL adds the type determination code for the GLSL determinant call.

Change-Id: I46bc57f4fd5f4f43021b20ee511b0b8fc809f4f8
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/23360
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index d4ecc3a..bf8c00f 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -64,7 +64,8 @@
 enum class GlslDataType {
   kFloatScalarOrVector,
   kIntScalarOrVector,
-  kFloatVector
+  kFloatVector,
+  kMatrix
 };
 struct GlslData {
   const char* name;
@@ -87,6 +88,7 @@
     {"cosh", 1, GLSLstd450Cosh, GlslDataType::kFloatScalarOrVector, 0},
     {"cross", 2, GLSLstd450Cross, GlslDataType::kFloatVector, 3},
     {"degrees", 1, GLSLstd450Degrees, GlslDataType::kFloatScalarOrVector, 0},
+    {"determinant", 1, GLSLstd450Determinant, GlslDataType::kMatrix, 0},
     {"distance", 2, GLSLstd450Distance, GlslDataType::kFloatScalarOrVector, 0},
     {"exp", 1, GLSLstd450Exp, GlslDataType::kFloatScalarOrVector, 0},
     {"exp2", 1, GLSLstd450Exp2, GlslDataType::kFloatScalarOrVector, 0},
@@ -780,6 +782,13 @@
           return nullptr;
         }
         break;
+      case GlslDataType::kMatrix:
+        if (!result_types.back()->IsMatrix()) {
+          set_error(source,
+                    "incorrect type for " + name + ". Requires matrix value");
+          return nullptr;
+        }
+        break;
     }
   }
 
@@ -799,6 +808,10 @@
                ? result_types[0]
                : result_types[0]->AsVector()->type();
   }
+  // The determinant returns the component type of the columns
+  if (name == "determinant") {
+    return result_types[0]->AsMatrix()->type();
+  }
   return result_types[0];
 }
 
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 1587e99..8ec424f 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -3185,5 +3185,88 @@
                                          GLSLData{"umax", GLSLstd450UMax},
                                          GLSLData{"smax", GLSLstd450SMax}));
 
+TEST_F(TypeDeterminerTest, ImportData_GLSL_Determinant_Matrix) {
+  ast::type::F32Type f32;
+  ast::type::MatrixType mat(&f32, 3, 3);
+
+  auto var = std::make_unique<ast::Variable>(
+      "var", ast::StorageClass::kFunction, &mat);
+  mod()->AddGlobalVariable(std::move(var));
+
+  // Register the global
+  ASSERT_TRUE(td()->Determine()) << td()->error();
+
+  ast::ExpressionList params;
+  params.push_back(std::make_unique<ast::IdentifierExpression>("var"));
+
+  ASSERT_TRUE(td()->DetermineResultType(params)) << td()->error();
+
+  uint32_t id = 0;
+  auto* type =
+      td()->GetImportData({0, 0}, "GLSL.std.450", "determinant", params, &id);
+  ASSERT_NE(type, nullptr);
+  EXPECT_TRUE(type->IsF32());
+  EXPECT_EQ(id, GLSLstd450Determinant);
+}
+
+TEST_F(TypeDeterminerTest, ImportData_GLSL_Determinant_Error_Float) {
+  ast::type::F32Type f32;
+
+  auto var = std::make_unique<ast::Variable>(
+      "var", ast::StorageClass::kFunction, &f32);
+  mod()->AddGlobalVariable(std::move(var));
+
+  // Register the global
+  ASSERT_TRUE(td()->Determine()) << td()->error();
+
+  ast::ExpressionList params;
+  params.push_back(std::make_unique<ast::IdentifierExpression>("var"));
+
+  ASSERT_TRUE(td()->DetermineResultType(params)) << td()->error();
+
+  uint32_t id = 0;
+  auto* type =
+      td()->GetImportData({0, 0}, "GLSL.std.450", "determinant", params, &id);
+  ASSERT_EQ(type, nullptr);
+  EXPECT_EQ(td()->error(),
+            "incorrect type for determinant. Requires matrix value");
+}
+
+TEST_F(TypeDeterminerTest, ImportData_GLSL_Determinant_Error_NoParams) {
+  ast::ExpressionList params;
+
+  uint32_t id = 0;
+  auto* type =
+      td()->GetImportData({0, 0}, "GLSL.std.450", "determinant", params, &id);
+  ASSERT_EQ(type, nullptr);
+  EXPECT_EQ(td()->error(),
+            "incorrect number of parameters for determinant. Expected 1 got 0");
+}
+
+TEST_F(TypeDeterminerTest, ImportData_GLSL_Determinant_Error_TooManyParams) {
+  ast::type::F32Type f32;
+  ast::type::MatrixType mat(&f32, 3, 3);
+
+  auto var = std::make_unique<ast::Variable>(
+      "var", ast::StorageClass::kFunction, &mat);
+  mod()->AddGlobalVariable(std::move(var));
+
+  // Register the global
+  ASSERT_TRUE(td()->Determine()) << td()->error();
+
+  ast::ExpressionList params;
+  params.push_back(std::make_unique<ast::IdentifierExpression>("var"));
+  params.push_back(std::make_unique<ast::IdentifierExpression>("var"));
+
+  ASSERT_TRUE(td()->DetermineResultType(params)) << td()->error();
+
+  uint32_t id = 0;
+  auto* type =
+      td()->GetImportData({0, 0}, "GLSL.std.450", "determinant", params, &id);
+  ASSERT_EQ(type, nullptr);
+  EXPECT_EQ(td()->error(),
+            "incorrect number of parameters for determinant. Expected 1 got 2");
+}
+
 }  // namespace
 }  // namespace tint