1 // Copyright (c) 2022 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 #ifndef SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_ 16 #define SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_ 17 18 #include "source/opt/pass.h" 19 20 namespace spvtools { 21 namespace opt { 22 23 // See optimizer.hpp for documentation. 24 class SpreadVolatileSemantics : public Pass { 25 public: SpreadVolatileSemantics()26 SpreadVolatileSemantics() {} 27 name()28 const char* name() const override { return "spread-volatile-semantics"; } 29 30 Status Process() override; 31 GetPreservedAnalyses()32 IRContext::Analysis GetPreservedAnalyses() override { 33 return IRContext::kAnalysisDefUse | IRContext::kAnalysisDecorations | 34 IRContext::kAnalysisInstrToBlockMapping; 35 } 36 37 private: 38 // Returns true if it does not have an execution model. Linkage shaders do not 39 // have an execution model. HasNoExecutionModel()40 bool HasNoExecutionModel() { 41 return get_module()->entry_points().empty() && 42 context()->get_feature_mgr()->HasCapability( 43 spv::Capability::Linkage); 44 } 45 46 // Iterates interface variables and spreads the Volatile semantics if it has 47 // load instructions for the Volatile semantics. 48 Pass::Status SpreadVolatileSemanticsToVariables( 49 const bool is_vk_memory_model_enabled); 50 51 // Returns whether |var_id| is the result id of a target builtin variable for 52 // the volatile semantics for |execution_model| based on the Vulkan spec 53 // VUID-StandaloneSpirv-VulkanMemoryModel-04678 or 54 // VUID-StandaloneSpirv-VulkanMemoryModel-04679. 55 bool IsTargetForVolatileSemantics(uint32_t var_id, 56 spv::ExecutionModel execution_model); 57 58 // Collects interface variables that need the volatile semantics. 59 // |is_vk_memory_model_enabled| is true if VulkanMemoryModel capability is 60 // enabled. 61 void CollectTargetsForVolatileSemantics( 62 const bool is_vk_memory_model_enabled); 63 64 // Reports an error if an interface variable is used by two entry points and 65 // it needs the Volatile decoration for one but not for another. Returns true 66 // if the error must be reported. 67 bool HasInterfaceInConflictOfVolatileSemantics(); 68 69 // Returns whether the variable whose result is |var_id| is used by a 70 // non-volatile load or a pointer to it is used by a non-volatile load in 71 // |entry_point| or not. 72 bool IsTargetUsedByNonVolatileLoadInEntryPoint(uint32_t var_id, 73 Instruction* entry_point); 74 75 // Visits load instructions of pointers to variable whose result id is 76 // |var_id| if the load instructions are in reachable functions from entry 77 // points. |handle_load| is a function to do some actions for the load 78 // instructions. Finishes the traversal and returns false if |handle_load| 79 // returns false for a load instruction. Otherwise, returns true after running 80 // |handle_load| for all the load instructions. 81 bool VisitLoadsOfPointersToVariableInEntries( 82 uint32_t var_id, const std::function<bool(Instruction*)>& handle_load, 83 const std::unordered_set<uint32_t>& function_ids); 84 85 // Sets Memory Operands of OpLoad instructions that load |var| or pointers 86 // of |var| as Volatile if the function id of the OpLoad instruction is 87 // included in |entry_function_ids|. 88 void SetVolatileForLoadsInEntries( 89 Instruction* var, const std::unordered_set<uint32_t>& entry_function_ids); 90 91 // Adds OpDecorate Volatile for |var| if it does not exist. 92 void DecorateVarWithVolatile(Instruction* var); 93 94 // Returns a set of entry function ids to spread the volatile semantics for 95 // the variable with the result id |var_id|. EntryFunctionsToSpreadVolatileSemanticsForVar(uint32_t var_id)96 std::unordered_set<uint32_t> EntryFunctionsToSpreadVolatileSemanticsForVar( 97 uint32_t var_id) { 98 auto itr = var_ids_to_entry_fn_for_volatile_semantics_.find(var_id); 99 if (itr == var_ids_to_entry_fn_for_volatile_semantics_.end()) return {}; 100 return itr->second; 101 } 102 103 // Specifies that we have to spread the volatile semantics for the 104 // variable with the result id |var_id| for the entry point |entry_point|. 105 void MarkVolatileSemanticsForVariable(uint32_t var_id, 106 Instruction* entry_point); 107 108 // Result ids of variables to entry function ids for the volatile semantics 109 // spread. 110 std::unordered_map<uint32_t, std::unordered_set<uint32_t>> 111 var_ids_to_entry_fn_for_volatile_semantics_; 112 }; 113 114 } // namespace opt 115 } // namespace spvtools 116 117 #endif // SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_ 118