1 | // Copyright (c) 2017 Google Inc. |
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/feature_manager.h" |
16 | |
17 | #include <queue> |
18 | #include <stack> |
19 | #include <string> |
20 | |
21 | #include "source/enum_string_mapping.h" |
22 | |
23 | namespace spvtools { |
24 | namespace opt { |
25 | |
26 | void FeatureManager::Analyze(Module* module) { |
27 | AddExtensions(module); |
28 | AddCapabilities(module); |
29 | AddExtInstImportIds(module); |
30 | } |
31 | |
32 | void FeatureManager::AddExtensions(Module* module) { |
33 | for (auto ext : module->extensions()) { |
34 | AddExtension(&ext); |
35 | } |
36 | } |
37 | |
38 | void FeatureManager::AddExtension(Instruction* ext) { |
39 | assert(ext->opcode() == SpvOpExtension && |
40 | "Expecting an extension instruction." ); |
41 | |
42 | const std::string name = |
43 | reinterpret_cast<const char*>(ext->GetInOperand(0u).words.data()); |
44 | Extension extension; |
45 | if (GetExtensionFromString(name.c_str(), &extension)) { |
46 | extensions_.Add(extension); |
47 | } |
48 | } |
49 | |
50 | void FeatureManager::RemoveExtension(Extension ext) { |
51 | if (!extensions_.Contains(ext)) return; |
52 | extensions_.Remove(ext); |
53 | } |
54 | |
55 | void FeatureManager::AddCapability(SpvCapability cap) { |
56 | if (capabilities_.Contains(cap)) return; |
57 | |
58 | capabilities_.Add(cap); |
59 | |
60 | spv_operand_desc desc = {}; |
61 | if (SPV_SUCCESS == |
62 | grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, cap, &desc)) { |
63 | CapabilitySet(desc->numCapabilities, desc->capabilities) |
64 | .ForEach([this](SpvCapability c) { AddCapability(c); }); |
65 | } |
66 | } |
67 | |
68 | void FeatureManager::RemoveCapability(SpvCapability cap) { |
69 | if (!capabilities_.Contains(cap)) return; |
70 | capabilities_.Remove(cap); |
71 | } |
72 | |
73 | void FeatureManager::AddCapabilities(Module* module) { |
74 | for (Instruction& inst : module->capabilities()) { |
75 | AddCapability(static_cast<SpvCapability>(inst.GetSingleWordInOperand(0))); |
76 | } |
77 | } |
78 | |
79 | void FeatureManager::AddExtInstImportIds(Module* module) { |
80 | extinst_importid_GLSLstd450_ = module->GetExtInstImportId("GLSL.std.450" ); |
81 | } |
82 | |
83 | bool operator==(const FeatureManager& a, const FeatureManager& b) { |
84 | // We check that the addresses of the grammars are the same because they |
85 | // are large objects, and this is faster. It can be changed if needed as a |
86 | // later time. |
87 | if (&a.grammar_ != &b.grammar_) { |
88 | return false; |
89 | } |
90 | |
91 | if (a.capabilities_ != b.capabilities_) { |
92 | return false; |
93 | } |
94 | |
95 | if (a.extensions_ != b.extensions_) { |
96 | return false; |
97 | } |
98 | |
99 | if (a.extinst_importid_GLSLstd450_ != b.extinst_importid_GLSLstd450_) { |
100 | return false; |
101 | } |
102 | |
103 | return true; |
104 | } |
105 | } // namespace opt |
106 | } // namespace spvtools |
107 | |