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(SpvCapabilityLinkage); 43 } 44 45 // Iterates interface variables and spreads the Volatile semantics if it has 46 // load instructions for the Volatile semantics. 47 Pass::Status SpreadVolatileSemanticsToVariables( 48 const bool is_vk_memory_model_enabled); 49 50 // Returns whether |var_id| is the result id of a target builtin variable for 51 // the volatile semantics for |execution_model| based on the Vulkan spec 52 // VUID-StandaloneSpirv-VulkanMemoryModel-04678 or 53 // VUID-StandaloneSpirv-VulkanMemoryModel-04679. 54 bool IsTargetForVolatileSemantics(uint32_t var_id, 55 SpvExecutionModel execution_model); 56 57 // Collects interface variables that need the volatile semantics. 58 // |is_vk_memory_model_enabled| is true if VulkanMemoryModel capability is 59 // enabled. 60 void CollectTargetsForVolatileSemantics( 61 const bool is_vk_memory_model_enabled); 62 63 // Reports an error if an interface variable is used by two entry points and 64 // it needs the Volatile decoration for one but not for another. Returns true 65 // if the error must be reported. 66 bool HasInterfaceInConflictOfVolatileSemantics(); 67 68 // Returns whether the variable whose result is |var_id| is used by a 69 // non-volatile load or a pointer to it is used by a non-volatile load in 70 // |entry_point| or not. 71 bool IsTargetUsedByNonVolatileLoadInEntryPoint(uint32_t var_id, 72 Instruction* entry_point); 73 74 // Visits load instructions of pointers to variable whose result id is 75 // |var_id| if the load instructions are in reachable functions from entry 76 // points. |handle_load| is a function to do some actions for the load 77 // instructions. Finishes the traversal and returns false if |handle_load| 78 // returns false for a load instruction. Otherwise, returns true after running 79 // |handle_load| for all the load instructions. 80 bool VisitLoadsOfPointersToVariableInEntries( 81 uint32_t var_id, const std::function<bool(Instruction*)>& handle_load, 82 const std::unordered_set<uint32_t>& function_ids); 83 84 // Sets Memory Operands of OpLoad instructions that load |var| or pointers 85 // of |var| as Volatile if the function id of the OpLoad instruction is 86 // included in |entry_function_ids|. 87 void SetVolatileForLoadsInEntries( 88 Instruction* var, const std::unordered_set<uint32_t>& entry_function_ids); 89 90 // Adds OpDecorate Volatile for |var| if it does not exist. 91 void DecorateVarWithVolatile(Instruction* var); 92 93 // Returns a set of entry function ids to spread the volatile semantics for 94 // the variable with the result id |var_id|. EntryFunctionsToSpreadVolatileSemanticsForVar(uint32_t var_id)95 std::unordered_set<uint32_t> EntryFunctionsToSpreadVolatileSemanticsForVar( 96 uint32_t var_id) { 97 auto itr = var_ids_to_entry_fn_for_volatile_semantics_.find(var_id); 98 if (itr == var_ids_to_entry_fn_for_volatile_semantics_.end()) return {}; 99 return itr->second; 100 } 101 102 // Specifies that we have to spread the volatile semantics for the 103 // variable with the result id |var_id| for the entry point |entry_point|. 104 void MarkVolatileSemanticsForVariable(uint32_t var_id, 105 Instruction* entry_point); 106 107 // Result ids of variables to entry function ids for the volatile semantics 108 // spread. 109 std::unordered_map<uint32_t, std::unordered_set<uint32_t>> 110 var_ids_to_entry_fn_for_volatile_semantics_; 111 }; 112 113 } // namespace opt 114 } // namespace spvtools 115 116 #endif // SOURCE_OPT_SPREAD_VOLATILE_SEMANTICS_H_ 117