[spirv-reader] Add ConvertSToF, ConvertUToF

Bug: tint:3
Change-Id: I28bcc109a207ef6f5225b9ea707bff11b1b6fd50
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/23420
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 117dcc9..932c5ca 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -35,6 +35,7 @@
 #include "src/ast/break_statement.h"
 #include "src/ast/call_expression.h"
 #include "src/ast/case_statement.h"
+#include "src/ast/cast_expression.h"
 #include "src/ast/continue_statement.h"
 #include "src/ast/else_statement.h"
 #include "src/ast/fallthrough_statement.h"
@@ -2533,6 +2534,9 @@
   if (opcode == SpvOpVectorShuffle) {
     return MakeVectorShuffle(inst);
   }
+  if (opcode == SpvOpConvertSToF || opcode == SpvOpConvertUToF) {
+    return MakeNumericConversion(inst);
+  }
 
   // builtin readonly function
   // glsl.std.450 readonly function
@@ -2545,8 +2549,6 @@
   //    OpSatConvertUToS
   //    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
@@ -2893,6 +2895,15 @@
   }
 }
 
+TypedExpression FunctionEmitter::MakeNumericConversion(
+    const spvtools::opt::Instruction& inst) {
+  auto* result_type = parser_impl_.ConvertType(inst.type_id());
+  auto arg_expr = MakeOperand(inst, 0);
+
+  return {result_type, std::make_unique<ast::CastExpression>(
+                           result_type, std::move(arg_expr.expr))};
+}
+
 }  // namespace spirv
 }  // namespace reader
 }  // namespace tint
diff --git a/src/reader/spirv/function.h b/src/reader/spirv/function.h
index 3d16aa9..fbab63b 100644
--- a/src/reader/spirv/function.h
+++ b/src/reader/spirv/function.h
@@ -463,6 +463,11 @@
   /// @returns an AST expression for the instruction, or nullptr.
   TypedExpression MakeVectorShuffle(const spvtools::opt::Instruction& inst);
 
+  /// Creates an expression for a numeric conversion.
+  /// @param inst a numeric conversion instruction
+  /// @returns an AST expression for the instruction, or nullptr.
+  TypedExpression MakeNumericConversion(const spvtools::opt::Instruction& inst);
+
   /// Gets the block info for a block ID, if any exists
   /// @param id the SPIR-V ID of the OpLabel instruction starting the block
   /// @returns the block info for the given ID, if it exists, or nullptr
diff --git a/src/reader/spirv/function_conversion_test.cc b/src/reader/spirv/function_conversion_test.cc
index 49aa594..92d3c6c 100644
--- a/src/reader/spirv/function_conversion_test.cc
+++ b/src/reader/spirv/function_conversion_test.cc
@@ -119,10 +119,224 @@
       << ToString(fe.ast_body());
 }
 
+TEST_F(SpvUnaryConversionTest, ConvertSToF_Scalar_FromSigned) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %30 = OpCopyObject %int %int_30
+     %1 = OpConvertSToF %float %30
+     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
+    __f32
+    {
+      Cast<__f32>(
+        Identifier{x_30}
+      )
+    }
+  })"))
+      << ToString(fe.ast_body());
+}
+
+TEST_F(SpvUnaryConversionTest, ConvertSToF_Scalar_FromUnsigned) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %30 = OpCopyObject %uint %uint_10
+     %1 = OpConvertSToF %float %30
+     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
+    __f32
+    {
+      Cast<__f32>(
+        As<__i32>{
+          Identifier{x_30}
+        }
+      )
+    }
+  })"))
+      << ToString(fe.ast_body());
+}
+
+TEST_F(SpvUnaryConversionTest, ConvertSToF_Vector_FromSigned) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %30 = OpCopyObject %v2int %v2int_30_40
+     %1 = OpConvertSToF %v2float %30
+     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
+    {
+      Cast<__vec_2__f32>(
+        Identifier{x_30}
+      )
+    }
+  })"))
+      << ToString(fe.ast_body());
+}
+
+TEST_F(SpvUnaryConversionTest, ConvertSToF_Vector_FromUnsigned) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %30 = OpCopyObject %v2uint %v2uint_10_20
+     %1 = OpConvertSToF %v2float %30
+     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
+    {
+      Cast<__vec_2__f32>(
+        As<__vec_2__i32>{
+          Identifier{x_30}
+        }
+      )
+    }
+  })"))
+      << ToString(fe.ast_body());
+}
+
+TEST_F(SpvUnaryConversionTest, ConvertUToF_Scalar_FromSigned) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %30 = OpCopyObject %int %int_30
+     %1 = OpConvertUToF %float %30
+     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
+    __f32
+    {
+      Cast<__f32>(
+        As<__u32>{
+          Identifier{x_30}
+        }
+      )
+    }
+  })"))
+      << ToString(fe.ast_body());
+}
+
+TEST_F(SpvUnaryConversionTest, ConvertUToF_Scalar_FromUnsigned) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %30 = OpCopyObject %uint %uint_10
+     %1 = OpConvertUToF %float %30
+     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
+    __f32
+    {
+      Cast<__f32>(
+        Identifier{x_30}
+      )
+    }
+  })"))
+      << ToString(fe.ast_body());
+}
+
+TEST_F(SpvUnaryConversionTest, ConvertUToF_Vector_FromSigned) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %30 = OpCopyObject %v2int %v2int_30_40
+     %1 = OpConvertUToF %v2float %30
+     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
+    {
+      Cast<__vec_2__f32>(
+        As<__vec_2__u32>{
+          Identifier{x_30}
+        }
+      )
+    }
+  })"))
+      << ToString(fe.ast_body());
+}
+
+TEST_F(SpvUnaryConversionTest, ConvertUToF_Vector_FromUnsigned) {
+  const auto assembly = CommonTypes() + R"(
+     %100 = OpFunction %void None %voidfn
+     %entry = OpLabel
+     %30 = OpCopyObject %v2uint %v2uint_10_20
+     %1 = OpConvertUToF %v2float %30
+     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
+    {
+      Cast<__vec_2__f32>(
+        Identifier{x_30}
+      )
+    }
+  })"))
+      << 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
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index c90a620c..54dcff5 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -133,6 +133,7 @@
     case SpvOpSLessThanEqual:
     case SpvOpSGreaterThan:
     case SpvOpSGreaterThanEqual:
+    case SpvOpConvertSToF:
       return true;
     default:
       break;
@@ -149,6 +150,7 @@
     case SpvOpULessThanEqual:
     case SpvOpUGreaterThan:
     case SpvOpUGreaterThanEqual:
+    case SpvOpConvertUToF:
       return true;
     default:
       break;