[spirv-builder] Generate load for cast expression.

If the value being casted is a pointer it must be loaded first. This CL
adds the needed load.

Bug: tint:72
Change-Id: Ia019b7976db6b97c811f6424db8fe4f07a3d11f3
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/20900
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: dan sinclair <dsinclair@google.com>
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index a8eaa1d..9483257 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -1163,6 +1163,7 @@
   if (val_id == 0) {
     return 0;
   }
+  val_id = GenerateLoadIfNeeded(cast->expr()->result_type(), val_id);
 
   auto* to_type = cast->result_type()->UnwrapPtrIfNeeded();
   auto* from_type = cast->expr()->result_type()->UnwrapPtrIfNeeded();
@@ -1178,7 +1179,8 @@
     op = spv::Op::OpConvertFToU;
   }
   if (op == spv::Op::OpNop) {
-    error_ = "unable to determine conversion type for cast";
+    error_ = "unable to determine conversion type for cast, from: " +
+             from_type->type_name() + " to: " + to_type->type_name();
     return 0;
   }
 
diff --git a/src/writer/spirv/builder_cast_expression_test.cc b/src/writer/spirv/builder_cast_expression_test.cc
index 0af27a2..90ca156 100644
--- a/src/writer/spirv/builder_cast_expression_test.cc
+++ b/src/writer/spirv/builder_cast_expression_test.cc
@@ -15,6 +15,7 @@
 #include "gtest/gtest.h"
 #include "src/ast/cast_expression.h"
 #include "src/ast/float_literal.h"
+#include "src/ast/identifier_expression.h"
 #include "src/ast/int_literal.h"
 #include "src/ast/module.h"
 #include "src/ast/scalar_constructor_expression.h"
@@ -64,7 +65,39 @@
 
 TEST_F(BuilderTest, DISABLED_Cast_U32ToFloat) {}
 
-TEST_F(BuilderTest, DISABLED_Cast_WithLoad) {}
+TEST_F(BuilderTest, Cast_WithLoad) {
+  ast::type::F32Type f32;
+  ast::type::I32Type i32;
+
+  // var i : i32 = 1;
+  // cast<f32>(i);
+  auto var =
+      std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &i32);
+
+  ast::CastExpression cast(&f32,
+                           std::make_unique<ast::IdentifierExpression>("i"));
+
+  Context ctx;
+  ast::Module mod;
+  TypeDeterminer td(&ctx, &mod);
+  td.RegisterVariableForTesting(var.get());
+  ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+  Builder b(&mod);
+  b.push_function(Function{});
+  ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
+  EXPECT_EQ(b.GenerateCastExpression(&cast), 4u) << b.error();
+
+  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
+%2 = OpTypePointer Private %3
+%1 = OpVariable %2 Private
+%5 = OpTypeFloat 32
+)");
+  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+            R"(%6 = OpLoad %3 %1
+%4 = OpConvertSToF %5 %6
+)");
+}
 
 TEST_F(BuilderTest, DISABLED_Cast_WithAlias) {}