1 // Copyright 2020 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_WRITER_MSL_GENERATOR_IMPL_H_ 16 #define SRC_WRITER_MSL_GENERATOR_IMPL_H_ 17 18 #include <sstream> 19 #include <string> 20 #include <unordered_map> 21 22 #include "src/ast/intrinsic.h" 23 #include "src/ast/literal.h" 24 #include "src/ast/module.h" 25 #include "src/ast/scalar_constructor_expression.h" 26 #include "src/ast/type/struct_type.h" 27 #include "src/ast/type_constructor_expression.h" 28 #include "src/scope_stack.h" 29 #include "src/writer/msl/namer.h" 30 #include "src/writer/text_generator.h" 31 32 namespace tint { 33 namespace writer { 34 namespace msl { 35 36 /// Implementation class for MSL generator 37 class GeneratorImpl : public TextGenerator { 38 public: 39 /// Constructor 40 /// @param module the module to generate 41 explicit GeneratorImpl(ast::Module* module); 42 ~GeneratorImpl(); 43 44 /// @returns true on successful generation; false otherwise 45 bool Generate(); 46 47 /// Calculates the alignment size of the given |type|. This returns 0 48 /// for pointers as the size is unknown. 49 /// @param type the type to calculate the alignment size for 50 /// @returns the number of bytes used to align |type| or 0 on error 51 uint32_t calculate_alignment_size(ast::type::Type* type); 52 /// Calculates the largest alignment seen within a struct 53 /// @param type the struct to calculate 54 /// @returns the largest alignment value 55 uint32_t calculate_largest_alignment(ast::type::StructType* type); 56 57 /// Handles generating a constructed 58 /// @param ty the constructed type to generate 59 /// @returns true if the constructed type was emitted 60 bool EmitConstructedType(const ast::type::Type* ty); 61 /// Handles an array accessor expression 62 /// @param expr the expression to emit 63 /// @returns true if the array accessor was emitted 64 bool EmitArrayAccessor(ast::ArrayAccessorExpression* expr); 65 /// Handles an assignment statement 66 /// @param stmt the statement to emit 67 /// @returns true if the statement was emitted successfully 68 bool EmitAssign(ast::AssignmentStatement* stmt); 69 /// Handles generating a binary expression 70 /// @param expr the binary expression 71 /// @returns true if the expression was emitted, false otherwise 72 bool EmitBinary(ast::BinaryExpression* expr); 73 /// Handles generating a bitcast expression 74 /// @param expr the bitcast expression 75 /// @returns true if the bitcast was emitted 76 bool EmitBitcast(ast::BitcastExpression* expr); 77 /// Handles a block statement 78 /// @param stmt the statement to emit 79 /// @returns true if the statement was emitted successfully 80 bool EmitBlock(const ast::BlockStatement* stmt); 81 /// Handles a block statement with a newline at the end 82 /// @param stmt the statement to emit 83 /// @returns true if the statement was emitted successfully 84 bool EmitIndentedBlockAndNewline(ast::BlockStatement* stmt); 85 /// Handles a block statement with a newline at the end 86 /// @param stmt the statement to emit 87 /// @returns true if the statement was emitted successfully 88 bool EmitBlockAndNewline(const ast::BlockStatement* stmt); 89 /// Handles a break statement 90 /// @param stmt the statement to emit 91 /// @returns true if the statement was emitted successfully 92 bool EmitBreak(ast::BreakStatement* stmt); 93 /// Handles generating a call expression 94 /// @param expr the call expression 95 /// @returns true if the call expression is emitted 96 bool EmitCall(ast::CallExpression* expr); 97 /// Handles a case statement 98 /// @param stmt the statement 99 /// @returns true if the statement was emitted successfully 100 bool EmitCase(ast::CaseStatement* stmt); 101 /// Handles generating constructor expressions 102 /// @param expr the constructor expression 103 /// @returns true if the expression was emitted 104 bool EmitConstructor(ast::ConstructorExpression* expr); 105 /// Handles a continue statement 106 /// @param stmt the statement to emit 107 /// @returns true if the statement was emitted successfully 108 bool EmitContinue(ast::ContinueStatement* stmt); 109 /// Handles generating a discard statement 110 /// @param stmt the discard statement 111 /// @returns true if the statement was successfully emitted 112 bool EmitDiscard(ast::DiscardStatement* stmt); 113 /// Handles generating an else statement 114 /// @param stmt the statement to emit 115 /// @returns true if the statement was emitted 116 bool EmitElse(ast::ElseStatement* stmt); 117 /// Handles emitting information for an entry point 118 /// @param func the entry point function 119 /// @returns true if the entry point data was emitted 120 bool EmitEntryPointData(ast::Function* func); 121 /// Handles emitting the entry point function 122 /// @param func the entry point function 123 /// @returns true if the entry point function was emitted 124 bool EmitEntryPointFunction(ast::Function* func); 125 /// Handles generate an Expression 126 /// @param expr the expression 127 /// @returns true if the expression was emitted 128 bool EmitExpression(ast::Expression* expr); 129 /// Handles generating a function 130 /// @param func the function to generate 131 /// @returns true if the function was emitted 132 bool EmitFunction(ast::Function* func); 133 /// Internal helper for emitting functions 134 /// @param func the function to emit 135 /// @param emit_duplicate_functions set true if we need to duplicate per entry 136 /// point 137 /// @param ep_name the current entry point or blank if none set 138 /// @returns true if the function was emitted. 139 bool EmitFunctionInternal(ast::Function* func, 140 bool emit_duplicate_functions, 141 const std::string& ep_name); 142 /// Handles generating an identifier expression 143 /// @param expr the identifier expression 144 /// @returns true if the identifier was emitted 145 bool EmitIdentifier(ast::IdentifierExpression* expr); 146 /// Handles an if statement 147 /// @param stmt the statement to emit 148 /// @returns true if the statement was successfully emitted 149 bool EmitIf(ast::IfStatement* stmt); 150 /// Handles a literal 151 /// @param lit the literal to emit 152 /// @returns true if the literal was successfully emitted 153 bool EmitLiteral(ast::Literal* lit); 154 /// Handles a loop statement 155 /// @param stmt the statement to emit 156 /// @returns true if the statement was emitted 157 bool EmitLoop(ast::LoopStatement* stmt); 158 /// Handles a member accessor expression 159 /// @param expr the member accessor expression 160 /// @returns true if the member accessor was emitted 161 bool EmitMemberAccessor(ast::MemberAccessorExpression* expr); 162 /// Handles return statements 163 /// @param stmt the statement to emit 164 /// @returns true if the statement was successfully emitted 165 bool EmitReturn(ast::ReturnStatement* stmt); 166 /// Handles generating a scalar constructor 167 /// @param expr the scalar constructor expression 168 /// @returns true if the scalar constructor is emitted 169 bool EmitScalarConstructor(ast::ScalarConstructorExpression* expr); 170 /// Handles emitting a pipeline stage name 171 /// @param stage the stage to emit 172 void EmitStage(ast::PipelineStage stage); 173 /// Handles statement 174 /// @param stmt the statement to emit 175 /// @returns true if the statement was emitted 176 bool EmitStatement(ast::Statement* stmt); 177 /// Handles generating a switch statement 178 /// @param stmt the statement to emit 179 /// @returns true if the statement was emitted 180 bool EmitSwitch(ast::SwitchStatement* stmt); 181 /// Handles generating type 182 /// @param type the type to generate 183 /// @param name the name of the variable, only used for array emission 184 /// @returns true if the type is emitted 185 bool EmitType(ast::type::Type* type, const std::string& name); 186 /// Handles generating a struct declaration 187 /// @param str the struct to generate 188 /// @returns true if the struct is emitted 189 bool EmitStructType(const ast::type::StructType* str); 190 /// Handles emitting a type constructor 191 /// @param expr the type constructor expression 192 /// @returns true if the constructor is emitted 193 bool EmitTypeConstructor(ast::TypeConstructorExpression* expr); 194 /// Handles a unary op expression 195 /// @param expr the expression to emit 196 /// @returns true if the expression was emitted 197 bool EmitUnaryOp(ast::UnaryOpExpression* expr); 198 /// Handles generating a variable 199 /// @param var the variable to generate 200 /// @param skip_constructor set true if the constructor should be skipped 201 /// @returns true if the variable was emitted 202 bool EmitVariable(ast::Variable* var, bool skip_constructor); 203 /// Handles generating a program scope constant variable 204 /// @param var the variable to emit 205 /// @returns true if the variable was emitted 206 bool EmitProgramConstVariable(const ast::Variable* var); 207 /// Emits the zero value for the given type 208 /// @param type the type to emit the value for 209 /// @returns true if the zero value was successfully emitted. 210 bool EmitZeroValue(ast::type::Type* type); 211 212 /// Determines if the function needs the input struct passed to it. 213 /// @param func the function to check 214 /// @returns true if there are input struct variables used in the function 215 bool has_referenced_in_var_needing_struct(ast::Function* func); 216 /// Determines if the function needs the output struct passed to it. 217 /// @param func the function to check 218 /// @returns true if there are output struct variables used in the function 219 bool has_referenced_out_var_needing_struct(ast::Function* func); 220 /// Determines if any used module variable requires an input or output struct. 221 /// @param func the function to check 222 /// @returns true if an input or output struct is required. 223 bool has_referenced_var_needing_struct(ast::Function* func); 224 225 /// Generates a name for the prefix 226 /// @param prefix the prefix of the name to generate 227 /// @returns the name 228 std::string generate_name(const std::string& prefix); 229 /// Generates an intrinsic name from the given name 230 /// @param intrinsic the intrinsic to convert to an method name 231 /// @returns the intrinsic name or blank on error 232 std::string generate_intrinsic_name(ast::Intrinsic intrinsic); 233 /// Handles generating a builtin name 234 /// @param ident the identifier to build the name from 235 /// @returns the name or "" if not valid 236 std::string generate_builtin_name(ast::IdentifierExpression* ident); 237 238 /// Checks if the global variable is in an input or output struct 239 /// @param var the variable to check 240 /// @returns true if the global is in an input or output struct 241 bool global_is_in_struct(ast::Variable* var) const; 242 243 /// Converts a builtin to an attribute name 244 /// @param builtin the builtin to convert 245 /// @returns the string name of the builtin or blank on error 246 std::string builtin_to_attribute(ast::Builtin builtin) const; 247 248 /// @returns the namer for testing namer_for_testing()249 Namer* namer_for_testing() { return &namer_; } 250 251 private: 252 enum class VarType { kIn, kOut }; 253 254 struct EntryPointData { 255 std::string struct_name; 256 std::string var_name; 257 }; 258 259 std::string current_ep_var_name(VarType type); 260 261 Namer namer_; 262 ScopeStack<ast::Variable*> global_variables_; 263 std::string current_ep_name_; 264 bool generating_entry_point_ = false; 265 const ast::Module* module_ = nullptr; 266 uint32_t loop_emission_counter_ = 0; 267 268 std::unordered_map<std::string, EntryPointData> ep_name_to_in_data_; 269 std::unordered_map<std::string, EntryPointData> ep_name_to_out_data_; 270 271 // This maps an input of "<entry_point_name>_<function_name>" to a remapped 272 // function name. If there is no entry for a given key then function did 273 // not need to be remapped for the entry point and can be emitted directly. 274 std::unordered_map<std::string, std::string> ep_func_name_remapped_; 275 }; 276 277 } // namespace msl 278 } // namespace writer 279 } // namespace tint 280 281 #endif // SRC_WRITER_MSL_GENERATOR_IMPL_H_ 282