1 // Copyright 2021 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "gmock/gmock.h"
16 #include "src/ast/call_statement.h"
17 #include "src/reader/spirv/function.h"
18 #include "src/reader/spirv/parser_impl_test_helper.h"
19 #include "src/reader/spirv/spirv_tools_helpers_test.h"
20 #include "src/sem/call.h"
21
22 namespace tint {
23 namespace reader {
24 namespace spirv {
25 namespace {
26
27 using ::testing::Eq;
28 using ::testing::HasSubstr;
29 using ::testing::Not;
30 using ::testing::StartsWith;
31
ParseAndBuild(std::string spirv)32 Program ParseAndBuild(std::string spirv) {
33 const char* preamble = R"(OpCapability Shader
34 OpMemoryModel Logical GLSL450
35 OpEntryPoint GLCompute %main "main"
36 OpExecutionMode %main LocalSize 1 1 1
37 OpName %main "main"
38 )";
39
40 auto p = std::make_unique<ParserImpl>(test::Assemble(preamble + spirv));
41 if (!p->BuildAndParseInternalModule()) {
42 ProgramBuilder builder;
43 builder.Diagnostics().add_error(diag::System::Reader, p->error());
44 return Program(std::move(builder));
45 }
46 return p->program();
47 }
48
TEST_F(SpvParserTest,WorkgroupBarrier)49 TEST_F(SpvParserTest, WorkgroupBarrier) {
50 auto program = ParseAndBuild(R"(
51 OpName %helper "helper"
52 %void = OpTypeVoid
53 %1 = OpTypeFunction %void
54 %uint = OpTypeInt 32 0
55 %uint_2 = OpConstant %uint 2
56 %uint_264 = OpConstant %uint 264
57 %helper = OpFunction %void None %1
58 %4 = OpLabel
59 OpControlBarrier %uint_2 %uint_2 %uint_264
60 OpReturn
61 OpFunctionEnd
62 %main = OpFunction %void None %1
63 %5 = OpLabel
64 OpReturn
65 OpFunctionEnd
66 )");
67 ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
68 auto* helper =
69 program.AST().Functions().Find(program.Symbols().Get("helper"));
70 ASSERT_NE(helper, nullptr);
71 ASSERT_GT(helper->body->statements.size(), 0u);
72 auto* call = helper->body->statements[0]->As<ast::CallStatement>();
73 ASSERT_NE(call, nullptr);
74 EXPECT_EQ(call->expr->args.size(), 0u);
75 auto* sem_call = program.Sem().Get(call->expr);
76 ASSERT_NE(sem_call, nullptr);
77 auto* intrinsic = sem_call->Target()->As<sem::Intrinsic>();
78 ASSERT_NE(intrinsic, nullptr);
79 EXPECT_EQ(intrinsic->Type(), sem::IntrinsicType::kWorkgroupBarrier);
80 }
81
TEST_F(SpvParserTest,StorageBarrier)82 TEST_F(SpvParserTest, StorageBarrier) {
83 auto program = ParseAndBuild(R"(
84 OpName %helper "helper"
85 %void = OpTypeVoid
86 %1 = OpTypeFunction %void
87 %uint = OpTypeInt 32 0
88 %uint_2 = OpConstant %uint 2
89 %uint_1 = OpConstant %uint 1
90 %uint_72 = OpConstant %uint 72
91 %helper = OpFunction %void None %1
92 %4 = OpLabel
93 OpControlBarrier %uint_2 %uint_1 %uint_72
94 OpReturn
95 OpFunctionEnd
96 %main = OpFunction %void None %1
97 %5 = OpLabel
98 OpReturn
99 OpFunctionEnd
100 )");
101 ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
102 auto* helper =
103 program.AST().Functions().Find(program.Symbols().Get("helper"));
104 ASSERT_NE(helper, nullptr);
105 ASSERT_GT(helper->body->statements.size(), 0u);
106 auto* call = helper->body->statements[0]->As<ast::CallStatement>();
107 ASSERT_NE(call, nullptr);
108 EXPECT_EQ(call->expr->args.size(), 0u);
109 auto* sem_call = program.Sem().Get(call->expr);
110 ASSERT_NE(sem_call, nullptr);
111 auto* intrinsic = sem_call->Target()->As<sem::Intrinsic>();
112 ASSERT_NE(intrinsic, nullptr);
113 EXPECT_EQ(intrinsic->Type(), sem::IntrinsicType::kStorageBarrier);
114 }
115
TEST_F(SpvParserTest,ErrBarrierInvalidExecution)116 TEST_F(SpvParserTest, ErrBarrierInvalidExecution) {
117 auto program = ParseAndBuild(R"(
118 %void = OpTypeVoid
119 %1 = OpTypeFunction %void
120 %uint = OpTypeInt 32 0
121 %uint_0 = OpConstant %uint 0
122 %uint_2 = OpConstant %uint 2
123 %uint_264 = OpConstant %uint 264
124 %main = OpFunction %void None %1
125 %4 = OpLabel
126 OpControlBarrier %uint_0 %uint_2 %uint_264
127 OpReturn
128 OpFunctionEnd
129 )");
130 EXPECT_FALSE(program.IsValid());
131 EXPECT_THAT(program.Diagnostics().str(),
132 HasSubstr("unsupported control barrier execution scope"));
133 }
134
TEST_F(SpvParserTest,ErrBarrierSemanticsMissingAcquireRelease)135 TEST_F(SpvParserTest, ErrBarrierSemanticsMissingAcquireRelease) {
136 auto program = ParseAndBuild(R"(
137 %void = OpTypeVoid
138 %1 = OpTypeFunction %void
139 %uint = OpTypeInt 32 0
140 %uint_2 = OpConstant %uint 2
141 %uint_0 = OpConstant %uint 0
142 %main = OpFunction %void None %1
143 %4 = OpLabel
144 OpControlBarrier %uint_2 %uint_2 %uint_0
145 OpReturn
146 OpFunctionEnd
147 )");
148 EXPECT_FALSE(program.IsValid());
149 EXPECT_THAT(
150 program.Diagnostics().str(),
151 HasSubstr("control barrier semantics requires acquire and release"));
152 }
153
TEST_F(SpvParserTest,ErrBarrierInvalidSemantics)154 TEST_F(SpvParserTest, ErrBarrierInvalidSemantics) {
155 auto program = ParseAndBuild(R"(
156 %void = OpTypeVoid
157 %1 = OpTypeFunction %void
158 %uint = OpTypeInt 32 0
159 %uint_2 = OpConstant %uint 2
160 %uint_9 = OpConstant %uint 9
161 %main = OpFunction %void None %1
162 %4 = OpLabel
163 OpControlBarrier %uint_2 %uint_2 %uint_9
164 OpReturn
165 OpFunctionEnd
166 )");
167 EXPECT_FALSE(program.IsValid());
168 EXPECT_THAT(program.Diagnostics().str(),
169 HasSubstr("unsupported control barrier semantics"));
170 }
171
TEST_F(SpvParserTest,ErrWorkgroupBarrierInvalidMemory)172 TEST_F(SpvParserTest, ErrWorkgroupBarrierInvalidMemory) {
173 auto program = ParseAndBuild(R"(
174 %void = OpTypeVoid
175 %1 = OpTypeFunction %void
176 %uint = OpTypeInt 32 0
177 %uint_2 = OpConstant %uint 2
178 %uint_8 = OpConstant %uint 8
179 %uint_264 = OpConstant %uint 264
180 %main = OpFunction %void None %1
181 %4 = OpLabel
182 OpControlBarrier %uint_2 %uint_8 %uint_264
183 OpReturn
184 OpFunctionEnd
185 )");
186 EXPECT_FALSE(program.IsValid());
187 EXPECT_THAT(program.Diagnostics().str(),
188 HasSubstr("workgroupBarrier requires workgroup memory scope"));
189 }
190
TEST_F(SpvParserTest,ErrStorageBarrierInvalidMemory)191 TEST_F(SpvParserTest, ErrStorageBarrierInvalidMemory) {
192 auto program = ParseAndBuild(R"(
193 %void = OpTypeVoid
194 %1 = OpTypeFunction %void
195 %uint = OpTypeInt 32 0
196 %uint_2 = OpConstant %uint 2
197 %uint_8 = OpConstant %uint 8
198 %uint_72 = OpConstant %uint 72
199 %main = OpFunction %void None %1
200 %4 = OpLabel
201 OpControlBarrier %uint_2 %uint_8 %uint_72
202 OpReturn
203 OpFunctionEnd
204 )");
205 EXPECT_FALSE(program.IsValid());
206 EXPECT_THAT(program.Diagnostics().str(),
207 HasSubstr("storageBarrier requires device memory scope"));
208 }
209
210 } // namespace
211 } // namespace spirv
212 } // namespace reader
213 } // namespace tint
214