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