1#!/usr/bin/env vpython 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. 16 17from collections import OrderedDict 18from datetime import date 19from perfect_hash import generate_hash, Hash2 20import argparse 21import hashlib 22import json 23import re 24import os 25import sys 26import random 27 28template_immutablestring_cpp = """// GENERATED FILE - DO NOT EDIT. 29// Generated by {script_name} using data from {variable_data_source_name} and 30// {function_data_source_name}. 31// 32// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved. 33// Use of this source code is governed by a BSD-style license that can be 34// found in the LICENSE file. 35// 36// ImmutableString_autogen.cpp: Wrapper for static or pool allocated char arrays, that are guaranteed to be 37// valid and unchanged for the duration of the compilation. 38// Implements mangledNameHash using perfect hash function from gen_builtin_symbols.py 39 40#include "compiler/translator/ImmutableString.h" 41 42std::ostream &operator<<(std::ostream &os, const sh::ImmutableString &str) 43{{ 44 return os.write(str.data(), str.length()); 45}} 46 47#if defined(_MSC_VER) 48# pragma warning(disable : 4309) // truncation of constant value 49#endif 50 51 52namespace 53{{ 54 55constexpr int kT1[] = {{{S1}}}; 56constexpr int kT2[] = {{{S2}}}; 57constexpr int kG[] = {{{G}}}; 58 59int HashG(const char *key, const int *T) 60{{ 61 int sum = 0; 62 63 for (int i = 0; key[i] != '\\0'; i++) 64 {{ 65 sum += T[i] * key[i]; 66 sum %= {NG}; 67 }} 68 return kG[sum]; 69}} 70 71int PerfectHash(const char *key) 72{{ 73 if (strlen(key) > {NS}) 74 return 0; 75 76 return (HashG(key, kT1) + HashG(key, kT2)) % {NG}; 77}} 78 79}} 80 81namespace sh 82{{ 83 84template <> 85const size_t ImmutableString::FowlerNollVoHash<4>::kFnvPrime = 16777619u; 86 87template <> 88const size_t ImmutableString::FowlerNollVoHash<4>::kFnvOffsetBasis = 0x811c9dc5u; 89 90template <> 91const size_t ImmutableString::FowlerNollVoHash<8>::kFnvPrime = 92 static_cast<size_t>(1099511628211ull); 93 94template <> 95const size_t ImmutableString::FowlerNollVoHash<8>::kFnvOffsetBasis = 96 static_cast<size_t>(0xcbf29ce484222325ull); 97 98uint32_t ImmutableString::mangledNameHash() const 99{{ 100 return PerfectHash(data()); 101}} 102 103}} // namespace sh 104""" 105 106template_immutablestringtest_cpp = """// GENERATED FILE - DO NOT EDIT. 107// Generated by {script_name} using data from {function_data_source_name}. 108// 109// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved. 110// Use of this source code is governed by a BSD-style license that can be 111// found in the LICENSE file. 112// 113// ImmutableString_test_autogen.cpp: 114// Tests for matching script-generated hashes with runtime computed hashes. 115 116#include "compiler/translator/ImmutableString.h" 117#include "gtest/gtest.h" 118 119namespace sh 120{{ 121 122TEST(ImmutableStringTest, ScriptGeneratedHashesMatch) 123{{ 124{script_generated_hash_tests} 125}} 126 127}} // namespace sh 128""" 129 130# The header file has a "get" function for each variable. They are used in traversers. 131# It also declares id values of built-ins with human readable names, so they can be used to identify built-ins. 132template_builtin_header = """// GENERATED FILE - DO NOT EDIT. 133// Generated by {script_name} using data from {variable_data_source_name} and 134// {function_data_source_name}. 135// 136// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved. 137// Use of this source code is governed by a BSD-style license that can be 138// found in the LICENSE file. 139// 140// BuiltIn_autogen.h: 141// Compile-time initialized built-ins. 142 143#ifndef COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_ 144#define COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_ 145 146#include "compiler/translator/SymbolUniqueId.h" 147 148namespace sh 149{{ 150 151class TVariable; 152 153class BuiltInId 154{{ 155public: 156 157{builtin_id_declarations} 158 159}}; // class BuiltInId 160 161namespace BuiltInVariable 162{{ 163 164{get_variable_declarations} 165 166}} // namespace BuiltInVariable 167 168}} // namespace sh 169 170#endif // COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_ 171""" 172 173template_symboltable_h = """// GENERATED FILE - DO NOT EDIT. 174// Generated by {script_name} using data from {variable_data_source_name} and 175// {function_data_source_name}. 176// 177// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved. 178// Use of this source code is governed by a BSD-style license that can be 179// found in the LICENSE file. 180// 181// SymbolTable_autogen.h: 182// Autogenerated member variables of TSymbolTable. 183 184#ifndef COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_ 185#define COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_ 186 187namespace sh 188{{ 189 190class TSymbolTableBase 191{{ 192 protected: 193 TSymbolTableBase() = default; 194{declare_member_variables} 195}}; 196 197}} // namespace sh 198 199#endif // COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_ 200""" 201 202# By having the variables defined in a cpp file we ensure that there's just one instance of each of the declared variables. 203template_symboltable_cpp = """// GENERATED FILE - DO NOT EDIT. 204// Generated by {script_name} using data from {variable_data_source_name} and 205// {function_data_source_name}. 206// 207// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved. 208// Use of this source code is governed by a BSD-style license that can be 209// found in the LICENSE file. 210// 211// SymbolTable_autogen.cpp: 212// Compile-time initialized built-ins. 213 214#include "compiler/translator/SymbolTable.h" 215 216#include "angle_gl.h" 217#include "compiler/translator/tree_util/BuiltIn_autogen.h" 218#include "compiler/translator/ImmutableString.h" 219#include "compiler/translator/StaticType.h" 220#include "compiler/translator/Symbol.h" 221#include "compiler/translator/SymbolTable.h" 222 223namespace sh 224{{ 225 226// Since some of the BuiltInId declarations are used outside of constexpr expressions, we need to 227// have these definitions without an initializer. C++17 should eventually remove the need for this. 228{builtin_id_definitions} 229 230const int TSymbolTable::kLastBuiltInId = {last_builtin_id}; 231 232namespace BuiltInName 233{{ 234 235constexpr const ImmutableString _empty(""); 236{name_declarations} 237 238}} // namespace BuiltInName 239 240// TODO(oetuaho): Would be nice to make this a class instead of a namespace so that we could friend 241// this from TVariable. Now symbol constructors taking an id have to be public even though they're 242// not supposed to be accessible from outside of here. http://anglebug.com/2390 243namespace BuiltInVariable 244{{ 245 246{variable_declarations} 247 248{get_variable_definitions} 249 250}} // namespace BuiltInVariable 251 252namespace BuiltInParameters 253{{ 254 255{parameter_declarations} 256 257}} // namespace BuiltInParameters 258 259namespace UnmangledBuiltIns 260{{ 261 262{unmangled_builtin_declarations} 263 264}} // namespace UnmangledBuiltIns 265 266// TODO(oetuaho): Would be nice to make this a class instead of a namespace so that we could friend 267// this from TFunction. Now symbol constructors taking an id have to be public even though they're 268// not supposed to be accessible from outside of here. http://anglebug.com/2390 269namespace BuiltInFunction 270{{ 271 272{function_declarations} 273 274}} // namespace BuiltInFunction 275 276void TSymbolTable::initializeBuiltInVariables(sh::GLenum shaderType, 277 ShShaderSpec spec, 278 const ShBuiltInResources &resources) 279{{ 280 const TSourceLoc zeroSourceLoc = {{0, 0, 0, 0}}; 281{init_member_variables} 282}} 283 284const TSymbol *TSymbolTable::findBuiltIn(const ImmutableString &name, 285 int shaderVersion) const 286{{ 287 if (name.length() > {max_mangled_name_length}) 288 {{ 289 return nullptr; 290 }} 291 uint32_t nameHash = name.mangledNameHash(); 292{get_builtin} 293}} 294 295const UnmangledBuiltIn *TSymbolTable::getUnmangledBuiltInForShaderVersion(const ImmutableString &name, int shaderVersion) 296{{ 297 if (name.length() > {max_unmangled_name_length}) 298 {{ 299 return nullptr; 300 }} 301 uint32_t nameHash = name.mangledNameHash(); 302{get_unmangled_builtin} 303}} 304 305}} // namespace sh 306""" 307 308template_parsecontext_header = """// GENERATED FILE - DO NOT EDIT. 309// Generated by {script_name} using data from {variable_data_source_name} and 310// {function_data_source_name}. 311// 312// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved. 313// Use of this source code is governed by a BSD-style license that can be 314// found in the LICENSE file. 315// 316// ParseContext_autogen.h: 317// Helpers for built-in related checks. 318 319#ifndef COMPILER_TRANSLATOR_PARSECONTEXT_AUTOGEN_H_ 320#define COMPILER_TRANSLATOR_PARSECONTEXT_AUTOGEN_H_ 321 322namespace sh 323{{ 324 325namespace BuiltInGroup 326{{ 327 328{is_in_group_definitions} 329 330}} // namespace BuiltInGroup 331 332}} // namespace sh 333 334#endif // COMPILER_TRANSLATOR_PARSECONTEXT_AUTOGEN_H_ 335 336""" 337 338parsed_variables = None 339 340basic_types_enumeration = [ 341 'Void', 'Float', 'Int', 'UInt', 'Bool', 'AtomicCounter', 'YuvCscStandardEXT', 'Sampler2D', 342 'Sampler3D', 'SamplerCube', 'Sampler2DArray', 'SamplerExternalOES', 'SamplerExternal2DY2YEXT', 343 'Sampler2DRect', 'Sampler2DMS', 'Sampler2DMSArray', 'ISampler2D', 'ISampler3D', 'ISamplerCube', 344 'ISampler2DArray', 'ISampler2DMS', 'ISampler2DMSArray', 'USampler2D', 'USampler3D', 345 'USamplerCube', 'USampler2DArray', 'USampler2DMS', 'USampler2DMSArray', 'Sampler2DShadow', 346 'SamplerCubeShadow', 'Sampler2DArrayShadow', 'Image2D', 'IImage2D', 'UImage2D', 'Image3D', 347 'IImage3D', 'UImage3D', 'Image2DArray', 'IImage2DArray', 'UImage2DArray', 'ImageCube', 348 'IImageCube', 'UImageCube' 349] 350 351id_counter = 0 352 353 354def set_working_dir(): 355 script_dir = os.path.dirname(os.path.abspath(__file__)) 356 os.chdir(script_dir) 357 358 359def get_basic_mangled_name(basic): 360 index = basic_types_enumeration.index(basic) 361 if index < 26: 362 return '0' + chr(ord('A') + index) 363 return '0' + chr(ord('a') + index - 26) 364 365 366levels = ['ESSL3_1_BUILTINS', 'ESSL3_BUILTINS', 'ESSL1_BUILTINS', 'COMMON_BUILTINS'] 367 368 369def get_shader_version_condition_for_level(level): 370 if level == 'ESSL3_1_BUILTINS': 371 return 'shaderVersion >= 310' 372 elif level == 'ESSL3_BUILTINS': 373 return 'shaderVersion >= 300' 374 elif level == 'ESSL1_BUILTINS': 375 return 'shaderVersion == 100' 376 elif level == 'COMMON_BUILTINS': 377 return '' 378 else: 379 raise Exception('Unsupported symbol table level') 380 381 382class GroupedList: 383 """"Class for storing a list of objects grouped by symbol table level and condition.""" 384 385 def __init__(self): 386 self.objs = OrderedDict() 387 self.max_name_length = 0 388 # We need to add all the levels here instead of lazily since they must be in a specific order. 389 for l in levels: 390 self.objs[l] = OrderedDict() 391 392 def add_obj(self, level, condition, name, obj): 393 if (level not in levels): 394 raise Exception('Unexpected level: ' + str(level)) 395 if condition not in self.objs[level]: 396 self.objs[level][condition] = OrderedDict() 397 self.objs[level][condition][name] = obj 398 if len(name) > self.max_name_length: 399 self.max_name_length = len(name) 400 401 def has_key(self, level, condition, name): 402 if (level not in levels): 403 raise Exception('Unexpected level: ' + str(level)) 404 if condition not in self.objs[level]: 405 return False 406 return (name in self.objs[level][condition]) 407 408 def get(self, level, condition, name): 409 if self.has_key(level, condition, name): 410 return self.objs[level][condition][name] 411 return None 412 413 def get_max_name_length(self): 414 return self.max_name_length 415 416 def get_switch_code(self, hashfn, script_generated_hash_tests): 417 code = [] 418 for level in levels: 419 if len(self.objs[level]) == 0: 420 continue 421 level_condition = get_shader_version_condition_for_level(level) 422 if level_condition != '': 423 code.append('if ({condition})\n {{'.format(condition=level_condition)) 424 425 for condition, objs in self.objs[level].iteritems(): 426 if len(objs) > 0: 427 if condition != 'NO_CONDITION': 428 condition_header = ' if ({condition})\n {{'.format(condition=condition) 429 code.append(condition_header.replace('shaderType', 'mShaderType')) 430 431 switch = {} 432 for name, obj in objs.iteritems(): 433 name_hash = mangledNameHash(name, hashfn, script_generated_hash_tests) 434 if name_hash not in switch: 435 switch[name_hash] = [] 436 switch[name_hash].append(obj['hash_matched_code']) 437 438 code.append('switch(nameHash) {') 439 for name_hash, obj in sorted(switch.iteritems()): 440 code.append('case 0x' + ('%08x' % name_hash) + 'u:\n{') 441 code += obj 442 code.append('break;\n}') 443 code.append('}') 444 445 if condition != 'NO_CONDITION': 446 code.append('}') 447 448 if level_condition != '': 449 code.append('}') 450 code.append('return nullptr;') 451 return '\n'.join(code) 452 453 454class TType: 455 456 def __init__(self, glsl_header_type): 457 if isinstance(glsl_header_type, basestring): 458 self.data = self.parse_type(glsl_header_type) 459 else: 460 self.data = glsl_header_type 461 self.normalize() 462 463 def normalize(self): 464 # Note that this will set primarySize and secondarySize also on genTypes. In that case they 465 # are overridden when the specific types are generated. 466 if 'primarySize' not in self.data: 467 if ('secondarySize' in self.data): 468 raise Exception( 469 'Unexpected secondarySize on type that does not have primarySize set') 470 self.data['primarySize'] = 1 471 if 'secondarySize' not in self.data: 472 self.data['secondarySize'] = 1 473 if 'precision' not in self.data: 474 self.data['precision'] = 'Undefined' 475 if 'qualifier' not in self.data: 476 self.data['qualifier'] = 'Global' 477 478 def get_statictype_string(self): 479 template_type = 'StaticType::Get<Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}>()' 480 return template_type.format(**self.data) 481 482 def get_dynamic_type_string(self): 483 template_type = 'new TType(Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize})' 484 return template_type.format(**self.data) 485 486 def get_mangled_name(self): 487 mangled_name = '' 488 489 size_key = (self.data['secondarySize'] - 1) * 4 + self.data['primarySize'] - 1 490 if size_key < 10: 491 mangled_name += chr(ord('0') + size_key) 492 else: 493 mangled_name += chr(ord('A') + size_key - 10) 494 495 mangled_name += get_basic_mangled_name(self.data['basic']) 496 return mangled_name 497 498 def get_human_readable_name(self): 499 name = self.data['basic'] 500 name += str(self.data['primarySize']) 501 if self.data['secondarySize'] > 1: 502 name += 'x' + str(self.data['secondarySize']) 503 return name 504 505 def is_vector(self): 506 return self.data['primarySize'] > 1 and self.data['secondarySize'] == 1 507 508 def is_matrix(self): 509 return self.data['secondarySize'] > 1 510 511 def get_object_size(self): 512 return self.data['primarySize'] * self.data['secondarySize'] 513 514 def specific_sampler_or_image_type(self, basic_type_prefix): 515 if 'genType' in self.data: 516 type = {} 517 if 'basic' not in self.data: 518 type['basic'] = {'': 'Float', 'I': 'Int', 'U': 'UInt'}[basic_type_prefix] 519 type['primarySize'] = self.data['primarySize'] 520 else: 521 type['basic'] = basic_type_prefix + self.data['basic'] 522 type['primarySize'] = 1 523 type['precision'] = 'Undefined' 524 return TType(type) 525 return self 526 527 def specific_type(self, vec_size): 528 type = {} 529 if 'genType' in self.data: 530 type['basic'] = self.data['basic'] 531 type['precision'] = self.data['precision'] 532 type['qualifier'] = self.data['qualifier'] 533 type['primarySize'] = vec_size 534 type['secondarySize'] = 1 535 return TType(type) 536 return self 537 538 def parse_type(self, glsl_header_type): 539 if glsl_header_type.startswith('out '): 540 type_obj = self.parse_type(glsl_header_type[4:]) 541 type_obj['qualifier'] = 'Out' 542 return type_obj 543 if glsl_header_type.startswith('inout '): 544 type_obj = self.parse_type(glsl_header_type[6:]) 545 type_obj['qualifier'] = 'InOut' 546 return type_obj 547 548 basic_type_map = { 549 'float': 'Float', 550 'int': 'Int', 551 'uint': 'UInt', 552 'bool': 'Bool', 553 'void': 'Void', 554 'atomic_uint': 'AtomicCounter', 555 'yuvCscStandardEXT': 'YuvCscStandardEXT' 556 } 557 558 if glsl_header_type in basic_type_map: 559 return {'basic': basic_type_map[glsl_header_type]} 560 561 type_obj = {} 562 563 basic_type_prefix_map = {'': 'Float', 'i': 'Int', 'u': 'UInt', 'b': 'Bool', 'v': 'Void'} 564 565 vec_re = re.compile(r'^([iub]?)vec([234]?)$') 566 vec_match = vec_re.match(glsl_header_type) 567 if vec_match: 568 type_obj['basic'] = basic_type_prefix_map[vec_match.group(1)] 569 if vec_match.group(2) == '': 570 # Type like "ivec" that represents either ivec2, ivec3 or ivec4 571 type_obj['genType'] = 'vec' 572 else: 573 # vec with specific size 574 type_obj['primarySize'] = int(vec_match.group(2)) 575 return type_obj 576 577 mat_re = re.compile(r'^mat([234])(x([234]))?$') 578 mat_match = mat_re.match(glsl_header_type) 579 if mat_match: 580 type_obj['basic'] = 'Float' 581 if len(glsl_header_type) == 4: 582 mat_size = int(mat_match.group(1)) 583 type_obj['primarySize'] = mat_size 584 type_obj['secondarySize'] = mat_size 585 else: 586 type_obj['primarySize'] = int(mat_match.group(1)) 587 type_obj['secondarySize'] = int(mat_match.group(3)) 588 return type_obj 589 590 gen_re = re.compile(r'^gen([IUB]?)Type$') 591 gen_match = gen_re.match(glsl_header_type) 592 if gen_match: 593 type_obj['basic'] = basic_type_prefix_map[gen_match.group(1).lower()] 594 type_obj['genType'] = 'yes' 595 return type_obj 596 597 if glsl_header_type.startswith('sampler'): 598 type_obj['basic'] = glsl_header_type[0].upper() + glsl_header_type[1:] 599 return type_obj 600 601 if glsl_header_type.startswith('gsampler') or glsl_header_type.startswith('gimage'): 602 type_obj['basic'] = glsl_header_type[1].upper() + glsl_header_type[2:] 603 type_obj['genType'] = 'sampler_or_image' 604 return type_obj 605 606 if glsl_header_type == 'gvec4': 607 return {'primarySize': 4, 'genType': 'sampler_or_image'} 608 if glsl_header_type == 'gvec3': 609 return {'primarySize': 3, 'genType': 'sampler_or_image'} 610 611 raise Exception('Unrecognized type: ' + str(glsl_header_type)) 612 613 614class HashFunction: 615 616 def __init__(self, f1, f2, G): 617 self.f1 = f1 618 self.f2 = f2 619 self.G = G 620 621 def hash(self, key): 622 return (self.G[self.f1(key)] + self.G[self.f2(key)]) % len(self.G) 623 624 625def get_parsed_functions(functions_txt_filename): 626 627 def parse_function_parameters(parameters): 628 if parameters == '': 629 return [] 630 parametersOut = [] 631 parameters = parameters.split(', ') 632 for parameter in parameters: 633 parametersOut.append(TType(parameter.strip())) 634 return parametersOut 635 636 lines = [] 637 with open(functions_txt_filename) as f: 638 lines = f.readlines() 639 lines = [ 640 line.strip() for line in lines if line.strip() != '' and not line.strip().startswith('//') 641 ] 642 643 fun_re = re.compile(r'^(\w+) (\w+)\((.*)\);$') 644 645 parsed_functions = OrderedDict() 646 group_stack = [] 647 default_metadata = {} 648 649 for line in lines: 650 fun_match = fun_re.match(line) 651 if line.startswith('GROUP BEGIN '): 652 group_rest = line[12:].strip() 653 group_parts = group_rest.split(' ', 1) 654 current_group = {'functions': [], 'name': group_parts[0], 'subgroups': {}} 655 if len(group_parts) > 1: 656 group_metadata = json.loads(group_parts[1]) 657 current_group.update(group_metadata) 658 group_stack.append(current_group) 659 elif line.startswith('GROUP END '): 660 group_end_name = line[10:].strip() 661 current_group = group_stack[-1] 662 if current_group['name'] != group_end_name: 663 raise Exception('GROUP END: Unexpected function group name "' + group_end_name + 664 '" was expecting "' + current_group['name'] + '"') 665 group_stack.pop() 666 is_top_level_group = (len(group_stack) == 0) 667 if is_top_level_group: 668 parsed_functions[current_group['name']] = current_group 669 default_metadata = {} 670 else: 671 super_group = group_stack[-1] 672 super_group['subgroups'][current_group['name']] = current_group 673 elif line.startswith('DEFAULT METADATA'): 674 line_rest = line[16:].strip() 675 default_metadata = json.loads(line_rest) 676 elif fun_match: 677 return_type = fun_match.group(1) 678 name = fun_match.group(2) 679 parameters = fun_match.group(3) 680 function_props = { 681 'name': name, 682 'returnType': TType(return_type), 683 'parameters': parse_function_parameters(parameters) 684 } 685 function_props.update(default_metadata) 686 group_stack[-1]['functions'].append(function_props) 687 else: 688 raise Exception('Unexpected function input line: ' + line) 689 690 return parsed_functions 691 692 693def mangledNameHash(str, hashfn, script_generated_hash_tests, save_test=True): 694 hash = hashfn.hash(str) 695 if save_test: 696 sanity_check = ' ASSERT_EQ(0x{hash}u, ImmutableString("{str}").mangledNameHash());'.format( 697 hash=('%08x' % hash), str=str) 698 script_generated_hash_tests.update({sanity_check: None}) 699 return hash 700 701 702def get_function_names(group, mangled_names): 703 if 'functions' in group: 704 for function_props in group['functions']: 705 function_name = function_props['name'] 706 mangled_names.append(function_name) 707 function_variants = gen_function_variants(function_name, function_props) 708 for function_props in function_variants: 709 parameters = get_parameters(function_props) 710 mangled_names.append(get_function_mangled_name(function_name, parameters)) 711 if 'subgroups' in group: 712 for subgroup_name, subgroup in group['subgroups'].iteritems(): 713 get_function_names(subgroup, mangled_names) 714 715 716def get_variable_names(group, mangled_names): 717 if 'variables' in group: 718 for variable_name, props in group['variables'].iteritems(): 719 mangled_names.append(variable_name) 720 if 'subgroups' in group: 721 for subgroup_name, subgroup in group['subgroups'].iteritems(): 722 get_variable_names(subgroup, mangled_names) 723 724 725def get_suffix(props): 726 if 'suffix' in props: 727 return props['suffix'] 728 return '' 729 730 731def get_extension(props): 732 if 'extension' in props: 733 return props['extension'] 734 return 'UNDEFINED' 735 736 737def get_op(name, function_props): 738 if 'op' not in function_props: 739 raise Exception('function op not defined') 740 if function_props['op'] == 'auto': 741 return name[0].upper() + name[1:] 742 return function_props['op'] 743 744 745def get_known_to_not_have_side_effects(function_props): 746 if 'op' in function_props and function_props['op'] != 'CallBuiltInFunction': 747 if 'hasSideEffects' in function_props: 748 return 'false' 749 else: 750 for param in get_parameters(function_props): 751 if 'qualifier' in param.data and (param.data['qualifier'] == 'Out' or 752 param.data['qualifier'] == 'InOut'): 753 return 'false' 754 return 'true' 755 return 'false' 756 757 758def get_parameters(function_props): 759 if 'parameters' in function_props: 760 return function_props['parameters'] 761 return [] 762 763 764def get_function_mangled_name(function_name, parameters): 765 mangled_name = function_name + '(' 766 for param in parameters: 767 mangled_name += param.get_mangled_name() 768 return mangled_name 769 770 771def get_function_human_readable_name(function_name, parameters): 772 name = function_name 773 for param in parameters: 774 name += '_' + param.get_human_readable_name() 775 return name 776 777 778def get_unique_identifier_name(function_name, parameters): 779 unique_name = function_name + '_' 780 for param in parameters: 781 unique_name += param.get_mangled_name() 782 return unique_name 783 784 785def get_variable_name_to_store_parameter(param): 786 unique_name = 'pt' 787 if 'qualifier' in param.data: 788 if param.data['qualifier'] == 'Out': 789 unique_name += '_o_' 790 if param.data['qualifier'] == 'InOut': 791 unique_name += '_io_' 792 unique_name += param.get_mangled_name() 793 return unique_name 794 795 796def get_variable_name_to_store_parameters(parameters): 797 if len(parameters) == 0: 798 return 'empty' 799 unique_name = 'p' 800 for param in parameters: 801 if 'qualifier' in param.data: 802 if param.data['qualifier'] == 'Out': 803 unique_name += '_o_' 804 if param.data['qualifier'] == 'InOut': 805 unique_name += '_io_' 806 unique_name += param.get_mangled_name() 807 return unique_name 808 809 810def define_constexpr_variable(template_args, variable_declarations): 811 template_variable_declaration = 'constexpr const TVariable kVar_{name_with_suffix}(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, TExtension::{extension}, {type});' 812 variable_declarations.append(template_variable_declaration.format(**template_args)) 813 814 815def gen_function_variants(function_name, function_props): 816 function_variants = [] 817 parameters = get_parameters(function_props) 818 function_is_gen_type = False 819 gen_type = set() 820 for param in parameters: 821 if 'genType' in param.data: 822 if param.data['genType'] not in ['sampler_or_image', 'vec', 'yes']: 823 raise Exception('Unexpected value of genType "' + str(param.data['genType']) + 824 '" should be "sampler_or_image", "vec", or "yes"') 825 gen_type.add(param.data['genType']) 826 if len(gen_type) > 1: 827 raise Exception('Unexpected multiple values of genType set on the same function: ' 828 + str(list(gen_type))) 829 if len(gen_type) == 0: 830 function_variants.append(function_props) 831 return function_variants 832 833 # If we have a gsampler_or_image then we're generating variants for float, int and uint 834 # samplers. 835 if 'sampler_or_image' in gen_type: 836 types = ['', 'I', 'U'] 837 for type in types: 838 variant_props = function_props.copy() 839 variant_parameters = [] 840 for param in parameters: 841 variant_parameters.append(param.specific_sampler_or_image_type(type)) 842 variant_props['parameters'] = variant_parameters 843 variant_props['returnType'] = function_props[ 844 'returnType'].specific_sampler_or_image_type(type) 845 function_variants.append(variant_props) 846 return function_variants 847 848 # If we have a normal gentype then we're generating variants for different sizes of vectors. 849 sizes = range(1, 5) 850 if 'vec' in gen_type: 851 sizes = range(2, 5) 852 for size in sizes: 853 variant_props = function_props.copy() 854 variant_parameters = [] 855 for param in parameters: 856 variant_parameters.append(param.specific_type(size)) 857 variant_props['parameters'] = variant_parameters 858 variant_props['returnType'] = function_props['returnType'].specific_type(size) 859 function_variants.append(variant_props) 860 return function_variants 861 862 863def process_single_function_group( 864 condition, group_name, group, parameter_declarations, name_declarations, 865 unmangled_function_if_statements, unmangled_builtin_declarations, 866 defined_function_variants, builtin_id_declarations, builtin_id_definitions, 867 defined_parameter_names, variable_declarations, function_declarations, 868 script_generated_hash_tests, get_builtin_if_statements): 869 global id_counter 870 871 if 'functions' not in group: 872 return 873 874 for function_props in group['functions']: 875 function_name = function_props['name'] 876 level = function_props['level'] 877 extension = get_extension(function_props) 878 template_args = { 879 'name': function_name, 880 'name_with_suffix': function_name + get_suffix(function_props), 881 'level': level, 882 'extension': extension, 883 'op': get_op(function_name, function_props), 884 'known_to_not_have_side_effects': get_known_to_not_have_side_effects(function_props) 885 } 886 887 function_variants = gen_function_variants(function_name, function_props) 888 889 template_name_declaration = 'constexpr const ImmutableString {name_with_suffix}("{name}");' 890 name_declaration = template_name_declaration.format(**template_args) 891 if not name_declaration in name_declarations: 892 name_declarations.add(name_declaration) 893 894 template_unmangled_if = """if (name == BuiltInName::{name_with_suffix}) 895{{ 896 return &UnmangledBuiltIns::{extension}; 897}}""" 898 unmangled_if = template_unmangled_if.format(**template_args) 899 unmangled_builtin_no_condition = unmangled_function_if_statements.get( 900 level, 'NO_CONDITION', function_name) 901 if unmangled_builtin_no_condition != None and unmangled_builtin_no_condition[ 902 'extension'] == 'UNDEFINED': 903 # We already have this unmangled name without a condition nor extension on the same level. No need to add a duplicate with a condition. 904 pass 905 elif (not unmangled_function_if_statements.has_key( 906 level, condition, function_name)) or extension == 'UNDEFINED': 907 # We don't have this unmangled builtin recorded yet or we might replace an unmangled builtin from an extension with one from core. 908 unmangled_function_if_statements.add_obj(level, condition, function_name, { 909 'hash_matched_code': unmangled_if, 910 'extension': extension 911 }) 912 unmangled_builtin_declarations.add( 913 'constexpr const UnmangledBuiltIn {extension}(TExtension::{extension});'.format( 914 **template_args)) 915 916 for function_props in function_variants: 917 template_args['id'] = id_counter 918 919 parameters = get_parameters(function_props) 920 921 template_args['unique_name'] = get_unique_identifier_name( 922 template_args['name_with_suffix'], parameters) 923 924 if template_args['unique_name'] in defined_function_variants: 925 continue 926 defined_function_variants.add(template_args['unique_name']) 927 928 template_args['param_count'] = len(parameters) 929 template_args['return_type'] = function_props['returnType'].get_statictype_string() 930 template_args['mangled_name'] = get_function_mangled_name(function_name, parameters) 931 template_args['human_readable_name'] = get_function_human_readable_name( 932 template_args['name_with_suffix'], parameters) 933 template_args['mangled_name_length'] = len(template_args['mangled_name']) 934 935 template_builtin_id_declaration = ' static constexpr const TSymbolUniqueId {human_readable_name} = TSymbolUniqueId({id});' 936 builtin_id_declarations.append(template_builtin_id_declaration.format(**template_args)) 937 template_builtin_id_definition = 'constexpr const TSymbolUniqueId BuiltInId::{human_readable_name};' 938 builtin_id_definitions.append(template_builtin_id_definition.format(**template_args)) 939 940 parameters_list = [] 941 for param in parameters: 942 unique_param_name = get_variable_name_to_store_parameter(param) 943 param_template_args = { 944 'name': '_empty', 945 'name_with_suffix': unique_param_name, 946 'type': param.get_statictype_string(), 947 'extension': 'UNDEFINED' 948 } 949 if unique_param_name not in defined_parameter_names: 950 id_counter += 1 951 param_template_args['id'] = id_counter 952 template_builtin_id_declaration = ' static constexpr const TSymbolUniqueId {name_with_suffix} = TSymbolUniqueId({id});' 953 builtin_id_declarations.append( 954 template_builtin_id_declaration.format(**param_template_args)) 955 define_constexpr_variable(param_template_args, variable_declarations) 956 defined_parameter_names.add(unique_param_name) 957 parameters_list.append( 958 '&BuiltInVariable::kVar_{name_with_suffix}'.format(**param_template_args)) 959 960 template_args['parameters_var_name'] = get_variable_name_to_store_parameters( 961 parameters) 962 if len(parameters) > 0: 963 template_args['parameters_list'] = ', '.join(parameters_list) 964 template_parameter_list_declaration = 'constexpr const TVariable *{parameters_var_name}[{param_count}] = {{ {parameters_list} }};' 965 parameter_declarations[template_args[ 966 'parameters_var_name']] = template_parameter_list_declaration.format( 967 **template_args) 968 else: 969 template_parameter_list_declaration = 'constexpr const TVariable **{parameters_var_name} = nullptr;' 970 parameter_declarations[template_args[ 971 'parameters_var_name']] = template_parameter_list_declaration.format( 972 **template_args) 973 974 template_function_declaration = 'constexpr const TFunction kFunction_{unique_name}(BuiltInId::{human_readable_name}, BuiltInName::{name_with_suffix}, TExtension::{extension}, BuiltInParameters::{parameters_var_name}, {param_count}, {return_type}, EOp{op}, {known_to_not_have_side_effects});' 975 function_declarations.append(template_function_declaration.format(**template_args)) 976 977 template_mangled_name_declaration = 'constexpr const ImmutableString {unique_name}("{mangled_name}");' 978 name_declarations.add(template_mangled_name_declaration.format(**template_args)) 979 template_mangled_if = """if (name == BuiltInName::{unique_name}) 980{{ 981 return &BuiltInFunction::kFunction_{unique_name}; 982}}""" 983 mangled_if = template_mangled_if.format(**template_args) 984 get_builtin_if_statements.add_obj(level, condition, template_args['mangled_name'], 985 {'hash_matched_code': mangled_if}) 986 987 id_counter += 1 988 989 990def process_function_group(group_name, group, parameter_declarations, name_declarations, 991 unmangled_function_if_statements, unmangled_builtin_declarations, 992 defined_function_variants, builtin_id_declarations, 993 builtin_id_definitions, defined_parameter_names, variable_declarations, 994 function_declarations, script_generated_hash_tests, 995 get_builtin_if_statements, is_in_group_definitions): 996 global id_counter 997 first_id = id_counter 998 999 condition = 'NO_CONDITION' 1000 if 'condition' in group: 1001 condition = group['condition'] 1002 1003 process_single_function_group( 1004 condition, group_name, group, parameter_declarations, name_declarations, 1005 unmangled_function_if_statements, unmangled_builtin_declarations, 1006 defined_function_variants, builtin_id_declarations, builtin_id_definitions, 1007 defined_parameter_names, variable_declarations, function_declarations, 1008 script_generated_hash_tests, get_builtin_if_statements) 1009 1010 if 'subgroups' in group: 1011 for subgroup_name, subgroup in group['subgroups'].iteritems(): 1012 process_function_group( 1013 group_name + subgroup_name, subgroup, parameter_declarations, name_declarations, 1014 unmangled_function_if_statements, unmangled_builtin_declarations, 1015 defined_function_variants, builtin_id_declarations, builtin_id_definitions, 1016 defined_parameter_names, variable_declarations, function_declarations, 1017 script_generated_hash_tests, get_builtin_if_statements, is_in_group_definitions) 1018 1019 if 'queryFunction' in group: 1020 template_args = {'first_id': first_id, 'last_id': id_counter - 1, 'group_name': group_name} 1021 template_is_in_group_definition = """bool is{group_name}(const TFunction *func) 1022{{ 1023 int id = func->uniqueId().get(); 1024 return id >= {first_id} && id <= {last_id}; 1025}}""" 1026 is_in_group_definitions.append(template_is_in_group_definition.format(**template_args)) 1027 1028 1029def prune_parameters_arrays(parameter_declarations, function_declarations): 1030 # We can share parameters arrays between functions in case one array is a subarray of another. 1031 parameter_variable_name_replacements = {} 1032 used_param_variable_names = set() 1033 for param_variable_name, param_declaration in sorted( 1034 parameter_declarations.iteritems(), key=lambda item: -len(item[0])): 1035 replaced = False 1036 for used in used_param_variable_names: 1037 if used.startswith(param_variable_name): 1038 parameter_variable_name_replacements[param_variable_name] = used 1039 replaced = True 1040 break 1041 if not replaced: 1042 used_param_variable_names.add(param_variable_name) 1043 1044 for i in xrange(len(function_declarations)): 1045 for replaced, replacement in parameter_variable_name_replacements.iteritems(): 1046 function_declarations[i] = function_declarations[i].replace( 1047 'BuiltInParameters::' + replaced + ',', 'BuiltInParameters::' + replacement + ',') 1048 1049 return [ 1050 value for key, value in parameter_declarations.iteritems() 1051 if key in used_param_variable_names 1052 ] 1053 1054 1055def process_single_variable_group(condition, group_name, group, builtin_id_declarations, 1056 builtin_id_definitions, name_declarations, init_member_variables, 1057 get_variable_declarations, get_builtin_if_statements, 1058 declare_member_variables, variable_declarations, 1059 get_variable_definitions, variable_name_count): 1060 global id_counter 1061 if 'variables' not in group: 1062 return 1063 for variable_name, props in group['variables'].iteritems(): 1064 level = props['level'] 1065 template_args = { 1066 'id': id_counter, 1067 'name': variable_name, 1068 'name_with_suffix': variable_name + get_suffix(props), 1069 'level': props['level'], 1070 'extension': get_extension(props), 1071 'class': 'TVariable' 1072 } 1073 1074 template_builtin_id_declaration = ' static constexpr const TSymbolUniqueId {name_with_suffix} = TSymbolUniqueId({id});' 1075 builtin_id_declarations.append(template_builtin_id_declaration.format(**template_args)) 1076 template_builtin_id_definition = 'constexpr const TSymbolUniqueId BuiltInId::{name_with_suffix};' 1077 builtin_id_definitions.append(template_builtin_id_definition.format(**template_args)) 1078 1079 template_name_declaration = 'constexpr const ImmutableString {name}("{name}");' 1080 name_declarations.add(template_name_declaration.format(**template_args)) 1081 1082 is_member = True 1083 template_init_variable = '' 1084 1085 if 'type' in props: 1086 if props['type']['basic'] != 'Bool' and 'precision' not in props['type']: 1087 raise Exception('Missing precision for variable ' + variable_name) 1088 template_args['type'] = TType(props['type']).get_statictype_string() 1089 1090 if 'fields' in props: 1091 # Handle struct and interface block definitions. 1092 template_args['class'] = props['class'] 1093 template_args['fields'] = 'fields_{name_with_suffix}'.format(**template_args) 1094 init_member_variables.append( 1095 ' TFieldList *{fields} = new TFieldList();'.format(**template_args)) 1096 for field_name, field_type in props['fields'].iteritems(): 1097 template_args['field_name'] = field_name 1098 template_args['field_type'] = TType(field_type).get_dynamic_type_string() 1099 template_name_declaration = 'constexpr const ImmutableString {field_name}("{field_name}");' 1100 name_declarations.add(template_name_declaration.format(**template_args)) 1101 template_add_field = ' {fields}->push_back(new TField({field_type}, BuiltInName::{field_name}, zeroSourceLoc, SymbolType::BuiltIn));' 1102 init_member_variables.append(template_add_field.format(**template_args)) 1103 template_init_temp_variable = ' {class} *{name_with_suffix} = new {class}(BuiltInId::{name_with_suffix}, BuiltInName::{name}, TExtension::{extension}, {fields});' 1104 init_member_variables.append(template_init_temp_variable.format(**template_args)) 1105 if 'private' in props and props['private']: 1106 is_member = False 1107 else: 1108 template_init_variable = ' mVar_{name_with_suffix} = {name_with_suffix};' 1109 1110 elif 'initDynamicType' in props: 1111 # Handle variables whose type can't be expressed as TStaticType 1112 # (type is a struct or has variable array size for example). 1113 template_args['type_name'] = 'type_{name_with_suffix}'.format(**template_args) 1114 template_args['type'] = template_args['type_name'] 1115 template_args['initDynamicType'] = props['initDynamicType'].format(**template_args) 1116 template_init_variable = """ {initDynamicType} 1117 {type_name}->realize(); 1118 mVar_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, TExtension::{extension}, {type});""" 1119 1120 elif 'value' in props: 1121 # Handle variables with constant value, such as gl_MaxDrawBuffers. 1122 if props['value'] != 'resources': 1123 raise Exception('Unrecognized value source in variable properties: ' + 1124 str(props['value'])) 1125 resources_key = variable_name[3:] 1126 if 'valueKey' in props: 1127 resources_key = props['valueKey'] 1128 template_args['value'] = 'resources.' + resources_key 1129 template_args['object_size'] = TType(props['type']).get_object_size() 1130 template_init_variable = """ mVar_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, TExtension::{extension}, {type}); 1131 {{ 1132 TConstantUnion *unionArray = new TConstantUnion[{object_size}]; 1133 unionArray[0].setIConst({value}); 1134 mVar_{name_with_suffix}->shareConstPointer(unionArray); 1135 }}""" 1136 if template_args['object_size'] > 1: 1137 template_init_variable = """ mVar_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, TExtension::{extension}, {type}); 1138 {{ 1139 TConstantUnion *unionArray = new TConstantUnion[{object_size}]; 1140 for (size_t index = 0u; index < {object_size}; ++index) 1141 {{ 1142 unionArray[index].setIConst({value}[index]); 1143 }} 1144 mVar_{name_with_suffix}->shareConstPointer(unionArray); 1145 }}""" 1146 1147 else: 1148 # Handle variables that can be stored as constexpr TVariable like 1149 # gl_Position, gl_FragColor etc. 1150 define_constexpr_variable(template_args, variable_declarations) 1151 is_member = False 1152 1153 template_get_variable_declaration = 'const TVariable *{name_with_suffix}();' 1154 get_variable_declarations.append( 1155 template_get_variable_declaration.format(**template_args)) 1156 1157 template_get_variable_definition = """const TVariable *{name_with_suffix}() 1158{{ 1159 return &kVar_{name_with_suffix}; 1160}} 1161""" 1162 get_variable_definitions.append( 1163 template_get_variable_definition.format(**template_args)) 1164 1165 if level != 'GLSL_BUILTINS': 1166 template_name_if = """if (name == BuiltInName::{name}) 1167{{ 1168 return &BuiltInVariable::kVar_{name_with_suffix}; 1169}}""" 1170 name_if = template_name_if.format(**template_args) 1171 get_builtin_if_statements.add_obj(level, condition, template_args['name'], 1172 {'hash_matched_code': name_if}) 1173 1174 if is_member: 1175 get_condition = condition 1176 init_conditionally = ( 1177 condition != 'NO_CONDITION' and variable_name_count[variable_name] == 1) 1178 if init_conditionally: 1179 # Instead of having the condition if statement at lookup, it's cheaper to have it at initialization time. 1180 init_member_variables.append( 1181 ' if ({condition})\n {{'.format(condition=condition)) 1182 template_args[ 1183 'condition_comment'] = '\n // Only initialized if {condition}'.format( 1184 condition=condition) 1185 get_condition = 'NO_CONDITION' 1186 else: 1187 template_args['condition_comment'] = '' 1188 init_member_variables.append(template_init_variable.format(**template_args)) 1189 if init_conditionally: 1190 init_member_variables.append(' }') 1191 1192 template_declare_member_variable = '{class} *mVar_{name_with_suffix} = nullptr;' 1193 declare_member_variables.append( 1194 template_declare_member_variable.format(**template_args)) 1195 1196 if level != 'GLSL_BUILTINS': 1197 template_name_if = """if (name == BuiltInName::{name}) 1198{{{condition_comment} 1199 return mVar_{name_with_suffix}; 1200}}""" 1201 name_if = template_name_if.format(**template_args) 1202 get_builtin_if_statements.add_obj(level, get_condition, variable_name, 1203 {'hash_matched_code': name_if}) 1204 1205 id_counter += 1 1206 1207 1208def count_variable_names(group, variable_name_count): 1209 if 'variables' in group: 1210 for name in group['variables'].iterkeys(): 1211 if name not in variable_name_count: 1212 variable_name_count[name] = 1 1213 else: 1214 variable_name_count[name] += 1 1215 if 'subgroups' in group: 1216 for subgroup_name, subgroup in group['subgroups'].iteritems(): 1217 count_variable_names(subgroup, variable_name_count) 1218 1219 1220def process_variable_group(parent_condition, group_name, group, builtin_id_declarations, 1221 builtin_id_definitions, name_declarations, init_member_variables, 1222 get_variable_declarations, get_builtin_if_statements, 1223 declare_member_variables, variable_declarations, 1224 get_variable_definitions, variable_name_count): 1225 global id_counter 1226 condition = 'NO_CONDITION' 1227 if 'condition' in group: 1228 condition = group['condition'] 1229 1230 if parent_condition != 'NO_CONDITION': 1231 if condition == 'NO_CONDITION': 1232 condition = parent_condition 1233 else: 1234 condition = '({cond1}) && ({cond2})'.format(cond1=parent_condition, cond2=condition) 1235 1236 process_single_variable_group(condition, group_name, group, builtin_id_declarations, 1237 builtin_id_definitions, name_declarations, init_member_variables, 1238 get_variable_declarations, get_builtin_if_statements, 1239 declare_member_variables, variable_declarations, 1240 get_variable_definitions, variable_name_count) 1241 1242 if 'subgroups' in group: 1243 for subgroup_name, subgroup in group['subgroups'].iteritems(): 1244 process_variable_group( 1245 condition, subgroup_name, subgroup, builtin_id_declarations, 1246 builtin_id_definitions, name_declarations, init_member_variables, 1247 get_variable_declarations, get_builtin_if_statements, declare_member_variables, 1248 variable_declarations, get_variable_definitions, variable_name_count) 1249 1250 1251def main(): 1252 random.seed(0) 1253 set_working_dir() 1254 1255 parser = argparse.ArgumentParser() 1256 parser.add_argument( 1257 '--dump-intermediate-json', 1258 help='Dump parsed function data as a JSON file builtin_functions.json', 1259 action="store_true") 1260 parser.add_argument('auto_script_command', nargs='?', default='') 1261 args = parser.parse_args() 1262 1263 test_filename = '../../tests/compiler_tests/ImmutableString_test_autogen.cpp' 1264 variables_json_filename = 'builtin_variables.json' 1265 functions_txt_filename = 'builtin_function_declarations.txt' 1266 1267 # auto_script parameters. 1268 if args.auto_script_command != '': 1269 inputs = [ 1270 functions_txt_filename, 1271 variables_json_filename, 1272 ] 1273 outputs = [ 1274 'ImmutableString_autogen.cpp', 1275 'ParseContext_autogen.h', 1276 'SymbolTable_autogen.cpp', 1277 'SymbolTable_autogen.h', 1278 'tree_util/BuiltIn_autogen.h', 1279 test_filename, 1280 ] 1281 1282 if args.auto_script_command == 'inputs': 1283 print ','.join(inputs) 1284 elif args.auto_script_command == 'outputs': 1285 print ','.join(outputs) 1286 else: 1287 print('Invalid script parameters') 1288 return 1 1289 return 0 1290 1291 # Declarations of symbol unique ids 1292 builtin_id_declarations = [] 1293 1294 # Definitions of symbol unique ids needed for those ids used outside of constexpr expressions. 1295 builtin_id_definitions = [] 1296 1297 # Declarations of name string variables 1298 name_declarations = set() 1299 1300 # Declarations of builtin TVariables 1301 variable_declarations = [] 1302 1303 # Declarations of builtin TFunctions 1304 function_declarations = [] 1305 1306 # Functions for querying the pointer to a specific TVariable. 1307 get_variable_declarations = [] 1308 get_variable_definitions = [] 1309 1310 # Code for defining TVariables stored as members of TSymbolTable. 1311 declare_member_variables = [] 1312 init_member_variables = [] 1313 1314 # Code for querying builtins. 1315 get_builtin_if_statements = GroupedList() 1316 1317 # Declarations of UnmangledBuiltIn objects 1318 unmangled_builtin_declarations = set() 1319 1320 # Code for querying builtin function unmangled names. 1321 unmangled_function_if_statements = GroupedList() 1322 1323 # Code for testing that script-generated hashes match with runtime computed hashes. 1324 script_generated_hash_tests = OrderedDict() 1325 1326 # Functions for testing whether a builtin belongs in group. 1327 is_in_group_definitions = [] 1328 1329 # Counts of variables with a certain name string: 1330 variable_name_count = {} 1331 1332 # Declarations of parameter arrays for builtin TFunctions. Map from C++ variable name to the full 1333 # declaration. 1334 parameter_declarations = {} 1335 1336 defined_function_variants = set() 1337 defined_parameter_names = set() 1338 1339 parsed_functions = get_parsed_functions(functions_txt_filename) 1340 1341 if args.dump_intermediate_json: 1342 with open('builtin_functions.json', 'w') as outfile: 1343 1344 def serialize_obj(obj): 1345 if isinstance(obj, TType): 1346 return obj.data 1347 else: 1348 raise "Cannot serialize to JSON: " + str(obj) 1349 1350 json.dump( 1351 parsed_functions, outfile, indent=4, separators=(',', ': '), default=serialize_obj) 1352 1353 with open(variables_json_filename) as f: 1354 parsed_variables = json.load(f, object_pairs_hook=OrderedDict) 1355 1356 # This script uses a perfect hash function to avoid dealing with collisions 1357 names = [] 1358 for group_name, group in parsed_functions.iteritems(): 1359 get_function_names(group, names) 1360 for group_name, group in parsed_variables.iteritems(): 1361 get_variable_names(group, names) 1362 # Remove duplicates 1363 names = list(dict.fromkeys(names)) 1364 names_dict = dict(zip(names, range(1, len(names) + 1))) 1365 # Generate the perfect hash function 1366 f1, f2, G = generate_hash(names_dict, Hash2) 1367 hashfn = HashFunction(f1, f2, G) 1368 S1 = f1.salt 1369 S2 = f2.salt 1370 1371 for group_name, group in parsed_functions.iteritems(): 1372 process_function_group( 1373 group_name, group, parameter_declarations, name_declarations, 1374 unmangled_function_if_statements, unmangled_builtin_declarations, 1375 defined_function_variants, builtin_id_declarations, builtin_id_definitions, 1376 defined_parameter_names, variable_declarations, function_declarations, 1377 script_generated_hash_tests, get_builtin_if_statements, is_in_group_definitions) 1378 1379 parameter_declarations = prune_parameters_arrays(parameter_declarations, function_declarations) 1380 1381 for group_name, group in parsed_variables.iteritems(): 1382 count_variable_names(group, variable_name_count) 1383 1384 for group_name, group in parsed_variables.iteritems(): 1385 process_variable_group('NO_CONDITION', group_name, group, builtin_id_declarations, 1386 builtin_id_definitions, name_declarations, init_member_variables, 1387 get_variable_declarations, get_builtin_if_statements, 1388 declare_member_variables, variable_declarations, 1389 get_variable_definitions, variable_name_count) 1390 1391 output_strings = { 1392 'script_name': 1393 os.path.basename(__file__), 1394 'copyright_year': 1395 date.today().year, 1396 'builtin_id_declarations': 1397 '\n'.join(builtin_id_declarations), 1398 'builtin_id_definitions': 1399 '\n'.join(builtin_id_definitions), 1400 'last_builtin_id': 1401 id_counter - 1, 1402 'name_declarations': 1403 '\n'.join(sorted(list(name_declarations))), 1404 'function_data_source_name': 1405 functions_txt_filename, 1406 'function_declarations': 1407 '\n'.join(function_declarations), 1408 'parameter_declarations': 1409 '\n'.join(sorted(parameter_declarations)), 1410 'is_in_group_definitions': 1411 '\n'.join(is_in_group_definitions), 1412 'variable_data_source_name': 1413 variables_json_filename, 1414 'variable_declarations': 1415 '\n'.join(sorted(variable_declarations)), 1416 'get_variable_declarations': 1417 '\n'.join(sorted(get_variable_declarations)), 1418 'get_variable_definitions': 1419 '\n'.join(sorted(get_variable_definitions)), 1420 'unmangled_builtin_declarations': 1421 '\n'.join(sorted(unmangled_builtin_declarations)), 1422 'declare_member_variables': 1423 '\n'.join(declare_member_variables), 1424 'init_member_variables': 1425 '\n'.join(init_member_variables), 1426 'get_unmangled_builtin': 1427 unmangled_function_if_statements.get_switch_code(hashfn, script_generated_hash_tests), 1428 'get_builtin': 1429 get_builtin_if_statements.get_switch_code(hashfn, script_generated_hash_tests), 1430 'max_unmangled_name_length': 1431 unmangled_function_if_statements.get_max_name_length(), 1432 'max_mangled_name_length': 1433 get_builtin_if_statements.get_max_name_length(), 1434 'script_generated_hash_tests': 1435 '\n'.join(script_generated_hash_tests.iterkeys()), 1436 'S1': 1437 str(S1).replace('[', ' ').replace(']', ' '), 1438 'S2': 1439 str(S2).replace('[', ' ').replace(']', ' '), 1440 'G': 1441 str(G).replace('[', ' ').replace(']', ' '), 1442 'NG': 1443 len(G), 1444 'NS': 1445 len(S1) 1446 } 1447 1448 with open('ImmutableString_autogen.cpp', 'wt') as outfile_cpp: 1449 output_cpp = template_immutablestring_cpp.format(**output_strings) 1450 outfile_cpp.write(output_cpp) 1451 1452 with open(test_filename, 'wt') as outfile_cpp: 1453 output_cpp = template_immutablestringtest_cpp.format(**output_strings) 1454 outfile_cpp.write(output_cpp) 1455 1456 with open('tree_util/BuiltIn_autogen.h', 'wt') as outfile_header: 1457 output_header = template_builtin_header.format(**output_strings) 1458 outfile_header.write(output_header) 1459 1460 with open('SymbolTable_autogen.cpp', 'wt') as outfile_cpp: 1461 output_cpp = template_symboltable_cpp.format(**output_strings) 1462 outfile_cpp.write(output_cpp) 1463 1464 with open('ParseContext_autogen.h', 'wt') as outfile_header: 1465 output_header = template_parsecontext_header.format(**output_strings) 1466 outfile_header.write(output_header) 1467 1468 with open('SymbolTable_autogen.h', 'wt') as outfile_h: 1469 output_h = template_symboltable_h.format(**output_strings) 1470 outfile_h.write(output_h) 1471 1472 return 0 1473 1474 1475if __name__ == '__main__': 1476 sys.exit(main()) 1477