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_SPIRV_BUILDER_H_ 16 #define SRC_WRITER_SPIRV_BUILDER_H_ 17 18 #include <string> 19 #include <unordered_map> 20 #include <unordered_set> 21 #include <vector> 22 23 #include "spirv/unified1/spirv.h" 24 #include "src/ast/assignment_statement.h" 25 #include "src/ast/bitcast_expression.h" 26 #include "src/ast/break_statement.h" 27 #include "src/ast/continue_statement.h" 28 #include "src/ast/discard_statement.h" 29 #include "src/ast/if_statement.h" 30 #include "src/ast/interpolate_decoration.h" 31 #include "src/ast/loop_statement.h" 32 #include "src/ast/return_statement.h" 33 #include "src/ast/switch_statement.h" 34 #include "src/ast/unary_op_expression.h" 35 #include "src/ast/variable_decl_statement.h" 36 #include "src/program_builder.h" 37 #include "src/scope_stack.h" 38 #include "src/sem/intrinsic.h" 39 #include "src/sem/storage_texture_type.h" 40 #include "src/writer/spirv/function.h" 41 #include "src/writer/spirv/scalar_constant.h" 42 43 namespace tint { 44 45 // Forward declarations 46 namespace sem { 47 class Call; 48 class Reference; 49 class TypeConstructor; 50 class TypeConversion; 51 } // namespace sem 52 53 namespace writer { 54 namespace spirv { 55 56 /// The result of sanitizing a program for generation. 57 struct SanitizedResult { 58 /// The sanitized program. 59 Program program; 60 }; 61 62 /// Sanitize a program in preparation for generating SPIR-V. 63 /// @param emit_vertex_point_size `true` to emit a vertex point size builtin 64 /// @param disable_workgroup_init `true` to disable workgroup memory zero 65 /// @returns the sanitized program and any supplementary information 66 SanitizedResult Sanitize(const Program* program, 67 bool emit_vertex_point_size = false, 68 bool disable_workgroup_init = false); 69 70 /// Builder class to create SPIR-V instructions from a module. 71 class Builder { 72 public: 73 /// Contains information for generating accessor chains 74 struct AccessorInfo { 75 AccessorInfo(); 76 ~AccessorInfo(); 77 78 /// The ID of the current chain source. The chain source may change as we 79 /// evaluate the access chain. The chain source always points to the ID 80 /// which we will use to evaluate the current set of accessors. This maybe 81 /// the original variable, or maybe an intermediary if we had to evaulate 82 /// the access chain early (in the case of a swizzle of an access chain). 83 uint32_t source_id; 84 /// The type of the current chain source. This type matches the deduced 85 /// result_type of the current source defined above. 86 const sem::Type* source_type; 87 /// A list of access chain indices to emit. Note, we _only_ have access 88 /// chain indices if the source is reference. 89 std::vector<uint32_t> access_chain_indices; 90 }; 91 92 /// Constructor 93 /// @param program the program 94 explicit Builder(const Program* program); 95 ~Builder(); 96 97 /// Generates the SPIR-V instructions for the given program 98 /// @returns true if the SPIR-V was successfully built 99 bool Build(); 100 101 /// @returns the error string or blank if no error was reported. error()102 const std::string& error() const { return error_; } 103 /// @returns true if the builder encountered an error has_error()104 bool has_error() const { return !error_.empty(); } 105 106 /// @returns the number of uint32_t's needed to make up the results 107 uint32_t total_size() const; 108 109 /// @returns the id bound for this program id_bound()110 uint32_t id_bound() const { return next_id_; } 111 112 /// @returns the next id to be used next_id()113 uint32_t next_id() { 114 auto id = next_id_; 115 next_id_ += 1; 116 return id; 117 } 118 119 /// Iterates over all the instructions in the correct order and calls the 120 /// given callback 121 /// @param cb the callback to execute 122 void iterate(std::function<void(const Instruction&)> cb) const; 123 124 /// Adds an instruction to the list of capabilities, if the capability 125 /// hasn't already been added. 126 /// @param cap the capability to set 127 void push_capability(uint32_t cap); 128 /// @returns the capabilities capabilities()129 const InstructionList& capabilities() const { return capabilities_; } 130 /// Adds an instruction to the extensions 131 /// @param op the op to set 132 /// @param operands the operands for the instruction push_extension(spv::Op op,const OperandList & operands)133 void push_extension(spv::Op op, const OperandList& operands) { 134 extensions_.push_back(Instruction{op, operands}); 135 } 136 /// @returns the extensions extensions()137 const InstructionList& extensions() const { return extensions_; } 138 /// Adds an instruction to the ext import 139 /// @param op the op to set 140 /// @param operands the operands for the instruction push_ext_import(spv::Op op,const OperandList & operands)141 void push_ext_import(spv::Op op, const OperandList& operands) { 142 ext_imports_.push_back(Instruction{op, operands}); 143 } 144 /// @returns the ext imports ext_imports()145 const InstructionList& ext_imports() const { return ext_imports_; } 146 /// Adds an instruction to the memory model 147 /// @param op the op to set 148 /// @param operands the operands for the instruction push_memory_model(spv::Op op,const OperandList & operands)149 void push_memory_model(spv::Op op, const OperandList& operands) { 150 memory_model_.push_back(Instruction{op, operands}); 151 } 152 /// @returns the memory model memory_model()153 const InstructionList& memory_model() const { return memory_model_; } 154 /// Adds an instruction to the entry points 155 /// @param op the op to set 156 /// @param operands the operands for the instruction push_entry_point(spv::Op op,const OperandList & operands)157 void push_entry_point(spv::Op op, const OperandList& operands) { 158 entry_points_.push_back(Instruction{op, operands}); 159 } 160 /// @returns the entry points entry_points()161 const InstructionList& entry_points() const { return entry_points_; } 162 /// Adds an instruction to the execution modes 163 /// @param op the op to set 164 /// @param operands the operands for the instruction push_execution_mode(spv::Op op,const OperandList & operands)165 void push_execution_mode(spv::Op op, const OperandList& operands) { 166 execution_modes_.push_back(Instruction{op, operands}); 167 } 168 /// @returns the execution modes execution_modes()169 const InstructionList& execution_modes() const { return execution_modes_; } 170 /// Adds an instruction to the debug 171 /// @param op the op to set 172 /// @param operands the operands for the instruction push_debug(spv::Op op,const OperandList & operands)173 void push_debug(spv::Op op, const OperandList& operands) { 174 debug_.push_back(Instruction{op, operands}); 175 } 176 /// @returns the debug instructions debug()177 const InstructionList& debug() const { return debug_; } 178 /// Adds an instruction to the types 179 /// @param op the op to set 180 /// @param operands the operands for the instruction push_type(spv::Op op,const OperandList & operands)181 void push_type(spv::Op op, const OperandList& operands) { 182 types_.push_back(Instruction{op, operands}); 183 } 184 /// @returns the type instructions types()185 const InstructionList& types() const { return types_; } 186 /// Adds an instruction to the annotations 187 /// @param op the op to set 188 /// @param operands the operands for the instruction push_annot(spv::Op op,const OperandList & operands)189 void push_annot(spv::Op op, const OperandList& operands) { 190 annotations_.push_back(Instruction{op, operands}); 191 } 192 /// @returns the annotations annots()193 const InstructionList& annots() const { return annotations_; } 194 195 /// Adds a function to the builder 196 /// @param func the function to add push_function(const Function & func)197 void push_function(const Function& func) { 198 functions_.push_back(func); 199 current_label_id_ = func.label_id(); 200 } 201 /// @returns the functions functions()202 const std::vector<Function>& functions() const { return functions_; } 203 /// Pushes an instruction to the current function. If we're outside 204 /// a function then issue an internal error and return false. 205 /// @param op the operation 206 /// @param operands the operands 207 /// @returns true if we succeeded 208 bool push_function_inst(spv::Op op, const OperandList& operands); 209 /// Pushes a variable to the current function 210 /// @param operands the variable operands push_function_var(const OperandList & operands)211 void push_function_var(const OperandList& operands) { 212 if (functions_.empty()) { 213 TINT_ICE(Writer, builder_.Diagnostics()) 214 << "push_function_var() called without a function"; 215 } 216 functions_.back().push_var(operands); 217 } 218 219 /// Converts a storage class to a SPIR-V storage class. 220 /// @param klass the storage class to convert 221 /// @returns the SPIR-V storage class or SpvStorageClassMax on error. 222 SpvStorageClass ConvertStorageClass(ast::StorageClass klass) const; 223 /// Converts a builtin to a SPIR-V builtin and pushes a capability if needed. 224 /// @param builtin the builtin to convert 225 /// @param storage the storage class that this builtin is being used with 226 /// @returns the SPIR-V builtin or SpvBuiltInMax on error. 227 SpvBuiltIn ConvertBuiltin(ast::Builtin builtin, ast::StorageClass storage); 228 229 /// Converts an interpolate attribute to SPIR-V decorations and pushes a 230 /// capability if needed. 231 /// @param id the id to decorate 232 /// @param type the interpolation type 233 /// @param sampling the interpolation sampling 234 void AddInterpolationDecorations(uint32_t id, 235 ast::InterpolationType type, 236 ast::InterpolationSampling sampling); 237 238 /// Generates a label for the given id. Emits an error and returns false if 239 /// we're currently outside a function. 240 /// @param id the id to use for the label 241 /// @returns true on success. 242 bool GenerateLabel(uint32_t id); 243 /// Generates an assignment statement 244 /// @param assign the statement to generate 245 /// @returns true if the statement was successfully generated 246 bool GenerateAssignStatement(const ast::AssignmentStatement* assign); 247 /// Generates a block statement, wrapped in a push/pop scope 248 /// @param stmt the statement to generate 249 /// @returns true if the statement was successfully generated 250 bool GenerateBlockStatement(const ast::BlockStatement* stmt); 251 /// Generates a block statement 252 /// @param stmt the statement to generate 253 /// @returns true if the statement was successfully generated 254 bool GenerateBlockStatementWithoutScoping(const ast::BlockStatement* stmt); 255 /// Generates a break statement 256 /// @param stmt the statement to generate 257 /// @returns true if the statement was successfully generated 258 bool GenerateBreakStatement(const ast::BreakStatement* stmt); 259 /// Generates a continue statement 260 /// @param stmt the statement to generate 261 /// @returns true if the statement was successfully generated 262 bool GenerateContinueStatement(const ast::ContinueStatement* stmt); 263 /// Generates a discard statement 264 /// @param stmt the statement to generate 265 /// @returns true if the statement was successfully generated 266 bool GenerateDiscardStatement(const ast::DiscardStatement* stmt); 267 /// Generates an entry point instruction 268 /// @param func the function 269 /// @param id the id of the function 270 /// @returns true if the instruction was generated, false otherwise 271 bool GenerateEntryPoint(const ast::Function* func, uint32_t id); 272 /// Generates execution modes for an entry point 273 /// @param func the function 274 /// @param id the id of the function 275 /// @returns false on failure 276 bool GenerateExecutionModes(const ast::Function* func, uint32_t id); 277 /// Generates an expression 278 /// @param expr the expression to generate 279 /// @returns the resulting ID of the expression or 0 on error 280 uint32_t GenerateExpression(const ast::Expression* expr); 281 /// Generates the instructions for a function 282 /// @param func the function to generate 283 /// @returns true if the instructions were generated 284 bool GenerateFunction(const ast::Function* func); 285 /// Generates a function type if not already created 286 /// @param func the function to generate for 287 /// @returns the ID to use for the function type. Returns 0 on failure. 288 uint32_t GenerateFunctionTypeIfNeeded(const sem::Function* func); 289 /// Generates access control annotations if needed 290 /// @param type the type to generate for 291 /// @param struct_id the struct id 292 /// @param member_idx the member index 293 void GenerateMemberAccessIfNeeded(const sem::Type* type, 294 uint32_t struct_id, 295 uint32_t member_idx); 296 /// Generates a function variable 297 /// @param var the variable 298 /// @returns true if the variable was generated 299 bool GenerateFunctionVariable(const ast::Variable* var); 300 /// Generates a global variable 301 /// @param var the variable to generate 302 /// @returns true if the variable is emited. 303 bool GenerateGlobalVariable(const ast::Variable* var); 304 /// Generates an index accessor expression. 305 /// 306 /// For more information on accessors see the "Pointer evaluation" section of 307 /// the WGSL specification. 308 /// 309 /// @param expr the expresssion to generate 310 /// @returns the id of the expression or 0 on failure 311 uint32_t GenerateAccessorExpression(const ast::Expression* expr); 312 /// Generates an index accessor 313 /// @param expr the accessor to generate 314 /// @param info the current accessor information 315 /// @returns true if the accessor was generated successfully 316 bool GenerateIndexAccessor(const ast::IndexAccessorExpression* expr, 317 AccessorInfo* info); 318 /// Generates a member accessor 319 /// @param expr the accessor to generate 320 /// @param info the current accessor information 321 /// @returns true if the accessor was generated successfully 322 bool GenerateMemberAccessor(const ast::MemberAccessorExpression* expr, 323 AccessorInfo* info); 324 /// Generates an identifier expression 325 /// @param expr the expresssion to generate 326 /// @returns the id of the expression or 0 on failure 327 uint32_t GenerateIdentifierExpression(const ast::IdentifierExpression* expr); 328 /// Generates a unary op expression 329 /// @param expr the expression to generate 330 /// @returns the id of the expression or 0 on failure 331 uint32_t GenerateUnaryOpExpression(const ast::UnaryOpExpression* expr); 332 /// Generates an if statement 333 /// @param stmt the statement to generate 334 /// @returns true on success 335 bool GenerateIfStatement(const ast::IfStatement* stmt); 336 /// Generates an import instruction for the "GLSL.std.450" extended 337 /// instruction set, if one doesn't exist yet, and returns the import ID. 338 /// @returns the import ID, or 0 on error. 339 uint32_t GetGLSLstd450Import(); 340 /// Generates a constructor expression 341 /// @param var the variable generated for, nullptr if no variable associated. 342 /// @param expr the expression to generate 343 /// @returns the ID of the expression or 0 on failure. 344 uint32_t GenerateConstructorExpression(const ast::Variable* var, 345 const ast::Expression* expr); 346 /// Generates a literal constant if needed 347 /// @param var the variable generated for, nullptr if no variable associated. 348 /// @param lit the literal to generate 349 /// @returns the ID on success or 0 on failure 350 uint32_t GenerateLiteralIfNeeded(const ast::Variable* var, 351 const ast::LiteralExpression* lit); 352 /// Generates a binary expression 353 /// @param expr the expression to generate 354 /// @returns the expression ID on success or 0 otherwise 355 uint32_t GenerateBinaryExpression(const ast::BinaryExpression* expr); 356 /// Generates a bitcast expression 357 /// @param expr the expression to generate 358 /// @returns the expression ID on success or 0 otherwise 359 uint32_t GenerateBitcastExpression(const ast::BitcastExpression* expr); 360 /// Generates a short circuting binary expression 361 /// @param expr the expression to generate 362 /// @returns teh expression ID on success or 0 otherwise 363 uint32_t GenerateShortCircuitBinaryExpression( 364 const ast::BinaryExpression* expr); 365 /// Generates a call expression 366 /// @param expr the expression to generate 367 /// @returns the expression ID on success or 0 otherwise 368 uint32_t GenerateCallExpression(const ast::CallExpression* expr); 369 /// Handles generating a function call expression 370 /// @param call the call expression 371 /// @param function the function being called 372 /// @returns the expression ID on success or 0 otherwise 373 uint32_t GenerateFunctionCall(const sem::Call* call, 374 const sem::Function* function); 375 /// Handles generating an intrinsic call expression 376 /// @param call the call expression 377 /// @param intrinsic the intrinsic being called 378 /// @returns the expression ID on success or 0 otherwise 379 uint32_t GenerateIntrinsicCall(const sem::Call* call, 380 const sem::Intrinsic* intrinsic); 381 /// Handles generating a type constructor or type conversion expression 382 /// @param call the call expression 383 /// @param var the variable that is being initialized. May be null. 384 /// @returns the expression ID on success or 0 otherwise 385 uint32_t GenerateTypeConstructorOrConversion(const sem::Call* call, 386 const ast::Variable* var); 387 /// Generates a texture intrinsic call. Emits an error and returns false if 388 /// we're currently outside a function. 389 /// @param call the call expression 390 /// @param intrinsic the semantic information for the texture intrinsic 391 /// @param result_type result type operand of the texture instruction 392 /// @param result_id result identifier operand of the texture instruction 393 /// parameters 394 /// @returns true on success 395 bool GenerateTextureIntrinsic(const sem::Call* call, 396 const sem::Intrinsic* intrinsic, 397 spirv::Operand result_type, 398 spirv::Operand result_id); 399 /// Generates a control barrier statement. 400 /// @param intrinsic the semantic information for the barrier intrinsic call 401 /// @returns true on success 402 bool GenerateControlBarrierIntrinsic(const sem::Intrinsic* intrinsic); 403 /// Generates an atomic intrinsic call. 404 /// @param call the call expression 405 /// @param intrinsic the semantic information for the atomic intrinsic call 406 /// @param result_type result type operand of the texture instruction 407 /// @param result_id result identifier operand of the texture instruction 408 /// @returns true on success 409 bool GenerateAtomicIntrinsic(const sem::Call* call, 410 const sem::Intrinsic* intrinsic, 411 Operand result_type, 412 Operand result_id); 413 /// Generates a sampled image 414 /// @param texture_type the texture type 415 /// @param texture_operand the texture operand 416 /// @param sampler_operand the sampler operand 417 /// @returns the expression ID 418 uint32_t GenerateSampledImage(const sem::Type* texture_type, 419 Operand texture_operand, 420 Operand sampler_operand); 421 /// Generates a cast or object copy for the expression result, 422 /// or return the ID generated the expression if it is already 423 /// of the right type. 424 /// @param to_type the type we're casting too 425 /// @param from_expr the expression to cast 426 /// @param is_global_init if this is a global initializer 427 /// @returns the expression ID on success or 0 otherwise 428 uint32_t GenerateCastOrCopyOrPassthrough(const sem::Type* to_type, 429 const ast::Expression* from_expr, 430 bool is_global_init); 431 /// Generates a loop statement 432 /// @param stmt the statement to generate 433 /// @returns true on successful generation 434 bool GenerateLoopStatement(const ast::LoopStatement* stmt); 435 /// Generates a return statement 436 /// @param stmt the statement to generate 437 /// @returns true on success, false otherwise 438 bool GenerateReturnStatement(const ast::ReturnStatement* stmt); 439 /// Generates a switch statement 440 /// @param stmt the statement to generate 441 /// @returns ture on success, false otherwise 442 bool GenerateSwitchStatement(const ast::SwitchStatement* stmt); 443 /// Generates a conditional section merge block 444 /// @param cond the condition 445 /// @param true_body the statements making up the true block 446 /// @param cur_else_idx the index of the current else statement to process 447 /// @param else_stmts the list of all else statements 448 /// @returns true on success, false on failure 449 bool GenerateConditionalBlock(const ast::Expression* cond, 450 const ast::BlockStatement* true_body, 451 size_t cur_else_idx, 452 const ast::ElseStatementList& else_stmts); 453 /// Generates a statement 454 /// @param stmt the statement to generate 455 /// @returns true if the statement was generated 456 bool GenerateStatement(const ast::Statement* stmt); 457 /// Geneates an OpLoad 458 /// @param type the type to load 459 /// @param id the variable id to load 460 /// @returns the ID of the loaded value or `id` if type is not a reference 461 uint32_t GenerateLoadIfNeeded(const sem::Type* type, uint32_t id); 462 /// Generates an OpStore. Emits an error and returns false if we're 463 /// currently outside a function. 464 /// @param to the ID to store too 465 /// @param from the ID to store from 466 /// @returns true on success 467 bool GenerateStore(uint32_t to, uint32_t from); 468 /// Generates a type if not already created 469 /// @param type the type to create 470 /// @returns the ID to use for the given type. Returns 0 on unknown type. 471 uint32_t GenerateTypeIfNeeded(const sem::Type* type); 472 /// Generates a texture type declaration 473 /// @param texture the texture to generate 474 /// @param result the result operand 475 /// @returns true if the texture was successfully generated 476 bool GenerateTextureType(const sem::Texture* texture, const Operand& result); 477 /// Generates an array type declaration 478 /// @param ary the array to generate 479 /// @param result the result operand 480 /// @returns true if the array was successfully generated 481 bool GenerateArrayType(const sem::Array* ary, const Operand& result); 482 /// Generates a matrix type declaration 483 /// @param mat the matrix to generate 484 /// @param result the result operand 485 /// @returns true if the matrix was successfully generated 486 bool GenerateMatrixType(const sem::Matrix* mat, const Operand& result); 487 /// Generates a pointer type declaration 488 /// @param ptr the pointer type to generate 489 /// @param result the result operand 490 /// @returns true if the pointer was successfully generated 491 bool GeneratePointerType(const sem::Pointer* ptr, const Operand& result); 492 /// Generates a reference type declaration 493 /// @param ref the reference type to generate 494 /// @param result the result operand 495 /// @returns true if the reference was successfully generated 496 bool GenerateReferenceType(const sem::Reference* ref, const Operand& result); 497 /// Generates a vector type declaration 498 /// @param struct_type the vector to generate 499 /// @param result the result operand 500 /// @returns true if the vector was successfully generated 501 bool GenerateStructType(const sem::Struct* struct_type, 502 const Operand& result); 503 /// Generates a struct member 504 /// @param struct_id the id of the parent structure 505 /// @param idx the index of the member 506 /// @param member the member to generate 507 /// @returns the id of the struct member or 0 on error. 508 uint32_t GenerateStructMember(uint32_t struct_id, 509 uint32_t idx, 510 const sem::StructMember* member); 511 /// Generates a variable declaration statement 512 /// @param stmt the statement to generate 513 /// @returns true on successfull generation 514 bool GenerateVariableDeclStatement(const ast::VariableDeclStatement* stmt); 515 /// Generates a vector type declaration 516 /// @param vec the vector to generate 517 /// @param result the result operand 518 /// @returns true if the vector was successfully generated 519 bool GenerateVectorType(const sem::Vector* vec, const Operand& result); 520 521 /// Generates instructions to splat `scalar_id` into a vector of type 522 /// `vec_type` 523 /// @param scalar_id scalar to splat 524 /// @param vec_type type of vector 525 /// @returns id of the new vector 526 uint32_t GenerateSplat(uint32_t scalar_id, const sem::Type* vec_type); 527 528 /// Generates instructions to add or subtract two matrices 529 /// @param lhs_id id of multiplicand 530 /// @param rhs_id id of multiplier 531 /// @param type type of both matrices and of result 532 /// @param op one of `spv::Op::OpFAdd` or `spv::Op::OpFSub` 533 /// @returns id of the result matrix 534 uint32_t GenerateMatrixAddOrSub(uint32_t lhs_id, 535 uint32_t rhs_id, 536 const sem::Matrix* type, 537 spv::Op op); 538 539 /// Converts AST image format to SPIR-V and pushes an appropriate capability. 540 /// @param format AST image format type 541 /// @returns SPIR-V image format type 542 SpvImageFormat convert_image_format_to_spv(const ast::ImageFormat format); 543 544 /// Determines if the given type constructor is created from constant values 545 /// @param expr the expression to check 546 /// @returns true if the constructor is constant 547 bool IsConstructorConst(const ast::Expression* expr); 548 549 private: 550 /// @returns an Operand with a new result ID in it. Increments the next_id_ 551 /// automatically. 552 Operand result_op(); 553 554 /// @returns the resolved type of the ast::Expression `expr` 555 /// @param expr the expression TypeOf(const ast::Expression * expr)556 const sem::Type* TypeOf(const ast::Expression* expr) const { 557 return builder_.TypeOf(expr); 558 } 559 560 /// Generates a scalar constant if needed 561 /// @param constant the constant to generate. 562 /// @returns the ID on success or 0 on failure 563 uint32_t GenerateConstantIfNeeded(const ScalarConstant& constant); 564 565 /// Generates a constant-null of the given type, if needed 566 /// @param type the type of the constant null to generate. 567 /// @returns the ID on success or 0 on failure 568 uint32_t GenerateConstantNullIfNeeded(const sem::Type* type); 569 570 /// Generates a vector constant splat if needed 571 /// @param type the type of the vector to generate 572 /// @param value_id the ID of the scalar value to splat 573 /// @returns the ID on success or 0 on failure 574 uint32_t GenerateConstantVectorSplatIfNeeded(const sem::Vector* type, 575 uint32_t value_id); 576 577 ProgramBuilder builder_; 578 std::string error_; 579 uint32_t next_id_ = 1; 580 uint32_t current_label_id_ = 0; 581 InstructionList capabilities_; 582 InstructionList extensions_; 583 InstructionList ext_imports_; 584 InstructionList memory_model_; 585 InstructionList entry_points_; 586 InstructionList execution_modes_; 587 InstructionList debug_; 588 InstructionList types_; 589 InstructionList annotations_; 590 std::vector<Function> functions_; 591 592 std::unordered_map<std::string, uint32_t> import_name_to_id_; 593 std::unordered_map<Symbol, uint32_t> func_symbol_to_id_; 594 std::unordered_map<sem::CallTargetSignature, uint32_t> func_sig_to_id_; 595 std::unordered_map<std::string, uint32_t> type_name_to_id_; 596 std::unordered_map<ScalarConstant, uint32_t> const_to_id_; 597 std::unordered_map<std::string, uint32_t> type_constructor_to_id_; 598 std::unordered_map<std::string, uint32_t> const_null_to_id_; 599 std::unordered_map<uint64_t, uint32_t> const_splat_to_id_; 600 std::unordered_map<std::string, uint32_t> 601 texture_type_name_to_sampled_image_type_id_; 602 ScopeStack<uint32_t> scope_stack_; 603 std::unordered_map<uint32_t, const ast::Variable*> spirv_id_to_variable_; 604 std::vector<uint32_t> merge_stack_; 605 std::vector<uint32_t> continue_stack_; 606 std::unordered_set<uint32_t> capability_set_; 607 bool has_overridable_workgroup_size_ = false; 608 609 struct ContinuingInfo { 610 ContinuingInfo(const ast::Statement* last_statement, 611 uint32_t loop_header_id, 612 uint32_t break_target_id); 613 // The last statement in the continiung block. 614 const ast::Statement* const last_statement = nullptr; 615 // The ID of the loop header 616 const uint32_t loop_header_id = 0u; 617 // The ID of the merge block for the loop. 618 const uint32_t break_target_id = 0u; 619 }; 620 // Stack of nodes, where each is the last statement in a surrounding 621 // continuing block. 622 std::vector<ContinuingInfo> continuing_stack_; 623 624 // The instruction to emit as the backedge of a loop. 625 struct Backedge { 626 Backedge(spv::Op, OperandList); 627 Backedge(const Backedge&); 628 Backedge& operator=(const Backedge&); 629 ~Backedge(); 630 631 spv::Op opcode; 632 OperandList operands; 633 }; 634 std::vector<Backedge> backedge_stack_; 635 }; 636 637 } // namespace spirv 638 } // namespace writer 639 } // namespace tint 640 641 #endif // SRC_WRITER_SPIRV_BUILDER_H_ 642