[spirv-reader] Add OpBitcast

Bug: tint:3
Change-Id: I51f4521edeacf9e7c4d8dbf4a1832295b1705550
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/19886
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 49a445b..3d68847 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -511,6 +511,7 @@
     "src/reader/spirv/enum_converter_test.cc",
     "src/reader/spirv/fail_stream_test.cc",
     "src/reader/spirv/function_arithmetic_test.cc",
+    "src/reader/spirv/function_conversion_test.cc",
     "src/reader/spirv/function_decl_test.cc",
     "src/reader/spirv/function_logical_test.cc",
     "src/reader/spirv/function_memory_test.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6e2d82f..8a490be 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -326,6 +326,7 @@
     reader/spirv/enum_converter_test.cc
     reader/spirv/fail_stream_test.cc
     reader/spirv/function_arithmetic_test.cc
+    reader/spirv/function_conversion_test.cc
     reader/spirv/function_decl_test.cc
     reader/spirv/function_logical_test.cc
     reader/spirv/function_var_test.cc
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index d882907..33b6e4d 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -425,6 +425,13 @@
     return {ast_type, std::move(unary_expr)};
   }
 
+  if (inst.opcode() == SpvOpBitcast) {
+    auto target_ty = parser_impl_.ConvertType(inst.type_id());
+    auto cast = std::make_unique<ast::AsExpression>(target_ty, operand(0));
+    cast->set_result_type(target_ty);
+    return cast;
+  }
+
   // builtin readonly function
   // glsl.std.450 readonly function
 
@@ -434,13 +441,13 @@
   //    OpBitcast
   //    OpSatConvertSToU
   //    OpSatConvertUToS
-  //    OpSatConvertFToS
-  //    OpSatConvertFToU
-  //    OpSatConvertSToF
-  //    OpSatConvertUToF
-  //    OpUConvert
-  //    OpSConvert
-  //    OpFConvert
+  //    OpConvertFToS
+  //    OpConvertFToU
+  //    OpConvertSToF
+  //    OpConvertUToF
+  //    OpUConvert // Only needed when multiple widths supported
+  //    OpSConvert // Only needed when multiple widths supported
+  //    OpFConvert // Only needed when multiple widths supported
   //    OpConvertPtrToU // Not in WebGPU
   //    OpConvertUToPtr // Not in WebGPU
   //    OpPtrCastToGeneric // Not in Vulkan
diff --git a/src/reader/spirv/function_conversion_test.cc b/src/reader/spirv/function_conversion_test.cc
new file mode 100644
index 0000000..bdb3f90
--- /dev/null
+++ b/src/reader/spirv/function_conversion_test.cc
@@ -0,0 +1,136 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "src/reader/spirv/function.h"
+#include "src/reader/spirv/parser_impl.h"
+#include "src/reader/spirv/parser_impl_test_helper.h"
+#include "src/reader/spirv/spirv_tools_helpers_test.h"
+
+namespace tint {
+namespace reader {
+namespace spirv {
+namespace {
+
+using ::testing::HasSubstr;
+
+std::string CommonTypes() {
+  return R"(
+  %void = OpTypeVoid
+  %voidfn = OpTypeFunction %void
+
+  %uint = OpTypeInt 32 0
+  %int = OpTypeInt 32 1
+  %float = OpTypeFloat 32
+
+  %uint_10 = OpConstant %uint 10
+  %uint_20 = OpConstant %uint 20
+  %int_30 = OpConstant %int 30
+  %int_40 = OpConstant %int 40
+  %float_50 = OpConstant %float 50
+  %float_60 = OpConstant %float 60
+
+  %ptr_uint = OpTypePointer Function %uint
+  %ptr_int = OpTypePointer Function %int
+  %ptr_float = OpTypePointer Function %float
+
+  %v2uint = OpTypeVector %uint 2
+  %v2int = OpTypeVector %int 2
+  %v2float = OpTypeVector %float 2
+
+  %v2uint_10_20 = OpConstantComposite %v2uint %uint_10 %uint_20
+  %v2uint_20_10 = OpConstantComposite %v2uint %uint_20 %uint_10
+  %v2int_30_40 = OpConstantComposite %v2int %int_30 %int_40
+  %v2int_40_30 = OpConstantComposite %v2int %int_40 %int_30
+  %v2float_50_60 = OpConstantComposite %v2float %float_50 %float_60
+  %v2float_60_50 = OpConstantComposite %v2float %float_60 %float_50
+)";
+}
+
+using SpvUnaryConversionTest = SpvParserTestBase<::testing::Test>;
+
+TEST_F(SpvUnaryConversionTest, Bitcast_Scalar) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %1 = OpBitcast %uint %float_50
+     OpReturn
+     OpFunctionEnd
+  )";
+  auto p = parser(test::Assemble(assembly));
+  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+  FunctionEmitter fe(p, *spirv_function(100));
+  EXPECT_TRUE(fe.EmitBody()) << p->error();
+  EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(
+  Variable{
+    x_1
+    none
+    __u32
+    {
+      As<__u32>{
+        ScalarConstructor{50.000000}
+      }
+    }
+  })"))
+      << ToString(fe.ast_body());
+}
+
+TEST_F(SpvUnaryConversionTest, Bitcast_Vector) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %1 = OpBitcast %v2float %v2uint_10_20
+     OpReturn
+     OpFunctionEnd
+  )";
+  auto p = parser(test::Assemble(assembly));
+  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+  FunctionEmitter fe(p, *spirv_function(100));
+  EXPECT_TRUE(fe.EmitBody()) << p->error();
+  EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(
+  Variable{
+    x_1
+    none
+    __vec_2__f32
+    {
+      As<__vec_2__f32>{
+        TypeConstructor{
+          __vec_2__u32
+          ScalarConstructor{10}
+          ScalarConstructor{20}
+        }
+      }
+    }
+  })"))
+      << ToString(fe.ast_body());
+}
+
+// TODO(dneto): OpConvertFToU
+// TODO(dneto): OpConvertFToS
+// TODO(dneto): OpConvertUToF
+// TODO(dneto): OpConvertSToF
+// TODO(dneto): OpSConvert // only if multiple widths
+// TODO(dneto): OpUConvert // only if multiple widths
+// TODO(dneto): OpFConvert // only if multiple widths
+// TODO(dneto): OpQuantizeToF16 // only if f16 supported
+// TODO(dneto): OpConvertSToU
+// TODO(dneto): OpConvertUToS
+
+}  // namespace
+}  // namespace spirv
+}  // namespace reader
+}  // namespace tint