1#!/usr/bin/env vpython3 2# 3# [VPYTHON:BEGIN] 4# wheel: < 5# name: "infra/python/wheels/perfect-hash-py2_py3" 6# version: "version:0.2.1" 7# > 8# [VPYTHON:END] 9# 10# Copyright 2018 The ANGLE Project Authors. All rights reserved. 11# Use of this source code is governed by a BSD-style license that can be 12# found in the LICENSE file. 13# 14# gen_builtin_symbols.py: 15# Code generation for the built-in symbol tables. 16import sys 17 18# Conditional import enables getting inputs/outputs with python3 instead of vpython3 19if len(sys.argv) < 2: 20 from perfect_hash import generate_hash, Hash2 21 22from collections import OrderedDict 23import argparse 24import copy 25import hashlib 26import json 27import re 28import os 29import random 30 31template_immutablestring_cpp = """// GENERATED FILE - DO NOT EDIT. 32// Generated by {script_name} using data from {variable_data_source_name} and 33// {function_data_source_name}. 34// 35// Copyright 2020 The ANGLE Project Authors. All rights reserved. 36// Use of this source code is governed by a BSD-style license that can be 37// found in the LICENSE file. 38// 39// ImmutableString_autogen.cpp: Wrapper for static or pool allocated char arrays, that are guaranteed to be 40// valid and unchanged for the duration of the compilation. 41// Implements mangledNameHash using perfect hash function from gen_builtin_symbols.py 42 43#include "compiler/translator/ImmutableString.h" 44 45namespace sh {{ 46 47std::ostream &operator<<(std::ostream &os, const ImmutableString &str) 48{{ 49 return os.write(str.data(), str.length()); 50}} 51 52}} 53 54#if defined(_MSC_VER) 55# pragma warning(disable : 4309) // truncation of constant value 56#endif 57 58 59namespace 60{{ 61 62constexpr int mangledkT1[] = {{{mangled_S1}}}; 63constexpr int mangledkT2[] = {{{mangled_S2}}}; 64constexpr int mangledkG[] = {{{mangled_G}}}; 65 66int MangledHashG(const char *key, const int *T) 67{{ 68 int sum = 0; 69 70 for (int i = 0; key[i] != '\\0'; i++) 71 {{ 72 sum += T[i] * key[i]; 73 sum %= {mangled_NG}; 74 }} 75 return mangledkG[sum]; 76}} 77 78int MangledPerfectHash(const char *key) 79{{ 80 if (strlen(key) > {mangled_NS}) 81 return 0; 82 83 return (MangledHashG(key, mangledkT1) + MangledHashG(key, mangledkT2)) % {mangled_NG}; 84}} 85 86constexpr int unmangledkT1[] = {{{unmangled_S1}}}; 87constexpr int unmangledkT2[] = {{{unmangled_S2}}}; 88constexpr int unmangledkG[] = {{{unmangled_G}}}; 89 90int UnmangledHashG(const char *key, const int *T) 91{{ 92 int sum = 0; 93 94 for (int i = 0; key[i] != '\\0'; i++) 95 {{ 96 sum += T[i] * key[i]; 97 sum %= {unmangled_NG}; 98 }} 99 return unmangledkG[sum]; 100}} 101 102int UnmangledPerfectHash(const char *key) 103{{ 104 if (strlen(key) > {unmangled_NS}) 105 return 0; 106 107 return (UnmangledHashG(key, unmangledkT1) + UnmangledHashG(key, unmangledkT2)) % {unmangled_NG}; 108}} 109 110}} 111 112namespace sh 113{{ 114 115template <> 116const size_t ImmutableString::FowlerNollVoHash<4>::kFnvPrime = 16777619u; 117 118template <> 119const size_t ImmutableString::FowlerNollVoHash<4>::kFnvOffsetBasis = 0x811c9dc5u; 120 121template <> 122const size_t ImmutableString::FowlerNollVoHash<8>::kFnvPrime = 123 static_cast<size_t>(1099511628211ull); 124 125template <> 126const size_t ImmutableString::FowlerNollVoHash<8>::kFnvOffsetBasis = 127 static_cast<size_t>(0xcbf29ce484222325ull); 128 129uint32_t ImmutableString::mangledNameHash() const 130{{ 131 return MangledPerfectHash(data()); 132}} 133 134uint32_t ImmutableString::unmangledNameHash() const 135{{ 136 return UnmangledPerfectHash(data()); 137}} 138 139}} // namespace sh 140""" 141 142template_immutablestringtest_cpp = """// GENERATED FILE - DO NOT EDIT. 143// Generated by {script_name} using data from {function_data_source_name}. 144// 145// Copyright 2020 The ANGLE Project Authors. All rights reserved. 146// Use of this source code is governed by a BSD-style license that can be 147// found in the LICENSE file. 148// 149// ImmutableString_test_autogen.cpp: 150// Tests for matching script-generated hashes with runtime computed hashes. 151 152#include "compiler/translator/ImmutableString.h" 153#include "gtest/gtest.h" 154 155namespace sh 156{{ 157 158TEST(ImmutableStringTest, ScriptGeneratedHashesMatch) 159{{ 160{script_generated_hash_tests} 161{unmangled_script_generated_hash_tests} 162}} 163 164}} // namespace sh 165""" 166 167# The header file has a "get" function for each variable. They are used in traversers. 168# It also declares id values of built-ins with human readable names, so they can be used to identify built-ins. 169template_builtin_header = """// GENERATED FILE - DO NOT EDIT. 170// Generated by {script_name} using data from {variable_data_source_name} and 171// {function_data_source_name}. 172// 173// Copyright 2020 The ANGLE Project Authors. All rights reserved. 174// Use of this source code is governed by a BSD-style license that can be 175// found in the LICENSE file. 176// 177// BuiltIn_autogen.h: 178// Compile-time initialized built-ins. 179 180#ifndef COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_ 181#define COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_ 182 183#include "compiler/translator/SymbolUniqueId.h" 184 185namespace sh 186{{ 187 188class TVariable; 189 190class BuiltInId 191{{ 192public: 193 194{builtin_id_declarations} 195 196}}; // class BuiltInId 197 198namespace BuiltInVariable 199{{ 200 201{get_variable_declarations} 202 203}} // namespace BuiltInVariable 204 205}} // namespace sh 206 207#endif // COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_ 208""" 209 210template_symboltable_header = """// GENERATED FILE - DO NOT EDIT. 211// Generated by {script_name} using data from {variable_data_source_name} and 212// {function_data_source_name}. 213// 214// Copyright 2020 The ANGLE Project Authors. All rights reserved. 215// Use of this source code is governed by a BSD-style license that can be 216// found in the LICENSE file. 217// 218// SymbolTable_autogen.h: 219// Autogenerated member variables of TSymbolTable. 220 221#ifndef COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_ 222#define COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_ 223 224namespace sh 225{{ 226 227class TSymbolTableBase 228{{ 229 public: 230 TSymbolTableBase() = default; 231{declare_member_variables} 232}}; 233 234}} // namespace sh 235 236#endif // COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_ 237""" 238 239# By having the variables defined in a cpp file we ensure that there's just one instance of each of the declared variables. 240template_symboltable_cpp = """// GENERATED FILE - DO NOT EDIT. 241// Generated by {script_name} using data from {variable_data_source_name} and 242// {function_data_source_name}. 243// 244// Copyright 2020 The ANGLE Project Authors. All rights reserved. 245// Use of this source code is governed by a BSD-style license that can be 246// found in the LICENSE file. 247// 248// SymbolTable_autogen.cpp: 249// Compile-time initialized built-ins. 250 251#include "compiler/translator/SymbolTable.h" 252 253#include "angle_gl.h" 254#include "compiler/translator/tree_util/BuiltIn.h" 255#include "compiler/translator/ImmutableString.h" 256#include "compiler/translator/StaticType.h" 257#include "compiler/translator/Symbol.h" 258#include "compiler/translator/SymbolTable.h" 259 260namespace sh 261{{ 262using Resources = ShBuiltInResources; 263using TableBase = TSymbolTableBase; 264 265struct SymbolIdChecker 266{{ 267 static_assert(TSymbolTable::kFirstUserDefinedSymbolId > {last_builtin_id}); 268}}; 269 270namespace BuiltInName 271{{ 272 273constexpr const ImmutableString _empty(""); 274{name_declarations} 275 276}} // namespace BuiltInName 277 278// TODO(oetuaho): Would be nice to make this a class instead of a namespace so that we could friend 279// this from TVariable. Now symbol constructors taking an id have to be public even though they're 280// not supposed to be accessible from outside of here. http://anglebug.com/42261100 281namespace BuiltInVariable 282{{ 283 284{type_array_sizes_declarations} 285 286{variable_declarations} 287 288{get_variable_definitions} 289 290}} // namespace BuiltInVariable 291 292namespace BuiltInParameters 293{{ 294 295{parameter_declarations} 296 297}} // namespace BuiltInParameters 298 299// TODO(oetuaho): Would be nice to make this a class instead of a namespace so that we could friend 300// this from TFunction. Now symbol constructors taking an id have to be public even though they're 301// not supposed to be accessible from outside of here. http://anglebug.com/42261100 302namespace Func 303{{ 304 305{function_declarations} 306 307}} // namespace Func 308 309namespace BuiltInArray 310{{ 311using namespace Func; 312using Rule = SymbolRule; 313 314// Rules used to initialize the mangled name array. 315constexpr SymbolRule kRules[] = {{ 316{mangled_rules} 317}}; 318 319// Flat array of all mangled names. 320constexpr const char *kMangledNames[] = {{ 321{mangled_names_array} 322}}; 323 324// Flat array of offsets from a symbol into the rules table. 325constexpr uint16_t kMangledOffsets[] = {{ 326{mangled_offsets_array} 327}}; 328 329using Ext = TExtension; 330 331// Flat array of all unmangled name identifiers. 332constexpr UnmangledEntry unmangled[] = {{ 333{unmangled_array} 334}}; 335 336}} 337 338void TSymbolTable::initializeBuiltInVariables(sh::GLenum shaderType, 339 ShShaderSpec spec, 340 const ShBuiltInResources &resources) 341{{ 342 const TSourceLoc zeroSourceLoc = {{0, 0, 0, 0}}; 343{init_member_variables} 344}} 345 346namespace 347{{ 348uint16_t GetNextRuleIndex(uint32_t nameHash) 349{{ 350 if (nameHash == {num_mangled_names} - 1) 351 return ArraySize(BuiltInArray::kRules); 352 return BuiltInArray::kMangledOffsets[nameHash + 1]; 353}} 354}} // namespace 355 356const TSymbol *TSymbolTable::findBuiltIn(const ImmutableString &name, 357 int shaderVersion) const 358{{ 359 if (name.length() > {max_mangled_name_length}) 360 return nullptr; 361 362 uint32_t nameHash = name.mangledNameHash(); 363 if (nameHash >= {num_mangled_names}) 364 return nullptr; 365 366 const char *actualName = BuiltInArray::kMangledNames[nameHash]; 367 if (name != actualName) 368 return nullptr; 369 370 uint16_t startIndex = BuiltInArray::kMangledOffsets[nameHash]; 371 uint16_t nextIndex = GetNextRuleIndex(nameHash); 372 373 return FindMangledBuiltIn(mShaderSpec, shaderVersion, mShaderType, mResources, *this, BuiltInArray::kRules, startIndex, nextIndex); 374}} 375 376bool TSymbolTable::isUnmangledBuiltInName(const ImmutableString &name, 377 int shaderVersion, 378 const TExtensionBehavior &extensions) const 379{{ 380 if (name.length() > {max_unmangled_name_length}) 381 return false; 382 383 uint32_t nameHash = name.unmangledNameHash(); 384 if (nameHash >= {num_unmangled_names}) 385 return false; 386 387 return BuiltInArray::unmangled[nameHash].matches(name, mShaderSpec, shaderVersion, mShaderType, extensions); 388}} 389 390}} // namespace sh 391""" 392 393template_operator_header = """// GENERATED FILE - DO NOT EDIT. 394// Generated by {script_name} using data from {function_data_source_name}. 395// 396// Copyright 2021 The ANGLE Project Authors. All rights reserved. 397// Use of this source code is governed by a BSD-style license that can be 398// found in the LICENSE file. 399// 400// Operator_autogen.h: 401// Operators used by the high-level (parse tree) representation. 402 403#ifndef COMPILER_TRANSLATOR_OPERATOR_AUTOGEN_H_ 404#define COMPILER_TRANSLATOR_OPERATOR_AUTOGEN_H_ 405 406#include <stdint.h> 407 408namespace sh 409{{ 410 411enum TOperator : uint16_t 412{{ 413 EOpNull, // if in a node, should only mean a node is still being built 414 415 // Call a function defined in the AST. This might be a user-defined function or a function 416 // inserted by an AST transformation. 417 EOpCallFunctionInAST, 418 419 // Call an internal helper function with a raw implementation - the implementation can't be 420 // subject to AST transformations. Raw functions have a few constraints to keep them compatible 421 // with AST traversers: 422 // * They should not return arrays. 423 // * They should not have out parameters. 424 // 425 // DEPRECATED; DO NOT USE. TODO: remove this. http://anglebug.com/42264589 426 // 427 EOpCallInternalRawFunction, 428 429 // 430 // Branch (TIntermBranch) 431 // 432 433 EOpKill, // Fragment only 434 EOpReturn, 435 EOpBreak, 436 EOpContinue, 437 438 // 439 // Constructor (TIntermAggregate) 440 // 441 442 EOpConstruct, 443 444 // 445 // Unary operators with special GLSL syntax (TIntermUnary). 446 // 447 448 EOpNegative, 449 EOpPositive, 450 EOpLogicalNot, 451 EOpBitwiseNot, 452 453 EOpPostIncrement, 454 EOpPostDecrement, 455 EOpPreIncrement, 456 EOpPreDecrement, 457 458 EOpArrayLength, 459 460 // 461 // Binary operators with special GLSL syntax (TIntermBinary). 462 // 463 464 EOpAdd, 465 EOpSub, 466 EOpMul, 467 EOpDiv, 468 EOpIMod, 469 470 EOpEqual, 471 EOpNotEqual, 472 EOpLessThan, 473 EOpGreaterThan, 474 EOpLessThanEqual, 475 EOpGreaterThanEqual, 476 477 EOpComma, 478 479 EOpVectorTimesScalar, 480 EOpVectorTimesMatrix, 481 EOpMatrixTimesVector, 482 EOpMatrixTimesScalar, 483 EOpMatrixTimesMatrix, 484 485 EOpLogicalOr, 486 EOpLogicalXor, 487 EOpLogicalAnd, 488 489 EOpBitShiftLeft, 490 EOpBitShiftRight, 491 492 EOpBitwiseAnd, 493 EOpBitwiseXor, 494 EOpBitwiseOr, 495 496 EOpIndexDirect, 497 EOpIndexIndirect, 498 EOpIndexDirectStruct, 499 EOpIndexDirectInterfaceBlock, 500 501 // 502 // Moves (TIntermBinary) 503 // 504 505 EOpAssign, 506 EOpInitialize, 507 EOpAddAssign, 508 EOpSubAssign, 509 510 EOpMulAssign, 511 EOpVectorTimesMatrixAssign, 512 EOpVectorTimesScalarAssign, 513 EOpMatrixTimesScalarAssign, 514 EOpMatrixTimesMatrixAssign, 515 516 EOpDivAssign, 517 EOpIModAssign, 518 EOpBitShiftLeftAssign, 519 EOpBitShiftRightAssign, 520 EOpBitwiseAndAssign, 521 EOpBitwiseXorAssign, 522 EOpBitwiseOrAssign, 523 524 // Not an op, but a marker for the start of built-in ops. 525 EOpLastNonBuiltIn = EOpBitwiseOrAssign, 526 527 // 528 // Built-in functions mapped to operators (either unary (TIntermUnary) or with multiple 529 // parameters (TIntermAggregate)) 530 // 531 {operator_enum_declarations} 532}}; 533 534// Returns the string corresponding to the operator in GLSL. For built-in functions use the 535// function name directly. 536const char *GetOperatorString(TOperator op); 537 538// Say whether or not a binary or unary operation changes the value of a variable. 539bool IsAssignment(TOperator op); 540 541namespace BuiltInGroup 542{{ 543static inline bool IsBuiltIn(TOperator op) 544{{ 545 return op > EOpLastNonBuiltIn; 546}} 547{is_in_group_definitions} 548}} // namespace BuiltInGroup 549 550}} // namespace sh 551 552#endif // COMPILER_TRANSLATOR_OPERATOR_AUTOGEN_H_ 553 554""" 555 556template_rule = """Rule::Get<{version}, {shaders}, {extension}>({symbol_or_var})""" 557 558basic_types_enumeration = [ 559 'Void', 560 'Float', 561 'Int', 562 'UInt', 563 'Bool', 564 'AtomicCounter', 565 'YuvCscStandardEXT', 566 'Sampler2D', 567 'Sampler3D', 568 'SamplerCube', 569 'Sampler2DArray', 570 'SamplerExternalOES', 571 'SamplerExternal2DY2YEXT', 572 'Sampler2DRect', 573 'Sampler2DMS', 574 'Sampler2DMSArray', 575 'ISampler2D', 576 'ISampler3D', 577 'ISamplerCube', 578 'ISampler2DArray', 579 'ISampler2DMS', 580 'ISampler2DMSArray', 581 'USampler2D', 582 'USampler3D', 583 'USamplerCube', 584 'USampler2DArray', 585 'USampler2DMS', 586 'USampler2DMSArray', 587 'Sampler2DShadow', 588 'SamplerCubeShadow', 589 'Sampler2DArrayShadow', 590 'SamplerBuffer', 591 'SamplerCubeArray', 592 'SamplerCubeArrayShadow', 593 'Sampler2DRectShadow', 594 'ISampler2DRect', 595 'ISamplerBuffer', 596 'ISamplerCubeArray', 597 'USampler2DRect', 598 'USamplerBuffer', 599 'USamplerCubeArray', 600 'SamplerVideoWEBGL', 601 'Image2D', 602 'Image3D', 603 'Image2DArray', 604 'ImageCube', 605 'Image2DMS', 606 'Image2DMSArray', 607 'ImageCubeArray', 608 'ImageRect', 609 'ImageBuffer', 610 'IImage2D', 611 'IImage3D', 612 'IImage2DArray', 613 'IImageCube', 614 'IImage2DMS', 615 'IImage2DMSArray', 616 'IImageCubeArray', 617 'IImageRect', 618 'IImageBuffer', 619 'UImage2D', 620 'UImage3D', 621 'UImage2DArray', 622 'UImageCube', 623 'UImage2DMS', 624 'UImage2DMSArray', 625 'UImageCubeArray', 626 'UImageRect', 627 'UImageBuffer', 628 'PixelLocalANGLE', 629 'IPixelLocalANGLE', 630 'UPixelLocalANGLE', 631 'SubpassInput', 632 'ISubpassInput', 633 'USubpassInput', 634] 635 636id_counter = 0 637 638 639def set_working_dir(): 640 script_dir = os.path.dirname(os.path.abspath(__file__)) 641 os.chdir(script_dir) 642 643 644def get_basic_mangled_name(basic): 645 index = basic_types_enumeration.index(basic) 646 if index < 26: 647 return '0' + chr(ord('A') + index) 648 if index < 52: 649 return '0' + chr(ord('a') + index - 26) 650 if index < 78: 651 return '1' + chr(ord('A') + index - 52) 652 return '1' + chr(ord('a') + index - 78) 653 654 655essl_levels = [ 656 'ESSL3_2_BUILTINS', 'ESSL3_1_BUILTINS', 'ESSL3_BUILTINS', 'ESSL1_BUILTINS', 'COMMON_BUILTINS', 657 'ESSL_INTERNAL_BACKEND_BUILTINS' 658] 659 660 661def generate_suffix_from_level(level): 662 assert (level[:4] == 'ESSL') 663 assert (level[-9:] == '_BUILTINS') 664 665 # Turn XYSLN_M_BUILTINS to XYN_M 666 return level[:2] + level[4:-9] 667 668 669def get_essl_shader_version_for_level(level): 670 if level == None: 671 return '-1' 672 elif level == 'ESSL_INTERNAL_BACKEND_BUILTINS': 673 return 'kESSLInternalBackendBuiltIns' 674 elif level == 'ESSL3_2_BUILTINS': 675 return '320' 676 elif level == 'ESSL3_1_BUILTINS': 677 return '310' 678 elif level == 'ESSL3_BUILTINS': 679 return '300' 680 elif level == 'ESSL1_BUILTINS': 681 return '100' 682 elif level == 'COMMON_BUILTINS': 683 return '0' 684 else: 685 raise Exception('Unsupported symbol table level') 686 687 688def get_shader_version_for_level(level): 689 return get_essl_shader_version_for_level(level) 690 691 692def get_extension_list(extensions): 693 extension_list = [ext.strip() for ext in extensions.split(',')] 694 extension_string = ', '.join(['TExtension::' + ext for ext in extension_list]) 695 return 'std::array<TExtension, ' + str(len(extension_list)) + 'u>{{' + extension_string + '}}' 696 697 698class GroupedList: 699 """"Class for storing a list of objects grouped by symbol table level and condition.""" 700 701 def __init__(self, hashfn, num_names): 702 self.objs = OrderedDict() 703 self.max_name_length = 0 704 self.hashfn = hashfn 705 self.num_names = num_names 706 self.rule_offset = 0 707 708 def add_entry(self, essl_level, shader_type, name, symbol, essl_extension, 709 script_generated_hash_tests): 710 if essl_level not in essl_levels: 711 raise Exception('Unexpected essl level: ' + str(essl_level)) 712 if len(name) > self.max_name_length: 713 self.max_name_length = len(name) 714 715 name_hash = mangledNameHash(name, self.hashfn, script_generated_hash_tests, False) 716 if name_hash not in self.objs: 717 self.objs[name_hash] = OrderedDict() 718 719 self.objs[name_hash]['name'] = name 720 721 if essl_extension == 'UNDEFINED': 722 if 'symbol' in self.objs[name_hash] and self.objs[name_hash]['symbol'] != symbol: 723 # Adding a variable that is part of two ESSL extensions that have become core 724 if 'symbol2' not in self.objs[name_hash]: 725 self.objs[name_hash]['essl_level2'] = essl_level 726 self.objs[name_hash]['symbol2'] = symbol 727 self.objs[name_hash]['shader_type2'] = shader_type 728 elif 'symbol3' not in self.objs[name_hash]: 729 self.objs[name_hash]['essl_level3'] = essl_level 730 self.objs[name_hash]['symbol3'] = symbol 731 self.objs[name_hash]['shader_type3'] = shader_type 732 elif 'symbol4' not in self.objs[name_hash]: 733 self.objs[name_hash]['essl_level4'] = essl_level 734 self.objs[name_hash]['symbol4'] = symbol 735 self.objs[name_hash]['shader_type4'] = shader_type 736 else: 737 assert (False) 738 else: 739 self.objs[name_hash]['essl_level'] = essl_level 740 self.objs[name_hash]['symbol'] = symbol 741 self.objs[name_hash]['shader_type'] = shader_type 742 743 if essl_extension != 'UNDEFINED': 744 if ('essl_ext_symbol' in self.objs[name_hash] and 745 self.objs[name_hash]['essl_ext_symbol'] != symbol): 746 # Adding a variable that is part of two ESSL extensions 747 if 'essl_ext_symbol2' not in self.objs[name_hash]: 748 self.objs[name_hash]['essl_extension2'] = essl_extension 749 self.objs[name_hash]['essl_ext_level2'] = essl_level 750 self.objs[name_hash]['essl_ext_symbol2'] = symbol 751 self.objs[name_hash]['essl_ext_shader_type2'] = shader_type 752 elif 'essl_ext_symbol3' not in self.objs[name_hash]: 753 self.objs[name_hash]['essl_extension3'] = essl_extension 754 self.objs[name_hash]['essl_ext_level3'] = essl_level 755 self.objs[name_hash]['essl_ext_symbol3'] = symbol 756 self.objs[name_hash]['essl_ext_shader_type3'] = shader_type 757 elif 'essl_ext_symbol4' not in self.objs[name_hash]: 758 self.objs[name_hash]['essl_extension4'] = essl_extension 759 self.objs[name_hash]['essl_ext_level4'] = essl_level 760 self.objs[name_hash]['essl_ext_symbol4'] = symbol 761 self.objs[name_hash]['essl_ext_shader_type4'] = shader_type 762 else: 763 assert (False) 764 else: 765 self.objs[name_hash]['essl_extension'] = essl_extension 766 self.objs[name_hash]['essl_ext_level'] = essl_level 767 self.objs[name_hash]['essl_ext_symbol'] = symbol 768 self.objs[name_hash]['essl_ext_shader_type'] = shader_type 769 770 def get_max_name_length(self): 771 return self.max_name_length 772 773 def format_rule(self, rule): 774 return template_rule.format(**rule) 775 776 def format_rules(self, rules): 777 return ", ".join([self.format_rule(rule) for rule in rules]) 778 779 def get_rules(self): 780 return self.rules 781 782 def get_names(self): 783 return self.names 784 785 def get_offsets(self): 786 return self.offsets 787 788 def update_arrays(self): 789 790 def add_rule(rules, level, shaders, extension, symbol): 791 var = ("&TableBase::%s" % symbol) if symbol.startswith("m_gl") else None 792 793 extension_list = [] 794 versionField = get_shader_version_for_level(level) 795 shadersField = "Shader::%s" % ("ALL" if shaders == "NONE" else shaders) 796 symbolOrVarField = symbol.replace("Func::", "") if var is None else var 797 if extension != None: 798 extension_list = [ext.strip() for ext in extension.split(',')] 799 for ext in extension_list: 800 rules.append({ 801 "version": versionField, 802 "shaders": shadersField, 803 "extension": "0" if ext == None else "EXT_INDEX(%s)" % ext, 804 "symbol_or_var": symbolOrVarField 805 }) 806 else: 807 rules.append({ 808 "version": versionField, 809 "shaders": shadersField, 810 "extension": "0", 811 "symbol_or_var": symbolOrVarField 812 }) 813 814 self.names = [] 815 self.offsets = [] 816 self.rules = [] 817 for hash_val in range(0, self.num_names): 818 if hash_val in self.objs: 819 data = self.objs[hash_val] 820 821 rules = [] 822 823 if "symbol" in data and "essl_level" in data: 824 add_rule(rules, data['essl_level'], data['shader_type'], None, data["symbol"]) 825 826 if "symbol2" in data and "essl_level2" in data: 827 add_rule(rules, data['essl_level2'], data['shader_type2'], None, 828 data["symbol2"]) 829 830 if "symbol3" in data and "essl_level3" in data: 831 add_rule(rules, data['essl_level3'], data['shader_type3'], None, 832 data["symbol3"]) 833 834 if "symbol4" in data and "essl_level4" in data: 835 add_rule(rules, data['essl_level4'], data['shader_type4'], None, 836 data["symbol4"]) 837 838 if "essl_ext_symbol" in data: 839 add_rule(rules, data["essl_ext_level"], data["essl_ext_shader_type"], 840 data["essl_extension"], data["essl_ext_symbol"]) 841 842 if "essl_ext_symbol2" in data: 843 add_rule(rules, data["essl_ext_level2"], data["essl_ext_shader_type2"], 844 data["essl_extension2"], data["essl_ext_symbol2"]) 845 846 if "essl_ext_symbol3" in data: 847 add_rule(rules, data["essl_ext_level3"], data["essl_ext_shader_type3"], 848 data["essl_extension3"], data["essl_ext_symbol3"]) 849 850 if "essl_ext_symbol4" in data: 851 add_rule(rules, data["essl_ext_level4"], data["essl_ext_shader_type4"], 852 data["essl_extension4"], data["essl_ext_symbol4"]) 853 854 name = data['name'] 855 name_underscore = name.replace("(", "_") 856 857 self.names.append('"%s"' % name) 858 self.offsets.append("%d, // %s" % (self.rule_offset, name_underscore)) 859 self.rules.append("%s" % self.format_rules(rules)) 860 861 self.rule_offset += len(rules) 862 863 else: 864 self.names.append('""') 865 self.offsets.append('%d, // Empty' % self.rule_offset) 866 867 868class UnmangledGroupedList: 869 """"Class for storing a list of unmangled objects grouped by symbol table level and condition.""" 870 871 def __init__(self, hashfn, num_names): 872 self.objs = OrderedDict() 873 self.max_name_length = 0 874 self.hashfn = hashfn 875 self.num_names = num_names 876 877 def add_entry(self, essl_level, shader_type, name, essl_ext, essl_extension, 878 unmangled_script_generated_hash_tests): 879 if essl_level not in essl_levels: 880 raise Exception('Unexpected essl level: ' + str(essl_level)) 881 if len(name) > self.max_name_length: 882 self.max_name_length = len(name) 883 884 name_hash = mangledNameHash(name, self.hashfn, unmangled_script_generated_hash_tests, True) 885 self.objs[name_hash] = OrderedDict() 886 self.objs[name_hash]['name'] = name 887 self.objs[name_hash]['essl_level'] = essl_level 888 self.objs[name_hash]['shader_type'] = shader_type 889 self.objs[name_hash]['essl_ext'] = essl_ext 890 self.objs[name_hash]['essl_extension'] = essl_extension 891 892 def has_key(self, essl_level, shader_type, name): 893 name_hash = mangledNameHash(name, self.hashfn, None, True, False) 894 if name_hash not in self.objs: 895 return False 896 entry = self.objs[name_hash] 897 if entry['essl_level'] != essl_level: 898 return False 899 if entry['shader_type'] != shader_type: 900 return False 901 return True 902 903 def get(self, essl_level, shader_type, name): 904 if self.has_key(essl_level, shader_type, name): 905 name_hash = mangledNameHash(name, self.hashfn, None, True, False) 906 return self.objs[name_hash] 907 return None 908 909 def get_max_name_length(self): 910 return self.max_name_length 911 912 def get_array(self): 913 code = [] 914 for hash_val in range(0, self.num_names): 915 obj = self.objs[hash_val] 916 essl_level = obj['essl_level'] 917 shader_type = 'Shader::' + obj['shader_type'] if obj[ 918 'shader_type'] != 'NONE' else 'Shader::ALL' 919 data = [] 920 data.append('"{name}"'.format(name=obj['name'])) 921 essl_extensions = [ext.strip() for ext in obj['essl_extension'].split(',')] 922 template_extensions = 'std::array<TExtension, {count}>{{{{{extensions}}}}}' 923 data.append( 924 template_extensions.format( 925 count=len(essl_extensions), 926 extensions=','.join(['Ext::' + ext for ext in essl_extensions]))) 927 data.append(get_essl_shader_version_for_level(essl_level)) 928 data.append(shader_type) 929 930 code.append('{%s}' % ', '.join(data)) 931 return code 932 933 934class TType: 935 936 def __init__(self, glsl_header_type): 937 if isinstance(glsl_header_type, str): 938 self.data = self.parse_type(glsl_header_type) 939 else: 940 self.data = glsl_header_type 941 self.normalize() 942 943 def normalize(self): 944 # Note that this will set primarySize and secondarySize also on genTypes. In that case they 945 # are overridden when the specific types are generated. 946 if 'primarySize' not in self.data: 947 if ('secondarySize' in self.data): 948 raise Exception( 949 'Unexpected secondarySize on type that does not have primarySize set') 950 self.data['primarySize'] = 1 951 if 'secondarySize' not in self.data: 952 self.data['secondarySize'] = 1 953 if 'precision' not in self.data: 954 self.data['precision'] = 'Undefined' 955 if 'qualifier' not in self.data: 956 self.data['qualifier'] = 'Global' 957 958 def has_array_size(self): 959 return 'arraySize' in self.data 960 961 def get_statictype_string(self): 962 template_type = 'StaticType::Get<Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}>()' 963 if self.has_array_size(): 964 template_type = 'StaticType::GetArray<Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}, kArraySize{arraySize}, 1>()' 965 return template_type.format(**self.data) 966 967 def get_dynamic_type_string(self): 968 template_type = 'new TType(Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}' 969 if self.has_array_size(): 970 template_type += ', TVector<unsigned int>{{{arraySize}}}' 971 template_type += ')' 972 return template_type.format(**self.data) 973 974 def get_mangled_name(self): 975 mangled_name = '' 976 977 size_key = (self.data['secondarySize'] - 1) * 4 + self.data['primarySize'] - 1 978 if size_key < 10: 979 mangled_name += chr(ord('0') + size_key) 980 else: 981 mangled_name += chr(ord('A') + size_key - 10) 982 mangled_name += get_basic_mangled_name(self.data['basic']) 983 if self.has_array_size(): 984 mangled_name += 'x' + str(self.data['arraySize']) 985 return mangled_name 986 987 def get_human_readable_name(self): 988 name = self.data['basic'] 989 if self.has_array_size(): 990 name = str(self.data['arraySize']) + 'x' + name 991 name += str(self.data['primarySize']) 992 if self.data['secondarySize'] > 1: 993 name += 'x' + str(self.data['secondarySize']) 994 return name 995 996 def is_vector(self): 997 return self.data['primarySize'] > 1 and self.data['secondarySize'] == 1 998 999 def is_matrix(self): 1000 return self.data['secondarySize'] > 1 1001 1002 def get_object_size(self): 1003 return self.data['primarySize'] * self.data['secondarySize'] 1004 1005 def specific_sampler_or_image_or_subpass_type(self, basic_type_prefix): 1006 if 'genType' in self.data and self.data['genType'] == 'sampler_or_image_or_subpass': 1007 type = {} 1008 if 'basic' not in self.data: 1009 type['basic'] = {'': 'Float', 'I': 'Int', 'U': 'UInt'}[basic_type_prefix] 1010 type['primarySize'] = self.data['primarySize'] 1011 else: 1012 type['basic'] = basic_type_prefix + self.data['basic'] 1013 type['primarySize'] = 1 1014 type['precision'] = 'Undefined' 1015 return TType(type) 1016 return self 1017 1018 def specific_type(self, vec_size): 1019 type = {} 1020 if 'genType' in self.data: 1021 type['basic'] = self.data['basic'] 1022 type['precision'] = self.data['precision'] 1023 type['qualifier'] = self.data['qualifier'] 1024 type['primarySize'] = vec_size 1025 type['secondarySize'] = 1 1026 return TType(type) 1027 return self 1028 1029 def parse_type(self, glsl_header_type): 1030 # TODO(http://anglebug.com/42262477): handle readonly, writeonly qualifiers 1031 if glsl_header_type.startswith('readonly writeonly '): 1032 type_obj = self.parse_type(glsl_header_type[19:]) 1033 type_obj['qualifier'] = 'Readonly Writeonly' 1034 return type_obj 1035 if glsl_header_type.startswith('readonly '): 1036 type_obj = self.parse_type(glsl_header_type[9:]) 1037 type_obj['qualifier'] = 'Readonly' 1038 return type_obj 1039 if glsl_header_type.startswith('writeonly '): 1040 type_obj = self.parse_type(glsl_header_type[10:]) 1041 type_obj['qualifier'] = 'Writeonly' 1042 return type_obj 1043 if glsl_header_type.startswith('out '): 1044 type_obj = self.parse_type(glsl_header_type[4:]) 1045 type_obj['qualifier'] = 'ParamOut' 1046 return type_obj 1047 if glsl_header_type.startswith('inout '): 1048 type_obj = self.parse_type(glsl_header_type[6:]) 1049 type_obj['qualifier'] = 'ParamInOut' 1050 return type_obj 1051 1052 basic_type_map = { 1053 'float': 'Float', 1054 'int': 'Int', 1055 'uint': 'UInt', 1056 'bool': 'Bool', 1057 'void': 'Void', 1058 'atomic_uint': 'AtomicCounter', 1059 'yuvCscStandardEXT': 'YuvCscStandardEXT' 1060 } 1061 1062 if glsl_header_type in basic_type_map: 1063 return {'basic': basic_type_map[glsl_header_type]} 1064 1065 type_obj = {} 1066 1067 basic_type_prefix_map = {'': 'Float', 'i': 'Int', 'u': 'UInt', 'b': 'Bool', 'v': 'Void'} 1068 1069 vec_re = re.compile(r'^([iudb]?)vec([234]?)((\[[234]\])?)$') 1070 vec_match = vec_re.match(glsl_header_type) 1071 if vec_match: 1072 type_obj['basic'] = basic_type_prefix_map[vec_match.group(1)] 1073 if vec_match.group(2) == '': 1074 # Type like "ivec" that represents either ivec2, ivec3 or ivec4 1075 type_obj['genType'] = 'vec' 1076 else: 1077 # vec with specific size 1078 if vec_match.group(3) != '': 1079 # vec array 1080 type_obj['primarySize'] = int(vec_match.group(2)) 1081 type_obj['arraySize'] = int(vec_match.group(3)[1]) 1082 else: 1083 type_obj['primarySize'] = int(vec_match.group(2)) 1084 return type_obj 1085 1086 mat_re = re.compile(r'^mat([234])(x([234]))?$') 1087 mat_match = mat_re.match(glsl_header_type) 1088 if mat_match: 1089 type_obj['basic'] = 'Float' 1090 if len(glsl_header_type) == 4: 1091 mat_size = int(mat_match.group(1)) 1092 type_obj['primarySize'] = mat_size 1093 type_obj['secondarySize'] = mat_size 1094 else: 1095 type_obj['primarySize'] = int(mat_match.group(1)) 1096 type_obj['secondarySize'] = int(mat_match.group(3)) 1097 return type_obj 1098 1099 gen_re = re.compile(r'^gen([IUDB]?)Type$') 1100 gen_match = gen_re.match(glsl_header_type) 1101 if gen_match: 1102 type_obj['basic'] = basic_type_prefix_map[gen_match.group(1).lower()] 1103 type_obj['genType'] = 'yes' 1104 return type_obj 1105 1106 if glsl_header_type.startswith('sampler'): 1107 type_obj['basic'] = glsl_header_type[0].upper() + glsl_header_type[1:] 1108 return type_obj 1109 1110 if glsl_header_type.startswith('gsampler') or \ 1111 glsl_header_type.startswith('gimage') or \ 1112 glsl_header_type.startswith('gpixelLocal') or \ 1113 glsl_header_type.startswith('gsubpassInput'): 1114 type_obj['basic'] = glsl_header_type[1].upper() + glsl_header_type[2:] 1115 type_obj['genType'] = 'sampler_or_image_or_subpass' 1116 return type_obj 1117 1118 if glsl_header_type == 'gvec4': 1119 return {'primarySize': 4, 'genType': 'sampler_or_image_or_subpass'} 1120 if glsl_header_type == 'gvec3': 1121 return {'primarySize': 3, 'genType': 'sampler_or_image_or_subpass'} 1122 1123 if glsl_header_type == 'IMAGE_PARAMS': 1124 return {'genType': 'image_params'} 1125 1126 raise Exception('Unrecognized type: ' + str(glsl_header_type)) 1127 1128 1129class SymbolsData: 1130 1131 def __init__(self): 1132 1133 # Declarations of symbol unique ids 1134 self.builtin_id_declarations = [] 1135 1136 # Declarations of name string variables 1137 self.name_declarations = set() 1138 1139 # Code for testing that script-generated hashes match with runtime computed hashes. 1140 self.script_generated_hash_tests = OrderedDict() 1141 self.unmangled_script_generated_hash_tests = OrderedDict() 1142 1143 1144class VariablesData: 1145 1146 def __init__(self): 1147 1148 # Code for defining TVariables stored as members of TSymbolTable. 1149 self.declare_member_variables = [] 1150 self.init_member_variables = [] 1151 1152 # Declarations of static array sizes if any builtin TVariable is array. 1153 self.type_array_sizes_declarations = set() 1154 1155 # Declarations of builtin TVariables 1156 self.variable_declarations = [] 1157 1158 # Functions for querying the pointer to a specific TVariable. 1159 self.get_variable_declarations = [] 1160 self.get_variable_definitions = [] 1161 1162 1163class FunctionsData: 1164 1165 def __init__(self): 1166 1167 # Declarations of builtin TFunctions 1168 self.function_declarations = [] 1169 1170 # TOperator enum values (and grouping comments) for built-in functions. 1171 self.operator_list = dict() 1172 self.operator_enum_declarations = [] 1173 1174 # Functions for testing whether a builtin belongs in group. 1175 self.is_in_group_definitions = [] 1176 1177 # Declarations of parameter arrays for builtin TFunctions. Map from C++ variable name to the 1178 # full declaration. 1179 self.parameter_declarations = {} 1180 1181 self.defined_function_variants = set() 1182 self.defined_parameter_names = set() 1183 1184 def find_op(self, search_index, direction, limit_for_assertion): 1185 1186 while True: 1187 # Make sure the group is not empty. An "opSuffix" must be used to distinguish between 1188 # built-ins with the same name, but in different groups. 1189 assert (search_index != limit_for_assertion) 1190 1191 line = self.operator_enum_declarations[search_index].lstrip() 1192 if line.startswith('EOp'): 1193 return line[:line.index(',')] 1194 search_index += direction 1195 1196 1197class HashFunction: 1198 1199 def __init__(self, f1, f2, G): 1200 self.f1 = f1 1201 self.f2 = f2 1202 self.G = G 1203 1204 def hash(self, key): 1205 return (self.G[self.f1(key)] + self.G[self.f2(key)]) % len(self.G) 1206 1207 1208def get_parsed_functions(functions_txt_filename): 1209 1210 def parse_function_parameters(parameters): 1211 if parameters == '': 1212 return [] 1213 parametersOut = [] 1214 parameters = parameters.split(', ') 1215 for parameter in parameters: 1216 parametersOut.append(TType(parameter.strip())) 1217 return parametersOut 1218 1219 lines = [] 1220 with open(functions_txt_filename) as f: 1221 lines = f.readlines() 1222 lines = [ 1223 line.strip() for line in lines if line.strip() != '' and not line.strip().startswith('//') 1224 ] 1225 1226 fun_re = re.compile(r'^(\w+) (\w+)\((.*)\);$') 1227 1228 parsed_functions = OrderedDict() 1229 group_stack = [] 1230 default_metadata = {} 1231 1232 for line in lines: 1233 if line.startswith('GROUP BEGIN '): 1234 group_rest = line[12:].strip() 1235 group_parts = group_rest.split(' ', 1) 1236 current_group = {'functions': [], 'name': group_parts[0], 'subgroups': {}} 1237 if len(group_parts) > 1: 1238 group_metadata = json.loads(group_parts[1]) 1239 current_group.update(group_metadata) 1240 group_stack.append(current_group) 1241 elif line.startswith('GROUP END '): 1242 group_end_name = line[10:].strip() 1243 current_group = group_stack[-1] 1244 if current_group['name'] != group_end_name: 1245 raise Exception('GROUP END: Unexpected function group name "' + group_end_name + 1246 '" was expecting "' + current_group['name'] + '"') 1247 group_stack.pop() 1248 is_top_level_group = (len(group_stack) == 0) 1249 if is_top_level_group: 1250 if current_group['name'] in parsed_functions: 1251 raise Exception('GROUP END: Duplicate group name "%s"' % current_group['name']) 1252 parsed_functions[current_group['name']] = current_group 1253 default_metadata = {} 1254 else: 1255 super_group = group_stack[-1] 1256 super_group['subgroups'][current_group['name']] = current_group 1257 elif line.startswith('DEFAULT METADATA'): 1258 line_rest = line[16:].strip() 1259 default_metadata = json.loads(line_rest) 1260 else: 1261 fun_match = fun_re.match(line) 1262 if fun_match: 1263 return_type = fun_match.group(1) 1264 name = fun_match.group(2) 1265 parameters = fun_match.group(3) 1266 function_props = { 1267 'name': name, 1268 'returnType': TType(return_type), 1269 'parameters': parse_function_parameters(parameters) 1270 } 1271 function_props.update(default_metadata) 1272 if 'essl_level' in function_props: 1273 group_stack[-1]['functions'].append(function_props) 1274 else: 1275 raise Exception('Unexpected function input line: ' + line) 1276 1277 return parsed_functions 1278 1279 1280def mangledNameHash(str, hashfn, script_generated_hash_tests, unmangled, save_test=True): 1281 hash = hashfn.hash(str) 1282 if save_test: 1283 confidence_check = '' 1284 if unmangled: 1285 confidence_check = ' ASSERT_EQ(0x{hash}u, ImmutableString("{str}").unmangledNameHash());'.format( 1286 hash=('%08x' % hash), str=str) 1287 else: 1288 confidence_check = ' ASSERT_EQ(0x{hash}u, ImmutableString("{str}").mangledNameHash());'.format( 1289 hash=('%08x' % hash), str=str) 1290 script_generated_hash_tests.update({confidence_check: None}) 1291 return hash 1292 1293 1294def get_function_names(group, mangled_names, unmangled_names): 1295 if 'functions' in group: 1296 for function_props in group['functions']: 1297 function_name = function_props['name'] 1298 unmangled_names.append(function_name) 1299 function_variants = gen_function_variants(function_props) 1300 for function_props in function_variants: 1301 parameters = get_parameters(function_props) 1302 mangled_names.append(get_function_mangled_name(function_name, parameters)) 1303 if 'subgroups' in group: 1304 for subgroup_name, subgroup in group['subgroups'].items(): 1305 get_function_names(subgroup, mangled_names, unmangled_names) 1306 1307 1308def get_variable_names(group, mangled_names): 1309 if 'variables' in group: 1310 for variable_name, props in group['variables'].items(): 1311 mangled_names.append(variable_name) 1312 if 'subgroups' in group: 1313 for subgroup_name, subgroup in group['subgroups'].items(): 1314 get_variable_names(subgroup, mangled_names) 1315 1316 1317def get_suffix(props): 1318 if 'suffix' in props: 1319 return props['suffix'] 1320 return '' 1321 1322 1323def get_essl_extension(props): 1324 if 'essl_extension' in props: 1325 return props['essl_extension'] 1326 return 'UNDEFINED' 1327 1328 1329def get_op(name, function_props, group_op_suffix): 1330 return 'EOp' + name[0].upper() + name[1:] + group_op_suffix + function_props.get( 1331 'opSuffix', '') 1332 1333 1334def get_known_to_not_have_side_effects(function_props): 1335 if 'hasSideEffects' in function_props: 1336 has_side_effects = function_props['hasSideEffects'] 1337 if isinstance(has_side_effects, str): 1338 assert has_side_effects in ['true', 1339 'false'], 'Bad side effects value: ' + has_side_effects 1340 has_side_effects = has_side_effects == 'true' 1341 assert isinstance(has_side_effects, bool) 1342 return 'false' if has_side_effects else 'true' 1343 else: 1344 for param in get_parameters(function_props): 1345 if 'qualifier' in param.data and (param.data['qualifier'] == 'ParamOut' or 1346 param.data['qualifier'] == 'ParamInOut'): 1347 return 'false' 1348 return 'true' 1349 1350 1351def get_parameters(function_props): 1352 if 'parameters' in function_props: 1353 return function_props['parameters'] 1354 return [] 1355 1356 1357def get_function_mangled_name(function_name, parameters): 1358 mangled_name = function_name + '(' 1359 for param in parameters: 1360 mangled_name += param.get_mangled_name() 1361 return mangled_name 1362 1363 1364def get_function_human_readable_name(function_name, parameters): 1365 name = function_name 1366 for param in parameters: 1367 name += '_' + param.get_human_readable_name() 1368 return name 1369 1370 1371def get_unique_identifier_name(function_name, parameters): 1372 unique_name = function_name + '_' 1373 for param in parameters: 1374 unique_name += param.get_mangled_name() 1375 return unique_name 1376 1377 1378def get_variable_name_to_store_parameter(param): 1379 unique_name = 'pt' 1380 if 'qualifier' in param.data: 1381 if param.data['qualifier'] == 'ParamOut': 1382 unique_name += '_o_' 1383 if param.data['qualifier'] == 'ParamInOut': 1384 unique_name += '_io_' 1385 unique_name += param.get_mangled_name() 1386 return unique_name 1387 1388 1389def get_variable_name_to_store_parameters(parameters): 1390 if len(parameters) == 0: 1391 return 'empty' 1392 unique_name = 'p' 1393 for param in parameters: 1394 if 'qualifier' in param.data: 1395 if param.data['qualifier'] == 'ParamOut': 1396 unique_name += '_o_' 1397 if param.data['qualifier'] == 'ParamInOut': 1398 unique_name += '_io_' 1399 unique_name += param.get_mangled_name() 1400 return unique_name 1401 1402 1403def define_constexpr_type_array_sizes(template_args, type_array_sizes_declarations): 1404 template_array_sizes_declaration = 'constexpr const unsigned int kArraySize{arraySize}[1] = {{{arraySize}}};' 1405 type_array_sizes_declarations.add(template_array_sizes_declaration.format(**template_args)) 1406 1407 1408def define_constexpr_variable(template_args, variable_declarations): 1409 template_args['extension'] = get_extension_list(template_args['extension']) 1410 template_variable_declaration = 'constexpr const TVariable k{name_with_suffix}(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type});' 1411 1412 variable_declarations.append(template_variable_declaration.format(**template_args)) 1413 1414 1415def gen_function_variants(function_props): 1416 function_variants = [] 1417 parameters = get_parameters(function_props) 1418 function_is_gen_type = False 1419 gen_type = set() 1420 image_params_index = 0 1421 for param in parameters + [function_props['returnType']]: 1422 if 'genType' in param.data: 1423 if param.data['genType'] not in [ 1424 'sampler_or_image_or_subpass', 'vec', 'yes', 'image_params' 1425 ]: 1426 raise Exception( 1427 'Unexpected value of genType "' + str(param.data['genType']) + 1428 '" should be "sampler_or_image_or_subpass", "vec", "yes", or "image_params"') 1429 gen_type.add(param.data['genType']) 1430 if param.data['genType'] == 'image_params': 1431 image_params_index = parameters.index(param) 1432 1433 if len(gen_type) == 0: 1434 function_variants.append(function_props) 1435 return function_variants 1436 1437 # If we have image_params then we're generating variants for 33 separate functions, 1438 # each for a different type of image variable 1439 if 'image_params' in gen_type: 1440 variants = [['gimage2D', 'ivec2'], ['gimage3D', 'ivec3'], ['gimageCube', 'ivec3'], 1441 ['gimageBuffer', 'int'], ['gimage2DArray', 'ivec3'], 1442 ['gimageCubeArray', 'ivec3'], ['gimageRect', 'ivec2'], 1443 ['gimage2DMS', 'ivec2', 'int'], ['gimage2DMSArray', 'ivec3', 'int']] 1444 for variant in variants: 1445 image_variant_parameters = [] 1446 for param in parameters: 1447 if parameters.index(param) == image_params_index: 1448 for variant_param in variant: 1449 image_variant_parameters.append(TType(variant_param)) 1450 else: 1451 image_variant_parameters.append(param) 1452 types = ['', 'I', 'U'] 1453 for type in types: 1454 variant_props = function_props.copy() 1455 variant_parameters = [] 1456 for param in image_variant_parameters: 1457 variant_parameters.append( 1458 param.specific_sampler_or_image_or_subpass_type(type)) 1459 variant_props['parameters'] = variant_parameters 1460 variant_props['returnType'] = function_props[ 1461 'returnType'].specific_sampler_or_image_or_subpass_type(type) 1462 function_variants.append(variant_props) 1463 return function_variants 1464 1465 # If we have a gsampler_or_image_or_subpass then we're generating variants for float, int and uint 1466 # samplers. 1467 if 'sampler_or_image_or_subpass' in gen_type: 1468 types = ['', 'I', 'U'] 1469 for type in types: 1470 variant_props = function_props.copy() 1471 variant_parameters = [] 1472 for param in parameters: 1473 variant_parameters.append(param.specific_sampler_or_image_or_subpass_type(type)) 1474 variant_props['parameters'] = variant_parameters 1475 variant_props['returnType'] = function_props[ 1476 'returnType'].specific_sampler_or_image_or_subpass_type(type) 1477 function_variants.append(variant_props) 1478 return function_variants 1479 1480 # If we have a normal gentype then we're generating variants for different sizes of vectors. 1481 sizes = range(1, 5) 1482 if 'vec' in gen_type: 1483 sizes = range(2, 5) 1484 for size in sizes: 1485 variant_props = function_props.copy() 1486 variant_parameters = [] 1487 for param in parameters: 1488 variant_parameters.append(param.specific_type(size)) 1489 variant_props['parameters'] = variant_parameters 1490 variant_props['returnType'] = function_props['returnType'].specific_type(size) 1491 function_variants.append(variant_props) 1492 return function_variants 1493 1494 1495def process_single_function(shader_type, group_name, function_props, symbols, variables, functions, 1496 group_op_suffix, unmangled_function_if_statements, mangled_builtins): 1497 global id_counter 1498 1499 function_name = function_props['name'] 1500 essl_level = function_props['essl_level'] if 'essl_level' in function_props else None 1501 essl_extension = get_essl_extension(function_props) 1502 op = get_op(function_name, function_props, group_op_suffix) 1503 template_args = { 1504 'name': function_name, 1505 'name_with_suffix': function_name + get_suffix(function_props), 1506 'essl_level': essl_level, 1507 'essl_extension': essl_extension, 1508 'extension': essl_extension, 1509 'op': op, 1510 'known_to_not_have_side_effects': get_known_to_not_have_side_effects(function_props) 1511 } 1512 1513 function_variants = gen_function_variants(function_props) 1514 1515 template_name_declaration = 'constexpr const ImmutableString {name_with_suffix}("{name}");' 1516 name_declaration = template_name_declaration.format(**template_args) 1517 if not name_declaration in symbols.name_declarations: 1518 symbols.name_declarations.add(name_declaration) 1519 1520 essl_ext = '{essl_extension}'.format(**template_args) 1521 unmangled_builtin_no_shader_type = unmangled_function_if_statements.get( 1522 essl_level, 'NONE', function_name) 1523 if unmangled_builtin_no_shader_type != None and unmangled_builtin_no_shader_type[ 1524 'essl_extension'] == 'UNDEFINED': 1525 # We already have this unmangled name without a shader type nor extension on the same level. 1526 # No need to add a duplicate with a type. 1527 pass 1528 elif (not unmangled_function_if_statements.has_key(essl_level, shader_type, function_name) 1529 ) or (unmangled_builtin_no_shader_type and 1530 (essl_extension == 'UNDEFINED' and 1531 unmangled_builtin_no_shader_type['essl_extension'] != 'UNDEFINED')): 1532 unmangled_function_if_statements.add_entry(essl_level, shader_type, function_name, 1533 essl_ext, essl_extension, 1534 symbols.unmangled_script_generated_hash_tests) 1535 1536 extension_string = get_extension_list(template_args['extension']) 1537 1538 if op not in functions.operator_list: 1539 functions.operator_list[op] = group_name 1540 is_unary = group_name.startswith('Math') and len(get_parameters(function_variants[0])) == 1 1541 assert (not is_unary or 1542 all([len(get_parameters(props)) == 1 for props in function_variants])) 1543 1544 template_operator_enum = ' {op},{is_unary_comment}' 1545 template_args['is_unary_comment'] = ' // Unary' if is_unary else '' 1546 1547 functions.operator_enum_declarations.append(template_operator_enum.format(**template_args)) 1548 else: 1549 # Ensure that built-ins in different groups don't generate the same op. The Is<Group> query 1550 # functions rely on this. 1551 previous_group_name = functions.operator_list[op] 1552 if group_name != previous_group_name: 1553 print('Op ' + op + ' found in group ' + group_name + ' but was previously in group ' + 1554 previous_group_name) 1555 assert (group_name == previous_group_name) 1556 1557 for function_props in function_variants: 1558 template_args['id'] = id_counter 1559 1560 parameters = get_parameters(function_props) 1561 1562 template_args['unique_name'] = get_unique_identifier_name( 1563 template_args['name_with_suffix'], parameters) 1564 template_args['param_count'] = len(parameters) 1565 template_args['return_type'] = function_props['returnType'].get_statictype_string() 1566 template_args['mangled_name'] = get_function_mangled_name(function_name, parameters) 1567 template_args['human_readable_name'] = get_function_human_readable_name( 1568 template_args['name_with_suffix'], parameters) 1569 template_args['mangled_name_length'] = len(template_args['mangled_name']) 1570 1571 symbol = '&Func::{unique_name}'.format(**template_args) 1572 mangled_builtins.add_entry(essl_level, shader_type, template_args['mangled_name'], symbol, 1573 template_args['essl_extension'], 1574 symbols.script_generated_hash_tests) 1575 1576 if template_args['unique_name'] in functions.defined_function_variants: 1577 continue 1578 functions.defined_function_variants.add(template_args['unique_name']) 1579 1580 template_builtin_id_declaration = ' static constexpr const TSymbolUniqueId {human_readable_name} = TSymbolUniqueId({id});' 1581 symbols.builtin_id_declarations.append( 1582 template_builtin_id_declaration.format(**template_args)) 1583 1584 parameters_list = [] 1585 for param in parameters: 1586 unique_param_name = get_variable_name_to_store_parameter(param) 1587 param_template_args = { 1588 'name': '_empty', 1589 'name_with_suffix': unique_param_name, 1590 'type': param.get_statictype_string(), 1591 'extension': 'UNDEFINED' 1592 } 1593 if unique_param_name not in functions.defined_parameter_names: 1594 id_counter += 1 1595 param_template_args['id'] = id_counter 1596 template_builtin_id_declaration = ' static constexpr const TSymbolUniqueId {name_with_suffix} = TSymbolUniqueId({id});' 1597 symbols.builtin_id_declarations.append( 1598 template_builtin_id_declaration.format(**param_template_args)) 1599 define_constexpr_variable(param_template_args, variables.variable_declarations) 1600 functions.defined_parameter_names.add(unique_param_name) 1601 if param.has_array_size(): 1602 array_size_template_args = {'arraySize': param.data['arraySize']} 1603 define_constexpr_type_array_sizes(array_size_template_args, 1604 variables.type_array_sizes_declarations) 1605 parameters_list.append( 1606 '&BuiltInVariable::k{name_with_suffix}'.format(**param_template_args)) 1607 1608 template_args['parameters_var_name'] = get_variable_name_to_store_parameters(parameters) 1609 if len(parameters) > 0: 1610 template_args['parameters_list'] = ', '.join(parameters_list) 1611 template_parameter_list_declaration = 'constexpr const TVariable *{parameters_var_name}[{param_count}] = {{ {parameters_list} }};' 1612 functions.parameter_declarations[ 1613 template_args['parameters_var_name']] = template_parameter_list_declaration.format( 1614 **template_args) 1615 else: 1616 template_parameter_list_declaration = 'constexpr const TVariable **{parameters_var_name} = nullptr;' 1617 functions.parameter_declarations[ 1618 template_args['parameters_var_name']] = template_parameter_list_declaration.format( 1619 **template_args) 1620 1621 template_args['extension'] = extension_string 1622 template_function_declaration = 'constexpr const TFunction {unique_name}(BuiltInId::{human_readable_name}, BuiltInName::{name_with_suffix}, {extension}, BuiltInParameters::{parameters_var_name}, {param_count}, {return_type}, {op}, {known_to_not_have_side_effects});' 1623 functions.function_declarations.append( 1624 template_function_declaration.format(**template_args)) 1625 1626 id_counter += 1 1627 1628 1629def process_single_function_group(shader_type, group_name, group, symbols, variables, functions, 1630 group_op_suffix, unmangled_function_if_statements, 1631 mangled_builtins): 1632 1633 if 'functions' not in group: 1634 return 1635 1636 for function_props in group['functions']: 1637 process_single_function(shader_type, group_name, function_props, symbols, variables, 1638 functions, group_op_suffix, unmangled_function_if_statements, 1639 mangled_builtins) 1640 1641 if 'essl_extension_becomes_core_in' in function_props: 1642 assert ('essl_extension' in function_props) 1643 1644 core_props = copy.deepcopy(function_props) 1645 1646 # Adjust the props by updating the level, removing extension and adding suffix 1647 core_level = function_props['essl_extension_becomes_core_in'] 1648 core_props['essl_level'] = core_level 1649 del core_props['essl_extension'] 1650 suffix = core_props['suffix'] if 'suffix' in core_props else '' 1651 suffix += generate_suffix_from_level(core_level) 1652 core_props['suffix'] = suffix 1653 1654 process_single_function(shader_type, group_name, core_props, symbols, variables, 1655 functions, group_op_suffix, unmangled_function_if_statements, 1656 mangled_builtins) 1657 1658 1659def process_function_group(group_name, group, symbols, variables, functions, 1660 parent_group_op_suffix, unmangled_function_if_statements, 1661 mangled_builtins): 1662 1663 functions.operator_enum_declarations.append('') 1664 functions.operator_enum_declarations.append(' // Group ' + group_name) 1665 first_op_index = len(functions.operator_enum_declarations) 1666 1667 shader_type = 'NONE' 1668 if 'shader_type' in group: 1669 shader_type = group['shader_type'] 1670 1671 group_op_suffix = parent_group_op_suffix + group.get('opSuffix', '') 1672 process_single_function_group(shader_type, group_name, group, symbols, variables, functions, 1673 group_op_suffix, unmangled_function_if_statements, 1674 mangled_builtins) 1675 1676 if 'subgroups' in group: 1677 for subgroup_name, subgroup in group['subgroups'].items(): 1678 process_function_group(group_name + subgroup_name, subgroup, symbols, variables, 1679 functions, group_op_suffix, unmangled_function_if_statements, 1680 mangled_builtins) 1681 1682 if 'queryFunction' in group: 1683 last_op_index = len(functions.operator_enum_declarations) - 1 1684 1685 first_op = functions.find_op(first_op_index, +1, last_op_index + 1) 1686 last_op = functions.find_op(last_op_index, -1, first_op_index - 1) 1687 1688 template_args = {'first_op': first_op, 'last_op': last_op, 'group_name': group_name} 1689 template_is_in_group_definition = """static inline bool Is{group_name}(TOperator op) 1690{{ 1691 return op >= {first_op} && op <= {last_op}; 1692}}""" 1693 functions.is_in_group_definitions.append( 1694 template_is_in_group_definition.format(**template_args)) 1695 1696 1697def prune_parameters_arrays(parameter_declarations, function_declarations): 1698 # We can share parameters arrays between functions in case one array is a subarray of another. 1699 parameter_variable_name_replacements = {} 1700 used_param_variable_names = set() 1701 for param_variable_name, param_declaration in sorted( 1702 parameter_declarations.items(), key=lambda item: -len(item[0])): 1703 replaced = False 1704 for used in sorted(used_param_variable_names): 1705 if used.startswith(param_variable_name): 1706 parameter_variable_name_replacements[param_variable_name] = used 1707 replaced = True 1708 break 1709 if not replaced: 1710 used_param_variable_names.add(param_variable_name) 1711 1712 for i in range(len(function_declarations)): 1713 for replaced, replacement in parameter_variable_name_replacements.items(): 1714 function_declarations[i] = function_declarations[i].replace( 1715 'BuiltInParameters::' + replaced + ',', 'BuiltInParameters::' + replacement + ',') 1716 1717 return [ 1718 value for key, value in parameter_declarations.items() if key in used_param_variable_names 1719 ] 1720 1721 1722def process_single_variable(shader_type, variable_name, props, symbols, variables, 1723 mangled_builtins): 1724 global id_counter 1725 1726 essl_level = props['essl_level'] if 'essl_level' in props else None 1727 template_args = { 1728 'id': id_counter, 1729 'name': variable_name, 1730 'name_with_suffix': variable_name + get_suffix(props), 1731 'essl_level': essl_level, 1732 'essl_extension': get_essl_extension(props), 1733 'extension': get_essl_extension(props), 1734 'class': 'TVariable' 1735 } 1736 1737 template_builtin_id_declaration = ' static constexpr const TSymbolUniqueId {name_with_suffix} = TSymbolUniqueId({id});' 1738 symbols.builtin_id_declarations.append(template_builtin_id_declaration.format(**template_args)) 1739 1740 template_name_declaration = 'constexpr const ImmutableString {name}("{name}");' 1741 symbols.name_declarations.add(template_name_declaration.format(**template_args)) 1742 1743 is_member = True 1744 template_init_variable = '' 1745 1746 extension_string = get_extension_list(template_args['extension']) 1747 1748 if 'type' in props: 1749 if props['type']['basic'] != 'Bool' and 'precision' not in props['type']: 1750 raise Exception('Missing precision for variable ' + variable_name) 1751 template_args['type'] = TType(props['type']).get_statictype_string() 1752 1753 if 'fields' in props: 1754 # Handle struct and interface block definitions. 1755 template_args['class'] = props['class'] 1756 template_args['fields'] = 'fields_{name_with_suffix}'.format(**template_args) 1757 variables.init_member_variables.append( 1758 ' TFieldList *{fields} = new TFieldList();'.format(**template_args)) 1759 for field_name, field_type in props['fields'].items(): 1760 template_args['field_name'] = field_name 1761 template_args['field_type'] = TType(field_type).get_dynamic_type_string() 1762 template_name_declaration = 'constexpr const ImmutableString {field_name}("{field_name}");' 1763 symbols.name_declarations.add(template_name_declaration.format(**template_args)) 1764 template_add_field = ' {fields}->push_back(new TField({field_type}, BuiltInName::{field_name}, zeroSourceLoc, SymbolType::BuiltIn));' 1765 variables.init_member_variables.append(template_add_field.format(**template_args)) 1766 template_args['extension'] = extension_string 1767 template_init_temp_variable = ' {class} *{name_with_suffix} = new {class}(BuiltInId::{name_with_suffix}, BuiltInName::{name}, {extension}, {fields});' 1768 variables.init_member_variables.append(template_init_temp_variable.format(**template_args)) 1769 if 'private' in props and props['private']: 1770 is_member = False 1771 else: 1772 template_init_variable = ' m_{name_with_suffix} = {name_with_suffix};' 1773 1774 elif 'initDynamicType' in props: 1775 # Handle variables whose type can't be expressed as TStaticType 1776 # (type is a struct or has variable array size for example). 1777 template_args['type_name'] = 'type_{name_with_suffix}'.format(**template_args) 1778 template_args['type'] = template_args['type_name'] 1779 template_args['ext_or_core_suffix'] = '' 1780 if 'essl_extension_becomes_core_in' in props and 'essl_extension' not in props: 1781 template_args['ext_or_core_suffix'] = generate_suffix_from_level(props['essl_level']) 1782 template_args['initDynamicType'] = props['initDynamicType'].format(**template_args) 1783 template_args['extension'] = extension_string 1784 template_init_variable = """ {initDynamicType} 1785{type_name}->realize(); 1786m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type});""" 1787 1788 elif 'value' in props: 1789 # Handle variables with constant value, such as gl_MaxDrawBuffers. 1790 if props['value'] != 'resources': 1791 raise Exception('Unrecognized value source in variable properties: ' + 1792 str(props['value'])) 1793 resources_key = variable_name[3:] 1794 if 'valueKey' in props: 1795 resources_key = props['valueKey'] 1796 template_args['value'] = 'resources.' + resources_key 1797 template_args['object_size'] = TType(props['type']).get_object_size() 1798 template_args['extension'] = extension_string 1799 template_init_variable = """ m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type}); 1800{{ 1801 TConstantUnion *unionArray = new TConstantUnion[{object_size}]; 1802 unionArray[0].setIConst({value}); 1803 static_cast<TVariable *>(m_{name_with_suffix})->shareConstPointer(unionArray); 1804}}""" 1805 if template_args['object_size'] > 1: 1806 template_init_variable = """ m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type}); 1807{{ 1808 TConstantUnion *unionArray = new TConstantUnion[{object_size}]; 1809 for (size_t index = 0u; index < {object_size}; ++index) 1810 {{ 1811 unionArray[index].setIConst({value}[index]); 1812 }} 1813 static_cast<TVariable *>(m_{name_with_suffix})->shareConstPointer(unionArray); 1814}}""" 1815 1816 else: 1817 # Handle variables that can be stored as constexpr TVariable like 1818 # gl_Position, gl_FragColor etc. 1819 define_constexpr_variable(template_args, variables.variable_declarations) 1820 is_member = False 1821 1822 template_get_variable_declaration = 'const TVariable *{name_with_suffix}();' 1823 variables.get_variable_declarations.append( 1824 template_get_variable_declaration.format(**template_args)) 1825 1826 template_get_variable_definition = """const TVariable *{name_with_suffix}() 1827{{ 1828return &k{name_with_suffix}; 1829}} 1830""" 1831 variables.get_variable_definitions.append( 1832 template_get_variable_definition.format(**template_args)) 1833 1834 obj = '&BuiltInVariable::k{name_with_suffix}'.format(**template_args) 1835 mangled_builtins.add_entry(essl_level, shader_type, template_args['name'], obj, 1836 template_args['essl_extension'], 1837 symbols.script_generated_hash_tests) 1838 1839 if is_member: 1840 variables.init_member_variables.append(template_init_variable.format(**template_args)) 1841 1842 template_declare_member_variable = 'TSymbol *m_{name_with_suffix} = nullptr;' 1843 variables.declare_member_variables.append( 1844 template_declare_member_variable.format(**template_args)) 1845 1846 obj = 'm_{name_with_suffix}'.format(**template_args) 1847 1848 mangled_builtins.add_entry(essl_level, shader_type, template_args['name'], obj, 1849 template_args['essl_extension'], 1850 symbols.script_generated_hash_tests) 1851 1852 id_counter += 1 1853 1854 1855def process_single_variable_group(shader_type, group, symbols, variables, mangled_builtins): 1856 global id_counter 1857 if 'variables' not in group: 1858 return 1859 for variable_name, props in group['variables'].items(): 1860 process_single_variable(shader_type, variable_name, props, symbols, variables, 1861 mangled_builtins) 1862 1863 if 'essl_extension_becomes_core_in' in props: 1864 assert ('essl_extension' in props) 1865 1866 core_props = copy.deepcopy(props) 1867 1868 # Adjust the props by updating the level, removing extension and adding suffix 1869 core_level = props['essl_extension_becomes_core_in'] 1870 core_props['essl_level'] = core_level 1871 del core_props['essl_extension'] 1872 suffix = core_props['suffix'] if 'suffix' in core_props else '' 1873 suffix += generate_suffix_from_level(core_level) 1874 core_props['suffix'] = suffix 1875 process_single_variable(shader_type, variable_name, core_props, symbols, variables, 1876 mangled_builtins) 1877 1878 1879def process_variable_group(shader_type, group_name, group, symbols, variables, mangled_builtins): 1880 global id_counter 1881 1882 if 'shader_type' in group: 1883 shader_type = group['shader_type'] 1884 1885 process_single_variable_group(shader_type, group, symbols, variables, mangled_builtins) 1886 1887 if 'subgroups' in group: 1888 for subgroup_name, subgroup in group['subgroups'].items(): 1889 process_variable_group(shader_type, subgroup_name, subgroup, symbols, variables, 1890 mangled_builtins) 1891 1892 1893def generate_files(args, functions_txt_filename, variables_json_filename, 1894 immutablestring_cpp_filename, immutablestringtest_cpp_filename, 1895 builtin_header_filename, symboltable_cpp_filename, operator_header_filename, 1896 symboltable_header_filename): 1897 1898 symbols = SymbolsData() 1899 variables = VariablesData() 1900 functions = FunctionsData() 1901 1902 parsed_functions = get_parsed_functions(functions_txt_filename) 1903 1904 if args.dump_intermediate_json: 1905 with open('builtin_functions_ESSL.json', 'w') as outfile: 1906 1907 def serialize_obj(obj): 1908 if isinstance(obj, TType): 1909 return obj.data 1910 else: 1911 raise "Cannot serialize to JSON: " + str(obj) 1912 1913 json.dump( 1914 parsed_functions, outfile, indent=4, separators=(',', ': '), default=serialize_obj) 1915 1916 parsed_variables = None 1917 with open(variables_json_filename) as f: 1918 parsed_variables = json.load(f, object_pairs_hook=OrderedDict) 1919 1920 # This script uses a perfect hash function to avoid dealing with collisions 1921 mangled_names = [] 1922 unmangled_names = [] 1923 for group_name, group in parsed_functions.items(): 1924 get_function_names(group, mangled_names, unmangled_names) 1925 for group_name, group in parsed_variables.items(): 1926 get_variable_names(group, mangled_names) 1927 1928 # Hashing mangled names 1929 mangled_names = list(dict.fromkeys(mangled_names)) 1930 num_mangled_names = len(mangled_names) 1931 mangled_names_dict = dict(zip(mangled_names, range(0, len(mangled_names)))) 1932 # Generate the perfect hash function 1933 f1, f2, mangled_G = generate_hash(mangled_names_dict, Hash2) 1934 mangled_hashfn = HashFunction(f1, f2, mangled_G) 1935 mangled_S1 = f1.salt 1936 mangled_S2 = f2.salt 1937 # Array for querying mangled builtins 1938 mangled_builtins = GroupedList(mangled_hashfn, num_mangled_names) 1939 1940 # Hashing unmangled names 1941 unmangled_names = list(dict.fromkeys(unmangled_names)) 1942 num_unmangled_names = len(unmangled_names) 1943 unmangled_names_dict = dict(zip(unmangled_names, range(0, len(unmangled_names)))) 1944 # Generate the perfect hash function 1945 f1, f2, unmangled_G = generate_hash(unmangled_names_dict, Hash2) 1946 unmangled_hashfn = HashFunction(f1, f2, unmangled_G) 1947 unmangled_S1 = f1.salt 1948 unmangled_S2 = f2.salt 1949 # Array for querying unmangled builtins 1950 unmangled_function_if_statements = UnmangledGroupedList(unmangled_hashfn, num_unmangled_names) 1951 1952 for group_name, group in parsed_functions.items(): 1953 process_function_group(group_name, group, symbols, variables, functions, '', 1954 unmangled_function_if_statements, mangled_builtins) 1955 1956 functions.parameter_declarations = prune_parameters_arrays(functions.parameter_declarations, 1957 functions.function_declarations) 1958 1959 for group_name, group in parsed_variables.items(): 1960 process_variable_group('NONE', group_name, group, symbols, variables, mangled_builtins) 1961 1962 mangled_builtins.update_arrays() 1963 1964 output_strings = { 1965 'script_name': 1966 os.path.basename(__file__), 1967 'builtin_id_declarations': 1968 '\n'.join(symbols.builtin_id_declarations), 1969 'last_builtin_id': 1970 id_counter - 1, 1971 'name_declarations': 1972 '\n'.join(sorted(list(symbols.name_declarations))), 1973 'function_data_source_name': 1974 functions_txt_filename, 1975 'function_declarations': 1976 '\n'.join(functions.function_declarations), 1977 'parameter_declarations': 1978 '\n'.join(sorted(functions.parameter_declarations)), 1979 'operator_enum_declarations': 1980 '\n'.join(functions.operator_enum_declarations), 1981 'is_in_group_definitions': 1982 '\n'.join(functions.is_in_group_definitions), 1983 'variable_data_source_name': 1984 variables_json_filename, 1985 'type_array_sizes_declarations': 1986 '\n'.join(sorted(variables.type_array_sizes_declarations)), 1987 'variable_declarations': 1988 '\n'.join(sorted(variables.variable_declarations)), 1989 'get_variable_declarations': 1990 '\n'.join(sorted(variables.get_variable_declarations)), 1991 'get_variable_definitions': 1992 '\n'.join(sorted(variables.get_variable_definitions)), 1993 'declare_member_variables': 1994 '\n'.join(variables.declare_member_variables), 1995 'init_member_variables': 1996 '\n'.join(variables.init_member_variables), 1997 'mangled_names_array': 1998 ',\n'.join(mangled_builtins.get_names()), 1999 'mangled_offsets_array': 2000 '\n'.join(mangled_builtins.get_offsets()), 2001 'mangled_rules': 2002 ',\n'.join(mangled_builtins.get_rules()), 2003 'unmangled_array': 2004 ', '.join(unmangled_function_if_statements.get_array()), 2005 'max_unmangled_name_length': 2006 unmangled_function_if_statements.get_max_name_length(), 2007 'max_mangled_name_length': 2008 mangled_builtins.get_max_name_length(), 2009 'num_unmangled_names': 2010 num_unmangled_names, 2011 'num_mangled_names': 2012 num_mangled_names, 2013 'script_generated_hash_tests': 2014 '\n'.join(symbols.script_generated_hash_tests.keys()), 2015 'unmangled_script_generated_hash_tests': 2016 '\n'.join(symbols.unmangled_script_generated_hash_tests.keys()), 2017 'mangled_S1': 2018 str(mangled_S1).replace('[', ' ').replace(']', ' '), 2019 'mangled_S2': 2020 str(mangled_S2).replace('[', ' ').replace(']', ' '), 2021 'mangled_G': 2022 str(mangled_G).replace('[', ' ').replace(']', ' '), 2023 'mangled_NG': 2024 len(mangled_G), 2025 'mangled_NS': 2026 len(mangled_S1), 2027 'unmangled_S1': 2028 str(unmangled_S1).replace('[', ' ').replace(']', ' '), 2029 'unmangled_S2': 2030 str(unmangled_S2).replace('[', ' ').replace(']', ' '), 2031 'unmangled_G': 2032 str(unmangled_G).replace('[', ' ').replace(']', ' '), 2033 'unmangled_NG': 2034 len(unmangled_G), 2035 'unmangled_NS': 2036 len(unmangled_S1), 2037 } 2038 2039 with open(immutablestring_cpp_filename, 'wt') as outfile_cpp: 2040 output_cpp = template_immutablestring_cpp.format(**output_strings) 2041 outfile_cpp.write(output_cpp) 2042 2043 with open(immutablestringtest_cpp_filename, 'wt') as outfile_cpp: 2044 output_cpp = template_immutablestringtest_cpp.format(**output_strings) 2045 outfile_cpp.write(output_cpp) 2046 2047 with open(builtin_header_filename, 'wt') as outfile_header: 2048 output_header = template_builtin_header.format(**output_strings) 2049 outfile_header.write(output_header) 2050 2051 with open(symboltable_cpp_filename, 'wt') as outfile_cpp: 2052 output_cpp = template_symboltable_cpp.format(**output_strings) 2053 outfile_cpp.write(output_cpp) 2054 2055 with open(operator_header_filename, 'wt') as outfile_header: 2056 output_header = template_operator_header.format(**output_strings) 2057 outfile_header.write(output_header) 2058 2059 with open(symboltable_header_filename, 'wt') as outfile_h: 2060 output_h = template_symboltable_header.format(**output_strings) 2061 outfile_h.write(output_h) 2062 2063 2064def main(): 2065 random.seed(0) 2066 set_working_dir() 2067 2068 parser = argparse.ArgumentParser() 2069 parser.add_argument( 2070 '--dump-intermediate-json', 2071 help='Dump parsed function data as a JSON file builtin_functions.json', 2072 action="store_true") 2073 parser.add_argument('auto_script_command', nargs='?', default='') 2074 args = parser.parse_args() 2075 2076 test_filename = '../../tests/compiler_tests/ImmutableString_test_autogen.cpp' 2077 variables_json_filename = 'builtin_variables.json' 2078 functions_txt_filename = 'builtin_function_declarations.txt' 2079 2080 # auto_script parameters. 2081 if args.auto_script_command != '': 2082 inputs = [ 2083 functions_txt_filename, 2084 variables_json_filename, 2085 ] 2086 outputs = [ 2087 'Operator_autogen.h', 2088 'SymbolTable_autogen.h', 2089 test_filename, 2090 'ImmutableString_autogen.cpp', 2091 'SymbolTable_autogen.cpp', 2092 'tree_util/BuiltIn_autogen.h', 2093 ] 2094 2095 if args.auto_script_command == 'inputs': 2096 print(','.join(inputs)) 2097 elif args.auto_script_command == 'outputs': 2098 print(','.join(outputs)) 2099 else: 2100 print('Invalid script parameters') 2101 return 1 2102 return 0 2103 2104 # Generate files based on ESSL symbols 2105 generate_files(args, functions_txt_filename, variables_json_filename, 2106 'ImmutableString_autogen.cpp', test_filename, 'tree_util/BuiltIn_autogen.h', 2107 'SymbolTable_autogen.cpp', 'Operator_autogen.h', 'SymbolTable_autogen.h') 2108 2109 return 0 2110 2111 2112if __name__ == '__main__': 2113 sys.exit(main()) 2114