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