1 // Copyright 2021 The Tint Authors. 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 SRC_SEM_FUNCTION_H_ 16 #define SRC_SEM_FUNCTION_H_ 17 18 #include <array> 19 #include <utility> 20 #include <vector> 21 22 #include "src/ast/variable.h" 23 #include "src/sem/call.h" 24 #include "src/utils/unique_vector.h" 25 26 namespace tint { 27 28 // Forward declarations 29 namespace ast { 30 class BuiltinDecoration; 31 class Function; 32 class LocationDecoration; 33 class ReturnStatement; 34 } // namespace ast 35 36 namespace sem { 37 38 class Intrinsic; 39 class Variable; 40 41 /// WorkgroupDimension describes the size of a single dimension of an entry 42 /// point's workgroup size. 43 struct WorkgroupDimension { 44 /// The size of this dimension. 45 uint32_t value; 46 /// A pipeline-overridable constant that overrides the size, or nullptr if 47 /// this dimension is not overridable. 48 const ast::Variable* overridable_const = nullptr; 49 }; 50 51 /// WorkgroupSize is a three-dimensional array of WorkgroupDimensions. 52 using WorkgroupSize = std::array<WorkgroupDimension, 3>; 53 54 /// Function holds the semantic information for function nodes. 55 class Function : public Castable<Function, CallTarget> { 56 public: 57 /// A vector of [Variable*, ast::VariableBindingPoint] pairs 58 using VariableBindings = 59 std::vector<std::pair<const Variable*, ast::VariableBindingPoint>>; 60 61 /// Constructor 62 /// @param declaration the ast::Function 63 /// @param return_type the return type of the function 64 /// @param parameters the parameters to the function 65 Function(const ast::Function* declaration, 66 Type* return_type, 67 std::vector<Parameter*> parameters); 68 69 /// Destructor 70 ~Function() override; 71 72 /// @returns the ast::Function declaration Declaration()73 const ast::Function* Declaration() const { return declaration_; } 74 75 /// @returns the workgroup size {x, y, z} for the function. WorkgroupSize()76 const sem::WorkgroupSize& WorkgroupSize() const { return workgroup_size_; } 77 78 /// Sets the workgroup size {x, y, z} for the function. 79 /// @param workgroup_size the new workgroup size of the function SetWorkgroupSize(sem::WorkgroupSize workgroup_size)80 void SetWorkgroupSize(sem::WorkgroupSize workgroup_size) { 81 workgroup_size_ = std::move(workgroup_size); 82 } 83 84 /// @returns all directly referenced global variables DirectlyReferencedGlobals()85 const utils::UniqueVector<const GlobalVariable*>& DirectlyReferencedGlobals() 86 const { 87 return directly_referenced_globals_; 88 } 89 90 /// Records that this function directly references the given global variable. 91 /// Note: Implicitly adds this global to the transtively-called globals. 92 /// @param global the module-scope variable AddDirectlyReferencedGlobal(const sem::GlobalVariable * global)93 void AddDirectlyReferencedGlobal(const sem::GlobalVariable* global) { 94 directly_referenced_globals_.add(global); 95 transitively_referenced_globals_.add(global); 96 } 97 98 /// @returns all transitively referenced global variables 99 const utils::UniqueVector<const GlobalVariable*>& TransitivelyReferencedGlobals()100 TransitivelyReferencedGlobals() const { 101 return transitively_referenced_globals_; 102 } 103 104 /// Records that this function transitively references the given global 105 /// variable. 106 /// @param global the module-scoped variable AddTransitivelyReferencedGlobal(const sem::GlobalVariable * global)107 void AddTransitivelyReferencedGlobal(const sem::GlobalVariable* global) { 108 transitively_referenced_globals_.add(global); 109 } 110 111 /// @returns the list of functions that this function transitively calls. TransitivelyCalledFunctions()112 const utils::UniqueVector<const Function*>& TransitivelyCalledFunctions() 113 const { 114 return transitively_called_functions_; 115 } 116 117 /// Records that this function transitively calls `function`. 118 /// @param function the function this function transitively calls AddTransitivelyCalledFunction(const Function * function)119 void AddTransitivelyCalledFunction(const Function* function) { 120 transitively_called_functions_.add(function); 121 } 122 123 /// @returns the list of intrinsics that this function directly calls. DirectlyCalledIntrinsics()124 const utils::UniqueVector<const Intrinsic*>& DirectlyCalledIntrinsics() 125 const { 126 return directly_called_intrinsics_; 127 } 128 129 /// Records that this function transitively calls `intrinsic`. 130 /// @param intrinsic the intrinsic this function directly calls AddDirectlyCalledIntrinsic(const Intrinsic * intrinsic)131 void AddDirectlyCalledIntrinsic(const Intrinsic* intrinsic) { 132 directly_called_intrinsics_.add(intrinsic); 133 } 134 135 /// @returns the list of direct calls to functions / intrinsics made by this 136 /// function DirectCallStatements()137 std::vector<const Call*> DirectCallStatements() const { 138 return direct_calls_; 139 } 140 141 /// Adds a record of the direct function / intrinsic calls made by this 142 /// function 143 /// @param call the call AddDirectCall(const Call * call)144 void AddDirectCall(const Call* call) { direct_calls_.emplace_back(call); } 145 146 /// @param target the target of a call 147 /// @returns the Call to the given CallTarget, or nullptr the target was not 148 /// called by this function. FindDirectCallTo(const CallTarget * target)149 const Call* FindDirectCallTo(const CallTarget* target) const { 150 for (auto* call : direct_calls_) { 151 if (call->Target() == target) { 152 return call; 153 } 154 } 155 return nullptr; 156 } 157 158 /// @returns the list of callsites of this function CallSites()159 std::vector<const Call*> CallSites() const { return callsites_; } 160 161 /// Adds a record of a callsite to this function 162 /// @param call the callsite AddCallSite(const Call * call)163 void AddCallSite(const Call* call) { callsites_.emplace_back(call); } 164 165 /// @returns the ancestor entry points AncestorEntryPoints()166 const std::vector<const Function*>& AncestorEntryPoints() const { 167 return ancestor_entry_points_; 168 } 169 170 /// Adds a record that the given entry point transitively calls this function 171 /// @param entry_point the entry point that transtively calls this function AddAncestorEntryPoint(const sem::Function * entry_point)172 void AddAncestorEntryPoint(const sem::Function* entry_point) { 173 ancestor_entry_points_.emplace_back(entry_point); 174 } 175 176 /// Retrieves any referenced location variables 177 /// @returns the <variable, decoration> pair. 178 std::vector<std::pair<const Variable*, const ast::LocationDecoration*>> 179 TransitivelyReferencedLocationVariables() const; 180 181 /// Retrieves any referenced builtin variables 182 /// @returns the <variable, decoration> pair. 183 std::vector<std::pair<const Variable*, const ast::BuiltinDecoration*>> 184 TransitivelyReferencedBuiltinVariables() const; 185 186 /// Retrieves any referenced uniform variables. Note, the variables must be 187 /// decorated with both binding and group decorations. 188 /// @returns the referenced uniforms 189 VariableBindings TransitivelyReferencedUniformVariables() const; 190 191 /// Retrieves any referenced storagebuffer variables. Note, the variables 192 /// must be decorated with both binding and group decorations. 193 /// @returns the referenced storagebuffers 194 VariableBindings TransitivelyReferencedStorageBufferVariables() const; 195 196 /// Retrieves any referenced regular Sampler variables. Note, the 197 /// variables must be decorated with both binding and group decorations. 198 /// @returns the referenced storagebuffers 199 VariableBindings TransitivelyReferencedSamplerVariables() const; 200 201 /// Retrieves any referenced comparison Sampler variables. Note, the 202 /// variables must be decorated with both binding and group decorations. 203 /// @returns the referenced storagebuffers 204 VariableBindings TransitivelyReferencedComparisonSamplerVariables() const; 205 206 /// Retrieves any referenced sampled textures variables. Note, the 207 /// variables must be decorated with both binding and group decorations. 208 /// @returns the referenced sampled textures 209 VariableBindings TransitivelyReferencedSampledTextureVariables() const; 210 211 /// Retrieves any referenced multisampled textures variables. Note, the 212 /// variables must be decorated with both binding and group decorations. 213 /// @returns the referenced sampled textures 214 VariableBindings TransitivelyReferencedMultisampledTextureVariables() const; 215 216 /// Retrieves any referenced variables of the given type. Note, the variables 217 /// must be decorated with both binding and group decorations. 218 /// @param type_info the type of the variables to find 219 /// @returns the referenced variables 220 VariableBindings TransitivelyReferencedVariablesOfType( 221 const tint::TypeInfo& type_info) const; 222 223 /// Retrieves any referenced variables of the given type. Note, the variables 224 /// must be decorated with both binding and group decorations. 225 /// @returns the referenced variables 226 template <typename T> TransitivelyReferencedVariablesOfType()227 VariableBindings TransitivelyReferencedVariablesOfType() const { 228 return TransitivelyReferencedVariablesOfType(TypeInfo::Of<T>()); 229 } 230 231 /// Checks if the given entry point is an ancestor 232 /// @param sym the entry point symbol 233 /// @returns true if `sym` is an ancestor entry point of this function 234 bool HasAncestorEntryPoint(Symbol sym) const; 235 236 /// Sets that this function has a discard statement SetHasDiscard()237 void SetHasDiscard() { has_discard_ = true; } 238 239 /// Returns true if this function has a discard statement 240 /// @returns true if this function has a discard statement HasDiscard()241 bool HasDiscard() const { return has_discard_; } 242 243 /// @return the behaviors of this function Behaviors()244 const sem::Behaviors& Behaviors() const { return behaviors_; } 245 246 /// @return the behaviors of this function Behaviors()247 sem::Behaviors& Behaviors() { return behaviors_; } 248 249 private: 250 VariableBindings TransitivelyReferencedSamplerVariablesImpl( 251 ast::SamplerKind kind) const; 252 VariableBindings TransitivelyReferencedSampledTextureVariablesImpl( 253 bool multisampled) const; 254 255 const ast::Function* const declaration_; 256 257 sem::WorkgroupSize workgroup_size_; 258 utils::UniqueVector<const GlobalVariable*> directly_referenced_globals_; 259 utils::UniqueVector<const GlobalVariable*> transitively_referenced_globals_; 260 utils::UniqueVector<const Function*> transitively_called_functions_; 261 utils::UniqueVector<const Intrinsic*> directly_called_intrinsics_; 262 std::vector<const Call*> direct_calls_; 263 std::vector<const Call*> callsites_; 264 std::vector<const Function*> ancestor_entry_points_; 265 bool has_discard_ = false; 266 sem::Behaviors behaviors_{sem::Behavior::kNext}; 267 }; 268 269 } // namespace sem 270 } // namespace tint 271 272 #endif // SRC_SEM_FUNCTION_H_ 273