spirv-writer: support isFinite
Fixed: tint:157 Change-Id: I7b9af49edd44cbd8feb85fe637b82ac76a225e50 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/52420 Commit-Queue: David Neto <dneto@google.com> Auto-Submit: David Neto <dneto@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: James Price <jrprice@google.com>
This commit is contained in:
parent
7a47fa8495
commit
42d89ca199
|
@ -1971,6 +1971,22 @@ uint32_t Builder::GenerateIntrinsic(ast::CallExpression* call,
|
||||||
return result_id;
|
return result_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generates the SPIR-V ID for the expression for the indexed call parameter,
|
||||||
|
// and loads it if necessary. Returns 0 on error.
|
||||||
|
auto get_param_as_value_id = [&](size_t i) -> uint32_t {
|
||||||
|
auto* arg = call->params()[i];
|
||||||
|
auto& param = intrinsic->Parameters()[i];
|
||||||
|
auto val_id = GenerateExpression(arg);
|
||||||
|
if (val_id == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!param.type->Is<sem::Pointer>()) {
|
||||||
|
val_id = GenerateLoadIfNeeded(TypeOf(arg), val_id);
|
||||||
|
}
|
||||||
|
return val_id;
|
||||||
|
};
|
||||||
|
|
||||||
OperandList params = {Operand::Int(result_type_id), result};
|
OperandList params = {Operand::Int(result_type_id), result};
|
||||||
|
|
||||||
spv::Op op = spv::Op::OpNop;
|
spv::Op op = spv::Op::OpNop;
|
||||||
|
@ -2054,6 +2070,32 @@ uint32_t Builder::GenerateIntrinsic(ast::CallExpression* call,
|
||||||
case IntrinsicType::kIsNan:
|
case IntrinsicType::kIsNan:
|
||||||
op = spv::Op::OpIsNan;
|
op = spv::Op::OpIsNan;
|
||||||
break;
|
break;
|
||||||
|
case IntrinsicType::kIsFinite: {
|
||||||
|
// Implemented as: not(IsInf or IsNan)
|
||||||
|
auto val_id = get_param_as_value_id(0);
|
||||||
|
if (!val_id) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto inf_result = result_op();
|
||||||
|
auto nan_result = result_op();
|
||||||
|
auto or_result = result_op();
|
||||||
|
if (push_function_inst(spv::Op::OpIsInf,
|
||||||
|
{Operand::Int(result_type_id), inf_result,
|
||||||
|
Operand::Int(val_id)}) &&
|
||||||
|
push_function_inst(spv::Op::OpIsNan,
|
||||||
|
{Operand::Int(result_type_id), nan_result,
|
||||||
|
Operand::Int(val_id)}) &&
|
||||||
|
push_function_inst(spv::Op::OpLogicalOr,
|
||||||
|
{Operand::Int(result_type_id), or_result,
|
||||||
|
Operand::Int(inf_result.to_i()),
|
||||||
|
Operand::Int(nan_result.to_i())}) &&
|
||||||
|
push_function_inst(spv::Op::OpLogicalNot,
|
||||||
|
{Operand::Int(result_type_id), result,
|
||||||
|
Operand::Int(or_result.to_i())})) {
|
||||||
|
return result_id;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
case IntrinsicType::kReverseBits:
|
case IntrinsicType::kReverseBits:
|
||||||
op = spv::Op::OpBitReverse;
|
op = spv::Op::OpBitReverse;
|
||||||
break;
|
break;
|
||||||
|
@ -2090,18 +2132,11 @@ uint32_t Builder::GenerateIntrinsic(ast::CallExpression* call,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < call->params().size(); i++) {
|
for (size_t i = 0; i < call->params().size(); i++) {
|
||||||
auto* arg = call->params()[i];
|
if (auto val_id = get_param_as_value_id(i)) {
|
||||||
auto& param = intrinsic->Parameters()[i];
|
|
||||||
auto val_id = GenerateExpression(arg);
|
|
||||||
if (val_id == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!param.type->Is<sem::Pointer>()) {
|
|
||||||
val_id = GenerateLoadIfNeeded(TypeOf(arg), val_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
params.emplace_back(Operand::Int(val_id));
|
params.emplace_back(Operand::Int(val_id));
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!push_function_inst(op, params)) {
|
if (!push_function_inst(op, params)) {
|
||||||
|
|
|
@ -128,6 +128,62 @@ INSTANTIATE_TEST_SUITE_P(IntrinsicBuilderTest,
|
||||||
testing::Values(IntrinsicData{"isNan", "OpIsNan"},
|
testing::Values(IntrinsicData{"isNan", "OpIsNan"},
|
||||||
IntrinsicData{"isInf", "OpIsInf"}));
|
IntrinsicData{"isInf", "OpIsInf"}));
|
||||||
|
|
||||||
|
TEST_F(IntrinsicBuilderTest, IsFinite_Scalar) {
|
||||||
|
auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate);
|
||||||
|
|
||||||
|
auto* expr = Call("isFinite", "v");
|
||||||
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
b.push_function(Function{});
|
||||||
|
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
|
||||||
|
|
||||||
|
EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error();
|
||||||
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
|
||||||
|
%2 = OpTypePointer Private %3
|
||||||
|
%4 = OpConstantNull %3
|
||||||
|
%1 = OpVariable %2 Private %4
|
||||||
|
%6 = OpTypeBool
|
||||||
|
)");
|
||||||
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
||||||
|
R"(%7 = OpLoad %3 %1
|
||||||
|
%8 = OpIsInf %6 %7
|
||||||
|
%9 = OpIsNan %6 %7
|
||||||
|
%10 = OpLogicalOr %6 %8 %9
|
||||||
|
%5 = OpLogicalNot %6 %10
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(IntrinsicBuilderTest, IsFinite_Vector) {
|
||||||
|
auto* var = Global("v", ty.vec3<f32>(), ast::StorageClass::kPrivate);
|
||||||
|
|
||||||
|
auto* expr = Call("isFinite", "v");
|
||||||
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
b.push_function(Function{});
|
||||||
|
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
|
||||||
|
|
||||||
|
EXPECT_EQ(b.GenerateCallExpression(expr), 6u) << b.error();
|
||||||
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
|
||||||
|
%3 = OpTypeVector %4 3
|
||||||
|
%2 = OpTypePointer Private %3
|
||||||
|
%5 = OpConstantNull %3
|
||||||
|
%1 = OpVariable %2 Private %5
|
||||||
|
%8 = OpTypeBool
|
||||||
|
%7 = OpTypeVector %8 3
|
||||||
|
)");
|
||||||
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
||||||
|
R"(%9 = OpLoad %3 %1
|
||||||
|
%10 = OpIsInf %7 %9
|
||||||
|
%11 = OpIsNan %7 %9
|
||||||
|
%12 = OpLogicalOr %7 %10 %11
|
||||||
|
%6 = OpLogicalNot %7 %12
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
using IntrinsicIntTest = IntrinsicBuilderTestWithParam<IntrinsicData>;
|
using IntrinsicIntTest = IntrinsicBuilderTestWithParam<IntrinsicData>;
|
||||||
TEST_P(IntrinsicIntTest, Call_SInt_Scalar) {
|
TEST_P(IntrinsicIntTest, Call_SInt_Scalar) {
|
||||||
auto param = GetParam();
|
auto param = GetParam();
|
||||||
|
|
Loading…
Reference in New Issue