text: //
  // Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
  // Copyright (C) 2012-2013 LunarG, Inc.
  // Copyright (C) 2017 ARM Limited.
  // Copyright (C) 2015-2020 Google, Inc.
  // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
  //
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions
  // are met:
  //
  //    Redistributions of source code must retain the above copyright
  //    notice, this list of conditions and the following disclaimer.
  //
  //    Redistributions in binary form must reproduce the above
  //    copyright notice, this list of conditions and the following
  //    disclaimer in the documentation and/or other materials provided
  //    with the distribution.
  //
  //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
  //    contributors may be used to endorse or promote products derived
  //    from this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  // POSSIBILITY OF SUCH DAMAGE.
  //
  
  //
  // Help manage multiple profiles, versions, extensions etc.
  //
  // These don't return error codes, as the presumption is parsing will
  // always continue as if the tested feature were enabled, and thus there
  // is no error recovery needed.
  //
  
  //
  // HOW TO add a feature enabled by an extension.
  //
  // To add a new hypothetical "Feature F" to the front end, where an extension
  // "XXX_extension_X" can be used to enable the feature, do the following.
  //
  // OVERVIEW: Specific features are what are error-checked for, not
  //    extensions:  A specific Feature F might be enabled by an extension, or a
  //    particular version in a particular profile, or a stage, or combinations, etc.
  //
  //    The basic mechanism is to use the following to "declare" all the things that
  //    enable/disable Feature F, in a code path that implements Feature F:
  //
  //        requireProfile()
  //        profileRequires()
  //        requireStage()
  //        checkDeprecated()
  //        requireNotRemoved()
  //        requireExtensions()
  //        extensionRequires()
  //
  //    Typically, only the first two calls are needed.  They go into a code path that
  //    implements Feature F, and will log the proper error/warning messages.  Parsing
  //    will then always continue as if the tested feature was enabled.
  //
  //    There is typically no if-testing or conditional parsing, just insertion of the calls above.
  //    However, if symbols specific to the extension are added (step 5), they will
  //    only be added under tests that the minimum version and profile are present.
  //
  // 1) Add a symbol name for the extension string at the bottom of Versions.h:
  //
  //     const char* const XXX_extension_X = "XXX_extension_X";
  //
  // 2) Add extension initialization to TParseVersions::initializeExtensionBehavior(),
  //    the first function below and optionally a entry to extensionData for additional
  //    error checks:
  //
  //     extensionBehavior[XXX_extension_X] = EBhDisable;
  //     (Optional) exts[] = {XXX_extension_X, EShTargetSpv_1_4}
  //
  // 3) Add any preprocessor directives etc. in the next function, TParseVersions::getPreamble():
  //
  //           "#define XXX_extension_X 1\n"
  //
  //    The new-line is important, as that ends preprocess tokens.
  //
  // 4) Insert a profile check in the feature's path (unless all profiles support the feature,
  //    for some version level).  That is, call requireProfile() to constrain the profiles, e.g.:
  //
  //         // ... in a path specific to Feature F...
  //         requireProfile(loc,
  //                        ECoreProfile | ECompatibilityProfile,
  //                        "Feature F");
  //
  // 5) For each profile that supports the feature, insert version/extension checks:
  //
  //    The mostly likely scenario is that Feature F can only be used with a
  //    particular profile if XXX_extension_X is present or the version is
  //    high enough that the core specification already incorporated it.
  //
  //        // following the requireProfile() call...
  //        profileRequires(loc,
  //                        ECoreProfile | ECompatibilityProfile,
  //                        420,             // 0 if no version incorporated the feature into the core spec.
  //                        XXX_extension_X, // can be a list of extensions that all add the feature
  //                        "Feature F Description");
  //
  //    This allows the feature if either A) one of the extensions is enabled or
  //    B) the version is high enough.  If no version yet incorporates the feature
  //    into core, pass in 0.
  //
  //    This can be called multiple times, if different profiles support the
  //    feature starting at different version numbers or with different
  //    extensions.
  //
  //    This must be called for each profile allowed by the initial call to requireProfile().
  //
  //    Profiles are all masks, which can be "or"-ed together.
  //
  //        ENoProfile
  //        ECoreProfile
  //        ECompatibilityProfile
  //        EEsProfile
  //
  //    The ENoProfile profile is only for desktop, before profiles showed up in version 150;
  //    All other #version with no profile default to either es or core, and so have profiles.
  //
  //    You can select all but a particular profile using ~.  The following basically means "desktop":
  //
  //        ~EEsProfile
  //
  // 6) If built-in symbols are added by the extension, add them in Initialize.cpp:  Their use
  //    will be automatically error checked against the extensions enabled at that moment.
  //    see the comment at the top of Initialize.cpp for where to put them.  Establish them at
  //    the earliest release that supports the extension.  Then, tag them with the
  //    set of extensions that both enable them and are necessary, given the version of the symbol
  //    table. (There is a different symbol table for each version.)
  //
  // 7) If the extension has additional requirements like minimum SPIR-V version required, add them
  //    to extensionRequires()
  
  #include "parseVersions.h"
  #include "localintermediate.h"
  
  namespace glslang {
  
  #ifndef GLSLANG_WEB
  
  //
  // Initialize all extensions, almost always to 'disable', as once their features
  // are incorporated into a core version, their features are supported through allowing that
  // core version, not through a pseudo-enablement of the extension.
  //
  void TParseVersions::initializeExtensionBehavior()
  {
      typedef struct {
          const char *const extensionName;
          EShTargetLanguageVersion minSpvVersion;
      } extensionData;
  
      const extensionData exts[] = { {E_GL_EXT_ray_tracing, EShTargetSpv_1_4} };
  
      for (int ii = 0; ii < sizeof(exts) / sizeof(exts[0]); ii++) {
          // Add only extensions which require > spv1.0 to save space in map
          if (exts[ii].minSpvVersion > EShTargetSpv_1_0) {
              extensionMinSpv[E_GL_EXT_ray_tracing] = exts[ii].minSpvVersion;
          }
      }
  
      extensionBehavior[E_GL_OES_texture_3D]                   = EBhDisable;
      extensionBehavior[E_GL_OES_standard_derivatives]         = EBhDisable;
      extensionBehavior[E_GL_EXT_frag_depth]                   = EBhDisable;
      extensionBehavior[E_GL_OES_EGL_image_external]           = EBhDisable;
      extensionBehavior[E_GL_OES_EGL_image_external_essl3]     = EBhDisable;
      extensionBehavior[E_GL_EXT_YUV_target]                   = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_texture_lod]           = EBhDisable;
      extensionBehavior[E_GL_EXT_shadow_samplers]              = EBhDisable;
      extensionBehavior[E_GL_ARB_texture_rectangle]            = EBhDisable;
      extensionBehavior[E_GL_3DL_array_objects]                = EBhDisable;
      extensionBehavior[E_GL_ARB_shading_language_420pack]     = EBhDisable;
      extensionBehavior[E_GL_ARB_texture_gather]               = EBhDisable;
      extensionBehavior[E_GL_ARB_gpu_shader5]                  = EBhDisablePartial;
      extensionBehavior[E_GL_ARB_separate_shader_objects]      = EBhDisable;
      extensionBehavior[E_GL_ARB_compute_shader]               = EBhDisable;
      extensionBehavior[E_GL_ARB_tessellation_shader]          = EBhDisable;
      extensionBehavior[E_GL_ARB_enhanced_layouts]             = EBhDisable;
      extensionBehavior[E_GL_ARB_texture_cube_map_array]       = EBhDisable;
      extensionBehavior[E_GL_ARB_texture_multisample]          = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_texture_lod]           = EBhDisable;
      extensionBehavior[E_GL_ARB_explicit_attrib_location]     = EBhDisable;
      extensionBehavior[E_GL_ARB_explicit_uniform_location]    = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_image_load_store]      = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_atomic_counters]       = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_draw_parameters]       = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_group_vote]            = EBhDisable;
      extensionBehavior[E_GL_ARB_derivative_control]           = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_texture_image_samples] = EBhDisable;
      extensionBehavior[E_GL_ARB_viewport_array]               = EBhDisable;
      extensionBehavior[E_GL_ARB_gpu_shader_int64]             = EBhDisable;
      extensionBehavior[E_GL_ARB_gpu_shader_fp64]              = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_ballot]                = EBhDisable;
      extensionBehavior[E_GL_ARB_sparse_texture2]              = EBhDisable;
      extensionBehavior[E_GL_ARB_sparse_texture_clamp]         = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_stencil_export]        = EBhDisable;
  //    extensionBehavior[E_GL_ARB_cull_distance]                = EBhDisable;    // present for 4.5, but need extension control over block members
      extensionBehavior[E_GL_ARB_post_depth_coverage]          = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_viewport_layer_array]  = EBhDisable;
      extensionBehavior[E_GL_ARB_fragment_shader_interlock]    = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_clock]                 = EBhDisable;
      extensionBehavior[E_GL_ARB_uniform_buffer_object]        = EBhDisable;
      extensionBehavior[E_GL_ARB_sample_shading]               = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_bit_encoding]          = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_image_size]            = EBhDisable;
      extensionBehavior[E_GL_ARB_shader_storage_buffer_object] = EBhDisable;
      extensionBehavior[E_GL_ARB_shading_language_packing]     = EBhDisable;
      extensionBehavior[E_GL_ARB_texture_query_lod]            = EBhDisable;
      extensionBehavior[E_GL_ARB_vertex_attrib_64bit]          = EBhDisable;
  
      extensionBehavior[E_GL_KHR_shader_subgroup_basic]            = EBhDisable;
      extensionBehavior[E_GL_KHR_shader_subgroup_vote]             = EBhDisable;
      extensionBehavior[E_GL_KHR_shader_subgroup_arithmetic]       = EBhDisable;
      extensionBehavior[E_GL_KHR_shader_subgroup_ballot]           = EBhDisable;
      extensionBehavior[E_GL_KHR_shader_subgroup_shuffle]          = EBhDisable;
      extensionBehavior[E_GL_KHR_shader_subgroup_shuffle_relative] = EBhDisable;
      extensionBehavior[E_GL_KHR_shader_subgroup_clustered]        = EBhDisable;
      extensionBehavior[E_GL_KHR_shader_subgroup_quad]             = EBhDisable;
      extensionBehavior[E_GL_KHR_memory_scope_semantics]           = EBhDisable;
  
      extensionBehavior[E_GL_EXT_shader_atomic_int64]              = EBhDisable;
  
      extensionBehavior[E_GL_EXT_shader_non_constant_global_initializers] = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_image_load_formatted]             = EBhDisable;
      extensionBehavior[E_GL_EXT_post_depth_coverage]                     = EBhDisable;
      extensionBehavior[E_GL_EXT_control_flow_attributes]                 = EBhDisable;
      extensionBehavior[E_GL_EXT_nonuniform_qualifier]                    = EBhDisable;
      extensionBehavior[E_GL_EXT_samplerless_texture_functions]           = EBhDisable;
      extensionBehavior[E_GL_EXT_scalar_block_layout]                     = EBhDisable;
      extensionBehavior[E_GL_EXT_fragment_invocation_density]             = EBhDisable;
      extensionBehavior[E_GL_EXT_buffer_reference]                        = EBhDisable;
      extensionBehavior[E_GL_EXT_buffer_reference2]                       = EBhDisable;
      extensionBehavior[E_GL_EXT_buffer_reference_uvec2]                  = EBhDisable;
      extensionBehavior[E_GL_EXT_demote_to_helper_invocation]             = EBhDisable;
      extensionBehavior[E_GL_EXT_debug_printf]                            = EBhDisable;
  
      extensionBehavior[E_GL_EXT_shader_16bit_storage]                    = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_8bit_storage]                     = EBhDisable;
  
      // #line and #include
      extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive]          = EBhDisable;
      extensionBehavior[E_GL_GOOGLE_include_directive]                 = EBhDisable;
  
      extensionBehavior[E_GL_AMD_shader_ballot]                        = EBhDisable;
      extensionBehavior[E_GL_AMD_shader_trinary_minmax]                = EBhDisable;
      extensionBehavior[E_GL_AMD_shader_explicit_vertex_parameter]     = EBhDisable;
      extensionBehavior[E_GL_AMD_gcn_shader]                           = EBhDisable;
      extensionBehavior[E_GL_AMD_gpu_shader_half_float]                = EBhDisable;
      extensionBehavior[E_GL_AMD_texture_gather_bias_lod]              = EBhDisable;
      extensionBehavior[E_GL_AMD_gpu_shader_int16]                     = EBhDisable;
      extensionBehavior[E_GL_AMD_shader_image_load_store_lod]          = EBhDisable;
      extensionBehavior[E_GL_AMD_shader_fragment_mask]                 = EBhDisable;
      extensionBehavior[E_GL_AMD_gpu_shader_half_float_fetch]          = EBhDisable;
  
      extensionBehavior[E_GL_INTEL_shader_integer_functions2]          = EBhDisable;
  
      extensionBehavior[E_GL_NV_sample_mask_override_coverage]         = EBhDisable;
      extensionBehavior[E_SPV_NV_geometry_shader_passthrough]          = EBhDisable;
      extensionBehavior[E_GL_NV_viewport_array2]                       = EBhDisable;
      extensionBehavior[E_GL_NV_stereo_view_rendering]                 = EBhDisable;
      extensionBehavior[E_GL_NVX_multiview_per_view_attributes]        = EBhDisable;
      extensionBehavior[E_GL_NV_shader_atomic_int64]                   = EBhDisable;
      extensionBehavior[E_GL_NV_conservative_raster_underestimation]   = EBhDisable;
      extensionBehavior[E_GL_NV_shader_noperspective_interpolation]    = EBhDisable;
      extensionBehavior[E_GL_NV_shader_subgroup_partitioned]           = EBhDisable;
      extensionBehavior[E_GL_NV_shading_rate_image]                    = EBhDisable;
      extensionBehavior[E_GL_NV_ray_tracing]                           = EBhDisable;
      extensionBehavior[E_GL_NV_fragment_shader_barycentric]           = EBhDisable;
      extensionBehavior[E_GL_NV_compute_shader_derivatives]            = EBhDisable;
      extensionBehavior[E_GL_NV_shader_texture_footprint]              = EBhDisable;
      extensionBehavior[E_GL_NV_mesh_shader]                           = EBhDisable;
  
      extensionBehavior[E_GL_NV_cooperative_matrix]                    = EBhDisable;
      extensionBehavior[E_GL_NV_shader_sm_builtins]                    = EBhDisable;
      extensionBehavior[E_GL_NV_integer_cooperative_matrix]            = EBhDisable;
  
      // AEP
      extensionBehavior[E_GL_ANDROID_extension_pack_es31a]             = EBhDisable;
      extensionBehavior[E_GL_KHR_blend_equation_advanced]              = EBhDisable;
      extensionBehavior[E_GL_OES_sample_variables]                     = EBhDisable;
      extensionBehavior[E_GL_OES_shader_image_atomic]                  = EBhDisable;
      extensionBehavior[E_GL_OES_shader_multisample_interpolation]     = EBhDisable;
      extensionBehavior[E_GL_OES_texture_storage_multisample_2d_array] = EBhDisable;
      extensionBehavior[E_GL_EXT_geometry_shader]                      = EBhDisable;
      extensionBehavior[E_GL_EXT_geometry_point_size]                  = EBhDisable;
      extensionBehavior[E_GL_EXT_gpu_shader5]                          = EBhDisable;
      extensionBehavior[E_GL_EXT_primitive_bounding_box]               = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_io_blocks]                     = EBhDisable;
      extensionBehavior[E_GL_EXT_tessellation_shader]                  = EBhDisable;
      extensionBehavior[E_GL_EXT_tessellation_point_size]              = EBhDisable;
      extensionBehavior[E_GL_EXT_texture_buffer]                       = EBhDisable;
      extensionBehavior[E_GL_EXT_texture_cube_map_array]               = EBhDisable;
  
      // OES matching AEP
      extensionBehavior[E_GL_OES_geometry_shader]          = EBhDisable;
      extensionBehavior[E_GL_OES_geometry_point_size]      = EBhDisable;
      extensionBehavior[E_GL_OES_gpu_shader5]              = EBhDisable;
      extensionBehavior[E_GL_OES_primitive_bounding_box]   = EBhDisable;
      extensionBehavior[E_GL_OES_shader_io_blocks]         = EBhDisable;
      extensionBehavior[E_GL_OES_tessellation_shader]      = EBhDisable;
      extensionBehavior[E_GL_OES_tessellation_point_size]  = EBhDisable;
      extensionBehavior[E_GL_OES_texture_buffer]           = EBhDisable;
      extensionBehavior[E_GL_OES_texture_cube_map_array]   = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_integer_mix]       = EBhDisable;
  
      // EXT extensions
      extensionBehavior[E_GL_EXT_device_group]                = EBhDisable;
      extensionBehavior[E_GL_EXT_multiview]                   = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_realtime_clock]       = EBhDisable;
      extensionBehavior[E_GL_EXT_ray_tracing]                 = EBhDisable;
      extensionBehavior[E_GL_EXT_ray_query]                   = EBhDisable;
      extensionBehavior[E_GL_EXT_ray_flags_primitive_culling] = EBhDisable;
      extensionBehavior[E_GL_EXT_blend_func_extended]         = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_implicit_conversions] = EBhDisable;
  
      // OVR extensions
      extensionBehavior[E_GL_OVR_multiview]                = EBhDisable;
      extensionBehavior[E_GL_OVR_multiview2]               = EBhDisable;
  
      // explicit types
      extensionBehavior[E_GL_EXT_shader_explicit_arithmetic_types]         = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_explicit_arithmetic_types_int8]    = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_explicit_arithmetic_types_int16]   = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_explicit_arithmetic_types_int32]   = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_explicit_arithmetic_types_int64]   = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_explicit_arithmetic_types_float16] = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_explicit_arithmetic_types_float32] = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_explicit_arithmetic_types_float64] = EBhDisable;
  
      // subgroup extended types
      extensionBehavior[E_GL_EXT_shader_subgroup_extended_types_int8]    = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_subgroup_extended_types_int16]   = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_subgroup_extended_types_int64]   = EBhDisable;
      extensionBehavior[E_GL_EXT_shader_subgroup_extended_types_float16] = EBhDisable;
  }
  
  #endif // GLSLANG_WEB
  
  // Get code that is not part of a shared symbol table, is specific to this shader,
  // or needed by the preprocessor (which does not use a shared symbol table).
  void TParseVersions::getPreamble(std::string& preamble)
  {
      if (isEsProfile()) {
          preamble =
              "#define GL_ES 1\n"
              "#define GL_FRAGMENT_PRECISION_HIGH 1\n"
  #ifdef GLSLANG_WEB
              ;
  #else
              "#define GL_OES_texture_3D 1\n"
              "#define GL_OES_standard_derivatives 1\n"
              "#define GL_EXT_frag_depth 1\n"
              "#define GL_OES_EGL_image_external 1\n"
              "#define GL_OES_EGL_image_external_essl3 1\n"
              "#define GL_EXT_YUV_target 1\n"
              "#define GL_EXT_shader_texture_lod 1\n"
              "#define GL_EXT_shadow_samplers 1\n"
  
              // AEP
              "#define GL_ANDROID_extension_pack_es31a 1\n"
              "#define GL_OES_sample_variables 1\n"
              "#define GL_OES_shader_image_atomic 1\n"
              "#define GL_OES_shader_multisample_interpolation 1\n"
              "#define GL_OES_texture_storage_multisample_2d_array 1\n"
              "#define GL_EXT_geometry_shader 1\n"
              "#define GL_EXT_geometry_point_size 1\n"
              "#define GL_EXT_gpu_shader5 1\n"
              "#define GL_EXT_primitive_bounding_box 1\n"
              "#define GL_EXT_shader_io_blocks 1\n"
              "#define GL_EXT_tessellation_shader 1\n"
              "#define GL_EXT_tessellation_point_size 1\n"
              "#define GL_EXT_texture_buffer 1\n"
              "#define GL_EXT_texture_cube_map_array 1\n"
              "#define GL_EXT_shader_implicit_conversions 1\n"
              "#define GL_EXT_shader_integer_mix 1\n"
              "#define GL_EXT_blend_func_extended 1\n"
  
              // OES matching AEP
              "#define GL_OES_geometry_shader 1\n"
              "#define GL_OES_geometry_point_size 1\n"
              "#define GL_OES_gpu_shader5 1\n"
              "#define GL_OES_primitive_bounding_box 1\n"
              "#define GL_OES_shader_io_blocks 1\n"
              "#define GL_OES_tessellation_shader 1\n"
              "#define GL_OES_tessellation_point_size 1\n"
              "#define GL_OES_texture_buffer 1\n"
              "#define GL_OES_texture_cube_map_array 1\n"
              "#define GL_EXT_shader_non_constant_global_initializers 1\n"
              ;
  
              if (isEsProfile() && version >= 300) {
                  preamble += "#define GL_NV_shader_noperspective_interpolation 1\n";
              }
  
      } else {
          preamble =
              "#define GL_FRAGMENT_PRECISION_HIGH 1\n"
              "#define GL_ARB_texture_rectangle 1\n"
              "#define GL_ARB_shading_language_420pack 1\n"
              "#define GL_ARB_texture_gather 1\n"
              "#define GL_ARB_gpu_shader5 1\n"
              "#define GL_ARB_separate_shader_objects 1\n"
              "#define GL_ARB_compute_shader 1\n"
              "#define GL_ARB_tessellation_shader 1\n"
              "#define GL_ARB_enhanced_layouts 1\n"
              "#define GL_ARB_texture_cube_map_array 1\n"
              "#define GL_ARB_texture_multisample 1\n"
              "#define GL_ARB_shader_texture_lod 1\n"
              "#define GL_ARB_explicit_attrib_location 1\n"
              "#define GL_ARB_explicit_uniform_location 1\n"
              "#define GL_ARB_shader_image_load_store 1\n"
              "#define GL_ARB_shader_atomic_counters 1\n"
              "#define GL_ARB_shader_draw_parameters 1\n"
              "#define GL_ARB_shader_group_vote 1\n"
              "#define GL_ARB_derivative_control 1\n"
              "#define GL_ARB_shader_texture_image_samples 1\n"
              "#define GL_ARB_viewport_array 1\n"
              "#define GL_ARB_gpu_shader_int64 1\n"
              "#define GL_ARB_gpu_shader_fp64 1\n"
              "#define GL_ARB_shader_ballot 1\n"
              "#define GL_ARB_sparse_texture2 1\n"
              "#define GL_ARB_sparse_texture_clamp 1\n"
              "#define GL_ARB_shader_stencil_export 1\n"
              "#define GL_ARB_sample_shading 1\n"
              "#define GL_ARB_shader_image_size 1\n"
              "#define GL_ARB_shading_language_packing 1\n"
  //            "#define GL_ARB_cull_distance 1\n"    // present for 4.5, but need extension control over block members
              "#define GL_ARB_post_depth_coverage 1\n"
              "#define GL_ARB_fragment_shader_interlock 1\n"
              "#define GL_ARB_uniform_buffer_object 1\n"
              "#define GL_ARB_shader_bit_encoding 1\n"
              "#define GL_ARB_shader_storage_buffer_object 1\n"
              "#define GL_ARB_texture_query_lod 1\n"
              "#define GL_ARB_vertex_attrib_64bit 1\n"
              "#define GL_EXT_shader_non_constant_global_initializers 1\n"
              "#define GL_EXT_shader_image_load_formatted 1\n"
              "#define GL_EXT_post_depth_coverage 1\n"
              "#define GL_EXT_control_flow_attributes 1\n"
              "#define GL_EXT_nonuniform_qualifier 1\n"
              "#define GL_EXT_shader_16bit_storage 1\n"
              "#define GL_EXT_shader_8bit_storage 1\n"
              "#define GL_EXT_samplerless_texture_functions 1\n"
              "#define GL_EXT_scalar_block_layout 1\n"
              "#define GL_EXT_fragment_invocation_density 1\n"
              "#define GL_EXT_buffer_reference 1\n"
              "#define GL_EXT_buffer_reference2 1\n"
              "#define GL_EXT_buffer_reference_uvec2 1\n"
              "#define GL_EXT_demote_to_helper_invocation 1\n"
              "#define GL_EXT_debug_printf 1\n"
  
              // GL_KHR_shader_subgroup
              "#define GL_KHR_shader_subgroup_basic 1\n"
              "#define GL_KHR_shader_subgroup_vote 1\n"
              "#define GL_KHR_shader_subgroup_arithmetic 1\n"
              "#define GL_KHR_shader_subgroup_ballot 1\n"
              "#define GL_KHR_shader_subgroup_shuffle 1\n"
              "#define GL_KHR_shader_subgroup_shuffle_relative 1\n"
              "#define GL_KHR_shader_subgroup_clustered 1\n"
              "#define GL_KHR_shader_subgroup_quad 1\n"
  
              "#define E_GL_EXT_shader_atomic_int64 1\n"
              "#define E_GL_EXT_shader_realtime_clock 1\n"
              "#define E_GL_EXT_ray_tracing 1\n"
              "#define E_GL_EXT_ray_query 1\n"
              "#define E_GL_EXT_ray_flags_primitive_culling 1\n"
  
              "#define GL_AMD_shader_ballot 1\n"
              "#define GL_AMD_shader_trinary_minmax 1\n"
              "#define GL_AMD_shader_explicit_vertex_parameter 1\n"
              "#define GL_AMD_gcn_shader 1\n"
              "#define GL_AMD_gpu_shader_half_float 1\n"
              "#define GL_AMD_texture_gather_bias_lod 1\n"
              "#define GL_AMD_gpu_shader_int16 1\n"
              "#define GL_AMD_shader_image_load_store_lod 1\n"
              "#define GL_AMD_shader_fragment_mask 1\n"
              "#define GL_AMD_gpu_shader_half_float_fetch 1\n"
  
              "#define GL_INTEL_shader_integer_functions2 1\n"
  
              "#define GL_NV_sample_mask_override_coverage 1\n"
              "#define GL_NV_geometry_shader_passthrough 1\n"
              "#define GL_NV_viewport_array2 1\n"
              "#define GL_NV_shader_atomic_int64 1\n"
              "#define GL_NV_conservative_raster_underestimation 1\n"
              "#define GL_NV_shader_subgroup_partitioned 1\n"
              "#define GL_NV_shading_rate_image 1\n"
              "#define GL_NV_ray_tracing 1\n"
              "#define GL_NV_fragment_shader_barycentric 1\n"
              "#define GL_NV_compute_shader_derivatives 1\n"
              "#define GL_NV_shader_texture_footprint 1\n"
              "#define GL_NV_mesh_shader 1\n"
              "#define GL_NV_cooperative_matrix 1\n"
              "#define GL_NV_integer_cooperative_matrix 1\n"
  
              "#define GL_EXT_shader_explicit_arithmetic_types 1\n"
              "#define GL_EXT_shader_explicit_arithmetic_types_int8 1\n"
              "#define GL_EXT_shader_explicit_arithmetic_types_int16 1\n"
              "#define GL_EXT_shader_explicit_arithmetic_types_int32 1\n"
              "#define GL_EXT_shader_explicit_arithmetic_types_int64 1\n"
              "#define GL_EXT_shader_explicit_arithmetic_types_float16 1\n"
              "#define GL_EXT_shader_explicit_arithmetic_types_float32 1\n"
              "#define GL_EXT_shader_explicit_arithmetic_types_float64 1\n"
  
              "#define GL_EXT_shader_subgroup_extended_types_int8 1\n"
              "#define GL_EXT_shader_subgroup_extended_types_int16 1\n"
              "#define GL_EXT_shader_subgroup_extended_types_int64 1\n"
              "#define GL_EXT_shader_subgroup_extended_types_float16 1\n"
              ;
  
          if (version >= 150) {
              // define GL_core_profile and GL_compatibility_profile
              preamble += "#define GL_core_profile 1\n";
  
              if (profile == ECompatibilityProfile)
                  preamble += "#define GL_compatibility_profile 1\n";
          }
  #endif // GLSLANG_WEB
      }
  
  #ifndef GLSLANG_WEB
      if ((!isEsProfile() && version >= 140) ||
          (isEsProfile() && version >= 310)) {
          preamble +=
              "#define GL_EXT_device_group 1\n"
              "#define GL_EXT_multiview 1\n"
              "#define GL_NV_shader_sm_builtins 1\n"
              ;
      }
  
      if (version >= 300 /* both ES and non-ES */) {
          preamble +=
              "#define GL_OVR_multiview 1\n"
              "#define GL_OVR_multiview2 1\n"
              ;
      }
  
      // #line and #include
      preamble +=
              "#define GL_GOOGLE_cpp_style_line_directive 1\n"
              "#define GL_GOOGLE_include_directive 1\n"
              "#define GL_KHR_blend_equation_advanced 1\n"
              ;
  #endif
  
      // #define VULKAN XXXX
      const int numberBufSize = 12;
      char numberBuf[numberBufSize];
      if (spvVersion.vulkanGlsl > 0) {
          preamble += "#define VULKAN ";
          snprintf(numberBuf, numberBufSize, "%d", spvVersion.vulkanGlsl);
          preamble += numberBuf;
          preamble += "\n";
      }
  
  #ifndef GLSLANG_WEB
      // #define GL_SPIRV XXXX
      if (spvVersion.openGl > 0) {
          preamble += "#define GL_SPIRV ";
          snprintf(numberBuf, numberBufSize, "%d", spvVersion.openGl);
          preamble += numberBuf;
          preamble += "\n";
      }
  #endif
  }
  
  //
  // Map from stage enum to externally readable text name.
  //
  const char* StageName(EShLanguage stage)
  {
      switch(stage) {
      case EShLangVertex:         return "vertex";
      case EShLangFragment:       return "fragment";
      case EShLangCompute:        return "compute";
  #ifndef GLSLANG_WEB
      case EShLangTessControl:    return "tessellation control";
      case EShLangTessEvaluation: return "tessellation evaluation";
      case EShLangGeometry:       return "geometry";
      case EShLangRayGen:         return "ray-generation";
      case EShLangIntersect:      return "intersection";
      case EShLangAnyHit:         return "any-hit";
      case EShLangClosestHit:     return "closest-hit";
      case EShLangMiss:           return "miss";
      case EShLangCallable:       return "callable";
      case EShLangMeshNV:         return "mesh";
      case EShLangTaskNV:         return "task";
  #endif
      default:                    return "unknown stage";
      }
  }
  
  //
  // When to use requireStage()
  //
  //     If only some stages support a feature.
  //
  // Operation: If the current stage is not present, give an error message.
  //
  void TParseVersions::requireStage(const TSourceLoc& loc, EShLanguageMask languageMask, const char* featureDesc)
  {
      if (((1 << language) & languageMask) == 0)
          error(loc, "not supported in this stage:", featureDesc, StageName(language));
  }
  
  // If only one stage supports a feature, this can be called.  But, all supporting stages
  // must be specified with one call.
  void TParseVersions::requireStage(const TSourceLoc& loc, EShLanguage stage, const char* featureDesc)
  {
      requireStage(loc, static_cast<EShLanguageMask>(1 << stage), featureDesc);
  }
  
  #ifndef GLSLANG_WEB
  //
  // When to use requireProfile():
  //
  //     Use if only some profiles support a feature.  However, if within a profile the feature
  //     is version or extension specific, follow this call with calls to profileRequires().
  //
  // Operation:  If the current profile is not one of the profileMask,
  // give an error message.
  //
  void TParseVersions::requireProfile(const TSourceLoc& loc, int profileMask, const char* featureDesc)
  {
      if (! (profile & profileMask))
          error(loc, "not supported with this profile:", featureDesc, ProfileName(profile));
  }
  
  //
  // When to use profileRequires():
  //
  //     If a set of profiles have the same requirements for what version or extensions
  //     are needed to support a feature.
  //
  //     It must be called for each profile that needs protection.  Use requireProfile() first
  //     to reduce that set of profiles.
  //
  // Operation: Will issue warnings/errors based on the current profile, version, and extension
  // behaviors.  It only checks extensions when the current profile is one of the profileMask.
  //
  // A minVersion of 0 means no version of the profileMask support this in core,
  // the extension must be present.
  //
  
  // entry point that takes multiple extensions
  void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, int numExtensions,
      const char* const extensions[], const char* featureDesc)
  {
      if (profile & profileMask) {
          bool okay = minVersion > 0 && version >= minVersion;
  #ifndef GLSLANG_WEB
          for (int i = 0; i < numExtensions; ++i) {
              switch (getExtensionBehavior(extensions[i])) {
              case EBhWarn:
                  infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
                  // fall through
              case EBhRequire:
              case EBhEnable:
                  okay = true;
                  break;
              default: break; // some compilers want this
              }
          }
  #endif
          if (! okay)
              error(loc, "not supported for this version or the enabled extensions", featureDesc, "");
      }
  }
  
  // entry point for the above that takes a single extension
  void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, const char* extension,
      const char* featureDesc)
  {
      profileRequires(loc, profileMask, minVersion, extension ? 1 : 0, &extension, featureDesc);
  }
  
  void TParseVersions::unimplemented(const TSourceLoc& loc, const char* featureDesc)
  {
      error(loc, "feature not yet implemented", featureDesc, "");
  }
  
  //
  // Within a set of profiles, see if a feature is deprecated and give an error or warning based on whether
  // a future compatibility context is being use.
  //
  void TParseVersions::checkDeprecated(const TSourceLoc& loc, int profileMask, int depVersion, const char* featureDesc)
  {
      if (profile & profileMask) {
          if (version >= depVersion) {
              if (forwardCompatible)
                  error(loc, "deprecated, may be removed in future release", featureDesc, "");
              else if (! suppressWarnings())
                  infoSink.info.message(EPrefixWarning, (TString(featureDesc) + " deprecated in version " +
                                                         String(depVersion) + "; may be removed in future release").c_str(), loc);
          }
      }
  }
  
  //
  // Within a set of profiles, see if a feature has now been removed and if so, give an error.
  // The version argument is the first version no longer having the feature.
  //
  void TParseVersions::requireNotRemoved(const TSourceLoc& loc, int profileMask, int removedVersion, const char* featureDesc)
  {
      if (profile & profileMask) {
          if (version >= removedVersion) {
              const int maxSize = 60;
              char buf[maxSize];
              snprintf(buf, maxSize, "%s profile; removed in version %d", ProfileName(profile), removedVersion);
              error(loc, "no longer supported in", featureDesc, buf);
          }
      }
  }
  
  // Returns true if at least one of the extensions in the extensions parameter is requested. Otherwise, returns false.
  // Warns appropriately if the requested behavior of an extension is "warn".
  bool TParseVersions::checkExtensionsRequested(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
  {
      // First, see if any of the extensions are enabled
      for (int i = 0; i < numExtensions; ++i) {
          TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
          if (behavior == EBhEnable || behavior == EBhRequire)
              return true;
      }
  
      // See if any extensions want to give a warning on use; give warnings for all such extensions
      bool warned = false;
      for (int i = 0; i < numExtensions; ++i) {
          TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
          if (behavior == EBhDisable && relaxedErrors()) {
              infoSink.info.message(EPrefixWarning, "The following extension must be enabled to use this feature:", loc);
              behavior = EBhWarn;
          }
          if (behavior == EBhWarn) {
              infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
              warned = true;
          }
      }
      if (warned)
          return true;
      return false;
  }
  
  //
  // Use when there are no profile/version to check, it's just an error if one of the
  // extensions is not present.
  //
  void TParseVersions::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
  {
      if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc))
          return;
  
      // If we get this far, give errors explaining what extensions are needed
      if (numExtensions == 1)
          error(loc, "required extension not requested:", featureDesc, extensions[0]);
      else {
          error(loc, "required extension not requested:", featureDesc, "Possible extensions include:");
          for (int i = 0; i < numExtensions; ++i)
              infoSink.info.message(EPrefixNone, extensions[i]);
      }
  }
  
  //
  // Use by preprocessor when there are no profile/version to check, it's just an error if one of the
  // extensions is not present.
  //
  void TParseVersions::ppRequireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
  {
      if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc))
          return;
  
      // If we get this far, give errors explaining what extensions are needed
      if (numExtensions == 1)
          ppError(loc, "required extension not requested:", featureDesc, extensions[0]);
      else {
          ppError(loc, "required extension not requested:", featureDesc, "Possible extensions include:");
          for (int i = 0; i < numExtensions; ++i)
              infoSink.info.message(EPrefixNone, extensions[i]);
      }
  }
  
  TExtensionBehavior TParseVersions::getExtensionBehavior(const char* extension)
  {
      auto iter = extensionBehavior.find(TString(extension));
      if (iter == extensionBehavior.end())
          return EBhMissing;
      else
          return iter->second;
  }
  
  // Returns true if the given extension is set to enable, require, or warn.
  bool TParseVersions::extensionTurnedOn(const char* const extension)
  {
        switch (getExtensionBehavior(extension)) {
        case EBhEnable:
        case EBhRequire:
        case EBhWarn:
            return true;
        default:
            break;
        }
        return false;
  }
  // See if any of the extensions are set to enable, require, or warn.
  bool TParseVersions::extensionsTurnedOn(int numExtensions, const char* const extensions[])
  {
      for (int i = 0; i < numExtensions; ++i) {
          if (extensionTurnedOn(extensions[i]))
              return true;
      }
      return false;
  }
  
  //
  // Change the current state of an extension's behavior.
  //
  void TParseVersions::updateExtensionBehavior(int line, const char* extension, const char* behaviorString)
  {
      // Translate from text string of extension's behavior to an enum.
      TExtensionBehavior behavior = EBhDisable;
      if (! strcmp("require", behaviorString))
          behavior = EBhRequire;
      else if (! strcmp("enable", behaviorString))
          behavior = EBhEnable;
      else if (! strcmp("disable", behaviorString))
          behavior = EBhDisable;
      else if (! strcmp("warn", behaviorString))
          behavior = EBhWarn;
      else {
          error(getCurrentLoc(), "behavior not supported:", "#extension", behaviorString);
          return;
      }
  
      // check if extension is used with correct shader stage
      checkExtensionStage(getCurrentLoc(), extension);
  
      // check if extension has additional requirements
      extensionRequires(getCurrentLoc(), extension ,behaviorString);
  
      // update the requested extension
      updateExtensionBehavior(extension, behavior);
  
      // see if need to propagate to implicitly modified things
      if (strcmp(extension, "GL_ANDROID_extension_pack_es31a") == 0) {
          // to everything in AEP
          updateExtensionBehavior(line, "GL_KHR_blend_equation_advanced", behaviorString);
          updateExtensionBehavior(line, "GL_OES_sample_variables", behaviorString);
          updateExtensionBehavior(line, "GL_OES_shader_image_atomic", behaviorString);
          updateExtensionBehavior(line, "GL_OES_shader_multisample_interpolation", behaviorString);
          updateExtensionBehavior(line, "GL_OES_texture_storage_multisample_2d_array", behaviorString);
          updateExtensionBehavior(line, "GL_EXT_geometry_shader", behaviorString);
          updateExtensionBehavior(line, "GL_EXT_gpu_shader5", behaviorString);
          updateExtensionBehavior(line, "GL_EXT_primitive_bounding_box", behaviorString);
          updateExtensionBehavior(line, "GL_EXT_shader_io_blocks", behaviorString);
          updateExtensionBehavior(line, "GL_EXT_tessellation_shader", behaviorString);
          updateExtensionBehavior(line, "GL_EXT_texture_buffer", behaviorString);
          updateExtensionBehavior(line, "GL_EXT_texture_cube_map_array", behaviorString);
      }
      // geometry to io_blocks
      else if (strcmp(extension, "GL_EXT_geometry_shader") == 0)
          updateExtensionBehavior(line, "GL_EXT_shader_io_blocks", behaviorString);
      else if (strcmp(extension, "GL_OES_geometry_shader") == 0)
          updateExtensionBehavior(line, "GL_OES_shader_io_blocks", behaviorString);
      // tessellation to io_blocks
      else if (strcmp(extension, "GL_EXT_tessellation_shader") == 0)
          updateExtensionBehavior(line, "GL_EXT_shader_io_blocks", behaviorString);
      else if (strcmp(extension, "GL_OES_tessellation_shader") == 0)
          updateExtensionBehavior(line, "GL_OES_shader_io_blocks", behaviorString);
      else if (strcmp(extension, "GL_GOOGLE_include_directive") == 0)
          updateExtensionBehavior(line, "GL_GOOGLE_cpp_style_line_directive", behaviorString);
      // subgroup_* to subgroup_basic
      else if (strcmp(extension, "GL_KHR_shader_subgroup_vote") == 0)
          updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString);
      else if (strcmp(extension, "GL_KHR_shader_subgroup_arithmetic") == 0)
          updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString);
      else if (strcmp(extension, "GL_KHR_shader_subgroup_ballot") == 0)
          updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString);
      else if (strcmp(extension, "GL_KHR_shader_subgroup_shuffle") == 0)
          updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString);
      else if (strcmp(extension, "GL_KHR_shader_subgroup_shuffle_relative") == 0)
          updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString);
      else if (strcmp(extension, "GL_KHR_shader_subgroup_clustered") == 0)
          updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString);
      else if (strcmp(extension, "GL_KHR_shader_subgroup_quad") == 0)
          updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString);
      else if (strcmp(extension, "GL_NV_shader_subgroup_partitioned") == 0)
          updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString);
      else if (strcmp(extension, "GL_EXT_buffer_reference2") == 0 ||
               strcmp(extension, "GL_EXT_buffer_reference_uvec2") == 0)
          updateExtensionBehavior(line, "GL_EXT_buffer_reference", behaviorString);
      else if (strcmp(extension, "GL_NV_integer_cooperative_matrix") == 0)
          updateExtensionBehavior(line, "GL_NV_cooperative_matrix", behaviorString);
      // subgroup extended types to explicit types
      else if (strcmp(extension, "GL_EXT_shader_subgroup_extended_types_int8") == 0)
          updateExtensionBehavior(line, "GL_EXT_shader_explicit_arithmetic_types_int8", behaviorString);
      else if (strcmp(extension, "GL_EXT_shader_subgroup_extended_types_int16") == 0)
          updateExtensionBehavior(line, "GL_EXT_shader_explicit_arithmetic_types_int16", behaviorString);
      else if (strcmp(extension, "GL_EXT_shader_subgroup_extended_types_int64") == 0)
          updateExtensionBehavior(line, "GL_EXT_shader_explicit_arithmetic_types_int64", behaviorString);
      else if (strcmp(extension, "GL_EXT_shader_subgroup_extended_types_float16") == 0)
          updateExtensionBehavior(line, "GL_EXT_shader_explicit_arithmetic_types_float16", behaviorString);
  }
  
  void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
  {
      // Update the current behavior
      if (strcmp(extension, "all") == 0) {
          // special case for the 'all' extension; apply it to every extension present
          if (behavior == EBhRequire || behavior == EBhEnable) {
              error(getCurrentLoc(), "extension 'all' cannot have 'require' or 'enable' behavior", "#extension", "");
              return;
          } else {
              for (auto iter = extensionBehavior.begin(); iter != extensionBehavior.end(); ++iter)
                  iter->second = behavior;
          }
      } else {
          // Do the update for this single extension
          auto iter = extensionBehavior.find(TString(extension));
          if (iter == extensionBehavior.end()) {
              switch (behavior) {
              case EBhRequire:
                  error(getCurrentLoc(), "extension not supported:", "#extension", extension);
                  break;
              case EBhEnable:
              case EBhWarn:
              case EBhDisable:
                  warn(getCurrentLoc(), "extension not supported:", "#extension", extension);
                  break;
              default:
                  assert(0 && "unexpected behavior");
              }
  
              return;
          } else {
              if (iter->second == EBhDisablePartial)
                  warn(getCurrentLoc(), "extension is only partially supported:", "#extension", extension);
              if (behavior == EBhEnable || behavior == EBhRequire || behavior == EBhDisable)
                  intermediate.updateRequestedExtension(extension, behavior);
              iter->second = behavior;
          }
      }
  }
  
  // Check if extension is used with correct shader stage.
  void TParseVersions::checkExtensionStage(const TSourceLoc& loc, const char * const extension)
  {
      // GL_NV_mesh_shader extension is only allowed in task/mesh shaders
      if (strcmp(extension, "GL_NV_mesh_shader") == 0) {
          requireStage(loc, (EShLanguageMask)(EShLangTaskNVMask | EShLangMeshNVMask | EShLangFragmentMask),
                       "#extension GL_NV_mesh_shader");
          profileRequires(loc, ECoreProfile, 450, 0, "#extension GL_NV_mesh_shader");
          profileRequires(loc, EEsProfile, 320, 0, "#extension GL_NV_mesh_shader");
      }
  }
  
  // Check if extension has additional requirements
  void TParseVersions::extensionRequires(const TSourceLoc &loc, const char * const extension, const char *behaviorString)
  {
      bool isEnabled = false;
      if (!strcmp("require", behaviorString))
          isEnabled = true;
      else if (!strcmp("enable", behaviorString))
          isEnabled = true;
  
      if (isEnabled) {
          unsigned int minSpvVersion = 0;
          auto iter = extensionMinSpv.find(TString(extension));
          if (iter != extensionMinSpv.end())
              minSpvVersion = iter->second;
          requireSpv(loc, extension, minSpvVersion);
      }
  }
  
  // Call for any operation needing full GLSL integer data-type support.
  void TParseVersions::fullIntegerCheck(const TSourceLoc& loc, const char* op)
  {
      profileRequires(loc, ENoProfile, 130, nullptr, op);
      profileRequires(loc, EEsProfile, 300, nullptr, op);
  }
  
  // Call for any operation needing GLSL double data-type support.
  void TParseVersions::doubleCheck(const TSourceLoc& loc, const char* op)
  {
  
      //requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
      if (language == EShLangVertex) {
          const char* const f64_Extensions[] = {E_GL_ARB_gpu_shader_fp64, E_GL_ARB_vertex_attrib_64bit};
          profileRequires(loc, ECoreProfile | ECompatibilityProfile, 400, 2, f64_Extensions, op);
      } else
          profileRequires(loc, ECoreProfile | ECompatibilityProfile, 400, E_GL_ARB_gpu_shader_fp64, op);
  }
  
  // Call for any operation needing GLSL float16 data-type support.
  void TParseVersions::float16Check(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (!builtIn) {
          const char* const extensions[] = {
                                             E_GL_AMD_gpu_shader_half_float,
                                             E_GL_EXT_shader_explicit_arithmetic_types,
                                             E_GL_EXT_shader_explicit_arithmetic_types_float16};
          requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
      }
  }
  
  bool TParseVersions::float16Arithmetic()
  {
      const char* const extensions[] = {
                                         E_GL_AMD_gpu_shader_half_float,
                                         E_GL_EXT_shader_explicit_arithmetic_types,
                                         E_GL_EXT_shader_explicit_arithmetic_types_float16};
      return extensionsTurnedOn(sizeof(extensions)/sizeof(extensions[0]), extensions);
  }
  
  bool TParseVersions::int16Arithmetic()
  {
      const char* const extensions[] = {
                                         E_GL_AMD_gpu_shader_int16,
                                         E_GL_EXT_shader_explicit_arithmetic_types,
                                         E_GL_EXT_shader_explicit_arithmetic_types_int16};
      return extensionsTurnedOn(sizeof(extensions)/sizeof(extensions[0]), extensions);
  }
  
  bool TParseVersions::int8Arithmetic()
  {
      const char* const extensions[] = {
                                         E_GL_EXT_shader_explicit_arithmetic_types,
                                         E_GL_EXT_shader_explicit_arithmetic_types_int8};
      return extensionsTurnedOn(sizeof(extensions)/sizeof(extensions[0]), extensions);
  }
  
  void TParseVersions::requireFloat16Arithmetic(const TSourceLoc& loc, const char* op, const char* featureDesc)
  {
      TString combined;
      combined = op;
      combined += ": ";
      combined += featureDesc;
  
      const char* const extensions[] = {
                                         E_GL_AMD_gpu_shader_half_float,
                                         E_GL_EXT_shader_explicit_arithmetic_types,
                                         E_GL_EXT_shader_explicit_arithmetic_types_float16};
      requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, combined.c_str());
  }
  
  void TParseVersions::requireInt16Arithmetic(const TSourceLoc& loc, const char* op, const char* featureDesc)
  {
      TString combined;
      combined = op;
      combined += ": ";
      combined += featureDesc;
  
      const char* const extensions[] = {
                                         E_GL_AMD_gpu_shader_int16,
                                         E_GL_EXT_shader_explicit_arithmetic_types,
                                         E_GL_EXT_shader_explicit_arithmetic_types_int16};
      requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, combined.c_str());
  }
  
  void TParseVersions::requireInt8Arithmetic(const TSourceLoc& loc, const char* op, const char* featureDesc)
  {
      TString combined;
      combined = op;
      combined += ": ";
      combined += featureDesc;
  
      const char* const extensions[] = {
                                         E_GL_EXT_shader_explicit_arithmetic_types,
                                         E_GL_EXT_shader_explicit_arithmetic_types_int8};
      requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, combined.c_str());
  }
  
  void TParseVersions::float16ScalarVectorCheck(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (!builtIn) {
          const char* const extensions[] = {
                                             E_GL_AMD_gpu_shader_half_float,
                                             E_GL_EXT_shader_16bit_storage,
                                             E_GL_EXT_shader_explicit_arithmetic_types,
                                             E_GL_EXT_shader_explicit_arithmetic_types_float16};
          requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
      }
  }
  
  // Call for any operation needing GLSL float32 data-type support.
  void TParseVersions::explicitFloat32Check(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (!builtIn) {
          const char* const extensions[2] = {E_GL_EXT_shader_explicit_arithmetic_types,
                                             E_GL_EXT_shader_explicit_arithmetic_types_float32};
          requireExtensions(loc, 2, extensions, op);
      }
  }
  
  // Call for any operation needing GLSL float64 data-type support.
  void TParseVersions::explicitFloat64Check(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (!builtIn) {
          const char* const extensions[2] = {E_GL_EXT_shader_explicit_arithmetic_types,
                                             E_GL_EXT_shader_explicit_arithmetic_types_float64};
          requireExtensions(loc, 2, extensions, op);
          requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
          profileRequires(loc, ECoreProfile | ECompatibilityProfile, 400, nullptr, op);
      }
  }
  
  // Call for any operation needing GLSL explicit int8 data-type support.
  void TParseVersions::explicitInt8Check(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (! builtIn) {
          const char* const extensions[2] = {E_GL_EXT_shader_explicit_arithmetic_types,
                                             E_GL_EXT_shader_explicit_arithmetic_types_int8};
          requireExtensions(loc, 2, extensions, op);
      }
  }
  
  // Call for any operation needing GLSL float16 opaque-type support
  void TParseVersions::float16OpaqueCheck(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (! builtIn) {
          requireExtensions(loc, 1, &E_GL_AMD_gpu_shader_half_float_fetch, op);
          requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
          profileRequires(loc, ECoreProfile | ECompatibilityProfile, 400, nullptr, op);
      }
  }
  
  // Call for any operation needing GLSL explicit int16 data-type support.
  void TParseVersions::explicitInt16Check(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (! builtIn) {
          const char* const extensions[] = {
                                             E_GL_AMD_gpu_shader_int16,
                                             E_GL_EXT_shader_explicit_arithmetic_types,
                                             E_GL_EXT_shader_explicit_arithmetic_types_int16};
          requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
      }
  }
  
  void TParseVersions::int16ScalarVectorCheck(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (! builtIn) {
      	const char* const extensions[] = {
                                             E_GL_AMD_gpu_shader_int16,
                                             E_GL_EXT_shader_16bit_storage,
                                             E_GL_EXT_shader_explicit_arithmetic_types,
                                             E_GL_EXT_shader_explicit_arithmetic_types_int16};
          requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
      }
  }
  
  void TParseVersions::int8ScalarVectorCheck(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (! builtIn) {
      	const char* const extensions[] = {
                                             E_GL_EXT_shader_8bit_storage,
                                             E_GL_EXT_shader_explicit_arithmetic_types,
                                             E_GL_EXT_shader_explicit_arithmetic_types_int8};
          requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
      }
  }
  
  // Call for any operation needing GLSL explicit int32 data-type support.
  void TParseVersions::explicitInt32Check(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (! builtIn) {
          const char* const extensions[2] = {E_GL_EXT_shader_explicit_arithmetic_types,
                                             E_GL_EXT_shader_explicit_arithmetic_types_int32};
          requireExtensions(loc, 2, extensions, op);
      }
  }
  
  // Call for any operation needing GLSL 64-bit integer data-type support.
  void TParseVersions::int64Check(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (! builtIn) {
          const char* const extensions[3] = {E_GL_ARB_gpu_shader_int64,
                                             E_GL_EXT_shader_explicit_arithmetic_types,
                                             E_GL_EXT_shader_explicit_arithmetic_types_int64};
          requireExtensions(loc, 3, extensions, op);
          requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
          profileRequires(loc, ECoreProfile | ECompatibilityProfile, 400, nullptr, op);
      }
  }
  
  void TParseVersions::fcoopmatCheck(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (!builtIn) {
          const char* const extensions[] = {E_GL_NV_cooperative_matrix};
          requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
      }
  }
  
  void TParseVersions::intcoopmatCheck(const TSourceLoc& loc, const char* op, bool builtIn)
  {
      if (!builtIn) {
          const char* const extensions[] = {E_GL_NV_integer_cooperative_matrix};
          requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op);
      }
  }
  #endif // GLSLANG_WEB
  // Call for any operation removed because SPIR-V is in use.
  void TParseVersions::spvRemoved(const TSourceLoc& loc, const char* op)
  {
      if (spvVersion.spv != 0)
          error(loc, "not allowed when generating SPIR-V", op, "");
  }
  
  // Call for any operation removed because Vulkan SPIR-V is being generated.
  void TParseVersions::vulkanRemoved(const TSourceLoc& loc, const char* op)
  {
      if (spvVersion.vulkan > 0)
          error(loc, "not allowed when using GLSL for Vulkan", op, "");
  }
  
  // Call for any operation that requires Vulkan.
  void TParseVersions::requireVulkan(const TSourceLoc& loc, const char* op)
  {
  #ifndef GLSLANG_WEB
      if (spvVersion.vulkan == 0)
          error(loc, "only allowed when using GLSL for Vulkan", op, "");
  #endif
  }
  
  // Call for any operation that requires SPIR-V.
  void TParseVersions::requireSpv(const TSourceLoc& loc, const char* op)
  {
  #ifndef GLSLANG_WEB
      if (spvVersion.spv == 0)
          error(loc, "only allowed when generating SPIR-V", op, "");
  #endif
  }
  void TParseVersions::requireSpv(const TSourceLoc& loc, const char *op, unsigned int version)
  {
  #ifndef GLSLANG_WEB
      if (spvVersion.spv < version)
          error(loc, "not supported for current targeted SPIR-V version", op, "");
  #endif
  }
  
  } // end namespace glslang
  