mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-08-07 20:49:25 +00:00
[spirv-reader] Add OpSNegate
Bug: tint:3 Change-Id: Id396319dd32216a71e21464d41bb2f2545929207 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/19882 Reviewed-by: dan sinclair <dsinclair@google.com>
This commit is contained in:
parent
e150e0f13e
commit
6584028bb4
@ -27,6 +27,8 @@
|
|||||||
#include "src/ast/scalar_constructor_expression.h"
|
#include "src/ast/scalar_constructor_expression.h"
|
||||||
#include "src/ast/storage_class.h"
|
#include "src/ast/storage_class.h"
|
||||||
#include "src/ast/uint_literal.h"
|
#include "src/ast/uint_literal.h"
|
||||||
|
#include "src/ast/unary_op.h"
|
||||||
|
#include "src/ast/unary_op_expression.h"
|
||||||
#include "src/ast/variable.h"
|
#include "src/ast/variable.h"
|
||||||
#include "src/ast/variable_decl_statement.h"
|
#include "src/ast/variable_decl_statement.h"
|
||||||
#include "src/reader/spirv/fail_stream.h"
|
#include "src/reader/spirv/fail_stream.h"
|
||||||
@ -37,6 +39,25 @@ namespace reader {
|
|||||||
namespace spirv {
|
namespace spirv {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// Gets the AST unary opcode for the given SPIR-V opcode, if any
|
||||||
|
// @param opcode SPIR-V opcode
|
||||||
|
// @param ast_unary_op return parameter
|
||||||
|
// @returns true if it was a unary operation
|
||||||
|
bool GetUnaryOp(SpvOp opcode, ast::UnaryOp* ast_unary_op) {
|
||||||
|
switch (opcode) {
|
||||||
|
case SpvOpSNegate:
|
||||||
|
*ast_unary_op = ast::UnaryOp::kNegation;
|
||||||
|
return true;
|
||||||
|
// TODO(dneto): SpvOpNegate SpvOpNot SpvLogicalNot
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts a SPIR-V opcode to its corresponding AST binary opcode, if any
|
||||||
|
// @param opcode SPIR-V opcode
|
||||||
// @returns the AST binary op for the given opcode, or kNone
|
// @returns the AST binary op for the given opcode, or kNone
|
||||||
ast::BinaryOp ConvertBinaryOp(SpvOp opcode) {
|
ast::BinaryOp ConvertBinaryOp(SpvOp opcode) {
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
@ -386,7 +407,20 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
|
|||||||
return {ast_type, std::move(binary_expr)};
|
return {ast_type, std::move(binary_expr)};
|
||||||
}
|
}
|
||||||
|
|
||||||
// unary operator
|
auto unary_op = ast::UnaryOp::kNegation;
|
||||||
|
if (GetUnaryOp(inst.opcode(), &unary_op)) {
|
||||||
|
auto arg0 = operand(0);
|
||||||
|
auto unary_expr = std::make_unique<ast::UnaryOpExpression>(
|
||||||
|
unary_op, std::move(arg0.expr));
|
||||||
|
auto* forced_result_ty =
|
||||||
|
parser_impl_.ForcedResultType(inst.opcode(), arg0.type);
|
||||||
|
if (forced_result_ty && forced_result_ty != ast_type) {
|
||||||
|
return {ast_type, std::make_unique<ast::AsExpression>(
|
||||||
|
ast_type, std::move(unary_expr))};
|
||||||
|
}
|
||||||
|
return {ast_type, std::move(unary_expr)};
|
||||||
|
}
|
||||||
|
|
||||||
// builtin readonly function
|
// builtin readonly function
|
||||||
// glsl.std.450 readonly function
|
// glsl.std.450 readonly function
|
||||||
|
|
||||||
|
@ -117,6 +117,223 @@ std::string AstFor(std::string assembly) {
|
|||||||
return "bad case";
|
return "bad case";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using SpvUnaryArithTest = SpvParserTestBase<::testing::Test>;
|
||||||
|
|
||||||
|
TEST_F(SpvUnaryArithTest, SNegate_Int_Int) {
|
||||||
|
const auto assembly = CommonTypes() + R"(
|
||||||
|
%100 = OpFunction %void None %voidfn
|
||||||
|
%entry = OpLabel
|
||||||
|
%1 = OpSNegate %int %int_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
|
||||||
|
__i32
|
||||||
|
{
|
||||||
|
UnaryOp{
|
||||||
|
negation
|
||||||
|
ScalarConstructor{30}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})"))
|
||||||
|
<< ToString(fe.ast_body());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvUnaryArithTest, SNegate_Int_Uint) {
|
||||||
|
const auto assembly = CommonTypes() + R"(
|
||||||
|
%100 = OpFunction %void None %voidfn
|
||||||
|
%entry = OpLabel
|
||||||
|
%1 = OpSNegate %int %uint_10
|
||||||
|
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
|
||||||
|
__i32
|
||||||
|
{
|
||||||
|
UnaryOp{
|
||||||
|
negation
|
||||||
|
As<__i32>{
|
||||||
|
ScalarConstructor{10}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})"))
|
||||||
|
<< ToString(fe.ast_body());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvUnaryArithTest, SNegate_Uint_Int) {
|
||||||
|
const auto assembly = CommonTypes() + R"(
|
||||||
|
%100 = OpFunction %void None %voidfn
|
||||||
|
%entry = OpLabel
|
||||||
|
%1 = OpSNegate %uint %int_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
|
||||||
|
__u32
|
||||||
|
{
|
||||||
|
As<__u32>{
|
||||||
|
UnaryOp{
|
||||||
|
negation
|
||||||
|
ScalarConstructor{30}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})"))
|
||||||
|
<< ToString(fe.ast_body());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvUnaryArithTest, SNegate_Uint_Uint) {
|
||||||
|
const auto assembly = CommonTypes() + R"(
|
||||||
|
%100 = OpFunction %void None %voidfn
|
||||||
|
%entry = OpLabel
|
||||||
|
%1 = OpSNegate %uint %uint_10
|
||||||
|
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>{
|
||||||
|
UnaryOp{
|
||||||
|
negation
|
||||||
|
As<__i32>{
|
||||||
|
ScalarConstructor{10}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})"))
|
||||||
|
<< ToString(fe.ast_body());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvUnaryArithTest, SNegate_SignedVec_SignedVec) {
|
||||||
|
const auto assembly = CommonTypes() + R"(
|
||||||
|
%100 = OpFunction %void None %voidfn
|
||||||
|
%entry = OpLabel
|
||||||
|
%1 = OpSNegate %v2int %v2int_30_40
|
||||||
|
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__i32
|
||||||
|
{
|
||||||
|
UnaryOp{
|
||||||
|
negation
|
||||||
|
TypeConstructor{
|
||||||
|
__vec_2__i32
|
||||||
|
ScalarConstructor{30}
|
||||||
|
ScalarConstructor{40}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})"))
|
||||||
|
<< ToString(fe.ast_body());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvUnaryArithTest, SNegate_SignedVec_UnsignedVec) {
|
||||||
|
const auto assembly = CommonTypes() + R"(
|
||||||
|
%100 = OpFunction %void None %voidfn
|
||||||
|
%entry = OpLabel
|
||||||
|
%1 = OpSNegate %v2int %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__i32
|
||||||
|
{
|
||||||
|
UnaryOp{
|
||||||
|
negation
|
||||||
|
As<__vec_2__i32>{
|
||||||
|
TypeConstructor{
|
||||||
|
__vec_2__u32
|
||||||
|
ScalarConstructor{10}
|
||||||
|
ScalarConstructor{20}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})"))
|
||||||
|
<< ToString(fe.ast_body());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvUnaryArithTest, SNegate_UnsignedVec_UnsignedVec) {
|
||||||
|
const auto assembly = CommonTypes() + R"(
|
||||||
|
%100 = OpFunction %void None %voidfn
|
||||||
|
%entry = OpLabel
|
||||||
|
%1 = OpSNegate %v2uint %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__u32
|
||||||
|
{
|
||||||
|
As<__vec_2__u32>{
|
||||||
|
UnaryOp{
|
||||||
|
negation
|
||||||
|
As<__vec_2__i32>{
|
||||||
|
TypeConstructor{
|
||||||
|
__vec_2__u32
|
||||||
|
ScalarConstructor{10}
|
||||||
|
ScalarConstructor{20}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})"))
|
||||||
|
<< ToString(fe.ast_body());
|
||||||
|
}
|
||||||
|
|
||||||
struct BinaryData {
|
struct BinaryData {
|
||||||
const std::string res_type;
|
const std::string res_type;
|
||||||
const std::string lhs;
|
const std::string lhs;
|
||||||
@ -804,6 +1021,28 @@ INSTANTIATE_TEST_SUITE_P(
|
|||||||
BinaryData{"v2int", "v2int_40_30", "OpBitwiseXor", "v2uint_20_10",
|
BinaryData{"v2int", "v2int_40_30", "OpBitwiseXor", "v2uint_20_10",
|
||||||
"__vec_2__i32", AstFor("v2int_40_30"), "xor",
|
"__vec_2__i32", AstFor("v2int_40_30"), "xor",
|
||||||
AstFor("v2uint_20_10")}));
|
AstFor("v2uint_20_10")}));
|
||||||
|
|
||||||
|
// TODO(dneto): OpSNegate
|
||||||
|
// TODO(dneto): OpFNegate
|
||||||
|
|
||||||
|
// TODO(dneto): OpSRem. Missing from WGSL
|
||||||
|
// https://github.com/gpuweb/gpuweb/issues/702
|
||||||
|
|
||||||
|
// TODO(dneto): OpFRem. Missing from WGSL
|
||||||
|
// https://github.com/gpuweb/gpuweb/issues/702
|
||||||
|
|
||||||
|
// TODO(dneto): OpVectorTimesScalar
|
||||||
|
// TODO(dneto): OpMatrixTimesScalar
|
||||||
|
// TODO(dneto): OpVectorTimesMatrix
|
||||||
|
// TODO(dneto): OpMatrixTimesVector
|
||||||
|
// TODO(dneto): OpMatrixTimesMatrix
|
||||||
|
// TODO(dneto): OpOuterProduct
|
||||||
|
// TODO(dneto): OpDot
|
||||||
|
// TODO(dneto): OpIAddCarry
|
||||||
|
// TODO(dneto): OpISubBorrow
|
||||||
|
// TODO(dneto): OpIMulExtended
|
||||||
|
// TODO(dneto): OpSMulExtended
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace spirv
|
} // namespace spirv
|
||||||
} // namespace reader
|
} // namespace reader
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
#include "src/ast/type/void_type.h"
|
#include "src/ast/type/void_type.h"
|
||||||
#include "src/ast/type_constructor_expression.h"
|
#include "src/ast/type_constructor_expression.h"
|
||||||
#include "src/ast/uint_literal.h"
|
#include "src/ast/uint_literal.h"
|
||||||
|
#include "src/ast/unary_op_expression.h"
|
||||||
#include "src/ast/variable.h"
|
#include "src/ast/variable.h"
|
||||||
#include "src/ast/variable_decl_statement.h"
|
#include "src/ast/variable_decl_statement.h"
|
||||||
#include "src/ast/variable_decoration.h"
|
#include "src/ast/variable_decoration.h"
|
||||||
@ -124,6 +125,7 @@ class FunctionTraverser {
|
|||||||
// Returns true if the opcode operates as if its operands are signed integral.
|
// Returns true if the opcode operates as if its operands are signed integral.
|
||||||
bool AssumesSignedOperands(SpvOp opcode) {
|
bool AssumesSignedOperands(SpvOp opcode) {
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
|
case SpvOpSNegate:
|
||||||
case SpvOpSDiv:
|
case SpvOpSDiv:
|
||||||
case SpvOpSRem:
|
case SpvOpSRem:
|
||||||
case SpvOpSMod:
|
case SpvOpSMod:
|
||||||
@ -158,9 +160,9 @@ bool AssumesUnsignedOperands(SpvOp opcode) {
|
|||||||
// the signedness of the result to match the signedness of the first operand.
|
// the signedness of the result to match the signedness of the first operand.
|
||||||
bool AssumesResultSignednessMatchesBinaryFirstOperand(SpvOp opcode) {
|
bool AssumesResultSignednessMatchesBinaryFirstOperand(SpvOp opcode) {
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
// TODO(dneto): More arithmetic operations.
|
|
||||||
case SpvOpSDiv:
|
case SpvOpSDiv:
|
||||||
case SpvOpSMod:
|
case SpvOpSMod:
|
||||||
|
case SpvOpSRem:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -947,7 +949,8 @@ ast::type::Type* ParserImpl::ForcedResultType(
|
|||||||
ast::type::Type* first_operand_type) {
|
ast::type::Type* first_operand_type) {
|
||||||
const bool binary_match_first_operand =
|
const bool binary_match_first_operand =
|
||||||
AssumesResultSignednessMatchesBinaryFirstOperand(op);
|
AssumesResultSignednessMatchesBinaryFirstOperand(op);
|
||||||
if (binary_match_first_operand) {
|
const bool unary_match_operand = (op == SpvOpSNegate);
|
||||||
|
if (binary_match_first_operand || unary_match_operand) {
|
||||||
return first_operand_type;
|
return first_operand_type;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user