[spirv-writer] Fixup constructor with bitcast parameters.

Currently if a constructor contains constructors we consider it const.
This falls down with the new type constructor syntax if the types don't
match. In the case they don't match we no longer consider the
constructor const as we'll generate OpBitcast and OpCopyObject
instructions which we need to build the composite from.

Bug: tint: 263
Change-Id: Ic85f58c8410e862a2ec30c7d93c9b87a61822f6d
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/29523
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index addfdd1..b37fdd7 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -1100,6 +1100,8 @@
   std::ostringstream out;
   out << "__const";
 
+  auto* result_type = init->type()->UnwrapAliasPtrAlias();
+
   OperandList ops;
   bool constructor_is_const = true;
   for (const auto& e : values) {
@@ -1109,11 +1111,19 @@
         return 0;
       }
       constructor_is_const = false;
+      break;
+    } else if (result_type->IsVector()) {
+      // Even if we have constructor parameters if the types are different then
+      // the constructor is not const as we'll generate OpBitcast or
+      // OpCopyObject instructions.
+      auto* subtype = result_type->AsVector()->type()->UnwrapAliasPtrAlias();
+      if (subtype != e->result_type()->UnwrapAliasPtrAlias()) {
+        constructor_is_const = false;
+        break;
+      }
     }
   }
 
-  auto* result_type = init->type()->UnwrapAliasPtrAlias();
-
   bool can_cast_or_copy = result_type->is_scalar();
   if (result_type->IsVector() && result_type->AsVector()->type()->is_scalar()) {
     auto* value_type = values[0]->result_type()->UnwrapAliasPtrAlias();
diff --git a/src/writer/spirv/builder_constructor_expression_test.cc b/src/writer/spirv/builder_constructor_expression_test.cc
index 12ac999..db910e7 100644
--- a/src/writer/spirv/builder_constructor_expression_test.cc
+++ b/src/writer/spirv/builder_constructor_expression_test.cc
@@ -171,6 +171,43 @@
 )");
 }
 
+TEST_F(BuilderTest, Constructor_Vector_Bitcast_Params) {
+  ast::type::I32Type i32;
+  ast::type::U32Type u32;
+  ast::type::VectorType vec(&u32, 2);
+
+  ast::ExpressionList vals;
+  vals.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::SintLiteral>(&i32, 1)));
+  vals.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+      std::make_unique<ast::SintLiteral>(&i32, 1)));
+
+  ast::TypeConstructorExpression t(&vec, std::move(vals));
+
+  Context ctx;
+  ast::Module mod;
+  TypeDeterminer td(&ctx, &mod);
+  EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
+
+  Builder b(&mod);
+  b.push_function(Function{});
+
+  EXPECT_EQ(b.GenerateExpression(&t), 7u);
+  ASSERT_FALSE(b.has_error()) << b.error();
+
+  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
+%1 = OpTypeVector %2 2
+%3 = OpTypeInt 32 1
+%4 = OpConstant %3 1
+)");
+
+  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+            R"(%5 = OpBitcast %2 %4
+%6 = OpBitcast %2 %4
+%7 = OpCompositeConstruct %1 %5 %6
+)");
+}
+
 TEST_F(BuilderTest, Constructor_Type_NonConst_Value_Fails) {
   ast::type::F32Type f32;
   ast::type::VectorType vec(&f32, 2);
@@ -188,7 +225,11 @@
 
   ast::TypeConstructorExpression t(&vec, std::move(vals));
 
+  Context ctx;
   ast::Module mod;
+  TypeDeterminer td(&ctx, &mod);
+  EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
+
   Builder b(&mod);
   EXPECT_EQ(b.GenerateConstructorExpression(nullptr, &t, true), 0u);
   EXPECT_TRUE(b.has_error());