mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-14 09:06:11 +00:00
Remove duplicate tests. Use a common pattern of sanitizing, building and dumping the whole module instead of calling individual methods. There's too much internal state being tracked in the tests for my liking. Split most tests into three: * Const_* tests will check the emission of creation-time-constant expressions. * Runtime_* tests will check the emission of runtime expressions, where indexing operates with a constant index. * Dynamic_* tests will check the emission of runtime expressions, where indexing operates with a runtime index. Bug: tint:1580 Change-Id: I0f92aaaa570cbd917d2b6937c6396605c6b542c9 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94333 Reviewed-by: David Neto <dneto@google.com> Commit-Queue: Ben Clayton <bclayton@google.com>
1312 lines
36 KiB
C++
1312 lines
36 KiB
C++
// Copyright 2020 The Tint Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "src/tint/writer/spirv/spv_dump.h"
|
|
#include "src/tint/writer/spirv/test_helper.h"
|
|
|
|
using namespace tint::number_suffixes; // NOLINT
|
|
|
|
namespace tint::writer::spirv {
|
|
namespace {
|
|
|
|
using BuilderTest = TestHelper;
|
|
|
|
TEST_F(BuilderTest, Const_IndexAccessor_Vector) {
|
|
// let ary = vec3<i32>(1, 2, 3);
|
|
// var x = ary[1i];
|
|
|
|
auto* ary = Let("ary", nullptr, vec3<i32>(1_i, 2_i, 3_i));
|
|
auto* x = Var("x", nullptr, IndexAccessor(ary, 1_i));
|
|
WrapInFunction(ary, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%6 = OpTypeInt 32 1
|
|
%5 = OpTypeVector %6 3
|
|
%7 = OpConstant %6 1
|
|
%8 = OpConstant %6 2
|
|
%9 = OpConstant %6 3
|
|
%10 = OpConstantComposite %5 %7 %8 %9
|
|
%12 = OpTypePointer Function %6
|
|
%13 = OpConstantNull %6
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%11 = OpVariable %12 Function %13
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %11 %8
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Runtime_IndexAccessor_Vector) {
|
|
// var ary : vec3<u32>;
|
|
// var x = ary[1i];
|
|
|
|
auto* ary = Var("ary", ty.vec3<u32>());
|
|
auto* x = Var("x", nullptr, IndexAccessor(ary, 1_i));
|
|
WrapInFunction(ary, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%8 = OpTypeInt 32 0
|
|
%7 = OpTypeVector %8 3
|
|
%6 = OpTypePointer Function %7
|
|
%9 = OpConstantNull %7
|
|
%10 = OpTypeInt 32 1
|
|
%11 = OpConstant %10 1
|
|
%12 = OpTypePointer Function %8
|
|
%16 = OpConstantNull %8
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
|
|
%15 = OpVariable %12 Function %16
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%13 = OpAccessChain %12 %5 %11
|
|
%14 = OpLoad %8 %13
|
|
OpStore %15 %14
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Dynamic_IndexAccessor_Vector) {
|
|
// var ary : vec3<f32>;
|
|
// var idx : i32;
|
|
// var x = ary[idx];
|
|
|
|
auto* ary = Var("ary", ty.vec3<f32>());
|
|
auto* idx = Var("idx", ty.i32());
|
|
auto* x = Var("x", nullptr, IndexAccessor(ary, idx));
|
|
WrapInFunction(ary, idx, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%8 = OpTypeFloat 32
|
|
%7 = OpTypeVector %8 3
|
|
%6 = OpTypePointer Function %7
|
|
%9 = OpConstantNull %7
|
|
%12 = OpTypeInt 32 1
|
|
%11 = OpTypePointer Function %12
|
|
%13 = OpConstantNull %12
|
|
%15 = OpTypePointer Function %8
|
|
%19 = OpConstantNull %8
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
|
|
%10 = OpVariable %11 Function %13
|
|
%18 = OpVariable %15 Function %19
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%14 = OpLoad %12 %10
|
|
%16 = OpAccessChain %15 %5 %14
|
|
%17 = OpLoad %8 %16
|
|
OpStore %18 %17
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Const_IndexAccessor_Vector2) {
|
|
// let ary : vec3<i32>(1, 2, 3);
|
|
// var x = ary[1i + 2i];
|
|
|
|
auto* ary = Let("ary", nullptr, vec3<i32>(1_i, 2_i, 3_i));
|
|
auto* x = Var("x", nullptr, IndexAccessor(ary, Add(1_i, 2_i)));
|
|
WrapInFunction(ary, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%6 = OpTypeInt 32 1
|
|
%5 = OpTypeVector %6 3
|
|
%7 = OpConstant %6 1
|
|
%8 = OpConstant %6 2
|
|
%9 = OpConstant %6 3
|
|
%10 = OpConstantComposite %5 %7 %8 %9
|
|
%14 = OpTypePointer Function %6
|
|
%15 = OpConstantNull %6
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%13 = OpVariable %14 Function %15
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%11 = OpIAdd %6 %7 %8
|
|
%12 = OpVectorExtractDynamic %6 %10 %11
|
|
OpStore %13 %12
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Runtime_IndexAccessor_Vector2) {
|
|
// var ary : vec3<f32>;
|
|
// var x = ary[1i + 2i];
|
|
|
|
auto* ary = Var("ary", ty.vec3<f32>());
|
|
auto* x = Var("x", nullptr, IndexAccessor(ary, Add(1_i, 2_i)));
|
|
WrapInFunction(ary, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%8 = OpTypeFloat 32
|
|
%7 = OpTypeVector %8 3
|
|
%6 = OpTypePointer Function %7
|
|
%9 = OpConstantNull %7
|
|
%10 = OpTypeInt 32 1
|
|
%11 = OpConstant %10 1
|
|
%12 = OpConstant %10 2
|
|
%14 = OpTypePointer Function %8
|
|
%18 = OpConstantNull %8
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
|
|
%17 = OpVariable %14 Function %18
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%13 = OpIAdd %10 %11 %12
|
|
%15 = OpAccessChain %14 %5 %13
|
|
%16 = OpLoad %8 %15
|
|
OpStore %17 %16
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Dynamic_IndexAccessor_Vector2) {
|
|
// var ary : vec3<f32>;
|
|
// var one = 1i;
|
|
// var x = ary[one + 2i];
|
|
|
|
auto* ary = Var("ary", ty.vec3<f32>());
|
|
auto* one = Var("one", nullptr, Expr(1_i));
|
|
auto* x = Var("x", nullptr, IndexAccessor(ary, Add(one, 2_i)));
|
|
WrapInFunction(ary, one, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%8 = OpTypeFloat 32
|
|
%7 = OpTypeVector %8 3
|
|
%6 = OpTypePointer Function %7
|
|
%9 = OpConstantNull %7
|
|
%10 = OpTypeInt 32 1
|
|
%11 = OpConstant %10 1
|
|
%13 = OpTypePointer Function %10
|
|
%14 = OpConstantNull %10
|
|
%16 = OpConstant %10 2
|
|
%18 = OpTypePointer Function %8
|
|
%22 = OpConstantNull %8
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
|
|
%12 = OpVariable %13 Function %14
|
|
%21 = OpVariable %18 Function %22
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %12 %11
|
|
%15 = OpLoad %10 %12
|
|
%17 = OpIAdd %10 %15 %16
|
|
%19 = OpAccessChain %18 %5 %17
|
|
%20 = OpLoad %8 %19
|
|
OpStore %21 %20
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Const_IndexAccessor_Array_MultiLevel) {
|
|
// let ary = array<vec3<f32>, 2u>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(4.0f, 5.0f, 6.0f));
|
|
// var x = ary[1i][2i];
|
|
|
|
auto* ary =
|
|
Let("ary", nullptr,
|
|
array(ty.vec3<f32>(), 2_u, vec3<f32>(1._f, 2._f, 3._f), vec3<f32>(4._f, 5._f, 6._f)));
|
|
auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(ary, 1_i), 2_i));
|
|
WrapInFunction(ary, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%7 = OpTypeFloat 32
|
|
%6 = OpTypeVector %7 3
|
|
%8 = OpTypeInt 32 0
|
|
%9 = OpConstant %8 2
|
|
%5 = OpTypeArray %6 %9
|
|
%10 = OpConstant %7 1
|
|
%11 = OpConstant %7 2
|
|
%12 = OpConstant %7 3
|
|
%13 = OpConstantComposite %6 %10 %11 %12
|
|
%14 = OpConstant %7 4
|
|
%15 = OpConstant %7 5
|
|
%16 = OpConstant %7 6
|
|
%17 = OpConstantComposite %6 %14 %15 %16
|
|
%18 = OpConstantComposite %5 %13 %17
|
|
%19 = OpTypeInt 32 1
|
|
%20 = OpConstant %19 1
|
|
%22 = OpConstant %19 2
|
|
%25 = OpTypePointer Function %7
|
|
%26 = OpConstantNull %7
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%24 = OpVariable %25 Function %26
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
|
R"(%21 = OpCompositeExtract %6 %18 1
|
|
%23 = OpCompositeExtract %7 %21 2
|
|
OpStore %24 %23
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Runtime_IndexAccessor_Array_MultiLevel) {
|
|
// var ary : array<vec3<f32>, 4u>;
|
|
// var x = ary[1i][2i];
|
|
|
|
auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
|
|
auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(ary, 1_i), 2_i));
|
|
WrapInFunction(ary, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%9 = OpTypeFloat 32
|
|
%8 = OpTypeVector %9 3
|
|
%10 = OpTypeInt 32 0
|
|
%11 = OpConstant %10 4
|
|
%7 = OpTypeArray %8 %11
|
|
%6 = OpTypePointer Function %7
|
|
%12 = OpConstantNull %7
|
|
%13 = OpTypeInt 32 1
|
|
%14 = OpConstant %13 1
|
|
%15 = OpConstant %13 2
|
|
%16 = OpTypePointer Function %9
|
|
%20 = OpConstantNull %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
|
|
%19 = OpVariable %16 Function %20
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
|
R"(%17 = OpAccessChain %16 %5 %14 %15
|
|
%18 = OpLoad %9 %17
|
|
OpStore %19 %18
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Dynamic_IndexAccessor_Array_MultiLevel) {
|
|
// var ary : array<vec3<f32>, 4u>;
|
|
// var one = 1i;
|
|
// var x = ary[one][2i];
|
|
|
|
auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
|
|
auto* one = Var("one", nullptr, Expr(3_i));
|
|
auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(ary, one), 2_i));
|
|
WrapInFunction(ary, one, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%9 = OpTypeFloat 32
|
|
%8 = OpTypeVector %9 3
|
|
%10 = OpTypeInt 32 0
|
|
%11 = OpConstant %10 4
|
|
%7 = OpTypeArray %8 %11
|
|
%6 = OpTypePointer Function %7
|
|
%12 = OpConstantNull %7
|
|
%13 = OpTypeInt 32 1
|
|
%14 = OpConstant %13 3
|
|
%16 = OpTypePointer Function %13
|
|
%17 = OpConstantNull %13
|
|
%19 = OpConstant %13 2
|
|
%20 = OpTypePointer Function %9
|
|
%24 = OpConstantNull %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
|
|
%15 = OpVariable %16 Function %17
|
|
%23 = OpVariable %20 Function %24
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %15 %14
|
|
%18 = OpLoad %13 %15
|
|
%21 = OpAccessChain %20 %5 %18 %19
|
|
%22 = OpLoad %9 %21
|
|
OpStore %23 %22
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Const_IndexAccessor_Array_ArrayWithSwizzle) {
|
|
// let ary = array<vec3<f32>, 2u>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(4.0f, 5.0f, 6.0f));
|
|
// var x = a[1i].xy;
|
|
|
|
auto* ary =
|
|
Let("ary", nullptr,
|
|
array(ty.vec3<f32>(), 2_u, vec3<f32>(1._f, 2._f, 3._f), vec3<f32>(4._f, 5._f, 6._f)));
|
|
auto* x = Var("x", nullptr, MemberAccessor(IndexAccessor("ary", 1_i), "xy"));
|
|
WrapInFunction(ary, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%7 = OpTypeFloat 32
|
|
%6 = OpTypeVector %7 3
|
|
%8 = OpTypeInt 32 0
|
|
%9 = OpConstant %8 2
|
|
%5 = OpTypeArray %6 %9
|
|
%10 = OpConstant %7 1
|
|
%11 = OpConstant %7 2
|
|
%12 = OpConstant %7 3
|
|
%13 = OpConstantComposite %6 %10 %11 %12
|
|
%14 = OpConstant %7 4
|
|
%15 = OpConstant %7 5
|
|
%16 = OpConstant %7 6
|
|
%17 = OpConstantComposite %6 %14 %15 %16
|
|
%18 = OpConstantComposite %5 %13 %17
|
|
%19 = OpTypeInt 32 1
|
|
%20 = OpConstant %19 1
|
|
%22 = OpTypeVector %7 2
|
|
%25 = OpTypePointer Function %22
|
|
%26 = OpConstantNull %22
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%24 = OpVariable %25 Function %26
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
|
R"(%21 = OpCompositeExtract %6 %18 1
|
|
%23 = OpVectorShuffle %22 %21 %21 0 1
|
|
OpStore %24 %23
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Runtime_IndexAccessor_Array_ArrayWithSwizzle) {
|
|
// var ary : array<vec3<f32>, 4u>;
|
|
// var x = ary[1i].xy;
|
|
|
|
auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
|
|
auto* x = Var("x", nullptr, MemberAccessor(IndexAccessor("ary", 1_i), "xy"));
|
|
WrapInFunction(ary, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%9 = OpTypeFloat 32
|
|
%8 = OpTypeVector %9 3
|
|
%10 = OpTypeInt 32 0
|
|
%11 = OpConstant %10 4
|
|
%7 = OpTypeArray %8 %11
|
|
%6 = OpTypePointer Function %7
|
|
%12 = OpConstantNull %7
|
|
%13 = OpTypeInt 32 1
|
|
%14 = OpConstant %13 1
|
|
%15 = OpTypePointer Function %8
|
|
%17 = OpTypeVector %9 2
|
|
%21 = OpTypePointer Function %17
|
|
%22 = OpConstantNull %17
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
|
|
%20 = OpVariable %21 Function %22
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%16 = OpAccessChain %15 %5 %14
|
|
%18 = OpLoad %8 %16
|
|
%19 = OpVectorShuffle %17 %18 %18 0 1
|
|
OpStore %20 %19
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Dynamic_IndexAccessor_Array_ArrayWithSwizzle) {
|
|
// var ary : array<vec3<f32>, 4u>;
|
|
// var one = 1i;
|
|
// var x = ary[one].xy;
|
|
|
|
auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
|
|
auto* one = Var("one", nullptr, Expr(1_i));
|
|
auto* x = Var("x", nullptr, MemberAccessor(IndexAccessor("ary", one), "xy"));
|
|
WrapInFunction(ary, one, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%9 = OpTypeFloat 32
|
|
%8 = OpTypeVector %9 3
|
|
%10 = OpTypeInt 32 0
|
|
%11 = OpConstant %10 4
|
|
%7 = OpTypeArray %8 %11
|
|
%6 = OpTypePointer Function %7
|
|
%12 = OpConstantNull %7
|
|
%13 = OpTypeInt 32 1
|
|
%14 = OpConstant %13 1
|
|
%16 = OpTypePointer Function %13
|
|
%17 = OpConstantNull %13
|
|
%19 = OpTypePointer Function %8
|
|
%21 = OpTypeVector %9 2
|
|
%25 = OpTypePointer Function %21
|
|
%26 = OpConstantNull %21
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
|
|
%15 = OpVariable %16 Function %17
|
|
%24 = OpVariable %25 Function %26
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %15 %14
|
|
%18 = OpLoad %13 %15
|
|
%20 = OpAccessChain %19 %5 %18
|
|
%22 = OpLoad %8 %20
|
|
%23 = OpVectorShuffle %21 %22 %22 0 1
|
|
OpStore %24 %23
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Const_IndexAccessor_Nested_Array_f32) {
|
|
// let pos : array<array<f32, 2>, 3u> = array<vec2<f32, 2>, 3u>(
|
|
// array<f32, 2>(0.0, 0.5),
|
|
// array<f32, 2>(-0.5, -0.5),
|
|
// array<f32, 2>(0.5, -0.5));
|
|
// var x = pos[1u][0u];
|
|
|
|
auto* pos = Let("pos", ty.array(ty.vec2<f32>(), 3_u),
|
|
Construct(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0_f, 0.5_f),
|
|
vec2<f32>(-0.5_f, -0.5_f), vec2<f32>(0.5_f, -0.5_f)));
|
|
auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(pos, 1_u), 0_u));
|
|
WrapInFunction(pos, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%7 = OpTypeFloat 32
|
|
%6 = OpTypeVector %7 2
|
|
%8 = OpTypeInt 32 0
|
|
%9 = OpConstant %8 3
|
|
%5 = OpTypeArray %6 %9
|
|
%10 = OpConstantNull %7
|
|
%11 = OpConstant %7 0.5
|
|
%12 = OpConstantComposite %6 %10 %11
|
|
%13 = OpConstant %7 -0.5
|
|
%14 = OpConstantComposite %6 %13 %13
|
|
%15 = OpConstantComposite %6 %11 %13
|
|
%16 = OpConstantComposite %5 %12 %14 %15
|
|
%17 = OpConstant %8 1
|
|
%19 = OpConstantNull %8
|
|
%22 = OpTypePointer Function %7
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%21 = OpVariable %22 Function %10
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
|
R"(%18 = OpCompositeExtract %6 %16 1
|
|
%20 = OpCompositeExtract %7 %18 0
|
|
OpStore %21 %20
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Runtime_IndexAccessor_Nested_Array_f32) {
|
|
// var pos : array<array<f32, 2>, 3u>;
|
|
// var x = pos[1u][2u];
|
|
|
|
auto* pos = Var("pos", ty.array(ty.vec2<f32>(), 3_u));
|
|
auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(pos, 1_u), 2_u));
|
|
WrapInFunction(pos, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%9 = OpTypeFloat 32
|
|
%8 = OpTypeVector %9 2
|
|
%10 = OpTypeInt 32 0
|
|
%11 = OpConstant %10 3
|
|
%7 = OpTypeArray %8 %11
|
|
%6 = OpTypePointer Function %7
|
|
%12 = OpConstantNull %7
|
|
%13 = OpConstant %10 1
|
|
%14 = OpConstant %10 2
|
|
%15 = OpTypePointer Function %9
|
|
%19 = OpConstantNull %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
|
|
%18 = OpVariable %15 Function %19
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
|
R"(%16 = OpAccessChain %15 %5 %13 %14
|
|
%17 = OpLoad %9 %16
|
|
OpStore %18 %17
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Dynamic_IndexAccessor_Nested_Array_f32) {
|
|
// var pos : array<array<f32, 2>, 3u>;
|
|
// var one = 1u;
|
|
// var x = pos[one][2u];
|
|
|
|
auto* pos = Var("pos", ty.array(ty.vec2<f32>(), 3_u));
|
|
auto* one = Var("one", nullptr, Expr(2_u));
|
|
auto* x = Var("x", nullptr, IndexAccessor(IndexAccessor(pos, "one"), 2_u));
|
|
WrapInFunction(pos, one, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%9 = OpTypeFloat 32
|
|
%8 = OpTypeVector %9 2
|
|
%10 = OpTypeInt 32 0
|
|
%11 = OpConstant %10 3
|
|
%7 = OpTypeArray %8 %11
|
|
%6 = OpTypePointer Function %7
|
|
%12 = OpConstantNull %7
|
|
%13 = OpConstant %10 2
|
|
%15 = OpTypePointer Function %10
|
|
%16 = OpConstantNull %10
|
|
%18 = OpTypePointer Function %9
|
|
%22 = OpConstantNull %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %12
|
|
%14 = OpVariable %15 Function %16
|
|
%21 = OpVariable %18 Function %22
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %14 %13
|
|
%17 = OpLoad %10 %14
|
|
%19 = OpAccessChain %18 %5 %17 %13
|
|
%20 = OpLoad %9 %19
|
|
OpStore %21 %20
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Const_IndexAccessor_Matrix) {
|
|
// let a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
|
|
// var x = a[1i]
|
|
|
|
auto* a = Let("a", ty.mat2x2<f32>(),
|
|
Construct(ty.mat2x2<f32>(), Construct(ty.vec2<f32>(), 1_f, 2_f),
|
|
Construct(ty.vec2<f32>(), 3_f, 4_f)));
|
|
auto* x = Var("x", nullptr, IndexAccessor("a", 1_i));
|
|
WrapInFunction(a, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%7 = OpTypeFloat 32
|
|
%6 = OpTypeVector %7 2
|
|
%5 = OpTypeMatrix %6 2
|
|
%8 = OpConstant %7 1
|
|
%9 = OpConstant %7 2
|
|
%10 = OpConstantComposite %6 %8 %9
|
|
%11 = OpConstant %7 3
|
|
%12 = OpConstant %7 4
|
|
%13 = OpConstantComposite %6 %11 %12
|
|
%14 = OpConstantComposite %5 %10 %13
|
|
%16 = OpTypePointer Function %6
|
|
%17 = OpConstantNull %6
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%15 = OpVariable %16 Function %17
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %15 %13
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Runtime_IndexAccessor_Matrix) {
|
|
// var a : mat2x2<f32>;
|
|
// var x = a[1i]
|
|
|
|
auto* a = Var("a", ty.mat2x2<f32>());
|
|
auto* x = Var("x", nullptr, IndexAccessor("a", 1_i));
|
|
WrapInFunction(a, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%9 = OpTypeFloat 32
|
|
%8 = OpTypeVector %9 2
|
|
%7 = OpTypeMatrix %8 2
|
|
%6 = OpTypePointer Function %7
|
|
%10 = OpConstantNull %7
|
|
%11 = OpTypeInt 32 1
|
|
%12 = OpConstant %11 1
|
|
%13 = OpTypePointer Function %8
|
|
%17 = OpConstantNull %8
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
|
|
%16 = OpVariable %13 Function %17
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%14 = OpAccessChain %13 %5 %12
|
|
%15 = OpLoad %8 %14
|
|
OpStore %16 %15
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, Dynamic_IndexAccessor_Matrix) {
|
|
// var a : mat2x2<f32>;
|
|
// var idx : i32
|
|
// var x = a[idx]
|
|
|
|
auto* a = Var("a", ty.mat2x2<f32>());
|
|
auto* idx = Var("idx", ty.i32());
|
|
auto* x = Var("x", nullptr, IndexAccessor("a", idx));
|
|
WrapInFunction(a, idx, x);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%9 = OpTypeFloat 32
|
|
%8 = OpTypeVector %9 2
|
|
%7 = OpTypeMatrix %8 2
|
|
%6 = OpTypePointer Function %7
|
|
%10 = OpConstantNull %7
|
|
%13 = OpTypeInt 32 1
|
|
%12 = OpTypePointer Function %13
|
|
%14 = OpConstantNull %13
|
|
%16 = OpTypePointer Function %8
|
|
%20 = OpConstantNull %8
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
|
|
%11 = OpVariable %12 Function %14
|
|
%19 = OpVariable %16 Function %20
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%15 = OpLoad %13 %11
|
|
%17 = OpAccessChain %16 %5 %15
|
|
%18 = OpLoad %8 %17
|
|
OpStore %19 %18
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, MemberAccessor) {
|
|
// my_struct {
|
|
// a : f32
|
|
// b : f32
|
|
// }
|
|
// var ident : my_struct
|
|
// ident.b
|
|
|
|
auto* s = Structure("my_struct", {
|
|
Member("a", ty.f32()),
|
|
Member("b", ty.f32()),
|
|
});
|
|
|
|
auto* var = Var("ident", ty.Of(s));
|
|
|
|
auto* expr = MemberAccessor("ident", "b");
|
|
WrapInFunction(var, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%8 = OpTypeFloat 32
|
|
%7 = OpTypeStruct %8 %8
|
|
%6 = OpTypePointer Function %7
|
|
%9 = OpConstantNull %7
|
|
%10 = OpTypeInt 32 0
|
|
%11 = OpConstant %10 1
|
|
%12 = OpTypePointer Function %8
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%13 = OpAccessChain %12 %5 %11
|
|
%14 = OpLoad %8 %13
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, MemberAccessor_Nested) {
|
|
// inner_struct {
|
|
// a : f32
|
|
// b : f32
|
|
// }
|
|
// my_struct {
|
|
// inner : inner_struct
|
|
// }
|
|
//
|
|
// var ident : my_struct
|
|
// ident.inner.a
|
|
auto* inner_struct = Structure("Inner", {
|
|
Member("a", ty.f32()),
|
|
Member("b", ty.f32()),
|
|
});
|
|
|
|
auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
|
|
|
|
auto* var = Var("ident", ty.Of(s_type));
|
|
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
|
|
WrapInFunction(var, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%9 = OpTypeFloat 32
|
|
%8 = OpTypeStruct %9 %9
|
|
%7 = OpTypeStruct %8
|
|
%6 = OpTypePointer Function %7
|
|
%10 = OpConstantNull %7
|
|
%11 = OpTypeInt 32 0
|
|
%12 = OpConstant %11 0
|
|
%13 = OpConstant %11 1
|
|
%14 = OpTypePointer Function %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
|
R"(%15 = OpAccessChain %14 %5 %12 %13
|
|
%16 = OpLoad %9 %15
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, MemberAccessor_NonPointer) {
|
|
// my_struct {
|
|
// a : f32
|
|
// b : f32
|
|
// }
|
|
// let ident : my_struct = my_struct();
|
|
// ident.b
|
|
|
|
auto* s = Structure("my_struct", {
|
|
Member("a", ty.f32()),
|
|
Member("b", ty.f32()),
|
|
});
|
|
|
|
auto* var = Let("ident", ty.Of(s), Construct(ty.Of(s), 0_f, 0_f));
|
|
|
|
auto* expr = MemberAccessor("ident", "b");
|
|
WrapInFunction(var, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%6 = OpTypeFloat 32
|
|
%5 = OpTypeStruct %6 %6
|
|
%7 = OpConstantNull %6
|
|
%8 = OpConstantComposite %5 %7 %7
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%9 = OpCompositeExtract %6 %8 1
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, MemberAccessor_Nested_NonPointer) {
|
|
// inner_struct {
|
|
// a : f32
|
|
// b : f32
|
|
// }
|
|
// my_struct {
|
|
// inner : inner_struct
|
|
// }
|
|
//
|
|
// let ident : my_struct = my_struct();
|
|
// ident.inner.a
|
|
auto* inner_struct = Structure("Inner", {
|
|
Member("a", ty.f32()),
|
|
Member("b", ty.f32()),
|
|
});
|
|
|
|
auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
|
|
|
|
auto* var = Let("ident", ty.Of(s_type),
|
|
Construct(ty.Of(s_type), Construct(ty.Of(inner_struct), 0_f, 0_f)));
|
|
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
|
|
WrapInFunction(var, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%7 = OpTypeFloat 32
|
|
%6 = OpTypeStruct %7 %7
|
|
%5 = OpTypeStruct %6
|
|
%8 = OpConstantNull %7
|
|
%9 = OpConstantComposite %6 %8 %8
|
|
%10 = OpConstantComposite %5 %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
|
R"(%11 = OpCompositeExtract %6 %10 0
|
|
%12 = OpCompositeExtract %7 %11 1
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, MemberAccessor_Nested_WithAlias) {
|
|
// struct Inner {
|
|
// a : f32
|
|
// b : f32
|
|
// };
|
|
// type Alias = Inner;
|
|
// my_struct {
|
|
// inner : Inner
|
|
// }
|
|
//
|
|
// var ident : my_struct
|
|
// ident.inner.a
|
|
auto* inner_struct = Structure("Inner", {
|
|
Member("a", ty.f32()),
|
|
Member("b", ty.f32()),
|
|
});
|
|
|
|
auto* alias = Alias("Alias", ty.Of(inner_struct));
|
|
auto* s_type = Structure("Outer", {Member("inner", ty.Of(alias))});
|
|
|
|
auto* var = Var("ident", ty.Of(s_type));
|
|
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "a");
|
|
WrapInFunction(var, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%9 = OpTypeFloat 32
|
|
%8 = OpTypeStruct %9 %9
|
|
%7 = OpTypeStruct %8
|
|
%6 = OpTypePointer Function %7
|
|
%10 = OpConstantNull %7
|
|
%11 = OpTypeInt 32 0
|
|
%12 = OpConstant %11 0
|
|
%13 = OpTypePointer Function %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
|
R"(%14 = OpAccessChain %13 %5 %12 %12
|
|
%15 = OpLoad %9 %14
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_LHS) {
|
|
// inner_struct {
|
|
// a : f32
|
|
// }
|
|
// my_struct {
|
|
// inner : inner_struct
|
|
// }
|
|
//
|
|
// var ident : my_struct
|
|
// ident.inner.a = 2.0f;
|
|
auto* inner_struct = Structure("Inner", {
|
|
Member("a", ty.f32()),
|
|
Member("b", ty.f32()),
|
|
});
|
|
|
|
auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
|
|
|
|
auto* var = Var("ident", ty.Of(s_type));
|
|
auto* expr = Assign(MemberAccessor(MemberAccessor("ident", "inner"), "a"), Expr(2_f));
|
|
WrapInFunction(var, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%9 = OpTypeFloat 32
|
|
%8 = OpTypeStruct %9 %9
|
|
%7 = OpTypeStruct %8
|
|
%6 = OpTypePointer Function %7
|
|
%10 = OpConstantNull %7
|
|
%11 = OpTypeInt 32 0
|
|
%12 = OpConstant %11 0
|
|
%13 = OpTypePointer Function %9
|
|
%15 = OpConstant %9 2
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
|
R"(%14 = OpAccessChain %13 %5 %12 %12
|
|
OpStore %14 %15
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_RHS) {
|
|
// inner_struct {
|
|
// a : f32
|
|
// }
|
|
// my_struct {
|
|
// inner : inner_struct
|
|
// }
|
|
//
|
|
// var ident : my_struct
|
|
// var store : f32 = ident.inner.a
|
|
|
|
auto* inner_struct = Structure("Inner", {
|
|
Member("a", ty.f32()),
|
|
Member("b", ty.f32()),
|
|
});
|
|
|
|
auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
|
|
|
|
auto* var = Var("ident", ty.Of(s_type));
|
|
auto* store = Var("store", ty.f32());
|
|
|
|
auto* rhs = MemberAccessor(MemberAccessor("ident", "inner"), "a");
|
|
auto* expr = Assign("store", rhs);
|
|
WrapInFunction(var, store, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%9 = OpTypeFloat 32
|
|
%8 = OpTypeStruct %9 %9
|
|
%7 = OpTypeStruct %8
|
|
%6 = OpTypePointer Function %7
|
|
%10 = OpConstantNull %7
|
|
%12 = OpTypePointer Function %9
|
|
%13 = OpConstantNull %9
|
|
%14 = OpTypeInt 32 0
|
|
%15 = OpConstant %14 0
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %10
|
|
%11 = OpVariable %12 Function %13
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
|
R"(%16 = OpAccessChain %12 %5 %15 %15
|
|
%17 = OpLoad %9 %16
|
|
OpStore %11 %17
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, MemberAccessor_Swizzle_Single) {
|
|
// ident.y
|
|
|
|
auto* var = Var("ident", ty.vec3<f32>());
|
|
|
|
auto* expr = MemberAccessor("ident", "y");
|
|
WrapInFunction(var, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%8 = OpTypeFloat 32
|
|
%7 = OpTypeVector %8 3
|
|
%6 = OpTypePointer Function %7
|
|
%9 = OpConstantNull %7
|
|
%10 = OpTypeInt 32 0
|
|
%11 = OpConstant %10 1
|
|
%12 = OpTypePointer Function %8
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%13 = OpAccessChain %12 %5 %11
|
|
%14 = OpLoad %8 %13
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, MemberAccessor_Swizzle_MultipleNames) {
|
|
// ident.yx
|
|
|
|
auto* var = Var("ident", ty.vec3<f32>());
|
|
|
|
auto* expr = MemberAccessor("ident", "yx");
|
|
WrapInFunction(var, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%8 = OpTypeFloat 32
|
|
%7 = OpTypeVector %8 3
|
|
%6 = OpTypePointer Function %7
|
|
%9 = OpConstantNull %7
|
|
%10 = OpTypeVector %8 2
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%11 = OpLoad %7 %5
|
|
%12 = OpVectorShuffle %10 %11 %11 1 0
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, MemberAccessor_Swizzle_of_Swizzle) {
|
|
// ident.yxz.xz
|
|
|
|
auto* var = Var("ident", ty.vec3<f32>());
|
|
|
|
auto* expr = MemberAccessor(MemberAccessor("ident", "yxz"), "xz");
|
|
WrapInFunction(var, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%8 = OpTypeFloat 32
|
|
%7 = OpTypeVector %8 3
|
|
%6 = OpTypePointer Function %7
|
|
%9 = OpConstantNull %7
|
|
%12 = OpTypeVector %8 2
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%10 = OpLoad %7 %5
|
|
%11 = OpVectorShuffle %7 %10 %10 1 0 2
|
|
%13 = OpVectorShuffle %12 %11 %11 0 2
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, MemberAccessor_Member_of_Swizzle) {
|
|
// ident.yxz.x
|
|
|
|
auto* var = Var("ident", ty.vec3<f32>());
|
|
|
|
auto* expr = MemberAccessor(MemberAccessor("ident", "yxz"), "x");
|
|
WrapInFunction(var, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%8 = OpTypeFloat 32
|
|
%7 = OpTypeVector %8 3
|
|
%6 = OpTypePointer Function %7
|
|
%9 = OpConstantNull %7
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%10 = OpLoad %7 %5
|
|
%11 = OpVectorShuffle %7 %10 %10 1 0 2
|
|
%12 = OpCompositeExtract %8 %11 0
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, MemberAccessor_Array_of_Swizzle) {
|
|
// index.yxz[1i]
|
|
|
|
auto* var = Var("ident", ty.vec3<f32>());
|
|
|
|
auto* expr = IndexAccessor(MemberAccessor("ident", "yxz"), 1_i);
|
|
WrapInFunction(var, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%8 = OpTypeFloat 32
|
|
%7 = OpTypeVector %8 3
|
|
%6 = OpTypePointer Function %7
|
|
%9 = OpConstantNull %7
|
|
%12 = OpTypeInt 32 1
|
|
%13 = OpConstant %12 1
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %9
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%10 = OpLoad %7 %5
|
|
%11 = OpVectorShuffle %7 %10 %10 1 0 2
|
|
%14 = OpCompositeExtract %8 %11 1
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
TEST_F(BuilderTest, IndexAccessor_Mixed_ArrayAndMember) {
|
|
// type C = struct {
|
|
// baz : vec3<f32>
|
|
// }
|
|
// type B = struct {
|
|
// bar : C;
|
|
// }
|
|
// type A = struct {
|
|
// foo : array<B, 3>
|
|
// }
|
|
// var index : array<A, 2u>
|
|
// index[0i].foo[2i].bar.baz.yx
|
|
|
|
auto* c_type = Structure("C", {Member("baz", ty.vec3<f32>())});
|
|
|
|
auto* b_type = Structure("B", {Member("bar", ty.Of(c_type))});
|
|
auto* b_ary_type = ty.array(ty.Of(b_type), 3_u);
|
|
auto* a_type = Structure("A", {Member("foo", b_ary_type)});
|
|
|
|
auto* a_ary_type = ty.array(ty.Of(a_type), 2_u);
|
|
auto* var = Var("index", a_ary_type);
|
|
auto* expr = MemberAccessor(
|
|
MemberAccessor(
|
|
MemberAccessor(IndexAccessor(MemberAccessor(IndexAccessor("index", 0_i), "foo"), 2_i),
|
|
"bar"),
|
|
"baz"),
|
|
"yx");
|
|
WrapInFunction(var, expr);
|
|
|
|
spirv::Builder& b = SanitizeAndBuild();
|
|
|
|
ASSERT_TRUE(b.Build()) << b.error();
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
%1 = OpTypeFunction %2
|
|
%13 = OpTypeFloat 32
|
|
%12 = OpTypeVector %13 3
|
|
%11 = OpTypeStruct %12
|
|
%10 = OpTypeStruct %11
|
|
%14 = OpTypeInt 32 0
|
|
%15 = OpConstant %14 3
|
|
%9 = OpTypeArray %10 %15
|
|
%8 = OpTypeStruct %9
|
|
%16 = OpConstant %14 2
|
|
%7 = OpTypeArray %8 %16
|
|
%6 = OpTypePointer Function %7
|
|
%17 = OpConstantNull %7
|
|
%18 = OpTypeInt 32 1
|
|
%19 = OpConstantNull %18
|
|
%20 = OpConstant %14 0
|
|
%21 = OpConstant %18 2
|
|
%22 = OpTypePointer Function %12
|
|
%24 = OpTypeVector %13 2
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"(%5 = OpVariable %6 Function %17
|
|
)");
|
|
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
|
R"(%23 = OpAccessChain %22 %5 %19 %20 %21 %20 %20
|
|
%25 = OpLoad %12 %23
|
|
%26 = OpVectorShuffle %24 %25 %25 1 0
|
|
OpReturn
|
|
)");
|
|
|
|
Validate(b);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace tint::writer::spirv
|