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 
22 namespace spvtools {
23 namespace opt {
24 namespace {
25 
26 using 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.
TEST_F(StripNonSemanticInfoTest,StripReflectEnd2EndExample)34 TEST_F(StripNonSemanticInfoTest, StripReflectEnd2EndExample) {
35   // This is a non-sensical example, but exercises the instructions.
36   std::string before = R"(OpCapability Shader
37 OpCapability Linkage
38 OpExtension "SPV_GOOGLE_decorate_string"
39 OpExtension "SPV_GOOGLE_hlsl_functionality1"
40 OpMemoryModel Logical Simple
41 OpDecorateStringGOOGLE %float HlslSemanticGOOGLE "foobar"
42 OpDecorateStringGOOGLE %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
62 OpCapability Linkage
63 OpMemoryModel 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.
TEST_F(StripNonSemanticInfoTest,StripHlslSemantic)72 TEST_F(StripNonSemanticInfoTest, StripHlslSemantic) {
73   // This is a non-sensical example, but exercises the instructions.
74   std::string before = R"(OpCapability Shader
75 OpCapability Linkage
76 OpExtension "SPV_GOOGLE_decorate_string"
77 OpExtension "SPV_GOOGLE_hlsl_functionality1"
78 OpMemoryModel Logical Simple
79 OpDecorateStringGOOGLE %float HlslSemanticGOOGLE "foobar"
80 OpDecorateStringGOOGLE %void HlslSemanticGOOGLE "my goodness"
81 %void = OpTypeVoid
82 %float = OpTypeFloat 32
83 )";
84   std::string after = R"(OpCapability Shader
85 OpCapability Linkage
86 OpMemoryModel Logical Simple
87 %void = OpTypeVoid
88 %float = OpTypeFloat 32
89 )";
90 
91   SinglePassRunAndCheck<StripNonSemanticInfoPass>(before, after, false);
92 }
93 
TEST_F(StripNonSemanticInfoTest,StripHlslCounterBuffer)94 TEST_F(StripNonSemanticInfoTest, StripHlslCounterBuffer) {
95   std::string before = R"(OpCapability Shader
96 OpCapability Linkage
97 OpExtension "SPV_GOOGLE_hlsl_functionality1"
98 OpMemoryModel Logical Simple
99 OpDecorateId %void HlslCounterBufferGOOGLE %float
100 %void = OpTypeVoid
101 %float = OpTypeFloat 32
102 )";
103   std::string after = R"(OpCapability Shader
104 OpCapability Linkage
105 OpMemoryModel Logical Simple
106 %void = OpTypeVoid
107 %float = OpTypeFloat 32
108 )";
109 
110   SinglePassRunAndCheck<StripNonSemanticInfoPass>(before, after, false);
111 }
112 
TEST_F(StripNonSemanticInfoTest,StripHlslSemanticOnMember)113 TEST_F(StripNonSemanticInfoTest, StripHlslSemanticOnMember) {
114   // This is a non-sensical example, but exercises the instructions.
115   std::string before = R"(OpCapability Shader
116 OpCapability Linkage
117 OpExtension "SPV_GOOGLE_decorate_string"
118 OpExtension "SPV_GOOGLE_hlsl_functionality1"
119 OpMemoryModel Logical Simple
120 OpMemberDecorateStringGOOGLE %struct 0 HlslSemanticGOOGLE "foobar"
121 %float = OpTypeFloat 32
122 %_struct_3 = OpTypeStruct %float
123 )";
124   std::string after = R"(OpCapability Shader
125 OpCapability Linkage
126 OpMemoryModel Logical Simple
127 %float = OpTypeFloat 32
128 %_struct_3 = OpTypeStruct %float
129 )";
130 
131   SinglePassRunAndCheck<StripNonSemanticInfoPass>(before, after, false);
132 }
133 
TEST_F(StripNonSemanticInfoTest,StripNonSemanticImport)134 TEST_F(StripNonSemanticInfoTest, StripNonSemanticImport) {
135   std::string text = R"(
136 ; CHECK-NOT: OpExtension "SPV_KHR_non_semantic_info"
137 ; CHECK-NOT: OpExtInstImport
138 OpCapability Shader
139 OpCapability Linkage
140 OpExtension "SPV_KHR_non_semantic_info"
141 %ext = OpExtInstImport "NonSemantic.Test"
142 OpMemoryModel Logical GLSL450
143 )";
144 
145   SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
146 }
147 
TEST_F(StripNonSemanticInfoTest,StripNonSemanticGlobal)148 TEST_F(StripNonSemanticInfoTest, StripNonSemanticGlobal) {
149   std::string text = R"(
150 ; CHECK-NOT: OpExtInst
151 OpCapability Shader
152 OpCapability Linkage
153 OpExtension "SPV_KHR_non_semantic_info"
154 %ext = OpExtInstImport "NonSemantic.Test"
155 OpMemoryModel Logical GLSL450
156 %void = OpTypeVoid
157 %1 = OpExtInst %void %ext 1
158 )";
159 
160   SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
161 }
162 
TEST_F(StripNonSemanticInfoTest,StripNonSemanticInFunction)163 TEST_F(StripNonSemanticInfoTest, StripNonSemanticInFunction) {
164   std::string text = R"(
165 ; CHECK-NOT: OpExtInst
166 OpCapability Shader
167 OpCapability Linkage
168 OpExtension "SPV_KHR_non_semantic_info"
169 %ext = OpExtInstImport "NonSemantic.Test"
170 OpMemoryModel 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
176 OpReturn
177 OpFunctionEnd
178 )";
179 
180   SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
181 }
182 
TEST_F(StripNonSemanticInfoTest,StripNonSemanticAfterFunction)183 TEST_F(StripNonSemanticInfoTest, StripNonSemanticAfterFunction) {
184   std::string text = R"(
185 ; CHECK-NOT: OpExtInst
186 OpCapability Shader
187 OpCapability Linkage
188 OpExtension "SPV_KHR_non_semantic_info"
189 %ext = OpExtInstImport "NonSemantic.Test"
190 OpMemoryModel Logical GLSL450
191 %void = OpTypeVoid
192 %void_fn = OpTypeFunction %void
193 %foo = OpFunction %void None %void_fn
194 %entry = OpLabel
195 OpReturn
196 OpFunctionEnd
197 %1 = OpExtInst %void %ext 1 %foo
198 )";
199 
200   SinglePassRunAndMatch<StripNonSemanticInfoPass>(text, true);
201 }
202 
TEST_F(StripNonSemanticInfoTest,StripNonSemanticBetweenFunctions)203 TEST_F(StripNonSemanticInfoTest, StripNonSemanticBetweenFunctions) {
204   std::string text = R"(
205 ; CHECK-NOT: OpExtInst
206 OpCapability Shader
207 OpCapability Linkage
208 OpExtension "SPV_KHR_non_semantic_info"
209 %ext = OpExtInstImport "NonSemantic.Test"
210 OpMemoryModel Logical GLSL450
211 %void = OpTypeVoid
212 %void_fn = OpTypeFunction %void
213 %foo = OpFunction %void None %void_fn
214 %entry = OpLabel
215 OpReturn
216 OpFunctionEnd
217 %1 = OpExtInst %void %ext 1 %foo
218 %bar = OpFunction %void None %void_fn
219 %bar_entry = OpLabel
220 OpReturn
221 OpFunctionEnd
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).
TEST_F(StripNonSemanticInfoTest,DontStripDebug)229 TEST_F(StripNonSemanticInfoTest, DontStripDebug) {
230   std::string text = R"(OpCapability Shader
231 OpMemoryModel Logical Simple
232 OpEntryPoint Fragment %1 "main"
233 OpExecutionMode %1 OriginUpperLeft
234 %2 = OpString "file"
235 %void = OpTypeVoid
236 %4 = OpTypeFunction %void
237 %1 = OpFunction %void None %4
238 %5 = OpLabel
239 OpLine %2 1 1
240 OpReturn
241 OpFunctionEnd
242 )";
243 
244   SinglePassRunAndCheck<StripNonSemanticInfoPass>(text, text, false);
245 }
246 
TEST_F(StripNonSemanticInfoTest,RemovedNonSemanticDebugInfo)247 TEST_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