1 // Copyright 2020 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/reader/spirv/parser_impl_test_helper.h"
17 #include "src/reader/spirv/spirv_tools_helpers_test.h"
18
19 namespace tint {
20 namespace reader {
21 namespace spirv {
22 namespace {
23
24 using ::testing::HasSubstr;
25
TEST_F(SpvParserTest,Impl_Uint32VecEmpty)26 TEST_F(SpvParserTest, Impl_Uint32VecEmpty) {
27 std::vector<uint32_t> data;
28 auto p = parser(data);
29 EXPECT_FALSE(p->Parse());
30 // TODO(dneto): What message?
31 }
32
TEST_F(SpvParserTest,Impl_InvalidModuleFails)33 TEST_F(SpvParserTest, Impl_InvalidModuleFails) {
34 auto invalid_spv = test::Assemble("%ty = OpTypeInt 3 0");
35 auto p = parser(invalid_spv);
36 EXPECT_FALSE(p->Parse());
37 EXPECT_THAT(
38 p->error(),
39 HasSubstr("TypeInt cannot appear before the memory model instruction"));
40 EXPECT_THAT(p->error(), HasSubstr("OpTypeInt 3 0"));
41 }
42
TEST_F(SpvParserTest,Impl_GenericVulkanShader_SimpleMemoryModel)43 TEST_F(SpvParserTest, Impl_GenericVulkanShader_SimpleMemoryModel) {
44 auto spv = test::Assemble(R"(
45 OpCapability Shader
46 OpMemoryModel Logical Simple
47 OpEntryPoint GLCompute %main "main"
48 OpExecutionMode %main LocalSize 1 1 1
49 %void = OpTypeVoid
50 %voidfn = OpTypeFunction %void
51 %main = OpFunction %void None %voidfn
52 %entry = OpLabel
53 OpReturn
54 OpFunctionEnd
55 )");
56 auto p = parser(spv);
57 EXPECT_TRUE(p->Parse());
58 EXPECT_TRUE(p->error().empty());
59 }
60
TEST_F(SpvParserTest,Impl_GenericVulkanShader_GLSL450MemoryModel)61 TEST_F(SpvParserTest, Impl_GenericVulkanShader_GLSL450MemoryModel) {
62 auto spv = test::Assemble(R"(
63 OpCapability Shader
64 OpMemoryModel Logical GLSL450
65 OpEntryPoint GLCompute %main "main"
66 OpExecutionMode %main LocalSize 1 1 1
67 %void = OpTypeVoid
68 %voidfn = OpTypeFunction %void
69 %main = OpFunction %void None %voidfn
70 %entry = OpLabel
71 OpReturn
72 OpFunctionEnd
73 )");
74 auto p = parser(spv);
75 EXPECT_TRUE(p->Parse());
76 EXPECT_TRUE(p->error().empty());
77 }
78
TEST_F(SpvParserTest,Impl_GenericVulkanShader_VulkanMemoryModel)79 TEST_F(SpvParserTest, Impl_GenericVulkanShader_VulkanMemoryModel) {
80 auto spv = test::Assemble(R"(
81 OpCapability Shader
82 OpCapability VulkanMemoryModelKHR
83 OpExtension "SPV_KHR_vulkan_memory_model"
84 OpMemoryModel Logical VulkanKHR
85 OpEntryPoint GLCompute %main "main"
86 OpExecutionMode %main LocalSize 1 1 1
87 %void = OpTypeVoid
88 %voidfn = OpTypeFunction %void
89 %main = OpFunction %void None %voidfn
90 %entry = OpLabel
91 OpReturn
92 OpFunctionEnd
93 )");
94 auto p = parser(spv);
95 EXPECT_TRUE(p->Parse());
96 EXPECT_TRUE(p->error().empty());
97 }
98
TEST_F(SpvParserTest,Impl_OpenCLKernel_Fails)99 TEST_F(SpvParserTest, Impl_OpenCLKernel_Fails) {
100 auto spv = test::Assemble(R"(
101 OpCapability Kernel
102 OpCapability Addresses
103 OpMemoryModel Physical32 OpenCL
104 OpEntryPoint Kernel %main "main"
105 %void = OpTypeVoid
106 %voidfn = OpTypeFunction %void
107 %main = OpFunction %void None %voidfn
108 %entry = OpLabel
109 OpReturn
110 OpFunctionEnd
111 )");
112 auto p = parser(spv);
113 EXPECT_FALSE(p->Parse());
114 EXPECT_THAT(p->error(), HasSubstr("Capability Kernel is not allowed"));
115 }
116
TEST_F(SpvParserTest,Impl_Source_NoOpLine)117 TEST_F(SpvParserTest, Impl_Source_NoOpLine) {
118 auto spv = test::Assemble(R"(
119 OpCapability Shader
120 OpMemoryModel Logical Simple
121 OpEntryPoint GLCompute %main "main"
122 OpExecutionMode %main LocalSize 1 1 1
123 %void = OpTypeVoid
124 %voidfn = OpTypeFunction %void
125 %5 = OpTypeInt 32 0
126 %60 = OpConstantNull %5
127 %main = OpFunction %void None %voidfn
128 %1 = OpLabel
129 OpReturn
130 OpFunctionEnd
131 )");
132 auto p = parser(spv);
133 EXPECT_TRUE(p->Parse());
134 EXPECT_TRUE(p->error().empty());
135 // Use instruction counting.
136 auto s5 = p->GetSourceForResultIdForTest(5);
137 EXPECT_EQ(7u, s5.range.begin.line);
138 EXPECT_EQ(0u, s5.range.begin.column);
139 auto s60 = p->GetSourceForResultIdForTest(60);
140 EXPECT_EQ(8u, s60.range.begin.line);
141 EXPECT_EQ(0u, s60.range.begin.column);
142 auto s1 = p->GetSourceForResultIdForTest(1);
143 EXPECT_EQ(10u, s1.range.begin.line);
144 EXPECT_EQ(0u, s1.range.begin.column);
145 }
146
TEST_F(SpvParserTest,Impl_Source_WithOpLine_WithOpNoLine)147 TEST_F(SpvParserTest, Impl_Source_WithOpLine_WithOpNoLine) {
148 auto spv = test::Assemble(R"(
149 OpCapability Shader
150 OpMemoryModel Logical Simple
151 OpEntryPoint GLCompute %main "main"
152 OpExecutionMode %main LocalSize 1 1 1
153 %15 = OpString "myfile"
154 %void = OpTypeVoid
155 %voidfn = OpTypeFunction %void
156 OpLine %15 42 53
157 %5 = OpTypeInt 32 0
158 %60 = OpConstantNull %5
159 OpNoLine
160 %main = OpFunction %void None %voidfn
161 %1 = OpLabel
162 OpReturn
163 OpFunctionEnd
164 )");
165 auto p = parser(spv);
166 EXPECT_TRUE(p->Parse());
167 EXPECT_TRUE(p->error().empty());
168 // Use the information from the OpLine that is still in scope.
169 auto s5 = p->GetSourceForResultIdForTest(5);
170 EXPECT_EQ(42u, s5.range.begin.line);
171 EXPECT_EQ(53u, s5.range.begin.column);
172 auto s60 = p->GetSourceForResultIdForTest(60);
173 EXPECT_EQ(42u, s60.range.begin.line);
174 EXPECT_EQ(53u, s60.range.begin.column);
175 // After OpNoLine, revert back to instruction counting.
176 auto s1 = p->GetSourceForResultIdForTest(1);
177 EXPECT_EQ(14u, s1.range.begin.line);
178 EXPECT_EQ(0u, s1.range.begin.column);
179 }
180
TEST_F(SpvParserTest,Impl_Source_InvalidId)181 TEST_F(SpvParserTest, Impl_Source_InvalidId) {
182 auto spv = test::Assemble(R"(
183 OpCapability Shader
184 OpMemoryModel Logical Simple
185 OpEntryPoint GLCompute %main "main"
186 OpExecutionMode %main LocalSize 1 1 1
187 %15 = OpString "myfile"
188 %void = OpTypeVoid
189 %voidfn = OpTypeFunction %void
190 %main = OpFunction %void None %voidfn
191 %1 = OpLabel
192 OpReturn
193 OpFunctionEnd
194 )");
195 auto p = parser(spv);
196 EXPECT_TRUE(p->Parse());
197 EXPECT_TRUE(p->error().empty());
198 auto s99 = p->GetSourceForResultIdForTest(99);
199 EXPECT_EQ(0u, s99.range.begin.line);
200 EXPECT_EQ(0u, s99.range.begin.column);
201 }
202
TEST_F(SpvParserTest,Impl_IsValidIdentifier)203 TEST_F(SpvParserTest, Impl_IsValidIdentifier) {
204 EXPECT_FALSE(ParserImpl::IsValidIdentifier("")); // empty
205 EXPECT_FALSE(
206 ParserImpl::IsValidIdentifier("_")); // leading underscore, but ok later
207 EXPECT_FALSE(
208 ParserImpl::IsValidIdentifier("9")); // leading digit, but ok later
209 EXPECT_FALSE(ParserImpl::IsValidIdentifier(" ")); // leading space
210 EXPECT_FALSE(ParserImpl::IsValidIdentifier("a ")); // trailing space
211 EXPECT_FALSE(ParserImpl::IsValidIdentifier("a 1")); // space in the middle
212 EXPECT_FALSE(ParserImpl::IsValidIdentifier(".")); // weird character
213
214 // a simple identifier
215 EXPECT_TRUE(ParserImpl::IsValidIdentifier("A"));
216 // each upper case letter
217 EXPECT_TRUE(ParserImpl::IsValidIdentifier("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
218 // each lower case letter
219 EXPECT_TRUE(ParserImpl::IsValidIdentifier("abcdefghijklmnopqrstuvwxyz"));
220 EXPECT_TRUE(ParserImpl::IsValidIdentifier("a0123456789")); // each digit
221 EXPECT_TRUE(ParserImpl::IsValidIdentifier("x_")); // has underscore
222 }
223
224 } // namespace
225 } // namespace spirv
226 } // namespace reader
227 } // namespace tint
228