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 #include "gmock/gmock.h"
17 
18 #include "spirv-tools/optimizer.hpp"
19 
20 #include "test/opt/pass_fixture.h"
21 #include "test/opt/pass_utils.h"
22 
23 namespace spvtools {
24 namespace opt {
25 namespace {
26 
27 using StripLineReflectInfoTest = PassTest<::testing::Test>;
28 using StripNonSemanticInfoTest = PassTest<::testing::Test>;
29 
30 // This test acts as an end-to-end code example on how to strip
31 // reflection info from a SPIR-V module.  Use this code pattern
32 // when you have compiled HLSL code with Glslang or DXC using
33 // option -fhlsl_functionality1 to insert reflection information,
34 // but then want to filter out the extra instructions before sending
35 // it to a driver that does not implement VK_GOOGLE_hlsl_functionality1.
TEST_F(StripLineReflectInfoTest,StripReflectEnd2EndExample)36 TEST_F(StripLineReflectInfoTest, StripReflectEnd2EndExample) {
37   // This is a non-sensical example, but exercises the instructions.
38   std::string before = R"(OpCapability Shader
39 OpCapability Linkage
40 OpExtension "SPV_GOOGLE_decorate_string"
41 OpExtension "SPV_GOOGLE_hlsl_functionality1"
42 OpMemoryModel Logical Simple
43 OpDecorateStringGOOGLE %float HlslSemanticGOOGLE "foobar"
44 OpDecorateStringGOOGLE %void HlslSemanticGOOGLE "my goodness"
45 %void = OpTypeVoid
46 %float = OpTypeFloat 32
47 )";
48   SpirvTools tools(SPV_ENV_UNIVERSAL_1_1);
49   std::vector<uint32_t> binary_in;
50   tools.Assemble(before, &binary_in);
51 
52   // Instantiate the optimizer, and run the strip-reflection-info
53   // pass over the |binary_in| module, and place the modified module
54   // into |binary_out|.
55   spvtools::Optimizer optimizer(SPV_ENV_UNIVERSAL_1_1);
56   optimizer.RegisterPass(spvtools::CreateStripReflectInfoPass());
57   std::vector<uint32_t> binary_out;
58   optimizer.Run(binary_in.data(), binary_in.size(), &binary_out);
59 
60   // Check results
61   std::string disassembly;
62   tools.Disassemble(binary_out.data(), binary_out.size(), &disassembly);
63   std::string after = R"(OpCapability Shader
64 OpCapability Linkage
65 OpMemoryModel Logical Simple
66 %void = OpTypeVoid
67 %float = OpTypeFloat 32
68 )";
69   EXPECT_THAT(disassembly, testing::Eq(after));
70 }
71 
72 // This test is functionally the same as the end-to-end test above,
73 // but uses the test SinglePassRunAndCheck test fixture instead.
TEST_F(StripLineReflectInfoTest,StripHlslSemantic)74 TEST_F(StripLineReflectInfoTest, StripHlslSemantic) {
75   // This is a non-sensical example, but exercises the instructions.
76   std::string before = R"(OpCapability Shader
77 OpCapability Linkage
78 OpExtension "SPV_GOOGLE_decorate_string"
79 OpExtension "SPV_GOOGLE_hlsl_functionality1"
80 OpMemoryModel Logical Simple
81 OpDecorateStringGOOGLE %float HlslSemanticGOOGLE "foobar"
82 OpDecorateStringGOOGLE %void HlslSemanticGOOGLE "my goodness"
83 %void = OpTypeVoid
84 %float = OpTypeFloat 32
85 )";
86   std::string after = R"(OpCapability Shader
87 OpCapability Linkage
88 OpMemoryModel Logical Simple
89 %void = OpTypeVoid
90 %float = OpTypeFloat 32
91 )";
92 
93   SinglePassRunAndCheck<StripReflectInfoPass>(before, after, false);
94 }
95 
TEST_F(StripLineReflectInfoTest,StripHlslCounterBuffer)96 TEST_F(StripLineReflectInfoTest, StripHlslCounterBuffer) {
97   std::string before = R"(OpCapability Shader
98 OpCapability Linkage
99 OpExtension "SPV_GOOGLE_hlsl_functionality1"
100 OpMemoryModel Logical Simple
101 OpDecorateId %void HlslCounterBufferGOOGLE %float
102 %void = OpTypeVoid
103 %float = OpTypeFloat 32
104 )";
105   std::string after = R"(OpCapability Shader
106 OpCapability Linkage
107 OpMemoryModel Logical Simple
108 %void = OpTypeVoid
109 %float = OpTypeFloat 32
110 )";
111 
112   SinglePassRunAndCheck<StripReflectInfoPass>(before, after, false);
113 }
114 
TEST_F(StripLineReflectInfoTest,StripHlslSemanticOnMember)115 TEST_F(StripLineReflectInfoTest, StripHlslSemanticOnMember) {
116   // This is a non-sensical example, but exercises the instructions.
117   std::string before = R"(OpCapability Shader
118 OpCapability Linkage
119 OpExtension "SPV_GOOGLE_decorate_string"
120 OpExtension "SPV_GOOGLE_hlsl_functionality1"
121 OpMemoryModel Logical Simple
122 OpMemberDecorateStringGOOGLE %struct 0 HlslSemanticGOOGLE "foobar"
123 %float = OpTypeFloat 32
124 %_struct_3 = OpTypeStruct %float
125 )";
126   std::string after = R"(OpCapability Shader
127 OpCapability Linkage
128 OpMemoryModel Logical Simple
129 %float = OpTypeFloat 32
130 %_struct_3 = OpTypeStruct %float
131 )";
132 
133   SinglePassRunAndCheck<StripReflectInfoPass>(before, after, false);
134 }
135 
TEST_F(StripNonSemanticInfoTest,StripNonSemanticImport)136 TEST_F(StripNonSemanticInfoTest, StripNonSemanticImport) {
137   std::string text = R"(
138 ; CHECK-NOT: OpExtension "SPV_KHR_non_semantic_info"
139 ; CHECK-NOT: OpExtInstImport
140 OpCapability Shader
141 OpCapability Linkage
142 OpExtension "SPV_KHR_non_semantic_info"
143 %ext = OpExtInstImport "NonSemantic.Test"
144 OpMemoryModel Logical GLSL450
145 )";
146 
147   SinglePassRunAndMatch<StripReflectInfoPass>(text, true);
148 }
149 
TEST_F(StripNonSemanticInfoTest,StripNonSemanticGlobal)150 TEST_F(StripNonSemanticInfoTest, StripNonSemanticGlobal) {
151   std::string text = R"(
152 ; CHECK-NOT: OpExtInst
153 OpCapability Shader
154 OpCapability Linkage
155 OpExtension "SPV_KHR_non_semantic_info"
156 %ext = OpExtInstImport "NonSemantic.Test"
157 OpMemoryModel Logical GLSL450
158 %void = OpTypeVoid
159 %1 = OpExtInst %void %ext 1
160 )";
161 
162   SinglePassRunAndMatch<StripReflectInfoPass>(text, true);
163 }
164 
TEST_F(StripNonSemanticInfoTest,StripNonSemanticInFunction)165 TEST_F(StripNonSemanticInfoTest, StripNonSemanticInFunction) {
166   std::string text = R"(
167 ; CHECK-NOT: OpExtInst
168 OpCapability Shader
169 OpCapability Linkage
170 OpExtension "SPV_KHR_non_semantic_info"
171 %ext = OpExtInstImport "NonSemantic.Test"
172 OpMemoryModel Logical GLSL450
173 %void = OpTypeVoid
174 %void_fn = OpTypeFunction %void
175 %foo = OpFunction %void None %void_fn
176 %entry = OpLabel
177 %1 = OpExtInst %void %ext 1 %foo
178 OpReturn
179 OpFunctionEnd
180 )";
181 
182   SinglePassRunAndMatch<StripReflectInfoPass>(text, true);
183 }
184 
TEST_F(StripNonSemanticInfoTest,StripNonSemanticAfterFunction)185 TEST_F(StripNonSemanticInfoTest, StripNonSemanticAfterFunction) {
186   std::string text = R"(
187 ; CHECK-NOT: OpExtInst
188 OpCapability Shader
189 OpCapability Linkage
190 OpExtension "SPV_KHR_non_semantic_info"
191 %ext = OpExtInstImport "NonSemantic.Test"
192 OpMemoryModel Logical GLSL450
193 %void = OpTypeVoid
194 %void_fn = OpTypeFunction %void
195 %foo = OpFunction %void None %void_fn
196 %entry = OpLabel
197 OpReturn
198 OpFunctionEnd
199 %1 = OpExtInst %void %ext 1 %foo
200 )";
201 
202   SinglePassRunAndMatch<StripReflectInfoPass>(text, true);
203 }
204 
TEST_F(StripNonSemanticInfoTest,StripNonSemanticBetweenFunctions)205 TEST_F(StripNonSemanticInfoTest, StripNonSemanticBetweenFunctions) {
206   std::string text = R"(
207 ; CHECK-NOT: OpExtInst
208 OpCapability Shader
209 OpCapability Linkage
210 OpExtension "SPV_KHR_non_semantic_info"
211 %ext = OpExtInstImport "NonSemantic.Test"
212 OpMemoryModel Logical GLSL450
213 %void = OpTypeVoid
214 %void_fn = OpTypeFunction %void
215 %foo = OpFunction %void None %void_fn
216 %entry = OpLabel
217 OpReturn
218 OpFunctionEnd
219 %1 = OpExtInst %void %ext 1 %foo
220 %bar = OpFunction %void None %void_fn
221 %bar_entry = OpLabel
222 OpReturn
223 OpFunctionEnd
224 )";
225 
226   SinglePassRunAndMatch<StripReflectInfoPass>(text, true);
227 }
228 
229 }  // namespace
230 }  // namespace opt
231 }  // namespace spvtools
232