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