[spirv-reader] Support select over scalars and vectors
Still TODO: OpSelect over arrays and structures, as permitted in SPIR-V 1.4 Bug: tint:3, tint:99 Change-Id: I70f6c8a43ea3339cd715813c6eb0128d66ff0df8 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/25301 Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
d6b024b66d
commit
0a56a103be
|
@ -2605,7 +2605,8 @@ bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
return Fail() << "unhandled instruction with opcode " << inst.opcode();
|
||||
return Fail() << "unhandled instruction with opcode " << inst.opcode() << ": "
|
||||
<< inst.PrettyPrint();
|
||||
}
|
||||
|
||||
TypedExpression FunctionEmitter::MakeOperand(
|
||||
|
@ -2703,6 +2704,10 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
|
|||
return {ast_type, parser_impl_.MakeNullValue(ast_type)};
|
||||
}
|
||||
|
||||
if (opcode == SpvOpSelect) {
|
||||
return MakeSimpleSelect(inst);
|
||||
}
|
||||
|
||||
// builtin readonly function
|
||||
// glsl.std.450 readonly function
|
||||
|
||||
|
@ -3375,6 +3380,33 @@ bool FunctionEmitter::EmitFunctionCall(const spvtools::opt::Instruction& inst) {
|
|||
return EmitConstDefOrWriteToHoistedVar(inst, std::move(expr));
|
||||
}
|
||||
|
||||
TypedExpression FunctionEmitter::MakeSimpleSelect(
|
||||
const spvtools::opt::Instruction& inst) {
|
||||
auto condition = MakeOperand(inst, 0);
|
||||
auto operand1 = MakeOperand(inst, 1);
|
||||
auto operand2 = MakeOperand(inst, 2);
|
||||
|
||||
// SPIR-V validation requires:
|
||||
// - the condition to be bool or bool vector, so we don't check it here.
|
||||
// - operand1, operand2, and result type to match.
|
||||
// - you can't select over pointers or pointer vectors, unless you also have
|
||||
// a VariablePointers* capability, which is not allowed in by WebGPU.
|
||||
auto* op_ty = operand1.type;
|
||||
if (op_ty->IsVector() || op_ty->is_float_scalar() ||
|
||||
op_ty->is_integer_scalar() || op_ty->IsBool()) {
|
||||
ast::ExpressionList params;
|
||||
params.push_back(std::move(operand1.expr));
|
||||
params.push_back(std::move(operand2.expr));
|
||||
// The condition goes last.
|
||||
params.push_back(std::move(condition.expr));
|
||||
return {operand1.type,
|
||||
std::make_unique<ast::CallExpression>(
|
||||
std::make_unique<ast::IdentifierExpression>("select"),
|
||||
std::move(params))};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace spirv
|
||||
} // namespace reader
|
||||
} // namespace tint
|
||||
|
|
|
@ -676,6 +676,13 @@ class FunctionEmitter {
|
|||
/// @returns false if emission failed
|
||||
bool EmitFunctionCall(const spvtools::opt::Instruction& inst);
|
||||
|
||||
/// Returns an expression for an OpSelect, if its operands are scalars
|
||||
/// or vectors. These translate directly to WGSL select. Otherwise, return
|
||||
/// an expression with a null owned expression
|
||||
/// @param inst the SPIR-V OpSelect instruction
|
||||
/// @returns a typed expression, or one with a null owned expression
|
||||
TypedExpression MakeSimpleSelect(const spvtools::opt::Instruction& inst);
|
||||
|
||||
/// Finds the header block for a structured construct that we can "break"
|
||||
/// out from, from deeply nested control flow, if such a block exists.
|
||||
/// If the construct is:
|
||||
|
|
|
@ -1104,12 +1104,187 @@ TEST_F(SpvFUnordTest, FUnordGreaterThanEqual_Vector) {
|
|||
<< ToString(fe.ast_body());
|
||||
}
|
||||
|
||||
TEST_F(SpvFUnordTest, Select_BoolCond_BoolParams) {
|
||||
const auto assembly = CommonTypes() + R"(
|
||||
%100 = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%1 = OpSelect %bool %true %true %false
|
||||
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"(VariableDeclStatement{
|
||||
Variable{
|
||||
x_1
|
||||
none
|
||||
__bool
|
||||
{
|
||||
Call{
|
||||
Identifier{select}
|
||||
(
|
||||
ScalarConstructor{true}
|
||||
ScalarConstructor{false}
|
||||
ScalarConstructor{true}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})")) << ToString(fe.ast_body());
|
||||
}
|
||||
|
||||
TEST_F(SpvFUnordTest, Select_BoolCond_IntScalarParams) {
|
||||
const auto assembly = CommonTypes() + R"(
|
||||
%100 = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%1 = OpSelect %uint %true %uint_10 %uint_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"(VariableDeclStatement{
|
||||
Variable{
|
||||
x_1
|
||||
none
|
||||
__u32
|
||||
{
|
||||
Call{
|
||||
Identifier{select}
|
||||
(
|
||||
ScalarConstructor{10}
|
||||
ScalarConstructor{20}
|
||||
ScalarConstructor{true}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})")) << ToString(fe.ast_body());
|
||||
}
|
||||
|
||||
TEST_F(SpvFUnordTest, Select_BoolCond_FloatScalarParams) {
|
||||
const auto assembly = CommonTypes() + R"(
|
||||
%100 = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%1 = OpSelect %float %true %float_50 %float_60
|
||||
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"(VariableDeclStatement{
|
||||
Variable{
|
||||
x_1
|
||||
none
|
||||
__f32
|
||||
{
|
||||
Call{
|
||||
Identifier{select}
|
||||
(
|
||||
ScalarConstructor{50.000000}
|
||||
ScalarConstructor{60.000000}
|
||||
ScalarConstructor{true}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})")) << ToString(fe.ast_body());
|
||||
}
|
||||
|
||||
TEST_F(SpvFUnordTest, Select_BoolCond_VectorParams) {
|
||||
const auto assembly = CommonTypes() + R"(
|
||||
%100 = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%1 = OpSelect %v2uint %true %v2uint_10_20 %v2uint_20_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"(VariableDeclStatement{
|
||||
Variable{
|
||||
x_1
|
||||
none
|
||||
__vec_2__u32
|
||||
{
|
||||
Call{
|
||||
Identifier{select}
|
||||
(
|
||||
TypeConstructor{
|
||||
__vec_2__u32
|
||||
ScalarConstructor{10}
|
||||
ScalarConstructor{20}
|
||||
}
|
||||
TypeConstructor{
|
||||
__vec_2__u32
|
||||
ScalarConstructor{20}
|
||||
ScalarConstructor{10}
|
||||
}
|
||||
ScalarConstructor{true}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})")) << ToString(fe.ast_body());
|
||||
}
|
||||
|
||||
TEST_F(SpvFUnordTest, Select_VecBoolCond_VectorParams) {
|
||||
const auto assembly = CommonTypes() + R"(
|
||||
%100 = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%1 = OpSelect %v2uint %v2bool_t_f %v2uint_10_20 %v2uint_20_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"(VariableDeclStatement{
|
||||
Variable{
|
||||
x_1
|
||||
none
|
||||
__vec_2__u32
|
||||
{
|
||||
Call{
|
||||
Identifier{select}
|
||||
(
|
||||
TypeConstructor{
|
||||
__vec_2__u32
|
||||
ScalarConstructor{10}
|
||||
ScalarConstructor{20}
|
||||
}
|
||||
TypeConstructor{
|
||||
__vec_2__u32
|
||||
ScalarConstructor{20}
|
||||
ScalarConstructor{10}
|
||||
}
|
||||
TypeConstructor{
|
||||
__vec_2__bool
|
||||
ScalarConstructor{true}
|
||||
ScalarConstructor{false}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})")) << ToString(fe.ast_body());
|
||||
}
|
||||
|
||||
// TODO(dneto): OpAny - likely builtin function TBD
|
||||
// TODO(dneto): OpAll - likely builtin function TBD
|
||||
// TODO(dneto): OpIsNan - likely builtin function TBD
|
||||
// TODO(dneto): OpIsInf - likely builtin function TBD
|
||||
// TODO(dneto): Kernel-guarded instructions.
|
||||
// TODO(dneto): OpSelect - likely builtin function TBD
|
||||
// TODO(dneto): OpSelect over more general types, as in SPIR-V 1.4
|
||||
|
||||
} // namespace
|
||||
} // namespace spirv
|
||||
|
|
Loading…
Reference in New Issue