tint: Add unit test for HasSideEffects for builtins
Change-Id: I7f2546c36a06cd9646ddf39601636954b9da0459 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/98541 Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Antonio Maiorano <amaiorano@google.com> Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
f7e2de7971
commit
50bc60359e
|
@ -19,6 +19,7 @@
|
|||
#include "src/tint/sem/expression.h"
|
||||
#include "src/tint/sem/index_accessor_expression.h"
|
||||
#include "src/tint/sem/member_accessor_expression.h"
|
||||
#include "src/tint/utils/vector.h"
|
||||
|
||||
using namespace tint::number_suffixes; // NOLINT
|
||||
|
||||
|
@ -124,6 +125,228 @@ TEST_F(SideEffectsTest, Call_Builtin_SE) {
|
|||
EXPECT_TRUE(sem->HasSideEffects());
|
||||
}
|
||||
|
||||
namespace builtin {
|
||||
struct Case {
|
||||
const char* name;
|
||||
utils::Vector<const char*, 3> args;
|
||||
bool has_side_effects;
|
||||
ast::PipelineStage pipeline_stage;
|
||||
};
|
||||
static Case C(const char* name,
|
||||
utils::VectorRef<const char*> args,
|
||||
bool has_side_effects,
|
||||
ast::PipelineStage stage = ast::PipelineStage::kFragment) {
|
||||
Case c;
|
||||
c.name = name;
|
||||
c.args = std::move(args);
|
||||
c.has_side_effects = has_side_effects;
|
||||
c.pipeline_stage = stage;
|
||||
return c;
|
||||
}
|
||||
static std::ostream& operator<<(std::ostream& o, const Case& c) {
|
||||
o << c.name << "(";
|
||||
for (size_t i = 0; i < c.args.Length(); ++i) {
|
||||
o << c.args[i];
|
||||
if (i + 1 != c.args.Length()) {
|
||||
o << ", ";
|
||||
}
|
||||
}
|
||||
o << "), ";
|
||||
o << "has_side_effects = " << c.has_side_effects;
|
||||
return o;
|
||||
}
|
||||
|
||||
using SideEffectsBuiltinTest = resolver::ResolverTestWithParam<Case>;
|
||||
|
||||
TEST_P(SideEffectsBuiltinTest, Test) {
|
||||
Enable(ast::Extension::kChromiumExperimentalDp4A);
|
||||
auto& c = GetParam();
|
||||
|
||||
uint32_t next_binding = 0;
|
||||
GlobalVar("f", ty.f32(), ast::StorageClass::kPrivate);
|
||||
GlobalVar("i", ty.i32(), ast::StorageClass::kPrivate);
|
||||
GlobalVar("u", ty.u32(), ast::StorageClass::kPrivate);
|
||||
GlobalVar("b", ty.bool_(), ast::StorageClass::kPrivate);
|
||||
GlobalVar("vf", ty.vec3<f32>(), ast::StorageClass::kPrivate);
|
||||
GlobalVar("vf2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
|
||||
GlobalVar("vi2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
|
||||
GlobalVar("vf4", ty.vec4<f32>(), ast::StorageClass::kPrivate);
|
||||
GlobalVar("vb", ty.vec3<bool>(), ast::StorageClass::kPrivate);
|
||||
GlobalVar("m", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
|
||||
GlobalVar("arr", ty.array<f32, 10>(), ast::StorageClass::kPrivate);
|
||||
GlobalVar("storage_arr", ty.array<f32>(), ast::StorageClass::kStorage,
|
||||
GroupAndBinding(0, next_binding++));
|
||||
GlobalVar("a", ty.atomic(ty.i32()), ast::StorageClass::kStorage, ast::Access::kReadWrite,
|
||||
GroupAndBinding(0, next_binding++));
|
||||
if (c.pipeline_stage != ast::PipelineStage::kCompute) {
|
||||
GlobalVar("t2d", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
|
||||
GroupAndBinding(0, next_binding++));
|
||||
GlobalVar("tdepth2d", ty.depth_texture(ast::TextureDimension::k2d),
|
||||
GroupAndBinding(0, next_binding++));
|
||||
GlobalVar("t2d_arr", ty.sampled_texture(ast::TextureDimension::k2dArray, ty.f32()),
|
||||
GroupAndBinding(0, next_binding++));
|
||||
GlobalVar("t2d_multi", ty.multisampled_texture(ast::TextureDimension::k2d, ty.f32()),
|
||||
GroupAndBinding(0, next_binding++));
|
||||
GlobalVar("tstorage2d",
|
||||
ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
|
||||
ast::Access::kWrite),
|
||||
GroupAndBinding(0, next_binding++));
|
||||
GlobalVar("s2d", ty.sampler(ast::SamplerKind::kSampler),
|
||||
GroupAndBinding(0, next_binding++));
|
||||
GlobalVar("scomp", ty.sampler(ast::SamplerKind::kComparisonSampler),
|
||||
GroupAndBinding(0, next_binding++));
|
||||
}
|
||||
|
||||
utils::Vector<const ast::Statement*, 4> stmts;
|
||||
stmts.Push(Decl(Let("pstorage_arr", nullptr, AddressOf("storage_arr"))));
|
||||
stmts.Push(Decl(Let("pa", nullptr, AddressOf("a"))));
|
||||
|
||||
utils::Vector<const ast::Expression*, 5> args;
|
||||
for (auto& a : c.args) {
|
||||
args.Push(Expr(a));
|
||||
}
|
||||
auto* expr = Call(c.name, args);
|
||||
|
||||
utils::Vector<const ast::Attribute*, 2> attrs;
|
||||
attrs.Push(create<ast::StageAttribute>(c.pipeline_stage));
|
||||
if (c.pipeline_stage == ast::PipelineStage::kCompute) {
|
||||
attrs.Push(WorkgroupSize(Expr(1_u)));
|
||||
}
|
||||
|
||||
stmts.Push(create<ast::CallStatement>(expr));
|
||||
|
||||
Func("func", utils::Empty, ty.void_(), stmts, attrs);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
auto* sem = Sem().Get(expr);
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_TRUE(sem->Is<sem::Call>());
|
||||
EXPECT_EQ(c.has_side_effects, sem->HasSideEffects());
|
||||
}
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SideEffectsTest_Builtins,
|
||||
SideEffectsBuiltinTest,
|
||||
testing::ValuesIn(std::vector<Case>{
|
||||
// No side-effect builts
|
||||
C("abs", utils::Vector{"f"}, false), //
|
||||
C("acos", utils::Vector{"f"}, false), //
|
||||
C("acosh", utils::Vector{"f"}, false), //
|
||||
C("all", utils::Vector{"vb"}, false), //
|
||||
C("any", utils::Vector{"vb"}, false), //
|
||||
C("arrayLength", utils::Vector{"pstorage_arr"}, false), //
|
||||
C("asin", utils::Vector{"f"}, false), //
|
||||
C("asinh", utils::Vector{"f"}, false), //
|
||||
C("atan", utils::Vector{"f"}, false), //
|
||||
C("atan2", utils::Vector{"f", "f"}, false), //
|
||||
C("atanh", utils::Vector{"f"}, false), //
|
||||
C("atomicLoad", utils::Vector{"pa"}, false), //
|
||||
C("ceil", utils::Vector{"f"}, false), //
|
||||
C("clamp", utils::Vector{"f", "f", "f"}, false), //
|
||||
C("cos", utils::Vector{"f"}, false), //
|
||||
C("cosh", utils::Vector{"f"}, false), //
|
||||
C("countLeadingZeros", utils::Vector{"i"}, false), //
|
||||
C("countOneBits", utils::Vector{"i"}, false), //
|
||||
C("countTrailingZeros", utils::Vector{"i"}, false), //
|
||||
C("cross", utils::Vector{"vf", "vf"}, false), //
|
||||
C("degrees", utils::Vector{"f"}, false), //
|
||||
C("determinant", utils::Vector{"m"}, false), //
|
||||
C("distance", utils::Vector{"f", "f"}, false), //
|
||||
C("dot", utils::Vector{"vf", "vf"}, false), //
|
||||
C("dot4I8Packed", utils::Vector{"u", "u"}, false), //
|
||||
C("dot4U8Packed", utils::Vector{"u", "u"}, false), //
|
||||
C("exp", utils::Vector{"f"}, false), //
|
||||
C("exp2", utils::Vector{"f"}, false), //
|
||||
C("extractBits", utils::Vector{"i", "u", "u"}, false), //
|
||||
C("faceForward", utils::Vector{"vf", "vf", "vf"}, false), //
|
||||
C("firstLeadingBit", utils::Vector{"u"}, false), //
|
||||
C("firstTrailingBit", utils::Vector{"u"}, false), //
|
||||
C("floor", utils::Vector{"f"}, false), //
|
||||
C("fma", utils::Vector{"f", "f", "f"}, false), //
|
||||
C("fract", utils::Vector{"vf"}, false), //
|
||||
C("frexp", utils::Vector{"f"}, false), //
|
||||
C("insertBits", utils::Vector{"i", "i", "u", "u"}, false), //
|
||||
C("inverseSqrt", utils::Vector{"f"}, false), //
|
||||
C("ldexp", utils::Vector{"f", "i"}, false), //
|
||||
C("length", utils::Vector{"vf"}, false), //
|
||||
C("log", utils::Vector{"f"}, false), //
|
||||
C("log2", utils::Vector{"f"}, false), //
|
||||
C("max", utils::Vector{"f", "f"}, false), //
|
||||
C("min", utils::Vector{"f", "f"}, false), //
|
||||
C("mix", utils::Vector{"f", "f", "f"}, false), //
|
||||
C("modf", utils::Vector{"f"}, false), //
|
||||
C("normalize", utils::Vector{"vf"}, false), //
|
||||
C("pack2x16float", utils::Vector{"vf2"}, false), //
|
||||
C("pack2x16snorm", utils::Vector{"vf2"}, false), //
|
||||
C("pack2x16unorm", utils::Vector{"vf2"}, false), //
|
||||
C("pack4x8snorm", utils::Vector{"vf4"}, false), //
|
||||
C("pack4x8unorm", utils::Vector{"vf4"}, false), //
|
||||
C("pow", utils::Vector{"f", "f"}, false), //
|
||||
C("radians", utils::Vector{"f"}, false), //
|
||||
C("reflect", utils::Vector{"vf", "vf"}, false), //
|
||||
C("refract", utils::Vector{"vf", "vf", "f"}, false), //
|
||||
C("reverseBits", utils::Vector{"u"}, false), //
|
||||
C("round", utils::Vector{"f"}, false), //
|
||||
C("select", utils::Vector{"f", "f", "b"}, false), //
|
||||
C("sign", utils::Vector{"f"}, false), //
|
||||
C("sin", utils::Vector{"f"}, false), //
|
||||
C("sinh", utils::Vector{"f"}, false), //
|
||||
C("smoothstep", utils::Vector{"f", "f", "f"}, false), //
|
||||
C("sqrt", utils::Vector{"f"}, false), //
|
||||
C("step", utils::Vector{"f", "f"}, false), //
|
||||
C("tan", utils::Vector{"f"}, false), //
|
||||
C("tanh", utils::Vector{"f"}, false), //
|
||||
C("textureDimensions", utils::Vector{"t2d"}, false), //
|
||||
C("textureGather", utils::Vector{"tdepth2d", "s2d", "vf2"}, false), //
|
||||
C("textureGatherCompare", utils::Vector{"tdepth2d", "scomp", "vf2", "f"}, false), //
|
||||
C("textureLoad", utils::Vector{"t2d", "vi2", "i"}, false), //
|
||||
C("textureNumLayers", utils::Vector{"t2d_arr"}, false), //
|
||||
C("textureNumLevels", utils::Vector{"t2d"}, false), //
|
||||
C("textureNumSamples", utils::Vector{"t2d_multi"}, false), //
|
||||
C("textureSampleCompareLevel", utils::Vector{"tdepth2d", "scomp", "vf2", "f"}, false), //
|
||||
C("textureSampleGrad", utils::Vector{"t2d", "s2d", "vf2", "vf2", "vf2"}, false), //
|
||||
C("textureSampleLevel", utils::Vector{"t2d", "s2d", "vf2", "f"}, false), //
|
||||
C("transpose", utils::Vector{"m"}, false), //
|
||||
C("trunc", utils::Vector{"f"}, false), //
|
||||
C("unpack2x16float", utils::Vector{"u"}, false), //
|
||||
C("unpack2x16snorm", utils::Vector{"u"}, false), //
|
||||
C("unpack2x16unorm", utils::Vector{"u"}, false), //
|
||||
C("unpack4x8snorm", utils::Vector{"u"}, false), //
|
||||
C("unpack4x8unorm", utils::Vector{"u"}, false), //
|
||||
C("storageBarrier", utils::Empty, false, ast::PipelineStage::kCompute), //
|
||||
C("workgroupBarrier", utils::Empty, false, ast::PipelineStage::kCompute), //
|
||||
C("textureSample", utils::Vector{"t2d", "s2d", "vf2"}, false), //
|
||||
C("textureSampleBias", utils::Vector{"t2d", "s2d", "vf2", "f"}, false), //
|
||||
C("textureSampleCompare", utils::Vector{"tdepth2d", "scomp", "vf2", "f"}, false), //
|
||||
C("dpdx", utils::Vector{"f"}, false), //
|
||||
C("dpdxCoarse", utils::Vector{"f"}, false), //
|
||||
C("dpdxFine", utils::Vector{"f"}, false), //
|
||||
C("dpdy", utils::Vector{"f"}, false), //
|
||||
C("dpdyCoarse", utils::Vector{"f"}, false), //
|
||||
C("dpdyFine", utils::Vector{"f"}, false), //
|
||||
C("fwidth", utils::Vector{"f"}, false), //
|
||||
C("fwidthCoarse", utils::Vector{"f"}, false), //
|
||||
C("fwidthFine", utils::Vector{"f"}, false), //
|
||||
|
||||
// Side-effect builtins
|
||||
C("atomicAdd", utils::Vector{"pa", "i"}, true), //
|
||||
C("atomicAnd", utils::Vector{"pa", "i"}, true), //
|
||||
C("atomicCompareExchangeWeak", utils::Vector{"pa", "i", "i"}, true), //
|
||||
C("atomicExchange", utils::Vector{"pa", "i"}, true), //
|
||||
C("atomicMax", utils::Vector{"pa", "i"}, true), //
|
||||
C("atomicMin", utils::Vector{"pa", "i"}, true), //
|
||||
C("atomicOr", utils::Vector{"pa", "i"}, true), //
|
||||
C("atomicStore", utils::Vector{"pa", "i"}, true), //
|
||||
C("atomicSub", utils::Vector{"pa", "i"}, true), //
|
||||
C("atomicXor", utils::Vector{"pa", "i"}, true), //
|
||||
C("textureStore", utils::Vector{"tstorage2d", "vi2", "vf4"}, true), //
|
||||
|
||||
// Unimplemented builtins
|
||||
// C("quantizeToF16", utils::Vector{"f"}, false), //
|
||||
// C("saturate", utils::Vector{"f"}, false), //
|
||||
}));
|
||||
|
||||
} // namespace builtin
|
||||
|
||||
TEST_F(SideEffectsTest, Call_Function) {
|
||||
Func("f", utils::Empty, ty.i32(), utils::Vector{Return(1_i)});
|
||||
auto* expr = Call("f");
|
||||
|
|
|
@ -153,11 +153,21 @@ bool Builtin::IsDP4a() const {
|
|||
}
|
||||
|
||||
bool Builtin::HasSideEffects() const {
|
||||
if (IsAtomic() && type_ != sem::BuiltinType::kAtomicLoad) {
|
||||
return true;
|
||||
}
|
||||
if (type_ == sem::BuiltinType::kTextureStore) {
|
||||
return true;
|
||||
switch (type_) {
|
||||
case sem::BuiltinType::kAtomicAdd:
|
||||
case sem::BuiltinType::kAtomicAnd:
|
||||
case sem::BuiltinType::kAtomicCompareExchangeWeak:
|
||||
case sem::BuiltinType::kAtomicExchange:
|
||||
case sem::BuiltinType::kAtomicMax:
|
||||
case sem::BuiltinType::kAtomicMin:
|
||||
case sem::BuiltinType::kAtomicOr:
|
||||
case sem::BuiltinType::kAtomicStore:
|
||||
case sem::BuiltinType::kAtomicSub:
|
||||
case sem::BuiltinType::kAtomicXor:
|
||||
case sem::BuiltinType::kTextureStore:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue