1// Copyright (c) 2018 Google LLC
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 <string>
16
17#include "gmock/gmock.h"
18#include "spirv-tools/optimizer.hpp"
19#include "test/opt/pass_fixture.h"
20#include "test/opt/pass_utils.h"
21
22namespace spvtools {
23namespace opt {
24namespace {
25
26using StripNonSemanticInfoTest = PassTest<::testing::Test>;
27
28// This test acts as an end-to-end code example on how to strip
29// reflection info from a SPIR-V module.  Use this code pattern
30// when you have compiled HLSL code with Glslang or DXC using
31// option -fhlsl_functionality1 to insert reflection information,
32// but then want to filter out the extra instructions before sending
33// it to a driver that does not implement VK_GOOGLE_hlsl_functionality1.
34TEST_F(StripNonSemanticInfoTest, StripReflectEnd2EndExample) {
35  // This is a non-sensical example, but exercises the instructions.
36  std::string before = R"(OpCapability Shader
37OpCapability Linkage
38OpExtension "SPV_GOOGLE_decorate_string"
39OpExtension "SPV_GOOGLE_hlsl_functionality1"
40OpMemoryModel Logical Simple
41OpDecorateStringGOOGLE %float HlslSemanticGOOGLE "foobar"
42OpDecorateStringGOOGLE %void HlslSemanticGOOGLE "my goodness"
43%void = OpTypeVoid
44%float = OpTypeFloat 32
45)";
46  SpirvTools tools(SPV_ENV_UNIVERSAL_1_1);
47  std::vector<uint32_t> binary_in;
48  tools.Assemble(before, &binary_in);
49
50  // Instantiate the optimizer, and run the strip-nonsemantic-info
51  // pass over the |binary_in| module, and place the modified module
52  // into |binary_out|.
53  spvtools::Optimizer optimizer(SPV_ENV_UNIVERSAL_1_1);
54  optimizer.RegisterPass(spvtools::CreateStripNonSemanticInfoPass());
55  std::vector<uint32_t> binary_out;
56  optimizer.Run(binary_in.data(), binary_in.size(), &binary_out);
57
58  // Check results
59  std::string disassembly;
60  tools.Disassemble(binary_out.data(), binary_out.size(), &disassembly);
61  std::string after = R"(OpCapability Shader
62OpCapability Linkage
63OpMemoryModel Logical Simple
64%void = OpTypeVoid
65%float = OpTypeFloat 32
66)";
67  EXPECT_THAT(disassembly, testing::Eq(after));
68}
69
70// This test is functionally the same as the end-to-end test above,
71// but uses the test SinglePassRunAndCheck test fixture instead.
72TEST_F(StripNonSemanticInfoTest, StripHlslSemantic) {
73  // This is a non-sensical example, but exercises the instructions.
74  std::string before = R"(OpCapability Shader
75OpCapability Linkage
76OpExtension "SPV_GOOGLE_decorate_string"
77OpExtension "SPV_GOOGLE_hlsl_functionality1"
78OpMemoryModel Logical Simple
79OpDecorateStringGOOGLE %float HlslSemanticGOOGLE "foobar"
80OpDecorateStringGOOGLE %void HlslSemanticGOOGLE "my goodness"
81%void = OpTypeVoid
82%float = OpTypeFloat 32
83)";
84  std::string after = R"(OpCapability Shader
85OpCapability Linkage
86OpMemoryModel Logical Simple
87%void = OpTypeVoid
88%float = OpTypeFloat 32
89)";
90
91  SinglePassRunAndCheck<StripNonSemanticInfoPass>(before, after, false);
92}
93
94TEST_F(StripNonSemanticInfoTest, StripHlslCounterBuffer) {
95  std::string before = R"(OpCapability Shader
96OpCapability Linkage
97OpExtension "SPV_GOOGLE_hlsl_functionality1"
98OpMemoryModel Logical Simple
99OpDecorateId %void HlslCounterBufferGOOGLE %float
100%void = OpTypeVoid
101%float = OpTypeFloat 32
102)";
103  std::string after = R"(OpCapability Shader
104OpCapability Linkage
105OpMemoryModel Logical Simple
106%void = OpTypeVoid
107%float = OpTypeFloat 32
108)";
109
110  SinglePassRunAndCheck<StripNonSemanticInfoPass>(before, after, false);
111}
112
113TEST_F(StripNonSemanticInfoTest, StripHlslSemanticOnMember) {
114  // This is a non-sensical example, but exercises the instructions.
115  std::string before = R"(OpCapability Shader
116OpCapability Linkage
117OpExtension "SPV_GOOGLE_decorate_string"
118OpExtension "SPV_GOOGLE_hlsl_functionality1"
119OpMemoryModel Logical Simple
120OpMemberDecorateStringGOOGLE %struct 0 HlslSemanticGOOGLE "foobar"
121%float = OpTypeFloat 32
122%_struct_3 = OpTypeStruct %float
123)";
124  std::string after = R"(OpCapability Shader
125OpCapability Linkage
126OpMemoryModel Logical Simple
127%float = OpTypeFloat 32
128%_struct_3 = OpTypeStruct %float
129)";
130
131  SinglePassRunAndCheck<StripNonSemanticInfoPass>(before, after, false);
132}
133
134TEST_F(StripNonSemanticInfoTest, StripNonSemanticImport) {
135  std::string text = R"(
136; CHECK-NOT: OpExtension "SPV_KHR_non_semantic_info"
137; CHECK-NOT: OpExtInstImport
138OpCapability Shader
139OpCapability Linkage
140OpExtension "SPV_KHR_non_semantic_info"
141%ext = OpExtInstImport "NonSemantic.Test"
142OpMemoryModel Logical GLSL450
143)";
144
145  SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
146}
147
148TEST_F(StripNonSemanticInfoTest, StripNonSemanticGlobal) {
149  std::string text = R"(
150; CHECK-NOT: OpExtInst
151OpCapability Shader
152OpCapability Linkage
153OpExtension "SPV_KHR_non_semantic_info"
154%ext = OpExtInstImport "NonSemantic.Test"
155OpMemoryModel Logical GLSL450
156%void = OpTypeVoid
157%1 = OpExtInst %void %ext 1
158)";
159
160  SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
161}
162
163TEST_F(StripNonSemanticInfoTest, StripNonSemanticInFunction) {
164  std::string text = R"(
165; CHECK-NOT: OpExtInst
166OpCapability Shader
167OpCapability Linkage
168OpExtension "SPV_KHR_non_semantic_info"
169%ext = OpExtInstImport "NonSemantic.Test"
170OpMemoryModel Logical GLSL450
171%void = OpTypeVoid
172%void_fn = OpTypeFunction %void
173%foo = OpFunction %void None %void_fn
174%entry = OpLabel
175%1 = OpExtInst %void %ext 1 %foo
176OpReturn
177OpFunctionEnd
178)";
179
180  SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
181}
182
183TEST_F(StripNonSemanticInfoTest, StripNonSemanticAfterFunction) {
184  std::string text = R"(
185; CHECK-NOT: OpExtInst
186OpCapability Shader
187OpCapability Linkage
188OpExtension "SPV_KHR_non_semantic_info"
189%ext = OpExtInstImport "NonSemantic.Test"
190OpMemoryModel Logical GLSL450
191%void = OpTypeVoid
192%void_fn = OpTypeFunction %void
193%foo = OpFunction %void None %void_fn
194%entry = OpLabel
195OpReturn
196OpFunctionEnd
197%1 = OpExtInst %void %ext 1 %foo
198)";
199
200  SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
201}
202
203TEST_F(StripNonSemanticInfoTest, StripNonSemanticBetweenFunctions) {
204  std::string text = R"(
205; CHECK-NOT: OpExtInst
206OpCapability Shader
207OpCapability Linkage
208OpExtension "SPV_KHR_non_semantic_info"
209%ext = OpExtInstImport "NonSemantic.Test"
210OpMemoryModel Logical GLSL450
211%void = OpTypeVoid
212%void_fn = OpTypeFunction %void
213%foo = OpFunction %void None %void_fn
214%entry = OpLabel
215OpReturn
216OpFunctionEnd
217%1 = OpExtInst %void %ext 1 %foo
218%bar = OpFunction %void None %void_fn
219%bar_entry = OpLabel
220OpReturn
221OpFunctionEnd
222)";
223
224  SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
225}
226
227// Make sure that strip reflect does not remove the debug info (OpString and
228// OpLine).
229TEST_F(StripNonSemanticInfoTest, DontStripDebug) {
230  std::string text = R"(OpCapability Shader
231OpMemoryModel Logical Simple
232OpEntryPoint Fragment %1 "main"
233OpExecutionMode %1 OriginUpperLeft
234%2 = OpString "file"
235%void = OpTypeVoid
236%4 = OpTypeFunction %void
237%1 = OpFunction %void None %4
238%5 = OpLabel
239OpLine %2 1 1
240OpReturn
241OpFunctionEnd
242)";
243
244  SinglePassRunAndCheck<StripNonSemanticInfoPass>(text, text, false);
245}
246
247TEST_F(StripNonSemanticInfoTest, RemovedNonSemanticDebugInfo) {
248  const std::string text = R"(
249;CHECK-NOT: OpExtension "SPV_KHR_non_semantic_info
250;CHECK-NOT: OpExtInstImport "NonSemantic.Shader.DebugInfo.100
251;CHECK-NOT: OpExtInst %void {{%\w+}} DebugSource
252;CHECK-NOT: OpExtInst %void {{%\w+}} DebugLine
253               OpCapability Shader
254               OpExtension "SPV_KHR_non_semantic_info"
255          %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
256               OpMemoryModel Logical GLSL450
257               OpEntryPoint Fragment %PSMain "PSMain" %in_var_COLOR %out_var_SV_TARGET
258               OpExecutionMode %PSMain OriginUpperLeft
259          %5 = OpString "t.hlsl"
260          %6 = OpString "float"
261          %7 = OpString "color"
262          %8 = OpString "PSInput"
263          %9 = OpString "PSMain"
264         %10 = OpString ""
265         %11 = OpString "input"
266               OpName %in_var_COLOR "in.var.COLOR"
267               OpName %out_var_SV_TARGET "out.var.SV_TARGET"
268               OpName %PSMain "PSMain"
269               OpDecorate %in_var_COLOR Location 0
270               OpDecorate %out_var_SV_TARGET Location 0
271       %uint = OpTypeInt 32 0
272      %float = OpTypeFloat 32
273    %v4float = OpTypeVector %float 4
274%_ptr_Input_v4float = OpTypePointer Input %v4float
275%_ptr_Output_v4float = OpTypePointer Output %v4float
276       %void = OpTypeVoid
277     %uint_1 = OpConstant %uint 1
278     %uint_9 = OpConstant %uint 9
279         %21 = OpTypeFunction %void
280%in_var_COLOR = OpVariable %_ptr_Input_v4float Input
281%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
282         %13 = OpExtInst %void %1 DebugSource %5
283     %PSMain = OpFunction %void None %21
284         %22 = OpLabel
285         %23 = OpLoad %v4float %in_var_COLOR
286               OpStore %out_var_SV_TARGET %23
287         %24 = OpExtInst %void %1 DebugLine %13 %uint_9 %uint_9 %uint_1 %uint_1
288               OpReturn
289               OpFunctionEnd
290)";
291  SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
292}
293
294}  // namespace
295}  // namespace opt
296}  // namespace spvtools
297