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 "source/opt/strip_nonsemantic_info_pass.h" 16 17 #include <cstring> 18 #include <vector> 19 20 #include "source/opt/instruction.h" 21 #include "source/opt/ir_context.h" 22 #include "source/util/string_utils.h" 23 24 namespace spvtools { 25 namespace opt { 26 Process()27Pass::Status StripNonSemanticInfoPass::Process() { 28 bool modified = false; 29 30 std::vector<Instruction*> to_remove; 31 32 bool other_uses_for_decorate_string = false; 33 for (auto& inst : context()->module()->annotations()) { 34 switch (inst.opcode()) { 35 case SpvOpDecorateStringGOOGLE: 36 if (inst.GetSingleWordInOperand(1) == SpvDecorationHlslSemanticGOOGLE || 37 inst.GetSingleWordInOperand(1) == SpvDecorationUserTypeGOOGLE) { 38 to_remove.push_back(&inst); 39 } else { 40 other_uses_for_decorate_string = true; 41 } 42 break; 43 44 case SpvOpMemberDecorateStringGOOGLE: 45 if (inst.GetSingleWordInOperand(2) == SpvDecorationHlslSemanticGOOGLE || 46 inst.GetSingleWordInOperand(2) == SpvDecorationUserTypeGOOGLE) { 47 to_remove.push_back(&inst); 48 } else { 49 other_uses_for_decorate_string = true; 50 } 51 break; 52 53 case SpvOpDecorateId: 54 if (inst.GetSingleWordInOperand(1) == 55 SpvDecorationHlslCounterBufferGOOGLE) { 56 to_remove.push_back(&inst); 57 } 58 break; 59 60 default: 61 break; 62 } 63 } 64 65 for (auto& inst : context()->module()->extensions()) { 66 const std::string ext_name = inst.GetInOperand(0).AsString(); 67 if (ext_name == "SPV_GOOGLE_hlsl_functionality1") { 68 to_remove.push_back(&inst); 69 } else if (ext_name == "SPV_GOOGLE_user_type") { 70 to_remove.push_back(&inst); 71 } else if (!other_uses_for_decorate_string && 72 ext_name == "SPV_GOOGLE_decorate_string") { 73 to_remove.push_back(&inst); 74 } else if (ext_name == "SPV_KHR_non_semantic_info") { 75 to_remove.push_back(&inst); 76 } 77 } 78 79 // remove any extended inst imports that are non semantic 80 std::unordered_set<uint32_t> non_semantic_sets; 81 for (auto& inst : context()->module()->ext_inst_imports()) { 82 assert(inst.opcode() == SpvOpExtInstImport && 83 "Expecting an import of an extension's instruction set."); 84 const std::string extension_name = inst.GetInOperand(0).AsString(); 85 if (spvtools::utils::starts_with(extension_name, "NonSemantic.")) { 86 non_semantic_sets.insert(inst.result_id()); 87 to_remove.push_back(&inst); 88 } 89 } 90 91 // if we removed some non-semantic sets, then iterate over the instructions in 92 // the module to remove any OpExtInst that referenced those sets 93 if (!non_semantic_sets.empty()) { 94 context()->module()->ForEachInst( 95 [&non_semantic_sets, &to_remove](Instruction* inst) { 96 if (inst->opcode() == SpvOpExtInst) { 97 if (non_semantic_sets.find(inst->GetSingleWordInOperand(0)) != 98 non_semantic_sets.end()) { 99 to_remove.push_back(inst); 100 } 101 } 102 }, 103 true); 104 } 105 106 for (auto* inst : to_remove) { 107 modified = true; 108 context()->KillInst(inst); 109 } 110 111 return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; 112 } 113 114 } // namespace opt 115 } // namespace spvtools 116